Annotation of prex-old/usr/server/fs/vfs/vfs_syscalls.c, Revision 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: * 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 *file)
! 56: {
! 57: vnode_t vp, dvp;
! 58: file_t fp;
! 59: char *filename;
! 60: int err;
! 61:
! 62: dprintf("sys_open: path=%s flags=%x mode=%x\n", path, flags, mode);
! 63:
! 64: flags = FFLAGS(flags);
! 65: if (flags & O_CREAT) {
! 66: err = namei(path, &vp);
! 67: if (err == ENOENT) {
! 68: /* Create new file. */
! 69: if ((err = lookup(path, &dvp, &filename)) != 0)
! 70: return err;
! 71: if (dvp->v_mount->m_flags & MNT_RDONLY) {
! 72: vput(dvp);
! 73: return EROFS;
! 74: }
! 75: mode &= ~S_IFMT;
! 76: mode |= S_IFREG;
! 77: err = VOP_CREATE(dvp, filename, mode);
! 78: vput(dvp);
! 79: if (err)
! 80: return err;
! 81: if ((err = namei(path, &vp)) != 0)
! 82: return err;
! 83: flags &= ~O_TRUNC;
! 84: } else if (err) {
! 85: return err;
! 86: } else {
! 87: /* File already exits */
! 88: if (flags & O_EXCL) {
! 89: vput(vp);
! 90: return EEXIST;
! 91: }
! 92: flags &= ~O_CREAT;
! 93: }
! 94: } else {
! 95: /* Open */
! 96: if ((err = namei(path, &vp)) != 0)
! 97: return err;
! 98: }
! 99: if ((flags & O_CREAT) == 0) {
! 100: if (flags & FWRITE || flags & O_TRUNC) {
! 101: if (vp->v_mount->m_flags & MNT_RDONLY) {
! 102: vput(vp);
! 103: return EROFS;
! 104: }
! 105: if (vp->v_type == VDIR) {
! 106: /* Openning directory with writable. */
! 107: vput(vp);
! 108: return EISDIR;
! 109: }
! 110: }
! 111: }
! 112: if (flags & O_TRUNC) {
! 113: if (!(flags & FWRITE) || (vp->v_type != VREG)) {
! 114: vput(vp);
! 115: return EINVAL;
! 116: }
! 117: }
! 118: /* Process truncate request */
! 119: if (flags & O_TRUNC) {
! 120: if ((err = VOP_TRUNCATE(vp)) != 0) {
! 121: vput(vp);
! 122: return err;
! 123: }
! 124: }
! 125: /* Setup file structure */
! 126: if (!(fp = malloc(sizeof(struct file)))) {
! 127: vput(vp);
! 128: return ENOMEM;
! 129: }
! 130: /* Request to file system */
! 131: if ((err = VOP_OPEN(vp, mode)) != 0) {
! 132: free(fp);
! 133: vput(vp);
! 134: return err;
! 135: }
! 136: memset(fp, 0, sizeof(struct file));
! 137: fp->f_vnode = vp;
! 138: fp->f_flags = flags;
! 139: fp->f_offset = 0;
! 140: fp->f_count = 1;
! 141: *file = fp;
! 142: vn_unlock(vp);
! 143: return 0;
! 144: }
! 145:
! 146: int
! 147: sys_close(file_t fp)
! 148: {
! 149: vnode_t vp;
! 150: int err;
! 151:
! 152: dprintf("sys_close: fp=%x\n", (u_int)fp);
! 153:
! 154: vp = fp->f_vnode;
! 155: if (--fp->f_count > 0) {
! 156: vrele(vp);
! 157: return 0;
! 158: }
! 159: vn_lock(vp);
! 160: if ((err = VOP_CLOSE(vp, fp)) != 0) {
! 161: vn_unlock(vp);
! 162: return err;
! 163: }
! 164: vput(vp);
! 165: free(fp);
! 166: return 0;
! 167: }
! 168:
! 169: int
! 170: sys_read(file_t fp, void *buf, size_t size, size_t *count)
! 171: {
! 172: vnode_t vp;
! 173: int err;
! 174:
! 175: dprintf("sys_read: fp=%x buf=%x size=%d\n",
! 176: (u_int)fp, (u_int)buf, size);
! 177:
! 178: if ((fp->f_flags & FREAD) == 0)
! 179: return EPERM;
! 180: if (size == 0) {
! 181: *count = 0;
! 182: return 0;
! 183: }
! 184: vp = fp->f_vnode;
! 185: vn_lock(vp);
! 186: err = VOP_READ(vp, fp, buf, size, count);
! 187: vn_unlock(vp);
! 188: return err;
! 189: }
! 190:
! 191: int
! 192: sys_write(file_t fp, void *buf, size_t size, size_t *count)
! 193: {
! 194: vnode_t vp;
! 195: int err;
! 196:
! 197: dprintf("sys_write: fp=%x buf=%x size=%d\n",
! 198: (u_int)fp, (u_int)buf, size);
! 199:
! 200: if (size == 0) {
! 201: *count = 0;
! 202: return 0;
! 203: }
! 204: vp = fp->f_vnode;
! 205: vn_lock(vp);
! 206: err = VOP_WRITE(vp, fp, buf, size, count);
! 207: vn_unlock(vp);
! 208: return err;
! 209: }
! 210:
! 211: int
! 212: sys_lseek(file_t fp, off_t off, int type, off_t *origin)
! 213: {
! 214: vnode_t vp;
! 215:
! 216: dprintf("sys_seek: fp=%x off=%d type=%d\n", (u_int)fp,
! 217: (u_int)off, type);
! 218:
! 219: vp = fp->f_vnode;
! 220: vn_lock(vp);
! 221: switch (type) {
! 222: case SEEK_SET:
! 223: if (off < 0)
! 224: off = 0;
! 225: if (off > (off_t)vp->v_size)
! 226: off = vp->v_size;
! 227: break;
! 228: case SEEK_CUR:
! 229: if (fp->f_offset + off > (off_t)vp->v_size)
! 230: off = vp->v_size;
! 231: else if (fp->f_offset + off < 0)
! 232: off = 0;
! 233: else
! 234: off = fp->f_offset + off;
! 235: break;
! 236: case SEEK_END:
! 237: if (off > 0)
! 238: off = vp->v_size;
! 239: else if ((int)vp->v_size + off < 0)
! 240: off = 0;
! 241: else
! 242: off = vp->v_size + off;
! 243: break;
! 244: default:
! 245: vn_unlock(vp);
! 246: return EINVAL;
! 247: }
! 248: /* Request to check the file offset */
! 249: if (VOP_SEEK(vp, fp, fp->f_offset, off) != 0) {
! 250: vn_unlock(vp);
! 251: return EINVAL;
! 252: }
! 253: *origin = off;
! 254: fp->f_offset = off;
! 255: vn_unlock(vp);
! 256: return 0;
! 257: }
! 258:
! 259: int
! 260: sys_ioctl(file_t fp, int request, char *buf)
! 261: {
! 262: vnode_t vp;
! 263: int err;
! 264:
! 265: dprintf("sys_ioctl: fp=%x request=%x\n", fp, request);
! 266:
! 267: if ((fp->f_flags & (FREAD | FWRITE)) == 0)
! 268: return EBADF;
! 269:
! 270: vp = fp->f_vnode;
! 271: vn_lock(vp);
! 272: err = VOP_IOCTL(vp, fp, request, (u_long)buf);
! 273: vn_unlock(vp);
! 274: return err;
! 275: }
! 276:
! 277: int
! 278: sys_fsync(file_t fp)
! 279: {
! 280: vnode_t vp;
! 281: int err;
! 282:
! 283: dprintf("sys_fsync: fp=%x\n", fp);
! 284:
! 285: if ((fp->f_flags & FREAD) == 0)
! 286: return EBADF;
! 287:
! 288: vp = fp->f_vnode;
! 289: vn_lock(vp);
! 290: err = VOP_FSYNC(vp, fp);
! 291: vn_unlock(vp);
! 292: return err;
! 293: }
! 294:
! 295: int
! 296: sys_fstat(file_t fp, struct stat *st)
! 297: {
! 298: vnode_t vp;
! 299: mode_t mode;
! 300:
! 301: dprintf("sys_fstat: fp=%x\n", fp);
! 302:
! 303: memset(st, 0, sizeof(struct stat));
! 304:
! 305: vp = fp->f_vnode;
! 306: vn_lock(vp);
! 307: st->st_ino = (ino_t)&vp;
! 308: st->st_size = vp->v_size;
! 309: mode = vp->v_mode;
! 310: switch (vp->v_type) {
! 311: case VREG:
! 312: mode |= S_IFREG;
! 313: break;
! 314: case VDIR:
! 315: mode |= S_IFDIR;
! 316: break;
! 317: case VBLK:
! 318: mode |= S_IFBLK;
! 319: break;
! 320: case VCHR:
! 321: mode |= S_IFCHR;
! 322: break;
! 323: case VLNK:
! 324: mode |= S_IFLNK;
! 325: break;
! 326: case VSOCK:
! 327: mode |= S_IFSOCK;
! 328: break;
! 329: case VFIFO:
! 330: mode |= S_IFIFO;
! 331: break;
! 332: default:
! 333: return EBADF;
! 334: };
! 335: st->st_mode = mode;
! 336: st->st_blksize = BSIZE;
! 337: st->st_blocks = vp->v_size / S_BLKSIZE;
! 338: st->st_uid = 0;
! 339: st->st_gid = 0;
! 340: if (vp->v_type == VCHR || vp->v_type == VBLK)
! 341: st->st_rdev = (dev_t)vp->v_data;
! 342: vn_unlock(vp);
! 343: return 0;
! 344: }
! 345:
! 346: /*
! 347: * Return 0 if directory is empty
! 348: */
! 349: static int
! 350: check_dir_empty(char *path)
! 351: {
! 352: int err;
! 353: file_t fp;
! 354: struct dirent dir;
! 355:
! 356: if ((err = sys_opendir(path, &fp)) != 0)
! 357: return err;
! 358: do {
! 359: err = sys_readdir(fp, &dir);
! 360: if (err)
! 361: break;
! 362: } while (!strcmp(dir.d_name, ".") || !strcmp(dir.d_name, ".."));
! 363:
! 364: sys_closedir(fp);
! 365:
! 366: if (err == ENOENT)
! 367: return 0;
! 368: else if (err == 0)
! 369: return EEXIST;
! 370: return err;
! 371: }
! 372:
! 373: int
! 374: sys_opendir(char *path, file_t *file)
! 375: {
! 376: vnode_t dvp;
! 377: file_t fp;
! 378: int err;
! 379:
! 380: dprintf("sys_opendir: path=%s\n", path);
! 381:
! 382: if ((err = sys_open(path, O_RDONLY, 0, &fp)) != 0)
! 383: return err;
! 384:
! 385: dvp = fp->f_vnode;
! 386: vn_lock(dvp);
! 387: if (dvp->v_type != VDIR) {
! 388: vn_unlock(dvp);
! 389: sys_close(fp);
! 390: return ENOTDIR;
! 391: }
! 392: vn_unlock(dvp);
! 393:
! 394: *file = fp;
! 395: return 0;
! 396: }
! 397:
! 398: int
! 399: sys_closedir(file_t fp)
! 400: {
! 401: vnode_t dvp;
! 402: int err;
! 403:
! 404: dprintf("sys_closedir: fp=%x\n", fp);
! 405:
! 406: dvp = fp->f_vnode;
! 407: vn_lock(dvp);
! 408: if (dvp->v_type != VDIR) {
! 409: vn_unlock(dvp);
! 410: return EBADF;
! 411: }
! 412: vn_unlock(dvp);
! 413: err = sys_close(fp);
! 414: return err;
! 415: }
! 416:
! 417: int
! 418: sys_readdir(file_t fp, struct dirent *dir)
! 419: {
! 420: vnode_t dvp;
! 421: int err;
! 422:
! 423: dprintf("sys_readdir: fp=%x\n", fp);
! 424:
! 425: dvp = fp->f_vnode;
! 426: vn_lock(dvp);
! 427: if (dvp->v_type != VDIR) {
! 428: vn_unlock(dvp);
! 429: return ENOTDIR;
! 430: }
! 431: err = VOP_READDIR(dvp, fp, dir);
! 432: vn_unlock(dvp);
! 433: return err;
! 434: }
! 435:
! 436: int
! 437: sys_rewinddir(file_t fp)
! 438: {
! 439: vnode_t dvp;
! 440:
! 441: dvp = fp->f_vnode;
! 442: vn_lock(dvp);
! 443: if (dvp->v_type != VDIR) {
! 444: vn_unlock(dvp);
! 445: return EINVAL;
! 446: }
! 447: fp->f_offset = 0;
! 448: vn_unlock(dvp);
! 449: return 0;
! 450: }
! 451:
! 452: int
! 453: sys_seekdir(file_t fp, long loc)
! 454: {
! 455: vnode_t dvp;
! 456:
! 457: dvp = fp->f_vnode;
! 458: vn_lock(dvp);
! 459: if (dvp->v_type != VDIR) {
! 460: vn_unlock(dvp);
! 461: return EINVAL;
! 462: }
! 463: fp->f_offset = (off_t)loc;
! 464: vn_unlock(dvp);
! 465: return 0;
! 466: }
! 467:
! 468: int
! 469: sys_telldir(file_t fp, long *loc)
! 470: {
! 471: vnode_t dvp;
! 472:
! 473: dvp = fp->f_vnode;
! 474: vn_lock(dvp);
! 475: if (dvp->v_type != VDIR) {
! 476: vn_unlock(dvp);
! 477: return EINVAL;
! 478: }
! 479: *loc = (long)fp->f_offset;
! 480: vn_unlock(dvp);
! 481: return 0;
! 482: }
! 483:
! 484: int
! 485: sys_mkdir(char *path, mode_t mode)
! 486: {
! 487: char *name;
! 488: vnode_t vp, dvp;
! 489: int err;
! 490:
! 491: dprintf("sys_mkdir: path=%s mode=%d\n", path, mode);
! 492:
! 493: if ((err = namei(path, &vp)) == 0) {
! 494: /* File already exists */
! 495: vput(vp);
! 496: return EEXIST;
! 497: }
! 498: /* Notice: vp is invalid here! */
! 499:
! 500: if ((err = lookup(path, &dvp, &name)) != 0) {
! 501: /* Directory already exists */
! 502: return err;
! 503: }
! 504: if (dvp->v_mount->m_flags & MNT_RDONLY) {
! 505: err = EROFS;
! 506: goto out;
! 507: }
! 508: mode &= ~S_IFMT;
! 509: mode |= S_IFDIR;
! 510:
! 511: err = VOP_MKDIR(dvp, name, mode);
! 512: out:
! 513: vput(dvp);
! 514: return err;
! 515: }
! 516:
! 517: int
! 518: sys_rmdir(char *path)
! 519: {
! 520: vnode_t vp, dvp;
! 521: int err;
! 522: char *name;
! 523:
! 524: dprintf("sys_rmdir: path=%s\n", path);
! 525:
! 526: if ((err = check_dir_empty(path)) != 0)
! 527: return err;
! 528: if ((err = namei(path, &vp)) != 0)
! 529: return err;
! 530:
! 531: if (vp->v_mount->m_flags & MNT_RDONLY) {
! 532: err = EROFS;
! 533: goto out;
! 534: }
! 535: if (vp->v_type != VDIR) {
! 536: err = ENOTDIR;
! 537: goto out;
! 538: }
! 539: if (vp->v_flags & VROOT || vcount(vp) >= 2) {
! 540: err = EBUSY;
! 541: goto out;
! 542: }
! 543: if ((err = lookup(path, &dvp, &name)) != 0)
! 544: goto out;
! 545:
! 546: err = VOP_RMDIR(dvp, vp, name);
! 547: vn_unlock(vp);
! 548: vgone(vp);
! 549: vput(dvp);
! 550: return err;
! 551:
! 552: out:
! 553: vput(vp);
! 554: return err;
! 555: }
! 556:
! 557: int
! 558: sys_mknod(char *path, mode_t mode)
! 559: {
! 560: char *name;
! 561: vnode_t vp, dvp;
! 562: int err;
! 563:
! 564: dprintf("sys_mknod: path=%s mode=%d\n", path, mode);
! 565:
! 566: if ((err = namei(path, &vp)) == 0) {
! 567: vput(vp);
! 568: return EEXIST;
! 569: }
! 570:
! 571: if ((err = lookup(path, &dvp, &name)) != 0)
! 572: return err;
! 573:
! 574: if (S_ISDIR(mode))
! 575: err = VOP_MKDIR(dvp, name, mode);
! 576: else
! 577: err = VOP_CREATE(dvp, name, mode);
! 578:
! 579: vput(dvp);
! 580: return err;
! 581: }
! 582:
! 583: int
! 584: sys_rename(char *src, char *dest)
! 585: {
! 586: vnode_t vp1, vp2 = 0, dvp1, dvp2;
! 587: char *sname, *dname;
! 588: int err;
! 589: size_t len;
! 590: char root[] = "/";
! 591:
! 592: dprintf("sys_rename: src=%s dest=%s\n", src, dest);
! 593:
! 594: if ((err = namei(src, &vp1)) != 0)
! 595: return err;
! 596: if (vp1->v_mount->m_flags & MNT_RDONLY) {
! 597: err = EROFS;
! 598: goto err1;
! 599: }
! 600: /* If source and dest are the same, do nothing */
! 601: if (!strncmp(src, dest, PATH_MAX))
! 602: goto err1;
! 603:
! 604: /* Check if target is directory of source */
! 605: len = strlen(dest);
! 606: if (!strncmp(src, dest, len)) {
! 607: err = EINVAL;
! 608: goto err1;
! 609: }
! 610: /* Is the source busy ? */
! 611: if (vcount(vp1) >= 2) {
! 612: err = EBUSY;
! 613: goto err1;
! 614: }
! 615: /* Check type of source & target */
! 616: err = namei(dest, &vp2);
! 617: if (err == 0) {
! 618: /* target exists */
! 619: if (vp1->v_type == VDIR && vp2->v_type != VDIR) {
! 620: err = ENOTDIR;
! 621: goto err2;
! 622: } else if (vp1->v_type != VDIR && vp2->v_type == VDIR) {
! 623: err = EISDIR;
! 624: goto err2;
! 625: }
! 626: if (vp2->v_type == VDIR && check_dir_empty(dest)) {
! 627: err = EEXIST;
! 628: goto err2;
! 629: }
! 630:
! 631: if (vcount(vp2) >= 2) {
! 632: err = EBUSY;
! 633: goto err2;
! 634: }
! 635: }
! 636:
! 637: dname = strrchr(dest, '/');
! 638: if (dname == NULL) {
! 639: err = ENOTDIR;
! 640: goto err2;
! 641: }
! 642: if (dname == dest)
! 643: dest = root;
! 644:
! 645: *dname = 0;
! 646: dname++;
! 647:
! 648: if ((err = lookup(src, &dvp1, &sname)) != 0)
! 649: goto err2;
! 650:
! 651: if ((err = namei(dest, &dvp2)) != 0)
! 652: goto err3;
! 653:
! 654: /* The source and dest must be same file system */
! 655: if (dvp1->v_mount != dvp2->v_mount) {
! 656: err = EXDEV;
! 657: goto err4;
! 658: }
! 659: err = VOP_RENAME(dvp1, vp1, sname, dvp2, vp2, dname);
! 660: err4:
! 661: vput(dvp2);
! 662: err3:
! 663: vput(dvp1);
! 664: err2:
! 665: if (vp2)
! 666: vput(vp2);
! 667: err1:
! 668: vput(vp1);
! 669: return err;
! 670: }
! 671:
! 672: int
! 673: sys_unlink(char *path)
! 674: {
! 675: char *name;
! 676: vnode_t vp, dvp;
! 677: int err;
! 678:
! 679: dprintf("sys_unlink: path=%s\n", path);
! 680:
! 681: if ((err = namei(path, &vp)) != 0)
! 682: return err;
! 683:
! 684: if (vp->v_mount->m_flags & MNT_RDONLY) {
! 685: err = EROFS;
! 686: goto out;
! 687: }
! 688: if (vp->v_type == VDIR) {
! 689: err = EPERM;
! 690: goto out;
! 691: }
! 692: if (vp->v_flags & VROOT || vcount(vp) >= 2) {
! 693: err = EBUSY;
! 694: goto out;
! 695: }
! 696: if ((err = lookup(path, &dvp, &name)) != 0)
! 697: goto out;
! 698:
! 699: err = VOP_REMOVE(dvp, vp, name);
! 700:
! 701: vn_unlock(vp);
! 702: vgone(vp);
! 703: vput(dvp);
! 704: return 0;
! 705: out:
! 706: vput(vp);
! 707: return err;
! 708: }
! 709:
! 710: int
! 711: sys_access(char *path, int mode)
! 712: {
! 713: vnode_t vp;
! 714: int err;
! 715:
! 716: dprintf("sys_access: path=%s\n", path);
! 717:
! 718: if ((err = namei(path, &vp)) != 0)
! 719: return err;
! 720:
! 721: err = EACCES;
! 722: if ((mode & X_OK) && (vp->v_mode & 0111) == 0)
! 723: goto out;
! 724: if ((mode & W_OK) && (vp->v_mode & 0222) == 0)
! 725: goto out;
! 726: if ((mode & R_OK) && (vp->v_mode & 0444) == 0)
! 727: goto out;
! 728: err = 0;
! 729: out:
! 730: vput(vp);
! 731: return err;
! 732: }
CVSweb