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