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