1 /* $OpenBSD: ntfs_vfsops.c,v 1.28 2011/12/20 09:13:07 mikeb 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 system vnodes are still referenced */ 551 for(i=0;i<NTFS_SYSNODESNUM;i++) { 552 if(((mntflags & MNT_FORCE) == 0) && (ntmp->ntm_sysvn[i] && 553 ntmp->ntm_sysvn[i]->v_usecount > 1)) 554 return (EBUSY); 555 } 556 557 /* Dereference all system vnodes */ 558 for(i=0;i<NTFS_SYSNODESNUM;i++) 559 if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]); 560 561 /* vflush system vnodes */ 562 error = vflush(mp,NULLVP,flags); 563 if (error) { 564 /* XXX should this be panic() ? */ 565 printf("ntfs_unmount: vflush failed(sysnodes): %d\n",error); 566 } 567 568 /* Check if the type of device node isn't VBAD before 569 * touching v_specinfo. If the device vnode is revoked, the 570 * field is NULL and touching it causes null pointer derefercence. 571 */ 572 if (ntmp->ntm_devvp->v_type != VBAD) 573 ntmp->ntm_devvp->v_specmountpoint = NULL; 574 575 /* lock the device vnode before calling VOP_CLOSE() */ 576 VOP_LOCK(ntmp->ntm_devvp, LK_EXCLUSIVE | LK_RETRY, p); 577 vinvalbuf(ntmp->ntm_devvp, V_SAVE, NOCRED, p, 0, 0); 578 579 error = VOP_CLOSE(ntmp->ntm_devvp, ronly ? FREAD : FREAD|FWRITE, 580 NOCRED, p); 581 582 vput(ntmp->ntm_devvp); 583 584 /* free the toupper table, if this has been last mounted ntfs volume */ 585 ntfs_toupper_unuse(p); 586 587 dprintf(("ntfs_unmount: freeing memory...\n")); 588 mp->mnt_data = NULL; 589 mp->mnt_flag &= ~MNT_LOCAL; 590 free(ntmp->ntm_ad, M_NTFSMNT); 591 free(ntmp, M_NTFSMNT); 592 return (error); 593 } 594 595 static int 596 ntfs_root( 597 struct mount *mp, 598 struct vnode **vpp ) 599 { 600 struct vnode *nvp; 601 int error = 0; 602 603 dprintf(("ntfs_root(): sysvn: %p\n", 604 VFSTONTFS(mp)->ntm_sysvn[NTFS_ROOTINO])); 605 error = VFS_VGET(mp, (ino_t)NTFS_ROOTINO, &nvp); 606 if(error) { 607 printf("ntfs_root: VFS_VGET failed: %d\n",error); 608 return (error); 609 } 610 611 *vpp = nvp; 612 return (0); 613 } 614 615 /* 616 * Do operations associated with quotas, not supported 617 */ 618 /* ARGSUSED */ 619 static int 620 ntfs_quotactl ( 621 struct mount *mp, 622 int cmds, 623 uid_t uid, 624 caddr_t arg, 625 struct proc *p) 626 { 627 628 return EOPNOTSUPP; 629 } 630 631 int 632 ntfs_calccfree( 633 struct ntfsmount *ntmp, 634 cn_t *cfreep) 635 { 636 struct vnode *vp; 637 u_int8_t *tmp; 638 int j, error; 639 cn_t cfree = 0; 640 size_t bmsize, i; 641 642 vp = ntmp->ntm_sysvn[NTFS_BITMAPINO]; 643 644 bmsize = VTOF(vp)->f_size; 645 646 tmp = malloc(bmsize, M_TEMP, M_WAITOK); 647 648 error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL, 649 0, bmsize, tmp, NULL); 650 if (error) 651 goto out; 652 653 for(i=0;i<bmsize;i++) 654 for(j=0;j<8;j++) 655 if(~tmp[i] & (1 << j)) cfree++; 656 *cfreep = cfree; 657 658 out: 659 free(tmp, M_TEMP); 660 return(error); 661 } 662 663 static int 664 ntfs_statfs( 665 struct mount *mp, 666 struct statfs *sbp, 667 struct proc *p) 668 { 669 struct ntfsmount *ntmp = VFSTONTFS(mp); 670 u_int64_t mftallocated; 671 672 dprintf(("ntfs_statfs():\n")); 673 674 mftallocated = VTOF(ntmp->ntm_sysvn[NTFS_MFTINO])->f_allocated; 675 676 sbp->f_bsize = ntmp->ntm_bps; 677 sbp->f_iosize = ntmp->ntm_bps * ntmp->ntm_spc; 678 sbp->f_blocks = ntmp->ntm_bootfile.bf_spv; 679 sbp->f_bfree = sbp->f_bavail = ntfs_cntobn(ntmp->ntm_cfree); 680 sbp->f_ffree = sbp->f_bfree / ntmp->ntm_bpmftrec; 681 sbp->f_files = mftallocated / ntfs_bntob(ntmp->ntm_bpmftrec) + 682 sbp->f_ffree; 683 sbp->f_flags = mp->mnt_flag; 684 if (sbp != &mp->mnt_stat) { 685 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 686 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 687 bcopy(&mp->mnt_stat.mount_info.msdosfs_args, 688 &sbp->mount_info.msdosfs_args, sizeof(struct msdosfs_args)); 689 } 690 strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN); 691 692 return (0); 693 } 694 695 static int 696 ntfs_sync ( 697 struct mount *mp, 698 int waitfor, 699 struct ucred *cred, 700 struct proc *p) 701 { 702 /*dprintf(("ntfs_sync():\n"));*/ 703 return (0); 704 } 705 706 /*ARGSUSED*/ 707 static int 708 ntfs_fhtovp( 709 struct mount *mp, 710 struct fid *fhp, 711 struct vnode **vpp) 712 { 713 struct ntfid *ntfhp = (struct ntfid *)fhp; 714 int error; 715 716 ddprintf(("ntfs_fhtovp(): %s: %d\n", mp->mnt_stat.f_mntonname, 717 ntfhp->ntfid_ino)); 718 719 error = ntfs_vgetex(mp, ntfhp->ntfid_ino, ntfhp->ntfid_attr, NULL, 720 LK_EXCLUSIVE | LK_RETRY, 0, curproc, vpp); /* XXX */ 721 if (error != 0) { 722 *vpp = NULLVP; 723 return (error); 724 } 725 726 /* XXX as unlink/rmdir/mkdir/creat are not currently possible 727 * with NTFS, we don't need to check anything else for now */ 728 return (0); 729 } 730 731 static int 732 ntfs_vptofh( 733 struct vnode *vp, 734 struct fid *fhp) 735 { 736 struct ntnode *ntp; 737 struct ntfid *ntfhp; 738 struct fnode *fn; 739 740 ddprintf(("ntfs_fhtovp(): %s: %p\n", vp->v_mount->mnt_stat.f_mntonname, 741 vp)); 742 743 fn = VTOF(vp); 744 ntp = VTONT(vp); 745 ntfhp = (struct ntfid *)fhp; 746 ntfhp->ntfid_len = sizeof(struct ntfid); 747 ntfhp->ntfid_ino = ntp->i_number; 748 ntfhp->ntfid_attr = fn->f_attrtype; 749 #ifdef notyet 750 ntfhp->ntfid_gen = ntp->i_gen; 751 #endif 752 return (0); 753 } 754 755 int 756 ntfs_vgetex( 757 struct mount *mp, 758 ino_t ino, 759 u_int32_t attrtype, 760 char *attrname, 761 u_long lkflags, 762 u_long flags, 763 struct proc *p, 764 struct vnode **vpp) 765 { 766 int error; 767 struct ntfsmount *ntmp; 768 struct ntnode *ip; 769 struct fnode *fp; 770 struct vnode *vp; 771 enum vtype f_type; 772 773 dprintf(("ntfs_vgetex: ino: %d, attr: 0x%x:%s, lkf: 0x%lx, f: 0x%lx\n", 774 ino, attrtype, attrname?attrname:"", (u_long)lkflags, 775 (u_long)flags )); 776 777 ntmp = VFSTONTFS(mp); 778 *vpp = NULL; 779 780 /* Get ntnode */ 781 error = ntfs_ntlookup(ntmp, ino, &ip, p); 782 if (error) { 783 printf("ntfs_vget: ntfs_ntget failed\n"); 784 return (error); 785 } 786 787 /* It may be not initialized fully, so force load it */ 788 if (!(flags & VG_DONTLOADIN) && !(ip->i_flag & IN_LOADED)) { 789 error = ntfs_loadntnode(ntmp, ip); 790 if(error) { 791 printf("ntfs_vget: CAN'T LOAD ATTRIBUTES FOR INO: %d\n", 792 ip->i_number); 793 ntfs_ntput(ip, p); 794 795 return (error); 796 } 797 } 798 799 error = ntfs_fget(ntmp, ip, attrtype, attrname, &fp); 800 if (error) { 801 printf("ntfs_vget: ntfs_fget failed\n"); 802 ntfs_ntput(ip, p); 803 804 return (error); 805 } 806 807 if (!(flags & VG_DONTVALIDFN) && !(fp->f_flag & FN_VALID)) { 808 if ((ip->i_frflag & NTFS_FRFLAG_DIR) && 809 (fp->f_attrtype == NTFS_A_DATA && fp->f_attrname == NULL)) { 810 f_type = VDIR; 811 } else if (flags & VG_EXT) { 812 f_type = VNON; 813 fp->f_size = fp->f_allocated = 0; 814 } else { 815 f_type = VREG; 816 817 error = ntfs_filesize(ntmp, fp, 818 &fp->f_size, &fp->f_allocated); 819 if (error) { 820 ntfs_ntput(ip, p); 821 822 return (error); 823 } 824 } 825 826 fp->f_flag |= FN_VALID; 827 } 828 829 /* 830 * We may be calling vget() now. To avoid potential deadlock, we need 831 * to release ntnode lock, since due to locking order vnode 832 * lock has to be acquired first. 833 * ntfs_fget() bumped ntnode usecount, so ntnode won't be recycled 834 * prematurely. 835 */ 836 ntfs_ntput(ip, p); 837 838 if (FTOV(fp)) { 839 /* vget() returns error if the vnode has been recycled */ 840 if (vget(FTOV(fp), lkflags, p) == 0) { 841 *vpp = FTOV(fp); 842 return (0); 843 } 844 } 845 846 error = getnewvnode(VT_NTFS, ntmp->ntm_mountp, &ntfs_vops, &vp); 847 if(error) { 848 ntfs_frele(fp); 849 ntfs_ntput(ip, p); 850 851 return (error); 852 } 853 dprintf(("ntfs_vget: vnode: %p for ntnode: %d\n", vp,ino)); 854 855 fp->f_vp = vp; 856 vp->v_data = fp; 857 vp->v_type = f_type; 858 859 if (ino == NTFS_ROOTINO) 860 vp->v_flag |= VROOT; 861 862 if (lkflags & LK_TYPE_MASK) { 863 error = vn_lock(vp, lkflags, p); 864 if (error) { 865 vput(vp); 866 return (error); 867 } 868 } 869 870 *vpp = vp; 871 return (0); 872 } 873 874 static int 875 ntfs_vget( 876 struct mount *mp, 877 ino_t ino, 878 struct vnode **vpp) 879 { 880 return ntfs_vgetex(mp, ino, NTFS_A_DATA, NULL, 881 LK_EXCLUSIVE | LK_RETRY, 0, curproc, vpp); /* XXX */ 882 } 883 884 const struct vfsops ntfs_vfsops = { 885 ntfs_mount, 886 ntfs_start, 887 ntfs_unmount, 888 ntfs_root, 889 ntfs_quotactl, 890 ntfs_statfs, 891 ntfs_sync, 892 ntfs_vget, 893 ntfs_fhtovp, 894 ntfs_vptofh, 895 ntfs_init, 896 ntfs_sysctl, 897 ntfs_checkexp, 898 }; 899