1 /* $NetBSD: ntfs_vfsops.c,v 1.2 2003/02/01 06:23:41 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 1998, 1999 Semen Ustimenko 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * Id: ntfs_vfsops.c,v 1.7 1999/05/31 11:28:30 phk Exp 29 */ 30 31 #include <sys/cdefs.h> 32 __KERNEL_RCSID(0, "$NetBSD: ntfs_vfsops.c,v 1.2 2003/02/01 06:23:41 thorpej Exp $"); 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/namei.h> 37 #include <sys/proc.h> 38 #include <sys/kernel.h> 39 #include <sys/vnode.h> 40 #include <sys/mount.h> 41 #include <sys/buf.h> 42 #include <sys/fcntl.h> 43 #include <sys/malloc.h> 44 #include <sys/systm.h> 45 #include <sys/device.h> 46 #include <sys/conf.h> 47 48 #if defined(__NetBSD__) 49 #include <uvm/uvm_extern.h> 50 #else 51 #include <vm/vm.h> 52 #endif 53 54 #include <miscfs/specfs/specdev.h> 55 56 /*#define NTFS_DEBUG 1*/ 57 #include <fs/ntfs/ntfs.h> 58 #include <fs/ntfs/ntfs_inode.h> 59 #include <fs/ntfs/ntfs_subr.h> 60 #include <fs/ntfs/ntfs_vfsops.h> 61 #include <fs/ntfs/ntfs_ihash.h> 62 #include <fs/ntfs/ntfsmount.h> 63 64 MALLOC_DEFINE(M_NTFSMNT, "NTFS mount", "NTFS mount structure"); 65 MALLOC_DEFINE(M_NTFSNTNODE,"NTFS ntnode", "NTFS ntnode information"); 66 MALLOC_DEFINE(M_NTFSFNODE,"NTFS fnode", "NTFS fnode information"); 67 MALLOC_DEFINE(M_NTFSDIR,"NTFS dir", "NTFS dir buffer"); 68 69 #if defined(__FreeBSD__) 70 static int ntfs_mount __P((struct mount *, char *, caddr_t, 71 struct nameidata *, struct proc *)); 72 #else 73 static int ntfs_mount __P((struct mount *, const char *, void *, 74 struct nameidata *, struct proc *)); 75 #endif 76 static int ntfs_quotactl __P((struct mount *, int, uid_t, caddr_t, 77 struct proc *)); 78 static int ntfs_root __P((struct mount *, struct vnode **)); 79 static int ntfs_start __P((struct mount *, int, struct proc *)); 80 static int ntfs_statfs __P((struct mount *, struct statfs *, 81 struct proc *)); 82 static int ntfs_sync __P((struct mount *, int, struct ucred *, 83 struct proc *)); 84 static int ntfs_unmount __P((struct mount *, int, struct proc *)); 85 static int ntfs_vget __P((struct mount *mp, ino_t ino, 86 struct vnode **vpp)); 87 static int ntfs_mountfs __P((struct vnode *, struct mount *, 88 struct ntfs_args *, struct proc *)); 89 static int ntfs_vptofh __P((struct vnode *, struct fid *)); 90 91 #if defined(__FreeBSD__) 92 static int ntfs_init __P((struct vfsconf *)); 93 static int ntfs_fhtovp __P((struct mount *, struct fid *, 94 struct sockaddr *, struct vnode **, 95 int *, struct ucred **)); 96 #elif defined(__NetBSD__) 97 static void ntfs_init __P((void)); 98 static void ntfs_reinit __P((void)); 99 static void ntfs_done __P((void)); 100 static int ntfs_fhtovp __P((struct mount *, struct fid *, 101 struct vnode **)); 102 static int ntfs_checkexp __P((struct mount *, struct mbuf *, 103 int *, struct ucred **)); 104 static int ntfs_mountroot __P((void)); 105 static int ntfs_sysctl __P((int *, u_int, void *, size_t *, void *, 106 size_t, struct proc *)); 107 #else 108 static int ntfs_init __P((void)); 109 static int ntfs_fhtovp __P((struct mount *, struct fid *, 110 struct mbuf *, struct vnode **, 111 int *, struct ucred **)); 112 #endif 113 114 struct genfs_ops ntfs_genfsops = { 115 NULL, 116 NULL, 117 genfs_compat_gop_write, 118 }; 119 120 #ifdef __NetBSD__ 121 /* 122 * Verify a remote client has export rights and return these rights via. 123 * exflagsp and credanonp. 124 */ 125 static int 126 ntfs_checkexp(mp, nam, exflagsp, credanonp) 127 struct mount *mp; 128 struct mbuf *nam; 129 int *exflagsp; 130 struct ucred **credanonp; 131 { 132 struct netcred *np; 133 struct ntfsmount *ntm = VFSTONTFS(mp); 134 135 /* 136 * Get the export permission structure for this <mp, client> tuple. 137 */ 138 np = vfs_export_lookup(mp, &ntm->ntm_export, nam); 139 if (np == NULL) 140 return (EACCES); 141 142 *exflagsp = np->netc_exflags; 143 *credanonp = &np->netc_anon; 144 return (0); 145 } 146 147 /*ARGSUSED*/ 148 static int 149 ntfs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 150 int *name; 151 u_int namelen; 152 void *oldp; 153 size_t *oldlenp; 154 void *newp; 155 size_t newlen; 156 struct proc *p; 157 { 158 return (EINVAL); 159 } 160 161 static int 162 ntfs_mountroot() 163 { 164 struct mount *mp; 165 struct proc *p = curproc; /* XXX */ 166 int error; 167 struct ntfs_args args; 168 169 if (root_device->dv_class != DV_DISK) 170 return (ENODEV); 171 172 /* 173 * Get vnodes for rootdev. 174 */ 175 if (bdevvp(rootdev, &rootvp)) 176 panic("ntfs_mountroot: can't setup rootvp"); 177 178 if ((error = vfs_rootmountalloc(MOUNT_NTFS, "root_device", &mp))) { 179 vrele(rootvp); 180 return (error); 181 } 182 183 args.flag = 0; 184 args.uid = 0; 185 args.gid = 0; 186 args.mode = 0777; 187 188 if ((error = ntfs_mountfs(rootvp, mp, &args, p)) != 0) { 189 mp->mnt_op->vfs_refcount--; 190 vfs_unbusy(mp); 191 free(mp, M_MOUNT); 192 vrele(rootvp); 193 return (error); 194 } 195 196 simple_lock(&mountlist_slock); 197 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); 198 simple_unlock(&mountlist_slock); 199 (void)ntfs_statfs(mp, &mp->mnt_stat, p); 200 vfs_unbusy(mp); 201 return (0); 202 } 203 204 static void 205 ntfs_init() 206 { 207 ntfs_nthashinit(); 208 ntfs_toupper_init(); 209 } 210 211 static void 212 ntfs_reinit() 213 { 214 ntfs_nthashreinit(); 215 } 216 217 static void 218 ntfs_done() 219 { 220 ntfs_nthashdone(); 221 } 222 223 #elif defined(__FreeBSD__) 224 225 static int 226 ntfs_init ( 227 struct vfsconf *vcp ) 228 { 229 ntfs_nthashinit(); 230 ntfs_toupper_init(); 231 return 0; 232 } 233 234 #endif /* NetBSD */ 235 236 static int 237 ntfs_mount ( 238 struct mount *mp, 239 #if defined(__FreeBSD__) 240 char *path, 241 caddr_t data, 242 #else 243 const char *path, 244 void *data, 245 #endif 246 struct nameidata *ndp, 247 struct proc *p ) 248 { 249 size_t size; 250 int err = 0; 251 struct vnode *devvp; 252 struct ntfs_args args; 253 254 #ifdef __FreeBSD__ 255 /* 256 * Use NULL path to flag a root mount 257 */ 258 if( path == NULL) { 259 /* 260 *** 261 * Mounting root file system 262 *** 263 */ 264 265 /* Get vnode for root device*/ 266 if( bdevvp( rootdev, &rootvp)) 267 panic("ffs_mountroot: can't setup bdevvp for root"); 268 269 /* 270 * FS specific handling 271 */ 272 mp->mnt_flag |= MNT_RDONLY; /* XXX globally applicable?*/ 273 274 /* 275 * Attempt mount 276 */ 277 if( ( err = ntfs_mountfs(rootvp, mp, &args, p)) != 0) { 278 /* fs specific cleanup (if any)*/ 279 goto error_1; 280 } 281 282 goto dostatfs; /* success*/ 283 284 } 285 #endif /* FreeBSD */ 286 287 if (mp->mnt_flag & MNT_GETARGS) { 288 struct ntfsmount *ntmp = VFSTONTFS(mp); 289 if (ntmp == NULL) 290 return EIO; 291 args.fspec = NULL; 292 args.uid = ntmp->ntm_uid; 293 args.gid = ntmp->ntm_gid; 294 args.mode = ntmp->ntm_mode; 295 args.flag = ntmp->ntm_flag; 296 vfs_showexport(mp, &args.export, &ntmp->ntm_export); 297 return copyout(&args, data, sizeof(args)); 298 } 299 /* 300 *** 301 * Mounting non-root file system or updating a file system 302 *** 303 */ 304 305 /* copy in user arguments*/ 306 err = copyin(data, (caddr_t)&args, sizeof (struct ntfs_args)); 307 if (err) 308 goto error_1; /* can't get arguments*/ 309 310 /* 311 * If updating, check whether changing from read-only to 312 * read/write; if there is no device name, that's all we do. 313 */ 314 if (mp->mnt_flag & MNT_UPDATE) { 315 /* if not updating name...*/ 316 if (args.fspec == 0) { 317 /* 318 * Process export requests. Jumping to "success" 319 * will return the vfs_export() error code. 320 */ 321 struct ntfsmount *ntm = VFSTONTFS(mp); 322 err = vfs_export(mp, &ntm->ntm_export, &args.export); 323 goto success; 324 } 325 326 printf("ntfs_mount(): MNT_UPDATE not supported\n"); 327 err = EINVAL; 328 goto error_1; 329 } 330 331 /* 332 * Not an update, or updating the name: look up the name 333 * and verify that it refers to a sensible block device. 334 */ 335 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); 336 err = namei(ndp); 337 if (err) { 338 /* can't get devvp!*/ 339 goto error_1; 340 } 341 342 devvp = ndp->ni_vp; 343 344 if (devvp->v_type != VBLK) { 345 err = ENOTBLK; 346 goto error_2; 347 } 348 #ifdef __FreeBSD__ 349 if (bdevsw(devvp->v_rdev) == NULL) { 350 #else 351 if (bdevsw_lookup(devvp->v_rdev) == NULL) { 352 #endif 353 err = ENXIO; 354 goto error_2; 355 } 356 if (mp->mnt_flag & MNT_UPDATE) { 357 #if 0 358 /* 359 ******************** 360 * UPDATE 361 ******************** 362 */ 363 364 if (devvp != ntmp->um_devvp) 365 err = EINVAL; /* needs translation */ 366 else 367 vrele(devvp); 368 /* 369 * Update device name only on success 370 */ 371 if( !err) { 372 /* Save "mounted from" info for mount point (NULL pad)*/ 373 copyinstr( args.fspec, 374 mp->mnt_stat.f_mntfromname, 375 MNAMELEN - 1, 376 &size); 377 bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 378 } 379 #endif 380 } else { 381 /* 382 ******************** 383 * NEW MOUNT 384 ******************** 385 */ 386 387 /* 388 * Since this is a new mount, we want the names for 389 * the device and the mount point copied in. If an 390 * error occurs, the mountpoint is discarded by the 391 * upper level code. 392 */ 393 /* Save "last mounted on" info for mount point (NULL pad)*/ 394 copyinstr( path, /* mount point*/ 395 mp->mnt_stat.f_mntonname, /* save area*/ 396 MNAMELEN - 1, /* max size*/ 397 &size); /* real size*/ 398 bzero( mp->mnt_stat.f_mntonname + size, MNAMELEN - size); 399 400 /* Save "mounted from" info for mount point (NULL pad)*/ 401 copyinstr( args.fspec, /* device name*/ 402 mp->mnt_stat.f_mntfromname, /* save area*/ 403 MNAMELEN - 1, /* max size*/ 404 &size); /* real size*/ 405 bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 406 407 err = ntfs_mountfs(devvp, mp, &args, p); 408 } 409 if (err) { 410 goto error_2; 411 } 412 413 #ifdef __FreeBSD__ 414 dostatfs: 415 #endif 416 /* 417 * Initialize FS stat information in mount struct; uses both 418 * mp->mnt_stat.f_mntonname and mp->mnt_stat.f_mntfromname 419 * 420 * This code is common to root and non-root mounts 421 */ 422 (void)VFS_STATFS(mp, &mp->mnt_stat, p); 423 424 goto success; 425 426 427 error_2: /* error with devvp held*/ 428 429 /* release devvp before failing*/ 430 vrele(devvp); 431 432 error_1: /* no state to back out*/ 433 434 success: 435 return(err); 436 } 437 438 /* 439 * Common code for mount and mountroot 440 */ 441 int 442 ntfs_mountfs(devvp, mp, argsp, p) 443 struct vnode *devvp; 444 struct mount *mp; 445 struct ntfs_args *argsp; 446 struct proc *p; 447 { 448 struct buf *bp; 449 struct ntfsmount *ntmp; 450 dev_t dev = devvp->v_rdev; 451 int error, ronly, ncount, i; 452 struct vnode *vp; 453 454 /* 455 * Disallow multiple mounts of the same device. 456 * Disallow mounting of a device that is currently in use 457 * (except for root, which might share swap device for miniroot). 458 * Flush out any old buffers remaining from a previous use. 459 */ 460 error = vfs_mountedon(devvp); 461 if (error) 462 return (error); 463 ncount = vcount(devvp); 464 #if defined(__FreeBSD__) 465 if (devvp->v_object) 466 ncount -= 1; 467 #endif 468 if (ncount > 1 && devvp != rootvp) 469 return (EBUSY); 470 #if defined(__FreeBSD__) 471 VN_LOCK(devvp, LK_EXCLUSIVE | LK_RETRY, p); 472 error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0); 473 VOP__UNLOCK(devvp, 0, p); 474 #else 475 error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0); 476 #endif 477 if (error) 478 return (error); 479 480 ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 481 error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p); 482 if (error) 483 return (error); 484 485 bp = NULL; 486 487 error = bread(devvp, BBLOCK, BBSIZE, NOCRED, &bp); 488 if (error) 489 goto out; 490 ntmp = malloc( sizeof *ntmp, M_NTFSMNT, M_WAITOK ); 491 bzero( ntmp, sizeof *ntmp ); 492 bcopy( bp->b_data, &ntmp->ntm_bootfile, sizeof(struct bootfile) ); 493 brelse( bp ); 494 bp = NULL; 495 496 if (strncmp(ntmp->ntm_bootfile.bf_sysid, NTFS_BBID, NTFS_BBIDLEN)) { 497 error = EINVAL; 498 dprintf(("ntfs_mountfs: invalid boot block\n")); 499 goto out; 500 } 501 502 { 503 int8_t cpr = ntmp->ntm_mftrecsz; 504 if( cpr > 0 ) 505 ntmp->ntm_bpmftrec = ntmp->ntm_spc * cpr; 506 else 507 ntmp->ntm_bpmftrec = (1 << (-cpr)) / ntmp->ntm_bps; 508 } 509 dprintf(("ntfs_mountfs(): bps: %d, spc: %d, media: %x, mftrecsz: %d (%d sects)\n", 510 ntmp->ntm_bps,ntmp->ntm_spc,ntmp->ntm_bootfile.bf_media, 511 ntmp->ntm_mftrecsz,ntmp->ntm_bpmftrec)); 512 dprintf(("ntfs_mountfs(): mftcn: 0x%x|0x%x\n", 513 (u_int32_t)ntmp->ntm_mftcn,(u_int32_t)ntmp->ntm_mftmirrcn)); 514 515 ntmp->ntm_mountp = mp; 516 ntmp->ntm_dev = dev; 517 ntmp->ntm_devvp = devvp; 518 ntmp->ntm_uid = argsp->uid; 519 ntmp->ntm_gid = argsp->gid; 520 ntmp->ntm_mode = argsp->mode; 521 ntmp->ntm_flag = argsp->flag; 522 mp->mnt_data = ntmp; 523 524 /* set file name encode/decode hooks XXX utf-8 only for now */ 525 ntmp->ntm_wget = ntfs_utf8_wget; 526 ntmp->ntm_wput = ntfs_utf8_wput; 527 ntmp->ntm_wcmp = ntfs_utf8_wcmp; 528 529 dprintf(("ntfs_mountfs(): case-%s,%s uid: %d, gid: %d, mode: %o\n", 530 (ntmp->ntm_flag & NTFS_MFLAG_CASEINS)?"insens.":"sens.", 531 (ntmp->ntm_flag & NTFS_MFLAG_ALLNAMES)?" allnames,":"", 532 ntmp->ntm_uid, ntmp->ntm_gid, ntmp->ntm_mode)); 533 534 /* 535 * We read in some system nodes to do not allow 536 * reclaim them and to have everytime access to them. 537 */ 538 { 539 int pi[3] = { NTFS_MFTINO, NTFS_ROOTINO, NTFS_BITMAPINO }; 540 for (i=0; i<3; i++) { 541 error = VFS_VGET(mp, pi[i], &(ntmp->ntm_sysvn[pi[i]])); 542 if(error) 543 goto out1; 544 ntmp->ntm_sysvn[pi[i]]->v_flag |= VSYSTEM; 545 VREF(ntmp->ntm_sysvn[pi[i]]); 546 vput(ntmp->ntm_sysvn[pi[i]]); 547 } 548 } 549 550 /* read the Unicode lowercase --> uppercase translation table, 551 * if necessary */ 552 if ((error = ntfs_toupper_use(mp, ntmp))) 553 goto out1; 554 555 /* 556 * Scan $BitMap and count free clusters 557 */ 558 error = ntfs_calccfree(ntmp, &ntmp->ntm_cfree); 559 if(error) 560 goto out1; 561 562 /* 563 * Read and translate to internal format attribute 564 * definition file. 565 */ 566 { 567 int num,j; 568 struct attrdef ad; 569 570 /* Open $AttrDef */ 571 error = VFS_VGET(mp, NTFS_ATTRDEFINO, &vp ); 572 if(error) 573 goto out1; 574 575 /* Count valid entries */ 576 for(num=0;;num++) { 577 error = ntfs_readattr(ntmp, VTONT(vp), 578 NTFS_A_DATA, NULL, 579 num * sizeof(ad), sizeof(ad), 580 &ad, NULL); 581 if (error) 582 goto out1; 583 if (ad.ad_name[0] == 0) 584 break; 585 } 586 587 /* Alloc memory for attribute definitions */ 588 ntmp->ntm_ad = (struct ntvattrdef *) malloc( 589 num * sizeof(struct ntvattrdef), 590 M_NTFSMNT, M_WAITOK); 591 592 ntmp->ntm_adnum = num; 593 594 /* Read them and translate */ 595 for(i=0;i<num;i++){ 596 error = ntfs_readattr(ntmp, VTONT(vp), 597 NTFS_A_DATA, NULL, 598 i * sizeof(ad), sizeof(ad), 599 &ad, NULL); 600 if (error) 601 goto out1; 602 j = 0; 603 do { 604 ntmp->ntm_ad[i].ad_name[j] = ad.ad_name[j]; 605 } while(ad.ad_name[j++]); 606 ntmp->ntm_ad[i].ad_namelen = j - 1; 607 ntmp->ntm_ad[i].ad_type = ad.ad_type; 608 } 609 610 vput(vp); 611 } 612 613 #if defined(__FreeBSD__) 614 mp->mnt_stat.f_fsid.val[0] = dev2udev(dev); 615 mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 616 #else 617 mp->mnt_stat.f_fsid.val[0] = dev; 618 mp->mnt_stat.f_fsid.val[1] = makefstype(MOUNT_NTFS); 619 #endif 620 mp->mnt_maxsymlinklen = 0; 621 mp->mnt_flag |= MNT_LOCAL; 622 devvp->v_specmountpoint = mp; 623 return (0); 624 625 out1: 626 for(i=0;i<NTFS_SYSNODESNUM;i++) 627 if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]); 628 629 if (vflush(mp,NULLVP,0)) 630 dprintf(("ntfs_mountfs: vflush failed\n")); 631 632 out: 633 devvp->v_specmountpoint = NULL; 634 if (bp) 635 brelse(bp); 636 637 #if defined __NetBSD__ 638 /* lock the device vnode before calling VOP_CLOSE() */ 639 VN_LOCK(devvp, LK_EXCLUSIVE | LK_RETRY, p); 640 (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p); 641 VOP__UNLOCK(devvp, 0, p); 642 #else 643 (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p); 644 #endif 645 646 return (error); 647 } 648 649 static int 650 ntfs_start ( 651 struct mount *mp, 652 int flags, 653 struct proc *p ) 654 { 655 return (0); 656 } 657 658 static int 659 ntfs_unmount( 660 struct mount *mp, 661 int mntflags, 662 struct proc *p) 663 { 664 struct ntfsmount *ntmp; 665 int error, ronly = 0, flags, i; 666 667 dprintf(("ntfs_unmount: unmounting...\n")); 668 ntmp = VFSTONTFS(mp); 669 670 flags = 0; 671 if(mntflags & MNT_FORCE) 672 flags |= FORCECLOSE; 673 674 dprintf(("ntfs_unmount: vflushing...\n")); 675 error = vflush(mp,NULLVP,flags | SKIPSYSTEM); 676 if (error) { 677 dprintf(("ntfs_unmount: vflush failed: %d\n",error)); 678 return (error); 679 } 680 681 /* Check if only system vnodes are rest */ 682 for(i=0;i<NTFS_SYSNODESNUM;i++) 683 if((ntmp->ntm_sysvn[i]) && 684 (ntmp->ntm_sysvn[i]->v_usecount > 1)) return (EBUSY); 685 686 /* Dereference all system vnodes */ 687 for(i=0;i<NTFS_SYSNODESNUM;i++) 688 if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]); 689 690 /* vflush system vnodes */ 691 error = vflush(mp,NULLVP,flags); 692 if (error) { 693 /* XXX should this be panic() ? */ 694 printf("ntfs_unmount: vflush failed(sysnodes): %d\n",error); 695 } 696 697 /* Check if the type of device node isn't VBAD before 698 * touching v_specinfo. If the device vnode is revoked, the 699 * field is NULL and touching it causes null pointer derefercence. 700 */ 701 if (ntmp->ntm_devvp->v_type != VBAD) 702 ntmp->ntm_devvp->v_specmountpoint = NULL; 703 704 vinvalbuf(ntmp->ntm_devvp, V_SAVE, NOCRED, p, 0, 0); 705 706 #if defined(__NetBSD__) 707 /* lock the device vnode before calling VOP_CLOSE() */ 708 VOP_LOCK(ntmp->ntm_devvp, LK_EXCLUSIVE | LK_RETRY); 709 error = VOP_CLOSE(ntmp->ntm_devvp, ronly ? FREAD : FREAD|FWRITE, 710 NOCRED, p); 711 VOP__UNLOCK(ntmp->ntm_devvp, 0, p); 712 #else 713 error = VOP_CLOSE(ntmp->ntm_devvp, ronly ? FREAD : FREAD|FWRITE, 714 NOCRED, p); 715 #endif 716 717 vrele(ntmp->ntm_devvp); 718 719 /* free the toupper table, if this has been last mounted ntfs volume */ 720 ntfs_toupper_unuse(); 721 722 dprintf(("ntfs_umount: freeing memory...\n")); 723 mp->mnt_data = NULL; 724 mp->mnt_flag &= ~MNT_LOCAL; 725 free(ntmp->ntm_ad, M_NTFSMNT); 726 FREE(ntmp, M_NTFSMNT); 727 return (error); 728 } 729 730 static int 731 ntfs_root( 732 struct mount *mp, 733 struct vnode **vpp ) 734 { 735 struct vnode *nvp; 736 int error = 0; 737 738 dprintf(("ntfs_root(): sysvn: %p\n", 739 VFSTONTFS(mp)->ntm_sysvn[NTFS_ROOTINO])); 740 error = VFS_VGET(mp, (ino_t)NTFS_ROOTINO, &nvp); 741 if(error) { 742 printf("ntfs_root: VFS_VGET failed: %d\n",error); 743 return (error); 744 } 745 746 *vpp = nvp; 747 return (0); 748 } 749 750 static int 751 ntfs_quotactl ( 752 struct mount *mp, 753 int cmds, 754 uid_t uid, 755 caddr_t arg, 756 struct proc *p) 757 { 758 printf("\nntfs_quotactl():\n"); 759 return EOPNOTSUPP; 760 } 761 762 int 763 ntfs_calccfree( 764 struct ntfsmount *ntmp, 765 cn_t *cfreep) 766 { 767 struct vnode *vp; 768 u_int8_t *tmp; 769 int j, error; 770 long cfree = 0; 771 size_t bmsize, i; 772 773 vp = ntmp->ntm_sysvn[NTFS_BITMAPINO]; 774 775 bmsize = VTOF(vp)->f_size; 776 777 tmp = (u_int8_t *) malloc(bmsize, M_TEMP, M_WAITOK); 778 779 error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL, 780 0, bmsize, tmp, NULL); 781 if (error) 782 goto out; 783 784 for(i=0;i<bmsize;i++) 785 for(j=0;j<8;j++) 786 if(~tmp[i] & (1 << j)) cfree++; 787 *cfreep = cfree; 788 789 out: 790 free(tmp, M_TEMP); 791 return(error); 792 } 793 794 static int 795 ntfs_statfs( 796 struct mount *mp, 797 struct statfs *sbp, 798 struct proc *p) 799 { 800 struct ntfsmount *ntmp = VFSTONTFS(mp); 801 u_int64_t mftallocated; 802 803 dprintf(("ntfs_statfs():\n")); 804 805 mftallocated = VTOF(ntmp->ntm_sysvn[NTFS_MFTINO])->f_allocated; 806 807 #if defined(__FreeBSD__) 808 sbp->f_type = mp->mnt_vfc->vfc_typenum; 809 #elif defined(__NetBSD__) 810 sbp->f_type = 0; 811 #else 812 sbp->f_type = MOUNT_NTFS; 813 #endif 814 sbp->f_bsize = ntmp->ntm_bps; 815 sbp->f_iosize = ntmp->ntm_bps * ntmp->ntm_spc; 816 sbp->f_blocks = ntmp->ntm_bootfile.bf_spv; 817 sbp->f_bfree = sbp->f_bavail = ntfs_cntobn(ntmp->ntm_cfree); 818 sbp->f_ffree = sbp->f_bfree / ntmp->ntm_bpmftrec; 819 sbp->f_files = mftallocated / ntfs_bntob(ntmp->ntm_bpmftrec) + 820 sbp->f_ffree; 821 if (sbp != &mp->mnt_stat) { 822 bcopy((caddr_t)mp->mnt_stat.f_mntonname, 823 (caddr_t)&sbp->f_mntonname[0], MNAMELEN); 824 bcopy((caddr_t)mp->mnt_stat.f_mntfromname, 825 (caddr_t)&sbp->f_mntfromname[0], MNAMELEN); 826 } 827 sbp->f_flags = mp->mnt_flag; 828 #ifdef __NetBSD__ 829 strncpy(sbp->f_fstypename, mp->mnt_op->vfs_name, MFSNAMELEN); 830 #endif 831 832 return (0); 833 } 834 835 static int 836 ntfs_sync ( 837 struct mount *mp, 838 int waitfor, 839 struct ucred *cred, 840 struct proc *p) 841 { 842 /*dprintf(("ntfs_sync():\n"));*/ 843 return (0); 844 } 845 846 /*ARGSUSED*/ 847 static int 848 ntfs_fhtovp( 849 #if defined(__FreeBSD__) 850 struct mount *mp, 851 struct fid *fhp, 852 struct sockaddr *nam, 853 struct vnode **vpp, 854 int *exflagsp, 855 struct ucred **credanonp) 856 #elif defined(__NetBSD__) 857 struct mount *mp, 858 struct fid *fhp, 859 struct vnode **vpp) 860 #else 861 struct mount *mp, 862 struct fid *fhp, 863 struct mbuf *nam, 864 struct vnode **vpp, 865 int *exflagsp, 866 struct ucred **credanonp) 867 #endif 868 { 869 struct ntfid *ntfhp = (struct ntfid *)fhp; 870 int error; 871 872 ddprintf(("ntfs_fhtovp(): %s: %d\n", mp->mnt_stat.f_mntonname, 873 ntfhp->ntfid_ino)); 874 875 error = ntfs_vgetex(mp, ntfhp->ntfid_ino, ntfhp->ntfid_attr, NULL, 876 LK_EXCLUSIVE | LK_RETRY, 0, curproc, vpp); /* XXX */ 877 if (error != 0) { 878 *vpp = NULLVP; 879 return (error); 880 } 881 882 /* XXX as unlink/rmdir/mkdir/creat are not currently possible 883 * with NTFS, we don't need to check anything else for now */ 884 return (0); 885 } 886 887 static int 888 ntfs_vptofh( 889 struct vnode *vp, 890 struct fid *fhp) 891 { 892 struct ntnode *ntp; 893 struct ntfid *ntfhp; 894 struct fnode *fn; 895 896 ddprintf(("ntfs_fhtovp(): %s: %p\n", vp->v_mount->mnt_stat.f_mntonname, 897 vp)); 898 899 fn = VTOF(vp); 900 ntp = VTONT(vp); 901 ntfhp = (struct ntfid *)fhp; 902 ntfhp->ntfid_len = sizeof(struct ntfid); 903 ntfhp->ntfid_ino = ntp->i_number; 904 ntfhp->ntfid_attr = fn->f_attrtype; 905 #ifdef notyet 906 ntfhp->ntfid_gen = ntp->i_gen; 907 #endif 908 return (0); 909 } 910 911 int 912 ntfs_vgetex( 913 struct mount *mp, 914 ino_t ino, 915 u_int32_t attrtype, 916 char *attrname, 917 u_long lkflags, 918 u_long flags, 919 struct proc *p, 920 struct vnode **vpp) 921 { 922 int error; 923 struct ntfsmount *ntmp; 924 struct ntnode *ip; 925 struct fnode *fp; 926 struct vnode *vp; 927 enum vtype f_type; 928 929 dprintf(("ntfs_vgetex: ino: %d, attr: 0x%x:%s, lkf: 0x%lx, f: 0x%lx\n", 930 ino, attrtype, attrname?attrname:"", (u_long)lkflags, 931 (u_long)flags )); 932 933 ntmp = VFSTONTFS(mp); 934 *vpp = NULL; 935 936 /* Get ntnode */ 937 error = ntfs_ntlookup(ntmp, ino, &ip); 938 if (error) { 939 printf("ntfs_vget: ntfs_ntget failed\n"); 940 return (error); 941 } 942 943 /* It may be not initialized fully, so force load it */ 944 if (!(flags & VG_DONTLOADIN) && !(ip->i_flag & IN_LOADED)) { 945 error = ntfs_loadntnode(ntmp, ip); 946 if(error) { 947 printf("ntfs_vget: CAN'T LOAD ATTRIBUTES FOR INO: %d\n", 948 ip->i_number); 949 ntfs_ntput(ip); 950 return (error); 951 } 952 } 953 954 error = ntfs_fget(ntmp, ip, attrtype, attrname, &fp); 955 if (error) { 956 printf("ntfs_vget: ntfs_fget failed\n"); 957 ntfs_ntput(ip); 958 return (error); 959 } 960 961 if (!(flags & VG_DONTVALIDFN) && !(fp->f_flag & FN_VALID)) { 962 if ((ip->i_frflag & NTFS_FRFLAG_DIR) && 963 (fp->f_attrtype == NTFS_A_DATA && fp->f_attrname == NULL)) { 964 f_type = VDIR; 965 } else if (flags & VG_EXT) { 966 f_type = VNON; 967 fp->f_size = fp->f_allocated = 0; 968 } else { 969 f_type = VREG; 970 971 error = ntfs_filesize(ntmp, fp, 972 &fp->f_size, &fp->f_allocated); 973 if (error) { 974 ntfs_ntput(ip); 975 return (error); 976 } 977 } 978 979 fp->f_flag |= FN_VALID; 980 } 981 982 /* 983 * We may be calling vget() now. To avoid potential deadlock, we need 984 * to release ntnode lock, since due to locking order vnode 985 * lock has to be acquired first. 986 * ntfs_fget() bumped ntnode usecount, so ntnode won't be recycled 987 * prematurely. 988 */ 989 ntfs_ntput(ip); 990 991 if (FTOV(fp)) { 992 /* vget() returns error if the vnode has been recycled */ 993 if (VGET(FTOV(fp), lkflags, p) == 0) { 994 *vpp = FTOV(fp); 995 return (0); 996 } 997 } 998 999 error = getnewvnode(VT_NTFS, ntmp->ntm_mountp, ntfs_vnodeop_p, &vp); 1000 if(error) { 1001 ntfs_frele(fp); 1002 ntfs_ntput(ip); 1003 return (error); 1004 } 1005 dprintf(("ntfs_vget: vnode: %p for ntnode: %d\n", vp,ino)); 1006 1007 #ifdef __FreeBSD__ 1008 lockinit(&fp->f_lock, PINOD, "fnode", 0, 0); 1009 #endif 1010 fp->f_vp = vp; 1011 vp->v_data = fp; 1012 vp->v_type = f_type; 1013 1014 if (ino == NTFS_ROOTINO) 1015 vp->v_flag |= VROOT; 1016 1017 if (lkflags & LK_TYPE_MASK) { 1018 error = VN_LOCK(vp, lkflags, p); 1019 if (error) { 1020 vput(vp); 1021 return (error); 1022 } 1023 } 1024 1025 genfs_node_init(vp, &ntfs_genfsops); 1026 VREF(ip->i_devvp); 1027 *vpp = vp; 1028 return (0); 1029 } 1030 1031 static int 1032 ntfs_vget( 1033 struct mount *mp, 1034 ino_t ino, 1035 struct vnode **vpp) 1036 { 1037 return ntfs_vgetex(mp, ino, NTFS_A_DATA, NULL, 1038 LK_EXCLUSIVE | LK_RETRY, 0, curproc, vpp); /* XXX */ 1039 } 1040 1041 #if defined(__FreeBSD__) 1042 static struct vfsops ntfs_vfsops = { 1043 ntfs_mount, 1044 ntfs_start, 1045 ntfs_unmount, 1046 ntfs_root, 1047 ntfs_quotactl, 1048 ntfs_statfs, 1049 ntfs_sync, 1050 ntfs_vget, 1051 ntfs_fhtovp, 1052 ntfs_vptofh, 1053 ntfs_init, 1054 NULL 1055 }; 1056 VFS_SET(ntfs_vfsops, ntfs, 0); 1057 #elif defined(__NetBSD__) 1058 extern const struct vnodeopv_desc ntfs_vnodeop_opv_desc; 1059 1060 const struct vnodeopv_desc * const ntfs_vnodeopv_descs[] = { 1061 &ntfs_vnodeop_opv_desc, 1062 NULL, 1063 }; 1064 1065 struct vfsops ntfs_vfsops = { 1066 MOUNT_NTFS, 1067 ntfs_mount, 1068 ntfs_start, 1069 ntfs_unmount, 1070 ntfs_root, 1071 ntfs_quotactl, 1072 ntfs_statfs, 1073 ntfs_sync, 1074 ntfs_vget, 1075 ntfs_fhtovp, 1076 ntfs_vptofh, 1077 ntfs_init, 1078 ntfs_reinit, 1079 ntfs_done, 1080 ntfs_sysctl, 1081 ntfs_mountroot, 1082 ntfs_checkexp, 1083 ntfs_vnodeopv_descs, 1084 }; 1085 #endif 1086