Line data Source code
1 : /* $OpenBSD: ntfs_vfsops.c,v 1.61 2018/05/27 06:02:15 visa Exp $ */
2 : /* $NetBSD: ntfs_vfsops.c,v 1.7 2003/04/24 07:50:19 christos Exp $ */
3 :
4 : /*-
5 : * Copyright (c) 1998, 1999 Semen Ustimenko
6 : * All rights reserved.
7 : *
8 : * Redistribution and use in source and binary forms, with or without
9 : * modification, are permitted provided that the following conditions
10 : * are met:
11 : * 1. Redistributions of source code must retain the above copyright
12 : * notice, this list of conditions and the following disclaimer.
13 : * 2. Redistributions in binary form must reproduce the above copyright
14 : * notice, this list of conditions and the following disclaimer in the
15 : * documentation and/or other materials provided with the distribution.
16 : *
17 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 : * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 : * SUCH DAMAGE.
28 : *
29 : * Id: ntfs_vfsops.c,v 1.7 1999/05/31 11:28:30 phk Exp
30 : */
31 :
32 : #include <sys/param.h>
33 : #include <sys/systm.h>
34 : #include <sys/namei.h>
35 : #include <sys/proc.h>
36 : #include <sys/kernel.h>
37 : #include <sys/vnode.h>
38 : #include <sys/lock.h>
39 : #include <sys/mount.h>
40 : #include <sys/buf.h>
41 : #include <sys/disk.h>
42 : #include <sys/fcntl.h>
43 : #include <sys/malloc.h>
44 : #include <sys/device.h>
45 : #include <sys/conf.h>
46 : #include <sys/specdev.h>
47 :
48 : /*#define NTFS_DEBUG 1*/
49 : #include <ntfs/ntfs.h>
50 : #include <ntfs/ntfs_inode.h>
51 : #include <ntfs/ntfs_subr.h>
52 : #include <ntfs/ntfs_vfsops.h>
53 : #include <ntfs/ntfs_ihash.h>
54 :
55 : int ntfs_mount(struct mount *, const char *, void *,
56 : struct nameidata *, struct proc *);
57 : int ntfs_quotactl(struct mount *, int, uid_t, caddr_t,
58 : struct proc *);
59 : int ntfs_root(struct mount *, struct vnode **);
60 : int ntfs_start(struct mount *, int, struct proc *);
61 : int ntfs_statfs(struct mount *, struct statfs *,
62 : struct proc *);
63 : int ntfs_sync(struct mount *, int, int, struct ucred *,
64 : struct proc *);
65 : int ntfs_unmount(struct mount *, int, struct proc *);
66 : int ntfs_vget(struct mount *mp, ino_t ino,
67 : struct vnode **vpp);
68 : int ntfs_mountfs(struct vnode *, struct mount *,
69 : struct ntfs_args *, struct proc *);
70 : int ntfs_vptofh(struct vnode *, struct fid *);
71 :
72 : int ntfs_init(struct vfsconf *);
73 : int ntfs_fhtovp(struct mount *, struct fid *,
74 : struct vnode **);
75 : int ntfs_checkexp(struct mount *, struct mbuf *,
76 : int *, struct ucred **);
77 : int ntfs_sysctl(int *, u_int, void *, size_t *, void *,
78 : size_t, struct proc *);
79 :
80 : /*
81 : * Verify a remote client has export rights and return these rights via.
82 : * exflagsp and credanonp.
83 : */
84 : int
85 0 : ntfs_checkexp(struct mount *mp, struct mbuf *nam, int *exflagsp,
86 : struct ucred **credanonp)
87 : {
88 : struct netcred *np;
89 0 : struct ntfsmount *ntm = VFSTONTFS(mp);
90 :
91 : /*
92 : * Get the export permission structure for this <mp, client> tuple.
93 : */
94 0 : np = vfs_export_lookup(mp, &ntm->ntm_export, nam);
95 0 : if (np == NULL)
96 0 : return (EACCES);
97 :
98 0 : *exflagsp = np->netc_exflags;
99 0 : *credanonp = &np->netc_anon;
100 0 : return (0);
101 0 : }
102 :
103 : int
104 0 : ntfs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
105 : size_t newlen, struct proc *p)
106 : {
107 0 : return (EINVAL);
108 : }
109 :
110 : int
111 0 : ntfs_init(struct vfsconf *vcp)
112 : {
113 0 : return 0;
114 : }
115 :
116 : int
117 0 : ntfs_mount(struct mount *mp, const char *path, void *data,
118 : struct nameidata *ndp, struct proc *p)
119 : {
120 : int err = 0;
121 : struct vnode *devvp;
122 0 : struct ntfs_args *args = data;
123 0 : char fname[MNAMELEN];
124 0 : char fspec[MNAMELEN];
125 :
126 0 : ntfs_nthashinit();
127 :
128 : /*
129 : ***
130 : * Mounting non-root file system or updating a file system
131 : ***
132 : */
133 :
134 : /*
135 : * If updating, check whether changing from read-only to
136 : * read/write; if there is no device name, that's all we do.
137 : */
138 0 : if (mp->mnt_flag & MNT_UPDATE) {
139 : /* if not updating name...*/
140 0 : if (args && args->fspec == NULL) {
141 : /*
142 : * Process export requests. Jumping to "success"
143 : * will return the vfs_export() error code.
144 : */
145 0 : struct ntfsmount *ntm = VFSTONTFS(mp);
146 0 : err = vfs_export(mp, &ntm->ntm_export, &args->export_info);
147 : goto success;
148 : }
149 :
150 0 : printf("ntfs_mount(): MNT_UPDATE not supported\n");
151 : err = EINVAL;
152 0 : goto error_1;
153 : }
154 :
155 : /*
156 : * Not an update, or updating the name: look up the name
157 : * and verify that it refers to a sensible block device.
158 : */
159 0 : err = copyinstr(args->fspec, fspec, sizeof(fspec), NULL);
160 0 : if (err)
161 : goto error_1;
162 :
163 0 : if (disk_map(fspec, fname, sizeof(fname), DM_OPENBLCK) == -1)
164 0 : bcopy(fspec, fname, sizeof(fname));
165 :
166 0 : NDINIT(ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, fname, p);
167 0 : err = namei(ndp);
168 0 : if (err) {
169 : /* can't get devvp!*/
170 : goto error_1;
171 : }
172 :
173 0 : devvp = ndp->ni_vp;
174 :
175 0 : if (devvp->v_type != VBLK) {
176 : err = ENOTBLK;
177 0 : goto error_2;
178 : }
179 :
180 0 : if (major(devvp->v_rdev) >= nblkdev) {
181 : err = ENXIO;
182 0 : goto error_2;
183 : }
184 :
185 0 : if (mp->mnt_flag & MNT_UPDATE) {
186 : #if 0
187 : /*
188 : ********************
189 : * UPDATE
190 : ********************
191 : */
192 :
193 : if (devvp != ntmp->um_devvp)
194 : err = EINVAL; /* needs translation */
195 : else
196 : vrele(devvp);
197 : /*
198 : * Update device name only on success
199 : */
200 : if( !err) {
201 : err = set_statfs_info(NULL, UIO_USERSPACE, args->fspec,
202 : UIO_USERSPACE, mp, p);
203 : }
204 : #endif
205 : } else {
206 : /*
207 : ********************
208 : * NEW MOUNT
209 : ********************
210 : */
211 :
212 : /*
213 : * Since this is a new mount, we want the names for
214 : * the device and the mount point copied in. If an
215 : * error occurs, the mountpoint is discarded by the
216 : * upper level code.
217 : */
218 : /* Save "last mounted on" info for mount point (NULL pad)*/
219 0 : bzero(mp->mnt_stat.f_mntonname, MNAMELEN);
220 0 : strlcpy(mp->mnt_stat.f_mntonname, path, MNAMELEN);
221 0 : bzero(mp->mnt_stat.f_mntfromname, MNAMELEN);
222 0 : strlcpy(mp->mnt_stat.f_mntfromname, fname, MNAMELEN);
223 0 : bzero(mp->mnt_stat.f_mntfromspec, MNAMELEN);
224 0 : strlcpy(mp->mnt_stat.f_mntfromspec, fspec, MNAMELEN);
225 0 : bcopy(args, &mp->mnt_stat.mount_info.ntfs_args, sizeof(*args));
226 0 : if ( !err) {
227 0 : err = ntfs_mountfs(devvp, mp, args, p);
228 0 : }
229 : }
230 0 : if (err) {
231 : goto error_2;
232 : }
233 :
234 : /*
235 : * Initialize FS stat information in mount struct; uses both
236 : * mp->mnt_stat.f_mntonname and mp->mnt_stat.f_mntfromname
237 : *
238 : * This code is common to root and non-root mounts
239 : */
240 0 : (void)VFS_STATFS(mp, &mp->mnt_stat, p);
241 :
242 0 : goto success;
243 :
244 :
245 : error_2: /* error with devvp held*/
246 :
247 : /* release devvp before failing*/
248 0 : vrele(devvp);
249 :
250 : error_1: /* no state to back out*/
251 :
252 : success:
253 0 : return(err);
254 0 : }
255 :
256 : /*
257 : * Common code for mount and mountroot
258 : */
259 : int
260 0 : ntfs_mountfs(struct vnode *devvp, struct mount *mp, struct ntfs_args *argsp,
261 : struct proc *p)
262 : {
263 0 : struct buf *bp;
264 : struct ntfsmount *ntmp = NULL;
265 0 : dev_t dev = devvp->v_rdev;
266 : int error, ncount, i;
267 0 : struct vnode *vp;
268 :
269 : /*
270 : * Disallow multiple mounts of the same device.
271 : * Disallow mounting of a device that is currently in use
272 : * (except for root, which might share swap device for miniroot).
273 : * Flush out any old buffers remaining from a previous use.
274 : */
275 0 : error = vfs_mountedon(devvp);
276 0 : if (error)
277 0 : return (error);
278 0 : ncount = vcount(devvp);
279 0 : if (ncount > 1 && devvp != rootvp)
280 0 : return (EBUSY);
281 0 : vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
282 0 : error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0);
283 0 : VOP_UNLOCK(devvp);
284 0 : if (error)
285 0 : return (error);
286 :
287 0 : error = VOP_OPEN(devvp, FREAD, FSCRED, p);
288 0 : if (error)
289 0 : return (error);
290 :
291 0 : bp = NULL;
292 :
293 0 : error = bread(devvp, BBLOCK, BBSIZE, &bp);
294 0 : if (error)
295 : goto out;
296 0 : ntmp = malloc(sizeof *ntmp, M_NTFSMNT, M_WAITOK | M_ZERO);
297 0 : bcopy(bp->b_data, &ntmp->ntm_bootfile, sizeof(struct bootfile));
298 0 : brelse(bp);
299 0 : bp = NULL;
300 :
301 0 : if (strncmp(ntmp->ntm_bootfile.bf_sysid, NTFS_BBID, NTFS_BBIDLEN)) {
302 : error = EINVAL;
303 : DPRINTF("ntfs_mountfs: invalid boot block\n");
304 0 : goto out;
305 : }
306 :
307 : {
308 0 : int8_t cpr = ntmp->ntm_mftrecsz;
309 0 : if( cpr > 0 )
310 0 : ntmp->ntm_bpmftrec = ntmp->ntm_spc * cpr;
311 : else
312 0 : ntmp->ntm_bpmftrec = (1 << (-cpr)) / ntmp->ntm_bps;
313 : }
314 : DPRINTF("ntfs_mountfs(): bps: %u, spc: %u, media: %x, "
315 : "mftrecsz: %u (%u sects)\n", ntmp->ntm_bps, ntmp->ntm_spc,
316 : ntmp->ntm_bootfile.bf_media, ntmp->ntm_mftrecsz,
317 : ntmp->ntm_bpmftrec);
318 : DPRINTF("ntfs_mountfs(): mftcn: 0x%llx|0x%llx\n",
319 : ntmp->ntm_mftcn, ntmp->ntm_mftmirrcn);
320 :
321 0 : ntmp->ntm_mountp = mp;
322 0 : ntmp->ntm_dev = dev;
323 0 : ntmp->ntm_devvp = devvp;
324 0 : ntmp->ntm_uid = argsp->uid;
325 0 : ntmp->ntm_gid = argsp->gid;
326 0 : ntmp->ntm_mode = argsp->mode;
327 0 : ntmp->ntm_flag = argsp->flag;
328 0 : mp->mnt_data = ntmp;
329 0 : TAILQ_INIT(&ntmp->ntm_ntnodeq);
330 :
331 : /* set file name encode/decode hooks XXX utf-8 only for now */
332 0 : ntmp->ntm_wget = ntfs_utf8_wget;
333 0 : ntmp->ntm_wput = ntfs_utf8_wput;
334 0 : ntmp->ntm_wcmp = ntfs_utf8_wcmp;
335 :
336 : DPRINTF("ntfs_mountfs(): case-%s,%s uid: %d, gid: %d, mode: %o\n",
337 : (ntmp->ntm_flag & NTFS_MFLAG_CASEINS) ? "insens." : "sens.",
338 : (ntmp->ntm_flag & NTFS_MFLAG_ALLNAMES) ? " allnames," : "",
339 : ntmp->ntm_uid, ntmp->ntm_gid, ntmp->ntm_mode);
340 :
341 : /*
342 : * We read in some system nodes to do not allow
343 : * reclaim them and to have everytime access to them.
344 : */
345 : {
346 0 : int pi[3] = { NTFS_MFTINO, NTFS_ROOTINO, NTFS_BITMAPINO };
347 0 : for (i=0; i<3; i++) {
348 0 : error = VFS_VGET(mp, pi[i], &(ntmp->ntm_sysvn[pi[i]]));
349 0 : if(error)
350 0 : goto out1;
351 0 : ntmp->ntm_sysvn[pi[i]]->v_flag |= VSYSTEM;
352 0 : vref(ntmp->ntm_sysvn[pi[i]]);
353 0 : vput(ntmp->ntm_sysvn[pi[i]]);
354 : }
355 0 : }
356 :
357 : /* read the Unicode lowercase --> uppercase translation table,
358 : * if necessary */
359 0 : if ((error = ntfs_toupper_use(mp, ntmp, p)))
360 : goto out1;
361 :
362 : /*
363 : * Scan $BitMap and count free clusters
364 : */
365 0 : error = ntfs_calccfree(ntmp, &ntmp->ntm_cfree);
366 0 : if(error)
367 : goto out1;
368 :
369 : /*
370 : * Read and translate to internal format attribute
371 : * definition file.
372 : */
373 : {
374 : int num,j;
375 0 : struct attrdef ad;
376 :
377 : /* Open $AttrDef */
378 0 : error = VFS_VGET(mp, NTFS_ATTRDEFINO, &vp );
379 0 : if(error)
380 0 : goto out1;
381 :
382 : /* Count valid entries */
383 0 : for(num = 0; ; num++) {
384 0 : error = ntfs_readattr(ntmp, VTONT(vp),
385 0 : NTFS_A_DATA, NULL, num * sizeof(ad), sizeof(ad),
386 : &ad, NULL);
387 0 : if (error)
388 0 : goto out1;
389 0 : if (ad.ad_name[0] == 0)
390 : break;
391 : }
392 :
393 : /* Alloc memory for attribute definitions */
394 0 : ntmp->ntm_ad = mallocarray(num, sizeof(struct ntvattrdef),
395 : M_NTFSMNT, M_WAITOK);
396 :
397 0 : ntmp->ntm_adnum = num;
398 :
399 : /* Read them and translate */
400 0 : for(i = 0; i < num; i++){
401 0 : error = ntfs_readattr(ntmp, VTONT(vp),
402 0 : NTFS_A_DATA, NULL, i * sizeof(ad), sizeof(ad),
403 : &ad, NULL);
404 0 : if (error)
405 0 : goto out1;
406 : j = 0;
407 0 : do {
408 0 : ntmp->ntm_ad[i].ad_name[j] = ad.ad_name[j];
409 0 : } while(ad.ad_name[j++]);
410 0 : ntmp->ntm_ad[i].ad_namelen = j - 1;
411 0 : ntmp->ntm_ad[i].ad_type = ad.ad_type;
412 : }
413 :
414 0 : vput(vp);
415 0 : }
416 :
417 0 : mp->mnt_stat.f_fsid.val[0] = dev;
418 0 : mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
419 0 : mp->mnt_stat.f_namemax = NTFS_MAXFILENAME;
420 0 : mp->mnt_flag |= MNT_LOCAL;
421 0 : devvp->v_specmountpoint = mp;
422 0 : return (0);
423 :
424 : out1:
425 0 : for (i = 0; i < NTFS_SYSNODESNUM; i++)
426 0 : if (ntmp->ntm_sysvn[i])
427 0 : vrele(ntmp->ntm_sysvn[i]);
428 :
429 0 : if (vflush(mp,NULLVP,0))
430 : DPRINTF("ntfs_mountfs: vflush failed\n");
431 :
432 : out:
433 0 : if (devvp->v_specinfo)
434 0 : devvp->v_specmountpoint = NULL;
435 0 : if (bp)
436 0 : brelse(bp);
437 :
438 0 : if (ntmp != NULL) {
439 0 : if (ntmp->ntm_ad != NULL)
440 0 : free(ntmp->ntm_ad, M_NTFSMNT, 0);
441 0 : free(ntmp, M_NTFSMNT, 0);
442 0 : mp->mnt_data = NULL;
443 0 : }
444 :
445 : /* lock the device vnode before calling VOP_CLOSE() */
446 0 : vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
447 0 : (void)VOP_CLOSE(devvp, FREAD, NOCRED, p);
448 0 : VOP_UNLOCK(devvp);
449 :
450 0 : return (error);
451 0 : }
452 :
453 : int
454 0 : ntfs_start(struct mount *mp, int flags, struct proc *p)
455 : {
456 0 : return (0);
457 : }
458 :
459 : int
460 0 : ntfs_unmount(struct mount *mp, int mntflags, struct proc *p)
461 : {
462 : struct ntfsmount *ntmp;
463 : int error, flags, i;
464 :
465 : DPRINTF("ntfs_unmount: unmounting...\n");
466 0 : ntmp = VFSTONTFS(mp);
467 :
468 : flags = 0;
469 0 : if(mntflags & MNT_FORCE)
470 0 : flags |= FORCECLOSE;
471 :
472 : DPRINTF("ntfs_unmount: vflushing...\n");
473 0 : error = vflush(mp,NULLVP,flags | SKIPSYSTEM);
474 0 : if (error) {
475 : DPRINTF("ntfs_unmount: vflush failed: %d\n", error);
476 0 : return (error);
477 : }
478 :
479 : /* Check if system vnodes are still referenced */
480 0 : for(i=0;i<NTFS_SYSNODESNUM;i++) {
481 0 : if(((mntflags & MNT_FORCE) == 0) && (ntmp->ntm_sysvn[i] &&
482 0 : ntmp->ntm_sysvn[i]->v_usecount > 1))
483 0 : return (EBUSY);
484 : }
485 :
486 : /* Dereference all system vnodes */
487 0 : for(i=0;i<NTFS_SYSNODESNUM;i++)
488 0 : if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]);
489 :
490 : /* vflush system vnodes */
491 0 : error = vflush(mp,NULLVP,flags);
492 0 : if (error) {
493 : /* XXX should this be panic() ? */
494 0 : printf("ntfs_unmount: vflush failed(sysnodes): %d\n",error);
495 0 : }
496 :
497 : /* Check if the type of device node isn't VBAD before
498 : * touching v_specinfo. If the device vnode is revoked, the
499 : * field is NULL and touching it causes null pointer derefercence.
500 : */
501 0 : if (ntmp->ntm_devvp->v_type != VBAD)
502 0 : ntmp->ntm_devvp->v_specmountpoint = NULL;
503 :
504 : /* lock the device vnode before calling VOP_CLOSE() */
505 0 : vn_lock(ntmp->ntm_devvp, LK_EXCLUSIVE | LK_RETRY);
506 0 : vinvalbuf(ntmp->ntm_devvp, V_SAVE, NOCRED, p, 0, 0);
507 0 : (void)VOP_CLOSE(ntmp->ntm_devvp, FREAD, NOCRED, p);
508 0 : vput(ntmp->ntm_devvp);
509 :
510 : /* free the toupper table, if this has been last mounted ntfs volume */
511 0 : ntfs_toupper_unuse(p);
512 :
513 : DPRINTF("ntfs_unmount: freeing memory...\n");
514 0 : free(ntmp->ntm_ad, M_NTFSMNT, 0);
515 0 : free(ntmp, M_NTFSMNT, 0);
516 0 : mp->mnt_data = NULL;
517 0 : mp->mnt_flag &= ~MNT_LOCAL;
518 0 : return (0);
519 0 : }
520 :
521 : int
522 0 : ntfs_root(struct mount *mp, struct vnode **vpp)
523 : {
524 0 : struct vnode *nvp;
525 : int error = 0;
526 :
527 : DPRINTF("ntfs_root(): sysvn: %p\n",
528 : VFSTONTFS(mp)->ntm_sysvn[NTFS_ROOTINO]);
529 0 : error = VFS_VGET(mp, (ino_t)NTFS_ROOTINO, &nvp);
530 0 : if(error) {
531 0 : printf("ntfs_root: VFS_VGET failed: %d\n",error);
532 0 : return (error);
533 : }
534 :
535 0 : *vpp = nvp;
536 0 : return (0);
537 0 : }
538 :
539 : /*
540 : * Do operations associated with quotas, not supported
541 : */
542 : int
543 0 : ntfs_quotactl(struct mount *mp, int cmds, uid_t uid, caddr_t arg,
544 : struct proc *p)
545 : {
546 0 : return EOPNOTSUPP;
547 : }
548 :
549 : int
550 0 : ntfs_calccfree(struct ntfsmount *ntmp, cn_t *cfreep)
551 : {
552 : struct vnode *vp;
553 : u_int8_t *tmp;
554 : int j, error;
555 : cn_t cfree = 0;
556 : uint64_t bmsize, offset;
557 : size_t chunksize, i;
558 :
559 0 : vp = ntmp->ntm_sysvn[NTFS_BITMAPINO];
560 :
561 0 : bmsize = VTOF(vp)->f_size;
562 :
563 0 : if (bmsize > 1024 * 1024)
564 0 : chunksize = 1024 * 1024;
565 : else
566 : chunksize = bmsize;
567 :
568 0 : tmp = malloc(chunksize, M_TEMP, M_WAITOK);
569 :
570 0 : for (offset = 0; offset < bmsize; offset += chunksize) {
571 0 : if (chunksize > bmsize - offset)
572 0 : chunksize = bmsize - offset;
573 :
574 0 : error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL,
575 : offset, chunksize, tmp, NULL);
576 0 : if (error)
577 : goto out;
578 :
579 0 : for (i = 0; i < chunksize; i++)
580 0 : for (j = 0; j < 8; j++)
581 0 : if (~tmp[i] & (1 << j))
582 0 : cfree++;
583 : }
584 :
585 0 : *cfreep = cfree;
586 :
587 : out:
588 0 : free(tmp, M_TEMP, 0);
589 0 : return(error);
590 : }
591 :
592 : int
593 0 : ntfs_statfs(struct mount *mp, struct statfs *sbp, struct proc *p)
594 : {
595 0 : struct ntfsmount *ntmp = VFSTONTFS(mp);
596 : u_int64_t mftallocated;
597 :
598 : DPRINTF("ntfs_statfs():\n");
599 :
600 0 : mftallocated = VTOF(ntmp->ntm_sysvn[NTFS_MFTINO])->f_allocated;
601 :
602 0 : sbp->f_bsize = ntmp->ntm_bps;
603 0 : sbp->f_iosize = ntmp->ntm_bps * ntmp->ntm_spc;
604 0 : sbp->f_blocks = ntmp->ntm_bootfile.bf_spv;
605 0 : sbp->f_bfree = sbp->f_bavail = ntfs_cntobn(ntmp->ntm_cfree);
606 0 : sbp->f_ffree = sbp->f_favail = sbp->f_bfree / ntmp->ntm_bpmftrec;
607 0 : sbp->f_files = mftallocated / ntfs_bntob(ntmp->ntm_bpmftrec) +
608 : sbp->f_ffree;
609 0 : copy_statfs_info(sbp, mp);
610 :
611 0 : return (0);
612 : }
613 :
614 : int
615 0 : ntfs_sync(struct mount *mp, int waitfor, int stall, struct ucred *cred, struct proc *p)
616 : {
617 : /*DPRINTF("ntfs_sync():\n");*/
618 0 : return (0);
619 : }
620 :
621 : int
622 0 : ntfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
623 : {
624 0 : struct ntfid *ntfhp = (struct ntfid *)fhp;
625 : int error;
626 :
627 : DDPRINTF("ntfs_fhtovp(): %s: %u\n",
628 : mp->mnt_stat.f_mntonname, ntfhp->ntfid_ino);
629 :
630 0 : error = ntfs_vgetex(mp, ntfhp->ntfid_ino, ntfhp->ntfid_attr, NULL,
631 0 : LK_EXCLUSIVE | LK_RETRY, 0, curproc, vpp); /* XXX */
632 0 : if (error != 0) {
633 0 : *vpp = NULLVP;
634 0 : return (error);
635 : }
636 :
637 : /* XXX as unlink/rmdir/mkdir/creat are not currently possible
638 : * with NTFS, we don't need to check anything else for now */
639 0 : return (0);
640 0 : }
641 :
642 : int
643 0 : ntfs_vptofh(struct vnode *vp, struct fid *fhp)
644 : {
645 : struct ntnode *ntp;
646 : struct ntfid *ntfhp;
647 : struct fnode *fn;
648 :
649 : DDPRINTF("ntfs_fhtovp(): %s: %p\n",
650 : vp->v_mount->mnt_stat.f_mntonname, vp);
651 :
652 0 : fn = VTOF(vp);
653 0 : ntp = VTONT(vp);
654 0 : ntfhp = (struct ntfid *)fhp;
655 0 : ntfhp->ntfid_len = sizeof(struct ntfid);
656 0 : ntfhp->ntfid_ino = ntp->i_number;
657 0 : ntfhp->ntfid_attr = fn->f_attrtype;
658 : #ifdef notyet
659 : ntfhp->ntfid_gen = ntp->i_gen;
660 : #endif
661 0 : return (0);
662 : }
663 :
664 : int
665 0 : ntfs_vgetex(struct mount *mp, ntfsino_t ino, u_int32_t attrtype, char *attrname,
666 : u_long lkflags, u_long flags, struct proc *p, struct vnode **vpp)
667 : {
668 : int error;
669 : struct ntfsmount *ntmp;
670 0 : struct ntnode *ip;
671 0 : struct fnode *fp;
672 0 : struct vnode *vp;
673 : enum vtype f_type;
674 :
675 : DPRINTF("ntfs_vgetex: ino: %u, attr: 0x%x:%s, lkf: 0x%lx, f: 0x%lx\n",
676 : ino, attrtype, attrname ? attrname : "", lkflags, flags);
677 :
678 0 : ntmp = VFSTONTFS(mp);
679 0 : *vpp = NULL;
680 :
681 : /* Get ntnode */
682 0 : error = ntfs_ntlookup(ntmp, ino, &ip, p);
683 0 : if (error) {
684 0 : printf("ntfs_vget: ntfs_ntget failed\n");
685 0 : return (error);
686 : }
687 :
688 : /* It may be not initialized fully, so force load it */
689 0 : if (!(flags & VG_DONTLOADIN) && !(ip->i_flag & IN_LOADED)) {
690 0 : error = ntfs_loadntnode(ntmp, ip);
691 0 : if(error) {
692 0 : printf("ntfs_vget: CAN'T LOAD ATTRIBUTES FOR INO: %d\n",
693 0 : ip->i_number);
694 0 : ntfs_ntput(ip, p);
695 :
696 0 : return (error);
697 : }
698 : }
699 :
700 0 : error = ntfs_fget(ntmp, ip, attrtype, attrname, &fp);
701 0 : if (error) {
702 0 : printf("ntfs_vget: ntfs_fget failed\n");
703 0 : ntfs_ntput(ip, p);
704 :
705 0 : return (error);
706 : }
707 :
708 0 : if (!(flags & VG_DONTVALIDFN) && !(fp->f_flag & FN_VALID)) {
709 0 : if ((ip->i_frflag & NTFS_FRFLAG_DIR) &&
710 0 : (fp->f_attrtype == NTFS_A_DATA && fp->f_attrname == NULL)) {
711 : f_type = VDIR;
712 0 : } else if (flags & VG_EXT) {
713 : f_type = VNON;
714 0 : fp->f_size = fp->f_allocated = 0;
715 0 : } else {
716 : f_type = VREG;
717 :
718 0 : error = ntfs_filesize(ntmp, fp,
719 0 : &fp->f_size, &fp->f_allocated);
720 0 : if (error) {
721 0 : ntfs_ntput(ip, p);
722 :
723 0 : return (error);
724 : }
725 : }
726 :
727 0 : fp->f_flag |= FN_VALID;
728 0 : }
729 :
730 : /*
731 : * We may be calling vget() now. To avoid potential deadlock, we need
732 : * to release ntnode lock, since due to locking order vnode
733 : * lock has to be acquired first.
734 : * ntfs_fget() bumped ntnode usecount, so ntnode won't be recycled
735 : * prematurely.
736 : */
737 0 : ntfs_ntput(ip, p);
738 :
739 0 : if (FTOV(fp)) {
740 : /* vget() returns error if the vnode has been recycled */
741 0 : if (vget(FTOV(fp), lkflags) == 0) {
742 0 : *vpp = FTOV(fp);
743 0 : return (0);
744 : }
745 : }
746 :
747 0 : error = getnewvnode(VT_NTFS, ntmp->ntm_mountp, &ntfs_vops, &vp);
748 0 : if(error) {
749 0 : ntfs_frele(fp);
750 0 : ntfs_ntput(ip, p);
751 :
752 0 : return (error);
753 : }
754 : DPRINTF("ntfs_vget: vnode: %p for ntnode: %u\n", vp, ino);
755 :
756 0 : fp->f_vp = vp;
757 0 : vp->v_data = fp;
758 0 : vp->v_type = f_type;
759 :
760 0 : if (ino == NTFS_ROOTINO)
761 0 : vp->v_flag |= VROOT;
762 :
763 0 : if (lkflags & LK_TYPE_MASK) {
764 0 : error = vn_lock(vp, lkflags);
765 0 : if (error) {
766 0 : vput(vp);
767 0 : return (error);
768 : }
769 : }
770 :
771 0 : *vpp = vp;
772 0 : return (0);
773 0 : }
774 :
775 : int
776 0 : ntfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
777 : {
778 0 : if (ino > (ntfsino_t)-1)
779 0 : panic("ntfs_vget: alien ino_t %llu", (unsigned long long)ino);
780 0 : return ntfs_vgetex(mp, ino, NTFS_A_DATA, NULL,
781 0 : LK_EXCLUSIVE | LK_RETRY, 0, curproc, vpp); /* XXX */
782 : }
783 :
784 : const struct vfsops ntfs_vfsops = {
785 : ntfs_mount,
786 : ntfs_start,
787 : ntfs_unmount,
788 : ntfs_root,
789 : ntfs_quotactl,
790 : ntfs_statfs,
791 : ntfs_sync,
792 : ntfs_vget,
793 : ntfs_fhtovp,
794 : ntfs_vptofh,
795 : ntfs_init,
796 : ntfs_sysctl,
797 : ntfs_checkexp,
798 : };
|