Add an argument to vfs_add_vnodeops() to specify VVF_* flags for the vop_ops
[dragonfly.git] / sys / vfs / ntfs / ntfs_vfsops.c
CommitLineData
984263bc
MD
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: src/sys/ntfs/ntfs_vfsops.c,v 1.20.2.5 2001/12/25 01:44:45 dillon Exp $
dc1be39c 29 * $DragonFly: src/sys/vfs/ntfs/ntfs_vfsops.c,v 1.30 2005/09/17 07:43:12 dillon Exp $
984263bc
MD
30 */
31
32
33#include <sys/param.h>
34#include <sys/systm.h>
984263bc
MD
35#include <sys/conf.h>
36#include <sys/proc.h>
fad57d0e 37#include <sys/nlookup.h>
984263bc
MD
38#include <sys/kernel.h>
39#include <sys/vnode.h>
40#include <sys/mount.h>
41#include <sys/buf.h>
42#include <sys/fcntl.h>
43#include <sys/malloc.h>
44#include <sys/systm.h>
45#if defined(__NetBSD__)
46#include <sys/device.h>
47#endif
48
f91a71dd
JS
49#include <machine/inttypes.h>
50
984263bc
MD
51#include <vm/vm.h>
52#include <vm/vm_param.h>
53#if defined(__NetBSD__)
54#include <vm/vm_prot.h>
55#endif
56#include <vm/vm_page.h>
57#include <vm/vm_object.h>
58#include <vm/vm_extern.h>
59#include <vm/vm_zone.h>
60
61#if defined(__NetBSD__)
62#include <miscfs/specfs/specdev.h>
63#endif
64
65/*#define NTFS_DEBUG 1*/
1f2de5d4
MD
66#include "ntfs.h"
67#include "ntfs_inode.h"
68#include "ntfs_subr.h"
69#include "ntfs_vfsops.h"
70#include "ntfs_ihash.h"
71#include "ntfsmount.h"
984263bc 72
0961aa92
MD
73extern struct vnodeopv_entry_desc ntfs_vnodeop_entries[];
74
08c23b99 75#if defined(__DragonFly__)
984263bc
MD
76MALLOC_DEFINE(M_NTFSMNT, "NTFS mount", "NTFS mount structure");
77MALLOC_DEFINE(M_NTFSNTNODE,"NTFS ntnode", "NTFS ntnode information");
78MALLOC_DEFINE(M_NTFSFNODE,"NTFS fnode", "NTFS fnode information");
79MALLOC_DEFINE(M_NTFSDIR,"NTFS dir", "NTFS dir buffer");
80#endif
81
a6ee311a
RG
82static int ntfs_root (struct mount *, struct vnode **);
83static int ntfs_statfs (struct mount *, struct statfs *,
84 struct thread *);
85static int ntfs_unmount (struct mount *, int, struct thread *);
86static int ntfs_vget (struct mount *mp, ino_t ino,
87 struct vnode **vpp);
88static int ntfs_mountfs (struct vnode *, struct mount *,
89 struct ntfs_args *, struct thread *);
90static int ntfs_vptofh (struct vnode *, struct fid *);
91static int ntfs_fhtovp (struct mount *, struct fid *,
92 struct vnode **);
984263bc 93
08c23b99 94#if !defined (__DragonFly__)
a6ee311a
RG
95static int ntfs_quotactl (struct mount *, int, uid_t, caddr_t,
96 struct thread *);
97static int ntfs_start (struct mount *, int, struct thread *);
98static int ntfs_sync (struct mount *, int, struct ucred *,
99 struct thread *);
984263bc
MD
100#endif
101
08c23b99 102#if defined(__DragonFly__)
984263bc 103struct sockaddr;
21739618 104static int ntfs_mount (struct mount *, char *, caddr_t, struct thread *);
a6ee311a
RG
105static int ntfs_init (struct vfsconf *);
106static int ntfs_checkexp (struct mount *, struct sockaddr *,
107 int *, struct ucred **);
984263bc 108#elif defined(__NetBSD__)
a6ee311a
RG
109static int ntfs_mount (struct mount *, const char *, void *,
110 struct nameidata *, struct thread *);
111static void ntfs_init (void);
112static int ntfs_mountroot (void);
113static int ntfs_sysctl (int *, u_int, void *, size_t *, void *,
114 size_t, struct thread *);
115static int ntfs_checkexp (struct mount *, struct mbuf *,
116 int *, struct ucred **);
984263bc
MD
117#endif
118
119/*
120 * Verify a remote client has export rights and return these rights via.
121 * exflagsp and credanonp.
122 */
123static int
cd0a65a2 124ntfs_checkexp(struct mount *mp,
08c23b99 125#if defined(__DragonFly__)
cd0a65a2 126 struct sockaddr *nam,
984263bc 127#else /* defined(__NetBSD__) */
cd0a65a2 128 struct mbuf *nam,
984263bc 129#endif
cd0a65a2 130 int *exflagsp, struct ucred **credanonp)
984263bc 131{
34ee9825
RG
132 struct netcred *np;
133 struct ntfsmount *ntm = VFSTONTFS(mp);
984263bc
MD
134
135 /*
136 * Get the export permission structure for this <mp, client> tuple.
137 */
138 np = vfs_export_lookup(mp, &ntm->ntm_export, nam);
139 if (np == NULL)
140 return (EACCES);
141
142 *exflagsp = np->netc_exflags;
143 *credanonp = &np->netc_anon;
144 return (0);
145}
146
147#if defined(__NetBSD__)
148/*ARGSUSED*/
149static int
cd0a65a2
CP
150ntfs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
151 size_t newlen, struct thread *td)
984263bc
MD
152{
153 return (EINVAL);
154}
155
156static int
cd0a65a2 157ntfs_mountroot(void)
984263bc
MD
158{
159 struct mount *mp;
21739618 160 struct vnode *rootvp;
dadab5e9 161 struct thread *td = curthread; /* XXX */
984263bc 162 struct ntfs_args args;
41a01a4d
MD
163 lwkt_tokref ilock;
164 int error;
984263bc
MD
165
166 if (root_device->dv_class != DV_DISK)
167 return (ENODEV);
168
169 /*
170 * Get vnodes for rootdev.
171 */
172 if (bdevvp(rootdev, &rootvp))
173 panic("ntfs_mountroot: can't setup rootvp");
174
175 if ((error = vfs_rootmountalloc(MOUNT_NTFS, "root_device", &mp))) {
176 vrele(rootvp);
177 return (error);
178 }
179
180 args.flag = 0;
181 args.uid = 0;
182 args.gid = 0;
183 args.mode = 0777;
184
dadab5e9 185 if ((error = ntfs_mountfs(rootvp, mp, &args, td)) != 0) {
984263bc
MD
186 mp->mnt_op->vfs_refcount--;
187 vfs_unbusy(mp);
188 free(mp, M_MOUNT);
189 vrele(rootvp);
190 return (error);
191 }
861905fb 192 mountlist_insert(mp, MNTINS_LAST);
dadab5e9 193 (void)ntfs_statfs(mp, &mp->mnt_stat, td);
984263bc
MD
194 vfs_unbusy(mp);
195 return (0);
196}
197
198static void
cd0a65a2 199ntfs_init(void)
984263bc
MD
200{
201 ntfs_nthashinit();
202 ntfs_toupper_init();
203}
204
08c23b99 205#elif defined(__DragonFly__)
984263bc
MD
206
207static int
cd0a65a2 208ntfs_init(struct vfsconf *vcp)
984263bc
MD
209{
210 ntfs_nthashinit();
211 ntfs_toupper_init();
212 return 0;
213}
214
215#endif /* NetBSD */
216
217static int
cd0a65a2 218ntfs_mount(struct mount *mp,
08c23b99 219#if defined(__DragonFly__)
cd0a65a2 220 char *path, caddr_t data,
984263bc 221#else
cd0a65a2 222 const char *path, void *data,
984263bc 223#endif
21739618 224 struct thread *td)
cd0a65a2 225{
984263bc 226 size_t size;
fad57d0e 227 int error;
984263bc
MD
228 struct vnode *devvp;
229 struct ntfs_args args;
fad57d0e 230 struct nlookupdata nd;
21739618 231 struct vnode *rootvp;
984263bc 232
fad57d0e 233 error = 0;
08c23b99 234#ifdef __DragonFly__
984263bc
MD
235 /*
236 * Use NULL path to flag a root mount
237 */
238 if( path == NULL) {
239 /*
240 ***
241 * Mounting root file system
242 ***
243 */
244
245 /* Get vnode for root device*/
246 if( bdevvp( rootdev, &rootvp))
247 panic("ffs_mountroot: can't setup bdevvp for root");
248
249 /*
250 * FS specific handling
251 */
252 mp->mnt_flag |= MNT_RDONLY; /* XXX globally applicable?*/
253
254 /*
255 * Attempt mount
256 */
fad57d0e 257 if( ( error = ntfs_mountfs(rootvp, mp, &args, td)) != 0) {
984263bc
MD
258 /* fs specific cleanup (if any)*/
259 goto error_1;
260 }
261
262 goto dostatfs; /* success*/
263
264 }
265#endif /* FreeBSD */
266
267 /*
268 ***
269 * Mounting non-root file system or updating a file system
270 ***
271 */
272
273 /* copy in user arguments*/
fad57d0e
MD
274 error = copyin(data, (caddr_t)&args, sizeof (struct ntfs_args));
275 if (error)
984263bc
MD
276 goto error_1; /* can't get arguments*/
277
278 /*
279 * If updating, check whether changing from read-only to
280 * read/write; if there is no device name, that's all we do.
281 */
282 if (mp->mnt_flag & MNT_UPDATE) {
283 /* if not updating name...*/
284 if (args.fspec == 0) {
285 /*
286 * Process export requests. Jumping to "success"
287 * will return the vfs_export() error code.
288 */
289 struct ntfsmount *ntm = VFSTONTFS(mp);
fad57d0e 290 error = vfs_export(mp, &ntm->ntm_export, &args.export);
984263bc
MD
291 goto success;
292 }
293
294 printf("ntfs_mount(): MNT_UPDATE not supported\n");
fad57d0e 295 error = EINVAL;
984263bc
MD
296 goto error_1;
297 }
298
299 /*
300 * Not an update, or updating the name: look up the name
301 * and verify that it refers to a sensible block device.
302 */
fad57d0e
MD
303 devvp = NULL;
304 error = nlookup_init(&nd, args.fspec, UIO_USERSPACE, NLC_FOLLOW);
305 if (error == 0)
306 error = nlookup(&nd);
307 if (error == 0)
308 error = cache_vref(nd.nl_ncp, nd.nl_cred, &devvp);
309 nlookup_done(&nd);
310 if (error)
984263bc 311 goto error_1;
984263bc 312
08c23b99 313#if defined(__DragonFly__)
fad57d0e 314 if (!vn_isdisk(devvp, &error))
984263bc
MD
315 goto error_2;
316#else
317 if (devvp->v_type != VBLK) {
fad57d0e 318 error = ENOTBLK;
984263bc
MD
319 goto error_2;
320 }
e4c9c0c8 321 if (umajor(devvp->v_udev) >= nblkdev) {
fad57d0e 322 error = ENXIO;
984263bc
MD
323 goto error_2;
324 }
325#endif
326 if (mp->mnt_flag & MNT_UPDATE) {
327#if 0
328 /*
329 ********************
330 * UPDATE
331 ********************
332 */
333
334 if (devvp != ntmp->um_devvp)
fad57d0e 335 error = EINVAL; /* needs translation */
984263bc
MD
336 else
337 vrele(devvp);
338 /*
339 * Update device name only on success
340 */
fad57d0e 341 if( !error) {
984263bc
MD
342 /* Save "mounted from" info for mount point (NULL pad)*/
343 copyinstr( args.fspec,
344 mp->mnt_stat.f_mntfromname,
345 MNAMELEN - 1,
346 &size);
347 bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
348 }
349#endif
350 } else {
351 /*
352 ********************
353 * NEW MOUNT
354 ********************
355 */
356
984263bc
MD
357 /* Save "mounted from" info for mount point (NULL pad)*/
358 copyinstr( args.fspec, /* device name*/
359 mp->mnt_stat.f_mntfromname, /* save area*/
360 MNAMELEN - 1, /* max size*/
361 &size); /* real size*/
362 bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
363
fad57d0e 364 error = ntfs_mountfs(devvp, mp, &args, td);
984263bc 365 }
fad57d0e 366 if (error) {
984263bc
MD
367 goto error_2;
368 }
369
08c23b99 370#ifdef __DragonFly__
984263bc
MD
371dostatfs:
372#endif
373 /*
75ffff0d
JS
374 * Initialize FS stat information in mount struct; uses
375 * mp->mnt_stat.f_mntfromname.
984263bc
MD
376 *
377 * This code is common to root and non-root mounts
378 */
dadab5e9 379 (void)VFS_STATFS(mp, &mp->mnt_stat, td);
984263bc
MD
380
381 goto success;
382
383
384error_2: /* error with devvp held*/
385
386 /* release devvp before failing*/
387 vrele(devvp);
388
389error_1: /* no state to back out*/
390
391success:
fad57d0e 392 return(error);
984263bc
MD
393}
394
395/*
396 * Common code for mount and mountroot
397 */
398int
cd0a65a2
CP
399ntfs_mountfs(struct vnode *devvp, struct mount *mp, struct ntfs_args *argsp,
400 struct thread *td)
984263bc
MD
401{
402 struct buf *bp;
403 struct ntfsmount *ntmp;
e4c9c0c8 404 dev_t dev;
984263bc
MD
405 int error, ronly, ncount, i;
406 struct vnode *vp;
dadab5e9
MD
407 struct ucred *cred;
408
409 KKASSERT(td->td_proc);
410 cred = td->td_proc->p_ucred;
984263bc
MD
411
412 /*
413 * Disallow multiple mounts of the same device.
414 * Disallow mounting of a device that is currently in use
415 * (except for root, which might share swap device for miniroot).
416 * Flush out any old buffers remaining from a previous use.
417 */
418 error = vfs_mountedon(devvp);
419 if (error)
420 return (error);
715f92b6 421 ncount = count_udev(devvp->v_udev);
08c23b99 422#if defined(__DragonFly__)
984263bc
MD
423 if (devvp->v_object)
424 ncount -= 1;
425#endif
21739618 426 if (ncount > 1)
984263bc 427 return (EBUSY);
08c23b99 428#if defined(__DragonFly__)
dadab5e9 429 VN_LOCK(devvp, LK_EXCLUSIVE | LK_RETRY, td);
3b568787 430 error = vinvalbuf(devvp, V_SAVE, td, 0, 0);
dadab5e9 431 VOP__UNLOCK(devvp, 0, td);
984263bc 432#else
3b568787 433 error = vinvalbuf(devvp, V_SAVE, td, 0, 0);
984263bc
MD
434#endif
435 if (error)
436 return (error);
437
438 ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
dadab5e9 439 VN_LOCK(devvp, LK_EXCLUSIVE | LK_RETRY, td);
fad57d0e 440 error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, NULL, td);
dadab5e9 441 VOP__UNLOCK(devvp, 0, td);
984263bc
MD
442 if (error)
443 return (error);
e4c9c0c8 444 dev = devvp->v_rdev;
984263bc
MD
445
446 bp = NULL;
447
3b568787 448 error = bread(devvp, BBLOCK, BBSIZE, &bp);
984263bc
MD
449 if (error)
450 goto out;
451 ntmp = malloc( sizeof *ntmp, M_NTFSMNT, M_WAITOK );
452 bzero( ntmp, sizeof *ntmp );
453 bcopy( bp->b_data, &ntmp->ntm_bootfile, sizeof(struct bootfile) );
454 brelse( bp );
455 bp = NULL;
456
457 if (strncmp(ntmp->ntm_bootfile.bf_sysid, NTFS_BBID, NTFS_BBIDLEN)) {
458 error = EINVAL;
459 dprintf(("ntfs_mountfs: invalid boot block\n"));
460 goto out;
461 }
462
463 {
464 int8_t cpr = ntmp->ntm_mftrecsz;
465 if( cpr > 0 )
466 ntmp->ntm_bpmftrec = ntmp->ntm_spc * cpr;
467 else
468 ntmp->ntm_bpmftrec = (1 << (-cpr)) / ntmp->ntm_bps;
469 }
470 dprintf(("ntfs_mountfs(): bps: %d, spc: %d, media: %x, mftrecsz: %d (%d sects)\n",
471 ntmp->ntm_bps,ntmp->ntm_spc,ntmp->ntm_bootfile.bf_media,
472 ntmp->ntm_mftrecsz,ntmp->ntm_bpmftrec));
473 dprintf(("ntfs_mountfs(): mftcn: 0x%x|0x%x\n",
474 (u_int32_t)ntmp->ntm_mftcn,(u_int32_t)ntmp->ntm_mftmirrcn));
475
476 ntmp->ntm_mountp = mp;
477 ntmp->ntm_dev = dev;
478 ntmp->ntm_devvp = devvp;
479 ntmp->ntm_uid = argsp->uid;
480 ntmp->ntm_gid = argsp->gid;
481 ntmp->ntm_mode = argsp->mode;
482 ntmp->ntm_flag = argsp->flag;
483
484 /* Copy in the 8-bit to Unicode conversion table */
485 if (argsp->flag & NTFSMNT_U2WTABLE) {
486 ntfs_82u_init(ntmp, argsp->u2w);
487 } else {
488 ntfs_82u_init(ntmp, NULL);
489 }
490
491 /* Initialize Unicode to 8-bit table from 8toU table */
492 ntfs_u28_init(ntmp, ntmp->ntm_82u);
493
494 mp->mnt_data = (qaddr_t)ntmp;
495
496 dprintf(("ntfs_mountfs(): case-%s,%s uid: %d, gid: %d, mode: %o\n",
497 (ntmp->ntm_flag & NTFS_MFLAG_CASEINS)?"insens.":"sens.",
498 (ntmp->ntm_flag & NTFS_MFLAG_ALLNAMES)?" allnames,":"",
499 ntmp->ntm_uid, ntmp->ntm_gid, ntmp->ntm_mode));
500
dc1be39c
MD
501 vfs_add_vnodeops(mp, &mp->mnt_vn_norm_ops,
502 ntfs_vnodeop_entries, 0);
320bc044 503
984263bc
MD
504 /*
505 * We read in some system nodes to do not allow
506 * reclaim them and to have everytime access to them.
507 */
508 {
509 int pi[3] = { NTFS_MFTINO, NTFS_ROOTINO, NTFS_BITMAPINO };
510 for (i=0; i<3; i++) {
511 error = VFS_VGET(mp, pi[i], &(ntmp->ntm_sysvn[pi[i]]));
512 if(error)
513 goto out1;
514 ntmp->ntm_sysvn[pi[i]]->v_flag |= VSYSTEM;
597aea93 515 vref(ntmp->ntm_sysvn[pi[i]]);
984263bc
MD
516 vput(ntmp->ntm_sysvn[pi[i]]);
517 }
518 }
519
520 /* read the Unicode lowercase --> uppercase translation table,
521 * if necessary */
522 if ((error = ntfs_toupper_use(mp, ntmp)))
523 goto out1;
524
525 /*
526 * Scan $BitMap and count free clusters
527 */
528 error = ntfs_calccfree(ntmp, &ntmp->ntm_cfree);
529 if(error)
530 goto out1;
531
532 /*
533 * Read and translate to internal format attribute
534 * definition file.
535 */
536 {
537 int num,j;
538 struct attrdef ad;
539
540 /* Open $AttrDef */
541 error = VFS_VGET(mp, NTFS_ATTRDEFINO, &vp );
542 if(error)
543 goto out1;
544
545 /* Count valid entries */
546 for(num=0;;num++) {
547 error = ntfs_readattr(ntmp, VTONT(vp),
548 NTFS_A_DATA, NULL,
549 num * sizeof(ad), sizeof(ad),
550 &ad, NULL);
551 if (error)
552 goto out1;
553 if (ad.ad_name[0] == 0)
554 break;
555 }
556
557 /* Alloc memory for attribute definitions */
558 MALLOC(ntmp->ntm_ad, struct ntvattrdef *,
559 num * sizeof(struct ntvattrdef),
560 M_NTFSMNT, M_WAITOK);
561
562 ntmp->ntm_adnum = num;
563
564 /* Read them and translate */
565 for(i=0;i<num;i++){
566 error = ntfs_readattr(ntmp, VTONT(vp),
567 NTFS_A_DATA, NULL,
568 i * sizeof(ad), sizeof(ad),
569 &ad, NULL);
570 if (error)
571 goto out1;
572 j = 0;
573 do {
574 ntmp->ntm_ad[i].ad_name[j] = ad.ad_name[j];
575 } while(ad.ad_name[j++]);
576 ntmp->ntm_ad[i].ad_namelen = j - 1;
577 ntmp->ntm_ad[i].ad_type = ad.ad_type;
578 }
579
580 vput(vp);
581 }
582
08c23b99 583#if defined(__DragonFly__)
984263bc
MD
584 mp->mnt_stat.f_fsid.val[0] = dev2udev(dev);
585 mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
586#else
587 mp->mnt_stat.f_fsid.val[0] = dev;
588 mp->mnt_stat.f_fsid.val[1] = makefstype(MOUNT_NTFS);
589#endif
590 mp->mnt_maxsymlinklen = 0;
591 mp->mnt_flag |= MNT_LOCAL;
e4c9c0c8 592 dev->si_mountpoint = mp;
0961aa92 593
984263bc
MD
594 return (0);
595
596out1:
597 for(i=0;i<NTFS_SYSNODESNUM;i++)
598 if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]);
599
600 if (vflush(mp, 0, 0))
601 dprintf(("ntfs_mountfs: vflush failed\n"));
602
603out:
e4c9c0c8 604 dev->si_mountpoint = NULL;
984263bc
MD
605 if (bp)
606 brelse(bp);
607
608#if defined __NetBSD__
609 /* lock the device vnode before calling VOP_CLOSE() */
dadab5e9 610 VN_LOCK(devvp, LK_EXCLUSIVE | LK_RETRY, td);
3b568787 611 (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, td);
dadab5e9 612 VOP__UNLOCK(devvp, 0, td);
984263bc 613#else
3b568787 614 (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, td);
984263bc
MD
615#endif
616
617 return (error);
618}
619
08c23b99 620#if !defined(__DragonFly__)
984263bc 621static int
cd0a65a2 622ntfs_start(struct mount *mp, int flags, struct thread *td)
984263bc
MD
623{
624 return (0);
625}
626#endif
627
628static int
cd0a65a2 629ntfs_unmount(struct mount *mp, int mntflags, struct thread *td)
984263bc 630{
34ee9825 631 struct ntfsmount *ntmp;
984263bc
MD
632 int error, ronly = 0, flags, i;
633
634 dprintf(("ntfs_unmount: unmounting...\n"));
635 ntmp = VFSTONTFS(mp);
636
637 flags = 0;
638 if(mntflags & MNT_FORCE)
639 flags |= FORCECLOSE;
640
641 dprintf(("ntfs_unmount: vflushing...\n"));
642 error = vflush(mp, 0, flags | SKIPSYSTEM);
643 if (error) {
644 printf("ntfs_unmount: vflush failed: %d\n",error);
645 return (error);
646 }
647
648 /* Check if only system vnodes are rest */
649 for(i=0;i<NTFS_SYSNODESNUM;i++)
650 if((ntmp->ntm_sysvn[i]) &&
651 (ntmp->ntm_sysvn[i]->v_usecount > 1)) return (EBUSY);
652
653 /* Dereference all system vnodes */
654 for(i=0;i<NTFS_SYSNODESNUM;i++)
655 if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]);
656
657 /* vflush system vnodes */
658 error = vflush(mp, 0, flags);
659 if (error)
660 printf("ntfs_unmount: vflush failed(sysnodes): %d\n",error);
661
662 /* Check if the type of device node isn't VBAD before
663 * touching v_specinfo. If the device vnode is revoked, the
664 * field is NULL and touching it causes null pointer derefercence.
665 */
666 if (ntmp->ntm_devvp->v_type != VBAD)
e4c9c0c8 667 ntmp->ntm_devvp->v_rdev->si_mountpoint = NULL;
984263bc 668
3b568787 669 vinvalbuf(ntmp->ntm_devvp, V_SAVE, td, 0, 0);
984263bc
MD
670
671#if defined(__NetBSD__)
672 /* lock the device vnode before calling VOP_CLOSE() */
673 VOP_LOCK(ntmp->ntm_devvp, LK_EXCLUSIVE | LK_RETRY);
3b568787 674 error = VOP_CLOSE(ntmp->ntm_devvp, ronly ? FREAD : FREAD|FWRITE, td);
dadab5e9 675 VOP__UNLOCK(ntmp->ntm_devvp, 0, td);
984263bc 676#else
3b568787 677 error = VOP_CLOSE(ntmp->ntm_devvp, ronly ? FREAD : FREAD|FWRITE, td);
984263bc
MD
678#endif
679
680 vrele(ntmp->ntm_devvp);
681
682 /* free the toupper table, if this has been last mounted ntfs volume */
683 ntfs_toupper_unuse();
684
685 dprintf(("ntfs_umount: freeing memory...\n"));
686 ntfs_u28_uninit(ntmp);
687 ntfs_82u_uninit(ntmp);
688 mp->mnt_data = (qaddr_t)0;
689 mp->mnt_flag &= ~MNT_LOCAL;
690 FREE(ntmp->ntm_ad, M_NTFSMNT);
691 FREE(ntmp, M_NTFSMNT);
692 return (error);
693}
694
695static int
cd0a65a2 696ntfs_root(struct mount *mp, struct vnode **vpp)
984263bc
MD
697{
698 struct vnode *nvp;
699 int error = 0;
700
701 dprintf(("ntfs_root(): sysvn: %p\n",
702 VFSTONTFS(mp)->ntm_sysvn[NTFS_ROOTINO]));
703 error = VFS_VGET(mp, (ino_t)NTFS_ROOTINO, &nvp);
704 if(error) {
705 printf("ntfs_root: VFS_VGET failed: %d\n",error);
706 return (error);
707 }
708
709 *vpp = nvp;
710 return (0);
711}
712
08c23b99 713#if !defined(__DragonFly__)
984263bc 714static int
cd0a65a2
CP
715ntfs_quotactl(struct mount *mp, int cmds, uid_t uid, caddr_t arg,
716 struct thread *td)
984263bc
MD
717{
718 printf("\nntfs_quotactl():\n");
719 return EOPNOTSUPP;
720}
721#endif
722
723int
cd0a65a2 724ntfs_calccfree(struct ntfsmount *ntmp, cn_t *cfreep)
984263bc
MD
725{
726 struct vnode *vp;
727 u_int8_t *tmp;
728 int j, error;
729 long cfree = 0;
730 size_t bmsize, i;
731
732 vp = ntmp->ntm_sysvn[NTFS_BITMAPINO];
733
734 bmsize = VTOF(vp)->f_size;
735
736 MALLOC(tmp, u_int8_t *, bmsize, M_TEMP, M_WAITOK);
737
738 error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL,
739 0, bmsize, tmp, NULL);
740 if (error)
741 goto out;
742
743 for(i=0;i<bmsize;i++)
744 for(j=0;j<8;j++)
745 if(~tmp[i] & (1 << j)) cfree++;
746 *cfreep = cfree;
747
748 out:
749 FREE(tmp, M_TEMP);
750 return(error);
751}
752
753static int
cd0a65a2 754ntfs_statfs(struct mount *mp, struct statfs *sbp, struct thread *td)
984263bc
MD
755{
756 struct ntfsmount *ntmp = VFSTONTFS(mp);
757 u_int64_t mftsize,mftallocated;
758
759 dprintf(("ntfs_statfs():\n"));
760
761 mftsize = VTOF(ntmp->ntm_sysvn[NTFS_MFTINO])->f_size;
762 mftallocated = VTOF(ntmp->ntm_sysvn[NTFS_MFTINO])->f_allocated;
763
08c23b99 764#if defined(__DragonFly__)
984263bc
MD
765 sbp->f_type = mp->mnt_vfc->vfc_typenum;
766#elif defined(__NetBSD__)
767 sbp->f_type = 0;
768#else
769 sbp->f_type = MOUNT_NTFS;
770#endif
771 sbp->f_bsize = ntmp->ntm_bps;
772 sbp->f_iosize = ntmp->ntm_bps * ntmp->ntm_spc;
773 sbp->f_blocks = ntmp->ntm_bootfile.bf_spv;
774 sbp->f_bfree = sbp->f_bavail = ntfs_cntobn(ntmp->ntm_cfree);
775 sbp->f_ffree = sbp->f_bfree / ntmp->ntm_bpmftrec;
776 sbp->f_files = mftallocated / ntfs_bntob(ntmp->ntm_bpmftrec) +
777 sbp->f_ffree;
778 if (sbp != &mp->mnt_stat) {
984263bc
MD
779 bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
780 (caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
781 }
782 sbp->f_flags = mp->mnt_flag;
783#ifdef __NetBSD__
784 strncpy(sbp->f_fstypename, mp->mnt_op->vfs_name, MFSNAMELEN);
785#endif
786
787 return (0);
788}
789
08c23b99 790#if !defined(__DragonFly__)
984263bc 791static int
cd0a65a2 792ntfs_sync(struct mount *mp, int waitfor, struct ucred *cred, struct thread *td)
984263bc
MD
793{
794 /*dprintf(("ntfs_sync():\n"));*/
795 return (0);
796}
797#endif
798
799/*ARGSUSED*/
800static int
cd0a65a2 801ntfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
984263bc
MD
802{
803 struct vnode *nvp;
804 struct ntfid *ntfhp = (struct ntfid *)fhp;
805 int error;
806
807 ddprintf(("ntfs_fhtovp(): %d\n", ntfhp->ntfid_ino));
808
809 if ((error = VFS_VGET(mp, ntfhp->ntfid_ino, &nvp)) != 0) {
810 *vpp = NULLVP;
811 return (error);
812 }
813 /* XXX as unlink/rmdir/mkdir/creat are not currently possible
814 * with NTFS, we don't need to check anything else for now */
815 *vpp = nvp;
816
817 return (0);
818}
819
820static int
cd0a65a2 821ntfs_vptofh(struct vnode *vp, struct fid *fhp)
984263bc 822{
34ee9825
RG
823 struct ntnode *ntp;
824 struct ntfid *ntfhp;
984263bc
MD
825
826 ddprintf(("ntfs_fhtovp(): %p\n", vp));
827
828 ntp = VTONT(vp);
829 ntfhp = (struct ntfid *)fhp;
830 ntfhp->ntfid_len = sizeof(struct ntfid);
831 ntfhp->ntfid_ino = ntp->i_number;
832 /* ntfhp->ntfid_gen = ntp->i_gen; */
833 return (0);
834}
835
836int
cd0a65a2
CP
837ntfs_vgetex(struct mount *mp, ino_t ino, u_int32_t attrtype, char *attrname,
838 u_long lkflags, u_long flags, struct thread *td,
839 struct vnode **vpp)
984263bc
MD
840{
841 int error;
34ee9825 842 struct ntfsmount *ntmp;
984263bc
MD
843 struct ntnode *ip;
844 struct fnode *fp;
845 struct vnode *vp;
846 enum vtype f_type;
847
848 dprintf(("ntfs_vgetex: ino: %d, attr: 0x%x:%s, lkf: 0x%lx, f: 0x%lx\n",
849 ino, attrtype, attrname?attrname:"", (u_long)lkflags,
850 (u_long)flags ));
851
852 ntmp = VFSTONTFS(mp);
853 *vpp = NULL;
854
855 /* Get ntnode */
856 error = ntfs_ntlookup(ntmp, ino, &ip);
857 if (error) {
858 printf("ntfs_vget: ntfs_ntget failed\n");
859 return (error);
860 }
861
862 /* It may be not initialized fully, so force load it */
863 if (!(flags & VG_DONTLOADIN) && !(ip->i_flag & IN_LOADED)) {
864 error = ntfs_loadntnode(ntmp, ip);
865 if(error) {
f91a71dd 866 printf("ntfs_vget: CAN'T LOAD ATTRIBUTES FOR INO: %"PRId64"\n",
984263bc
MD
867 ip->i_number);
868 ntfs_ntput(ip);
869 return (error);
870 }
871 }
872
873 error = ntfs_fget(ntmp, ip, attrtype, attrname, &fp);
874 if (error) {
875 printf("ntfs_vget: ntfs_fget failed\n");
876 ntfs_ntput(ip);
877 return (error);
878 }
879
880 f_type = VNON;
881 if (!(flags & VG_DONTVALIDFN) && !(fp->f_flag & FN_VALID)) {
882 if ((ip->i_frflag & NTFS_FRFLAG_DIR) &&
883 (fp->f_attrtype == NTFS_A_DATA && fp->f_attrname == NULL)) {
884 f_type = VDIR;
885 } else if (flags & VG_EXT) {
886 f_type = VNON;
887 fp->f_size = fp->f_allocated = 0;
888 } else {
889 f_type = VREG;
890
891 error = ntfs_filesize(ntmp, fp,
892 &fp->f_size, &fp->f_allocated);
893 if (error) {
894 ntfs_ntput(ip);
895 return (error);
896 }
897 }
898
899 fp->f_flag |= FN_VALID;
900 }
901
902 if (FTOV(fp)) {
dadab5e9 903 VGET(FTOV(fp), lkflags, td);
984263bc
MD
904 *vpp = FTOV(fp);
905 ntfs_ntput(ip);
906 return (0);
907 }
908
6ddb7618 909 error = getnewvnode(VT_NTFS, ntmp->ntm_mountp, &vp, VLKTIMEOUT, 0);
984263bc
MD
910 if(error) {
911 ntfs_frele(fp);
912 ntfs_ntput(ip);
913 return (error);
914 }
915 dprintf(("ntfs_vget: vnode: %p for ntnode: %d\n", vp,ino));
916
984263bc
MD
917 fp->f_vp = vp;
918 vp->v_data = fp;
919 vp->v_type = f_type;
920
921 if (ino == NTFS_ROOTINO)
922 vp->v_flag |= VROOT;
923
924 ntfs_ntput(ip);
925
5fd012e0
MD
926 KKASSERT(lkflags & LK_TYPE_MASK);
927 KKASSERT((lkflags & LK_INTERLOCK) == 0);
928 /* XXX leave vnode locked exclusively from getnewvnode */
984263bc
MD
929 *vpp = vp;
930 return (0);
931
932}
933
934static int
cd0a65a2 935ntfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
984263bc
MD
936{
937 return ntfs_vgetex(mp, ino, NTFS_A_DATA, NULL,
dadab5e9 938 LK_EXCLUSIVE | LK_RETRY, 0, curthread, vpp);
984263bc
MD
939}
940
08c23b99 941#if defined(__DragonFly__)
984263bc 942static struct vfsops ntfs_vfsops = {
43c45e8f
HP
943 .vfs_mount = ntfs_mount,
944 .vfs_unmount = ntfs_unmount,
945 .vfs_root = ntfs_root,
946 .vfs_statfs = ntfs_statfs,
947 .vfs_sync = vfs_stdsync,
948 .vfs_vget = ntfs_vget,
949 .vfs_fhtovp = ntfs_fhtovp,
950 .vfs_checkexp = ntfs_checkexp,
951 .vfs_vptofh = ntfs_vptofh,
952 .vfs_init = ntfs_init,
953 .vfs_uninit = ntfs_nthash_uninit /* see ntfs_ihash.c */
984263bc
MD
954};
955VFS_SET(ntfs_vfsops, ntfs, 0);
956#elif defined(__NetBSD__)
957extern struct vnodeopv_desc ntfs_vnodeop_opv_desc;
958
959struct vnodeopv_desc *ntfs_vnodeopv_descs[] = {
960 &ntfs_vnodeop_opv_desc,
961 NULL,
962};
963
964struct vfsops ntfs_vfsops = {
965 MOUNT_NTFS,
966 ntfs_mount,
967 ntfs_start,
968 ntfs_unmount,
969 ntfs_root,
970 ntfs_quotactl,
971 ntfs_statfs,
972 ntfs_sync,
973 ntfs_vget,
974 ntfs_fhtovp,
975 ntfs_vptofh,
976 ntfs_init,
977 ntfs_sysctl,
978 ntfs_mountroot,
979 ntfs_checkexp,
980 ntfs_vnodeopv_descs,
981};
982#else /* !NetBSD && !FreeBSD */
983static struct vfsops ntfs_vfsops = {
984 ntfs_mount,
985 ntfs_start,
986 ntfs_unmount,
987 ntfs_root,
988 ntfs_quotactl,
989 ntfs_statfs,
990 ntfs_sync,
991 ntfs_vget,
992 ntfs_fhtovp,
993 ntfs_vptofh,
994 ntfs_init,
995};
996VFS_SET(ntfs_vfsops, ntfs, MOUNT_NTFS, 0);
997#endif
998
999