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