1 /* $NetBSD: sysvbfs_vnops.c,v 1.49 2013/12/24 09:56:18 hannken Exp $ */ 2 3 /*- 4 * Copyright (c) 2004 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: sysvbfs_vnops.c,v 1.49 2013/12/24 09:56:18 hannken Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/kernel.h> 37 #include <sys/resource.h> 38 #include <sys/vnode.h> 39 #include <sys/namei.h> 40 #include <sys/dirent.h> 41 #include <sys/malloc.h> 42 #include <sys/lockf.h> 43 #include <sys/unistd.h> 44 #include <sys/fcntl.h> 45 #include <sys/kauth.h> 46 #include <sys/buf.h> 47 48 #include <miscfs/genfs/genfs.h> 49 50 #include <fs/sysvbfs/sysvbfs.h> 51 #include <fs/sysvbfs/bfs.h> 52 53 #ifdef SYSVBFS_VNOPS_DEBUG 54 #define DPRINTF(fmt, args...) printf(fmt, ##args) 55 #else 56 #define DPRINTF(arg...) ((void)0) 57 #endif 58 #define ROUND_SECTOR(x) (((x) + 511) & ~511) 59 60 MALLOC_JUSTDEFINE(M_SYSVBFS_VNODE, "sysvbfs vnode", "sysvbfs vnode structures"); 61 MALLOC_DECLARE(M_BFS); 62 63 static void sysvbfs_file_setsize(struct vnode *, size_t); 64 65 int 66 sysvbfs_lookup(void *arg) 67 { 68 struct vop_lookup_args /* { 69 struct vnode *a_dvp; 70 struct vnode **a_vpp; 71 struct componentname *a_cnp; 72 } */ *a = arg; 73 struct vnode *v = a->a_dvp; 74 struct sysvbfs_node *bnode = v->v_data; 75 struct bfs *bfs = bnode->bmp->bfs; /* my filesystem */ 76 struct vnode *vpp = NULL; 77 struct bfs_dirent *dirent = NULL; 78 struct componentname *cnp = a->a_cnp; 79 int nameiop = cnp->cn_nameiop; 80 const char *name = cnp->cn_nameptr; 81 int namelen = cnp->cn_namelen; 82 int error; 83 84 DPRINTF("%s: %s op=%d %d\n", __func__, name, nameiop, 85 cnp->cn_flags); 86 87 *a->a_vpp = NULL; 88 89 KASSERT((cnp->cn_flags & ISDOTDOT) == 0); 90 91 if ((error = VOP_ACCESS(a->a_dvp, VEXEC, cnp->cn_cred)) != 0) { 92 return error; /* directory permission. */ 93 } 94 95 /* Deny last component write operation on a read-only mount */ 96 if ((cnp->cn_flags & ISLASTCN) && (v->v_mount->mnt_flag & MNT_RDONLY) && 97 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) 98 return EROFS; 99 100 if (namelen == 1 && name[0] == '.') { /* "." */ 101 vref(v); 102 *a->a_vpp = v; 103 } else { /* Regular file */ 104 if (!bfs_dirent_lookup_by_name(bfs, cnp->cn_nameptr, 105 &dirent)) { 106 if (nameiop != CREATE && nameiop != RENAME) { 107 DPRINTF("%s: no such a file. (1)\n", 108 __func__); 109 return ENOENT; 110 } 111 if ((error = VOP_ACCESS(v, VWRITE, cnp->cn_cred)) != 0) 112 return error; 113 return EJUSTRETURN; 114 } 115 116 /* Allocate v-node */ 117 if ((error = sysvbfs_vget(v->v_mount, dirent->inode, &vpp)) != 0) { 118 DPRINTF("%s: can't get vnode.\n", __func__); 119 return error; 120 } 121 *a->a_vpp = vpp; 122 } 123 124 return 0; 125 } 126 127 int 128 sysvbfs_create(void *arg) 129 { 130 struct vop_create_args /* { 131 struct vnode *a_dvp; 132 struct vnode **a_vpp; 133 struct componentname *a_cnp; 134 struct vattr *a_vap; 135 } */ *a = arg; 136 struct sysvbfs_node *bnode = a->a_dvp->v_data; 137 struct sysvbfs_mount *bmp = bnode->bmp; 138 struct bfs *bfs = bmp->bfs; 139 struct mount *mp = bmp->mountp; 140 struct bfs_dirent *dirent; 141 struct bfs_fileattr attr; 142 struct vattr *va = a->a_vap; 143 kauth_cred_t cr = a->a_cnp->cn_cred; 144 int err = 0; 145 146 DPRINTF("%s: %s\n", __func__, a->a_cnp->cn_nameptr); 147 KDASSERT(a->a_vap->va_type == VREG); 148 attr.uid = kauth_cred_geteuid(cr); 149 attr.gid = kauth_cred_getegid(cr); 150 attr.mode = va->va_mode; 151 152 if ((err = bfs_file_create(bfs, a->a_cnp->cn_nameptr, 0, 0, &attr)) 153 != 0) { 154 DPRINTF("%s: bfs_file_create failed.\n", __func__); 155 goto unlock_exit; 156 } 157 158 if (!bfs_dirent_lookup_by_name(bfs, a->a_cnp->cn_nameptr, &dirent)) 159 panic("no dirent for created file."); 160 161 if ((err = sysvbfs_vget(mp, dirent->inode, a->a_vpp)) != 0) { 162 DPRINTF("%s: sysvbfs_vget failed.\n", __func__); 163 goto unlock_exit; 164 } 165 bnode = (*a->a_vpp)->v_data; 166 bnode->update_ctime = true; 167 bnode->update_mtime = true; 168 bnode->update_atime = true; 169 170 unlock_exit: 171 /* unlock parent directory */ 172 vput(a->a_dvp); /* locked at sysvbfs_lookup(); */ 173 174 return err; 175 } 176 177 int 178 sysvbfs_open(void *arg) 179 { 180 struct vop_open_args /* { 181 struct vnode *a_vp; 182 int a_mode; 183 kauth_cred_t a_cred; 184 } */ *a = arg; 185 struct vnode *v = a->a_vp; 186 struct sysvbfs_node *bnode = v->v_data; 187 struct bfs_inode *inode = bnode->inode; 188 189 DPRINTF("%s:\n", __func__); 190 KDASSERT(v->v_type == VREG || v->v_type == VDIR); 191 192 bnode->update_atime = true; 193 if ((a->a_mode & FWRITE) && !(a->a_mode & O_APPEND)) { 194 bnode->size = 0; 195 } else { 196 bnode->size = bfs_file_size(inode); 197 } 198 bnode->data_block = inode->start_sector; 199 200 return 0; 201 } 202 203 int 204 sysvbfs_close(void *arg) 205 { 206 struct vop_close_args /* { 207 struct vnodeop_desc *a_desc; 208 struct vnode *a_vp; 209 int a_fflag; 210 kauth_cred_t a_cred; 211 } */ *a = arg; 212 struct vnode *v = a->a_vp; 213 struct sysvbfs_node *bnode = v->v_data; 214 struct bfs_fileattr attr; 215 216 DPRINTF("%s:\n", __func__); 217 218 if (v->v_mount->mnt_flag & MNT_RDONLY) 219 goto out; 220 221 uvm_vnp_setsize(v, bnode->size); 222 223 memset(&attr, 0xff, sizeof attr); /* Set VNOVAL all */ 224 if (bnode->update_atime) 225 attr.atime = time_second; 226 if (bnode->update_ctime) 227 attr.ctime = time_second; 228 if (bnode->update_mtime) 229 attr.mtime = time_second; 230 bfs_inode_set_attr(bnode->bmp->bfs, bnode->inode, &attr); 231 232 VOP_FSYNC(a->a_vp, a->a_cred, FSYNC_WAIT, 0, 0); 233 234 out: 235 return 0; 236 } 237 238 static int 239 sysvbfs_check_possible(struct vnode *vp, struct sysvbfs_node *bnode, 240 mode_t mode) 241 { 242 243 if ((mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) 244 return EROFS; 245 246 return 0; 247 } 248 249 static int 250 sysvbfs_check_permitted(struct vnode *vp, struct sysvbfs_node *bnode, 251 mode_t mode, kauth_cred_t cred) 252 { 253 struct bfs_fileattr *attr = &bnode->inode->attr; 254 255 return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode, 256 vp->v_type, attr->mode), vp, NULL, genfs_can_access(vp->v_type, 257 attr->mode, attr->uid, attr->gid, mode, cred)); 258 } 259 260 int 261 sysvbfs_access(void *arg) 262 { 263 struct vop_access_args /* { 264 struct vnode *a_vp; 265 int a_mode; 266 kauth_cred_t a_cred; 267 } */ *ap = arg; 268 struct vnode *vp = ap->a_vp; 269 struct sysvbfs_node *bnode = vp->v_data; 270 int error; 271 272 DPRINTF("%s:\n", __func__); 273 274 error = sysvbfs_check_possible(vp, bnode, ap->a_mode); 275 if (error) 276 return error; 277 278 error = sysvbfs_check_permitted(vp, bnode, ap->a_mode, ap->a_cred); 279 280 return error; 281 } 282 283 int 284 sysvbfs_getattr(void *v) 285 { 286 struct vop_getattr_args /* { 287 struct vnode *a_vp; 288 struct vattr *a_vap; 289 kauth_cred_t a_cred; 290 } */ *ap = v; 291 struct vnode *vp = ap->a_vp; 292 struct sysvbfs_node *bnode = vp->v_data; 293 struct bfs_inode *inode = bnode->inode; 294 struct bfs_fileattr *attr = &inode->attr; 295 struct sysvbfs_mount *bmp = bnode->bmp; 296 struct vattr *vap = ap->a_vap; 297 298 DPRINTF("%s:\n", __func__); 299 300 vap->va_type = vp->v_type; 301 vap->va_mode = attr->mode; 302 vap->va_nlink = attr->nlink; 303 vap->va_uid = attr->uid; 304 vap->va_gid = attr->gid; 305 vap->va_fsid = bmp->devvp->v_rdev; 306 vap->va_fileid = inode->number; 307 vap->va_size = bfs_file_size(inode); 308 vap->va_blocksize = BFS_BSIZE; 309 vap->va_atime.tv_sec = attr->atime; 310 vap->va_mtime.tv_sec = attr->mtime; 311 vap->va_ctime.tv_sec = attr->ctime; 312 vap->va_birthtime.tv_sec = 0; 313 vap->va_gen = 1; 314 vap->va_flags = 0; 315 vap->va_rdev = 0; /* No device file */ 316 vap->va_bytes = vap->va_size; 317 vap->va_filerev = 0; 318 vap->va_vaflags = 0; 319 320 return 0; 321 } 322 323 int 324 sysvbfs_setattr(void *arg) 325 { 326 struct vop_setattr_args /* { 327 struct vnode *a_vp; 328 struct vattr *a_vap; 329 kauth_cred_t a_cred; 330 struct proc *p; 331 } */ *ap = arg; 332 struct vnode *vp = ap->a_vp; 333 struct vattr *vap = ap->a_vap; 334 struct sysvbfs_node *bnode = vp->v_data; 335 struct bfs_inode *inode = bnode->inode; 336 struct bfs_fileattr *attr = &inode->attr; 337 struct bfs *bfs = bnode->bmp->bfs; 338 kauth_cred_t cred = ap->a_cred; 339 int error; 340 341 DPRINTF("%s:\n", __func__); 342 if (vp->v_mount->mnt_flag & MNT_RDONLY) 343 return EROFS; 344 345 if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || 346 (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || 347 (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || 348 ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) 349 return EINVAL; 350 351 if (vap->va_flags != VNOVAL) 352 return EOPNOTSUPP; 353 354 if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) { 355 uid_t uid = 356 (vap->va_uid != (uid_t)VNOVAL) ? vap->va_uid : attr->uid; 357 gid_t gid = 358 (vap->va_gid != (gid_t)VNOVAL) ? vap->va_gid : attr->gid; 359 error = kauth_authorize_vnode(cred, 360 KAUTH_VNODE_CHANGE_OWNERSHIP, vp, NULL, 361 genfs_can_chown(cred, attr->uid, attr->gid, uid, gid)); 362 if (error) 363 return error; 364 attr->uid = uid; 365 attr->gid = gid; 366 } 367 368 if (vap->va_size != VNOVAL) 369 switch (vp->v_type) { 370 case VDIR: 371 return EISDIR; 372 case VCHR: 373 case VBLK: 374 case VFIFO: 375 break; 376 case VREG: 377 if (vp->v_mount->mnt_flag & MNT_RDONLY) 378 return EROFS; 379 sysvbfs_file_setsize(vp, vap->va_size); 380 break; 381 default: 382 return EOPNOTSUPP; 383 } 384 385 if (vap->va_mode != (mode_t)VNOVAL) { 386 mode_t mode = vap->va_mode; 387 error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, 388 vp, NULL, genfs_can_chmod(vp->v_type, cred, attr->uid, 389 attr->gid, mode)); 390 if (error) 391 return error; 392 attr->mode = mode; 393 } 394 395 if ((vap->va_atime.tv_sec != VNOVAL) || 396 (vap->va_mtime.tv_sec != VNOVAL) || 397 (vap->va_ctime.tv_sec != VNOVAL)) { 398 error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp, 399 NULL, genfs_can_chtimes(vp, vap->va_vaflags, attr->uid, 400 cred)); 401 if (error) 402 return error; 403 404 if (vap->va_atime.tv_sec != VNOVAL) 405 attr->atime = vap->va_atime.tv_sec; 406 if (vap->va_mtime.tv_sec != VNOVAL) 407 attr->mtime = vap->va_mtime.tv_sec; 408 if (vap->va_ctime.tv_sec != VNOVAL) 409 attr->ctime = vap->va_ctime.tv_sec; 410 } 411 412 bfs_inode_set_attr(bfs, inode, attr); 413 414 return 0; 415 } 416 417 int 418 sysvbfs_read(void *arg) 419 { 420 struct vop_read_args /* { 421 struct vnode *a_vp; 422 struct uio *a_uio; 423 int a_ioflag; 424 kauth_cred_t a_cred; 425 } */ *a = arg; 426 struct vnode *v = a->a_vp; 427 struct uio *uio = a->a_uio; 428 struct sysvbfs_node *bnode = v->v_data; 429 struct bfs_inode *inode = bnode->inode; 430 vsize_t sz, filesz = bfs_file_size(inode); 431 int err; 432 const int advice = IO_ADV_DECODE(a->a_ioflag); 433 434 DPRINTF("%s: type=%d\n", __func__, v->v_type); 435 switch (v->v_type) { 436 case VREG: 437 break; 438 case VDIR: 439 return EISDIR; 440 default: 441 return EINVAL; 442 } 443 444 while (uio->uio_resid > 0) { 445 if ((sz = MIN(filesz - uio->uio_offset, uio->uio_resid)) == 0) 446 break; 447 448 err = ubc_uiomove(&v->v_uobj, uio, sz, advice, 449 UBC_READ | UBC_PARTIALOK | UBC_UNMAP_FLAG(v)); 450 if (err) 451 break; 452 DPRINTF("%s: read %ldbyte\n", __func__, sz); 453 } 454 455 return sysvbfs_update(v, NULL, NULL, UPDATE_WAIT); 456 } 457 458 int 459 sysvbfs_write(void *arg) 460 { 461 struct vop_write_args /* { 462 struct vnode *a_vp; 463 struct uio *a_uio; 464 int a_ioflag; 465 kauth_cred_t a_cred; 466 } */ *a = arg; 467 struct vnode *v = a->a_vp; 468 struct uio *uio = a->a_uio; 469 int advice = IO_ADV_DECODE(a->a_ioflag); 470 struct sysvbfs_node *bnode = v->v_data; 471 bool extended = false; 472 vsize_t sz; 473 int err = 0; 474 475 if (a->a_vp->v_type != VREG) 476 return EISDIR; 477 478 if (a->a_ioflag & IO_APPEND) 479 uio->uio_offset = bnode->size; 480 481 if (uio->uio_resid == 0) 482 return 0; 483 484 if (bnode->size < uio->uio_offset + uio->uio_resid) { 485 sysvbfs_file_setsize(v, uio->uio_offset + uio->uio_resid); 486 extended = true; 487 } 488 489 while (uio->uio_resid > 0) { 490 sz = uio->uio_resid; 491 err = ubc_uiomove(&v->v_uobj, uio, sz, advice, 492 UBC_WRITE | UBC_UNMAP_FLAG(v)); 493 if (err) 494 break; 495 DPRINTF("%s: write %ldbyte\n", __func__, sz); 496 } 497 if (err) 498 sysvbfs_file_setsize(v, bnode->size - uio->uio_resid); 499 500 VN_KNOTE(v, NOTE_WRITE | (extended ? NOTE_EXTEND : 0)); 501 502 return err; 503 } 504 505 int 506 sysvbfs_remove(void *arg) 507 { 508 struct vop_remove_args /* { 509 struct vnodeop_desc *a_desc; 510 struct vnode * a_dvp; 511 struct vnode * a_vp; 512 struct componentname * a_cnp; 513 } */ *ap = arg; 514 struct vnode *vp = ap->a_vp; 515 struct vnode *dvp = ap->a_dvp; 516 struct sysvbfs_node *bnode = vp->v_data; 517 struct sysvbfs_mount *bmp = bnode->bmp; 518 struct bfs *bfs = bmp->bfs; 519 int err; 520 521 DPRINTF("%s: delete %s\n", __func__, ap->a_cnp->cn_nameptr); 522 523 if (vp->v_type == VDIR) 524 return EPERM; 525 526 if ((err = bfs_file_delete(bfs, ap->a_cnp->cn_nameptr)) != 0) 527 DPRINTF("%s: bfs_file_delete failed.\n", __func__); 528 529 VN_KNOTE(ap->a_vp, NOTE_DELETE); 530 VN_KNOTE(ap->a_dvp, NOTE_WRITE); 531 if (dvp == vp) 532 vrele(vp); 533 else 534 vput(vp); 535 vput(dvp); 536 537 if (err == 0) { 538 bnode->removed = 1; 539 } 540 541 return err; 542 } 543 544 int 545 sysvbfs_rename(void *arg) 546 { 547 struct vop_rename_args /* { 548 struct vnode *a_fdvp; from parent-directory v-node 549 struct vnode *a_fvp; from file v-node 550 struct componentname *a_fcnp; 551 struct vnode *a_tdvp; to parent-directory 552 struct vnode *a_tvp; to file v-node 553 struct componentname *a_tcnp; 554 } */ *ap = arg; 555 struct vnode *fvp = ap->a_fvp; 556 struct vnode *fdvp = ap->a_fdvp; 557 struct vnode *tvp = ap->a_tvp; 558 struct vnode *tdvp = ap->a_tdvp; 559 struct sysvbfs_node *bnode = fvp->v_data; 560 struct bfs *bfs = bnode->bmp->bfs; 561 const char *from_name = ap->a_fcnp->cn_nameptr; 562 const char *to_name = ap->a_tcnp->cn_nameptr; 563 int error; 564 565 DPRINTF("%s: %s->%s\n", __func__, from_name, to_name); 566 if ((fvp->v_mount != tdvp->v_mount) || 567 (tvp && (fvp->v_mount != tvp->v_mount))) { 568 error = EXDEV; 569 printf("cross-device link\n"); 570 goto out; 571 } 572 573 KDASSERT(fvp->v_type == VREG); 574 KDASSERT(tvp == NULL ? true : tvp->v_type == VREG); 575 KASSERT(tdvp == fdvp); 576 577 /* 578 * Make sure the source hasn't been removed between lookup 579 * and target directory lock. 580 */ 581 if (bnode->removed) { 582 error = ENOENT; 583 goto out; 584 } 585 586 error = bfs_file_rename(bfs, from_name, to_name); 587 out: 588 if (tvp) { 589 if (error == 0) { 590 struct sysvbfs_node *tbnode = tvp->v_data; 591 tbnode->removed = 1; 592 } 593 vput(tvp); 594 } 595 596 /* tdvp == tvp probably can't happen with this fs, but safety first */ 597 if (tdvp == tvp) 598 vrele(tdvp); 599 else 600 vput(tdvp); 601 602 vrele(fdvp); 603 vrele(fvp); 604 605 return 0; 606 } 607 608 int 609 sysvbfs_readdir(void *v) 610 { 611 struct vop_readdir_args /* { 612 struct vnode *a_vp; 613 struct uio *a_uio; 614 kauth_cred_t a_cred; 615 int *a_eofflag; 616 off_t **a_cookies; 617 int *a_ncookies; 618 } */ *ap = v; 619 struct uio *uio = ap->a_uio; 620 struct vnode *vp = ap->a_vp; 621 struct sysvbfs_node *bnode = vp->v_data; 622 struct bfs *bfs = bnode->bmp->bfs; 623 struct dirent *dp; 624 struct bfs_dirent *file; 625 int i, n, error; 626 627 DPRINTF("%s: offset=%" PRId64 " residue=%zu\n", __func__, 628 uio->uio_offset, uio->uio_resid); 629 630 KDASSERT(vp->v_type == VDIR); 631 KDASSERT(uio->uio_offset >= 0); 632 633 dp = malloc(sizeof(struct dirent), M_BFS, M_WAITOK | M_ZERO); 634 635 i = uio->uio_offset / sizeof(struct dirent); 636 n = uio->uio_resid / sizeof(struct dirent); 637 if ((i + n) > bfs->n_dirent) 638 n = bfs->n_dirent - i; 639 640 for (file = &bfs->dirent[i]; i < n; file++) { 641 if (file->inode == 0) 642 continue; 643 if (i == bfs->max_dirent) { 644 DPRINTF("%s: file system inconsistent.\n", 645 __func__); 646 break; 647 } 648 i++; 649 memset(dp, 0, sizeof(struct dirent)); 650 dp->d_fileno = file->inode; 651 dp->d_type = file->inode == BFS_ROOT_INODE ? DT_DIR : DT_REG; 652 dp->d_namlen = strlen(file->name); 653 strncpy(dp->d_name, file->name, BFS_FILENAME_MAXLEN); 654 dp->d_reclen = sizeof(struct dirent); 655 if ((error = uiomove(dp, dp->d_reclen, uio)) != 0) { 656 DPRINTF("%s: uiomove failed.\n", __func__); 657 free(dp, M_BFS); 658 return error; 659 } 660 } 661 DPRINTF("%s: %d %d %d\n", __func__, i, n, bfs->n_dirent); 662 *ap->a_eofflag = (i == bfs->n_dirent); 663 664 free(dp, M_BFS); 665 return 0; 666 } 667 668 int 669 sysvbfs_inactive(void *arg) 670 { 671 struct vop_inactive_args /* { 672 struct vnode *a_vp; 673 bool *a_recycle; 674 } */ *a = arg; 675 struct vnode *v = a->a_vp; 676 struct sysvbfs_node *bnode = v->v_data; 677 678 DPRINTF("%s:\n", __func__); 679 if (bnode->removed) 680 *a->a_recycle = true; 681 else 682 *a->a_recycle = false; 683 VOP_UNLOCK(v); 684 685 return 0; 686 } 687 688 int 689 sysvbfs_reclaim(void *v) 690 { 691 extern struct pool sysvbfs_node_pool; 692 struct vop_reclaim_args /* { 693 struct vnode *a_vp; 694 } */ *ap = v; 695 struct vnode *vp = ap->a_vp; 696 struct sysvbfs_node *bnode = vp->v_data; 697 698 DPRINTF("%s:\n", __func__); 699 mutex_enter(&mntvnode_lock); 700 LIST_REMOVE(bnode, link); 701 mutex_exit(&mntvnode_lock); 702 genfs_node_destroy(vp); 703 pool_put(&sysvbfs_node_pool, bnode); 704 vp->v_data = NULL; 705 706 return 0; 707 } 708 709 int 710 sysvbfs_bmap(void *arg) 711 { 712 struct vop_bmap_args /* { 713 struct vnode *a_vp; 714 daddr_t a_bn; 715 struct vnode **a_vpp; 716 daddr_t *a_bnp; 717 int *a_runp; 718 } */ *a = arg; 719 struct vnode *v = a->a_vp; 720 struct sysvbfs_node *bnode = v->v_data; 721 struct sysvbfs_mount *bmp = bnode->bmp; 722 struct bfs_inode *inode = bnode->inode; 723 daddr_t blk; 724 725 DPRINTF("%s:\n", __func__); 726 /* BFS algorithm is contiguous allocation */ 727 blk = inode->start_sector + a->a_bn; 728 729 if (blk * BFS_BSIZE > bmp->bfs->data_end) 730 return ENOSPC; 731 732 *a->a_vpp = bmp->devvp; 733 *a->a_runp = 0; 734 DPRINTF("%s: %d + %" PRId64 "\n", __func__, inode->start_sector, 735 a->a_bn); 736 737 *a->a_bnp = blk; 738 739 740 return 0; 741 } 742 743 int 744 sysvbfs_strategy(void *arg) 745 { 746 struct vop_strategy_args /* { 747 struct vnode *a_vp; 748 struct buf *a_bp; 749 } */ *a = arg; 750 struct buf *b = a->a_bp; 751 struct vnode *v = a->a_vp; 752 struct sysvbfs_node *bnode = v->v_data; 753 struct sysvbfs_mount *bmp = bnode->bmp; 754 int error; 755 756 DPRINTF("%s:\n", __func__); 757 KDASSERT(v->v_type == VREG); 758 if (b->b_blkno == b->b_lblkno) { 759 error = VOP_BMAP(v, b->b_lblkno, NULL, &b->b_blkno, NULL); 760 if (error) { 761 b->b_error = error; 762 biodone(b); 763 return error; 764 } 765 if ((long)b->b_blkno == -1) 766 clrbuf(b); 767 } 768 if ((long)b->b_blkno == -1) { 769 biodone(b); 770 return 0; 771 } 772 773 return VOP_STRATEGY(bmp->devvp, b); 774 } 775 776 int 777 sysvbfs_print(void *v) 778 { 779 struct vop_print_args /* { 780 struct vnode *a_vp; 781 } */ *ap = v; 782 struct sysvbfs_node *bnode = ap->a_vp->v_data; 783 784 DPRINTF("%s:\n", __func__); 785 bfs_dump(bnode->bmp->bfs); 786 787 return 0; 788 } 789 790 int 791 sysvbfs_advlock(void *v) 792 { 793 struct vop_advlock_args /* { 794 struct vnode *a_vp; 795 void *a_id; 796 int a_op; 797 struct flock *a_fl; 798 int a_flags; 799 } */ *ap = v; 800 struct sysvbfs_node *bnode = ap->a_vp->v_data; 801 802 DPRINTF("%s: op=%d\n", __func__, ap->a_op); 803 804 return lf_advlock(ap, &bnode->lockf, bfs_file_size(bnode->inode)); 805 } 806 807 int 808 sysvbfs_pathconf(void *v) 809 { 810 struct vop_pathconf_args /* { 811 struct vnode *a_vp; 812 int a_name; 813 register_t *a_retval; 814 } */ *ap = v; 815 int err = 0; 816 817 DPRINTF("%s:\n", __func__); 818 819 switch (ap->a_name) { 820 case _PC_LINK_MAX: 821 *ap->a_retval = 1; 822 break; 823 case _PC_NAME_MAX: 824 *ap->a_retval = BFS_FILENAME_MAXLEN; 825 break; 826 case _PC_PATH_MAX: 827 *ap->a_retval = BFS_FILENAME_MAXLEN; 828 break; 829 case _PC_CHOWN_RESTRICTED: 830 *ap->a_retval = 1; 831 break; 832 case _PC_NO_TRUNC: 833 *ap->a_retval = 0; 834 break; 835 case _PC_SYNC_IO: 836 *ap->a_retval = 1; 837 break; 838 case _PC_FILESIZEBITS: 839 *ap->a_retval = 32; 840 break; 841 default: 842 err = EINVAL; 843 break; 844 } 845 846 return err; 847 } 848 849 int 850 sysvbfs_fsync(void *v) 851 { 852 struct vop_fsync_args /* { 853 struct vnode *a_vp; 854 kauth_cred_t a_cred; 855 int a_flags; 856 off_t offlo; 857 off_t offhi; 858 } */ *ap = v; 859 struct vnode *vp = ap->a_vp; 860 int error, wait; 861 862 if (ap->a_flags & FSYNC_CACHE) { 863 return EOPNOTSUPP; 864 } 865 866 wait = (ap->a_flags & FSYNC_WAIT) != 0; 867 error = vflushbuf(vp, ap->a_flags); 868 if (error == 0 && (ap->a_flags & FSYNC_DATAONLY) == 0) 869 error = sysvbfs_update(vp, NULL, NULL, wait ? UPDATE_WAIT : 0); 870 871 return error; 872 } 873 874 int 875 sysvbfs_update(struct vnode *vp, const struct timespec *acc, 876 const struct timespec *mod, int flags) 877 { 878 struct sysvbfs_node *bnode = vp->v_data; 879 struct bfs_fileattr attr; 880 881 if (vp->v_mount->mnt_flag & MNT_RDONLY) 882 return 0; 883 884 DPRINTF("%s:\n", __func__); 885 memset(&attr, 0xff, sizeof attr); /* Set VNOVAL all */ 886 if (bnode->update_atime) { 887 attr.atime = acc ? acc->tv_sec : time_second; 888 bnode->update_atime = false; 889 } 890 if (bnode->update_ctime) { 891 attr.ctime = time_second; 892 bnode->update_ctime = false; 893 } 894 if (bnode->update_mtime) { 895 attr.mtime = mod ? mod->tv_sec : time_second; 896 bnode->update_mtime = false; 897 } 898 bfs_inode_set_attr(bnode->bmp->bfs, bnode->inode, &attr); 899 900 return 0; 901 } 902 903 static void 904 sysvbfs_file_setsize(struct vnode *v, size_t size) 905 { 906 struct sysvbfs_node *bnode = v->v_data; 907 struct bfs_inode *inode = bnode->inode; 908 909 bnode->size = size; 910 uvm_vnp_setsize(v, bnode->size); 911 inode->end_sector = bnode->data_block + 912 (ROUND_SECTOR(bnode->size) >> DEV_BSHIFT) - 1; 913 inode->eof_offset_byte = bnode->data_block * DEV_BSIZE + 914 bnode->size - 1; 915 bnode->update_mtime = true; 916 } 917