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