1 /* $NetBSD: v7fs_vnops.c,v 1.31 2020/06/27 17:29:18 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2004, 2011 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by UCHIYAMA Yasushi. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: v7fs_vnops.c,v 1.31 2020/06/27 17:29:18 christos Exp $"); 34 #if defined _KERNEL_OPT 35 #include "opt_v7fs.h" 36 #endif 37 38 #include <sys/param.h> 39 #include <sys/kernel.h> 40 #include <sys/resource.h> 41 #include <sys/vnode.h> 42 #include <sys/namei.h> 43 #include <sys/dirent.h> 44 #include <sys/kmem.h> 45 #include <sys/lockf.h> 46 #include <sys/unistd.h> 47 #include <sys/fcntl.h> 48 #include <sys/kauth.h> 49 #include <sys/buf.h> 50 #include <sys/stat.h> /*APPEND */ 51 #include <miscfs/genfs/genfs.h> 52 53 #include <fs/v7fs/v7fs.h> 54 #include <fs/v7fs/v7fs_impl.h> 55 #include <fs/v7fs/v7fs_inode.h> 56 #include <fs/v7fs/v7fs_dirent.h> 57 #include <fs/v7fs/v7fs_file.h> 58 #include <fs/v7fs/v7fs_datablock.h> 59 #include <fs/v7fs/v7fs_extern.h> 60 61 #ifdef V7FS_VNOPS_DEBUG 62 #define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args) 63 #else 64 #define DPRINTF(arg...) ((void)0) 65 #endif 66 67 static v7fs_mode_t vtype_to_v7fs_mode(enum vtype); 68 static uint8_t v7fs_mode_to_d_type(v7fs_mode_t); 69 70 static v7fs_mode_t 71 vtype_to_v7fs_mode(enum vtype type) 72 { 73 /* Convert Vnode types to V7FS types (sys/vnode.h)*/ 74 v7fs_mode_t table[] = { 0, V7FS_IFREG, V7FS_IFDIR, V7FS_IFBLK, 75 V7FS_IFCHR, V7FSBSD_IFLNK, V7FSBSD_IFSOCK, 76 V7FSBSD_IFFIFO }; 77 return table[type]; 78 } 79 80 static uint8_t 81 v7fs_mode_to_d_type(v7fs_mode_t mode) 82 { 83 /* Convert V7FS types to dirent d_type (sys/dirent.h)*/ 84 85 return (mode & V7FS_IFMT) >> 12; 86 } 87 88 int 89 v7fs_lookup(void *v) 90 { 91 struct vop_lookup_v2_args /* { 92 struct vnode *a_dvp; 93 struct vnode **a_vpp; 94 struct componentname *a_cnp; 95 } */ *a = v; 96 struct vnode *dvp = a->a_dvp; 97 struct v7fs_node *parent_node = dvp->v_data; 98 struct v7fs_inode *parent = &parent_node->inode; 99 struct v7fs_self *fs = parent_node->v7fsmount->core;/* my filesystem */ 100 struct vnode *vpp; 101 struct componentname *cnp = a->a_cnp; 102 int nameiop = cnp->cn_nameiop; 103 const char *name = cnp->cn_nameptr; 104 int namelen = cnp->cn_namelen; 105 int flags = cnp->cn_flags; 106 bool isdotdot = flags & ISDOTDOT; 107 bool islastcn = flags & ISLASTCN; 108 v7fs_ino_t ino; 109 int error; 110 #ifdef V7FS_VNOPS_DEBUG 111 const char *opname[] = { "LOOKUP", "CREATE", "DELETE", "RENAME" }; 112 #endif 113 DPRINTF("'%s' op=%s flags=%d parent=%d %o %dbyte\n", name, 114 opname[nameiop], cnp->cn_flags, parent->inode_number, parent->mode, 115 parent->filesize); 116 117 *a->a_vpp = 0; 118 119 /* Check directory permission for search */ 120 if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred))) { 121 DPRINTF("***perm.\n"); 122 return error; 123 } 124 125 /* Deny last component write operation on a read-only mount */ 126 if (islastcn && (dvp->v_mount->mnt_flag & MNT_RDONLY) && 127 (nameiop == DELETE || nameiop == RENAME)) { 128 DPRINTF("***ROFS.\n"); 129 return EROFS; 130 } 131 132 /* No lookup on removed directory */ 133 if (v7fs_inode_nlink(parent) == 0) 134 return ENOENT; 135 136 /* "." */ 137 if (namelen == 1 && name[0] == '.') { 138 if ((nameiop == RENAME) && islastcn) { 139 return EISDIR; /* t_vnops rename_dir(3) */ 140 } 141 vref(dvp); /* usecount++ */ 142 *a->a_vpp = dvp; 143 DPRINTF("done.(.)\n"); 144 return 0; 145 } 146 147 /* ".." and reguler file. */ 148 if ((error = v7fs_file_lookup_by_name(fs, parent, name, &ino))) { 149 /* Not found. Tell this entry be able to allocate. */ 150 if (((nameiop == CREATE) || (nameiop == RENAME)) && islastcn) { 151 /* Check directory permission to allocate. */ 152 if ((error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred))) { 153 DPRINTF("access denied. (%s)\n", name); 154 return error; 155 } 156 DPRINTF("EJUSTRETURN op=%d (%s)\n", nameiop, name); 157 return EJUSTRETURN; 158 } 159 DPRINTF("lastcn=%d\n", flags & ISLASTCN); 160 return error; 161 } 162 163 if ((nameiop == DELETE) && islastcn) { 164 if ((error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred))) { 165 DPRINTF("access denied. (%s)\n", name); 166 return error; 167 } 168 } 169 170 /* Entry found. Allocate v-node */ 171 // Check permissions? 172 vpp = 0; 173 if (isdotdot) { 174 VOP_UNLOCK(dvp); /* preserve reference count. (not vput) */ 175 } 176 DPRINTF("enter vget\n"); 177 error = v7fs_vget(dvp->v_mount, ino, LK_EXCLUSIVE, &vpp); 178 if (error != 0) { 179 DPRINTF("***can't get vnode.\n"); 180 return error; 181 } 182 DPRINTF("exit vget\n"); 183 if (isdotdot) { 184 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); 185 } 186 if (vpp != dvp) 187 VOP_UNLOCK(vpp); 188 *a->a_vpp = vpp; 189 DPRINTF("done.(%s)\n", name); 190 191 return 0; 192 } 193 194 int 195 v7fs_create(void *v) 196 { 197 struct vop_create_v3_args /* { 198 struct vnode *a_dvp; 199 struct vnode **a_vpp; 200 struct componentname *a_cnp; 201 struct vattr *a_vap; 202 } */ *a = v; 203 struct v7fs_node *parent_node = a->a_dvp->v_data; 204 struct v7fs_mount *v7fsmount = parent_node->v7fsmount; 205 struct v7fs_self *fs = v7fsmount->core; 206 struct mount *mp = v7fsmount->mountp; 207 struct v7fs_fileattr attr; 208 struct vattr *va = a->a_vap; 209 kauth_cred_t cr = a->a_cnp->cn_cred; 210 v7fs_ino_t ino; 211 int error = 0; 212 213 DPRINTF("%s parent#%d\n", a->a_cnp->cn_nameptr, 214 parent_node->inode.inode_number); 215 KDASSERT((va->va_type == VREG) || (va->va_type == VSOCK)); 216 217 memset(&attr, 0, sizeof(attr)); 218 attr.uid = kauth_cred_geteuid(cr); 219 attr.gid = kauth_cred_getegid(cr); 220 attr.mode = va->va_mode | vtype_to_v7fs_mode (va->va_type); 221 attr.device = 0; 222 223 /* Allocate disk entry. and register its entry to parent directory. */ 224 if ((error = v7fs_file_allocate(fs, &parent_node->inode, 225 a->a_cnp->cn_nameptr, &attr, &ino))) { 226 DPRINTF("v7fs_file_allocate failed.\n"); 227 return error; 228 } 229 /* Sync dirent size change. */ 230 uvm_vnp_setsize(a->a_dvp, v7fs_inode_filesize(&parent_node->inode)); 231 232 /* Get myself vnode. */ 233 *a->a_vpp = 0; 234 error = v7fs_vget(mp, ino, LK_EXCLUSIVE, a->a_vpp); 235 if (error != 0) { 236 DPRINTF("v7fs_vget failed.\n"); 237 return error; 238 } 239 240 /* Scheduling update time. real update by v7fs_update */ 241 struct v7fs_node *newnode = (*a->a_vpp)->v_data; 242 newnode->update_ctime = true; 243 newnode->update_mtime = true; 244 newnode->update_atime = true; 245 DPRINTF("allocated %s->#%d\n", a->a_cnp->cn_nameptr, ino); 246 247 if (error == 0) 248 VOP_UNLOCK(*a->a_vpp); 249 250 return error; 251 } 252 253 int 254 v7fs_mknod(void *v) 255 { 256 struct vop_mknod_v3_args /* { 257 struct vnode *a_dvp; 258 struct vnode **a_vpp; 259 struct componentname *a_cnp; 260 struct vattr *a_vap; 261 } */ *a = v; 262 struct componentname *cnp = a->a_cnp; 263 kauth_cred_t cr = cnp->cn_cred; 264 struct vnode *dvp = a->a_dvp; 265 struct vattr *va = a->a_vap; 266 struct v7fs_node *parent_node = dvp->v_data; 267 struct v7fs_mount *v7fsmount = parent_node->v7fsmount; 268 struct v7fs_self *fs = v7fsmount->core; 269 struct mount *mp = v7fsmount->mountp; 270 struct v7fs_fileattr attr; 271 272 v7fs_ino_t ino; 273 int error = 0; 274 275 DPRINTF("%s %06o %lx %d\n", cnp->cn_nameptr, va->va_mode, 276 (long)va->va_rdev, va->va_type); 277 memset(&attr, 0, sizeof(attr)); 278 attr.uid = kauth_cred_geteuid(cr); 279 attr.gid = kauth_cred_getegid(cr); 280 attr.mode = va->va_mode | vtype_to_v7fs_mode(va->va_type); 281 attr.device = va->va_rdev; 282 283 if ((error = v7fs_file_allocate(fs, &parent_node->inode, 284 cnp->cn_nameptr, &attr, &ino))) 285 return error; 286 /* Sync dirent size change. */ 287 uvm_vnp_setsize(dvp, v7fs_inode_filesize(&parent_node->inode)); 288 289 error = v7fs_vget(mp, ino, LK_EXCLUSIVE, a->a_vpp); 290 if (error != 0) { 291 DPRINTF("can't get vnode.\n"); 292 return error; 293 } 294 struct v7fs_node *newnode = (*a->a_vpp)->v_data; 295 newnode->update_ctime = true; 296 newnode->update_mtime = true; 297 newnode->update_atime = true; 298 299 if (error == 0) 300 VOP_UNLOCK(*a->a_vpp); 301 302 return error; 303 } 304 305 int 306 v7fs_open(void *v) 307 { 308 struct vop_open_args /* { 309 struct vnode *a_vp; 310 int a_mode; 311 kauth_cred_t a_cred; 312 } */ *a = v; 313 314 struct vnode *vp = a->a_vp; 315 struct v7fs_node *v7node = vp->v_data; 316 struct v7fs_inode *inode = &v7node->inode; 317 318 DPRINTF("inode %d\n", inode->inode_number); 319 /* Append mode file pointer is managed by kernel. */ 320 if (inode->append_mode && 321 ((a->a_mode & (FWRITE | O_APPEND)) == FWRITE)) { 322 DPRINTF("file is already opened by append mode.\n"); 323 return EPERM; 324 } 325 326 return 0; 327 } 328 329 int 330 v7fs_close(void *v) 331 { 332 struct vop_close_args /* { 333 struct vnodeop_desc *a_desc; 334 struct vnode *a_vp; 335 int a_fflag; 336 kauth_cred_t a_cred; 337 } */ *a = v; 338 struct vnode *vp = a->a_vp; 339 #ifdef V7FS_VNOPS_DEBUG 340 struct v7fs_node *v7node = vp->v_data; 341 struct v7fs_inode *inode = &v7node->inode; 342 #endif 343 DPRINTF("#%d (i)%dbyte (v)%zubyte\n", inode->inode_number, 344 v7fs_inode_filesize(inode), vp->v_size); 345 346 /* Update timestamp */ 347 v7fs_update(vp, 0, 0, UPDATE_WAIT); 348 349 return 0; 350 } 351 352 static int 353 v7fs_check_possible(struct vnode *vp, struct v7fs_node *v7node, 354 mode_t mode) 355 { 356 357 if (!(mode & VWRITE)) 358 return 0; 359 360 switch (vp->v_type) { 361 default: 362 /* special file is always writable. */ 363 return 0; 364 case VDIR: 365 case VLNK: 366 case VREG: 367 break; 368 } 369 370 return vp->v_mount->mnt_flag & MNT_RDONLY ? EROFS : 0; 371 } 372 373 static int 374 v7fs_check_permitted(struct vnode *vp, struct v7fs_node *v7node, 375 accmode_t accmode, kauth_cred_t cred) 376 { 377 378 struct v7fs_inode *inode = &v7node->inode; 379 380 return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(accmode, 381 vp->v_type, inode->mode), vp, NULL, genfs_can_access(vp, cred, 382 inode->uid, inode->gid, inode->mode, NULL, accmode)); 383 } 384 385 int 386 v7fs_access(void *v) 387 { 388 struct vop_access_args /* { 389 struct vnode *a_vp; 390 accmode_t a_accmode; 391 kauth_cred_t a_cred; 392 } */ *ap = v; 393 struct vnode *vp = ap->a_vp; 394 struct v7fs_node *v7node = vp->v_data; 395 int error; 396 397 error = v7fs_check_possible(vp, v7node, ap->a_accmode); 398 if (error) 399 return error; 400 401 error = v7fs_check_permitted(vp, v7node, ap->a_accmode, ap->a_cred); 402 403 return error; 404 } 405 406 int 407 v7fs_getattr(void *v) 408 { 409 struct vop_getattr_args /* { 410 struct vnode *a_vp; 411 struct vattr *a_vap; 412 kauth_cred_t a_cred; 413 } */ *ap = v; 414 struct vnode *vp = ap->a_vp; 415 struct v7fs_node *v7node = vp->v_data; 416 struct v7fs_inode *inode = &v7node->inode; 417 struct v7fs_mount *v7fsmount = v7node->v7fsmount; 418 struct vattr *vap = ap->a_vap; 419 420 DPRINTF("\n"); 421 vap->va_type = vp->v_type; 422 vap->va_mode = inode->mode; 423 vap->va_nlink = inode->nlink; 424 vap->va_uid = inode->uid; 425 vap->va_gid = inode->gid; 426 vap->va_fsid = v7fsmount->devvp->v_rdev; 427 vap->va_fileid = inode->inode_number; 428 vap->va_size = vp->v_size; 429 if (vp->v_type == VLNK) { 430 /* Ajust for trailing NUL. */ 431 KASSERT(vap->va_size > 0); 432 vap->va_size -= 1; 433 } 434 vap->va_atime.tv_sec = inode->atime; 435 vap->va_mtime.tv_sec = inode->mtime; 436 vap->va_ctime.tv_sec = inode->ctime; 437 vap->va_birthtime.tv_sec = 0; 438 vap->va_gen = 1; 439 vap->va_flags = inode->append_mode ? SF_APPEND : 0; 440 vap->va_rdev = inode->device; 441 vap->va_bytes = vap->va_size; /* No sparse support. */ 442 vap->va_filerev = 0; 443 vap->va_vaflags = 0; 444 /* PAGE_SIZE is larger than sizeof(struct dirent). OK. 445 getcwd_scandir()@vfs_getcwd.c */ 446 vap->va_blocksize = PAGE_SIZE; 447 448 return 0; 449 } 450 451 int 452 v7fs_setattr(void *v) 453 { 454 struct vop_setattr_args /* { 455 struct vnode *a_vp; 456 struct vattr *a_vap; 457 kauth_cred_t a_cred; 458 struct proc *p; 459 } */ *ap = v; 460 struct vnode *vp = ap->a_vp; 461 struct vattr *vap = ap->a_vap; 462 struct v7fs_node *v7node = vp->v_data; 463 struct v7fs_self *fs = v7node->v7fsmount->core; 464 struct v7fs_inode *inode = &v7node->inode; 465 kauth_cred_t cred = ap->a_cred; 466 struct timespec *acc, *mod; 467 int error = 0; 468 acc = mod = NULL; 469 470 DPRINTF("\n"); 471 472 if (vp->v_mount->mnt_flag & MNT_RDONLY) { 473 switch (vp->v_type) { 474 default: 475 /* special file is always writable. */ 476 break; 477 case VDIR: 478 case VLNK: 479 case VREG: 480 DPRINTF("read-only mount\n"); 481 return EROFS; 482 } 483 } 484 485 if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || 486 (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || 487 (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || 488 ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { 489 DPRINTF("invalid request\n"); 490 return EINVAL; 491 } 492 /* File pointer mode. */ 493 if (vap->va_flags != VNOVAL) { 494 error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_FLAGS, 495 vp, NULL, genfs_can_chflags(vp, cred, inode->uid, 496 false)); 497 if (error) 498 return error; 499 inode->append_mode = vap->va_flags & SF_APPEND; 500 } 501 502 /* File size change. */ 503 if ((vap->va_size != VNOVAL) && (vp->v_type == VREG)) { 504 error = v7fs_datablock_size_change(fs, vap->va_size, inode); 505 if (error == 0) { 506 uvm_vnp_setsize(vp, vap->va_size); 507 v7node->update_mtime = true; 508 v7node->update_ctime = true; 509 } 510 } 511 uid_t uid = inode->uid; 512 gid_t gid = inode->gid; 513 514 if (vap->va_uid != (uid_t)VNOVAL) { 515 uid = vap->va_uid; 516 error = kauth_authorize_vnode(cred, 517 KAUTH_VNODE_CHANGE_OWNERSHIP, vp, NULL, 518 genfs_can_chown(vp, cred, inode->uid, inode->gid, uid, 519 gid)); 520 if (error) 521 return error; 522 inode->uid = uid; 523 } 524 if (vap->va_gid != (uid_t)VNOVAL) { 525 gid = vap->va_gid; 526 error = kauth_authorize_vnode(cred, 527 KAUTH_VNODE_CHANGE_OWNERSHIP, vp, NULL, 528 genfs_can_chown(vp, cred, inode->uid, inode->gid, uid, 529 gid)); 530 if (error) 531 return error; 532 inode->gid = gid; 533 } 534 if (vap->va_mode != (mode_t)VNOVAL) { 535 mode_t mode = vap->va_mode; 536 error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, 537 vp, NULL, genfs_can_chmod(vp, cred, inode->uid, inode->gid, 538 mode)); 539 if (error) { 540 return error; 541 } 542 v7fs_inode_chmod(inode, mode); 543 } 544 if ((vap->va_atime.tv_sec != VNOVAL) || 545 (vap->va_mtime.tv_sec != VNOVAL) || 546 (vap->va_ctime.tv_sec != VNOVAL)) { 547 error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp, 548 NULL, genfs_can_chtimes(vp, cred, inode->uid, 549 vap->va_vaflags)); 550 if (error) 551 return error; 552 553 if (vap->va_atime.tv_sec != VNOVAL) { 554 acc = &vap->va_atime; 555 } 556 if (vap->va_mtime.tv_sec != VNOVAL) { 557 mod = &vap->va_mtime; 558 v7node->update_mtime = true; 559 } 560 if (vap->va_ctime.tv_sec != VNOVAL) { 561 v7node->update_ctime = true; 562 } 563 } 564 565 v7node->update_atime = true; 566 v7fs_update(vp, acc, mod, 0); 567 568 return error; 569 } 570 571 int 572 v7fs_read(void *v) 573 { 574 struct vop_read_args /* { 575 struct vnode *a_vp; 576 struct uio *a_uio; 577 int a_ioflag; 578 kauth_cred_t a_cred; 579 } */ *a = v; 580 struct vnode *vp = a->a_vp; 581 struct uio *uio = a->a_uio; 582 struct v7fs_node *v7node = vp->v_data; 583 struct v7fs_inode *inode = &v7node->inode; 584 vsize_t sz, filesz = v7fs_inode_filesize(inode); 585 const int advice = IO_ADV_DECODE(a->a_ioflag); 586 int error = 0; 587 588 DPRINTF("type=%d inode=%d\n", vp->v_type, v7node->inode.inode_number); 589 590 while (uio->uio_resid > 0) { 591 if ((sz = MIN(filesz - uio->uio_offset, uio->uio_resid)) == 0) 592 break; 593 594 error = ubc_uiomove(&vp->v_uobj, uio, sz, advice, UBC_READ | 595 UBC_PARTIALOK | UBC_VNODE_FLAGS(vp)); 596 if (error) { 597 break; 598 } 599 DPRINTF("read %zubyte\n", sz); 600 } 601 v7node->update_atime = true; 602 603 return error; 604 } 605 606 int 607 v7fs_write(void *v) 608 { 609 struct vop_write_args /* { 610 struct vnode *a_vp; 611 struct uio *a_uio; 612 int a_ioflag; 613 kauth_cred_t a_cred; 614 } */ *a = v; 615 struct vnode *vp = a->a_vp; 616 struct uio *uio = a->a_uio; 617 int advice = IO_ADV_DECODE(a->a_ioflag); 618 struct v7fs_node *v7node = vp->v_data; 619 struct v7fs_inode *inode = &v7node->inode; 620 struct v7fs_self *fs = v7node->v7fsmount->core; 621 vsize_t sz; 622 int error = 0; 623 624 if (uio->uio_resid == 0) 625 return 0; 626 627 sz = v7fs_inode_filesize(inode); 628 DPRINTF("(i)%ld (v)%zu ofs=%zu + res=%zu = %zu\n", sz, vp->v_size, 629 uio->uio_offset, uio->uio_resid, uio->uio_offset + uio->uio_resid); 630 631 /* Append mode file offset is managed by kernel. */ 632 if (a->a_ioflag & IO_APPEND) 633 uio->uio_offset = sz; 634 635 /* If write region is over filesize, expand. */ 636 size_t newsize= uio->uio_offset + uio->uio_resid; 637 ssize_t expand = newsize - sz; 638 if (expand > 0) { 639 if ((error = v7fs_datablock_expand(fs, inode, expand))) 640 return error; 641 uvm_vnp_setsize(vp, newsize); 642 } 643 644 while (uio->uio_resid > 0) { 645 sz = uio->uio_resid; 646 if ((error = ubc_uiomove(&vp->v_uobj, uio, sz, advice, 647 UBC_WRITE | UBC_VNODE_FLAGS(vp)))) 648 break; 649 DPRINTF("write %zubyte\n", sz); 650 } 651 v7node->update_mtime = true; 652 653 return error; 654 } 655 656 int 657 v7fs_fsync(void *v) 658 { 659 struct vop_fsync_args /* { 660 struct vnode *a_vp; 661 kauth_cred_t a_cred; 662 int a_flags; 663 off_t offlo; 664 off_t offhi; 665 } */ *a = v; 666 struct vnode *vp = a->a_vp; 667 int error, wait; 668 669 DPRINTF("%p\n", a->a_vp); 670 if (a->a_flags & FSYNC_CACHE) { 671 return EOPNOTSUPP; 672 } 673 674 wait = (a->a_flags & FSYNC_WAIT); 675 error = vflushbuf(vp, a->a_flags); 676 677 if (error == 0 && (a->a_flags & FSYNC_DATAONLY) == 0) 678 error = v7fs_update(vp, NULL, NULL, wait ? UPDATE_WAIT : 0); 679 680 return error; 681 } 682 683 int 684 v7fs_remove(void *v) 685 { 686 struct vop_remove_v2_args /* { 687 struct vnodeop_desc *a_desc; 688 struct vnode * a_dvp; 689 struct vnode * a_vp; 690 struct componentname * a_cnp; 691 } */ *a = v; 692 struct v7fs_node *parent_node = a->a_dvp->v_data; 693 struct v7fs_mount *v7fsmount = parent_node->v7fsmount; 694 struct vnode *vp = a->a_vp; 695 struct vnode *dvp = a->a_dvp; 696 struct v7fs_inode *inode = &((struct v7fs_node *)vp->v_data)->inode; 697 struct v7fs_self *fs = v7fsmount->core; 698 int error = 0; 699 700 DPRINTF("delete %s\n", a->a_cnp->cn_nameptr); 701 702 if (vp->v_type == VDIR) { 703 error = EPERM; 704 goto out; 705 } 706 707 if ((error = v7fs_file_deallocate(fs, &parent_node->inode, 708 a->a_cnp->cn_nameptr))) { 709 DPRINTF("v7fs_file_delete failed.\n"); 710 goto out; 711 } 712 error = v7fs_inode_load(fs, inode, inode->inode_number); 713 if (error) 714 goto out; 715 /* Sync dirent size change. */ 716 uvm_vnp_setsize(dvp, v7fs_inode_filesize(&parent_node->inode)); 717 718 out: 719 if (dvp == vp) 720 vrele(vp); /* usecount-- of unlocked vp */ 721 else 722 vput(vp); /* unlock vp and then usecount-- */ 723 724 return error; 725 } 726 727 int 728 v7fs_link(void *v) 729 { 730 struct vop_link_v2_args /* { 731 struct vnode *a_dvp; 732 struct vnode *a_vp; 733 struct componentname *a_cnp; 734 } */ *a = v; 735 struct vnode *dvp = a->a_dvp; 736 struct vnode *vp = a->a_vp; 737 struct v7fs_node *parent_node = dvp->v_data; 738 struct v7fs_node *node = vp->v_data; 739 struct v7fs_inode *parent = &parent_node->inode; 740 struct v7fs_inode *p = &node->inode; 741 struct v7fs_self *fs = node->v7fsmount->core; 742 struct componentname *cnp = a->a_cnp; 743 int error = 0; 744 745 DPRINTF("%p\n", vp); 746 /* Lock soruce file */ 747 if ((error = vn_lock(vp, LK_EXCLUSIVE))) { 748 DPRINTF("lock failed. %p\n", vp); 749 VOP_ABORTOP(dvp, cnp); 750 goto unlock; 751 } 752 error = v7fs_file_link(fs, parent, p, cnp->cn_nameptr); 753 /* Sync dirent size change. */ 754 uvm_vnp_setsize(dvp, v7fs_inode_filesize(&parent_node->inode)); 755 756 VOP_UNLOCK(vp); 757 unlock: 758 return error; 759 } 760 761 int 762 v7fs_rename(void *v) 763 { 764 struct vop_rename_args /* { 765 struct vnode *a_fdvp; from parent-directory 766 struct vnode *a_fvp; from file 767 struct componentname *a_fcnp; 768 struct vnode *a_tdvp; to parent-directory 769 struct vnode *a_tvp; to file 770 struct componentname *a_tcnp; 771 } */ *a = v; 772 struct vnode *fvp = a->a_fvp; 773 struct vnode *tvp = a->a_tvp; 774 struct vnode *fdvp = a->a_fdvp; 775 struct vnode *tdvp = a->a_tdvp; 776 struct v7fs_node *parent_from = fdvp->v_data; 777 struct v7fs_node *parent_to = tdvp->v_data; 778 struct v7fs_node *v7node = fvp->v_data; 779 struct v7fs_self *fs = v7node->v7fsmount->core; 780 const char *from_name = a->a_fcnp->cn_nameptr; 781 const char *to_name = a->a_tcnp->cn_nameptr; 782 int error; 783 784 DPRINTF("%s->%s %p %p\n", from_name, to_name, fvp, tvp); 785 786 if ((fvp->v_mount != tdvp->v_mount) || 787 (tvp && (fvp->v_mount != tvp->v_mount))) { 788 error = EXDEV; 789 DPRINTF("cross-device link\n"); 790 goto out; 791 } 792 // XXXsource file lock? 793 error = v7fs_file_rename(fs, &parent_from->inode, from_name, 794 &parent_to->inode, to_name); 795 /* 'to file' inode may be changed. (hard-linked and it is cached.) 796 t_vnops rename_reg_nodir */ 797 if (error == 0 && tvp) { 798 struct v7fs_inode *inode = 799 &((struct v7fs_node *)tvp->v_data)->inode; 800 801 error = v7fs_inode_load(fs, inode, inode->inode_number); 802 uvm_vnp_setsize(tvp, v7fs_inode_filesize(inode)); 803 } 804 /* Sync dirent size change. */ 805 uvm_vnp_setsize(tdvp, v7fs_inode_filesize(&parent_to->inode)); 806 uvm_vnp_setsize(fdvp, v7fs_inode_filesize(&parent_from->inode)); 807 out: 808 if (tvp) 809 vput(tvp); /* locked on entry */ 810 if (tdvp == tvp) 811 vrele(tdvp); 812 else 813 vput(tdvp); 814 vrele(fdvp); 815 vrele(fvp); 816 817 return error; 818 } 819 820 int 821 v7fs_mkdir(void *v) 822 { 823 struct vop_mkdir_v3_args /* { 824 struct vnode *a_dvp; 825 struct vnode **a_vpp; 826 struct componentname *a_cnp; 827 struct vattr *a_vap; 828 } */ *a = v; 829 struct componentname *cnp = a->a_cnp; 830 kauth_cred_t cr = cnp->cn_cred; 831 struct vnode *dvp = a->a_dvp; 832 struct vattr *va = a->a_vap; 833 struct v7fs_node *parent_node = dvp->v_data; 834 struct v7fs_mount *v7fsmount = parent_node->v7fsmount; 835 struct v7fs_self *fs = v7fsmount->core; 836 struct v7fs_fileattr attr; 837 struct mount *mp = v7fsmount->mountp; 838 v7fs_ino_t ino; 839 int error = 0; 840 841 DPRINTF("\n"); 842 memset(&attr, 0, sizeof(attr)); 843 attr.uid = kauth_cred_geteuid(cr); 844 attr.gid = kauth_cred_getegid(cr); 845 attr.mode = va->va_mode | vtype_to_v7fs_mode(va->va_type); 846 847 if ((error = v7fs_file_allocate(fs, &parent_node->inode, 848 cnp->cn_nameptr, &attr, &ino))) 849 return error; 850 /* Sync dirent size change. */ 851 uvm_vnp_setsize(dvp, v7fs_inode_filesize(&parent_node->inode)); 852 853 error = v7fs_vget(mp, ino, LK_EXCLUSIVE, a->a_vpp); 854 if (error != 0) { 855 DPRINTF("can't get vnode.\n"); 856 } 857 struct v7fs_node *newnode = (*a->a_vpp)->v_data; 858 newnode->update_ctime = true; 859 newnode->update_mtime = true; 860 newnode->update_atime = true; 861 862 if (error == 0) 863 VOP_UNLOCK(*a->a_vpp); 864 865 return error; 866 } 867 868 int 869 v7fs_rmdir(void *v) 870 { 871 struct vop_rmdir_v2_args /* { 872 struct vnode *a_dvp; 873 struct vnode *a_vp; 874 struct componentname *a_cnp; 875 } */ *a = v; 876 struct vnode *vp = a->a_vp; 877 struct vnode *dvp = a->a_dvp; 878 struct v7fs_node *parent_node = dvp->v_data; 879 struct v7fs_mount *v7fsmount = parent_node->v7fsmount; 880 struct v7fs_inode *inode = &((struct v7fs_node *)vp->v_data)->inode; 881 struct v7fs_self *fs = v7fsmount->core; 882 int error = 0; 883 884 DPRINTF("delete %s\n", a->a_cnp->cn_nameptr); 885 886 KDASSERT(vp->v_type == VDIR); 887 888 if ((error = v7fs_file_deallocate(fs, &parent_node->inode, 889 a->a_cnp->cn_nameptr))) { 890 DPRINTF("v7fs_directory_deallocate failed.\n"); 891 goto out; 892 } 893 error = v7fs_inode_load(fs, inode, inode->inode_number); 894 if (error) 895 goto out; 896 uvm_vnp_setsize(vp, v7fs_inode_filesize(inode)); 897 /* Sync dirent size change. */ 898 uvm_vnp_setsize(dvp, v7fs_inode_filesize(&parent_node->inode)); 899 out: 900 vput(vp); 901 902 return error; 903 } 904 905 struct v7fs_readdir_arg { 906 struct dirent *dp; 907 struct uio *uio; 908 int start; 909 int end; 910 int cnt; 911 }; 912 static int readdir_subr(struct v7fs_self *, void *, v7fs_daddr_t, size_t); 913 914 int 915 readdir_subr(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk, size_t sz) 916 { 917 struct v7fs_readdir_arg *p = (struct v7fs_readdir_arg *)ctx; 918 struct v7fs_dirent *dir; 919 struct dirent *dp = p->dp; 920 struct v7fs_inode inode; 921 char filename[V7FS_NAME_MAX + 1]; 922 int i, n; 923 int error = 0; 924 void *buf; 925 926 if (!(buf = scratch_read(fs, blk))) 927 return EIO; 928 dir = (struct v7fs_dirent *)buf; 929 930 n = sz / sizeof(*dir); 931 932 for (i = 0; (i < n) && (p->cnt < p->end); i++, dir++, p->cnt++) { 933 if (p->cnt < p->start) 934 continue; 935 936 if ((error = v7fs_inode_load(fs, &inode, dir->inode_number))) 937 break; 938 939 v7fs_dirent_filename(filename, dir->name); 940 941 DPRINTF("inode=%d name=%s %s\n", dir->inode_number, filename, 942 v7fs_inode_isdir(&inode) ? "DIR" : "FILE"); 943 memset(dp, 0, sizeof(*dp)); 944 dp->d_fileno = dir->inode_number; 945 dp->d_type = v7fs_mode_to_d_type(inode.mode); 946 dp->d_namlen = strlen(filename); 947 strcpy(dp->d_name, filename); 948 dp->d_reclen = sizeof(*dp); 949 if ((error = uiomove(dp, dp->d_reclen, p->uio))) { 950 DPRINTF("uiomove failed.\n"); 951 break; 952 } 953 } 954 scratch_free(fs, buf); 955 956 if (p->cnt == p->end) 957 return V7FS_ITERATOR_BREAK; 958 959 return error; 960 } 961 962 int 963 v7fs_readdir(void *v) 964 { 965 struct vop_readdir_args /* { 966 struct vnode *a_vp; 967 struct uio *a_uio; 968 kauth_cred_t a_cred; 969 int *a_eofflag; 970 off_t **a_cookies; 971 int *a_ncookies; 972 } */ *a = v; 973 struct uio *uio = a->a_uio; 974 struct vnode *vp = a->a_vp; 975 struct v7fs_node *v7node = vp->v_data; 976 struct v7fs_inode *inode = &v7node->inode; 977 struct v7fs_self *fs = v7node->v7fsmount->core; 978 struct dirent *dp; 979 int error; 980 981 DPRINTF("offset=%zu residue=%zu\n", uio->uio_offset, uio->uio_resid); 982 983 KDASSERT(vp->v_type == VDIR); 984 KDASSERT(uio->uio_offset >= 0); 985 KDASSERT(v7fs_inode_isdir(inode)); 986 987 struct v7fs_readdir_arg arg; 988 arg.start = uio->uio_offset / sizeof(*dp); 989 arg.end = arg.start + uio->uio_resid / sizeof(*dp); 990 if (arg.start == arg.end) {/* user buffer has not enuf space. */ 991 DPRINTF("uio buffer too small\n"); 992 return ENOMEM; 993 } 994 dp = kmem_zalloc(sizeof(*dp), KM_SLEEP); 995 arg.cnt = 0; 996 arg.dp = dp; 997 arg.uio = uio; 998 999 *a->a_eofflag = false; 1000 error = v7fs_datablock_foreach(fs, inode, readdir_subr, &arg); 1001 if (error == V7FS_ITERATOR_END) { 1002 *a->a_eofflag = true; 1003 } 1004 if (error < 0) 1005 error = 0; 1006 1007 kmem_free(dp, sizeof(*dp)); 1008 1009 return error; 1010 } 1011 1012 int 1013 v7fs_inactive(void *v) 1014 { 1015 struct vop_inactive_v2_args /* { 1016 struct vnode *a_vp; 1017 bool *a_recycle; 1018 } */ *a = v; 1019 struct vnode *vp = a->a_vp; 1020 struct v7fs_node *v7node = vp->v_data; 1021 struct v7fs_inode *inode = &v7node->inode; 1022 1023 DPRINTF("%p #%d\n", vp, inode->inode_number); 1024 if (v7fs_inode_nlink(inode) > 0) { 1025 v7fs_update(vp, 0, 0, UPDATE_WAIT); 1026 *a->a_recycle = false; 1027 } else { 1028 *a->a_recycle = true; 1029 } 1030 1031 return 0; 1032 } 1033 1034 int 1035 v7fs_reclaim(void *v) 1036 { 1037 /*This vnode is no longer referenced by kernel. */ 1038 extern struct pool v7fs_node_pool; 1039 struct vop_reclaim_v2_args /* { 1040 struct vnode *a_vp; 1041 } */ *a = v; 1042 struct vnode *vp = a->a_vp; 1043 struct v7fs_node *v7node = vp->v_data; 1044 struct v7fs_self *fs = v7node->v7fsmount->core; 1045 struct v7fs_inode *inode = &v7node->inode; 1046 1047 VOP_UNLOCK(vp); 1048 1049 DPRINTF("%p #%d\n", vp, inode->inode_number); 1050 if (v7fs_inode_nlink(inode) == 0) { 1051 v7fs_datablock_size_change(fs, 0, inode); 1052 DPRINTF("remove datablock\n"); 1053 v7fs_inode_deallocate(fs, inode->inode_number); 1054 DPRINTF("remove inode\n"); 1055 } 1056 genfs_node_destroy(vp); 1057 pool_put(&v7fs_node_pool, v7node); 1058 mutex_enter(vp->v_interlock); 1059 vp->v_data = NULL; 1060 mutex_exit(vp->v_interlock); 1061 1062 return 0; 1063 } 1064 1065 int 1066 v7fs_bmap(void *v) 1067 { 1068 struct vop_bmap_args /* { 1069 struct vnode *a_vp; 1070 daddr_t a_bn; 1071 struct vnode **a_vpp; 1072 daddr_t *a_bnp; 1073 int *a_runp; 1074 } */ *a = v; 1075 struct vnode *vp = a->a_vp; 1076 struct v7fs_node *v7node = vp->v_data; 1077 struct v7fs_mount *v7fsmount = v7node->v7fsmount; 1078 struct v7fs_self *fs = v7node->v7fsmount->core; 1079 struct v7fs_inode *inode = &v7node->inode; 1080 int error = 0; 1081 1082 DPRINTF("inode=%d offset=%zu %p\n", inode->inode_number, a->a_bn, vp); 1083 DPRINTF("filesize: %d\n", inode->filesize); 1084 if (!a->a_bnp) 1085 return 0; 1086 1087 v7fs_daddr_t blk; 1088 if (!(blk = v7fs_datablock_last(fs, inode, 1089 (a->a_bn + 1) << V7FS_BSHIFT))) { 1090 /* +1 converts block # to file offset. */ 1091 return ENOSPC; 1092 } 1093 1094 *a->a_bnp = blk; 1095 1096 if (a->a_vpp) 1097 *a->a_vpp = v7fsmount->devvp; 1098 if (a->a_runp) 1099 *a->a_runp = 0; /*XXX TODO */ 1100 1101 DPRINTF("%d %zu->%zu status=%d\n", inode->inode_number, a->a_bn, 1102 *a->a_bnp, error); 1103 1104 return error; 1105 } 1106 1107 int 1108 v7fs_strategy(void *v) 1109 { 1110 struct vop_strategy_args /* { 1111 struct vnode *a_vp; 1112 struct buf *a_bp; 1113 } */ *a = v; 1114 struct buf *b = a->a_bp; 1115 struct vnode *vp = a->a_vp; 1116 struct v7fs_node *v7node = vp->v_data; 1117 struct v7fs_mount *v7fsmount = v7node->v7fsmount; 1118 int error; 1119 1120 DPRINTF("%p\n", vp); 1121 KDASSERT(vp->v_type == VREG); 1122 if (b->b_blkno == b->b_lblkno) { 1123 error = VOP_BMAP(vp, b->b_lblkno, NULL, &b->b_blkno, NULL); 1124 if (error) { 1125 b->b_error = error; 1126 biodone(b); 1127 return error; 1128 } 1129 if ((long)b->b_blkno == -1) 1130 clrbuf(b); 1131 } 1132 if ((long)b->b_blkno == -1) { 1133 biodone(b); 1134 return 0; 1135 } 1136 1137 return VOP_STRATEGY(v7fsmount->devvp, b); 1138 } 1139 1140 int 1141 v7fs_print(void *v) 1142 { 1143 struct vop_print_args /* { 1144 struct vnode *a_vp; 1145 } */ *a = v; 1146 struct v7fs_node *v7node = a->a_vp->v_data; 1147 1148 v7fs_inode_dump(&v7node->inode); 1149 1150 return 0; 1151 } 1152 1153 int 1154 v7fs_advlock(void *v) 1155 { 1156 struct vop_advlock_args /* { 1157 struct vnode *a_vp; 1158 void *a_id; 1159 int a_op; 1160 struct flock *a_fl; 1161 int a_flags; 1162 } */ *a = v; 1163 struct v7fs_node *v7node = a->a_vp->v_data; 1164 1165 DPRINTF("op=%d\n", a->a_op); 1166 1167 return lf_advlock(a, &v7node->lockf, 1168 v7fs_inode_filesize(&v7node->inode)); 1169 } 1170 1171 int 1172 v7fs_pathconf(void *v) 1173 { 1174 struct vop_pathconf_args /* { 1175 struct vnode *a_vp; 1176 int a_name; 1177 register_t *a_retval; 1178 } */ *ap = v; 1179 DPRINTF("%p\n", ap->a_vp); 1180 1181 switch (ap->a_name) { 1182 case _PC_LINK_MAX: 1183 *ap->a_retval = V7FS_LINK_MAX; 1184 return 0; 1185 case _PC_NAME_MAX: 1186 *ap->a_retval = V7FS_NAME_MAX; 1187 return 0; 1188 case _PC_PATH_MAX: 1189 *ap->a_retval = V7FS_PATH_MAX; 1190 return 0; 1191 case _PC_CHOWN_RESTRICTED: 1192 *ap->a_retval = 1; 1193 return 0; 1194 case _PC_NO_TRUNC: 1195 *ap->a_retval = 0; 1196 return 0; 1197 case _PC_SYNC_IO: 1198 *ap->a_retval = 1; 1199 return 0; 1200 case _PC_FILESIZEBITS: 1201 *ap->a_retval = 30; /* ~1G */ 1202 return 0; 1203 case _PC_SYMLINK_MAX: 1204 *ap->a_retval = V7FSBSD_MAXSYMLINKLEN; 1205 return 0; 1206 case _PC_2_SYMLINKS: 1207 *ap->a_retval = 1; 1208 return 0; 1209 default: 1210 return genfs_pathconf(ap); 1211 } 1212 } 1213 1214 int 1215 v7fs_update(struct vnode *vp, const struct timespec *acc, 1216 const struct timespec *mod, int flags) 1217 { 1218 struct v7fs_node *v7node = vp->v_data; 1219 struct v7fs_inode *inode = &v7node->inode; 1220 struct v7fs_self *fs = v7node->v7fsmount->core; 1221 bool update = false; 1222 1223 DPRINTF("%p %zu %d\n", vp, vp->v_size, v7fs_inode_filesize(inode)); 1224 KDASSERT(vp->v_size == v7fs_inode_filesize(inode)); 1225 1226 if (v7node->update_atime) { 1227 inode->atime = acc ? acc->tv_sec : time_second; 1228 v7node->update_atime = false; 1229 update = true; 1230 } 1231 if (v7node->update_ctime) { 1232 inode->ctime = time_second; 1233 v7node->update_ctime = false; 1234 update = true; 1235 } 1236 if (v7node->update_mtime) { 1237 inode->mtime = mod ? mod->tv_sec : time_second; 1238 v7node->update_mtime = false; 1239 update = true; 1240 } 1241 1242 if (update) 1243 v7fs_inode_writeback(fs, inode); 1244 1245 return 0; 1246 } 1247 1248 int 1249 v7fs_symlink(void *v) 1250 { 1251 struct vop_symlink_v3_args /* { 1252 struct vnode *a_dvp; 1253 struct vnode **a_vpp; 1254 struct componentname *a_cnp; 1255 struct vattr *a_vap; 1256 char *a_target; 1257 } */ *a = v; 1258 struct v7fs_node *parent_node = a->a_dvp->v_data; 1259 struct v7fs_mount *v7fsmount = parent_node->v7fsmount; 1260 struct v7fs_self *fs = v7fsmount->core; 1261 struct vattr *va = a->a_vap; 1262 kauth_cred_t cr = a->a_cnp->cn_cred; 1263 struct componentname *cnp = a->a_cnp; 1264 struct v7fs_fileattr attr; 1265 v7fs_ino_t ino; 1266 const char *from = a->a_target; 1267 const char *to = cnp->cn_nameptr; 1268 size_t len = strlen(from) + 1; 1269 int error = 0; 1270 1271 if (len > V7FS_BSIZE) { /* limited to 512byte pathname */ 1272 DPRINTF("too long pathname."); 1273 return ENAMETOOLONG; 1274 } 1275 1276 memset(&attr, 0, sizeof(attr)); 1277 attr.uid = kauth_cred_geteuid(cr); 1278 attr.gid = kauth_cred_getegid(cr); 1279 attr.mode = va->va_mode | vtype_to_v7fs_mode(va->va_type); 1280 1281 if ((error = v7fs_file_allocate 1282 (fs, &parent_node->inode, to, &attr, &ino))) { 1283 return error; 1284 } 1285 /* Sync dirent size change. */ 1286 uvm_vnp_setsize(a->a_dvp, v7fs_inode_filesize(&parent_node->inode)); 1287 1288 /* Get myself vnode. */ 1289 error = v7fs_vget(v7fsmount->mountp, ino, LK_EXCLUSIVE, a->a_vpp); 1290 if (error != 0) { 1291 DPRINTF("can't get vnode.\n"); 1292 } 1293 1294 struct v7fs_node *newnode = (*a->a_vpp)->v_data; 1295 struct v7fs_inode *p = &newnode->inode; 1296 v7fs_file_symlink(fs, p, from); 1297 uvm_vnp_setsize(*a->a_vpp, v7fs_inode_filesize(p)); 1298 1299 newnode->update_ctime = true; 1300 newnode->update_mtime = true; 1301 newnode->update_atime = true; 1302 1303 if (error == 0) 1304 VOP_UNLOCK(*a->a_vpp); 1305 1306 return error; 1307 } 1308 1309 int 1310 v7fs_readlink(void *v) 1311 { 1312 struct vop_readlink_args /* { 1313 struct vnode *a_vp; 1314 struct uio *a_uio; 1315 kauth_cred_t a_cred; 1316 } */ *a = v; 1317 struct uio *uio = a->a_uio; 1318 struct vnode *vp = a->a_vp; 1319 struct v7fs_node *v7node = vp->v_data; 1320 struct v7fs_inode *inode = &v7node->inode; 1321 struct v7fs_self *fs = v7node->v7fsmount->core; 1322 int error = 0; 1323 1324 KDASSERT(vp->v_type == VLNK); 1325 KDASSERT(uio->uio_offset >= 0); 1326 KDASSERT(v7fs_inode_islnk(inode)); 1327 1328 v7fs_daddr_t blk = inode->addr[0]; 1329 void *buf; 1330 if (!(buf = scratch_read(fs, blk))) { 1331 error = EIO; 1332 goto error_exit; 1333 } 1334 1335 if ((error = uiomove(buf, strlen(buf), uio))) { 1336 DPRINTF("uiomove failed.\n"); 1337 } 1338 scratch_free(fs, buf); 1339 1340 error_exit: 1341 return error; 1342 } 1343