sysfile.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. //
  2. // File-system system calls.
  3. // Mostly argument checking, since we don't trust
  4. // user code, and calls into file.c and fs.c.
  5. //
  6. #include "types.h"
  7. #include "defs.h"
  8. #include "param.h"
  9. #include "stat.h"
  10. #include "mmu.h"
  11. #include "proc.h"
  12. #include "fs.h"
  13. #include "file.h"
  14. #include "fcntl.h"
  15. // Fetch the nth word-sized system call argument as a file descriptor
  16. // and return both the descriptor and the corresponding struct file.
  17. static int
  18. argfd(int n, int *pfd, struct file **pf)
  19. {
  20. int fd;
  21. struct file *f;
  22. if(argint(n, &fd) < 0)
  23. return -1;
  24. if(fd < 0 || fd >= NOFILE || (f=curr_proc->ofile[fd]) == 0)
  25. return -1;
  26. if(pfd)
  27. *pfd = fd;
  28. if(pf)
  29. *pf = f;
  30. return 0;
  31. }
  32. // Allocate a file descriptor for the given file.
  33. // Takes over file reference from caller on success.
  34. static int
  35. fdalloc(struct file *f)
  36. {
  37. int fd;
  38. for(fd = 0; fd < NOFILE; fd++){
  39. if(curr_proc->ofile[fd] == 0){
  40. curr_proc->ofile[fd] = f;
  41. return fd;
  42. }
  43. }
  44. return -1;
  45. }
  46. int
  47. sys_dup(void)
  48. {
  49. struct file *f;
  50. int fd;
  51. if(argfd(0, 0, &f) < 0)
  52. return -1;
  53. if((fd=fdalloc(f)) < 0)
  54. return -1;
  55. filedup(f);
  56. return fd;
  57. }
  58. int
  59. sys_read(void)
  60. {
  61. struct file *f;
  62. int n;
  63. char *p;
  64. if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0)
  65. return -1;
  66. return fileread(f, p, n);
  67. }
  68. int
  69. sys_write(void)
  70. {
  71. struct file *f;
  72. int n;
  73. char *p;
  74. if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0)
  75. return -1;
  76. //cprintf("inside sys_write\n");
  77. return filewrite(f, p, n);
  78. }
  79. int
  80. sys_close(void)
  81. {
  82. int fd;
  83. struct file *f;
  84. if(argfd(0, &fd, &f) < 0)
  85. return -1;
  86. curr_proc->ofile[fd] = 0;
  87. fileclose(f);
  88. return 0;
  89. }
  90. int
  91. sys_fstat(void)
  92. {
  93. struct file *f;
  94. struct stat *st;
  95. if(argfd(0, 0, &f) < 0 || argptr(1, (void*)&st, sizeof(*st)) < 0)
  96. return -1;
  97. return filestat(f, st);
  98. }
  99. // Create the path new as a link to the same inode as old.
  100. int
  101. sys_link(void)
  102. {
  103. char name[DIRSIZ], *new, *old;
  104. struct inode *dp, *ip;
  105. if(argstr(0, &old) < 0 || argstr(1, &new) < 0)
  106. return -1;
  107. if((ip = namei(old)) == 0)
  108. return -1;
  109. begin_trans();
  110. ilock(ip);
  111. if(ip->type == T_DIR){
  112. iunlockput(ip);
  113. commit_trans();
  114. return -1;
  115. }
  116. ip->nlink++;
  117. iupdate(ip);
  118. iunlock(ip);
  119. if((dp = nameiparent(new, name)) == 0)
  120. goto bad;
  121. ilock(dp);
  122. if(dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0){
  123. iunlockput(dp);
  124. goto bad;
  125. }
  126. iunlockput(dp);
  127. iput(ip);
  128. commit_trans();
  129. return 0;
  130. bad:
  131. ilock(ip);
  132. ip->nlink--;
  133. iupdate(ip);
  134. iunlockput(ip);
  135. commit_trans();
  136. return -1;
  137. }
  138. // Is the directory dp empty except for "." and ".." ?
  139. static int
  140. isdirempty(struct inode *dp)
  141. {
  142. int off;
  143. struct dirent de;
  144. for(off=2*sizeof(de); off<dp->size; off+=sizeof(de)){
  145. if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
  146. panic("isdirempty: readi");
  147. if(de.inum != 0)
  148. return 0;
  149. }
  150. return 1;
  151. }
  152. //PAGEBREAK!
  153. int
  154. sys_unlink(void)
  155. {
  156. struct inode *ip, *dp;
  157. struct dirent de;
  158. char name[DIRSIZ], *path;
  159. uint off;
  160. if(argstr(0, &path) < 0)
  161. return -1;
  162. if((dp = nameiparent(path, name)) == 0)
  163. return -1;
  164. begin_trans();
  165. ilock(dp);
  166. // Cannot unlink "." or "..".
  167. if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0)
  168. goto bad;
  169. if((ip = dirlookup(dp, name, &off)) == 0)
  170. goto bad;
  171. ilock(ip);
  172. if(ip->nlink < 1)
  173. panic("unlink: nlink < 1");
  174. if(ip->type == T_DIR && !isdirempty(ip)){
  175. iunlockput(ip);
  176. goto bad;
  177. }
  178. memset(&de, 0, sizeof(de));
  179. if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
  180. panic("unlink: writei");
  181. if(ip->type == T_DIR){
  182. dp->nlink--;
  183. iupdate(dp);
  184. }
  185. iunlockput(dp);
  186. ip->nlink--;
  187. iupdate(ip);
  188. iunlockput(ip);
  189. commit_trans();
  190. return 0;
  191. bad:
  192. iunlockput(dp);
  193. commit_trans();
  194. return -1;
  195. }
  196. static struct inode*
  197. create(char *path, short type, short major, short minor)
  198. {
  199. uint off;
  200. struct inode *ip, *dp;
  201. char name[DIRSIZ];
  202. if((dp = nameiparent(path, name)) == 0)
  203. return 0;
  204. ilock(dp);
  205. if((ip = dirlookup(dp, name, &off)) != 0){
  206. iunlockput(dp);
  207. ilock(ip);
  208. if(type == T_FILE && ip->type == T_FILE)
  209. return ip;
  210. iunlockput(ip);
  211. return 0;
  212. }
  213. if((ip = ialloc(dp->dev, type)) == 0)
  214. panic("create: ialloc");
  215. ilock(ip);
  216. ip->major = major;
  217. ip->minor = minor;
  218. ip->nlink = 1;
  219. iupdate(ip);
  220. if(type == T_DIR){ // Create . and .. entries.
  221. dp->nlink++; // for ".."
  222. iupdate(dp);
  223. // No ip->nlink++ for ".": avoid cyclic ref count.
  224. if(dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0)
  225. panic("create dots");
  226. }
  227. if(dirlink(dp, name, ip->inum) < 0)
  228. panic("create: dirlink");
  229. iunlockput(dp);
  230. return ip;
  231. }
  232. int
  233. sys_open(void)
  234. {
  235. char *path;
  236. int fd, omode;
  237. struct file *f;
  238. struct inode *ip;
  239. if(argstr(0, &path) < 0 || argint(1, &omode) < 0)
  240. return -1;
  241. if(omode & O_CREATE){
  242. begin_trans();
  243. ip = create(path, T_FILE, 0, 0);
  244. commit_trans();
  245. if(ip == 0)
  246. return -1;
  247. } else {
  248. if((ip = namei(path)) == 0)
  249. return -1;
  250. ilock(ip);
  251. if(ip->type == T_DIR && omode != O_RDONLY){
  252. iunlockput(ip);
  253. return -1;
  254. }
  255. }
  256. if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){
  257. if(f)
  258. fileclose(f);
  259. iunlockput(ip);
  260. return -1;
  261. }
  262. iunlock(ip);
  263. f->type = FD_INODE;
  264. f->ip = ip;
  265. f->off = 0;
  266. f->readable = !(omode & O_WRONLY);
  267. f->writable = (omode & O_WRONLY) || (omode & O_RDWR);
  268. return fd;
  269. }
  270. int
  271. sys_mkdir(void)
  272. {
  273. char *path;
  274. struct inode *ip;
  275. begin_trans();
  276. if(argstr(0, &path) < 0 || (ip = create(path, T_DIR, 0, 0)) == 0){
  277. commit_trans();
  278. return -1;
  279. }
  280. iunlockput(ip);
  281. commit_trans();
  282. return 0;
  283. }
  284. int
  285. sys_mknod(void)
  286. {
  287. struct inode *ip;
  288. char *path;
  289. int len;
  290. int major, minor;
  291. begin_trans();
  292. if((len=argstr(0, &path)) < 0 ||
  293. argint(1, &major) < 0 ||
  294. argint(2, &minor) < 0 ||
  295. (ip = create(path, T_DEV, major, minor)) == 0){
  296. commit_trans();
  297. return -1;
  298. }
  299. iunlockput(ip);
  300. commit_trans();
  301. return 0;
  302. }
  303. int
  304. sys_chdir(void)
  305. {
  306. char *path;
  307. struct inode *ip;
  308. if(argstr(0, &path) < 0 || (ip = namei(path)) == 0)
  309. return -1;
  310. ilock(ip);
  311. if(ip->type != T_DIR){
  312. iunlockput(ip);
  313. return -1;
  314. }
  315. iunlock(ip);
  316. iput(curr_proc->cwd);
  317. curr_proc->cwd = ip;
  318. return 0;
  319. }
  320. int
  321. sys_exec(void)
  322. {
  323. char *path, *argv[MAXARG];
  324. int i;
  325. uint uargv, uarg;
  326. if(argstr(0, &path) < 0 || argint(1, (int*)&uargv) < 0){
  327. return -1;
  328. }
  329. memset(argv, 0, sizeof(char *)*MAXARG);
  330. for(i=0;; i++){
  331. if(i >= NELEM(argv))
  332. return -1;
  333. if(fetchint(uargv+4*i, (int*)&uarg) < 0)
  334. return -1;
  335. if(uarg == 0){
  336. argv[i] = 0;
  337. break;
  338. }
  339. if(fetchstr(uarg, &argv[i]) < 0)
  340. return -1;
  341. }
  342. return exec(path, argv);
  343. }
  344. int
  345. sys_pipe(void)
  346. {
  347. int *fd;
  348. struct file *rf, *wf;
  349. int fd0, fd1;
  350. if(argptr(0, (void*)&fd, 2*sizeof(fd[0])) < 0)
  351. return -1;
  352. if(pipealloc(&rf, &wf) < 0)
  353. return -1;
  354. fd0 = -1;
  355. if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){
  356. if(fd0 >= 0)
  357. curr_proc->ofile[fd0] = 0;
  358. fileclose(rf);
  359. fileclose(wf);
  360. return -1;
  361. }
  362. fd[0] = fd0;
  363. fd[1] = fd1;
  364. return 0;
  365. }