1 /* $NetBSD: hfs_vfsops.c,v 1.24 2009/12/03 14:29:04 pooka Exp $ */
4 * Copyright (c) 2005, 2007 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Yevgeny Binder and Dieter Baron.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * Copyright (c) 1991, 1993, 1994
34 * The Regents of the University of California. All rights reserved.
35 * (c) UNIX System Laboratories, Inc.
36 * All or some portions of this file are derived from material licensed
37 * to the University of California by American Telephone and Telegraph
38 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
39 * the permission of UNIX System Laboratories, Inc.
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
44 * 1. Redistributions of source code must retain the above copyright
45 * notice, this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright
47 * notice, this list of conditions and the following disclaimer in the
48 * documentation and/or other materials provided with the distribution.
49 * 3. Neither the name of the University nor the names of its contributors
50 * may be used to endorse or promote products derived from this software
51 * without specific prior written permission.
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
67 * Copyright (c) 1989, 1991, 1993, 1994
68 * The Regents of the University of California. All rights reserved.
70 * Redistribution and use in source and binary forms, with or without
71 * modification, are permitted provided that the following conditions
73 * 1. Redistributions of source code must retain the above copyright
74 * notice, this list of conditions and the following disclaimer.
75 * 2. Redistributions in binary form must reproduce the above copyright
76 * notice, this list of conditions and the following disclaimer in the
77 * documentation and/or other materials provided with the distribution.
78 * 3. Neither the name of the University nor the names of its contributors
79 * may be used to endorse or promote products derived from this software
80 * without specific prior written permission.
82 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
83 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
84 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
85 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
86 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
87 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
88 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
89 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
90 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
91 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
98 * Apple HFS+ filesystem
101 #include <sys/cdefs.h>
102 __KERNEL_RCSID(0, "$NetBSD: hfs_vfsops.c,v 1.24 2009/12/03 14:29:04 pooka Exp $");
105 #include "opt_compat_netbsd.h"
108 #include <sys/param.h>
109 #include <sys/systm.h>
110 #include <sys/namei.h>
111 #include <sys/proc.h>
112 #include <sys/kernel.h>
113 #include <sys/vnode.h>
114 #include <sys/socket.h>
115 #include <sys/mount.h>
117 #include <sys/device.h>
118 #include <sys/mbuf.h>
119 #include <sys/file.h>
120 #include <sys/disklabel.h>
121 #include <sys/ioctl.h>
122 #include <sys/errno.h>
123 #include <sys/malloc.h>
124 #include <sys/pool.h>
125 #include <sys/lock.h>
126 #include <sys/sysctl.h>
127 #include <sys/conf.h>
128 #include <sys/kauth.h>
129 #include <sys/stat.h>
130 #include <sys/module.h>
132 #include <miscfs/genfs/genfs.h>
133 #include <miscfs/specfs/specdev.h>
135 #include <fs/hfs/hfs.h>
136 #include <fs/hfs/libhfs.h>
138 MODULE(MODULE_CLASS_VFS
, hfs
, NULL
);
140 MALLOC_JUSTDEFINE(M_HFSMNT
, "hfs mount", "hfs mount structures");
142 extern kmutex_t hfs_hashlock
;
144 const struct vnodeopv_desc
* const hfs_vnodeopv_descs
[] = {
145 &hfs_vnodeop_opv_desc
,
146 &hfs_specop_opv_desc
,
147 &hfs_fifoop_opv_desc
,
151 struct vfsops hfs_vfsops
= {
153 sizeof (struct hfs_args
),
158 (void *)eopnotsupp
, /* vfs_quotactl */
167 NULL
, /* vfs_mountroot */
168 NULL
, /* vfs_snapshot */
170 (void *)eopnotsupp
, /* vfs_suspendctl */
171 genfs_renamelock_enter
,
172 genfs_renamelock_exit
,
179 static const struct genfs_ops hfs_genfsops
= {
180 .gop_size
= genfs_size
,
184 hfs_modcmd(modcmd_t cmd
, void *arg
)
188 case MODULE_CMD_INIT
:
189 return vfs_attach(&hfs_vfsops
);
190 case MODULE_CMD_FINI
:
191 return vfs_detach(&hfs_vfsops
);
198 hfs_mount(struct mount
*mp
, const char *path
, void *data
, size_t *data_len
)
200 struct lwp
*l
= curlwp
;
201 struct hfs_args
*args
= data
;
203 struct hfsmount
*hmp
;
208 if (*data_len
< sizeof *args
)
212 printf("vfsop = hfs_mount()\n");
213 #endif /* HFS_DEBUG */
215 if (mp
->mnt_flag
& MNT_GETARGS
) {
220 *data_len
= sizeof *args
;
227 /* FIXME: For development ONLY - disallow remounting for now */
229 update
= mp
->mnt_flag
& MNT_UPDATE
;
234 /* Check arguments */
235 if (args
->fspec
!= NULL
) {
237 * Look up the name and verify that it's sane.
239 error
= namei_simple_user(args
->fspec
,
240 NSM_FOLLOW_NOEMULROOT
, &devvp
);
246 * Be sure this is a valid block device
248 if (devvp
->v_type
!= VBLK
)
250 else if (bdevsw_lookup(devvp
->v_rdev
) == NULL
)
254 * Be sure we're still naming the same device
255 * used for our initial mount
258 if (devvp
!= hmp
->hm_devvp
)
263 /* Use the extant mount */
265 devvp
= hmp
->hm_devvp
;
268 /* New mounts must have a filename for the device */
275 * If mount by non-root, then verify that user has necessary
276 * permissions on the device.
278 * Permission to update a mount is checked higher, so here we presume
279 * updating the mount is okay (for example, as far as securelevel goes)
280 * which leaves us with the normal check.
285 (mp
->mnt_iflag
& IMNT_WANTRDWR
) != 0 :
286 (mp
->mnt_flag
& MNT_RDONLY
) == 0)
287 accessmode
|= VWRITE
;
288 vn_lock(devvp
, LK_EXCLUSIVE
| LK_RETRY
);
289 error
= genfs_can_mount(devvp
, accessmode
, l
->l_cred
);
290 VOP_UNLOCK(devvp
, 0);
297 printf("HFS: live remounting not yet supported!\n");
302 if ((error
= hfs_mountfs(devvp
, mp
, l
, args
->fspec
)) != 0)
305 error
= set_statvfs_info(path
, UIO_USERSPACE
, args
->fspec
, UIO_USERSPACE
,
306 mp
->mnt_op
->vfs_name
, mp
, l
);
313 volname
= malloc(hmp
->hm_vol
.name
.length
+ 1, M_TEMP
, M_WAITOK
);
315 printf("could not allocate volname; ignored\n");
317 if (hfs_unicode_to_ascii(hmp
->hm_vol
.name
.unicode
,
318 hmp
->hm_vol
.name
.length
, volname
) == NULL
)
319 printf("could not convert volume name to ascii; ignored\n");
321 printf("mounted volume \"%s\"\n", volname
);
322 free(volname
, M_TEMP
);
325 #endif /* HFS_DEBUG */
335 hfs_start(struct mount
*mp
, int flags
)
339 printf("vfsop = hfs_start()\n");
340 #endif /* HFS_DEBUG */
346 hfs_mountfs(struct vnode
*devvp
, struct mount
*mp
, struct lwp
*l
,
349 hfs_callback_args cbargs
;
350 hfs_libcb_argsopen argsopen
;
351 hfs_libcb_argsread argsread
;
352 struct hfsmount
*hmp
;
356 cred
= l
? l
->l_cred
: NOCRED
;
360 /* Create mounted volume structure. */
361 hmp
= (struct hfsmount
*)malloc(sizeof(struct hfsmount
),
367 memset(hmp
, 0, sizeof(struct hfsmount
));
370 mp
->mnt_flag
|= MNT_LOCAL
;
374 hmp
->hm_dev
= devvp
->v_rdev
;
375 hmp
->hm_devvp
= devvp
;
378 * Use libhfs to open the volume and read the volume header and other
379 * useful information.
382 hfslib_init_cbargs(&cbargs
);
383 argsopen
.cred
= argsread
.cred
= cred
;
384 argsopen
.l
= argsread
.l
= l
;
385 argsopen
.devvp
= devvp
;
386 cbargs
.read
= (void*)&argsread
;
387 cbargs
.openvol
= (void*)&argsopen
;
389 if ((error
= hfslib_open_volume(devpath
, mp
->mnt_flag
& MNT_RDONLY
,
390 &hmp
->hm_vol
, &cbargs
)) != 0)
393 /* Make sure this is not a journaled volume whose journal is dirty. */
394 if (!hfslib_is_journal_clean(&hmp
->hm_vol
)) {
395 printf("volume journal is dirty; not mounting\n");
400 mp
->mnt_fs_bshift
= 0;
401 while ((1 << mp
->mnt_fs_bshift
) < hmp
->hm_vol
.vh
.block_size
)
403 mp
->mnt_dev_bshift
= DEV_BSHIFT
;
415 hfs_unmount(struct mount
*mp
, int mntflags
)
417 hfs_callback_args cbargs
;
418 hfs_libcb_argsread argsclose
;
419 struct hfsmount
* hmp
;
424 printf("vfsop = hfs_unmount()\n");
425 #endif /* HFS_DEBUG */
430 if (mntflags
& MNT_FORCE
)
433 if ((error
= vflush(mp
, NULLVP
, flags
)) != 0)
436 hfslib_init_cbargs(&cbargs
);
437 argsclose
.l
= curlwp
;
438 cbargs
.closevol
= (void*)&argsclose
;
439 hfslib_close_volume(&hmp
->hm_vol
, &cbargs
);
441 vrele(hmp
->hm_devvp
);
445 mp
->mnt_flag
&= ~MNT_LOCAL
;
451 hfs_root(struct mount
*mp
, struct vnode
**vpp
)
457 printf("vfsop = hfs_root()\n");
458 #endif /* HFS_DEBUG */
460 if ((error
= VFS_VGET(mp
, HFS_CNID_ROOT_FOLDER
, &nvp
)) != 0)
468 hfs_statvfs(struct mount
*mp
, struct statvfs
*sbp
)
470 hfs_volume_header_t
*vh
;
473 printf("vfsop = hfs_statvfs()\n");
474 #endif /* HFS_DEBUG */
476 vh
= &VFSTOHFS(mp
)->hm_vol
.vh
;
478 sbp
->f_bsize
= vh
->block_size
;
479 sbp
->f_frsize
= sbp
->f_bsize
;
480 sbp
->f_iosize
= 4096;/* mac os x uses a 4 kb io size, so do the same */
481 sbp
->f_blocks
= vh
->total_blocks
;
482 sbp
->f_bfree
= vh
->free_blocks
; /* total free blocks */
483 sbp
->f_bavail
= vh
->free_blocks
; /* blocks free for non superuser */
485 sbp
->f_files
= vh
->file_count
; /* total files */
486 sbp
->f_ffree
= (1<<31) - vh
->file_count
; /* free file nodes */
487 copy_statvfs_info(sbp
, mp
);
493 hfs_sync(struct mount
*mp
, int waitfor
, kauth_cred_t cred
)
497 printf("vfsop = hfs_sync()\n");
498 #endif /* HFS_DEBUG */
504 * an ino_t corresponds directly to a CNID in our particular case,
505 * since both are conveniently 32-bit numbers
508 hfs_vget(struct mount
*mp
, ino_t ino
, struct vnode
**vpp
)
510 return hfs_vget_internal(mp
, ino
, HFS_DATAFORK
, vpp
);
514 * internal version with extra arguments to allow accessing resource fork
517 hfs_vget_internal(struct mount
*mp
, ino_t ino
, uint8_t fork
,
520 struct hfsmount
*hmp
;
521 struct hfsnode
*hnode
;
523 hfs_callback_args cbargs
;
525 hfs_catalog_keyed_record_t rec
;
526 hfs_catalog_key_t key
; /* the search key used to find this file on disk */
531 printf("vfsop = hfs_vget()\n");
532 #endif /* HFS_DEBUG */
538 cnid
= (hfs_cnid_t
)ino
;
540 if (fork
!= HFS_RSRCFORK
)
544 /* Check if this vnode has already been allocated. If so, just return it. */
545 if ((*vpp
= hfs_nhashget(dev
, cnid
, fork
, LK_EXCLUSIVE
)) != NULL
)
548 /* Allocate a new vnode/inode. */
549 if ((error
= getnewvnode(VT_HFS
, mp
, hfs_vnodeop_p
, &vp
)) != 0)
551 hnode
= malloc(sizeof(struct hfsnode
), M_TEMP
,
555 * If someone beat us to it while sleeping in getnewvnode(),
556 * push back the freshly allocated vnode we don't need, and return.
558 mutex_enter(&hfs_hashlock
);
559 if (hfs_nhashget(dev
, cnid
, fork
, 0) != NULL
) {
560 mutex_exit(&hfs_hashlock
);
566 vp
->v_vflag
|= VV_LOCKSWORK
;
568 genfs_node_init(vp
, &hfs_genfsops
);
572 hnode
->dummy
= 0x1337BABE;
575 * We need to put this vnode into the hash chain and lock it so that other
576 * requests for this inode will block if they arrive while we are sleeping
577 * waiting for old data structures to be purged or for the contents of the
578 * disk portion of this inode to be read. The hash chain requires the node's
579 * device and cnid to be known. Since this information was passed in the
580 * arguments, fill in the appropriate hfsnode fields without reading having
584 hnode
->h_rec
.u
.cnid
= cnid
;
585 hnode
->h_fork
= fork
;
587 hfs_nhashinsert(hnode
);
588 mutex_exit(&hfs_hashlock
);
592 * Read catalog record from disk.
594 hfslib_init_cbargs(&cbargs
);
596 if (hfslib_find_catalog_record_with_cnid(&hmp
->hm_vol
, cnid
,
597 &rec
, &key
, &cbargs
) != 0) {
603 memcpy(&hnode
->h_rec
, &rec
, sizeof(hnode
->h_rec
));
604 hnode
->h_parent
= key
.parent_cnid
;
606 /* XXX Eventually need to add an "ignore permissions" mount option */
609 * Now convert some of the catalog record's fields into values that make
610 * sense on this system.
615 * Initialize the vnode from the hfsnode, check for aliases.
616 * Note that the underlying vnode may change.
618 hfs_vinit(mp
, hfs_specop_p
, hfs_fifoop_p
, &vp
);
620 hnode
->h_devvp
= hmp
->hm_devvp
;
621 vref(hnode
->h_devvp
); /* Increment the ref count to the volume's device. */
623 /* Make sure UVM has allocated enough memory. (?) */
624 if (hnode
->h_rec
.u
.rec_type
== HFS_REC_FILE
) {
625 if (hnode
->h_fork
== HFS_DATAFORK
)
627 hnode
->h_rec
.file
.data_fork
.logical_size
);
630 hnode
->h_rec
.file
.rsrc_fork
.logical_size
);
633 uvm_vnp_setsize(vp
, 0); /* no directly reading directories */
645 hfs_fhtovp(struct mount
*mp
, struct fid
*fhp
, struct vnode
**vpp
)
649 printf("vfsop = hfs_fhtovp()\n");
650 #endif /* HFS_DEBUG */
656 hfs_vptofh(struct vnode
*vp
, struct fid
*fhp
, size_t *fh_size
)
660 printf("vfsop = hfs_vptofh()\n");
661 #endif /* HFS_DEBUG */
669 hfs_callbacks callbacks
;
672 printf("vfsop = hfs_init()\n");
673 #endif /* HFS_DEBUG */
675 malloc_type_attach(M_HFSMNT
);
677 callbacks
.error
= hfs_libcb_error
;
678 callbacks
.allocmem
= hfs_libcb_malloc
;
679 callbacks
.reallocmem
= hfs_libcb_realloc
;
680 callbacks
.freemem
= hfs_libcb_free
;
681 callbacks
.openvol
= hfs_libcb_opendev
;
682 callbacks
.closevol
= hfs_libcb_closedev
;
683 callbacks
.read
= hfs_libcb_read
;
686 hfslib_init(&callbacks
);
694 printf("vfsop = hfs_reinit()\n");
695 #endif /* HFS_DEBUG */
705 printf("vfsop = hfs_done()\n");
706 #endif /* HFS_DEBUG */
708 malloc_type_detach(M_HFSMNT
);
719 printf("vfsop = hfs_mountroot()\n");
720 #endif /* HFS_DEBUG */