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