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