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