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