Prex Home / Browse Source - Prex Version: 0.9.0

root/usr/server/fs/vfs/vfs_syscalls.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sys_open
  2. sys_close
  3. sys_read
  4. sys_write
  5. sys_lseek
  6. sys_ioctl
  7. sys_fsync
  8. sys_fstat
  9. check_dir_empty
  10. sys_opendir
  11. sys_closedir
  12. sys_readdir
  13. sys_rewinddir
  14. sys_seekdir
  15. sys_telldir
  16. sys_mkdir
  17. sys_rmdir
  18. sys_mknod
  19. sys_rename
  20. sys_unlink
  21. sys_access
  22. sys_stat
  23. sys_truncate
  24. sys_ftruncate
  25. sys_fchdir

   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] */