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