1 /* $OpenBSD: ntfs_vfsops.c,v 1.13 2008/05/13 02:24:08 brad 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/fcntl.h> 41 #include <sys/malloc.h> 42 #include <sys/systm.h> 43 #include <sys/device.h> 44 #include <sys/conf.h> 45 46 #if defined(__NetBSD__) || defined(__OpenBSD__) 47 #include <uvm/uvm_extern.h> 48 #else 49 #include <vm/vm.h> 50 #endif 51 52 #include <miscfs/specfs/specdev.h> 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 #if defined(__FreeBSD__) 101 static int ntfs_init(struct vfsconf *); 102 static int ntfs_fhtovp(struct mount *, struct fid *, 103 struct sockaddr *, struct vnode **, 104 int *, struct ucred **); 105 #elif defined(__NetBSD__) 106 static void ntfs_init(void); 107 static void ntfs_reinit(void); 108 static void ntfs_done(void); 109 static int ntfs_fhtovp(struct mount *, struct fid *, 110 struct vnode **); 111 static int ntfs_checkexp(struct mount *, struct mbuf *, 112 int *, struct ucred **); 113 static int ntfs_mountroot(void); 114 static int ntfs_sysctl(int *, u_int, void *, size_t *, void *, 115 size_t, struct proc *); 116 #elif defined(__OpenBSD__) 117 static int ntfs_init(struct vfsconf *); 118 static int ntfs_fhtovp(struct mount *, struct fid *, 119 struct vnode **); 120 static int ntfs_checkexp(struct mount *, struct mbuf *, 121 int *, struct ucred **); 122 static int ntfs_sysctl(int *, u_int, void *, size_t *, void *, 123 size_t, struct proc *); 124 #else 125 static int ntfs_init(void); 126 static int ntfs_fhtovp(struct mount *, struct fid *, 127 struct mbuf *, struct vnode **, 128 int *, struct ucred **); 129 #endif 130 131 #if defined(__FreeBSD__) || defined(__NetBSD__) 132 struct genfs_ops ntfs_genfsops = { 133 NULL, 134 NULL, 135 genfs_compat_gop_write, 136 }; 137 #endif 138 139 #if defined(__NetBSD__) || defined(__OpenBSD__) 140 /* 141 * Verify a remote client has export rights and return these rights via. 142 * exflagsp and credanonp. 143 */ 144 static int 145 ntfs_checkexp(mp, nam, exflagsp, credanonp) 146 struct mount *mp; 147 struct mbuf *nam; 148 int *exflagsp; 149 struct ucred **credanonp; 150 { 151 struct netcred *np; 152 struct ntfsmount *ntm = VFSTONTFS(mp); 153 154 /* 155 * Get the export permission structure for this <mp, client> tuple. 156 */ 157 np = vfs_export_lookup(mp, &ntm->ntm_export, nam); 158 if (np == NULL) 159 return (EACCES); 160 161 *exflagsp = np->netc_exflags; 162 *credanonp = &np->netc_anon; 163 return (0); 164 } 165 166 /*ARGSUSED*/ 167 static int 168 ntfs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 169 int *name; 170 u_int namelen; 171 void *oldp; 172 size_t *oldlenp; 173 void *newp; 174 size_t newlen; 175 struct proc *p; 176 { 177 return (EINVAL); 178 } 179 180 #endif 181 182 #ifdef __NetBSD__ 183 static int 184 ntfs_mountroot() 185 { 186 struct mount *mp; 187 struct proc *p = curproc; /* XXX */ 188 int error; 189 struct ntfs_args args; 190 191 if (root_device->dv_class != DV_DISK) 192 return (ENODEV); 193 194 /* 195 * Get vnodes for rootdev. 196 */ 197 if (bdevvp(rootdev, &rootvp)) 198 panic("ntfs_mountroot: can't setup rootvp"); 199 200 if ((error = vfs_rootmountalloc(MOUNT_NTFS, "root_device", &mp))) { 201 vrele(rootvp); 202 return (error); 203 } 204 205 args.flag = 0; 206 args.uid = 0; 207 args.gid = 0; 208 args.mode = 0777; 209 210 if ((error = ntfs_mountfs(rootvp, mp, &args, p)) != 0) { 211 mp->mnt_op->vfs_refcount--; 212 vfs_unbusy(mp); 213 free(mp, M_MOUNT); 214 vrele(rootvp); 215 return (error); 216 } 217 218 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); 219 (void)ntfs_statfs(mp, &mp->mnt_stat, p); 220 vfs_unbusy(mp); 221 222 return (0); 223 } 224 225 static void 226 ntfs_init() 227 { 228 #ifdef _LKM 229 malloc_type_attach(M_NTFSMNT); 230 malloc_type_attach(M_NTFSNTNODE); 231 malloc_type_attach(M_NTFSFNODE); 232 malloc_type_attach(M_NTFSDIR); 233 malloc_type_attach(M_NTFSNTHASH); 234 malloc_type_attach(M_NTFSNTVATTR); 235 malloc_type_attach(M_NTFSRDATA); 236 malloc_type_attach(M_NTFSDECOMP); 237 malloc_type_attach(M_NTFSRUN); 238 #endif 239 ntfs_nthashinit(); 240 ntfs_toupper_init(); 241 } 242 243 static void 244 ntfs_reinit() 245 { 246 ntfs_nthashreinit(); 247 } 248 249 static void 250 ntfs_done() 251 { 252 ntfs_nthashdone(); 253 #ifdef _LKM 254 malloc_type_detach(M_NTFSMNT); 255 malloc_type_detach(M_NTFSNTNODE); 256 malloc_type_detach(M_NTFSFNODE); 257 malloc_type_detach(M_NTFSDIR); 258 malloc_type_detach(M_NTFSNTHASH); 259 malloc_type_detach(M_NTFSNTVATTR); 260 malloc_type_detach(M_NTFSRDATA); 261 malloc_type_detach(M_NTFSDECOMP); 262 malloc_type_detach(M_NTFSRUN); 263 #endif 264 } 265 266 #elif defined(__FreeBSD__) || defined(__OpenBSD__) 267 268 static int 269 ntfs_init ( 270 struct vfsconf *vcp ) 271 { 272 ntfs_nthashinit(); 273 ntfs_toupper_init(); 274 return 0; 275 } 276 277 #endif /* NetBSD */ 278 279 static int 280 ntfs_mount( 281 struct mount *mp, 282 #if defined(__FreeBSD__) 283 char *path, 284 caddr_t data, 285 #else 286 const char *path, 287 void *data, 288 #endif 289 struct nameidata *ndp, 290 struct proc *p ) 291 { 292 int err = 0; 293 struct vnode *devvp; 294 struct ntfs_args args; 295 size_t size; 296 mode_t amode; 297 298 #ifdef __FreeBSD__ 299 /* 300 * Use NULL path to flag a root mount 301 */ 302 if( path == NULL) { 303 /* 304 *** 305 * Mounting root file system 306 *** 307 */ 308 309 /* Get vnode for root device*/ 310 if( bdevvp( rootdev, &rootvp)) 311 panic("ffs_mountroot: can't setup bdevvp for root"); 312 313 /* 314 * FS specific handling 315 */ 316 mp->mnt_flag |= MNT_RDONLY; /* XXX globally applicable?*/ 317 318 /* 319 * Attempt mount 320 */ 321 if( ( err = ntfs_mountfs(rootvp, mp, &args, p)) != 0) { 322 /* fs specific cleanup (if any)*/ 323 goto error_1; 324 } 325 326 goto dostatfs; /* success*/ 327 328 } 329 #endif /* FreeBSD */ 330 331 #ifdef __NetBSD__ 332 if (mp->mnt_flag & MNT_GETARGS) { 333 struct ntfsmount *ntmp = VFSTONTFS(mp); 334 if (ntmp == NULL) 335 return EIO; 336 args.fspec = NULL; 337 args.uid = ntmp->ntm_uid; 338 args.gid = ntmp->ntm_gid; 339 args.mode = ntmp->ntm_mode; 340 args.flag = ntmp->ntm_flag; 341 vfs_showexport(mp, &args.export, &ntmp->ntm_export); 342 return copyout(&args, data, sizeof(args)); 343 } 344 #endif 345 346 /* 347 *** 348 * Mounting non-root file system or updating a file system 349 *** 350 */ 351 352 /* copy in user arguments*/ 353 err = copyin(data, (caddr_t)&args, sizeof (struct ntfs_args)); 354 if (err) 355 goto error_1; /* can't get arguments*/ 356 357 /* 358 * If updating, check whether changing from read-only to 359 * read/write; if there is no device name, that's all we do. 360 */ 361 if (mp->mnt_flag & MNT_UPDATE) { 362 /* if not updating name...*/ 363 if (args.fspec == 0) { 364 /* 365 * Process export requests. Jumping to "success" 366 * will return the vfs_export() error code. 367 */ 368 struct ntfsmount *ntm = VFSTONTFS(mp); 369 err = vfs_export(mp, &ntm->ntm_export, &args.export_info); 370 goto success; 371 } 372 373 printf("ntfs_mount(): MNT_UPDATE not supported\n"); 374 err = EINVAL; 375 goto error_1; 376 } 377 378 /* 379 * Not an update, or updating the name: look up the name 380 * and verify that it refers to a sensible block device. 381 */ 382 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); 383 err = namei(ndp); 384 if (err) { 385 /* can't get devvp!*/ 386 goto error_1; 387 } 388 389 devvp = ndp->ni_vp; 390 391 if (devvp->v_type != VBLK) { 392 err = ENOTBLK; 393 goto error_2; 394 } 395 396 #ifdef __FreeBSD__ 397 if (bdevsw(devvp->v_rdev) == NULL) { 398 #elif defined(__NetBSD__) 399 if (bdevsw_lookup(devvp->v_rdev) == NULL) { 400 #else 401 if (major(devvp->v_rdev) >= nblkdev) { 402 #endif 403 err = ENXIO; 404 goto error_2; 405 } 406 407 /* 408 * If we are not root, make sure we have permission to access the 409 * requested device. 410 */ 411 if (p->p_ucred->cr_uid) { 412 amode = (mp->mnt_flag & MNT_RDONLY) ? VREAD : (VREAD | VWRITE); 413 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 414 err = VOP_ACCESS(devvp, amode, p->p_ucred, p); 415 VOP_UNLOCK(devvp, 0, p); 416 if (err) 417 goto error_2; 418 } 419 420 if (mp->mnt_flag & MNT_UPDATE) { 421 #if 0 422 /* 423 ******************** 424 * UPDATE 425 ******************** 426 */ 427 428 if (devvp != ntmp->um_devvp) 429 err = EINVAL; /* needs translation */ 430 else 431 vrele(devvp); 432 /* 433 * Update device name only on success 434 */ 435 if( !err) { 436 err = set_statfs_info(NULL, UIO_USERSPACE, args.fspec, 437 UIO_USERSPACE, mp, p); 438 } 439 #endif 440 } else { 441 /* 442 ******************** 443 * NEW MOUNT 444 ******************** 445 */ 446 447 /* 448 * Since this is a new mount, we want the names for 449 * the device and the mount point copied in. If an 450 * error occurs, the mountpoint is discarded by the 451 * upper level code. 452 */ 453 /* Save "last mounted on" info for mount point (NULL pad)*/ 454 #if defined(__FreeBSD__) || defined(__NetBSD__) 455 err = set_statfs_info(path, UIO_USERSPACE, args.fspec, 456 UIO_USERSPACE, mp, p); 457 #else 458 (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, 459 &size); 460 bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); 461 (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, 462 MNAMELEN - 1, &size); 463 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 464 bcopy(&args, &mp->mnt_stat.mount_info.ntfs_args, sizeof(args)); 465 #endif 466 if ( !err) { 467 err = ntfs_mountfs(devvp, mp, &args, p); 468 } 469 } 470 if (err) { 471 goto error_2; 472 } 473 474 #ifdef __FreeBSD__ 475 dostatfs: 476 #endif 477 /* 478 * Initialize FS stat information in mount struct; uses both 479 * mp->mnt_stat.f_mntonname and mp->mnt_stat.f_mntfromname 480 * 481 * This code is common to root and non-root mounts 482 */ 483 (void)VFS_STATFS(mp, &mp->mnt_stat, p); 484 485 goto success; 486 487 488 error_2: /* error with devvp held*/ 489 490 /* release devvp before failing*/ 491 vrele(devvp); 492 493 error_1: /* no state to back out*/ 494 495 success: 496 return(err); 497 } 498 499 /* 500 * Common code for mount and mountroot 501 */ 502 int 503 ntfs_mountfs(devvp, mp, argsp, p) 504 struct vnode *devvp; 505 struct mount *mp; 506 struct ntfs_args *argsp; 507 struct proc *p; 508 { 509 struct buf *bp; 510 struct ntfsmount *ntmp = NULL; 511 dev_t dev = devvp->v_rdev; 512 int error, ronly, ncount, i; 513 struct vnode *vp; 514 515 /* 516 * Disallow multiple mounts of the same device. 517 * Disallow mounting of a device that is currently in use 518 * (except for root, which might share swap device for miniroot). 519 * Flush out any old buffers remaining from a previous use. 520 */ 521 error = vfs_mountedon(devvp); 522 if (error) 523 return (error); 524 ncount = vcount(devvp); 525 if (ncount > 1 && devvp != rootvp) 526 return (EBUSY); 527 error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0); 528 if (error) 529 return (error); 530 531 ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 532 error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p); 533 if (error) 534 return (error); 535 536 bp = NULL; 537 538 error = bread(devvp, BBLOCK, BBSIZE, NOCRED, &bp); 539 if (error) 540 goto out; 541 ntmp = malloc(sizeof *ntmp, M_NTFSMNT, M_WAITOK | M_ZERO); 542 bcopy(bp->b_data, &ntmp->ntm_bootfile, sizeof(struct bootfile)); 543 brelse(bp); 544 bp = NULL; 545 546 if (strncmp(ntmp->ntm_bootfile.bf_sysid, NTFS_BBID, NTFS_BBIDLEN)) { 547 error = EINVAL; 548 dprintf(("ntfs_mountfs: invalid boot block\n")); 549 goto out; 550 } 551 552 { 553 int8_t cpr = ntmp->ntm_mftrecsz; 554 if( cpr > 0 ) 555 ntmp->ntm_bpmftrec = ntmp->ntm_spc * cpr; 556 else 557 ntmp->ntm_bpmftrec = (1 << (-cpr)) / ntmp->ntm_bps; 558 } 559 dprintf(("ntfs_mountfs(): bps: %d, spc: %d, media: %x, mftrecsz: %d (%d sects)\n", 560 ntmp->ntm_bps,ntmp->ntm_spc,ntmp->ntm_bootfile.bf_media, 561 ntmp->ntm_mftrecsz,ntmp->ntm_bpmftrec)); 562 dprintf(("ntfs_mountfs(): mftcn: 0x%x|0x%x\n", 563 (u_int32_t)ntmp->ntm_mftcn,(u_int32_t)ntmp->ntm_mftmirrcn)); 564 565 ntmp->ntm_mountp = mp; 566 ntmp->ntm_dev = dev; 567 ntmp->ntm_devvp = devvp; 568 ntmp->ntm_uid = argsp->uid; 569 ntmp->ntm_gid = argsp->gid; 570 ntmp->ntm_mode = argsp->mode; 571 ntmp->ntm_flag = argsp->flag; 572 #ifdef __OpenBSD__ 573 mp->mnt_data = (qaddr_t) ntmp; 574 #else 575 mp->mnt_data = ntmp; 576 #endif 577 578 /* set file name encode/decode hooks XXX utf-8 only for now */ 579 ntmp->ntm_wget = ntfs_utf8_wget; 580 ntmp->ntm_wput = ntfs_utf8_wput; 581 ntmp->ntm_wcmp = ntfs_utf8_wcmp; 582 583 dprintf(("ntfs_mountfs(): case-%s,%s uid: %d, gid: %d, mode: %o\n", 584 (ntmp->ntm_flag & NTFS_MFLAG_CASEINS)?"insens.":"sens.", 585 (ntmp->ntm_flag & NTFS_MFLAG_ALLNAMES)?" allnames,":"", 586 ntmp->ntm_uid, ntmp->ntm_gid, ntmp->ntm_mode)); 587 588 /* 589 * We read in some system nodes to do not allow 590 * reclaim them and to have everytime access to them. 591 */ 592 { 593 int pi[3] = { NTFS_MFTINO, NTFS_ROOTINO, NTFS_BITMAPINO }; 594 for (i=0; i<3; i++) { 595 error = VFS_VGET(mp, pi[i], &(ntmp->ntm_sysvn[pi[i]])); 596 if(error) 597 goto out1; 598 ntmp->ntm_sysvn[pi[i]]->v_flag |= VSYSTEM; 599 VREF(ntmp->ntm_sysvn[pi[i]]); 600 vput(ntmp->ntm_sysvn[pi[i]]); 601 } 602 } 603 604 /* read the Unicode lowercase --> uppercase translation table, 605 * if necessary */ 606 #ifndef __OpenBSD__ 607 if ((error = ntfs_toupper_use(mp, ntmp))) 608 #else 609 if ((error = ntfs_toupper_use(mp, ntmp, p))) 610 #endif 611 goto out1; 612 613 /* 614 * Scan $BitMap and count free clusters 615 */ 616 error = ntfs_calccfree(ntmp, &ntmp->ntm_cfree); 617 if(error) 618 goto out1; 619 620 /* 621 * Read and translate to internal format attribute 622 * definition file. 623 */ 624 { 625 int num,j; 626 struct attrdef ad; 627 628 /* Open $AttrDef */ 629 error = VFS_VGET(mp, NTFS_ATTRDEFINO, &vp ); 630 if(error) 631 goto out1; 632 633 /* Count valid entries */ 634 for(num=0;;num++) { 635 error = ntfs_readattr(ntmp, VTONT(vp), 636 NTFS_A_DATA, NULL, 637 num * sizeof(ad), sizeof(ad), 638 &ad, NULL); 639 if (error) 640 goto out1; 641 if (ad.ad_name[0] == 0) 642 break; 643 } 644 645 /* Alloc memory for attribute definitions */ 646 ntmp->ntm_ad = (struct ntvattrdef *) malloc( 647 num * sizeof(struct ntvattrdef), 648 M_NTFSMNT, M_WAITOK); 649 650 ntmp->ntm_adnum = num; 651 652 /* Read them and translate */ 653 for(i=0;i<num;i++){ 654 error = ntfs_readattr(ntmp, VTONT(vp), 655 NTFS_A_DATA, NULL, 656 i * sizeof(ad), sizeof(ad), 657 &ad, NULL); 658 if (error) 659 goto out1; 660 j = 0; 661 do { 662 ntmp->ntm_ad[i].ad_name[j] = ad.ad_name[j]; 663 } while(ad.ad_name[j++]); 664 ntmp->ntm_ad[i].ad_namelen = j - 1; 665 ntmp->ntm_ad[i].ad_type = ad.ad_type; 666 } 667 668 vput(vp); 669 } 670 671 #if defined(__FreeBSD__) 672 mp->mnt_stat.f_fsid.val[0] = dev2udev(dev); 673 mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 674 #else 675 mp->mnt_stat.f_fsid.val[0] = dev; 676 mp->mnt_stat.f_fsid.val[1] = makefstype(MOUNT_NTFS); 677 #endif 678 mp->mnt_maxsymlinklen = 0; 679 mp->mnt_flag |= MNT_LOCAL; 680 devvp->v_specmountpoint = mp; 681 return (0); 682 683 out1: 684 for (i = 0; i < NTFS_SYSNODESNUM; i++) 685 if (ntmp->ntm_sysvn[i]) 686 vrele(ntmp->ntm_sysvn[i]); 687 688 if (vflush(mp,NULLVP,0)) 689 dprintf(("ntfs_mountfs: vflush failed\n")); 690 691 out: 692 devvp->v_specmountpoint = NULL; 693 if (bp) 694 brelse(bp); 695 696 if (ntmp != NULL) { 697 if (ntmp->ntm_ad != NULL) 698 free(ntmp->ntm_ad, M_NTFSMNT); 699 free(ntmp, M_NTFSMNT); 700 mp->mnt_data = NULL; 701 } 702 703 /* lock the device vnode before calling VOP_CLOSE() */ 704 VN_LOCK(devvp, LK_EXCLUSIVE | LK_RETRY, p); 705 (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p); 706 VOP__UNLOCK(devvp, 0, p); 707 708 return (error); 709 } 710 711 static int 712 ntfs_start ( 713 struct mount *mp, 714 int flags, 715 struct proc *p ) 716 { 717 return (0); 718 } 719 720 static int 721 ntfs_unmount( 722 struct mount *mp, 723 int mntflags, 724 struct proc *p) 725 { 726 struct ntfsmount *ntmp; 727 int error, ronly = 0, flags, i; 728 729 dprintf(("ntfs_unmount: unmounting...\n")); 730 ntmp = VFSTONTFS(mp); 731 732 flags = 0; 733 if(mntflags & MNT_FORCE) 734 flags |= FORCECLOSE; 735 736 dprintf(("ntfs_unmount: vflushing...\n")); 737 error = vflush(mp,NULLVP,flags | SKIPSYSTEM); 738 if (error) { 739 dprintf(("ntfs_unmount: vflush failed: %d\n",error)); 740 return (error); 741 } 742 743 /* Check if only system vnodes are rest */ 744 for(i=0;i<NTFS_SYSNODESNUM;i++) 745 if((ntmp->ntm_sysvn[i]) && 746 (ntmp->ntm_sysvn[i]->v_usecount > 1)) return (EBUSY); 747 748 /* Dereference all system vnodes */ 749 for(i=0;i<NTFS_SYSNODESNUM;i++) 750 if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]); 751 752 /* vflush system vnodes */ 753 error = vflush(mp,NULLVP,flags); 754 if (error) { 755 /* XXX should this be panic() ? */ 756 printf("ntfs_unmount: vflush failed(sysnodes): %d\n",error); 757 } 758 759 /* Check if the type of device node isn't VBAD before 760 * touching v_specinfo. If the device vnode is revoked, the 761 * field is NULL and touching it causes null pointer derefercence. 762 */ 763 if (ntmp->ntm_devvp->v_type != VBAD) 764 ntmp->ntm_devvp->v_specmountpoint = NULL; 765 766 vinvalbuf(ntmp->ntm_devvp, V_SAVE, NOCRED, p, 0, 0); 767 768 /* lock the device vnode before calling VOP_CLOSE() */ 769 #ifndef __OpenBSD__ 770 VOP_LOCK(ntmp->ntm_devvp, LK_EXCLUSIVE | LK_RETRY); 771 #else 772 VOP_LOCK(ntmp->ntm_devvp, LK_EXCLUSIVE | LK_RETRY, p); 773 #endif 774 error = VOP_CLOSE(ntmp->ntm_devvp, ronly ? FREAD : FREAD|FWRITE, 775 NOCRED, p); 776 VOP__UNLOCK(ntmp->ntm_devvp, 0, p); 777 778 vrele(ntmp->ntm_devvp); 779 780 /* free the toupper table, if this has been last mounted ntfs volume */ 781 #ifndef __OpenBSD__ 782 ntfs_toupper_unuse(); 783 #else 784 ntfs_toupper_unuse(p); 785 #endif 786 787 dprintf(("ntfs_umount: freeing memory...\n")); 788 mp->mnt_data = NULL; 789 mp->mnt_flag &= ~MNT_LOCAL; 790 free(ntmp->ntm_ad, M_NTFSMNT); 791 free(ntmp, M_NTFSMNT); 792 return (error); 793 } 794 795 static int 796 ntfs_root( 797 struct mount *mp, 798 struct vnode **vpp ) 799 { 800 struct vnode *nvp; 801 int error = 0; 802 803 dprintf(("ntfs_root(): sysvn: %p\n", 804 VFSTONTFS(mp)->ntm_sysvn[NTFS_ROOTINO])); 805 error = VFS_VGET(mp, (ino_t)NTFS_ROOTINO, &nvp); 806 if(error) { 807 printf("ntfs_root: VFS_VGET failed: %d\n",error); 808 return (error); 809 } 810 811 *vpp = nvp; 812 return (0); 813 } 814 815 /* 816 * Do operations associated with quotas, not supported 817 */ 818 /* ARGSUSED */ 819 static int 820 ntfs_quotactl ( 821 struct mount *mp, 822 int cmds, 823 uid_t uid, 824 caddr_t arg, 825 struct proc *p) 826 { 827 828 return EOPNOTSUPP; 829 } 830 831 int 832 ntfs_calccfree( 833 struct ntfsmount *ntmp, 834 cn_t *cfreep) 835 { 836 struct vnode *vp; 837 u_int8_t *tmp; 838 int j, error; 839 cn_t cfree = 0; 840 size_t bmsize, i; 841 842 vp = ntmp->ntm_sysvn[NTFS_BITMAPINO]; 843 844 bmsize = VTOF(vp)->f_size; 845 846 tmp = (u_int8_t *) malloc(bmsize, M_TEMP, M_WAITOK); 847 848 error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL, 849 0, bmsize, tmp, NULL); 850 if (error) 851 goto out; 852 853 for(i=0;i<bmsize;i++) 854 for(j=0;j<8;j++) 855 if(~tmp[i] & (1 << j)) cfree++; 856 *cfreep = cfree; 857 858 out: 859 free(tmp, M_TEMP); 860 return(error); 861 } 862 863 static int 864 ntfs_statfs( 865 struct mount *mp, 866 struct statfs *sbp, 867 struct proc *p) 868 { 869 struct ntfsmount *ntmp = VFSTONTFS(mp); 870 u_int64_t mftallocated; 871 872 dprintf(("ntfs_statfs():\n")); 873 874 mftallocated = VTOF(ntmp->ntm_sysvn[NTFS_MFTINO])->f_allocated; 875 876 #if defined(__FreeBSD__) 877 sbp->f_type = mp->mnt_vfc->vfc_typenum; 878 #elif defined(__NetBSD__) 879 sbp->f_type = 0; 880 #elif !defined(__OpenBSD__) 881 sbp->f_type = MOUNT_NTFS; 882 #endif 883 sbp->f_bsize = ntmp->ntm_bps; 884 sbp->f_iosize = ntmp->ntm_bps * ntmp->ntm_spc; 885 sbp->f_blocks = ntmp->ntm_bootfile.bf_spv; 886 sbp->f_bfree = sbp->f_bavail = ntfs_cntobn(ntmp->ntm_cfree); 887 sbp->f_ffree = sbp->f_bfree / ntmp->ntm_bpmftrec; 888 sbp->f_files = mftallocated / ntfs_bntob(ntmp->ntm_bpmftrec) + 889 sbp->f_ffree; 890 sbp->f_flags = mp->mnt_flag; 891 #if !defined(__OpenBSD__) 892 copy_statfs_info(sbp, mp); 893 #else 894 if (sbp != &mp->mnt_stat) { 895 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 896 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 897 bcopy(&mp->mnt_stat.mount_info.msdosfs_args, 898 &sbp->mount_info.msdosfs_args, sizeof(struct msdosfs_args)); 899 } 900 strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN); 901 #endif 902 return (0); 903 } 904 905 static int 906 ntfs_sync ( 907 struct mount *mp, 908 int waitfor, 909 struct ucred *cred, 910 struct proc *p) 911 { 912 /*dprintf(("ntfs_sync():\n"));*/ 913 return (0); 914 } 915 916 /*ARGSUSED*/ 917 static int 918 ntfs_fhtovp( 919 #if defined(__FreeBSD__) 920 struct mount *mp, 921 struct fid *fhp, 922 struct sockaddr *nam, 923 struct vnode **vpp, 924 int *exflagsp, 925 struct ucred **credanonp) 926 #elif defined(__NetBSD__) || defined(__OpenBSD__) 927 struct mount *mp, 928 struct fid *fhp, 929 struct vnode **vpp) 930 #else 931 struct mount *mp, 932 struct fid *fhp, 933 struct mbuf *nam, 934 struct vnode **vpp, 935 int *exflagsp, 936 struct ucred **credanonp) 937 #endif 938 { 939 struct ntfid *ntfhp = (struct ntfid *)fhp; 940 int error; 941 942 ddprintf(("ntfs_fhtovp(): %s: %d\n", mp->mnt_stat.f_mntonname, 943 ntfhp->ntfid_ino)); 944 945 error = ntfs_vgetex(mp, ntfhp->ntfid_ino, ntfhp->ntfid_attr, NULL, 946 LK_EXCLUSIVE | LK_RETRY, 0, curproc, vpp); /* XXX */ 947 if (error != 0) { 948 *vpp = NULLVP; 949 return (error); 950 } 951 952 /* XXX as unlink/rmdir/mkdir/creat are not currently possible 953 * with NTFS, we don't need to check anything else for now */ 954 return (0); 955 } 956 957 static int 958 ntfs_vptofh( 959 struct vnode *vp, 960 struct fid *fhp) 961 { 962 struct ntnode *ntp; 963 struct ntfid *ntfhp; 964 struct fnode *fn; 965 966 ddprintf(("ntfs_fhtovp(): %s: %p\n", vp->v_mount->mnt_stat.f_mntonname, 967 vp)); 968 969 fn = VTOF(vp); 970 ntp = VTONT(vp); 971 ntfhp = (struct ntfid *)fhp; 972 ntfhp->ntfid_len = sizeof(struct ntfid); 973 ntfhp->ntfid_ino = ntp->i_number; 974 ntfhp->ntfid_attr = fn->f_attrtype; 975 #ifdef notyet 976 ntfhp->ntfid_gen = ntp->i_gen; 977 #endif 978 return (0); 979 } 980 981 int 982 ntfs_vgetex( 983 struct mount *mp, 984 ino_t ino, 985 u_int32_t attrtype, 986 char *attrname, 987 u_long lkflags, 988 u_long flags, 989 struct proc *p, 990 struct vnode **vpp) 991 { 992 int error; 993 struct ntfsmount *ntmp; 994 struct ntnode *ip; 995 struct fnode *fp; 996 struct vnode *vp; 997 enum vtype f_type; 998 999 dprintf(("ntfs_vgetex: ino: %d, attr: 0x%x:%s, lkf: 0x%lx, f: 0x%lx\n", 1000 ino, attrtype, attrname?attrname:"", (u_long)lkflags, 1001 (u_long)flags )); 1002 1003 ntmp = VFSTONTFS(mp); 1004 *vpp = NULL; 1005 1006 /* Get ntnode */ 1007 #ifndef __OpenBSD__ 1008 error = ntfs_ntlookup(ntmp, ino, &ip); 1009 #else 1010 error = ntfs_ntlookup(ntmp, ino, &ip, p); 1011 #endif 1012 if (error) { 1013 printf("ntfs_vget: ntfs_ntget failed\n"); 1014 return (error); 1015 } 1016 1017 /* It may be not initialized fully, so force load it */ 1018 if (!(flags & VG_DONTLOADIN) && !(ip->i_flag & IN_LOADED)) { 1019 error = ntfs_loadntnode(ntmp, ip); 1020 if(error) { 1021 printf("ntfs_vget: CAN'T LOAD ATTRIBUTES FOR INO: %d\n", 1022 ip->i_number); 1023 #ifndef __OpenBSD__ 1024 ntfs_ntput(ip); 1025 #else 1026 ntfs_ntput(ip, p); 1027 #endif 1028 return (error); 1029 } 1030 } 1031 1032 error = ntfs_fget(ntmp, ip, attrtype, attrname, &fp); 1033 if (error) { 1034 printf("ntfs_vget: ntfs_fget failed\n"); 1035 #ifndef __OpenBSD__ 1036 ntfs_ntput(ip); 1037 #else 1038 ntfs_ntput(ip, p); 1039 #endif 1040 return (error); 1041 } 1042 1043 if (!(flags & VG_DONTVALIDFN) && !(fp->f_flag & FN_VALID)) { 1044 if ((ip->i_frflag & NTFS_FRFLAG_DIR) && 1045 (fp->f_attrtype == NTFS_A_DATA && fp->f_attrname == NULL)) { 1046 f_type = VDIR; 1047 } else if (flags & VG_EXT) { 1048 f_type = VNON; 1049 fp->f_size = fp->f_allocated = 0; 1050 } else { 1051 f_type = VREG; 1052 1053 error = ntfs_filesize(ntmp, fp, 1054 &fp->f_size, &fp->f_allocated); 1055 if (error) { 1056 #ifndef __OpenBSD__ 1057 ntfs_ntput(ip); 1058 #else 1059 ntfs_ntput(ip, p); 1060 #endif 1061 return (error); 1062 } 1063 } 1064 1065 fp->f_flag |= FN_VALID; 1066 } 1067 1068 /* 1069 * We may be calling vget() now. To avoid potential deadlock, we need 1070 * to release ntnode lock, since due to locking order vnode 1071 * lock has to be acquired first. 1072 * ntfs_fget() bumped ntnode usecount, so ntnode won't be recycled 1073 * prematurely. 1074 */ 1075 #ifndef __OpenBSD__ 1076 ntfs_ntput(ip); 1077 #else 1078 ntfs_ntput(ip, p); 1079 #endif 1080 1081 if (FTOV(fp)) { 1082 /* vget() returns error if the vnode has been recycled */ 1083 if (VGET(FTOV(fp), lkflags, p) == 0) { 1084 *vpp = FTOV(fp); 1085 return (0); 1086 } 1087 } 1088 1089 error = getnewvnode(VT_NTFS, ntmp->ntm_mountp, ntfs_vnodeop_p, &vp); 1090 if(error) { 1091 ntfs_frele(fp); 1092 #ifndef __OpenBSD__ 1093 ntfs_ntput(ip); 1094 #else 1095 ntfs_ntput(ip, p); 1096 #endif 1097 return (error); 1098 } 1099 dprintf(("ntfs_vget: vnode: %p for ntnode: %d\n", vp,ino)); 1100 1101 #ifdef __FreeBSD__ 1102 lockinit(&fp->f_lock, PINOD, "fnode", 0, 0); 1103 #endif 1104 fp->f_vp = vp; 1105 vp->v_data = fp; 1106 vp->v_type = f_type; 1107 1108 if (ino == NTFS_ROOTINO) 1109 vp->v_flag |= VROOT; 1110 1111 if (lkflags & LK_TYPE_MASK) { 1112 error = VN_LOCK(vp, lkflags, p); 1113 if (error) { 1114 vput(vp); 1115 return (error); 1116 } 1117 } 1118 1119 #if defined(__FreeBSD__) || defined(__NetBSD__) 1120 genfs_node_init(vp, &ntfs_genfsops); 1121 #endif 1122 *vpp = vp; 1123 return (0); 1124 } 1125 1126 static int 1127 ntfs_vget( 1128 struct mount *mp, 1129 ino_t ino, 1130 struct vnode **vpp) 1131 { 1132 return ntfs_vgetex(mp, ino, NTFS_A_DATA, NULL, 1133 LK_EXCLUSIVE | LK_RETRY, 0, curproc, vpp); /* XXX */ 1134 } 1135 1136 #if defined(__FreeBSD__) 1137 static struct vfsops ntfs_vfsops = { 1138 ntfs_mount, 1139 ntfs_start, 1140 ntfs_unmount, 1141 ntfs_root, 1142 ntfs_quotactl, 1143 ntfs_statfs, 1144 ntfs_sync, 1145 ntfs_vget, 1146 ntfs_fhtovp, 1147 ntfs_vptofh, 1148 ntfs_init, 1149 NULL 1150 }; 1151 VFS_SET(ntfs_vfsops, ntfs, 0); 1152 #elif defined(__NetBSD__) 1153 extern const struct vnodeopv_desc ntfs_vnodeop_opv_desc; 1154 1155 const struct vnodeopv_desc * const ntfs_vnodeopv_descs[] = { 1156 &ntfs_vnodeop_opv_desc, 1157 NULL, 1158 }; 1159 1160 struct vfsops ntfs_vfsops = { 1161 MOUNT_NTFS, 1162 ntfs_mount, 1163 ntfs_start, 1164 ntfs_unmount, 1165 ntfs_root, 1166 ntfs_quotactl, 1167 ntfs_statfs, 1168 ntfs_sync, 1169 ntfs_vget, 1170 ntfs_fhtovp, 1171 ntfs_vptofh, 1172 ntfs_init, 1173 ntfs_reinit, 1174 ntfs_done, 1175 ntfs_sysctl, 1176 ntfs_mountroot, 1177 ntfs_checkexp, 1178 ntfs_vnodeopv_descs, 1179 }; 1180 #elif defined(__OpenBSD__) 1181 extern const struct vnodeopv_desc ntfs_vnodeop_opv_desc; 1182 1183 const struct vnodeopv_desc * const ntfs_vnodeopv_descs[] = { 1184 &ntfs_vnodeop_opv_desc, 1185 NULL, 1186 }; 1187 1188 const struct vfsops ntfs_vfsops = { 1189 ntfs_mount, 1190 ntfs_start, 1191 ntfs_unmount, 1192 ntfs_root, 1193 ntfs_quotactl, 1194 ntfs_statfs, 1195 ntfs_sync, 1196 ntfs_vget, 1197 ntfs_fhtovp, 1198 ntfs_vptofh, 1199 ntfs_init, 1200 ntfs_sysctl, 1201 ntfs_checkexp, 1202 }; 1203 1204 #endif 1205