Fix .Os and a .Xr. Expand HISTORY a bit.
[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 $
87de5057 29 * $DragonFly: src/sys/vfs/ntfs/ntfs_vfsops.c,v 1.36 2006/05/06 02:43:14 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);
87de5057 430 error = vinvalbuf(devvp, V_SAVE, 0, 0);
dadab5e9 431 VOP__UNLOCK(devvp, 0, td);
984263bc 432#else
87de5057 433 error = vinvalbuf(devvp, V_SAVE, 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);
87de5057 440 error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, NULL);
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
54078292 448 error = bread(devvp, ntfs_bntodoff(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);
87de5057 611 (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE);
dadab5e9 612 VOP__UNLOCK(devvp, 0, td);
984263bc 613#else
87de5057 614 (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE);
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;
fb8c9c01 632 int error, ronly, flags, i;
984263bc
MD
633
634 dprintf(("ntfs_unmount: unmounting...\n"));
635 ntmp = VFSTONTFS(mp);
636
fb8c9c01 637 ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
984263bc
MD
638 flags = 0;
639 if(mntflags & MNT_FORCE)
640 flags |= FORCECLOSE;
641
642 dprintf(("ntfs_unmount: vflushing...\n"));
643 error = vflush(mp, 0, flags | SKIPSYSTEM);
644 if (error) {
645 printf("ntfs_unmount: vflush failed: %d\n",error);
646 return (error);
647 }
648
649 /* Check if only system vnodes are rest */
650 for(i=0;i<NTFS_SYSNODESNUM;i++)
651 if((ntmp->ntm_sysvn[i]) &&
652 (ntmp->ntm_sysvn[i]->v_usecount > 1)) return (EBUSY);
653
654 /* Dereference all system vnodes */
655 for(i=0;i<NTFS_SYSNODESNUM;i++)
656 if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]);
657
658 /* vflush system vnodes */
659 error = vflush(mp, 0, flags);
660 if (error)
661 printf("ntfs_unmount: vflush failed(sysnodes): %d\n",error);
662
663 /* Check if the type of device node isn't VBAD before
664 * touching v_specinfo. If the device vnode is revoked, the
665 * field is NULL and touching it causes null pointer derefercence.
666 */
667 if (ntmp->ntm_devvp->v_type != VBAD)
e4c9c0c8 668 ntmp->ntm_devvp->v_rdev->si_mountpoint = NULL;
984263bc 669
87de5057 670 vinvalbuf(ntmp->ntm_devvp, V_SAVE, 0, 0);
984263bc
MD
671
672#if defined(__NetBSD__)
673 /* lock the device vnode before calling VOP_CLOSE() */
674 VOP_LOCK(ntmp->ntm_devvp, LK_EXCLUSIVE | LK_RETRY);
87de5057 675 error = VOP_CLOSE(ntmp->ntm_devvp, ronly ? FREAD : FREAD|FWRITE);
dadab5e9 676 VOP__UNLOCK(ntmp->ntm_devvp, 0, td);
984263bc 677#else
87de5057 678 error = VOP_CLOSE(ntmp->ntm_devvp, ronly ? FREAD : FREAD|FWRITE);
984263bc
MD
679#endif
680
681 vrele(ntmp->ntm_devvp);
682
683 /* free the toupper table, if this has been last mounted ntfs volume */
684 ntfs_toupper_unuse();
685
686 dprintf(("ntfs_umount: freeing memory...\n"));
687 ntfs_u28_uninit(ntmp);
688 ntfs_82u_uninit(ntmp);
689 mp->mnt_data = (qaddr_t)0;
690 mp->mnt_flag &= ~MNT_LOCAL;
691 FREE(ntmp->ntm_ad, M_NTFSMNT);
692 FREE(ntmp, M_NTFSMNT);
693 return (error);
694}
695
696static int
cd0a65a2 697ntfs_root(struct mount *mp, struct vnode **vpp)
984263bc
MD
698{
699 struct vnode *nvp;
700 int error = 0;
701
702 dprintf(("ntfs_root(): sysvn: %p\n",
703 VFSTONTFS(mp)->ntm_sysvn[NTFS_ROOTINO]));
704 error = VFS_VGET(mp, (ino_t)NTFS_ROOTINO, &nvp);
705 if(error) {
706 printf("ntfs_root: VFS_VGET failed: %d\n",error);
707 return (error);
708 }
709
710 *vpp = nvp;
711 return (0);
712}
713
08c23b99 714#if !defined(__DragonFly__)
984263bc 715static int
cd0a65a2
CP
716ntfs_quotactl(struct mount *mp, int cmds, uid_t uid, caddr_t arg,
717 struct thread *td)
984263bc
MD
718{
719 printf("\nntfs_quotactl():\n");
720 return EOPNOTSUPP;
721}
722#endif
723
724int
cd0a65a2 725ntfs_calccfree(struct ntfsmount *ntmp, cn_t *cfreep)
984263bc
MD
726{
727 struct vnode *vp;
728 u_int8_t *tmp;
729 int j, error;
730 long cfree = 0;
731 size_t bmsize, i;
732
733 vp = ntmp->ntm_sysvn[NTFS_BITMAPINO];
734
735 bmsize = VTOF(vp)->f_size;
736
737 MALLOC(tmp, u_int8_t *, bmsize, M_TEMP, M_WAITOK);
738
739 error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL,
740 0, bmsize, tmp, NULL);
741 if (error)
742 goto out;
743
744 for(i=0;i<bmsize;i++)
745 for(j=0;j<8;j++)
746 if(~tmp[i] & (1 << j)) cfree++;
747 *cfreep = cfree;
748
749 out:
750 FREE(tmp, M_TEMP);
751 return(error);
752}
753
754static int
cd0a65a2 755ntfs_statfs(struct mount *mp, struct statfs *sbp, struct thread *td)
984263bc
MD
756{
757 struct ntfsmount *ntmp = VFSTONTFS(mp);
758 u_int64_t mftsize,mftallocated;
759
760 dprintf(("ntfs_statfs():\n"));
761
762 mftsize = VTOF(ntmp->ntm_sysvn[NTFS_MFTINO])->f_size;
763 mftallocated = VTOF(ntmp->ntm_sysvn[NTFS_MFTINO])->f_allocated;
764
08c23b99 765#if defined(__DragonFly__)
984263bc
MD
766 sbp->f_type = mp->mnt_vfc->vfc_typenum;
767#elif defined(__NetBSD__)
768 sbp->f_type = 0;
769#else
770 sbp->f_type = MOUNT_NTFS;
771#endif
772 sbp->f_bsize = ntmp->ntm_bps;
773 sbp->f_iosize = ntmp->ntm_bps * ntmp->ntm_spc;
774 sbp->f_blocks = ntmp->ntm_bootfile.bf_spv;
775 sbp->f_bfree = sbp->f_bavail = ntfs_cntobn(ntmp->ntm_cfree);
776 sbp->f_ffree = sbp->f_bfree / ntmp->ntm_bpmftrec;
777 sbp->f_files = mftallocated / ntfs_bntob(ntmp->ntm_bpmftrec) +
778 sbp->f_ffree;
779 if (sbp != &mp->mnt_stat) {
984263bc
MD
780 bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
781 (caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
782 }
783 sbp->f_flags = mp->mnt_flag;
784#ifdef __NetBSD__
785 strncpy(sbp->f_fstypename, mp->mnt_op->vfs_name, MFSNAMELEN);
786#endif
787
788 return (0);
789}
790
08c23b99 791#if !defined(__DragonFly__)
984263bc 792static int
cd0a65a2 793ntfs_sync(struct mount *mp, int waitfor, struct ucred *cred, struct thread *td)
984263bc
MD
794{
795 /*dprintf(("ntfs_sync():\n"));*/
796 return (0);
797}
798#endif
799
800/*ARGSUSED*/
801static int
cd0a65a2 802ntfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
984263bc
MD
803{
804 struct vnode *nvp;
805 struct ntfid *ntfhp = (struct ntfid *)fhp;
806 int error;
807
808 ddprintf(("ntfs_fhtovp(): %d\n", ntfhp->ntfid_ino));
809
810 if ((error = VFS_VGET(mp, ntfhp->ntfid_ino, &nvp)) != 0) {
811 *vpp = NULLVP;
812 return (error);
813 }
814 /* XXX as unlink/rmdir/mkdir/creat are not currently possible
815 * with NTFS, we don't need to check anything else for now */
816 *vpp = nvp;
817
818 return (0);
819}
820
821static int
cd0a65a2 822ntfs_vptofh(struct vnode *vp, struct fid *fhp)
984263bc 823{
34ee9825
RG
824 struct ntnode *ntp;
825 struct ntfid *ntfhp;
984263bc
MD
826
827 ddprintf(("ntfs_fhtovp(): %p\n", vp));
828
829 ntp = VTONT(vp);
830 ntfhp = (struct ntfid *)fhp;
831 ntfhp->ntfid_len = sizeof(struct ntfid);
832 ntfhp->ntfid_ino = ntp->i_number;
833 /* ntfhp->ntfid_gen = ntp->i_gen; */
834 return (0);
835}
836
837int
cd0a65a2
CP
838ntfs_vgetex(struct mount *mp, ino_t ino, u_int32_t attrtype, char *attrname,
839 u_long lkflags, u_long flags, struct thread *td,
840 struct vnode **vpp)
984263bc
MD
841{
842 int error;
34ee9825 843 struct ntfsmount *ntmp;
984263bc
MD
844 struct ntnode *ip;
845 struct fnode *fp;
846 struct vnode *vp;
847 enum vtype f_type;
848
849 dprintf(("ntfs_vgetex: ino: %d, attr: 0x%x:%s, lkf: 0x%lx, f: 0x%lx\n",
850 ino, attrtype, attrname?attrname:"", (u_long)lkflags,
851 (u_long)flags ));
852
853 ntmp = VFSTONTFS(mp);
854 *vpp = NULL;
855
856 /* Get ntnode */
857 error = ntfs_ntlookup(ntmp, ino, &ip);
858 if (error) {
859 printf("ntfs_vget: ntfs_ntget failed\n");
860 return (error);
861 }
862
863 /* It may be not initialized fully, so force load it */
864 if (!(flags & VG_DONTLOADIN) && !(ip->i_flag & IN_LOADED)) {
865 error = ntfs_loadntnode(ntmp, ip);
866 if(error) {
f91a71dd 867 printf("ntfs_vget: CAN'T LOAD ATTRIBUTES FOR INO: %"PRId64"\n",
984263bc
MD
868 ip->i_number);
869 ntfs_ntput(ip);
870 return (error);
871 }
872 }
873
874 error = ntfs_fget(ntmp, ip, attrtype, attrname, &fp);
875 if (error) {
876 printf("ntfs_vget: ntfs_fget failed\n");
877 ntfs_ntput(ip);
878 return (error);
879 }
880
881 f_type = VNON;
882 if (!(flags & VG_DONTVALIDFN) && !(fp->f_flag & FN_VALID)) {
883 if ((ip->i_frflag & NTFS_FRFLAG_DIR) &&
884 (fp->f_attrtype == NTFS_A_DATA && fp->f_attrname == NULL)) {
885 f_type = VDIR;
886 } else if (flags & VG_EXT) {
887 f_type = VNON;
888 fp->f_size = fp->f_allocated = 0;
889 } else {
890 f_type = VREG;
891
892 error = ntfs_filesize(ntmp, fp,
893 &fp->f_size, &fp->f_allocated);
894 if (error) {
895 ntfs_ntput(ip);
896 return (error);
897 }
898 }
899
900 fp->f_flag |= FN_VALID;
901 }
902
903 if (FTOV(fp)) {
dadab5e9 904 VGET(FTOV(fp), lkflags, td);
984263bc
MD
905 *vpp = FTOV(fp);
906 ntfs_ntput(ip);
907 return (0);
908 }
909
6ddb7618 910 error = getnewvnode(VT_NTFS, ntmp->ntm_mountp, &vp, VLKTIMEOUT, 0);
984263bc
MD
911 if(error) {
912 ntfs_frele(fp);
913 ntfs_ntput(ip);
914 return (error);
915 }
916 dprintf(("ntfs_vget: vnode: %p for ntnode: %d\n", vp,ino));
917
984263bc
MD
918 fp->f_vp = vp;
919 vp->v_data = fp;
920 vp->v_type = f_type;
921
922 if (ino == NTFS_ROOTINO)
923 vp->v_flag |= VROOT;
924
30365587
MD
925 /*
926 * Normal files use the buffer cache
927 */
928 if (f_type == VREG)
7d5a83ff 929 vinitvmio(vp, fp->f_size);
30365587 930
984263bc
MD
931 ntfs_ntput(ip);
932
5fd012e0 933 KKASSERT(lkflags & LK_TYPE_MASK);
5fd012e0 934 /* XXX leave vnode locked exclusively from getnewvnode */
984263bc
MD
935 *vpp = vp;
936 return (0);
937
938}
939
940static int
cd0a65a2 941ntfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
984263bc
MD
942{
943 return ntfs_vgetex(mp, ino, NTFS_A_DATA, NULL,
dadab5e9 944 LK_EXCLUSIVE | LK_RETRY, 0, curthread, vpp);
984263bc
MD
945}
946
08c23b99 947#if defined(__DragonFly__)
984263bc 948static struct vfsops ntfs_vfsops = {
43c45e8f
HP
949 .vfs_mount = ntfs_mount,
950 .vfs_unmount = ntfs_unmount,
951 .vfs_root = ntfs_root,
952 .vfs_statfs = ntfs_statfs,
953 .vfs_sync = vfs_stdsync,
954 .vfs_vget = ntfs_vget,
955 .vfs_fhtovp = ntfs_fhtovp,
956 .vfs_checkexp = ntfs_checkexp,
957 .vfs_vptofh = ntfs_vptofh,
958 .vfs_init = ntfs_init,
959 .vfs_uninit = ntfs_nthash_uninit /* see ntfs_ihash.c */
984263bc
MD
960};
961VFS_SET(ntfs_vfsops, ntfs, 0);
962#elif defined(__NetBSD__)
963extern struct vnodeopv_desc ntfs_vnodeop_opv_desc;
964
965struct vnodeopv_desc *ntfs_vnodeopv_descs[] = {
966 &ntfs_vnodeop_opv_desc,
967 NULL,
968};
969
970struct 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 /* !NetBSD && !FreeBSD */
989static 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};
1002VFS_SET(ntfs_vfsops, ntfs, MOUNT_NTFS, 0);
1003#endif
1004
1005