112abb1a5SRobert Morris //
212abb1a5SRobert Morris // File-system system calls.
312abb1a5SRobert Morris // Mostly argument checking, since we don't trust
412abb1a5SRobert Morris // user code, and calls into file.c and fs.c.
512abb1a5SRobert Morris //
612abb1a5SRobert Morris
72685309fSrsc #include "types.h"
8558ab49fSrsc #include "defs.h"
92685309fSrsc #include "param.h"
10558ab49fSrsc #include "stat.h"
112685309fSrsc #include "mmu.h"
122685309fSrsc #include "proc.h"
132685309fSrsc #include "fs.h"
14dec637bcSFrans Kaashoek #include "spinlock.h"
15dec637bcSFrans Kaashoek #include "sleeplock.h"
169936bffaSrsc #include "file.h"
172685309fSrsc #include "fcntl.h"
182685309fSrsc
19224f6598Srsc // Fetch the nth word-sized system call argument as a file descriptor
20224f6598Srsc // and return both the descriptor and the corresponding struct file.
21224f6598Srsc static int
argfd(int n,int * pfd,struct file ** pf)2264c47374Srsc argfd(int n, int *pfd, struct file **pf)
23224f6598Srsc {
24224f6598Srsc int fd;
25224f6598Srsc struct file *f;
26224f6598Srsc
273a2310f7Srsc if(argint(n, &fd) < 0)
28224f6598Srsc return -1;
29abf847a0SFrans Kaashoek if(fd < 0 || fd >= NOFILE || (f=myproc()->ofile[fd]) == 0)
30224f6598Srsc return -1;
31224f6598Srsc if(pfd)
32224f6598Srsc *pfd = fd;
33224f6598Srsc if(pf)
34224f6598Srsc *pf = f;
35224f6598Srsc return 0;
36224f6598Srsc }
37224f6598Srsc
38224f6598Srsc // Allocate a file descriptor for the given file.
39224f6598Srsc // Takes over file reference from caller on success.
40224f6598Srsc static int
fdalloc(struct file * f)41224f6598Srsc fdalloc(struct file *f)
42224f6598Srsc {
43224f6598Srsc int fd;
44fbb4c094SFrans Kaashoek struct proc *curproc = myproc();
459583b476Srsc
46224f6598Srsc for(fd = 0; fd < NOFILE; fd++){
47fbb4c094SFrans Kaashoek if(curproc->ofile[fd] == 0){
48fbb4c094SFrans Kaashoek curproc->ofile[fd] = f;
49224f6598Srsc return fd;
50224f6598Srsc }
51224f6598Srsc }
52224f6598Srsc return -1;
53224f6598Srsc }
54224f6598Srsc
552685309fSrsc int
sys_dup(void)56f9a06440SRuss Cox sys_dup(void)
57f9a06440SRuss Cox {
58f9a06440SRuss Cox struct file *f;
59f9a06440SRuss Cox int fd;
60f9a06440SRuss Cox
61f9a06440SRuss Cox if(argfd(0, 0, &f) < 0)
62f9a06440SRuss Cox return -1;
63f9a06440SRuss Cox if((fd=fdalloc(f)) < 0)
64f9a06440SRuss Cox return -1;
65f9a06440SRuss Cox filedup(f);
66f9a06440SRuss Cox return fd;
67f9a06440SRuss Cox }
68f9a06440SRuss Cox
69f9a06440SRuss Cox int
sys_read(void)70eaea18cbSrsc sys_read(void)
712685309fSrsc {
72eaea18cbSrsc struct file *f;
73eaea18cbSrsc int n;
74666f58c7Srsc char *p;
752685309fSrsc
76666f58c7Srsc if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0)
772685309fSrsc return -1;
78666f58c7Srsc return fileread(f, p, n);
792685309fSrsc }
802685309fSrsc
812685309fSrsc int
sys_write(void)822685309fSrsc sys_write(void)
832685309fSrsc {
84224f6598Srsc struct file *f;
85224f6598Srsc int n;
86666f58c7Srsc char *p;
872685309fSrsc
88666f58c7Srsc if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0)
892685309fSrsc return -1;
90666f58c7Srsc return filewrite(f, p, n);
912685309fSrsc }
922685309fSrsc
932685309fSrsc int
sys_close(void)942685309fSrsc sys_close(void)
952685309fSrsc {
962685309fSrsc int fd;
97224f6598Srsc struct file *f;
982685309fSrsc
99224f6598Srsc if(argfd(0, &fd, &f) < 0)
1002685309fSrsc return -1;
101abf847a0SFrans Kaashoek myproc()->ofile[fd] = 0;
102224f6598Srsc fileclose(f);
1032685309fSrsc return 0;
1042685309fSrsc }
1052685309fSrsc
1068d2e9a48Srsc int
sys_fstat(void)1078d2e9a48Srsc sys_fstat(void)
1088d2e9a48Srsc {
1098d2e9a48Srsc struct file *f;
1108d2e9a48Srsc struct stat *st;
1118d2e9a48Srsc
1128d2e9a48Srsc if(argfd(0, 0, &f) < 0 || argptr(1, (void*)&st, sizeof(*st)) < 0)
1138d2e9a48Srsc return -1;
1148d2e9a48Srsc return filestat(f, st);
1158d2e9a48Srsc }
1168d2e9a48Srsc
117eaea18cbSrsc // Create the path new as a link to the same inode as old.
118eaea18cbSrsc int
sys_link(void)119eaea18cbSrsc sys_link(void)
120eaea18cbSrsc {
121eaea18cbSrsc char name[DIRSIZ], *new, *old;
122eaea18cbSrsc struct inode *dp, *ip;
123eaea18cbSrsc
124eaea18cbSrsc if(argstr(0, &old) < 0 || argstr(1, &new) < 0)
125eaea18cbSrsc return -1;
1265053dd6aSRobert Morris
12771453f72SRobert Morris begin_op();
1282c565472SRobert Morris if((ip = namei(old)) == 0){
12971453f72SRobert Morris end_op();
1302c565472SRobert Morris return -1;
1312c565472SRobert Morris }
1325053dd6aSRobert Morris
13307090dd7Srsc ilock(ip);
134eaea18cbSrsc if(ip->type == T_DIR){
13507090dd7Srsc iunlockput(ip);
13671453f72SRobert Morris end_op();
137eaea18cbSrsc return -1;
138eaea18cbSrsc }
1392e590463SRobert Morris
140eaea18cbSrsc ip->nlink++;
141eaea18cbSrsc iupdate(ip);
14207090dd7Srsc iunlock(ip);
143eaea18cbSrsc
14407090dd7Srsc if((dp = nameiparent(new, name)) == 0)
14507090dd7Srsc goto bad;
14607090dd7Srsc ilock(dp);
147f3685aa3Srsc if(dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0){
148f3685aa3Srsc iunlockput(dp);
14907090dd7Srsc goto bad;
150f3685aa3Srsc }
15107090dd7Srsc iunlockput(dp);
15207090dd7Srsc iput(ip);
1532e590463SRobert Morris
15471453f72SRobert Morris end_op();
1552e590463SRobert Morris
15607090dd7Srsc return 0;
15707090dd7Srsc
15807090dd7Srsc bad:
15907090dd7Srsc ilock(ip);
160eaea18cbSrsc ip->nlink--;
161eaea18cbSrsc iupdate(ip);
16207090dd7Srsc iunlockput(ip);
16371453f72SRobert Morris end_op();
164eaea18cbSrsc return -1;
165eaea18cbSrsc }
166eaea18cbSrsc
167eaea18cbSrsc // Is the directory dp empty except for "." and ".." ?
168eaea18cbSrsc static int
isdirempty(struct inode * dp)169eaea18cbSrsc isdirempty(struct inode *dp)
170eaea18cbSrsc {
171eaea18cbSrsc int off;
172eaea18cbSrsc struct dirent de;
173eaea18cbSrsc
174eaea18cbSrsc for(off=2*sizeof(de); off<dp->size; off+=sizeof(de)){
175eaea18cbSrsc if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
176eaea18cbSrsc panic("isdirempty: readi");
177eaea18cbSrsc if(de.inum != 0)
178eaea18cbSrsc return 0;
179eaea18cbSrsc }
180eaea18cbSrsc return 1;
181eaea18cbSrsc }
182eaea18cbSrsc
1838d2e9a48Srsc //PAGEBREAK!
184eaea18cbSrsc int
sys_unlink(void)185eaea18cbSrsc sys_unlink(void)
186eaea18cbSrsc {
187eaea18cbSrsc struct inode *ip, *dp;
188eaea18cbSrsc struct dirent de;
189eaea18cbSrsc char name[DIRSIZ], *path;
190eaea18cbSrsc uint off;
191eaea18cbSrsc
192eaea18cbSrsc if(argstr(0, &path) < 0)
193eaea18cbSrsc return -1;
1945053dd6aSRobert Morris
19571453f72SRobert Morris begin_op();
1962c565472SRobert Morris if((dp = nameiparent(path, name)) == 0){
19771453f72SRobert Morris end_op();
1982c565472SRobert Morris return -1;
1992c565472SRobert Morris }
2005053dd6aSRobert Morris
20107090dd7Srsc ilock(dp);
202eaea18cbSrsc
203eaea18cbSrsc // Cannot unlink "." or "..".
2044e015d81SAustin Clements if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0)
2054e015d81SAustin Clements goto bad;
206eaea18cbSrsc
2074e015d81SAustin Clements if((ip = dirlookup(dp, name, &off)) == 0)
2084e015d81SAustin Clements goto bad;
20907090dd7Srsc ilock(ip);
210eaea18cbSrsc
211eaea18cbSrsc if(ip->nlink < 1)
212eaea18cbSrsc panic("unlink: nlink < 1");
213eaea18cbSrsc if(ip->type == T_DIR && !isdirempty(ip)){
21407090dd7Srsc iunlockput(ip);
2154e015d81SAustin Clements goto bad;
216eaea18cbSrsc }
217eaea18cbSrsc
218eaea18cbSrsc memset(&de, 0, sizeof(de));
219eaea18cbSrsc if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
220eaea18cbSrsc panic("unlink: writei");
22115a26936Skolya if(ip->type == T_DIR){
22215a26936Skolya dp->nlink--;
22315a26936Skolya iupdate(dp);
22415a26936Skolya }
22507090dd7Srsc iunlockput(dp);
226eaea18cbSrsc
227eaea18cbSrsc ip->nlink--;
228eaea18cbSrsc iupdate(ip);
22907090dd7Srsc iunlockput(ip);
2302e590463SRobert Morris
23171453f72SRobert Morris end_op();
2322e590463SRobert Morris
233eaea18cbSrsc return 0;
2344e015d81SAustin Clements
2354e015d81SAustin Clements bad:
2364e015d81SAustin Clements iunlockput(dp);
23771453f72SRobert Morris end_op();
2384e015d81SAustin Clements return -1;
239eaea18cbSrsc }
240eaea18cbSrsc
241eaea18cbSrsc static struct inode*
create(char * path,short type,short major,short minor)242f3685aa3Srsc create(char *path, short type, short major, short minor)
243eaea18cbSrsc {
244eaea18cbSrsc struct inode *ip, *dp;
245eaea18cbSrsc char name[DIRSIZ];
246eaea18cbSrsc
24707090dd7Srsc if((dp = nameiparent(path, name)) == 0)
248eaea18cbSrsc return 0;
24907090dd7Srsc ilock(dp);
250eaea18cbSrsc
251*0581c37bSDan Cross if((ip = dirlookup(dp, name, 0)) != 0){
25207090dd7Srsc iunlockput(dp);
25307090dd7Srsc ilock(ip);
254f9a06440SRuss Cox if(type == T_FILE && ip->type == T_FILE)
255f9a06440SRuss Cox return ip;
25607090dd7Srsc iunlockput(ip);
257eaea18cbSrsc return 0;
258eaea18cbSrsc }
259eaea18cbSrsc
260f9a06440SRuss Cox if((ip = ialloc(dp->dev, type)) == 0)
261f9a06440SRuss Cox panic("create: ialloc");
262f9a06440SRuss Cox
26307090dd7Srsc ilock(ip);
264eaea18cbSrsc ip->major = major;
265eaea18cbSrsc ip->minor = minor;
266603deefcSrsc ip->nlink = 1;
267eaea18cbSrsc iupdate(ip);
268eaea18cbSrsc
269eaea18cbSrsc if(type == T_DIR){ // Create . and .. entries.
270eaea18cbSrsc dp->nlink++; // for ".."
271eaea18cbSrsc iupdate(dp);
272eaea18cbSrsc // No ip->nlink++ for ".": avoid cyclic ref count.
273eaea18cbSrsc if(dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0)
274e79b1659Srsc panic("create dots");
275eaea18cbSrsc }
276f3e87bc8Skolya
277f3685aa3Srsc if(dirlink(dp, name, ip->inum) < 0)
278f3685aa3Srsc panic("create: dirlink");
279f3e87bc8Skolya
28007090dd7Srsc iunlockput(dp);
2812e590463SRobert Morris
282eaea18cbSrsc return ip;
283eaea18cbSrsc }
284eaea18cbSrsc
2852685309fSrsc int
sys_open(void)2862685309fSrsc sys_open(void)
2872685309fSrsc {
288f32f3638Srsc char *path;
289f32f3638Srsc int fd, omode;
290224f6598Srsc struct file *f;
291f32f3638Srsc struct inode *ip;
2922685309fSrsc
293224f6598Srsc if(argstr(0, &path) < 0 || argint(1, &omode) < 0)
2942685309fSrsc return -1;
2952c565472SRobert Morris
29671453f72SRobert Morris begin_op();
2972c565472SRobert Morris
2982c565472SRobert Morris if(omode & O_CREATE){
2992e590463SRobert Morris ip = create(path, T_FILE, 0, 0);
3002c565472SRobert Morris if(ip == 0){
30171453f72SRobert Morris end_op();
302e2a620daSrsc return -1;
3032c565472SRobert Morris }
304eaea18cbSrsc } else {
3052c565472SRobert Morris if((ip = namei(path)) == 0){
30671453f72SRobert Morris end_op();
307eaea18cbSrsc return -1;
3082c565472SRobert Morris }
30907090dd7Srsc ilock(ip);
310f3685aa3Srsc if(ip->type == T_DIR && omode != O_RDONLY){
31107090dd7Srsc iunlockput(ip);
31271453f72SRobert Morris end_op();
3132685309fSrsc return -1;
3142685309fSrsc }
315eaea18cbSrsc }
3162685309fSrsc
317eaea18cbSrsc if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){
318eaea18cbSrsc if(f)
319224f6598Srsc fileclose(f);
32007090dd7Srsc iunlockput(ip);
32171453f72SRobert Morris end_op();
3222685309fSrsc return -1;
3232685309fSrsc }
32407090dd7Srsc iunlock(ip);
32571453f72SRobert Morris end_op();
3262685309fSrsc
327eaea18cbSrsc f->type = FD_INODE;
32807090dd7Srsc f->ip = ip;
329eaea18cbSrsc f->off = 0;
330e79b1659Srsc f->readable = !(omode & O_WRONLY);
331e79b1659Srsc f->writable = (omode & O_WRONLY) || (omode & O_RDWR);
332224f6598Srsc return fd;
3332685309fSrsc }
3342685309fSrsc
3352685309fSrsc int
sys_mkdir(void)336f9a06440SRuss Cox sys_mkdir(void)
337f9a06440SRuss Cox {
338f9a06440SRuss Cox char *path;
339f9a06440SRuss Cox struct inode *ip;
340f9a06440SRuss Cox
34171453f72SRobert Morris begin_op();
3422e590463SRobert Morris if(argstr(0, &path) < 0 || (ip = create(path, T_DIR, 0, 0)) == 0){
34371453f72SRobert Morris end_op();
344f9a06440SRuss Cox return -1;
3452e590463SRobert Morris }
346f9a06440SRuss Cox iunlockput(ip);
34771453f72SRobert Morris end_op();
348f9a06440SRuss Cox return 0;
349f9a06440SRuss Cox }
350f9a06440SRuss Cox
351f9a06440SRuss Cox int
sys_mknod(void)3522685309fSrsc sys_mknod(void)
3532685309fSrsc {
354eaea18cbSrsc struct inode *ip;
355224f6598Srsc char *path;
356aa6824abSrsc int major, minor;
3572685309fSrsc
35871453f72SRobert Morris begin_op();
3591ccb5a6fSPeter H. Froehlich if((argstr(0, &path)) < 0 ||
36007090dd7Srsc argint(1, &major) < 0 ||
36107090dd7Srsc argint(2, &minor) < 0 ||
3622e590463SRobert Morris (ip = create(path, T_DEV, major, minor)) == 0){
36371453f72SRobert Morris end_op();
3642685309fSrsc return -1;
3652e590463SRobert Morris }
36607090dd7Srsc iunlockput(ip);
36771453f72SRobert Morris end_op();
368224f6598Srsc return 0;
3692685309fSrsc }
3702685309fSrsc
3712685309fSrsc int
sys_chdir(void)3722685309fSrsc sys_chdir(void)
3732685309fSrsc {
374eaea18cbSrsc char *path;
3752685309fSrsc struct inode *ip;
376fbb4c094SFrans Kaashoek struct proc *curproc = myproc();
3772685309fSrsc
37871453f72SRobert Morris begin_op();
3792c565472SRobert Morris if(argstr(0, &path) < 0 || (ip = namei(path)) == 0){
38071453f72SRobert Morris end_op();
3812685309fSrsc return -1;
3822c565472SRobert Morris }
38307090dd7Srsc ilock(ip);
3842685309fSrsc if(ip->type != T_DIR){
38507090dd7Srsc iunlockput(ip);
38671453f72SRobert Morris end_op();
3872685309fSrsc return -1;
3882685309fSrsc }
38907090dd7Srsc iunlock(ip);
390fbb4c094SFrans Kaashoek iput(curproc->cwd);
39171453f72SRobert Morris end_op();
392fbb4c094SFrans Kaashoek curproc->cwd = ip;
3932685309fSrsc return 0;
3942685309fSrsc }
3952685309fSrsc
3962685309fSrsc int
sys_exec(void)3972685309fSrsc sys_exec(void)
3982685309fSrsc {
3994655d42eSRobert Morris char *path, *argv[MAXARG];
400f32f3638Srsc int i;
401f32f3638Srsc uint uargv, uarg;
4022685309fSrsc
40340889627SFrans Kaashoek if(argstr(0, &path) < 0 || argint(1, (int*)&uargv) < 0){
4042685309fSrsc return -1;
40540889627SFrans Kaashoek }
406eaea18cbSrsc memset(argv, 0, sizeof(argv));
4072685309fSrsc for(i=0;; i++){
408eaea18cbSrsc if(i >= NELEM(argv))
4092685309fSrsc return -1;
4109d59eb01SAustin Clements if(fetchint(uargv+4*i, (int*)&uarg) < 0)
411f32f3638Srsc return -1;
412f32f3638Srsc if(uarg == 0){
413f32f3638Srsc argv[i] = 0;
414f32f3638Srsc break;
4152685309fSrsc }
4169d59eb01SAustin Clements if(fetchstr(uarg, &argv[i]) < 0)
417f32f3638Srsc return -1;
418f32f3638Srsc }
419f32f3638Srsc return exec(path, argv);
420f32f3638Srsc }
421f32f3638Srsc
422eaea18cbSrsc int
sys_pipe(void)423eaea18cbSrsc sys_pipe(void)
424eaea18cbSrsc {
425eaea18cbSrsc int *fd;
426eaea18cbSrsc struct file *rf, *wf;
427eaea18cbSrsc int fd0, fd1;
428eaea18cbSrsc
429eaea18cbSrsc if(argptr(0, (void*)&fd, 2*sizeof(fd[0])) < 0)
430eaea18cbSrsc return -1;
4317834cca6Srsc if(pipealloc(&rf, &wf) < 0)
432eaea18cbSrsc return -1;
433eaea18cbSrsc fd0 = -1;
434eaea18cbSrsc if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){
435eaea18cbSrsc if(fd0 >= 0)
436abf847a0SFrans Kaashoek myproc()->ofile[fd0] = 0;
437eaea18cbSrsc fileclose(rf);
438eaea18cbSrsc fileclose(wf);
439eaea18cbSrsc return -1;
440eaea18cbSrsc }
441eaea18cbSrsc fd[0] = fd0;
442eaea18cbSrsc fd[1] = fd1;
443eaea18cbSrsc return 0;
444eaea18cbSrsc }
445