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