1 /* $NetBSD: ntfs_vfsops.c,v 1.23 1999/11/15 19:38:14 jdolecek 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: releng/6.4/sys/fs/ntfs/ntfs_vfsops.c 175489 2008-01-19 17:54:11Z maxim $
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/bio.h>
41 #include <sys/buf.h>
42 #include <sys/fcntl.h>
43 #include <sys/malloc.h>
44 #include <sys/stat.h>
45 #include <sys/systm.h>
46
47 #include <geom/geom.h>
48 #include <geom/geom_vfs.h>
49
50 #include <vm/vm.h>
51 #include <vm/vm_param.h>
52 #include <vm/vm_page.h>
53 #include <vm/vm_object.h>
54 #include <vm/vm_extern.h>
55
56 /*#define NTFS_DEBUG 1*/
57 #include <fs/ntfs/ntfs.h>
58 #include <fs/ntfs/ntfs_inode.h>
59 #include <fs/ntfs/ntfs_subr.h>
60 #include <fs/ntfs/ntfs_vfsops.h>
61 #include <fs/ntfs/ntfs_ihash.h>
62 #include <fs/ntfs/ntfsmount.h>
63
64 static MALLOC_DEFINE(M_NTFSMNT, "NTFS mount", "NTFS mount structure");
65 MALLOC_DEFINE(M_NTFSNTNODE,"NTFS ntnode", "NTFS ntnode information");
66 MALLOC_DEFINE(M_NTFSFNODE,"NTFS fnode", "NTFS fnode information");
67 MALLOC_DEFINE(M_NTFSDIR,"NTFS dir", "NTFS dir buffer");
68
69 struct sockaddr;
70
71 static int ntfs_mountfs(register struct vnode *, struct mount *,
72 struct thread *);
73 static int ntfs_calccfree(struct ntfsmount *ntmp, cn_t *cfreep);
74
75 static vfs_init_t ntfs_init;
76 static vfs_uninit_t ntfs_uninit;
77 static vfs_vget_t ntfs_vget;
78 static vfs_fhtovp_t ntfs_fhtovp;
79 static vfs_cmount_t ntfs_cmount;
80 static vfs_mount_t ntfs_mount;
81 static vfs_root_t ntfs_root;
82 static vfs_statfs_t ntfs_statfs;
83 static vfs_unmount_t ntfs_unmount;
84 static vfs_vptofh_t ntfs_vptofh;
85
86 static b_strategy_t ntfs_bufstrategy;
87
88 /*
89 * Buffer operations for NTFS vnodes.
90 * We punt on VOP_BMAP, so we need to do
91 * strategy on the file's vnode rather
92 * than the underlying device's
93 */
94 static struct buf_ops ntfs_vnbufops = {
95 .bop_name = "NTFS",
96 .bop_strategy = ntfs_bufstrategy,
97 };
98
99 static int
100 ntfs_init (
101 struct vfsconf *vcp )
102 {
103 ntfs_nthashinit();
104 ntfs_toupper_init();
105 return 0;
106 }
107
108 static int
109 ntfs_uninit (
110 struct vfsconf *vcp )
111 {
112 ntfs_toupper_destroy();
113 ntfs_nthashdestroy();
114 return 0;
115 }
116
117 static int
118 ntfs_cmount (
119 struct mntarg *ma,
120 void *data,
121 int flags,
122 struct thread *td )
123 {
124 int error;
125 struct ntfs_args args;
126
127 error = copyin(data, (caddr_t)&args, sizeof args);
128 if (error)
129 return (error);
130 ma = mount_argsu(ma, "from", args.fspec, MAXPATHLEN);
131 ma = mount_arg(ma, "export", &args.export, sizeof args.export);
132 ma = mount_argf(ma, "uid", "%d", args.uid);
133 ma = mount_argf(ma, "gid", "%d", args.gid);
134 ma = mount_argf(ma, "mode", "%d", args.mode);
135 ma = mount_argb(ma, args.flag & NTFS_MFLAG_CASEINS, "nocaseins");
136 ma = mount_argb(ma, args.flag & NTFS_MFLAG_ALLNAMES, "noallnames");
137 if (args.flag & NTFS_MFLAG_KICONV) {
138 ma = mount_argsu(ma, "cs_ntfs", args.cs_ntfs, 64);
139 ma = mount_argsu(ma, "cs_local", args.cs_local, 64);
140 }
141
142 error = kernel_mount(ma, flags);
143
144 return (error);
145 }
146
147 static const char *ntfs_opts[] = {
148 "from", "export", "uid", "gid", "mode", "caseins", "allnames",
149 "kiconv", "cs_ntfs", "cs_local", NULL
150 };
151
152 static int
153 ntfs_mount (
154 struct mount *mp,
155 struct thread *td )
156 {
157 int err = 0, error;
158 struct vnode *devvp;
159 struct nameidata ndp;
160 char *from;
161
162 if (vfs_filteropt(mp->mnt_optnew, ntfs_opts))
163 return (EINVAL);
164
165 from = vfs_getopts(mp->mnt_optnew, "from", &error);
166 if (error)
167 return (error);
168
169 /*
170 * If updating, check whether changing from read-only to
171 * read/write.
172 */
173 if (mp->mnt_flag & MNT_UPDATE) {
174 if (vfs_flagopt(mp->mnt_optnew, "export", NULL, 0)) {
175 /* Process export requests in vfs_mount.c */
176 goto success;
177 } else {
178 printf("ntfs_mount(): MNT_UPDATE not supported\n");
179 err = EINVAL;
180 goto error_1;
181 }
182 }
183
184 /*
185 * Not an update, or updating the name: look up the name
186 * and verify that it refers to a sensible block device.
187 */
188 NDINIT(&ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, from, td);
189 err = namei(&ndp);
190 if (err) {
191 /* can't get devvp!*/
192 goto error_1;
193 }
194 NDFREE(&ndp, NDF_ONLY_PNBUF);
195 devvp = ndp.ni_vp;
196
197 if (!vn_isdisk(devvp, &err)) {
198 vput(devvp);
199 return (err);
200 }
201
202 if (mp->mnt_flag & MNT_UPDATE) {
203 #if 0
204 /*
205 ********************
206 * UPDATE
207 ********************
208 */
209
210 if (devvp != ntmp->um_devvp)
211 err = EINVAL; /* needs translation */
212 vput(devvp);
213 if (err)
214 return (err);
215 #endif
216 } else {
217 /*
218 ********************
219 * NEW MOUNT
220 ********************
221 */
222
223 /*
224 * Since this is a new mount, we want the names for
225 * the device and the mount point copied in. If an
226 * error occurs, the mountpoint is discarded by the
227 * upper level code. Note that vfs_mount() handles
228 * copying the mountpoint f_mntonname for us, so we
229 * don't have to do it here unless we want to set it
230 * to something other than "path" for some rason.
231 */
232 /* Save "mounted from" info for mount point (NULL pad)*/
233 vfs_mountedfrom(mp, from);
234
235 err = ntfs_mountfs(devvp, mp, td);
236 }
237 if (err) {
238 vrele(devvp);
239 return (err);
240 }
241
242 goto success;
243
244 error_1: /* no state to back out*/
245 /* XXX: missing NDFREE(&ndp, ...) */
246
247 success:
248 return(err);
249 }
250
251 /*
252 * Common code for mount and mountroot
253 */
254 int
255 ntfs_mountfs(devvp, mp, td)
256 register struct vnode *devvp;
257 struct mount *mp;
258 struct thread *td;
259 {
260 struct buf *bp;
261 struct ntfsmount *ntmp;
262 struct cdev *dev = devvp->v_rdev;
263 int error, ronly, i, v;
264 struct vnode *vp;
265 struct g_consumer *cp;
266 char *cs_ntfs, *cs_local;
267
268 ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
269 DROP_GIANT();
270 g_topology_lock();
271 error = g_vfs_open(devvp, &cp, "ntfs", ronly ? 0 : 1);
272 g_topology_unlock();
273 PICKUP_GIANT();
274 VOP_UNLOCK(devvp, 0, td);
275 if (error)
276 return (error);
277
278 bp = NULL;
279
280 error = bread(devvp, BBLOCK, BBSIZE, NOCRED, &bp);
281 if (error)
282 goto out;
283 ntmp = malloc( sizeof *ntmp, M_NTFSMNT, M_WAITOK | M_ZERO);
284 bcopy( bp->b_data, &ntmp->ntm_bootfile, sizeof(struct bootfile) );
285 /*
286 * We must not cache the boot block if its size is not exactly
287 * one cluster in order to avoid confusing the buffer cache when
288 * the boot file is read later by ntfs_readntvattr_plain(), which
289 * reads a cluster at a time.
290 */
291 if (ntfs_cntob(1) != BBSIZE)
292 bp->b_flags |= B_NOCACHE;
293 brelse( bp );
294 bp = NULL;
295
296 if (strncmp(ntmp->ntm_bootfile.bf_sysid, NTFS_BBID, NTFS_BBIDLEN)) {
297 error = EINVAL;
298 dprintf(("ntfs_mountfs: invalid boot block\n"));
299 goto out;
300 }
301
302 {
303 int8_t cpr = ntmp->ntm_mftrecsz;
304 if( cpr > 0 )
305 ntmp->ntm_bpmftrec = ntmp->ntm_spc * cpr;
306 else
307 ntmp->ntm_bpmftrec = (1 << (-cpr)) / ntmp->ntm_bps;
308 }
309 dprintf(("ntfs_mountfs(): bps: %d, spc: %d, media: %x, mftrecsz: %d (%d sects)\n",
310 ntmp->ntm_bps,ntmp->ntm_spc,ntmp->ntm_bootfile.bf_media,
311 ntmp->ntm_mftrecsz,ntmp->ntm_bpmftrec));
312 dprintf(("ntfs_mountfs(): mftcn: 0x%x|0x%x\n",
313 (u_int32_t)ntmp->ntm_mftcn,(u_int32_t)ntmp->ntm_mftmirrcn));
314
315 ntmp->ntm_mountp = mp;
316 ntmp->ntm_devvp = devvp;
317 if (1 == vfs_scanopt(mp->mnt_optnew, "uid", "%d", &v))
318 ntmp->ntm_uid = v;
319 if (1 == vfs_scanopt(mp->mnt_optnew, "gid", "%d", &v))
320 ntmp->ntm_gid = v;
321 if (1 == vfs_scanopt(mp->mnt_optnew, "mode", "%d", &v))
322 ntmp->ntm_mode = v & ACCESSPERMS;
323 vfs_flagopt(mp->mnt_optnew,
324 "caseins", &ntmp->ntm_flag, NTFS_MFLAG_CASEINS);
325 vfs_flagopt(mp->mnt_optnew,
326 "allnames", &ntmp->ntm_flag, NTFS_MFLAG_ALLNAMES);
327 ntmp->ntm_cp = cp;
328 ntmp->ntm_bo = &devvp->v_bufobj;
329
330 cs_local = vfs_getopts(mp->mnt_optnew, "cs_local", &error);
331 if (error)
332 goto out;
333 cs_ntfs = vfs_getopts(mp->mnt_optnew, "cs_ntfs", &error);
334 if (error)
335 goto out;
336 /* Copy in the 8-bit to Unicode conversion table */
337 /* Initialize Unicode to 8-bit table from 8toU table */
338 ntfs_82u_init(ntmp, cs_local, cs_ntfs);
339 if (cs_local != NULL && cs_ntfs != NULL)
340 ntfs_u28_init(ntmp, NULL, cs_local, cs_ntfs);
341 else
342 ntfs_u28_init(ntmp, ntmp->ntm_82u, cs_local, cs_ntfs);
343
344 mp->mnt_data = (qaddr_t)ntmp;
345
346 dprintf(("ntfs_mountfs(): case-%s,%s uid: %d, gid: %d, mode: %o\n",
347 (ntmp->ntm_flag & NTFS_MFLAG_CASEINS)?"insens.":"sens.",
348 (ntmp->ntm_flag & NTFS_MFLAG_ALLNAMES)?" allnames,":"",
349 ntmp->ntm_uid, ntmp->ntm_gid, ntmp->ntm_mode));
350
351 /*
352 * We read in some system nodes to do not allow
353 * reclaim them and to have everytime access to them.
354 */
355 {
356 int pi[3] = { NTFS_MFTINO, NTFS_ROOTINO, NTFS_BITMAPINO };
357 for (i=0; i<3; i++) {
358 error = VFS_VGET(mp, pi[i], LK_EXCLUSIVE,
359 &(ntmp->ntm_sysvn[pi[i]]));
360 if(error)
361 goto out1;
362 ntmp->ntm_sysvn[pi[i]]->v_vflag |= VV_SYSTEM;
363 VREF(ntmp->ntm_sysvn[pi[i]]);
364 vput(ntmp->ntm_sysvn[pi[i]]);
365 }
366 }
367
368 /* read the Unicode lowercase --> uppercase translation table,
369 * if necessary */
370 if ((error = ntfs_toupper_use(mp, ntmp)))
371 goto out1;
372
373 /*
374 * Scan $BitMap and count free clusters
375 */
376 error = ntfs_calccfree(ntmp, &ntmp->ntm_cfree);
377 if(error)
378 goto out1;
379
380 /*
381 * Read and translate to internal format attribute
382 * definition file.
383 */
384 {
385 int num,j;
386 struct attrdef ad;
387
388 /* Open $AttrDef */
389 error = VFS_VGET(mp, NTFS_ATTRDEFINO, LK_EXCLUSIVE, &vp );
390 if(error)
391 goto out1;
392
393 /* Count valid entries */
394 for(num=0;;num++) {
395 error = ntfs_readattr(ntmp, VTONT(vp),
396 NTFS_A_DATA, NULL,
397 num * sizeof(ad), sizeof(ad),
398 &ad, NULL);
399 if (error)
400 goto out1;
401 if (ad.ad_name[0] == 0)
402 break;
403 }
404
405 /* Alloc memory for attribute definitions */
406 MALLOC(ntmp->ntm_ad, struct ntvattrdef *,
407 num * sizeof(struct ntvattrdef),
408 M_NTFSMNT, M_WAITOK);
409
410 ntmp->ntm_adnum = num;
411
412 /* Read them and translate */
413 for(i=0;i<num;i++){
414 error = ntfs_readattr(ntmp, VTONT(vp),
415 NTFS_A_DATA, NULL,
416 i * sizeof(ad), sizeof(ad),
417 &ad, NULL);
418 if (error)
419 goto out1;
420 j = 0;
421 do {
422 ntmp->ntm_ad[i].ad_name[j] = ad.ad_name[j];
423 } while(ad.ad_name[j++]);
424 ntmp->ntm_ad[i].ad_namelen = j - 1;
425 ntmp->ntm_ad[i].ad_type = ad.ad_type;
426 }
427
428 vput(vp);
429 }
430
431 mp->mnt_stat.f_fsid.val[0] = dev2udev(dev);
432 mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
433 mp->mnt_maxsymlinklen = 0;
434 MNT_ILOCK(mp);
435 mp->mnt_flag |= MNT_LOCAL;
436 MNT_IUNLOCK(mp);
437 return (0);
438
439 out1:
440 for(i=0;i<NTFS_SYSNODESNUM;i++)
441 if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]);
442
443 if (vflush(mp, 0, 0, td))
444 dprintf(("ntfs_mountfs: vflush failed\n"));
445
446 out:
447 if (bp)
448 brelse(bp);
449
450 DROP_GIANT();
451 g_topology_lock();
452 g_vfs_close(cp, td);
453 g_topology_unlock();
454 PICKUP_GIANT();
455
456 return (error);
457 }
458
459 static int
460 ntfs_unmount(
461 struct mount *mp,
462 int mntflags,
463 struct thread *td)
464 {
465 struct ntfsmount *ntmp;
466 int error, flags, i;
467
468 dprintf(("ntfs_unmount: unmounting...\n"));
469 ntmp = VFSTONTFS(mp);
470
471 flags = 0;
472 if(mntflags & MNT_FORCE)
473 flags |= FORCECLOSE;
474
475 dprintf(("ntfs_unmount: vflushing...\n"));
476 error = vflush(mp, 0, flags | SKIPSYSTEM, td);
477 if (error) {
478 printf("ntfs_unmount: vflush failed: %d\n",error);
479 return (error);
480 }
481
482 /* Check if only system vnodes are rest */
483 for(i=0;i<NTFS_SYSNODESNUM;i++)
484 if((ntmp->ntm_sysvn[i]) &&
485 (vrefcnt(ntmp->ntm_sysvn[i]) > 1)) return (EBUSY);
486
487 /* Dereference all system vnodes */
488 for(i=0;i<NTFS_SYSNODESNUM;i++)
489 if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]);
490
491 /* vflush system vnodes */
492 error = vflush(mp, 0, flags, td);
493 if (error)
494 printf("ntfs_unmount: vflush failed(sysnodes): %d\n",error);
495
496 vinvalbuf(ntmp->ntm_devvp, V_SAVE, td, 0, 0);
497
498 DROP_GIANT();
499 g_topology_lock();
500 g_vfs_close(ntmp->ntm_cp, td);
501 g_topology_unlock();
502 PICKUP_GIANT();
503
504 vrele(ntmp->ntm_devvp);
505
506 /* free the toupper table, if this has been last mounted ntfs volume */
507 ntfs_toupper_unuse();
508
509 dprintf(("ntfs_umount: freeing memory...\n"));
510 ntfs_u28_uninit(ntmp);
511 ntfs_82u_uninit(ntmp);
512 mp->mnt_data = (qaddr_t)0;
513 MNT_ILOCK(mp);
514 mp->mnt_flag &= ~MNT_LOCAL;
515 MNT_IUNLOCK(mp);
516 FREE(ntmp->ntm_ad, M_NTFSMNT);
517 FREE(ntmp, M_NTFSMNT);
518 return (error);
519 }
520
521 static int
522 ntfs_root(
523 struct mount *mp,
524 int flags,
525 struct vnode **vpp,
526 struct thread *td )
527 {
528 struct vnode *nvp;
529 int error = 0;
530
531 dprintf(("ntfs_root(): sysvn: %p\n",
532 VFSTONTFS(mp)->ntm_sysvn[NTFS_ROOTINO]));
533 error = VFS_VGET(mp, (ino_t)NTFS_ROOTINO, LK_EXCLUSIVE, &nvp);
534 if(error) {
535 printf("ntfs_root: VFS_VGET failed: %d\n",error);
536 return (error);
537 }
538
539 *vpp = nvp;
540 return (0);
541 }
542
543 static int
544 ntfs_calccfree(
545 struct ntfsmount *ntmp,
546 cn_t *cfreep)
547 {
548 struct vnode *vp;
549 u_int8_t *tmp;
550 int j, error;
551 long cfree = 0;
552 size_t bmsize, i;
553
554 vp = ntmp->ntm_sysvn[NTFS_BITMAPINO];
555
556 bmsize = VTOF(vp)->f_size;
557
558 MALLOC(tmp, u_int8_t *, bmsize, M_TEMP, M_WAITOK);
559
560 error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL,
561 0, bmsize, tmp, NULL);
562 if (error)
563 goto out;
564
565 for(i=0;i<bmsize;i++)
566 for(j=0;j<8;j++)
567 if(~tmp[i] & (1 << j)) cfree++;
568 *cfreep = cfree;
569
570 out:
571 FREE(tmp, M_TEMP);
572 return(error);
573 }
574
575 static int
576 ntfs_statfs(
577 struct mount *mp,
578 struct statfs *sbp,
579 struct thread *td)
580 {
581 struct ntfsmount *ntmp = VFSTONTFS(mp);
582 u_int64_t mftsize,mftallocated;
583
584 dprintf(("ntfs_statfs():\n"));
585
586 mftsize = VTOF(ntmp->ntm_sysvn[NTFS_MFTINO])->f_size;
587 mftallocated = VTOF(ntmp->ntm_sysvn[NTFS_MFTINO])->f_allocated;
588
589 sbp->f_type = mp->mnt_vfc->vfc_typenum;
590 sbp->f_bsize = ntmp->ntm_bps;
591 sbp->f_iosize = ntmp->ntm_bps * ntmp->ntm_spc;
592 sbp->f_blocks = ntmp->ntm_bootfile.bf_spv;
593 sbp->f_bfree = sbp->f_bavail = ntfs_cntobn(ntmp->ntm_cfree);
594 sbp->f_ffree = sbp->f_bfree / ntmp->ntm_bpmftrec;
595 sbp->f_files = mftallocated / ntfs_bntob(ntmp->ntm_bpmftrec) +
596 sbp->f_ffree;
597 sbp->f_flags = mp->mnt_flag;
598
599 return (0);
600 }
601
602 /*ARGSUSED*/
603 static int
604 ntfs_fhtovp(
605 struct mount *mp,
606 struct fid *fhp,
607 struct vnode **vpp)
608 {
609 struct vnode *nvp;
610 struct ntfid *ntfhp = (struct ntfid *)fhp;
611 int error;
612
613 ddprintf(("ntfs_fhtovp(): %d\n", ntfhp->ntfid_ino));
614
615 if ((error = VFS_VGET(mp, ntfhp->ntfid_ino, LK_EXCLUSIVE, &nvp)) != 0) {
616 *vpp = NULLVP;
617 return (error);
618 }
619 /* XXX as unlink/rmdir/mkdir/creat are not currently possible
620 * with NTFS, we don't need to check anything else for now */
621 *vpp = nvp;
622 vnode_create_vobject_off(nvp, VTOF(nvp)->f_size, curthread);
623 return (0);
624 }
625
626 static int
627 ntfs_vptofh(
628 struct vnode *vp,
629 struct fid *fhp)
630 {
631 register struct ntnode *ntp;
632 register struct ntfid *ntfhp;
633
634 ddprintf(("ntfs_fhtovp(): %p\n", vp));
635
636 ntp = VTONT(vp);
637 ntfhp = (struct ntfid *)fhp;
638 ntfhp->ntfid_len = sizeof(struct ntfid);
639 ntfhp->ntfid_ino = ntp->i_number;
640 /* ntfhp->ntfid_gen = ntp->i_gen; */
641 return (0);
642 }
643
644 int
645 ntfs_vgetex(
646 struct mount *mp,
647 ino_t ino,
648 u_int32_t attrtype,
649 char *attrname,
650 u_long lkflags,
651 u_long flags,
652 struct thread *td,
653 struct vnode **vpp)
654 {
655 int error;
656 register struct ntfsmount *ntmp;
657 struct ntnode *ip;
658 struct fnode *fp;
659 struct vnode *vp;
660 enum vtype f_type;
661
662 dprintf(("ntfs_vgetex: ino: %d, attr: 0x%x:%s, lkf: 0x%lx, f: 0x%lx\n",
663 ino, attrtype, attrname?attrname:"", (u_long)lkflags,
664 (u_long)flags));
665
666 ntmp = VFSTONTFS(mp);
667 *vpp = NULL;
668
669 /* Get ntnode */
670 error = ntfs_ntlookup(ntmp, ino, &ip);
671 if (error) {
672 printf("ntfs_vget: ntfs_ntget failed\n");
673 return (error);
674 }
675
676 /* It may be not initialized fully, so force load it */
677 if (!(flags & VG_DONTLOADIN) && !(ip->i_flag & IN_LOADED)) {
678 error = ntfs_loadntnode(ntmp, ip);
679 if(error) {
680 printf("ntfs_vget: CAN'T LOAD ATTRIBUTES FOR INO: %d\n",
681 ip->i_number);
682 ntfs_ntput(ip);
683 return (error);
684 }
685 }
686
687 error = ntfs_fget(ntmp, ip, attrtype, attrname, &fp);
688 if (error) {
689 printf("ntfs_vget: ntfs_fget failed\n");
690 ntfs_ntput(ip);
691 return (error);
692 }
693
694 f_type = VNON;
695 if (!(flags & VG_DONTVALIDFN) && !(fp->f_flag & FN_VALID)) {
696 if ((ip->i_frflag & NTFS_FRFLAG_DIR) &&
697 (fp->f_attrtype == NTFS_A_DATA && fp->f_attrname == NULL)) {
698 f_type = VDIR;
699 } else if (flags & VG_EXT) {
700 f_type = VNON;
701 fp->f_size = fp->f_allocated = 0;
702 } else {
703 f_type = VREG;
704
705 error = ntfs_filesize(ntmp, fp,
706 &fp->f_size, &fp->f_allocated);
707 if (error) {
708 ntfs_ntput(ip);
709 return (error);
710 }
711 }
712
713 fp->f_flag |= FN_VALID;
714 }
715
716 if (FTOV(fp)) {
717 vget(FTOV(fp), lkflags, td);
718 *vpp = FTOV(fp);
719 ntfs_ntput(ip);
720 return (0);
721 }
722
723 error = getnewvnode("ntfs", ntmp->ntm_mountp, &ntfs_vnodeops, &vp);
724 if(error) {
725 ntfs_frele(fp);
726 ntfs_ntput(ip);
727 return (error);
728 }
729 dprintf(("ntfs_vget: vnode: %p for ntnode: %d\n", vp,ino));
730
731 fp->f_vp = vp;
732 vp->v_data = fp;
733 vp->v_type = f_type;
734
735 vp->v_bufobj.bo_ops = &ntfs_vnbufops;
736 vp->v_bufobj.bo_private = vp;
737
738 if (ino == NTFS_ROOTINO)
739 vp->v_vflag |= VV_ROOT;
740
741 ntfs_ntput(ip);
742
743 if (lkflags & LK_TYPE_MASK) {
744 error = vn_lock(vp, lkflags, td);
745 if (error) {
746 vput(vp);
747 return (error);
748 }
749 }
750
751 *vpp = vp;
752 return (0);
753
754 }
755
756 static int
757 ntfs_vget(
758 struct mount *mp,
759 ino_t ino,
760 int lkflags,
761 struct vnode **vpp)
762 {
763 return ntfs_vgetex(mp, ino, NTFS_A_DATA, NULL, lkflags, 0,
764 curthread, vpp);
765 }
766
767 static void
768 ntfs_bufstrategy(struct bufobj *bo, struct buf *bp)
769 {
770 struct vnode *vp;
771 int rc;
772
773 vp = bo->bo_private;
774 KASSERT(bo == &vp->v_bufobj, ("BO/VP mismatch: vp %p bo %p != %p",
775 vp, &vp->v_bufobj, bo));
776 rc = VOP_STRATEGY(vp, bp);
777 KASSERT(rc == 0, ("NTFS VOP_STRATEGY failed: bp=%p, "
778 "vp=%p, rc=%d", bp, vp, rc));
779 }
780
781 static struct vfsops ntfs_vfsops = {
782 .vfs_fhtovp = ntfs_fhtovp,
783 .vfs_init = ntfs_init,
784 .vfs_cmount = ntfs_cmount,
785 .vfs_mount = ntfs_mount,
786 .vfs_root = ntfs_root,
787 .vfs_statfs = ntfs_statfs,
788 .vfs_uninit = ntfs_uninit,
789 .vfs_unmount = ntfs_unmount,
790 .vfs_vget = ntfs_vget,
791 .vfs_vptofh = ntfs_vptofh,
792 };
793 VFS_SET(ntfs_vfsops, ntfs, 0);
794 MODULE_VERSION(ntfs, 1);
Cache object: 7b899a4c63a156f9bae30246e9105a93
|