Annotation of prex/usr/server/fs/vfs/vfs_syscalls.c, Revision 1.1.1.1
1.1 nbrk 1: /*
2: * Copyright (c) 2005-2007, Kohsuke Ohtani
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: * 3. Neither the name of the author nor the names of any co-contributors
14: * may be used to endorse or promote products derived from this software
15: * without specific prior written permission.
16: *
17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27: * SUCH DAMAGE.
28: */
29:
30: /*
31: * vfs_syscalls.c - everything in this file is a routine implementing
32: * a VFS system call.
33: */
34:
35: #include <prex/prex.h>
36: #include <sys/stat.h>
37: #include <sys/vnode.h>
38: #include <sys/file.h>
39: #include <sys/mount.h>
40: #include <sys/dirent.h>
41: #include <sys/list.h>
42: #include <sys/buf.h>
43:
44: #include <limits.h>
45: #include <unistd.h>
46: #include <stdlib.h>
47: #include <string.h>
48: #include <stdio.h>
49: #include <errno.h>
50: #include <fcntl.h>
51:
52: #include "vfs.h"
53:
54: int
55: sys_open(char *path, int flags, mode_t mode, file_t *pfp)
56: {
57: vnode_t vp, dvp;
58: file_t fp;
59: char *filename;
60: int err;
61:
62: DPRINTF(VFSDB_SYSCALL, ("sys_open: path=%s flags=%x mode=%x\n",
63: path, flags, mode));
64:
65: flags = FFLAGS(flags);
66: if ((flags & (FREAD | FWRITE)) == 0)
67: return EINVAL;
68: if (flags & O_CREAT) {
69: err = namei(path, &vp);
70: if (err == ENOENT) {
71: /* Create new file. */
72: if ((err = lookup(path, &dvp, &filename)) != 0)
73: return err;
74: if (dvp->v_mount->m_flags & MNT_RDONLY) {
75: vput(dvp);
76: return EROFS;
77: }
78: mode &= ~S_IFMT;
79: mode |= S_IFREG;
80: err = VOP_CREATE(dvp, filename, mode);
81: vput(dvp);
82: if (err)
83: return err;
84: if ((err = namei(path, &vp)) != 0)
85: return err;
86: flags &= ~O_TRUNC;
87: } else if (err) {
88: return err;
89: } else {
90: /* File already exits */
91: if (flags & O_EXCL) {
92: vput(vp);
93: return EEXIST;
94: }
95: flags &= ~O_CREAT;
96: }
97: } else {
98: /* Open */
99: if ((err = namei(path, &vp)) != 0)
100: return err;
101: }
102: if ((flags & O_CREAT) == 0) {
103: if (flags & FWRITE || flags & O_TRUNC) {
104: if (vp->v_mount->m_flags & MNT_RDONLY) {
105: vput(vp);
106: return EROFS;
107: }
108: if (vp->v_type == VDIR) {
109: /* Openning directory with writable. */
110: vput(vp);
111: return EISDIR;
112: }
113: }
114: }
115: if (flags & O_TRUNC) {
116: if (!(flags & FWRITE) || (vp->v_type != VREG)) {
117: vput(vp);
118: return EINVAL;
119: }
120: }
121: /* Process truncate request */
122: if (flags & O_TRUNC) {
123: if ((err = VOP_TRUNCATE(vp)) != 0) {
124: vput(vp);
125: return err;
126: }
127: }
128: /* Setup file structure */
129: if (!(fp = malloc(sizeof(struct file)))) {
130: vput(vp);
131: return ENOMEM;
132: }
133: /* Request to file system */
134: if ((err = VOP_OPEN(vp, flags)) != 0) {
135: free(fp);
136: vput(vp);
137: return err;
138: }
139: memset(fp, 0, sizeof(struct file));
140: fp->f_vnode = vp;
141: fp->f_flags = flags;
142: fp->f_offset = 0;
143: fp->f_count = 1;
144: *pfp = fp;
145: vn_unlock(vp);
146: return 0;
147: }
148:
149: int
150: sys_close(file_t fp)
151: {
152: vnode_t vp;
153: int err;
154:
155: DPRINTF(VFSDB_SYSCALL, ("sys_close: fp=%x\n", (u_int)fp));
156:
157: vp = fp->f_vnode;
158: if (--fp->f_count > 0) {
159: vrele(vp);
160: return 0;
161: }
162: vn_lock(vp);
163: if ((err = VOP_CLOSE(vp, fp)) != 0) {
164: vn_unlock(vp);
165: return err;
166: }
167: vput(vp);
168: free(fp);
169: return 0;
170: }
171:
172: int
173: sys_read(file_t fp, void *buf, size_t size, size_t *count)
174: {
175: vnode_t vp;
176: int err;
177:
178: DPRINTF(VFSDB_SYSCALL, ("sys_read: fp=%x buf=%x size=%d\n",
179: (u_int)fp, (u_int)buf, size));
180:
181: if ((fp->f_flags & FREAD) == 0)
182: return EPERM;
183: if (size == 0) {
184: *count = 0;
185: return 0;
186: }
187: vp = fp->f_vnode;
188: vn_lock(vp);
189: err = VOP_READ(vp, fp, buf, size, count);
190: vn_unlock(vp);
191: return err;
192: }
193:
194: int
195: sys_write(file_t fp, void *buf, size_t size, size_t *count)
196: {
197: vnode_t vp;
198: int err;
199:
200: DPRINTF(VFSDB_SYSCALL, ("sys_write: fp=%x buf=%x size=%d\n",
201: (u_int)fp, (u_int)buf, size));
202:
203: if (size == 0) {
204: *count = 0;
205: return 0;
206: }
207: vp = fp->f_vnode;
208: vn_lock(vp);
209: err = VOP_WRITE(vp, fp, buf, size, count);
210: vn_unlock(vp);
211: return err;
212: }
213:
214: int
215: sys_lseek(file_t fp, off_t off, int type, off_t *origin)
216: {
217: vnode_t vp;
218:
219: DPRINTF(VFSDB_SYSCALL, ("sys_seek: fp=%x off=%d type=%d\n",
220: (u_int)fp, (u_int)off, type));
221:
222: vp = fp->f_vnode;
223: vn_lock(vp);
224: switch (type) {
225: case SEEK_SET:
226: if (off < 0)
227: off = 0;
228: if (off > (off_t)vp->v_size)
229: off = vp->v_size;
230: break;
231: case SEEK_CUR:
232: if (fp->f_offset + off > (off_t)vp->v_size)
233: off = vp->v_size;
234: else if (fp->f_offset + off < 0)
235: off = 0;
236: else
237: off = fp->f_offset + off;
238: break;
239: case SEEK_END:
240: if (off > 0)
241: off = vp->v_size;
242: else if ((int)vp->v_size + off < 0)
243: off = 0;
244: else
245: off = vp->v_size + off;
246: break;
247: default:
248: vn_unlock(vp);
249: return EINVAL;
250: }
251: /* Request to check the file offset */
252: if (VOP_SEEK(vp, fp, fp->f_offset, off) != 0) {
253: vn_unlock(vp);
254: return EINVAL;
255: }
256: *origin = off;
257: fp->f_offset = off;
258: vn_unlock(vp);
259: return 0;
260: }
261:
262: int
263: sys_ioctl(file_t fp, u_long request, void *buf)
264: {
265: vnode_t vp;
266: int err;
267:
268: DPRINTF(VFSDB_SYSCALL, ("sys_ioctl: fp=%x request=%x\n", fp, request));
269:
270: if ((fp->f_flags & (FREAD | FWRITE)) == 0)
271: return EBADF;
272:
273: vp = fp->f_vnode;
274: vn_lock(vp);
275: err = VOP_IOCTL(vp, fp, request, buf);
276: vn_unlock(vp);
277: return err;
278: }
279:
280: int
281: sys_fsync(file_t fp)
282: {
283: vnode_t vp;
284: int err;
285:
286: DPRINTF(VFSDB_SYSCALL, ("sys_fsync: fp=%x\n", fp));
287:
288: if ((fp->f_flags & FREAD) == 0)
289: return EBADF;
290:
291: vp = fp->f_vnode;
292: vn_lock(vp);
293: err = VOP_FSYNC(vp, fp);
294: vn_unlock(vp);
295: return err;
296: }
297:
298: int
299: sys_fstat(file_t fp, struct stat *st)
300: {
301: vnode_t vp;
302: int err = 0;
303:
304: DPRINTF(VFSDB_SYSCALL, ("sys_fstat: fp=%x\n", fp));
305:
306: vp = fp->f_vnode;
307: vn_lock(vp);
308: err = vn_stat(vp, st);
309: vn_unlock(vp);
310: return err;
311: }
312:
313: /*
314: * Return 0 if directory is empty
315: */
316: static int
317: check_dir_empty(char *path)
318: {
319: int err;
320: file_t fp;
321: struct dirent dir;
322:
323: if ((err = sys_opendir(path, &fp)) != 0)
324: return err;
325: do {
326: err = sys_readdir(fp, &dir);
327: if (err)
328: break;
329: } while (!strcmp(dir.d_name, ".") || !strcmp(dir.d_name, ".."));
330:
331: sys_closedir(fp);
332:
333: if (err == ENOENT)
334: return 0;
335: else if (err == 0)
336: return EEXIST;
337: return err;
338: }
339:
340: int
341: sys_opendir(char *path, file_t *file)
342: {
343: vnode_t dvp;
344: file_t fp;
345: int err;
346:
347: DPRINTF(VFSDB_SYSCALL, ("sys_opendir: path=%s\n", path));
348:
349: if ((err = sys_open(path, O_RDONLY, 0, &fp)) != 0)
350: return err;
351:
352: dvp = fp->f_vnode;
353: vn_lock(dvp);
354: if (dvp->v_type != VDIR) {
355: vn_unlock(dvp);
356: sys_close(fp);
357: return ENOTDIR;
358: }
359: vn_unlock(dvp);
360:
361: *file = fp;
362: return 0;
363: }
364:
365: int
366: sys_closedir(file_t fp)
367: {
368: vnode_t dvp;
369: int err;
370:
371: DPRINTF(VFSDB_SYSCALL, ("sys_closedir: fp=%x\n", fp));
372:
373: dvp = fp->f_vnode;
374: vn_lock(dvp);
375: if (dvp->v_type != VDIR) {
376: vn_unlock(dvp);
377: return EBADF;
378: }
379: vn_unlock(dvp);
380: err = sys_close(fp);
381: return err;
382: }
383:
384: int
385: sys_readdir(file_t fp, struct dirent *dir)
386: {
387: vnode_t dvp;
388: int err;
389:
390: DPRINTF(VFSDB_SYSCALL, ("sys_readdir: fp=%x\n", fp));
391:
392: dvp = fp->f_vnode;
393: vn_lock(dvp);
394: if (dvp->v_type != VDIR) {
395: vn_unlock(dvp);
396: return ENOTDIR;
397: }
398: err = VOP_READDIR(dvp, fp, dir);
399: vn_unlock(dvp);
400: return err;
401: }
402:
403: int
404: sys_rewinddir(file_t fp)
405: {
406: vnode_t dvp;
407:
408: dvp = fp->f_vnode;
409: vn_lock(dvp);
410: if (dvp->v_type != VDIR) {
411: vn_unlock(dvp);
412: return EINVAL;
413: }
414: fp->f_offset = 0;
415: vn_unlock(dvp);
416: return 0;
417: }
418:
419: int
420: sys_seekdir(file_t fp, long loc)
421: {
422: vnode_t dvp;
423:
424: dvp = fp->f_vnode;
425: vn_lock(dvp);
426: if (dvp->v_type != VDIR) {
427: vn_unlock(dvp);
428: return EINVAL;
429: }
430: fp->f_offset = (off_t)loc;
431: vn_unlock(dvp);
432: return 0;
433: }
434:
435: int
436: sys_telldir(file_t fp, long *loc)
437: {
438: vnode_t dvp;
439:
440: dvp = fp->f_vnode;
441: vn_lock(dvp);
442: if (dvp->v_type != VDIR) {
443: vn_unlock(dvp);
444: return EINVAL;
445: }
446: *loc = (long)fp->f_offset;
447: vn_unlock(dvp);
448: return 0;
449: }
450:
451: int
452: sys_mkdir(char *path, mode_t mode)
453: {
454: char *name;
455: vnode_t vp, dvp;
456: int err;
457:
458: DPRINTF(VFSDB_SYSCALL, ("sys_mkdir: path=%s mode=%d\n", path, mode));
459:
460: if ((err = namei(path, &vp)) == 0) {
461: /* File already exists */
462: vput(vp);
463: return EEXIST;
464: }
465: /* Notice: vp is invalid here! */
466:
467: if ((err = lookup(path, &dvp, &name)) != 0) {
468: /* Directory already exists */
469: return err;
470: }
471: if (dvp->v_mount->m_flags & MNT_RDONLY) {
472: err = EROFS;
473: goto out;
474: }
475: mode &= ~S_IFMT;
476: mode |= S_IFDIR;
477:
478: err = VOP_MKDIR(dvp, name, mode);
479: out:
480: vput(dvp);
481: return err;
482: }
483:
484: int
485: sys_rmdir(char *path)
486: {
487: vnode_t vp, dvp;
488: int err;
489: char *name;
490:
491: DPRINTF(VFSDB_SYSCALL, ("sys_rmdir: path=%s\n", path));
492:
493: if ((err = check_dir_empty(path)) != 0)
494: return err;
495: if ((err = namei(path, &vp)) != 0)
496: return err;
497:
498: if (vp->v_mount->m_flags & MNT_RDONLY) {
499: err = EROFS;
500: goto out;
501: }
502: if (vp->v_type != VDIR) {
503: err = ENOTDIR;
504: goto out;
505: }
506: if (vp->v_flags & VROOT || vcount(vp) >= 2) {
507: err = EBUSY;
508: goto out;
509: }
510: if ((err = lookup(path, &dvp, &name)) != 0)
511: goto out;
512:
513: err = VOP_RMDIR(dvp, vp, name);
514: vn_unlock(vp);
515: vgone(vp);
516: vput(dvp);
517: return err;
518:
519: out:
520: vput(vp);
521: return err;
522: }
523:
524: int
525: sys_mknod(char *path, mode_t mode)
526: {
527: char *name;
528: vnode_t vp, dvp;
529: int err;
530:
531: DPRINTF(VFSDB_SYSCALL, ("sys_mknod: path=%s mode=%d\n", path, mode));
532:
533: switch (mode & S_IFMT) {
534: case S_IFREG:
535: case S_IFDIR:
536: case S_IFIFO:
537: case S_IFSOCK:
538: /* OK */
539: break;
540: default:
541: return EINVAL;
542: }
543:
544: if ((err = namei(path, &vp)) == 0) {
545: vput(vp);
546: return EEXIST;
547: }
548:
549: if ((err = lookup(path, &dvp, &name)) != 0)
550: return err;
551:
552: if (dvp->v_mount->m_flags & MNT_RDONLY) {
553: err = EROFS;
554: goto out;
555: }
556: if (S_ISDIR(mode))
557: err = VOP_MKDIR(dvp, name, mode);
558: else
559: err = VOP_CREATE(dvp, name, mode);
560: out:
561: vput(dvp);
562: return err;
563: }
564:
565: int
566: sys_rename(char *src, char *dest)
567: {
568: vnode_t vp1, vp2 = 0, dvp1, dvp2;
569: char *sname, *dname;
570: int err;
571: size_t len;
572: char root[] = "/";
573:
574: DPRINTF(VFSDB_SYSCALL, ("sys_rename: src=%s dest=%s\n", src, dest));
575:
576: if ((err = namei(src, &vp1)) != 0)
577: return err;
578: if (vp1->v_mount->m_flags & MNT_RDONLY) {
579: err = EROFS;
580: goto err1;
581: }
582: /* If source and dest are the same, do nothing */
583: if (!strncmp(src, dest, PATH_MAX))
584: goto err1;
585:
586: /* Check if target is directory of source */
587: len = strlen(dest);
588: if (!strncmp(src, dest, len)) {
589: err = EINVAL;
590: goto err1;
591: }
592: /* Is the source busy ? */
593: if (vcount(vp1) >= 2) {
594: err = EBUSY;
595: goto err1;
596: }
597: /* Check type of source & target */
598: err = namei(dest, &vp2);
599: if (err == 0) {
600: /* target exists */
601: if (vp1->v_type == VDIR && vp2->v_type != VDIR) {
602: err = ENOTDIR;
603: goto err2;
604: } else if (vp1->v_type != VDIR && vp2->v_type == VDIR) {
605: err = EISDIR;
606: goto err2;
607: }
608: if (vp2->v_type == VDIR && check_dir_empty(dest)) {
609: err = EEXIST;
610: goto err2;
611: }
612:
613: if (vcount(vp2) >= 2) {
614: err = EBUSY;
615: goto err2;
616: }
617: }
618:
619: dname = strrchr(dest, '/');
620: if (dname == NULL) {
621: err = ENOTDIR;
622: goto err2;
623: }
624: if (dname == dest)
625: dest = root;
626:
627: *dname = 0;
628: dname++;
629:
630: if ((err = lookup(src, &dvp1, &sname)) != 0)
631: goto err2;
632:
633: if ((err = namei(dest, &dvp2)) != 0)
634: goto err3;
635:
636: /* The source and dest must be same file system */
637: if (dvp1->v_mount != dvp2->v_mount) {
638: err = EXDEV;
639: goto err4;
640: }
641: err = VOP_RENAME(dvp1, vp1, sname, dvp2, vp2, dname);
642: err4:
643: vput(dvp2);
644: err3:
645: vput(dvp1);
646: err2:
647: if (vp2)
648: vput(vp2);
649: err1:
650: vput(vp1);
651: return err;
652: }
653:
654: int
655: sys_unlink(char *path)
656: {
657: char *name;
658: vnode_t vp, dvp;
659: int err;
660:
661: DPRINTF(VFSDB_SYSCALL, ("sys_unlink: path=%s\n", path));
662:
663: if ((err = namei(path, &vp)) != 0)
664: return err;
665:
666: if (vp->v_mount->m_flags & MNT_RDONLY) {
667: err = EROFS;
668: goto out;
669: }
670: if (vp->v_type == VDIR) {
671: err = EPERM;
672: goto out;
673: }
674: if (vp->v_flags & VROOT || vcount(vp) >= 2) {
675: err = EBUSY;
676: goto out;
677: }
678: if ((err = lookup(path, &dvp, &name)) != 0)
679: goto out;
680:
681: err = VOP_REMOVE(dvp, vp, name);
682:
683: vn_unlock(vp);
684: vgone(vp);
685: vput(dvp);
686: return 0;
687: out:
688: vput(vp);
689: return err;
690: }
691:
692: int
693: sys_access(char *path, int mode)
694: {
695: vnode_t vp;
696: int err;
697:
698: DPRINTF(VFSDB_SYSCALL, ("sys_access: path=%s\n", path));
699:
700: if ((err = namei(path, &vp)) != 0)
701: return err;
702:
703: err = EACCES;
704: if ((mode & X_OK) && (vp->v_mode & 0111) == 0)
705: goto out;
706: if ((mode & W_OK) && (vp->v_mode & 0222) == 0)
707: goto out;
708: if ((mode & R_OK) && (vp->v_mode & 0444) == 0)
709: goto out;
710: err = 0;
711: out:
712: vput(vp);
713: return err;
714: }
715:
716: int
717: sys_stat(char *path, struct stat *st)
718: {
719: vnode_t vp;
720: int err;
721:
722: if ((err = namei(path, &vp)) != 0)
723: return err;
724: err = vn_stat(vp, st);
725: vput(vp);
726: return err;
727: }
CVSweb