1 /*- 2 * Copyright (c) 1998, 1999 Semen Ustimenko (semenu@FreeBSD.org) 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: src/sys/fs/hpfs/hpfs_vnops.c,v 1.2.2.2 2002/01/15 18:35:09 semenu Exp $ 27 * $DragonFly: src/sys/vfs/hpfs/hpfs_vnops.c,v 1.46 2007/11/20 21:03:50 dillon Exp $ 28 */ 29 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/kernel.h> 33 #include <sys/proc.h> 34 #include <sys/time.h> 35 #include <sys/types.h> 36 #include <sys/stat.h> 37 #include <sys/vnode.h> 38 #include <sys/mount.h> 39 #include <sys/namei.h> 40 #include <sys/malloc.h> 41 #include <sys/buf.h> 42 #include <sys/dirent.h> 43 44 #include <machine/limits.h> 45 46 #include <vm/vm.h> 47 #include <vm/vm_param.h> 48 #if !defined(__DragonFly__) 49 #include <vm/vm_prot.h> 50 #endif 51 #include <vm/vm_page.h> 52 #include <vm/vm_object.h> 53 #include <vm/vm_pager.h> 54 #include <vm/vm_zone.h> 55 #if defined(__DragonFly__) 56 #include <vm/vnode_pager.h> 57 #endif 58 #include <vm/vm_extern.h> 59 #include <sys/buf2.h> 60 61 #if !defined(__DragonFly__) 62 #include <miscfs/specfs/specdev.h> 63 #include <miscfs/genfs/genfs.h> 64 #endif 65 66 #include <sys/unistd.h> /* for pathconf(2) constants */ 67 68 #include "hpfs.h" 69 #include "hpfsmount.h" 70 #include "hpfs_subr.h" 71 #include "hpfs_ioctl.h" 72 73 static int hpfs_de_uiomove (int *, struct hpfsmount *, 74 struct hpfsdirent *, struct uio *); 75 static int hpfs_ioctl (struct vop_ioctl_args *ap); 76 static int hpfs_read (struct vop_read_args *); 77 static int hpfs_write (struct vop_write_args *ap); 78 static int hpfs_getattr (struct vop_getattr_args *ap); 79 static int hpfs_setattr (struct vop_setattr_args *ap); 80 static int hpfs_inactive (struct vop_inactive_args *ap); 81 static int hpfs_print (struct vop_print_args *ap); 82 static int hpfs_reclaim (struct vop_reclaim_args *ap); 83 static int hpfs_strategy (struct vop_strategy_args *ap); 84 static int hpfs_access (struct vop_access_args *ap); 85 static int hpfs_readdir (struct vop_readdir_args *ap); 86 static int hpfs_lookup (struct vop_old_lookup_args *ap); 87 static int hpfs_create (struct vop_old_create_args *); 88 static int hpfs_remove (struct vop_old_remove_args *); 89 static int hpfs_bmap (struct vop_bmap_args *ap); 90 #if defined(__DragonFly__) 91 static int hpfs_fsync (struct vop_fsync_args *ap); 92 #endif 93 static int hpfs_pathconf (struct vop_pathconf_args *ap); 94 95 #if defined(__DragonFly__) 96 97 /* 98 * hpfs_fsync(struct vnode *a_vp, int a_waitfor) 99 */ 100 static int 101 hpfs_fsync(struct vop_fsync_args *ap) 102 { 103 struct vnode *vp = ap->a_vp; 104 105 /* 106 * Flush all dirty buffers associated with a vnode. 107 */ 108 #ifdef DIAGNOSTIC 109 loop: 110 #endif 111 vfsync(vp, ap->a_waitfor, 0, NULL, NULL); 112 #ifdef DIAGNOSTIC 113 if (ap->a_waitfor == MNT_WAIT && !RB_EMPTY(&vp->v_rbdirty_tree)) { 114 vprint("hpfs_fsync: dirty", vp); 115 goto loop; 116 } 117 #endif 118 119 /* 120 * Write out the on-disc version of the vnode. 121 */ 122 return hpfs_update(VTOHP(vp)); 123 } 124 125 #endif 126 127 /* 128 * hpfs_ioctl(struct vnode *a_vp, u_long a_command, caddr_t a_data, 129 * int a_fflag, struct ucred *a_cred) 130 */ 131 static int 132 hpfs_ioctl(struct vop_ioctl_args *ap) 133 { 134 struct vnode *vp = ap->a_vp; 135 struct hpfsnode *hp = VTOHP(vp); 136 int error; 137 138 kprintf("hpfs_ioctl(0x%x, 0x%lx, 0x%p, 0x%x): ", 139 hp->h_no, ap->a_command, ap->a_data, ap->a_fflag); 140 141 switch (ap->a_command) { 142 case HPFSIOCGEANUM: { 143 u_long eanum; 144 u_long passed; 145 struct ea *eap; 146 147 eanum = 0; 148 149 if (hp->h_fn.fn_ealen > 0) { 150 eap = (struct ea *)&(hp->h_fn.fn_int); 151 passed = 0; 152 153 while (passed < hp->h_fn.fn_ealen) { 154 155 kprintf("EAname: %s\n", EA_NAME(eap)); 156 157 eanum++; 158 passed += sizeof(struct ea) + 159 eap->ea_namelen + 1 + eap->ea_vallen; 160 eap = (struct ea *)((caddr_t)hp->h_fn.fn_int + 161 passed); 162 } 163 error = 0; 164 } else { 165 error = ENOENT; 166 } 167 168 kprintf("%lu eas\n", eanum); 169 170 *(u_long *)ap->a_data = eanum; 171 172 break; 173 } 174 case HPFSIOCGEASZ: { 175 u_long eanum; 176 u_long passed; 177 struct ea *eap; 178 179 kprintf("EA%ld\n", *(u_long *)ap->a_data); 180 181 eanum = 0; 182 if (hp->h_fn.fn_ealen > 0) { 183 eap = (struct ea *)&(hp->h_fn.fn_int); 184 passed = 0; 185 186 error = ENOENT; 187 while (passed < hp->h_fn.fn_ealen) { 188 kprintf("EAname: %s\n", EA_NAME(eap)); 189 190 if (eanum == *(u_long *)ap->a_data) { 191 *(u_long *)ap->a_data = 192 eap->ea_namelen + 1 + 193 eap->ea_vallen; 194 195 error = 0; 196 break; 197 } 198 199 eanum++; 200 passed += sizeof(struct ea) + 201 eap->ea_namelen + 1 + eap->ea_vallen; 202 eap = (struct ea *)((caddr_t)hp->h_fn.fn_int + 203 passed); 204 } 205 } else { 206 error = ENOENT; 207 } 208 209 break; 210 } 211 case HPFSIOCRDEA: { 212 u_long eanum; 213 u_long passed; 214 struct hpfs_rdea *rdeap; 215 struct ea *eap; 216 217 rdeap = (struct hpfs_rdea *)ap->a_data; 218 kprintf("EA%ld\n", rdeap->ea_no); 219 220 eanum = 0; 221 if (hp->h_fn.fn_ealen > 0) { 222 eap = (struct ea *)&(hp->h_fn.fn_int); 223 passed = 0; 224 225 error = ENOENT; 226 while (passed < hp->h_fn.fn_ealen) { 227 kprintf("EAname: %s\n", EA_NAME(eap)); 228 229 if (eanum == rdeap->ea_no) { 230 rdeap->ea_sz = eap->ea_namelen + 1 + 231 eap->ea_vallen; 232 copyout(EA_NAME(eap),rdeap->ea_data, 233 rdeap->ea_sz); 234 error = 0; 235 break; 236 } 237 238 eanum++; 239 passed += sizeof(struct ea) + 240 eap->ea_namelen + 1 + eap->ea_vallen; 241 eap = (struct ea *)((caddr_t)hp->h_fn.fn_int + 242 passed); 243 } 244 } else { 245 error = ENOENT; 246 } 247 248 break; 249 } 250 default: 251 error = EOPNOTSUPP; 252 break; 253 } 254 return (error); 255 } 256 257 /* 258 * Map file offset to disk offset. 259 * 260 * hpfs_bmap(struct vnode *a_vp, off_t a_loffset, 261 * off_t *a_doffsetp, int *a_runp, int *a_runb) 262 */ 263 int 264 hpfs_bmap(struct vop_bmap_args *ap) 265 { 266 struct hpfsnode *hp = VTOHP(ap->a_vp); 267 int error; 268 daddr_t lbn; 269 daddr_t dbn; 270 271 if (ap->a_runb != NULL) 272 *ap->a_runb = 0; 273 if (ap->a_doffsetp == NULL) 274 return (0); 275 276 dprintf(("hpfs_bmap(0x%x, 0x%x): ",hp->h_no, ap->a_bn)); 277 278 lbn = ap->a_loffset >> DEV_BSHIFT; 279 KKASSERT(((int)ap->a_loffset & DEV_BMASK) == 0); 280 281 error = hpfs_hpbmap (hp, lbn, &dbn, ap->a_runp); 282 if (error || dbn == (daddr_t)-1) { 283 *ap->a_doffsetp = NOOFFSET; 284 } else { 285 *ap->a_doffsetp = (off_t)dbn << DEV_BSHIFT; 286 } 287 return (error); 288 } 289 290 /* 291 * hpfs_read(struct vnode *a_vp, struct uio *a_uio, int a_ioflag, 292 * struct ucred *a_cred) 293 */ 294 static int 295 hpfs_read(struct vop_read_args *ap) 296 { 297 struct vnode *vp = ap->a_vp; 298 struct hpfsnode *hp = VTOHP(vp); 299 struct uio *uio = ap->a_uio; 300 struct buf *bp; 301 u_int xfersz, toread; 302 u_int off; 303 daddr_t lbn, bn; 304 int resid; 305 int runl; 306 int error = 0; 307 308 resid = min (uio->uio_resid, hp->h_fn.fn_size - uio->uio_offset); 309 310 dprintf(("hpfs_read(0x%x, off: %d resid: %d, segflg: %d): [resid: 0x%x]\n",hp->h_no,(u_int32_t)uio->uio_offset,uio->uio_resid,uio->uio_segflg, resid)); 311 312 while (resid) { 313 lbn = uio->uio_offset >> DEV_BSHIFT; 314 off = uio->uio_offset & (DEV_BSIZE - 1); 315 dprintf(("hpfs_read: resid: 0x%x lbn: 0x%x off: 0x%x\n", 316 uio->uio_resid, lbn, off)); 317 error = hpfs_hpbmap(hp, lbn, &bn, &runl); 318 if (error) 319 return (error); 320 321 toread = min(off + resid, min(DFLTPHYS, (runl+1)*DEV_BSIZE)); 322 xfersz = (toread + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1); 323 dprintf(("hpfs_read: bn: 0x%x (0x%x) toread: 0x%x (0x%x)\n", 324 bn, runl, toread, xfersz)); 325 326 if (toread == 0) 327 break; 328 329 error = bread(hp->h_devvp, dbtodoff(bn), xfersz, &bp); 330 if (error) { 331 brelse(bp); 332 break; 333 } 334 335 error = uiomove(bp->b_data + off, toread - off, uio); 336 if(error) { 337 brelse(bp); 338 break; 339 } 340 brelse(bp); 341 resid -= toread; 342 } 343 dprintf(("hpfs_read: successful\n")); 344 return (error); 345 } 346 347 /* 348 * hpfs_write(struct vnode *a_vp, struct uio *a_uio, int a_ioflag, 349 * struct ucred *a_cred) 350 */ 351 static int 352 hpfs_write(struct vop_write_args *ap) 353 { 354 struct vnode *vp = ap->a_vp; 355 struct hpfsnode *hp = VTOHP(vp); 356 struct uio *uio = ap->a_uio; 357 struct buf *bp; 358 u_int xfersz, towrite; 359 u_int off; 360 daddr_t lbn, bn; 361 int runl; 362 int error = 0; 363 364 dprintf(("hpfs_write(0x%x, off: %d resid: %d, segflg: %d):\n",hp->h_no,(u_int32_t)uio->uio_offset,uio->uio_resid,uio->uio_segflg)); 365 366 if (ap->a_ioflag & IO_APPEND) { 367 dprintf(("hpfs_write: APPEND mode\n")); 368 uio->uio_offset = hp->h_fn.fn_size; 369 } 370 if (uio->uio_offset + uio->uio_resid > hp->h_fn.fn_size) { 371 error = hpfs_extend (hp, uio->uio_offset + uio->uio_resid); 372 if (error) { 373 kprintf("hpfs_write: hpfs_extend FAILED %d\n", error); 374 return (error); 375 } 376 } 377 378 while (uio->uio_resid) { 379 lbn = uio->uio_offset >> DEV_BSHIFT; 380 off = uio->uio_offset & (DEV_BSIZE - 1); 381 dprintf(("hpfs_write: resid: 0x%x lbn: 0x%x off: 0x%x\n", 382 uio->uio_resid, lbn, off)); 383 error = hpfs_hpbmap(hp, lbn, &bn, &runl); 384 if (error) 385 return (error); 386 387 towrite = min(off + uio->uio_resid, min(DFLTPHYS, (runl+1)*DEV_BSIZE)); 388 xfersz = (towrite + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1); 389 dprintf(("hpfs_write: bn: 0x%x (0x%x) towrite: 0x%x (0x%x)\n", 390 bn, runl, towrite, xfersz)); 391 392 /* 393 * We do not have to issue a read-before-write if the xfer 394 * size does not cover the whole block. 395 * 396 * In the UIO_NOCOPY case, however, we are not overwriting 397 * anything and must do a read-before-write to fill in 398 * any missing pieces. 399 */ 400 if (off == 0 && towrite == xfersz && 401 uio->uio_segflg != UIO_NOCOPY) { 402 bp = getblk(hp->h_devvp, dbtodoff(bn), xfersz, 0, 0); 403 clrbuf(bp); 404 } else { 405 error = bread(hp->h_devvp, dbtodoff(bn), xfersz, &bp); 406 if (error) { 407 brelse(bp); 408 return (error); 409 } 410 } 411 412 error = uiomove(bp->b_data + off, towrite - off, uio); 413 if(error) { 414 brelse(bp); 415 return (error); 416 } 417 418 if (ap->a_ioflag & IO_SYNC) 419 bwrite(bp); 420 else 421 bawrite(bp); 422 } 423 424 dprintf(("hpfs_write: successful\n")); 425 return (0); 426 } 427 428 /* 429 * XXXXX do we need hpfsnode locking inside? 430 * 431 * hpfs_getattr(struct vnode *a_vp, struct vattr *a_vap) 432 */ 433 static int 434 hpfs_getattr(struct vop_getattr_args *ap) 435 { 436 struct vnode *vp = ap->a_vp; 437 struct hpfsnode *hp = VTOHP(vp); 438 struct vattr *vap = ap->a_vap; 439 int error; 440 441 dprintf(("hpfs_getattr(0x%x):\n", hp->h_no)); 442 443 #if defined(__DragonFly__) 444 vap->va_fsid = dev2udev(hp->h_dev); 445 #else /* defined(__NetBSD__) */ 446 vap->va_fsid = ip->i_dev; 447 #endif 448 vap->va_fileid = hp->h_no; 449 vap->va_mode = hp->h_mode; 450 vap->va_nlink = 1; 451 vap->va_uid = hp->h_uid; 452 vap->va_gid = hp->h_gid; 453 vap->va_rmajor = VNOVAL; 454 vap->va_rminor = VNOVAL; 455 vap->va_size = hp->h_fn.fn_size; 456 vap->va_bytes = ((hp->h_fn.fn_size + DEV_BSIZE-1) & ~(DEV_BSIZE-1)) + 457 DEV_BSIZE; 458 459 if (!(hp->h_flag & H_PARVALID)) { 460 error = hpfs_validateparent(hp); 461 if (error) 462 return (error); 463 } 464 vap->va_atime = hpfstimetounix(hp->h_atime); 465 vap->va_mtime = hpfstimetounix(hp->h_mtime); 466 vap->va_ctime = hpfstimetounix(hp->h_ctime); 467 468 vap->va_flags = 0; 469 vap->va_gen = 0; 470 vap->va_blocksize = DEV_BSIZE; 471 vap->va_type = vp->v_type; 472 vap->va_filerev = 0; 473 474 return (0); 475 } 476 477 /* 478 * XXXXX do we need hpfsnode locking inside? 479 * 480 * hpfs_setattr(struct vnode *a_vp, struct vattr *a_vap, struct ucred *a_cred) 481 */ 482 static int 483 hpfs_setattr(struct vop_setattr_args *ap) 484 { 485 struct vnode *vp = ap->a_vp; 486 struct hpfsnode *hp = VTOHP(vp); 487 struct vattr *vap = ap->a_vap; 488 struct ucred *cred = ap->a_cred; 489 int error; 490 491 dprintf(("hpfs_setattr(0x%x):\n", hp->h_no)); 492 493 /* 494 * Check for unsettable attributes. 495 */ 496 if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || 497 (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || 498 (vap->va_blocksize != VNOVAL) || (vap->va_rmajor != VNOVAL) || 499 (vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { 500 dprintf(("hpfs_setattr: changing nonsettable attr\n")); 501 return (EINVAL); 502 } 503 504 /* Can't change flags XXX Could be implemented */ 505 if (vap->va_flags != VNOVAL) { 506 kprintf("hpfs_setattr: FLAGS CANNOT BE SET\n"); 507 return (EINVAL); 508 } 509 510 /* Can't change uid/gid XXX Could be implemented */ 511 if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) { 512 kprintf("hpfs_setattr: UID/GID CANNOT BE SET\n"); 513 return (EINVAL); 514 } 515 516 /* Can't change mode XXX Could be implemented */ 517 if (vap->va_mode != (mode_t)VNOVAL) { 518 kprintf("hpfs_setattr: MODE CANNOT BE SET\n"); 519 return (EINVAL); 520 } 521 522 /* Update times */ 523 if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { 524 if (vp->v_mount->mnt_flag & MNT_RDONLY) 525 return (EROFS); 526 if (cred->cr_uid != hp->h_uid && 527 (error = suser_cred(cred, PRISON_ROOT)) && 528 ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || 529 (error = VOP_ACCESS(vp, VWRITE, cred)))) 530 return (error); 531 if (vap->va_atime.tv_sec != VNOVAL) 532 hp->h_atime = vap->va_atime.tv_sec; 533 if (vap->va_mtime.tv_sec != VNOVAL) 534 hp->h_mtime = vap->va_mtime.tv_sec; 535 536 hp->h_flag |= H_PARCHANGE; 537 } 538 539 if (vap->va_size != VNOVAL) { 540 switch (vp->v_type) { 541 case VDIR: 542 return (EISDIR); 543 case VREG: 544 if (vp->v_mount->mnt_flag & MNT_RDONLY) 545 return (EROFS); 546 break; 547 default: 548 kprintf("hpfs_setattr: WRONG v_type\n"); 549 return (EINVAL); 550 } 551 552 if (vap->va_size < hp->h_fn.fn_size) { 553 #if defined(__DragonFly__) 554 error = vtruncbuf(vp, vap->va_size, DEV_BSIZE); 555 if (error) 556 return (error); 557 #else /* defined(__NetBSD__) */ 558 #error Need alternation for vtruncbuf() 559 #endif 560 error = hpfs_truncate(hp, vap->va_size); 561 if (error) 562 return (error); 563 564 } else if (vap->va_size > hp->h_fn.fn_size) { 565 #if defined(__DragonFly__) 566 vnode_pager_setsize(vp, vap->va_size); 567 #endif 568 error = hpfs_extend(hp, vap->va_size); 569 if (error) 570 return (error); 571 } 572 } 573 574 return (0); 575 } 576 577 /* 578 * Last reference to an node. If necessary, write or delete it. 579 * 580 * hpfs_inactive(struct vnode *a_vp) 581 */ 582 int 583 hpfs_inactive(struct vop_inactive_args *ap) 584 { 585 struct vnode *vp = ap->a_vp; 586 struct hpfsnode *hp = VTOHP(vp); 587 int error; 588 589 dprintf(("hpfs_inactive(0x%x): \n", hp->h_no)); 590 591 if (hp->h_flag & H_CHANGE) { 592 dprintf(("hpfs_inactive: node changed, update\n")); 593 error = hpfs_update (hp); 594 if (error) 595 return (error); 596 } 597 598 if (hp->h_flag & H_PARCHANGE) { 599 dprintf(("hpfs_inactive: parent node changed, update\n")); 600 error = hpfs_updateparent (hp); 601 if (error) 602 return (error); 603 } 604 605 if (prtactive && vp->v_sysref.refcnt > 1) 606 vprint("hpfs_inactive: pushing active", vp); 607 608 if (hp->h_flag & H_INVAL) { 609 #if defined(__DragonFly__) 610 vrecycle(vp); 611 #else /* defined(__NetBSD__) */ 612 vgone(vp); 613 #endif 614 return (0); 615 } 616 return (0); 617 } 618 619 /* 620 * Reclaim an inode so that it can be used for other purposes. 621 * 622 * hpfs_reclaim(struct vnode *a_vp) 623 */ 624 int 625 hpfs_reclaim(struct vop_reclaim_args *ap) 626 { 627 struct vnode *vp = ap->a_vp; 628 struct hpfsnode *hp = VTOHP(vp); 629 630 dprintf(("hpfs_reclaim(0x%x0): \n", hp->h_no)); 631 632 hpfs_hphashrem(hp); 633 634 /* Purge old data structures associated with the inode. */ 635 if (hp->h_devvp) { 636 vrele(hp->h_devvp); 637 hp->h_devvp = NULL; 638 } 639 640 vp->v_data = NULL; 641 642 FREE(hp, M_HPFSNO); 643 644 return (0); 645 } 646 647 /* 648 * hpfs_print(struct vnode *a_vp) 649 */ 650 static int 651 hpfs_print(struct vop_print_args *ap) 652 { 653 struct vnode *vp = ap->a_vp; 654 struct hpfsnode *hp = VTOHP(vp); 655 656 kprintf("tag VT_HPFS, ino 0x%x",hp->h_no); 657 lockmgr_printinfo(&vp->v_lock); 658 kprintf("\n"); 659 return (0); 660 } 661 662 /* 663 * Calculate the logical to physical mapping if not done already, 664 * then call the device strategy routine. 665 * 666 * In order to be able to swap to a file, the VOP_BMAP operation may not 667 * deadlock on memory. See hpfs_bmap() for details. XXXXXXX (not impl) 668 * 669 * hpfs_strategy(struct vnode *a_vp, struct bio *a_bio) 670 */ 671 int 672 hpfs_strategy(struct vop_strategy_args *ap) 673 { 674 struct bio *bio = ap->a_bio; 675 struct bio *nbio; 676 struct buf *bp = bio->bio_buf; 677 struct vnode *vp = ap->a_vp; 678 struct hpfsnode *hp; 679 int error; 680 681 dprintf(("hpfs_strategy(): \n")); 682 683 if (vp->v_type == VBLK || vp->v_type == VCHR) 684 panic("hpfs_strategy: spec"); 685 686 nbio = push_bio(bio); 687 if (nbio->bio_offset == NOOFFSET) { 688 error = VOP_BMAP(vp, bio->bio_offset, &nbio->bio_offset, 689 NULL, NULL); 690 if (error) { 691 kprintf("hpfs_strategy: VOP_BMAP FAILED %d\n", error); 692 bp->b_error = error; 693 bp->b_flags |= B_ERROR; 694 /* I/O was never started on nbio, must biodone(bio) */ 695 biodone(bio); 696 return (error); 697 } 698 if (nbio->bio_offset == NOOFFSET) 699 vfs_bio_clrbuf(bp); 700 } 701 if (nbio->bio_offset == NOOFFSET) { 702 /* I/O was never started on nbio, must biodone(bio) */ 703 biodone(bio); 704 return (0); 705 } 706 hp = VTOHP(ap->a_vp); 707 vn_strategy(hp->h_devvp, nbio); 708 return (0); 709 } 710 711 /* 712 * XXXXX do we need hpfsnode locking inside? 713 * 714 * hpfs_access(struct vnode *a_vp, int a_mode, struct ucred *a_cred) 715 */ 716 int 717 hpfs_access(struct vop_access_args *ap) 718 { 719 struct vnode *vp = ap->a_vp; 720 struct hpfsnode *hp = VTOHP(vp); 721 struct ucred *cred = ap->a_cred; 722 mode_t mask, mode = ap->a_mode; 723 gid_t *gp; 724 int i; 725 726 dprintf(("hpfs_access(0x%x):\n", hp->h_no)); 727 728 /* 729 * Disallow write attempts on read-only file systems; 730 * unless the file is a socket, fifo, or a block or 731 * character device resident on the file system. 732 */ 733 if (mode & VWRITE) { 734 switch ((int)vp->v_type) { 735 case VDIR: 736 case VLNK: 737 case VREG: 738 if (vp->v_mount->mnt_flag & MNT_RDONLY) 739 return (EROFS); 740 break; 741 } 742 } 743 744 /* Otherwise, user id 0 always gets access. */ 745 if (cred->cr_uid == 0) 746 return (0); 747 748 mask = 0; 749 750 /* Otherwise, check the owner. */ 751 if (cred->cr_uid == hp->h_uid) { 752 if (mode & VEXEC) 753 mask |= S_IXUSR; 754 if (mode & VREAD) 755 mask |= S_IRUSR; 756 if (mode & VWRITE) 757 mask |= S_IWUSR; 758 return ((hp->h_mode & mask) == mask ? 0 : EACCES); 759 } 760 761 /* Otherwise, check the groups. */ 762 for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++) 763 if (hp->h_gid == *gp) { 764 if (mode & VEXEC) 765 mask |= S_IXGRP; 766 if (mode & VREAD) 767 mask |= S_IRGRP; 768 if (mode & VWRITE) 769 mask |= S_IWGRP; 770 return ((hp->h_mode & mask) == mask ? 0 : EACCES); 771 } 772 773 /* Otherwise, check everyone else. */ 774 if (mode & VEXEC) 775 mask |= S_IXOTH; 776 if (mode & VREAD) 777 mask |= S_IROTH; 778 if (mode & VWRITE) 779 mask |= S_IWOTH; 780 return ((hp->h_mode & mask) == mask ? 0 : EACCES); 781 } 782 783 static int 784 hpfs_de_uiomove(int *error, struct hpfsmount *hpmp, struct hpfsdirent *dep, 785 struct uio *uio) 786 { 787 char convname[HPFS_MAXFILENAME + 1]; 788 int i, success; 789 790 dprintf(("[no: 0x%x, size: %d, name: %2d:%.*s, flag: 0x%x] ", 791 dep->de_fnode, dep->de_size, dep->de_namelen, 792 dep->de_namelen, dep->de_name, dep->de_flag)); 793 794 /*strncpy(cde.d_name, dep->de_name, dep->de_namelen);*/ 795 for (i=0; i<dep->de_namelen; i++) 796 convname[i] = hpfs_d2u(hpmp, dep->de_name[i]); 797 convname[dep->de_namelen] = '\0'; 798 799 success = vop_write_dirent(error, uio, dep->de_fnode, 800 (dep->de_flag & DE_DIR) ? DT_DIR : DT_REG, 801 dep->de_namelen, convname); 802 803 dprintf(("[0x%x] ", uio->uio_resid)); 804 return (success); 805 } 806 807 808 /* 809 * hpfs_readdir(struct vnode *a_vp, struct uio *a_uio, struct ucred *a_cred, 810 * int *a_ncookies, off_t **cookies) 811 */ 812 int 813 hpfs_readdir(struct vop_readdir_args *ap) 814 { 815 struct vnode *vp = ap->a_vp; 816 struct hpfsnode *hp = VTOHP(vp); 817 struct hpfsmount *hpmp = hp->h_hpmp; 818 struct uio *uio = ap->a_uio; 819 int ncookies = 0, i, num, cnum; 820 int error = 0; 821 struct buf *bp; 822 struct dirblk *dp; 823 struct hpfsdirent *dep; 824 lsn_t olsn; 825 lsn_t lsn; 826 int level; 827 828 dprintf(("hpfs_readdir(0x%x, 0x%x, 0x%x): ",hp->h_no,(u_int32_t)uio->uio_offset,uio->uio_resid)); 829 830 /* 831 * As we need to fake up . and .., and the remaining directory structure 832 * can't be expressed in one off_t as well, we just increment uio_offset 833 * by 1 for each entry. 834 * 835 * num is the entry we need to start reporting 836 * cnum is the current entry 837 */ 838 if (uio->uio_offset < 0 || uio->uio_offset > INT_MAX) 839 return(EINVAL); 840 if ((error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY)) != 0) 841 return (error); 842 843 num = uio->uio_offset; 844 cnum = 0; 845 846 if( num <= cnum ) { 847 dprintf((". faked, ")); 848 if (vop_write_dirent(&error, uio, hp->h_no, DT_DIR, 1, ".")) 849 goto done; 850 if (error) 851 goto done; 852 ncookies ++; 853 } 854 cnum++; 855 856 if( num <= cnum ) { 857 dprintf((".. faked, ")); 858 if (vop_write_dirent(&error, uio, hp->h_fn.fn_parent, DT_DIR, 2, "..")) 859 goto readdone; 860 if (error) 861 goto done; 862 ncookies ++; 863 } 864 cnum++; 865 866 lsn = ((alleaf_t *)hp->h_fn.fn_abd)->al_lsn; 867 868 olsn = 0; 869 level = 1; 870 871 dive: 872 dprintf(("[dive 0x%x] ", lsn)); 873 error = bread(hp->h_devvp, dbtodoff(lsn), D_BSIZE, &bp); 874 if (error) { 875 brelse(bp); 876 goto done; 877 } 878 879 dp = (struct dirblk *) bp->b_data; 880 if (dp->d_magic != D_MAGIC) { 881 kprintf("hpfs_readdir: MAGIC DOESN'T MATCH\n"); 882 brelse(bp); 883 error = EINVAL; 884 goto done; 885 } 886 887 dep = D_DIRENT(dp); 888 889 if (olsn) { 890 dprintf(("[restore 0x%x] ", olsn)); 891 892 while(!(dep->de_flag & DE_END) ) { 893 if((dep->de_flag & DE_DOWN) && 894 (olsn == DE_DOWNLSN(dep))) 895 break; 896 dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen); 897 } 898 899 if((dep->de_flag & DE_DOWN) && (olsn == DE_DOWNLSN(dep))) { 900 if (dep->de_flag & DE_END) 901 goto blockdone; 902 903 if (!(dep->de_flag & DE_SPECIAL)) { 904 if (num <= cnum) { 905 if (hpfs_de_uiomove(&error, hpmp, dep, uio)) { 906 brelse(bp); 907 dprintf(("[resid] ")); 908 goto readdone; 909 } 910 if (error) { 911 brelse (bp); 912 goto done; 913 } 914 ncookies++; 915 } 916 cnum++; 917 } 918 919 dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen); 920 } else { 921 kprintf("hpfs_readdir: ERROR! oLSN not found\n"); 922 brelse(bp); 923 error = EINVAL; 924 goto done; 925 } 926 } 927 928 olsn = 0; 929 930 while(!(dep->de_flag & DE_END)) { 931 if(dep->de_flag & DE_DOWN) { 932 lsn = DE_DOWNLSN(dep); 933 brelse(bp); 934 level++; 935 goto dive; 936 } 937 938 if (!(dep->de_flag & DE_SPECIAL)) { 939 if (num <= cnum) { 940 if (hpfs_de_uiomove(&error, hpmp, dep, uio)) { 941 brelse(bp); 942 dprintf(("[resid] ")); 943 goto readdone; 944 } 945 if (error) { 946 brelse (bp); 947 goto done; 948 } 949 ncookies++; 950 } 951 cnum++; 952 } 953 954 dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen); 955 } 956 957 if(dep->de_flag & DE_DOWN) { 958 dprintf(("[enddive] ")); 959 lsn = DE_DOWNLSN(dep); 960 brelse(bp); 961 level++; 962 goto dive; 963 } 964 965 blockdone: 966 dprintf(("[EOB] ")); 967 olsn = lsn; 968 lsn = dp->d_parent; 969 brelse(bp); 970 level--; 971 972 dprintf(("[level %d] ", level)); 973 974 if (level > 0) 975 goto dive; /* undive really */ 976 977 if (ap->a_eofflag) { 978 dprintf(("[EOF] ")); 979 *ap->a_eofflag = 1; 980 } 981 982 readdone: 983 uio->uio_offset = cnum; 984 dprintf(("[readdone]\n")); 985 if (!error && ap->a_ncookies != NULL) { 986 off_t *cookies; 987 off_t *cookiep; 988 989 dprintf(("%d cookies, ",ncookies)); 990 if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1) 991 panic("hpfs_readdir: unexpected uio from NFS server"); 992 MALLOC(cookies, off_t *, ncookies * sizeof(off_t), 993 M_TEMP, M_WAITOK); 994 for (cookiep = cookies, i=0; i < ncookies; i++) 995 *cookiep++ = ++num; 996 997 *ap->a_ncookies = ncookies; 998 *ap->a_cookies = cookies; 999 } 1000 1001 done: 1002 vn_unlock(ap->a_vp); 1003 return (error); 1004 } 1005 1006 /* 1007 * hpfs_lookup(struct vnode *a_dvp, struct vnode **a_vpp, 1008 * struct componentname *a_cnp) 1009 */ 1010 int 1011 hpfs_lookup(struct vop_old_lookup_args *ap) 1012 { 1013 struct vnode *dvp = ap->a_dvp; 1014 struct hpfsnode *dhp = VTOHP(dvp); 1015 struct hpfsmount *hpmp = dhp->h_hpmp; 1016 struct componentname *cnp = ap->a_cnp; 1017 struct ucred *cred = cnp->cn_cred; 1018 int error; 1019 int nameiop = cnp->cn_nameiop; 1020 int flags = cnp->cn_flags; 1021 int lockparent = flags & CNP_LOCKPARENT; 1022 #if HPFS_DEBUG 1023 int wantparent = flags & (CNP_LOCKPARENT | CNP_WANTPARENT); 1024 #endif 1025 dprintf(("hpfs_lookup(0x%x, %s, %ld, %d, %d): \n", 1026 dhp->h_no, cnp->cn_nameptr, cnp->cn_namelen, 1027 lockparent, wantparent)); 1028 1029 if (nameiop != NAMEI_CREATE && nameiop != NAMEI_DELETE && nameiop != NAMEI_LOOKUP) { 1030 kprintf("hpfs_lookup: LOOKUP, DELETE and CREATE are only supported\n"); 1031 return (EOPNOTSUPP); 1032 } 1033 1034 error = VOP_ACCESS(dvp, VEXEC, cred); 1035 if(error) 1036 return (error); 1037 1038 if( (cnp->cn_namelen == 1) && 1039 !strncmp(cnp->cn_nameptr,".",1) ) { 1040 dprintf(("hpfs_lookup(0x%x,...): . faked\n",dhp->h_no)); 1041 1042 vref(dvp); 1043 *ap->a_vpp = dvp; 1044 1045 return (0); 1046 } else if( (cnp->cn_namelen == 2) && 1047 !strncmp(cnp->cn_nameptr,"..",2) && (flags & CNP_ISDOTDOT) ) { 1048 dprintf(("hpfs_lookup(0x%x,...): .. faked (0x%x)\n", 1049 dhp->h_no, dhp->h_fn.fn_parent)); 1050 1051 VOP__UNLOCK(dvp, 0); 1052 1053 error = VFS_VGET(hpmp->hpm_mp, 1054 dhp->h_fn.fn_parent, ap->a_vpp); 1055 if (error) { 1056 VOP__LOCK(dvp, 0); 1057 return(error); 1058 } 1059 1060 if (lockparent && (error = VOP__LOCK(dvp, 0))) { 1061 vput( *(ap->a_vpp) ); 1062 return (error); 1063 } 1064 return (error); 1065 } else { 1066 struct buf *bp; 1067 struct hpfsdirent *dep; 1068 struct hpfsnode *hp; 1069 1070 error = hpfs_genlookupbyname(dhp, 1071 cnp->cn_nameptr, cnp->cn_namelen, &bp, &dep); 1072 if (error) { 1073 if (error == ENOENT && 1074 (nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME)) { 1075 if(!lockparent) 1076 VOP__UNLOCK(dvp, 0); 1077 return (EJUSTRETURN); 1078 } 1079 1080 return (error); 1081 } 1082 1083 dprintf(("hpfs_lookup: fnode: 0x%x, CPID: 0x%x\n", 1084 dep->de_fnode, dep->de_cpid)); 1085 1086 if (nameiop == NAMEI_DELETE) { 1087 error = VOP_ACCESS(dvp, VWRITE, cred); 1088 if (error) { 1089 brelse(bp); 1090 return (error); 1091 } 1092 } 1093 1094 if (dhp->h_no == dep->de_fnode) { 1095 brelse(bp); 1096 vref(dvp); 1097 *ap->a_vpp = dvp; 1098 return (0); 1099 } 1100 1101 error = VFS_VGET(hpmp->hpm_mp, dep->de_fnode, ap->a_vpp); 1102 if (error) { 1103 kprintf("hpfs_lookup: VFS_VGET FAILED %d\n", error); 1104 brelse(bp); 1105 return(error); 1106 } 1107 1108 hp = VTOHP(*ap->a_vpp); 1109 1110 hp->h_mtime = dep->de_mtime; 1111 hp->h_ctime = dep->de_ctime; 1112 hp->h_atime = dep->de_atime; 1113 bcopy(dep->de_name, hp->h_name, dep->de_namelen); 1114 hp->h_name[dep->de_namelen] = '\0'; 1115 hp->h_namelen = dep->de_namelen; 1116 hp->h_flag |= H_PARVALID; 1117 1118 brelse(bp); 1119 1120 if(!lockparent) 1121 VOP__UNLOCK(dvp, 0); 1122 } 1123 return (error); 1124 } 1125 1126 /* 1127 * hpfs_remove(struct vnode *a_dvp, struct vnode *a_vp, 1128 * struct componentname *a_cnp) 1129 */ 1130 int 1131 hpfs_remove(struct vop_old_remove_args *ap) 1132 { 1133 int error; 1134 1135 dprintf(("hpfs_remove(0x%x, %s, %ld): \n", VTOHP(ap->a_vp)->h_no, 1136 ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen)); 1137 1138 if (ap->a_vp->v_type == VDIR) 1139 return (EPERM); 1140 1141 error = hpfs_removefnode (ap->a_dvp, ap->a_vp, ap->a_cnp); 1142 return (error); 1143 } 1144 1145 /* 1146 * hpfs_create(struct vnode *a_dvp, struct vnode **a_vpp, 1147 * struct componentname *a_cnp, struct vattr *a_vap) 1148 */ 1149 int 1150 hpfs_create(struct vop_old_create_args *ap) 1151 { 1152 int error; 1153 1154 dprintf(("hpfs_create(0x%x, %s, %ld): \n", VTOHP(ap->a_dvp)->h_no, 1155 ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen)); 1156 1157 error = hpfs_makefnode (ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap); 1158 1159 return (error); 1160 } 1161 1162 /* 1163 * Return POSIX pathconf information applicable to NTFS filesystem 1164 * 1165 * hpfs_pathconf(struct vnode *a_vp, int a_name, t *a_retval) 1166 */ 1167 int 1168 hpfs_pathconf(struct vop_pathconf_args *ap) 1169 { 1170 switch (ap->a_name) { 1171 case _PC_LINK_MAX: 1172 *ap->a_retval = 1; 1173 return (0); 1174 case _PC_NAME_MAX: 1175 *ap->a_retval = HPFS_MAXFILENAME; 1176 return (0); 1177 case _PC_PATH_MAX: 1178 *ap->a_retval = PATH_MAX; 1179 return (0); 1180 case _PC_CHOWN_RESTRICTED: 1181 *ap->a_retval = 1; 1182 return (0); 1183 case _PC_NO_TRUNC: 1184 *ap->a_retval = 0; 1185 return (0); 1186 #if defined(__NetBSD__) 1187 case _PC_SYNC_IO: 1188 *ap->a_retval = 1; 1189 return (0); 1190 case _PC_FILESIZEBITS: 1191 *ap->a_retval = 32; 1192 return (0); 1193 #endif 1194 default: 1195 return (EINVAL); 1196 } 1197 /* NOTREACHED */ 1198 } 1199 1200 1201 /* 1202 * Global vfs data structures 1203 */ 1204 1205 struct vop_ops hpfs_vnode_vops = { 1206 .vop_default = vop_defaultop, 1207 .vop_getattr = hpfs_getattr, 1208 .vop_setattr = hpfs_setattr, 1209 .vop_inactive = hpfs_inactive, 1210 .vop_reclaim = hpfs_reclaim, 1211 .vop_print = hpfs_print, 1212 .vop_old_create = hpfs_create, 1213 .vop_old_remove = hpfs_remove, 1214 .vop_old_lookup = hpfs_lookup, 1215 .vop_access = hpfs_access, 1216 .vop_readdir = hpfs_readdir, 1217 .vop_fsync = hpfs_fsync, 1218 .vop_bmap = hpfs_bmap, 1219 .vop_getpages = vop_stdgetpages, 1220 .vop_putpages = vop_stdputpages, 1221 .vop_strategy = hpfs_strategy, 1222 .vop_read = hpfs_read, 1223 .vop_write = hpfs_write, 1224 .vop_ioctl = hpfs_ioctl, 1225 .vop_pathconf = hpfs_pathconf 1226 }; 1227 1228