xref: /xv6-public/sysfile.c (revision eaea18cb)
12685309fSrsc #include "types.h"
22685309fSrsc #include "stat.h"
32685309fSrsc #include "param.h"
42685309fSrsc #include "mmu.h"
52685309fSrsc #include "proc.h"
62685309fSrsc #include "defs.h"
72685309fSrsc #include "x86.h"
82685309fSrsc #include "traps.h"
92685309fSrsc #include "syscall.h"
102685309fSrsc #include "spinlock.h"
112685309fSrsc #include "buf.h"
122685309fSrsc #include "fs.h"
132685309fSrsc #include "fsvar.h"
149936bffaSrsc #include "file.h"
152685309fSrsc #include "fcntl.h"
162685309fSrsc 
17224f6598Srsc // Fetch the nth word-sized system call argument as a file descriptor
18224f6598Srsc // and return both the descriptor and the corresponding struct file.
19224f6598Srsc static int
20224f6598Srsc argfd(int argno, int *pfd, struct file **pf)
21224f6598Srsc {
22224f6598Srsc   int fd;
23224f6598Srsc   struct file *f;
24224f6598Srsc 
25224f6598Srsc   if(argint(argno, &fd) < 0)
26224f6598Srsc     return -1;
279583b476Srsc   if(fd < 0 || fd >= NOFILE || (f=cp->ofile[fd]) == 0)
28224f6598Srsc     return -1;
29224f6598Srsc   if(pfd)
30224f6598Srsc     *pfd = fd;
31224f6598Srsc   if(pf)
32224f6598Srsc     *pf = f;
33224f6598Srsc   return 0;
34224f6598Srsc }
35224f6598Srsc 
36224f6598Srsc // Allocate a file descriptor for the given file.
37224f6598Srsc // Takes over file reference from caller on success.
38224f6598Srsc static int
39224f6598Srsc fdalloc(struct file *f)
40224f6598Srsc {
41224f6598Srsc   int fd;
429583b476Srsc 
43224f6598Srsc   for(fd = 0; fd < NOFILE; fd++){
449583b476Srsc     if(cp->ofile[fd] == 0){
459583b476Srsc       cp->ofile[fd] = f;
46224f6598Srsc       return fd;
47224f6598Srsc     }
48224f6598Srsc   }
49224f6598Srsc   return -1;
50224f6598Srsc }
51224f6598Srsc 
522685309fSrsc int
53*eaea18cbSrsc sys_read(void)
542685309fSrsc {
55*eaea18cbSrsc   struct file *f;
56*eaea18cbSrsc   int n;
57*eaea18cbSrsc   char *cp;
582685309fSrsc 
59*eaea18cbSrsc   if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &cp, n) < 0)
602685309fSrsc     return -1;
61*eaea18cbSrsc   return fileread(f, cp, n);
622685309fSrsc }
632685309fSrsc 
642685309fSrsc int
652685309fSrsc sys_write(void)
662685309fSrsc {
67224f6598Srsc   struct file *f;
68224f6598Srsc   int n;
69224f6598Srsc   char *cp;
702685309fSrsc 
71224f6598Srsc   if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &cp, n) < 0)
722685309fSrsc     return -1;
73224f6598Srsc   return filewrite(f, cp, n);
742685309fSrsc }
752685309fSrsc 
762685309fSrsc int
77*eaea18cbSrsc sys_fstat(void)
782685309fSrsc {
79224f6598Srsc   struct file *f;
80*eaea18cbSrsc   struct stat *st;
812685309fSrsc 
82*eaea18cbSrsc   if(argfd(0, 0, &f) < 0 || argptr(1, (void*)&st, sizeof(*st)) < 0)
832685309fSrsc     return -1;
84*eaea18cbSrsc   return filestat(f, st);
852685309fSrsc }
862685309fSrsc 
872685309fSrsc int
882685309fSrsc sys_close(void)
892685309fSrsc {
902685309fSrsc   int fd;
91224f6598Srsc   struct file *f;
922685309fSrsc 
93224f6598Srsc   if(argfd(0, &fd, &f) < 0)
942685309fSrsc     return -1;
95b6095304Srsc   cp->ofile[fd] = 0;
96224f6598Srsc   fileclose(f);
972685309fSrsc   return 0;
982685309fSrsc }
992685309fSrsc 
100*eaea18cbSrsc // Create the path new as a link to the same inode as old.
101*eaea18cbSrsc int
102*eaea18cbSrsc sys_link(void)
103*eaea18cbSrsc {
104*eaea18cbSrsc   char name[DIRSIZ], *new, *old;
105*eaea18cbSrsc   struct inode *dp, *ip;
106*eaea18cbSrsc   struct uinode *ipu;
107*eaea18cbSrsc 
108*eaea18cbSrsc   if(argstr(0, &old) < 0 || argstr(1, &new) < 0)
109*eaea18cbSrsc     return -1;
110*eaea18cbSrsc   if((ip = ilock(namei(old))) == 0)
111*eaea18cbSrsc     return -1;
112*eaea18cbSrsc   if(ip->type == T_DIR){
113*eaea18cbSrsc     iput(iunlock(ip));
114*eaea18cbSrsc     return -1;
115*eaea18cbSrsc   }
116*eaea18cbSrsc   ip->nlink++;
117*eaea18cbSrsc   iupdate(ip);
118*eaea18cbSrsc   ipu = iunlock(ip);  ip = 0;
119*eaea18cbSrsc 
120*eaea18cbSrsc   if((dp = ilock(nameiparent(new, name))) == 0 ||
121*eaea18cbSrsc      dp->dev != ipu->dev || dirlink(dp, name, ipu->inum) < 0){
122*eaea18cbSrsc     if(dp)
123*eaea18cbSrsc       iput(iunlock(dp));
124*eaea18cbSrsc     ip = ilock(ipu);
125*eaea18cbSrsc     ip->nlink--;
126*eaea18cbSrsc     iupdate(ip);
127*eaea18cbSrsc     iput(iunlock(ip));
128*eaea18cbSrsc     return -1;
129*eaea18cbSrsc   }
130*eaea18cbSrsc   iput(iunlock(dp));
131*eaea18cbSrsc   iput(ipu);
132*eaea18cbSrsc   return 0;
133*eaea18cbSrsc }
134*eaea18cbSrsc 
135*eaea18cbSrsc // Is the directory dp empty except for "." and ".." ?
136*eaea18cbSrsc static int
137*eaea18cbSrsc isdirempty(struct inode *dp)
138*eaea18cbSrsc {
139*eaea18cbSrsc   int off;
140*eaea18cbSrsc   struct dirent de;
141*eaea18cbSrsc 
142*eaea18cbSrsc   for(off=2*sizeof(de); off<dp->size; off+=sizeof(de)){
143*eaea18cbSrsc     if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
144*eaea18cbSrsc       panic("isdirempty: readi");
145*eaea18cbSrsc     if(de.inum != 0)
146*eaea18cbSrsc       return 0;
147*eaea18cbSrsc   }
148*eaea18cbSrsc   return 1;
149*eaea18cbSrsc }
150*eaea18cbSrsc 
151*eaea18cbSrsc int
152*eaea18cbSrsc sys_unlink(void)
153*eaea18cbSrsc {
154*eaea18cbSrsc   struct inode *ip, *dp;
155*eaea18cbSrsc   struct dirent de;
156*eaea18cbSrsc   char name[DIRSIZ], *path;
157*eaea18cbSrsc   uint off;
158*eaea18cbSrsc 
159*eaea18cbSrsc   if(argstr(0, &path) < 0)
160*eaea18cbSrsc     return -1;
161*eaea18cbSrsc   if((dp = ilock(nameiparent(path, name))) == 0)
162*eaea18cbSrsc     return -1;
163*eaea18cbSrsc 
164*eaea18cbSrsc   // Cannot unlink "." or "..".
165*eaea18cbSrsc   if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0){
166*eaea18cbSrsc     iput(iunlock(dp));
167*eaea18cbSrsc     return -1;
168*eaea18cbSrsc   }
169*eaea18cbSrsc 
170*eaea18cbSrsc   if((ip = ilock(dirlookup(dp, name, &off))) == 0){
171*eaea18cbSrsc     iput(iunlock(dp));
172*eaea18cbSrsc     return -1;
173*eaea18cbSrsc   }
174*eaea18cbSrsc 
175*eaea18cbSrsc   if(ip->nlink < 1)
176*eaea18cbSrsc     panic("unlink: nlink < 1");
177*eaea18cbSrsc   if(ip->type == T_DIR && !isdirempty(ip)){
178*eaea18cbSrsc     iput(iunlock(ip));
179*eaea18cbSrsc     iput(iunlock(dp));
180*eaea18cbSrsc     return -1;
181*eaea18cbSrsc   }
182*eaea18cbSrsc 
183*eaea18cbSrsc   memset(&de, 0, sizeof(de));
184*eaea18cbSrsc   if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
185*eaea18cbSrsc     panic("unlink: writei");
186*eaea18cbSrsc   iput(iunlock(dp));
187*eaea18cbSrsc 
188*eaea18cbSrsc   ip->nlink--;
189*eaea18cbSrsc   iupdate(ip);
190*eaea18cbSrsc   iput(iunlock(ip));
191*eaea18cbSrsc   return 0;
192*eaea18cbSrsc }
193*eaea18cbSrsc 
194*eaea18cbSrsc // Create the path and return its unlocked inode structure.
195*eaea18cbSrsc static struct inode*
196*eaea18cbSrsc mkpath(char *path, int canexist, short type, short major, short minor)
197*eaea18cbSrsc {
198*eaea18cbSrsc   uint off;
199*eaea18cbSrsc   struct inode *ip, *dp;
200*eaea18cbSrsc   struct uinode *ipu;
201*eaea18cbSrsc   char name[DIRSIZ];
202*eaea18cbSrsc 
203*eaea18cbSrsc   if((dp = ilock(nameiparent(path, name))) == 0)
204*eaea18cbSrsc     return 0;
205*eaea18cbSrsc 
206*eaea18cbSrsc   if(canexist && (ipu = dirlookup(dp, name, &off)) != 0){
207*eaea18cbSrsc     iput(iunlock(dp));
208*eaea18cbSrsc     ip = ilock(ipu);
209*eaea18cbSrsc     if(ip->type != type || ip->major != major || ip->minor != minor){
210*eaea18cbSrsc       iput(iunlock(ip));
211*eaea18cbSrsc       return 0;
212*eaea18cbSrsc     }
213*eaea18cbSrsc     return ip;
214*eaea18cbSrsc   }
215*eaea18cbSrsc 
216*eaea18cbSrsc   if((ip = ilock(ialloc(dp->dev, type))) == 0){
217*eaea18cbSrsc     iput(iunlock(dp));
218*eaea18cbSrsc     return 0;
219*eaea18cbSrsc   }
220*eaea18cbSrsc   ip->major = major;
221*eaea18cbSrsc   ip->minor = minor;
222*eaea18cbSrsc   ip->size = 0;
223*eaea18cbSrsc   ip->nlink = 1;
224*eaea18cbSrsc   iupdate(ip);
225*eaea18cbSrsc 
226*eaea18cbSrsc   if(dirlink(dp, name, ip->inum) < 0){
227*eaea18cbSrsc     ip->nlink = 0;
228*eaea18cbSrsc     iput(iunlock(ip));
229*eaea18cbSrsc     iput(iunlock(dp));
230*eaea18cbSrsc     return 0;
231*eaea18cbSrsc   }
232*eaea18cbSrsc 
233*eaea18cbSrsc   if(type == T_DIR){  // Create . and .. entries.
234*eaea18cbSrsc     dp->nlink++;  // for ".."
235*eaea18cbSrsc     iupdate(dp);
236*eaea18cbSrsc     // No ip->nlink++ for ".": avoid cyclic ref count.
237*eaea18cbSrsc     if(dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0)
238*eaea18cbSrsc       panic("mkpath dots");
239*eaea18cbSrsc   }
240*eaea18cbSrsc   iput(iunlock(dp));
241*eaea18cbSrsc   return ip;
242*eaea18cbSrsc }
243*eaea18cbSrsc 
2442685309fSrsc int
2452685309fSrsc sys_open(void)
2462685309fSrsc {
247f32f3638Srsc   char *path;
248f32f3638Srsc   int fd, omode;
249224f6598Srsc   struct file *f;
250f32f3638Srsc   struct inode *ip;
2512685309fSrsc 
252224f6598Srsc   if(argstr(0, &path) < 0 || argint(1, &omode) < 0)
2532685309fSrsc     return -1;
2542685309fSrsc 
255*eaea18cbSrsc   if(omode & O_CREATE){
256*eaea18cbSrsc     if((ip = mkpath(path, 1, T_FILE, 0, 0)) == 0)
257e2a620daSrsc       return -1;
258*eaea18cbSrsc   }else{
259*eaea18cbSrsc     if((ip = ilock(namei(path))) == 0)
260*eaea18cbSrsc       return -1;
261f32f3638Srsc     if(ip->type == T_DIR && (omode & (O_RDWR|O_WRONLY))){
262*eaea18cbSrsc       iput(iunlock(ip));
2632685309fSrsc       return -1;
2642685309fSrsc     }
265*eaea18cbSrsc   }
2662685309fSrsc 
267*eaea18cbSrsc   if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){
268*eaea18cbSrsc     if(f)
269224f6598Srsc       fileclose(f);
270*eaea18cbSrsc     iput(iunlock(ip));
2712685309fSrsc     return -1;
2722685309fSrsc   }
2732685309fSrsc 
274*eaea18cbSrsc   f->type = FD_INODE;
275*eaea18cbSrsc   f->ip = iunlock(ip);
276*eaea18cbSrsc   f->off = 0;
277224f6598Srsc   if(omode & O_RDWR) {
278224f6598Srsc     f->readable = 1;
279224f6598Srsc     f->writable = 1;
280224f6598Srsc   } else if(omode & O_WRONLY) {
281224f6598Srsc     f->readable = 0;
282224f6598Srsc     f->writable = 1;
2832685309fSrsc   } else {
284224f6598Srsc     f->readable = 1;
285224f6598Srsc     f->writable = 0;
2862685309fSrsc   }
2872685309fSrsc 
288224f6598Srsc   return fd;
2892685309fSrsc }
2902685309fSrsc 
2912685309fSrsc int
2922685309fSrsc sys_mknod(void)
2932685309fSrsc {
294*eaea18cbSrsc   struct inode *ip;
295224f6598Srsc   char *path;
296224f6598Srsc   int len;
297224f6598Srsc   int type, major, minor;
2982685309fSrsc 
299224f6598Srsc   if((len=argstr(0, &path)) < 0 || argint(1, &type) < 0 ||
300224f6598Srsc      argint(2, &major) < 0 || argint(3, &minor) < 0)
3012685309fSrsc     return -1;
302*eaea18cbSrsc   // XXX check that type == T_DEV or eliminate type arg?
303*eaea18cbSrsc   if((ip = mkpath(path, 0, type, major, minor)) == 0)
3042685309fSrsc     return -1;
305*eaea18cbSrsc   iput(iunlock(ip));
306224f6598Srsc   return 0;
3072685309fSrsc }
3082685309fSrsc 
3092685309fSrsc int
3102685309fSrsc sys_mkdir(void)
3112685309fSrsc {
312f32f3638Srsc   char *path;
313*eaea18cbSrsc   struct inode *ip;
3142685309fSrsc 
315*eaea18cbSrsc   if(argstr(0, &path) < 0 || (ip = mkpath(path, 0, T_DIR, 0, 0)) == 0)
3162685309fSrsc     return -1;
317*eaea18cbSrsc   iput(iunlock(ip));
318*eaea18cbSrsc   return 0;
3192685309fSrsc }
3202685309fSrsc 
3212685309fSrsc int
3222685309fSrsc sys_chdir(void)
3232685309fSrsc {
324*eaea18cbSrsc   char *path;
3252685309fSrsc   struct inode *ip;
3262685309fSrsc 
327*eaea18cbSrsc   if(argstr(0, &path) < 0 || (ip = ilock(namei(path))) == 0)
3282685309fSrsc     return -1;
3292685309fSrsc   if(ip->type != T_DIR) {
330*eaea18cbSrsc     iput(iunlock(ip));
3312685309fSrsc     return -1;
3322685309fSrsc   }
333*eaea18cbSrsc   iput(cp->cwd);
334*eaea18cbSrsc   cp->cwd = iunlock(ip);
3352685309fSrsc   return 0;
3362685309fSrsc }
3372685309fSrsc 
3382685309fSrsc int
3392685309fSrsc sys_dup(void)
3402685309fSrsc {
341224f6598Srsc   struct file *f;
342224f6598Srsc   int fd;
3432685309fSrsc 
344224f6598Srsc   if(argfd(0, 0, &f) < 0)
3452685309fSrsc     return -1;
346224f6598Srsc   if((fd=fdalloc(f)) < 0)
3472685309fSrsc     return -1;
348224f6598Srsc   fileincref(f);
349224f6598Srsc   return fd;
3502685309fSrsc }
3512685309fSrsc 
3522685309fSrsc int
3532685309fSrsc sys_exec(void)
3542685309fSrsc {
355*eaea18cbSrsc   char *path, *argv[20];
356f32f3638Srsc   int i;
357f32f3638Srsc   uint uargv, uarg;
3582685309fSrsc 
359f32f3638Srsc   if(argstr(0, &path) < 0 || argint(1, (int*)&uargv) < 0)
3602685309fSrsc     return -1;
361*eaea18cbSrsc   memset(argv, 0, sizeof(argv));
3622685309fSrsc   for(i=0;; i++){
363*eaea18cbSrsc     if(i >= NELEM(argv))
3642685309fSrsc       return -1;
365f32f3638Srsc     if(fetchint(cp, uargv+4*i, (int*)&uarg) < 0)
366f32f3638Srsc       return -1;
367f32f3638Srsc     if(uarg == 0){
368f32f3638Srsc       argv[i] = 0;
369f32f3638Srsc       break;
3702685309fSrsc     }
371f32f3638Srsc     if(fetchstr(cp, uarg, &argv[i]) < 0)
372f32f3638Srsc       return -1;
373f32f3638Srsc   }
374f32f3638Srsc   return exec(path, argv);
375f32f3638Srsc }
376f32f3638Srsc 
377*eaea18cbSrsc int
378*eaea18cbSrsc sys_pipe(void)
379*eaea18cbSrsc {
380*eaea18cbSrsc   int *fd;
381*eaea18cbSrsc   struct file *rf, *wf;
382*eaea18cbSrsc   int fd0, fd1;
383*eaea18cbSrsc 
384*eaea18cbSrsc   if(argptr(0, (void*)&fd, 2*sizeof(fd[0])) < 0)
385*eaea18cbSrsc     return -1;
386*eaea18cbSrsc   if(pipe_alloc(&rf, &wf) < 0)
387*eaea18cbSrsc     return -1;
388*eaea18cbSrsc   fd0 = -1;
389*eaea18cbSrsc   if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){
390*eaea18cbSrsc     if(fd0 >= 0)
391*eaea18cbSrsc       cp->ofile[fd0] = 0;
392*eaea18cbSrsc     fileclose(rf);
393*eaea18cbSrsc     fileclose(wf);
394*eaea18cbSrsc     return -1;
395*eaea18cbSrsc   }
396*eaea18cbSrsc   fd[0] = fd0;
397*eaea18cbSrsc   fd[1] = fd1;
398*eaea18cbSrsc   return 0;
399*eaea18cbSrsc }
400