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