xref: /xv6-public/sysfile.c (revision 15a26936)
12685309fSrsc #include "types.h"
2558ab49fSrsc #include "defs.h"
32685309fSrsc #include "param.h"
4558ab49fSrsc #include "stat.h"
52685309fSrsc #include "mmu.h"
62685309fSrsc #include "proc.h"
72685309fSrsc #include "fs.h"
82685309fSrsc #include "fsvar.h"
99936bffaSrsc #include "file.h"
102685309fSrsc #include "fcntl.h"
112685309fSrsc 
12224f6598Srsc // Fetch the nth word-sized system call argument as a file descriptor
13224f6598Srsc // and return both the descriptor and the corresponding struct file.
14224f6598Srsc static int
1564c47374Srsc argfd(int n, int *pfd, struct file **pf)
16224f6598Srsc {
17224f6598Srsc   int fd;
18224f6598Srsc   struct file *f;
19224f6598Srsc 
203a2310f7Srsc   if(argint(n, &fd) < 0)
21224f6598Srsc     return -1;
229583b476Srsc   if(fd < 0 || fd >= NOFILE || (f=cp->ofile[fd]) == 0)
23224f6598Srsc     return -1;
24224f6598Srsc   if(pfd)
25224f6598Srsc     *pfd = fd;
26224f6598Srsc   if(pf)
27224f6598Srsc     *pf = f;
28224f6598Srsc   return 0;
29224f6598Srsc }
30224f6598Srsc 
31224f6598Srsc // Allocate a file descriptor for the given file.
32224f6598Srsc // Takes over file reference from caller on success.
33224f6598Srsc static int
34224f6598Srsc fdalloc(struct file *f)
35224f6598Srsc {
36224f6598Srsc   int fd;
379583b476Srsc 
38224f6598Srsc   for(fd = 0; fd < NOFILE; fd++){
399583b476Srsc     if(cp->ofile[fd] == 0){
409583b476Srsc       cp->ofile[fd] = f;
41224f6598Srsc       return fd;
42224f6598Srsc     }
43224f6598Srsc   }
44224f6598Srsc   return -1;
45224f6598Srsc }
46224f6598Srsc 
472685309fSrsc int
48eaea18cbSrsc sys_read(void)
492685309fSrsc {
50eaea18cbSrsc   struct file *f;
51eaea18cbSrsc   int n;
52666f58c7Srsc   char *p;
532685309fSrsc 
54666f58c7Srsc   if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0)
552685309fSrsc     return -1;
56666f58c7Srsc   return fileread(f, p, n);
572685309fSrsc }
582685309fSrsc 
592685309fSrsc int
602685309fSrsc sys_write(void)
612685309fSrsc {
62224f6598Srsc   struct file *f;
63224f6598Srsc   int n;
64666f58c7Srsc   char *p;
652685309fSrsc 
66666f58c7Srsc   if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0)
672685309fSrsc     return -1;
68666f58c7Srsc   return filewrite(f, p, n);
692685309fSrsc }
702685309fSrsc 
712685309fSrsc int
728d2e9a48Srsc sys_dup(void)
732685309fSrsc {
74224f6598Srsc   struct file *f;
758d2e9a48Srsc   int fd;
762685309fSrsc 
778d2e9a48Srsc   if(argfd(0, 0, &f) < 0)
782685309fSrsc     return -1;
798d2e9a48Srsc   if((fd=fdalloc(f)) < 0)
808d2e9a48Srsc     return -1;
811ccff18bSrsc   filedup(f);
828d2e9a48Srsc   return fd;
832685309fSrsc }
842685309fSrsc 
852685309fSrsc int
862685309fSrsc sys_close(void)
872685309fSrsc {
882685309fSrsc   int fd;
89224f6598Srsc   struct file *f;
902685309fSrsc 
91224f6598Srsc   if(argfd(0, &fd, &f) < 0)
922685309fSrsc     return -1;
93b6095304Srsc   cp->ofile[fd] = 0;
94224f6598Srsc   fileclose(f);
952685309fSrsc   return 0;
962685309fSrsc }
972685309fSrsc 
988d2e9a48Srsc int
998d2e9a48Srsc sys_fstat(void)
1008d2e9a48Srsc {
1018d2e9a48Srsc   struct file *f;
1028d2e9a48Srsc   struct stat *st;
1038d2e9a48Srsc 
1048d2e9a48Srsc   if(argfd(0, 0, &f) < 0 || argptr(1, (void*)&st, sizeof(*st)) < 0)
1058d2e9a48Srsc     return -1;
1068d2e9a48Srsc   return filestat(f, st);
1078d2e9a48Srsc }
1088d2e9a48Srsc 
109eaea18cbSrsc // Create the path new as a link to the same inode as old.
110eaea18cbSrsc int
111eaea18cbSrsc sys_link(void)
112eaea18cbSrsc {
113eaea18cbSrsc   char name[DIRSIZ], *new, *old;
114eaea18cbSrsc   struct inode *dp, *ip;
115eaea18cbSrsc 
116eaea18cbSrsc   if(argstr(0, &old) < 0 || argstr(1, &new) < 0)
117eaea18cbSrsc     return -1;
11807090dd7Srsc   if((ip = namei(old)) == 0)
119eaea18cbSrsc     return -1;
12007090dd7Srsc   ilock(ip);
121eaea18cbSrsc   if(ip->type == T_DIR){
12207090dd7Srsc     iunlockput(ip);
123eaea18cbSrsc     return -1;
124eaea18cbSrsc   }
125eaea18cbSrsc   ip->nlink++;
126eaea18cbSrsc   iupdate(ip);
12707090dd7Srsc   iunlock(ip);
128eaea18cbSrsc 
12907090dd7Srsc   if((dp = nameiparent(new, name)) == 0)
13007090dd7Srsc     goto  bad;
13107090dd7Srsc   ilock(dp);
13207090dd7Srsc   if(dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0)
13307090dd7Srsc     goto bad;
13407090dd7Srsc   iunlockput(dp);
13507090dd7Srsc   iput(ip);
13607090dd7Srsc   return 0;
13707090dd7Srsc 
13807090dd7Srsc bad:
139eaea18cbSrsc   if(dp)
14007090dd7Srsc     iunlockput(dp);
14107090dd7Srsc   ilock(ip);
142eaea18cbSrsc   ip->nlink--;
143eaea18cbSrsc   iupdate(ip);
14407090dd7Srsc   iunlockput(ip);
145eaea18cbSrsc   return -1;
146eaea18cbSrsc }
147eaea18cbSrsc 
148eaea18cbSrsc // Is the directory dp empty except for "." and ".." ?
149eaea18cbSrsc static int
150eaea18cbSrsc isdirempty(struct inode *dp)
151eaea18cbSrsc {
152eaea18cbSrsc   int off;
153eaea18cbSrsc   struct dirent de;
154eaea18cbSrsc 
155eaea18cbSrsc   for(off=2*sizeof(de); off<dp->size; off+=sizeof(de)){
156eaea18cbSrsc     if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
157eaea18cbSrsc       panic("isdirempty: readi");
158eaea18cbSrsc     if(de.inum != 0)
159eaea18cbSrsc       return 0;
160eaea18cbSrsc   }
161eaea18cbSrsc   return 1;
162eaea18cbSrsc }
163eaea18cbSrsc 
1648d2e9a48Srsc //PAGEBREAK!
165eaea18cbSrsc int
166eaea18cbSrsc sys_unlink(void)
167eaea18cbSrsc {
168eaea18cbSrsc   struct inode *ip, *dp;
169eaea18cbSrsc   struct dirent de;
170eaea18cbSrsc   char name[DIRSIZ], *path;
171eaea18cbSrsc   uint off;
172eaea18cbSrsc 
173eaea18cbSrsc   if(argstr(0, &path) < 0)
174eaea18cbSrsc     return -1;
17507090dd7Srsc   if((dp = nameiparent(path, name)) == 0)
176eaea18cbSrsc     return -1;
17707090dd7Srsc   ilock(dp);
178eaea18cbSrsc 
179eaea18cbSrsc   // Cannot unlink "." or "..".
180eaea18cbSrsc   if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0){
18107090dd7Srsc     iunlockput(dp);
182eaea18cbSrsc     return -1;
183eaea18cbSrsc   }
184eaea18cbSrsc 
18507090dd7Srsc   if((ip = dirlookup(dp, name, &off)) == 0){
18607090dd7Srsc     iunlockput(dp);
187eaea18cbSrsc     return -1;
188eaea18cbSrsc   }
18907090dd7Srsc   ilock(ip);
190eaea18cbSrsc 
191eaea18cbSrsc   if(ip->nlink < 1)
192eaea18cbSrsc     panic("unlink: nlink < 1");
193eaea18cbSrsc   if(ip->type == T_DIR && !isdirempty(ip)){
19407090dd7Srsc     iunlockput(ip);
19507090dd7Srsc     iunlockput(dp);
196eaea18cbSrsc     return -1;
197eaea18cbSrsc   }
198eaea18cbSrsc 
199eaea18cbSrsc   memset(&de, 0, sizeof(de));
200eaea18cbSrsc   if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
201eaea18cbSrsc     panic("unlink: writei");
202*15a26936Skolya   if(ip->type == T_DIR){
203*15a26936Skolya     dp->nlink--;
204*15a26936Skolya     iupdate(dp);
205*15a26936Skolya   }
20607090dd7Srsc   iunlockput(dp);
207eaea18cbSrsc 
208eaea18cbSrsc   ip->nlink--;
209eaea18cbSrsc   iupdate(ip);
21007090dd7Srsc   iunlockput(ip);
211eaea18cbSrsc   return 0;
212eaea18cbSrsc }
213eaea18cbSrsc 
214eaea18cbSrsc static struct inode*
215e79b1659Srsc create(char *path, int canexist, short type, short major, short minor)
216eaea18cbSrsc {
217eaea18cbSrsc   uint off;
218eaea18cbSrsc   struct inode *ip, *dp;
219eaea18cbSrsc   char name[DIRSIZ];
220eaea18cbSrsc 
22107090dd7Srsc   if((dp = nameiparent(path, name)) == 0)
222eaea18cbSrsc     return 0;
22307090dd7Srsc   ilock(dp);
224eaea18cbSrsc 
22507090dd7Srsc   if(canexist && (ip = dirlookup(dp, name, &off)) != 0){
22607090dd7Srsc     iunlockput(dp);
22707090dd7Srsc     ilock(ip);
228eaea18cbSrsc     if(ip->type != type || ip->major != major || ip->minor != minor){
22907090dd7Srsc       iunlockput(ip);
230eaea18cbSrsc       return 0;
231eaea18cbSrsc     }
232eaea18cbSrsc     return ip;
233eaea18cbSrsc   }
234eaea18cbSrsc 
23507090dd7Srsc   if((ip = ialloc(dp->dev, type)) == 0){
23607090dd7Srsc     iunlockput(dp);
237eaea18cbSrsc     return 0;
238eaea18cbSrsc   }
23907090dd7Srsc   ilock(ip);
240eaea18cbSrsc   ip->major = major;
241eaea18cbSrsc   ip->minor = minor;
242603deefcSrsc   ip->nlink = 1;
243eaea18cbSrsc   iupdate(ip);
244eaea18cbSrsc 
245eaea18cbSrsc   if(type == T_DIR){  // Create . and .. entries.
246eaea18cbSrsc     dp->nlink++;  // for ".."
247eaea18cbSrsc     iupdate(dp);
248eaea18cbSrsc     // No ip->nlink++ for ".": avoid cyclic ref count.
249eaea18cbSrsc     if(dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0)
250e79b1659Srsc       panic("create dots");
251eaea18cbSrsc   }
252f3e87bc8Skolya 
253f3e87bc8Skolya   if(dirlink(dp, name, ip->inum) < 0){
254*15a26936Skolya     if(type == T_DIR){
255f3e87bc8Skolya       dp->nlink--;
256f3e87bc8Skolya       iupdate(dp);
257*15a26936Skolya     }
258f3e87bc8Skolya     iunlockput(dp);
259f3e87bc8Skolya 
260f3e87bc8Skolya     ip->nlink = 0;
261f3e87bc8Skolya     iunlockput(ip);
262f3e87bc8Skolya     return 0;
263f3e87bc8Skolya   }
264f3e87bc8Skolya 
26507090dd7Srsc   iunlockput(dp);
266eaea18cbSrsc   return ip;
267eaea18cbSrsc }
268eaea18cbSrsc 
2692685309fSrsc int
2702685309fSrsc sys_open(void)
2712685309fSrsc {
272f32f3638Srsc   char *path;
273f32f3638Srsc   int fd, omode;
274224f6598Srsc   struct file *f;
275f32f3638Srsc   struct inode *ip;
2762685309fSrsc 
277224f6598Srsc   if(argstr(0, &path) < 0 || argint(1, &omode) < 0)
2782685309fSrsc     return -1;
2792685309fSrsc 
280eaea18cbSrsc   if(omode & O_CREATE){
281e79b1659Srsc     if((ip = create(path, 1, T_FILE, 0, 0)) == 0)
282e2a620daSrsc       return -1;
283eaea18cbSrsc   } else {
28407090dd7Srsc     if((ip = namei(path)) == 0)
285eaea18cbSrsc       return -1;
28607090dd7Srsc     ilock(ip);
287f32f3638Srsc     if(ip->type == T_DIR && (omode & (O_RDWR|O_WRONLY))){
28807090dd7Srsc       iunlockput(ip);
2892685309fSrsc       return -1;
2902685309fSrsc     }
291eaea18cbSrsc   }
2922685309fSrsc 
293eaea18cbSrsc   if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){
294eaea18cbSrsc     if(f)
295224f6598Srsc       fileclose(f);
29607090dd7Srsc     iunlockput(ip);
2972685309fSrsc     return -1;
2982685309fSrsc   }
29907090dd7Srsc   iunlock(ip);
3002685309fSrsc 
301eaea18cbSrsc   f->type = FD_INODE;
30207090dd7Srsc   f->ip = ip;
303eaea18cbSrsc   f->off = 0;
304e79b1659Srsc   f->readable = !(omode & O_WRONLY);
305e79b1659Srsc   f->writable = (omode & O_WRONLY) || (omode & O_RDWR);
3062685309fSrsc 
307224f6598Srsc   return fd;
3082685309fSrsc }
3092685309fSrsc 
3102685309fSrsc int
3112685309fSrsc sys_mknod(void)
3122685309fSrsc {
313eaea18cbSrsc   struct inode *ip;
314224f6598Srsc   char *path;
315224f6598Srsc   int len;
316aa6824abSrsc   int major, minor;
3172685309fSrsc 
31807090dd7Srsc   if((len=argstr(0, &path)) < 0 ||
31907090dd7Srsc      argint(1, &major) < 0 ||
32007090dd7Srsc      argint(2, &minor) < 0 ||
321e79b1659Srsc      (ip = create(path, 0, T_DEV, major, minor)) == 0)
3222685309fSrsc     return -1;
32307090dd7Srsc   iunlockput(ip);
324224f6598Srsc   return 0;
3252685309fSrsc }
3262685309fSrsc 
3272685309fSrsc int
3282685309fSrsc sys_mkdir(void)
3292685309fSrsc {
330f32f3638Srsc   char *path;
331eaea18cbSrsc   struct inode *ip;
3322685309fSrsc 
333e79b1659Srsc   if(argstr(0, &path) < 0 || (ip = create(path, 0, T_DIR, 0, 0)) == 0)
3342685309fSrsc     return -1;
33507090dd7Srsc   iunlockput(ip);
336eaea18cbSrsc   return 0;
3372685309fSrsc }
3382685309fSrsc 
3392685309fSrsc int
3402685309fSrsc sys_chdir(void)
3412685309fSrsc {
342eaea18cbSrsc   char *path;
3432685309fSrsc   struct inode *ip;
3442685309fSrsc 
34507090dd7Srsc   if(argstr(0, &path) < 0 || (ip = namei(path)) == 0)
3462685309fSrsc     return -1;
34707090dd7Srsc   ilock(ip);
3482685309fSrsc   if(ip->type != T_DIR){
34907090dd7Srsc     iunlockput(ip);
3502685309fSrsc     return -1;
3512685309fSrsc   }
35207090dd7Srsc   iunlock(ip);
353eaea18cbSrsc   iput(cp->cwd);
35407090dd7Srsc   cp->cwd = ip;
3552685309fSrsc   return 0;
3562685309fSrsc }
3572685309fSrsc 
3582685309fSrsc int
3592685309fSrsc sys_exec(void)
3602685309fSrsc {
361eaea18cbSrsc   char *path, *argv[20];
362f32f3638Srsc   int i;
363f32f3638Srsc   uint uargv, uarg;
3642685309fSrsc 
365f32f3638Srsc   if(argstr(0, &path) < 0 || argint(1, (int*)&uargv) < 0)
3662685309fSrsc     return -1;
367eaea18cbSrsc   memset(argv, 0, sizeof(argv));
3682685309fSrsc   for(i=0;; i++){
369eaea18cbSrsc     if(i >= NELEM(argv))
3702685309fSrsc       return -1;
371f32f3638Srsc     if(fetchint(cp, uargv+4*i, (int*)&uarg) < 0)
372f32f3638Srsc       return -1;
373f32f3638Srsc     if(uarg == 0){
374f32f3638Srsc       argv[i] = 0;
375f32f3638Srsc       break;
3762685309fSrsc     }
377f32f3638Srsc     if(fetchstr(cp, uarg, &argv[i]) < 0)
378f32f3638Srsc       return -1;
379f32f3638Srsc   }
380f32f3638Srsc   return exec(path, argv);
381f32f3638Srsc }
382f32f3638Srsc 
383eaea18cbSrsc int
384eaea18cbSrsc sys_pipe(void)
385eaea18cbSrsc {
386eaea18cbSrsc   int *fd;
387eaea18cbSrsc   struct file *rf, *wf;
388eaea18cbSrsc   int fd0, fd1;
389eaea18cbSrsc 
390eaea18cbSrsc   if(argptr(0, (void*)&fd, 2*sizeof(fd[0])) < 0)
391eaea18cbSrsc     return -1;
3927834cca6Srsc   if(pipealloc(&rf, &wf) < 0)
393eaea18cbSrsc     return -1;
394eaea18cbSrsc   fd0 = -1;
395eaea18cbSrsc   if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){
396eaea18cbSrsc     if(fd0 >= 0)
397eaea18cbSrsc       cp->ofile[fd0] = 0;
398eaea18cbSrsc     fileclose(rf);
399eaea18cbSrsc     fileclose(wf);
400eaea18cbSrsc     return -1;
401eaea18cbSrsc   }
402eaea18cbSrsc   fd[0] = fd0;
403eaea18cbSrsc   fd[1] = fd1;
404eaea18cbSrsc   return 0;
405eaea18cbSrsc }
406