2 * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (c) 1991, 1993, 1994
24 * The Regents of the University of California. All rights reserved.
25 * (c) UNIX System Laboratories, Inc.
26 * All or some portions of this file are derived from material licensed
27 * to the University of California by American Telephone and Telegraph
28 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
29 * the permission of UNIX System Laboratories, Inc.
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
34 * 1. Redistributions of source code must retain the above copyright
35 * notice, this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright
37 * notice, this list of conditions and the following disclaimer in the
38 * documentation and/or other materials provided with the distribution.
39 * 3. All advertising materials mentioning features or use of this software
40 * must display the following acknowledgement:
41 * This product includes software developed by the University of
42 * California, Berkeley and its contributors.
43 * 4. Neither the name of the University nor the names of its contributors
44 * may be used to endorse or promote products derived from this software
45 * without specific prior written permission.
47 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 * derived from @(#)ufs_vfsops.c 8.8 (Berkeley) 5/20/95
62 * (c) Copyright 1997-2002 Apple Computer, Inc. All rights reserved.
64 * hfs_vfsops.c -- VFS layer for loadable HFS file system.
67 #include <sys/param.h>
68 #include <sys/systm.h>
71 #include <sys/namei.h>
72 #include <sys/vnode.h>
73 #include <sys/mount.h>
74 #include <sys/malloc.h>
77 #include <sys/quota.h>
80 #include <miscfs/specfs/specdev.h>
81 #include <hfs/hfs_mount.h>
84 #include "hfs_catalog.h"
85 #include "hfs_cnode.h"
87 #include "hfs_endian.h"
88 #include "hfs_quota.h"
90 #include "hfscommon/headers/FileMgrInternal.h"
91 #include "hfscommon/headers/BTreesInternal.h"
100 extern struct vnodeopv_desc hfs_vnodeop_opv_desc
;
102 extern void hfs_converterinit(void);
104 extern void inittodr( time_t base
);
107 static int hfs_changefs
__P((struct mount
*mp
, struct hfs_mount_args
*args
,
109 static int hfs_reload
__P((struct mount
*mp
, struct ucred
*cred
, struct proc
*p
));
111 static int hfs_mountfs
__P((struct vnode
*devvp
, struct mount
*mp
, struct proc
*p
,
112 struct hfs_mount_args
*args
));
113 static int hfs_statfs
__P((struct mount
*mp
, register struct statfs
*sbp
,
118 * Called by vfs_mountroot when mounting HFS Plus as root.
123 extern struct vnode
*rootvp
;
125 struct proc
*p
= current_proc(); /* XXX */
126 struct hfsmount
*hfsmp
;
131 * Get vnode for rootdev.
133 if ((error
= bdevvp(rootdev
, &rootvp
))) {
134 printf("hfs_mountroot: can't setup bdevvp");
137 if ((error
= vfs_rootmountalloc("hfs", "root_device", &mp
))) {
138 vrele(rootvp
); /* release the reference from bdevvp() */
141 if ((error
= hfs_mountfs(rootvp
, mp
, p
, NULL
))) {
142 mp
->mnt_vfc
->vfc_refcount
--;
144 vrele(rootvp
); /* release the reference from bdevvp() */
145 _FREE_ZONE(mp
, sizeof (struct mount
), M_MOUNT
);
148 simple_lock(&mountlist_slock
);
149 CIRCLEQ_INSERT_TAIL(&mountlist
, mp
, mnt_list
);
150 simple_unlock(&mountlist_slock
);
153 hfsmp
= VFSTOHFS(mp
);
155 hfsmp
->hfs_uid
= UNKNOWNUID
;
156 hfsmp
->hfs_gid
= UNKNOWNGID
;
157 hfsmp
->hfs_dir_mask
= (S_IRWXU
| S_IRGRP
|S_IXGRP
| S_IROTH
|S_IXOTH
); /* 0755 */
158 hfsmp
->hfs_file_mask
= (S_IRWXU
| S_IRGRP
|S_IXGRP
| S_IROTH
|S_IXOTH
); /* 0755 */
160 /* Establish the free block reserve. */
161 vcb
= HFSTOVCB(hfsmp
);
162 vcb
->reserveBlocks
= ((u_int64_t
)vcb
->totalBlocks
* HFS_MINFREE
) / 100;
163 vcb
->reserveBlocks
= MIN(vcb
->reserveBlocks
, HFS_MAXRESERVE
/ vcb
->blockSize
);
165 (void)hfs_statfs(mp
, &mp
->mnt_stat
, p
);
168 inittodr(HFSTOVCB(hfsmp
)->vcbLsMod
);
180 hfs_mount(mp
, path
, data
, ndp
, p
)
181 register struct mount
*mp
;
184 struct nameidata
*ndp
;
187 struct hfsmount
*hfsmp
= NULL
;
189 struct hfs_mount_args args
;
195 if ((retval
= copyin(data
, (caddr_t
)&args
, sizeof(args
))))
199 * If updating, check whether changing from read-only to
200 * read/write; if there is no device name, that's all we do.
202 if (mp
->mnt_flag
& MNT_UPDATE
) {
204 hfsmp
= VFSTOHFS(mp
);
205 if ((hfsmp
->hfs_fs_ronly
== 0) && (mp
->mnt_flag
& MNT_RDONLY
)) {
207 /* use VFS_SYNC to push out System (btree) files */
208 retval
= VFS_SYNC(mp
, MNT_WAIT
, p
->p_ucred
, p
);
209 if (retval
&& ((mp
->mnt_flag
& MNT_FORCE
) == 0))
213 if (mp
->mnt_flag
& MNT_FORCE
)
216 if ((retval
= hfs_flushfiles(mp
, flags
, p
)))
218 hfsmp
->hfs_fs_ronly
= 1;
219 retval
= hfs_flushvolumeheader(hfsmp
, MNT_WAIT
, 0);
221 /* also get the volume bitmap blocks */
223 retval
= VOP_FSYNC(hfsmp
->hfs_devvp
, NOCRED
, MNT_WAIT
, p
);
226 hfsmp
->hfs_fs_ronly
= 0;
231 if ((mp
->mnt_flag
& MNT_RELOAD
) &&
232 (retval
= hfs_reload(mp
, ndp
->ni_cnd
.cn_cred
, p
)))
235 if (hfsmp
->hfs_fs_ronly
&& (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)) {
237 * If upgrade to read-write by non-root, then verify
238 * that user has necessary permissions on the device.
240 if (p
->p_ucred
->cr_uid
!= 0) {
241 devvp
= hfsmp
->hfs_devvp
;
242 vn_lock(devvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
243 if ((retval
= VOP_ACCESS(devvp
, VREAD
| VWRITE
, p
->p_ucred
, p
))) {
244 VOP_UNLOCK(devvp
, 0, p
);
247 VOP_UNLOCK(devvp
, 0, p
);
249 retval
= hfs_flushvolumeheader(hfsmp
, MNT_WAIT
, 0);
251 if (retval
!= E_NONE
)
254 /* only change hfs_fs_ronly after a successfull write */
255 hfsmp
->hfs_fs_ronly
= 0;
258 if ((hfsmp
->hfs_fs_ronly
== 0) &&
259 (HFSTOVCB(hfsmp
)->vcbSigWord
== kHFSPlusSigWord
)) {
260 /* setup private/hidden directory for unlinked files */
261 hfsmp
->hfs_private_metadata_dir
= FindMetaDataDirectory(HFSTOVCB(hfsmp
));
264 if (args
.fspec
== 0) {
266 * Process export requests.
268 return vfs_export(mp
, &hfsmp
->hfs_export
, &args
.export
);
273 * Not an update, or updating the name: look up the name
274 * and verify that it refers to a sensible block device.
276 NDINIT(ndp
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, args
.fspec
, p
);
278 if (retval
!= E_NONE
) {
279 DBG_ERR(("hfs_mount: CAN'T GET DEVICE: %s, %x\n", args
.fspec
, ndp
->ni_vp
->v_rdev
));
285 if (devvp
->v_type
!= VBLK
) {
290 if (major(devvp
->v_rdev
) >= nblkdev
) {
297 * If mount by non-root, then verify that user has necessary
298 * permissions on the device.
300 if (p
->p_ucred
->cr_uid
!= 0) {
302 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0)
303 accessmode
|= VWRITE
;
304 vn_lock(devvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
305 if ((retval
= VOP_ACCESS(devvp
, accessmode
, p
->p_ucred
, p
))) {
309 VOP_UNLOCK(devvp
, 0, p
);
312 if ((mp
->mnt_flag
& MNT_UPDATE
) == 0) {
313 retval
= hfs_mountfs(devvp
, mp
, p
, &args
);
314 if (retval
!= E_NONE
)
317 if (devvp
!= hfsmp
->hfs_devvp
)
318 retval
= EINVAL
; /* needs translation */
320 retval
= hfs_changefs(mp
, &args
, p
);
324 if (retval
!= E_NONE
) {
329 /* Set the mount flag to indicate that we support volfs */
330 mp
->mnt_flag
|= MNT_DOVOLFS
;
331 if (VFSTOVCB(mp
)->vcbSigWord
== kHFSSigWord
) {
332 /* HFS volumes only want roman-encoded names: */
333 mp
->mnt_flag
|= MNT_FIXEDSCRIPTENCODING
;
335 (void) copyinstr(path
, mp
->mnt_stat
.f_mntonname
, MNAMELEN
-1, &size
);
336 bzero(mp
->mnt_stat
.f_mntonname
+ size
, MNAMELEN
- size
);
337 (void) copyinstr(args
.fspec
, mp
->mnt_stat
.f_mntfromname
, MNAMELEN
- 1, &size
);
338 bzero(mp
->mnt_stat
.f_mntfromname
+ size
, MNAMELEN
- size
);
339 (void)hfs_statfs(mp
, &mp
->mnt_stat
, p
);
348 /* Change fs mount parameters */
350 hfs_changefs(mp
, args
, p
)
352 struct hfs_mount_args
*args
;
356 int namefix
, permfix
, permswitch
;
357 struct hfsmount
*hfsmp
;
360 register struct vnode
*vp
, *nvp
;
361 hfs_to_unicode_func_t get_unicode_func
;
362 unicode_to_hfs_func_t get_hfsname_func
;
363 struct cat_desc cndesc
;
364 struct cat_attr cnattr
;
367 hfsmp
= VFSTOHFS(mp
);
368 vcb
= HFSTOVCB(hfsmp
);
369 permswitch
= (((hfsmp
->hfs_unknownpermissions
!= 0) && ((mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) == 0)) ||
370 ((hfsmp
->hfs_unknownpermissions
== 0) && ((mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) != 0)));
371 /* The root filesystem must operate with actual permissions: */
372 if (permswitch
&& (mp
->mnt_flag
& MNT_ROOTFS
) && (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
)) {
373 mp
->mnt_flag
&= ~MNT_UNKNOWNPERMISSIONS
; /* Just say "No". */
376 hfsmp
->hfs_unknownpermissions
= ((mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) != 0);
377 namefix
= permfix
= 0;
379 /* Change the timezone (Note: this affects all hfs volumes and hfs+ volume create dates) */
380 if (args
->hfs_timezone
.tz_minuteswest
!= VNOVAL
) {
381 gTimeZone
= args
->hfs_timezone
;
384 /* Change the default uid, gid and/or mask */
385 if ((args
->hfs_uid
!= (uid_t
)VNOVAL
) && (hfsmp
->hfs_uid
!= args
->hfs_uid
)) {
386 hfsmp
->hfs_uid
= args
->hfs_uid
;
387 if (HFSTOVCB(hfsmp
)->vcbSigWord
== kHFSPlusSigWord
)
390 if ((args
->hfs_gid
!= (gid_t
)VNOVAL
) && (hfsmp
->hfs_gid
!= args
->hfs_gid
)) {
391 hfsmp
->hfs_gid
= args
->hfs_gid
;
392 if (HFSTOVCB(hfsmp
)->vcbSigWord
== kHFSPlusSigWord
)
395 if (args
->hfs_mask
!= (mode_t
)VNOVAL
) {
396 if (hfsmp
->hfs_dir_mask
!= (args
->hfs_mask
& ALLPERMS
)) {
397 hfsmp
->hfs_dir_mask
= args
->hfs_mask
& ALLPERMS
;
398 hfsmp
->hfs_file_mask
= args
->hfs_mask
& ALLPERMS
;
399 if ((args
->flags
!= VNOVAL
) && (args
->flags
& HFSFSMNT_NOXONFILES
))
400 hfsmp
->hfs_file_mask
= (args
->hfs_mask
& DEFFILEMODE
);
401 if (HFSTOVCB(hfsmp
)->vcbSigWord
== kHFSPlusSigWord
)
406 /* Change the hfs encoding value (hfs only) */
407 if ((HFSTOVCB(hfsmp
)->vcbSigWord
== kHFSSigWord
) &&
408 (hfsmp
->hfs_encoding
!= (u_long
)VNOVAL
) &&
409 (hfsmp
->hfs_encoding
!= args
->hfs_encoding
)) {
411 retval
= hfs_getconverter(args
->hfs_encoding
, &get_unicode_func
, &get_hfsname_func
);
416 * Connect the new hfs_get_unicode converter but leave
417 * the old hfs_get_hfsname converter in place so that
418 * we can lookup existing vnodes to get their correctly
421 * When we're all finished, we can then connect the new
422 * hfs_get_hfsname converter and release our interest
423 * in the old converters.
425 hfsmp
->hfs_get_unicode
= get_unicode_func
;
426 old_encoding
= hfsmp
->hfs_encoding
;
427 hfsmp
->hfs_encoding
= args
->hfs_encoding
;
431 if (!(namefix
|| permfix
|| permswitch
))
435 * For each active vnode fix things that changed
437 * Note that we can visit a vnode more than once
438 * and we can race with fsync.
440 simple_lock(&mntvnode_slock
);
442 for (vp
= mp
->mnt_vnodelist
.lh_first
; vp
!= NULL
; vp
= nvp
) {
444 * If the vnode that we are about to fix is no longer
445 * associated with this mount point, start over.
447 if (vp
->v_mount
!= mp
)
450 simple_lock(&vp
->v_interlock
);
451 nvp
= vp
->v_mntvnodes
.le_next
;
452 if (vp
->v_flag
& VSYSTEM
) {
453 simple_unlock(&vp
->v_interlock
);
456 simple_unlock(&mntvnode_slock
);
457 retval
= vget(vp
, LK_EXCLUSIVE
| LK_NOWAIT
| LK_INTERLOCK
, p
);
459 simple_lock(&mntvnode_slock
);
460 if (retval
== ENOENT
)
467 retval
= cat_lookup(hfsmp
, &cp
->c_desc
, 0, &cndesc
, &cnattr
, NULL
);
468 /* If we couldn't find this guy skip to the next one */
473 simple_lock(&mntvnode_slock
);
477 if (permswitch
|| permfix
) {
478 cp
->c_uid
= cnattr
.ca_uid
;
479 cp
->c_gid
= cnattr
.ca_gid
;
480 cp
->c_mode
= cnattr
.ca_mode
;
484 * If we're switching name converters then...
485 * Remove the existing entry from the namei cache.
486 * Update name to one based on new encoder.
490 replace_desc(cp
, &cndesc
);
492 if (cndesc
.cd_cnid
== kHFSRootFolderID
) {
493 strncpy(vcb
->vcbVN
, cp
->c_desc
.cd_nameptr
, NAME_MAX
);
494 cp
->c_desc
.cd_encoding
= hfsmp
->hfs_encoding
;
497 cat_releasedesc(&cndesc
);
500 simple_lock(&mntvnode_slock
);
502 } /* end for (vp...) */
503 simple_unlock(&mntvnode_slock
);
505 * If we're switching name converters we can now
506 * connect the new hfs_get_hfsname converter and
507 * release our interest in the old converters.
510 hfsmp
->hfs_get_hfsname
= get_hfsname_func
;
511 vcb
->volumeNameEncodingHint
= args
->hfs_encoding
;
512 (void) hfs_relconverter(old_encoding
);
520 * Reload all incore data for a filesystem (used after running fsck on
521 * the root filesystem and finding things to fix). The filesystem must
522 * be mounted read-only.
524 * Things to do to update the mount:
525 * invalidate all cached meta-data.
526 * invalidate all inactive vnodes.
527 * invalidate all cached file data.
528 * re-read volume header from disk.
529 * re-load meta-file info (extents, file size).
530 * re-load B-tree header data.
531 * re-read cnode data for all active vnodes.
534 hfs_reload(mountp
, cred
, p
)
535 register struct mount
*mountp
;
539 register struct vnode
*vp
, *nvp
, *devvp
;
544 struct hfsmount
*hfsmp
;
545 struct HFSPlusVolumeHeader
*vhp
;
547 struct filefork
*forkp
;
548 struct cat_desc cndesc
;
550 if ((mountp
->mnt_flag
& MNT_RDONLY
) == 0)
553 hfsmp
= VFSTOHFS(mountp
);
554 vcb
= HFSTOVCB(hfsmp
);
556 if (vcb
->vcbSigWord
== kHFSSigWord
)
557 return (EINVAL
); /* rooting from HFS is not supported! */
560 * Invalidate all cached meta-data.
562 devvp
= hfsmp
->hfs_devvp
;
563 if (vinvalbuf(devvp
, 0, cred
, p
, 0, 0))
564 panic("hfs_reload: dirty1");
565 InvalidateCatalogCache(vcb
);
568 simple_lock(&mntvnode_slock
);
569 for (vp
= mountp
->mnt_vnodelist
.lh_first
; vp
!= NULL
; vp
= nvp
) {
570 if (vp
->v_mount
!= mountp
) {
571 simple_unlock(&mntvnode_slock
);
574 nvp
= vp
->v_mntvnodes
.le_next
;
577 * Invalidate all inactive vnodes.
579 if (vrecycle(vp
, &mntvnode_slock
, p
))
583 * Invalidate all cached file data.
585 simple_lock(&vp
->v_interlock
);
586 simple_unlock(&mntvnode_slock
);
587 if (vget(vp
, LK_EXCLUSIVE
| LK_INTERLOCK
, p
)) {
590 if (vinvalbuf(vp
, 0, cred
, p
, 0, 0))
591 panic("hfs_reload: dirty2");
594 * Re-read cnode data for all active vnodes (non-metadata files).
597 if ((vp
->v_flag
& VSYSTEM
) == 0 && !VNODE_IS_RSRC(vp
)) {
598 struct cat_fork
*datafork
;
599 struct cat_desc desc
;
601 datafork
= cp
->c_datafork
? &cp
->c_datafork
->ff_data
: NULL
;
603 /* lookup by fileID since name could have changed */
604 if ((error
= cat_idlookup(hfsmp
, cp
->c_fileid
, &desc
, &cp
->c_attr
, datafork
))) {
610 /* update cnode's catalog descriptor */
611 (void) replace_desc(cp
, &desc
);
614 simple_lock(&mntvnode_slock
);
616 simple_unlock(&mntvnode_slock
);
619 * Re-read VolumeHeader from disk.
621 sectorsize
= hfsmp
->hfs_phys_block_size
;
623 error
= meta_bread(hfsmp
->hfs_devvp
,
624 (vcb
->hfsPlusIOPosOffset
/ sectorsize
) + HFS_PRI_SECTOR(sectorsize
),
625 sectorsize
, NOCRED
, &bp
);
632 vhp
= (HFSPlusVolumeHeader
*) (bp
->b_data
+ HFS_PRI_OFFSET(sectorsize
));
634 /* Do a quick sanity check */
635 if (SWAP_BE16(vhp
->signature
) != kHFSPlusSigWord
||
636 SWAP_BE16(vhp
->version
) != kHFSPlusVersion
||
637 SWAP_BE32(vhp
->blockSize
) != vcb
->blockSize
) {
642 vcb
->vcbLsMod
= to_bsd_time(SWAP_BE32(vhp
->modifyDate
));
643 vcb
->vcbAtrb
= (UInt16
) SWAP_BE32 (vhp
->attributes
); /* VCB only uses lower 16 bits */
644 vcb
->vcbClpSiz
= SWAP_BE32 (vhp
->rsrcClumpSize
);
645 vcb
->vcbNxtCNID
= SWAP_BE32 (vhp
->nextCatalogID
);
646 vcb
->vcbVolBkUp
= to_bsd_time(SWAP_BE32(vhp
->backupDate
));
647 vcb
->vcbWrCnt
= SWAP_BE32 (vhp
->writeCount
);
648 vcb
->vcbFilCnt
= SWAP_BE32 (vhp
->fileCount
);
649 vcb
->vcbDirCnt
= SWAP_BE32 (vhp
->folderCount
);
650 vcb
->nextAllocation
= SWAP_BE32 (vhp
->nextAllocation
);
651 vcb
->totalBlocks
= SWAP_BE32 (vhp
->totalBlocks
);
652 vcb
->freeBlocks
= SWAP_BE32 (vhp
->freeBlocks
);
653 vcb
->encodingsBitmap
= SWAP_BE64 (vhp
->encodingsBitmap
);
654 bcopy(vhp
->finderInfo
, vcb
->vcbFndrInfo
, sizeof(vhp
->finderInfo
));
655 vcb
->localCreateDate
= SWAP_BE32 (vhp
->createDate
); /* hfs+ create date is in local time */
658 * Re-load meta-file vnode data (extent info, file size, etc).
660 forkp
= VTOF((struct vnode
*)vcb
->extentsRefNum
);
661 for (i
= 0; i
< kHFSPlusExtentDensity
; i
++) {
662 forkp
->ff_extents
[i
].startBlock
=
663 SWAP_BE32 (vhp
->extentsFile
.extents
[i
].startBlock
);
664 forkp
->ff_extents
[i
].blockCount
=
665 SWAP_BE32 (vhp
->extentsFile
.extents
[i
].blockCount
);
667 forkp
->ff_size
= SWAP_BE64 (vhp
->extentsFile
.logicalSize
);
668 forkp
->ff_blocks
= SWAP_BE32 (vhp
->extentsFile
.totalBlocks
);
669 forkp
->ff_clumpsize
= SWAP_BE32 (vhp
->extentsFile
.clumpSize
);
672 forkp
= VTOF((struct vnode
*)vcb
->catalogRefNum
);
673 for (i
= 0; i
< kHFSPlusExtentDensity
; i
++) {
674 forkp
->ff_extents
[i
].startBlock
=
675 SWAP_BE32 (vhp
->catalogFile
.extents
[i
].startBlock
);
676 forkp
->ff_extents
[i
].blockCount
=
677 SWAP_BE32 (vhp
->catalogFile
.extents
[i
].blockCount
);
679 forkp
->ff_size
= SWAP_BE64 (vhp
->catalogFile
.logicalSize
);
680 forkp
->ff_blocks
= SWAP_BE32 (vhp
->catalogFile
.totalBlocks
);
681 forkp
->ff_clumpsize
= SWAP_BE32 (vhp
->catalogFile
.clumpSize
);
684 forkp
= VTOF((struct vnode
*)vcb
->allocationsRefNum
);
685 for (i
= 0; i
< kHFSPlusExtentDensity
; i
++) {
686 forkp
->ff_extents
[i
].startBlock
=
687 SWAP_BE32 (vhp
->allocationFile
.extents
[i
].startBlock
);
688 forkp
->ff_extents
[i
].blockCount
=
689 SWAP_BE32 (vhp
->allocationFile
.extents
[i
].blockCount
);
691 forkp
->ff_size
= SWAP_BE64 (vhp
->allocationFile
.logicalSize
);
692 forkp
->ff_blocks
= SWAP_BE32 (vhp
->allocationFile
.totalBlocks
);
693 forkp
->ff_clumpsize
= SWAP_BE32 (vhp
->allocationFile
.clumpSize
);
699 * Re-load B-tree header data
701 forkp
= VTOF((struct vnode
*)vcb
->extentsRefNum
);
702 if (error
= MacToVFSError( BTReloadData((FCB
*)forkp
) ))
705 forkp
= VTOF((struct vnode
*)vcb
->catalogRefNum
);
706 if (error
= MacToVFSError( BTReloadData((FCB
*)forkp
) ))
709 /* Reload the volume name */
710 if ((error
= cat_idlookup(hfsmp
, kHFSRootFolderID
, &cndesc
, NULL
, NULL
)))
712 vcb
->volumeNameEncodingHint
= cndesc
.cd_encoding
;
713 bcopy(cndesc
.cd_nameptr
, vcb
->vcbVN
, min(255, cndesc
.cd_namelen
));
714 cat_releasedesc(&cndesc
);
716 /* Re-establish private/hidden directory for unlinked files */
717 hfsmp
->hfs_private_metadata_dir
= FindMetaDataDirectory(vcb
);
724 * Common code for mount and mountroot
727 hfs_mountfs(struct vnode
*devvp
, struct mount
*mp
, struct proc
*p
,
728 struct hfs_mount_args
*args
)
731 struct hfsmount
*hfsmp
;
734 HFSMasterDirectoryBlock
*mdbp
;
742 u_int32_t minblksize
;
743 u_int32_t iswritable
;
746 cred
= p
? p
->p_ucred
: NOCRED
;
749 * Disallow multiple mounts of the same device.
750 * Disallow mounting of a device that is currently in use
751 * (except for root, which might share swap device for miniroot).
752 * Flush out any old buffers remaining from a previous use.
754 if ((retval
= vfs_mountedon(devvp
)))
756 if ((vcount(devvp
) > 1) && (devvp
!= rootvp
))
758 if ((retval
= vinvalbuf(devvp
, V_SAVE
, cred
, p
, 0, 0)))
761 ronly
= (mp
->mnt_flag
& MNT_RDONLY
) != 0;
762 if ((retval
= VOP_OPEN(devvp
, ronly
? FREAD
: FREAD
|FWRITE
, FSCRED
, p
)))
768 minblksize
= kHFSBlockSize
;
770 /* Get the real physical block size. */
771 if (VOP_IOCTL(devvp
, DKIOCGETBLOCKSIZE
, (caddr_t
)&blksize
, 0, cred
, p
)) {
775 /* Switch to 512 byte sectors (temporarily) */
777 u_int32_t size512
= 512;
779 if (VOP_IOCTL(devvp
, DKIOCSETBLOCKSIZE
, (caddr_t
)&size512
, FWRITE
, cred
, p
)) {
784 /* Get the number of 512 byte physical blocks. */
785 if (VOP_IOCTL(devvp
, DKIOCGETBLOCKCOUNT
, (caddr_t
)&blkcnt
, 0, cred
, p
)) {
789 /* Compute an accurate disk size (i.e. within 512 bytes) */
790 disksize
= blkcnt
* (u_int64_t
)512;
793 * There are only 31 bits worth of block count in
794 * the buffer cache. So for large volumes a 4K
795 * physical block size is needed.
797 if (blkcnt
> (u_int64_t
)0x000000007fffffff) {
798 minblksize
= blksize
= 4096;
800 /* Now switch to our prefered physical block size. */
802 if (VOP_IOCTL(devvp
, DKIOCSETBLOCKSIZE
, (caddr_t
)&blksize
, FWRITE
, cred
, p
)) {
806 /* Get the count of physical blocks. */
807 if (VOP_IOCTL(devvp
, DKIOCGETBLOCKCOUNT
, (caddr_t
)&blkcnt
, 0, cred
, p
)) {
815 * minblksize is the minimum physical block size
816 * blksize has our prefered physical block size
817 * blkcnt has the total number of physical blocks
819 devvp
->v_specsize
= blksize
;
821 /* cache the IO attributes */
822 if ((retval
= vfs_init_io_attributes(devvp
, mp
))) {
823 printf("hfs_mountfs: vfs_init_io_attributes returned %d\n",
828 if ((retval
= meta_bread(devvp
, HFS_PRI_SECTOR(blksize
), blksize
, cred
, &bp
))) {
831 MALLOC(mdbp
, HFSMasterDirectoryBlock
*, kMDBSize
, M_TEMP
, M_WAITOK
);
832 bcopy(bp
->b_data
+ HFS_PRI_OFFSET(blksize
), mdbp
, kMDBSize
);
836 MALLOC(hfsmp
, struct hfsmount
*, sizeof(struct hfsmount
), M_HFSMNT
, M_WAITOK
);
837 bzero(hfsmp
, sizeof(struct hfsmount
));
839 simple_lock_init(&hfsmp
->hfs_renamelock
);
842 * Init the volume information structure
844 mp
->mnt_data
= (qaddr_t
)hfsmp
;
845 hfsmp
->hfs_mp
= mp
; /* Make VFSTOHFS work */
846 hfsmp
->hfs_vcb
.vcb_hfsmp
= hfsmp
; /* Make VCBTOHFS work */
847 hfsmp
->hfs_raw_dev
= devvp
->v_rdev
;
848 hfsmp
->hfs_devvp
= devvp
;
849 hfsmp
->hfs_phys_block_size
= blksize
;
850 hfsmp
->hfs_phys_block_count
= blkcnt
;
851 hfsmp
->hfs_media_writeable
= 1;
852 hfsmp
->hfs_fs_ronly
= ronly
;
853 hfsmp
->hfs_unknownpermissions
= ((mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) != 0);
854 for (i
= 0; i
< MAXQUOTAS
; i
++)
855 hfsmp
->hfs_qfiles
[i
].qf_vp
= NULLVP
;
858 hfsmp
->hfs_uid
= (args
->hfs_uid
== (uid_t
)VNOVAL
) ? UNKNOWNUID
: args
->hfs_uid
;
859 if (hfsmp
->hfs_uid
== 0xfffffffd) hfsmp
->hfs_uid
= UNKNOWNUID
;
860 hfsmp
->hfs_gid
= (args
->hfs_gid
== (gid_t
)VNOVAL
) ? UNKNOWNGID
: args
->hfs_gid
;
861 if (hfsmp
->hfs_gid
== 0xfffffffd) hfsmp
->hfs_gid
= UNKNOWNGID
;
862 if (args
->hfs_mask
!= (mode_t
)VNOVAL
) {
863 hfsmp
->hfs_dir_mask
= args
->hfs_mask
& ALLPERMS
;
864 if (args
->flags
& HFSFSMNT_NOXONFILES
) {
865 hfsmp
->hfs_file_mask
= (args
->hfs_mask
& DEFFILEMODE
);
867 hfsmp
->hfs_file_mask
= args
->hfs_mask
& ALLPERMS
;
870 hfsmp
->hfs_dir_mask
= UNKNOWNPERMISSIONS
& ALLPERMS
; /* 0777: rwx---rwx */
871 hfsmp
->hfs_file_mask
= UNKNOWNPERMISSIONS
& DEFFILEMODE
; /* 0666: no --x by default? */
873 if ((args
->flags
!= (int)VNOVAL
) && (args
->flags
& HFSFSMNT_WRAPPER
))
876 /* Even w/o explicit mount arguments, MNT_UNKNOWNPERMISSIONS requires setting up uid, gid, and mask: */
877 if (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
878 hfsmp
->hfs_uid
= UNKNOWNUID
;
879 hfsmp
->hfs_gid
= UNKNOWNGID
;
880 hfsmp
->hfs_dir_mask
= UNKNOWNPERMISSIONS
& ALLPERMS
; /* 0777: rwx---rwx */
881 hfsmp
->hfs_file_mask
= UNKNOWNPERMISSIONS
& DEFFILEMODE
; /* 0666: no --x by default? */
885 /* Find out if disk media is writable. */
886 if (VOP_IOCTL(devvp
, DKIOCISWRITABLE
, (caddr_t
)&iswritable
, 0, cred
, p
) == 0) {
888 hfsmp
->hfs_media_writeable
= 1;
890 hfsmp
->hfs_media_writeable
= 0;
893 /* Mount a standard HFS disk */
894 if ((SWAP_BE16(mdbp
->drSigWord
) == kHFSSigWord
) &&
895 (mntwrapper
|| (SWAP_BE16(mdbp
->drEmbedSigWord
) != kHFSPlusSigWord
))) {
896 if (devvp
== rootvp
) {
897 retval
= EINVAL
; /* Cannot root from HFS standard disks */
900 /* HFS disks can only use 512 byte physical blocks */
901 if (blksize
> kHFSBlockSize
) {
902 blksize
= kHFSBlockSize
;
903 if (VOP_IOCTL(devvp
, DKIOCSETBLOCKSIZE
, (caddr_t
)&blksize
, FWRITE
, cred
, p
)) {
907 if (VOP_IOCTL(devvp
, DKIOCGETBLOCKCOUNT
, (caddr_t
)&blkcnt
, 0, cred
, p
)) {
911 devvp
->v_specsize
= blksize
;
912 hfsmp
->hfs_phys_block_size
= blksize
;
913 hfsmp
->hfs_phys_block_count
= blkcnt
;
916 hfsmp
->hfs_encoding
= args
->hfs_encoding
;
917 HFSTOVCB(hfsmp
)->volumeNameEncodingHint
= args
->hfs_encoding
;
919 /* establish the timezone */
920 gTimeZone
= args
->hfs_timezone
;
923 retval
= hfs_getconverter(hfsmp
->hfs_encoding
, &hfsmp
->hfs_get_unicode
,
924 &hfsmp
->hfs_get_hfsname
);
928 retval
= hfs_MountHFSVolume(hfsmp
, mdbp
, p
);
930 (void) hfs_relconverter(hfsmp
->hfs_encoding
);
932 } else /* Mount an HFS Plus disk */ {
933 HFSPlusVolumeHeader
*vhp
;
934 off_t embeddedOffset
;
936 /* Get the embedded Volume Header */
937 if (SWAP_BE16(mdbp
->drEmbedSigWord
) == kHFSPlusSigWord
) {
938 embeddedOffset
= SWAP_BE16(mdbp
->drAlBlSt
) * kHFSBlockSize
;
939 embeddedOffset
+= (u_int64_t
)SWAP_BE16(mdbp
->drEmbedExtent
.startBlock
) *
940 (u_int64_t
)SWAP_BE32(mdbp
->drAlBlkSiz
);
943 * If the embedded volume doesn't start on a block
944 * boundary, then switch the device to a 512-byte
945 * block size so everything will line up on a block
948 if ((embeddedOffset
% blksize
) != 0) {
949 printf("HFS Mount: embedded volume offset not"
950 " a multiple of physical block size (%d);"
951 " switching to 512\n", blksize
);
953 if (VOP_IOCTL(devvp
, DKIOCSETBLOCKSIZE
,
954 (caddr_t
)&blksize
, FWRITE
, cred
, p
)) {
958 if (VOP_IOCTL(devvp
, DKIOCGETBLOCKCOUNT
,
959 (caddr_t
)&blkcnt
, 0, cred
, p
)) {
963 /* XXX do we need to call vfs_init_io_attributes again? */
964 devvp
->v_specsize
= blksize
;
965 /* Note: relative block count adjustment */
966 hfsmp
->hfs_phys_block_count
*=
967 hfsmp
->hfs_phys_block_size
/ blksize
;
968 hfsmp
->hfs_phys_block_size
= blksize
;
971 disksize
= (u_int64_t
)SWAP_BE16(mdbp
->drEmbedExtent
.blockCount
) *
972 (u_int64_t
)SWAP_BE32(mdbp
->drAlBlkSiz
);
974 hfsmp
->hfs_phys_block_count
= disksize
/ blksize
;
976 retval
= meta_bread(devvp
, (embeddedOffset
/ blksize
) +
977 HFS_PRI_SECTOR(blksize
), blksize
, cred
, &bp
);
980 bcopy(bp
->b_data
+ HFS_PRI_OFFSET(blksize
), mdbp
, 512);
983 vhp
= (HFSPlusVolumeHeader
*) mdbp
;
985 } else /* pure HFS+ */ {
987 vhp
= (HFSPlusVolumeHeader
*) mdbp
;
990 (void) hfs_getconverter(0, &hfsmp
->hfs_get_unicode
, &hfsmp
->hfs_get_hfsname
);
992 retval
= hfs_MountHFSPlusVolume(hfsmp
, vhp
, embeddedOffset
, disksize
, p
);
994 * If the backend didn't like our physical blocksize
995 * then retry with physical blocksize of 512.
997 if ((retval
== ENXIO
) && (blksize
> 512) && (blksize
!= minblksize
)) {
998 printf("HFS Mount: could not use physical block size "
999 "(%d) switching to 512\n", blksize
);
1001 if (VOP_IOCTL(devvp
, DKIOCSETBLOCKSIZE
, (caddr_t
)&blksize
, FWRITE
, cred
, p
)) {
1005 if (VOP_IOCTL(devvp
, DKIOCGETBLOCKCOUNT
, (caddr_t
)&blkcnt
, 0, cred
, p
)) {
1009 devvp
->v_specsize
= blksize
;
1010 /* Note: relative block count adjustment (in case this is an embedded volume). */
1011 hfsmp
->hfs_phys_block_count
*= hfsmp
->hfs_phys_block_size
/ blksize
;
1012 hfsmp
->hfs_phys_block_size
= blksize
;
1014 /* Try again with a smaller block size... */
1015 retval
= hfs_MountHFSPlusVolume(hfsmp
, vhp
, embeddedOffset
, disksize
, p
);
1018 (void) hfs_relconverter(0);
1025 mp
->mnt_stat
.f_fsid
.val
[0] = (long)dev
;
1026 mp
->mnt_stat
.f_fsid
.val
[1] = mp
->mnt_vfc
->vfc_typenum
;
1027 mp
->mnt_maxsymlinklen
= 0;
1028 devvp
->v_specflags
|= SI_MOUNTEDON
;
1031 (void) hfs_flushvolumeheader(hfsmp
, MNT_WAIT
, 0);
1041 (void)VOP_CLOSE(devvp
, ronly
? FREAD
: FREAD
|FWRITE
, cred
, p
);
1043 FREE(hfsmp
, M_HFSMNT
);
1044 mp
->mnt_data
= (qaddr_t
)0;
1051 * Make a filesystem operational.
1052 * Nothing to do at the moment.
1056 hfs_start(mp
, flags
, p
)
1066 * unmount system call
1069 hfs_unmount(mp
, mntflags
, p
)
1074 struct hfsmount
*hfsmp
= VFSTOHFS(mp
);
1075 int retval
= E_NONE
;
1081 if (mntflags
& MNT_FORCE
) {
1082 flags
|= FORCECLOSE
;
1086 if ((retval
= hfs_flushfiles(mp
, flags
, p
)) && !force
)
1090 * Flush out the b-trees, volume bitmap and Volume Header
1092 if (hfsmp
->hfs_fs_ronly
== 0) {
1093 retval
= VOP_FSYNC(HFSTOVCB(hfsmp
)->catalogRefNum
, NOCRED
, MNT_WAIT
, p
);
1094 if (retval
&& !force
)
1097 retval
= VOP_FSYNC(HFSTOVCB(hfsmp
)->extentsRefNum
, NOCRED
, MNT_WAIT
, p
);
1098 if (retval
&& !force
)
1101 if (retval
= VOP_FSYNC(hfsmp
->hfs_devvp
, NOCRED
, MNT_WAIT
, p
)) {
1106 /* See if this volume is damaged, is so do not unmount cleanly */
1107 if (HFSTOVCB(hfsmp
)->vcbFlags
& kHFS_DamagedVolume
) {
1108 HFSTOVCB(hfsmp
)->vcbAtrb
&= ~kHFSVolumeUnmountedMask
;
1110 HFSTOVCB(hfsmp
)->vcbAtrb
|= kHFSVolumeUnmountedMask
;
1113 retval
= hfs_flushvolumeheader(hfsmp
, MNT_WAIT
, 0);
1115 HFSTOVCB(hfsmp
)->vcbAtrb
&= ~kHFSVolumeUnmountedMask
;
1117 return (retval
); /* could not flush everything */
1122 * Invalidate our caches and release metadata vnodes
1124 (void) hfsUnmount(hfsmp
, p
);
1126 if (HFSTOVCB(hfsmp
)->vcbSigWord
== kHFSSigWord
)
1127 (void) hfs_relconverter(hfsmp
->hfs_encoding
);
1129 hfsmp
->hfs_devvp
->v_specflags
&= ~SI_MOUNTEDON
;
1130 retval
= VOP_CLOSE(hfsmp
->hfs_devvp
,
1131 hfsmp
->hfs_fs_ronly
? FREAD
: FREAD
|FWRITE
,
1133 if (retval
&& !force
)
1136 vrele(hfsmp
->hfs_devvp
);
1137 FREE(hfsmp
, M_HFSMNT
);
1138 mp
->mnt_data
= (qaddr_t
)0;
1144 * Return the root of a filesystem.
1146 * OUT - vpp, should be locked and vget()'d (to increment usecount and lock)
1155 UInt32 rootObjID
= kRootDirID
;
1157 if ((retval
= VFS_VGET(mp
, &rootObjID
, &nvp
)))
1166 * Do operations associated with quotas
1169 hfs_quotactl(mp
, cmds
, uid
, arg
, p
)
1176 int cmd
, type
, error
;
1179 return (EOPNOTSUPP
);
1182 uid
= p
->p_cred
->p_ruid
;
1183 cmd
= cmds
>> SUBCMDSHIFT
;
1190 if (uid
== p
->p_cred
->p_ruid
)
1194 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
1198 type
= cmds
& SUBCMDMASK
;
1199 if ((u_int
)type
>= MAXQUOTAS
)
1201 if (vfs_busy(mp
, LK_NOWAIT
, 0, p
))
1207 error
= hfs_quotaon(p
, mp
, type
, arg
, UIO_USERSPACE
);
1211 error
= hfs_quotaoff(p
, mp
, type
);
1215 error
= hfs_setquota(mp
, uid
, type
, arg
);
1219 error
= hfs_setuse(mp
, uid
, type
, arg
);
1223 error
= hfs_getquota(mp
, uid
, type
, arg
);
1227 error
= hfs_qsync(mp
);
1231 error
= hfs_quotastat(mp
, type
, arg
);
1245 * Get file system statistics.
1248 hfs_statfs(mp
, sbp
, p
)
1250 register struct statfs
*sbp
;
1253 ExtendedVCB
*vcb
= VFSTOVCB(mp
);
1254 struct hfsmount
*hfsmp
= VFSTOHFS(mp
);
1257 freeCNIDs
= (u_long
)0xFFFFFFFF - (u_long
)vcb
->vcbNxtCNID
;
1259 sbp
->f_bsize
= vcb
->blockSize
;
1260 sbp
->f_iosize
= hfsmp
->hfs_logBlockSize
;
1261 sbp
->f_blocks
= vcb
->totalBlocks
;
1262 sbp
->f_bfree
= hfs_freeblks(hfsmp
, 0);
1263 sbp
->f_bavail
= hfs_freeblks(hfsmp
, 1);
1264 sbp
->f_files
= vcb
->totalBlocks
- 2; /* max files is constrained by total blocks */
1265 sbp
->f_ffree
= MIN(freeCNIDs
, sbp
->f_bavail
);
1268 if (sbp
!= &mp
->mnt_stat
) {
1269 sbp
->f_type
= mp
->mnt_vfc
->vfc_typenum
;
1270 bcopy((caddr_t
)mp
->mnt_stat
.f_mntonname
,
1271 (caddr_t
)&sbp
->f_mntonname
[0], MNAMELEN
);
1272 bcopy((caddr_t
)mp
->mnt_stat
.f_mntfromname
,
1273 (caddr_t
)&sbp
->f_mntfromname
[0], MNAMELEN
);
1280 * Go through the disk queues to initiate sandbagged IO;
1281 * go through the inodes to write those that have been modified;
1282 * initiate the writing of the super block if it has been modified.
1284 * Note: we are always called with the filesystem marked `MPBUSY'.
1287 hfs_sync(mp
, waitfor
, cred
, p
)
1293 struct vnode
*nvp
, *vp
;
1295 struct hfsmount
*hfsmp
;
1297 struct vnode
*meta_vp
[3];
1299 int error
, allerror
= 0;
1302 * During MNT_UPDATE hfs_changefs might be manipulating
1303 * vnodes so back off
1305 if (mp
->mnt_flag
& MNT_UPDATE
)
1308 hfsmp
= VFSTOHFS(mp
);
1309 if (hfsmp
->hfs_fs_ronly
!= 0) {
1310 panic("update: rofs mod");
1314 * Write back each 'modified' vnode
1318 simple_lock(&mntvnode_slock
);
1319 for (vp
= mp
->mnt_vnodelist
.lh_first
; vp
!= NULL
; vp
= nvp
) {
1322 * If the vnode that we are about to sync is no longer
1323 * associated with this mount point, start over.
1325 if (vp
->v_mount
!= mp
) {
1326 simple_unlock(&mntvnode_slock
);
1329 simple_lock(&vp
->v_interlock
);
1330 nvp
= vp
->v_mntvnodes
.le_next
;
1333 if ((vp
->v_flag
& VSYSTEM
) || (vp
->v_type
== VNON
) ||
1334 (((cp
->c_flag
& (C_ACCESS
| C_CHANGE
| C_MODIFIED
| C_UPDATE
)) == 0) &&
1335 (vp
->v_dirtyblkhd
.lh_first
== NULL
) && !(vp
->v_flag
& VHASDIRTY
))) {
1336 simple_unlock(&vp
->v_interlock
);
1337 simple_unlock(&mntvnode_slock
);
1338 simple_lock(&mntvnode_slock
);
1342 simple_unlock(&mntvnode_slock
);
1343 error
= vget(vp
, LK_EXCLUSIVE
| LK_NOWAIT
| LK_INTERLOCK
, p
);
1345 if (error
== ENOENT
)
1347 simple_lock(&mntvnode_slock
);
1351 didhold
= ubc_hold(vp
);
1352 if ((error
= VOP_FSYNC(vp
, cred
, waitfor
, p
))) {
1355 VOP_UNLOCK(vp
, 0, p
);
1359 simple_lock(&mntvnode_slock
);
1362 vcb
= HFSTOVCB(hfsmp
);
1364 meta_vp
[0] = vcb
->extentsRefNum
;
1365 meta_vp
[1] = vcb
->catalogRefNum
;
1366 meta_vp
[2] = vcb
->allocationsRefNum
; /* This is NULL for standard HFS */
1368 /* Now sync our three metadata files */
1369 for (i
= 0; i
< 3; ++i
) {
1372 btvp
= btvp
= meta_vp
[i
];;
1373 if ((btvp
==0) || (btvp
->v_type
== VNON
) || (btvp
->v_mount
!= mp
))
1375 simple_lock(&btvp
->v_interlock
);
1377 if (((cp
->c_flag
& (C_ACCESS
| C_CHANGE
| C_MODIFIED
| C_UPDATE
)) == 0) &&
1378 (btvp
->v_dirtyblkhd
.lh_first
== NULL
) && !(btvp
->v_flag
& VHASDIRTY
)) {
1379 simple_unlock(&btvp
->v_interlock
);
1382 simple_unlock(&mntvnode_slock
);
1383 error
= vget(btvp
, LK_EXCLUSIVE
| LK_NOWAIT
| LK_INTERLOCK
, p
);
1385 simple_lock(&mntvnode_slock
);
1388 if ((error
= VOP_FSYNC(btvp
, cred
, waitfor
, p
)))
1390 VOP_UNLOCK(btvp
, 0, p
);
1392 simple_lock(&mntvnode_slock
);
1395 simple_unlock(&mntvnode_slock
);
1398 * Force stale file system control information to be flushed.
1400 if (vcb
->vcbSigWord
== kHFSSigWord
) {
1401 if ((error
= VOP_FSYNC(hfsmp
->hfs_devvp
, cred
, waitfor
, p
)))
1408 * Write back modified superblock.
1411 if (IsVCBDirty(vcb
)) {
1412 error
= hfs_flushvolumeheader(hfsmp
, waitfor
, 0);
1422 * File handle to vnode
1424 * Have to be really careful about stale file handles:
1425 * - check that the cnode id is valid
1426 * - call hfs_vget() to get the locked cnode
1427 * - check for an unallocated cnode (i_mode == 0)
1428 * - check that the given client host has export rights and return
1429 * those rights via. exflagsp and credanonp
1432 hfs_fhtovp(mp
, fhp
, nam
, vpp
, exflagsp
, credanonp
)
1433 register struct mount
*mp
;
1438 struct ucred
**credanonp
;
1440 struct hfsfid
*hfsfhp
;
1446 hfsfhp
= (struct hfsfid
*)fhp
;
1449 * Get the export permission structure for this <mp, client> tuple.
1451 np
= vfs_export_lookup(mp
, &VFSTOHFS(mp
)->hfs_export
, nam
);
1456 result
= VFS_VGET(mp
, &hfsfhp
->hfsfid_cnid
, &nvp
);
1457 if (result
) return result
;
1458 if (nvp
== NULL
) return ESTALE
;
1460 /* The createtime can be changed by hfs_setattr or hfs_setattrlist.
1461 * For NFS, we are assuming that only if the createtime was moved
1462 * forward would it mean the fileID got reused in that session by
1463 * wrapping. We don't have a volume ID or other unique identifier to
1464 * to use here for a generation ID across reboots, crashes where
1465 * metadata noting lastFileID didn't make it to disk but client has
1466 * it, or volume erasures where fileIDs start over again. Lastly,
1467 * with HFS allowing "wraps" of fileIDs now, this becomes more
1468 * error prone. Future, would be change the "wrap bit" to a unique
1469 * wrap number and use that for generation number. For now do this.
1471 if ((hfsfhp
->hfsfid_gen
< VTOC(nvp
)->c_itime
)) {
1477 *exflagsp
= np
->netc_exflags
;
1478 *credanonp
= &np
->netc_anon
;
1485 * Vnode pointer to File handle
1494 struct hfsfid
*hfsfhp
;
1496 if (ISHFS(VTOVCB(vp
)))
1497 return (EOPNOTSUPP
); /* hfs standard is not exportable */
1500 hfsfhp
= (struct hfsfid
*)fhp
;
1501 hfsfhp
->hfsfid_len
= sizeof(struct hfsfid
);
1502 hfsfhp
->hfsfid_pad
= 0;
1503 hfsfhp
->hfsfid_cnid
= cp
->c_cnid
;
1504 hfsfhp
->hfsfid_gen
= cp
->c_itime
;
1511 * Initial HFS filesystems, done only once.
1515 struct vfsconf
*vfsp
;
1517 static int done
= 0;
1523 hfs_converterinit();
1529 * Allocate Catalog Iterator cache...
1531 (void) InitCatalogCache();
1538 * HFS filesystem related variables.
1541 hfs_sysctl(name
, namelen
, oldp
, oldlenp
, newp
, newlen
, p
)
1550 extern u_int32_t hfs_encodingbias
;
1552 /* all sysctl names at this level are terminal */
1554 return (ENOTDIR
); /* overloaded */
1556 if (name
[0] == HFS_ENCODINGBIAS
)
1557 return (sysctl_int(oldp
, oldlenp
, newp
, newlen
,
1558 &hfs_encodingbias
));
1560 return (EOPNOTSUPP
);
1564 /* This will return a vnode of either a directory or a data vnode based on an object id. If
1565 * it is a file id, its data fork will be returned.
1568 hfs_vget(mp
, ino
, vpp
)
1573 cnid_t cnid
= *(cnid_t
*)ino
;
1575 /* Check for cnids that should't be exported. */
1576 if ((cnid
< kHFSFirstUserCatalogNodeID
)
1577 && (cnid
!= kHFSRootFolderID
&& cnid
!= kHFSRootParentID
))
1579 /* Don't export HFS Private Data dir. */
1580 if (cnid
== VFSTOHFS(mp
)->hfs_privdir_desc
.cd_cnid
)
1583 return (hfs_getcnode(VFSTOHFS(mp
), cnid
, NULL
, 0, NULL
, NULL
, vpp
));
1587 * Flush out all the files in a filesystem.
1590 hfs_flushfiles(struct mount
*mp
, int flags
, struct proc
*p
)
1592 register struct hfsmount
*hfsmp
;
1597 hfsmp
= VFSTOHFS(mp
);
1599 if (mp
->mnt_flag
& MNT_QUOTA
) {
1600 if (error
= vflush(mp
, NULLVP
, SKIPSYSTEM
|flags
))
1602 for (i
= 0; i
< MAXQUOTAS
; i
++) {
1603 if (hfsmp
->hfs_qfiles
[i
].qf_vp
== NULLVP
)
1605 hfs_quotaoff(p
, mp
, i
);
1608 * Here we fall through to vflush again to ensure
1609 * that we have gotten rid of all the system vnodes.
1614 error
= vflush(mp
, NULLVP
, (SKIPSYSTEM
| SKIPSWAP
| flags
));
1615 error
= vflush(mp
, NULLVP
, (SKIPSYSTEM
| flags
));
1621 * Update volume encoding bitmap (HFS Plus only)
1625 hfs_setencodingbits(struct hfsmount
*hfsmp
, u_int32_t encoding
)
1627 #define kIndexMacUkrainian 48 /* MacUkrainian encoding is 152 */
1628 #define kIndexMacFarsi 49 /* MacFarsi encoding is 140 */
1633 case kTextEncodingMacUkrainian
:
1634 index
= kIndexMacUkrainian
;
1636 case kTextEncodingMacFarsi
:
1637 index
= kIndexMacFarsi
;
1645 HFSTOVCB(hfsmp
)->encodingsBitmap
|= (1 << index
);
1646 HFSTOVCB(hfsmp
)->vcbFlags
|= 0xFF00;
1651 * Update volume stats
1655 hfs_volupdate(struct hfsmount
*hfsmp
, enum volop op
, int inroot
)
1659 vcb
= HFSTOVCB(hfsmp
);
1660 vcb
->vcbFlags
|= 0xFF00;
1661 vcb
->vcbLsMod
= time
.tv_sec
;
1667 if (vcb
->vcbDirCnt
!= 0xFFFFFFFF)
1669 if (inroot
&& vcb
->vcbNmRtDirs
!= 0xFFFF)
1673 if (vcb
->vcbDirCnt
!= 0)
1675 if (inroot
&& vcb
->vcbNmRtDirs
!= 0xFFFF)
1679 if (vcb
->vcbFilCnt
!= 0xFFFFFFFF)
1681 if (inroot
&& vcb
->vcbNmFls
!= 0xFFFF)
1685 if (vcb
->vcbFilCnt
!= 0)
1687 if (inroot
&& vcb
->vcbNmFls
!= 0xFFFF)
1696 hfs_flushMDB(struct hfsmount
*hfsmp
, int waitfor
, int altflush
)
1698 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
1699 struct filefork
*fp
;
1700 HFSMasterDirectoryBlock
*mdb
;
1701 struct buf
*bp
= NULL
;
1706 sectorsize
= hfsmp
->hfs_phys_block_size
;
1708 retval
= bread(hfsmp
->hfs_devvp
, HFS_PRI_SECTOR(sectorsize
), sectorsize
, NOCRED
, &bp
);
1715 DBG_ASSERT(bp
!= NULL
);
1716 DBG_ASSERT(bp
->b_data
!= NULL
);
1717 DBG_ASSERT(bp
->b_bcount
== size
);
1719 mdb
= (HFSMasterDirectoryBlock
*)(bp
->b_data
+ HFS_PRI_OFFSET(sectorsize
));
1721 mdb
->drCrDate
= SWAP_BE32 (UTCToLocal(to_hfs_time(vcb
->vcbCrDate
)));
1722 mdb
->drLsMod
= SWAP_BE32 (UTCToLocal(to_hfs_time(vcb
->vcbLsMod
)));
1723 mdb
->drAtrb
= SWAP_BE16 (vcb
->vcbAtrb
);
1724 mdb
->drNmFls
= SWAP_BE16 (vcb
->vcbNmFls
);
1725 mdb
->drAllocPtr
= SWAP_BE16 (vcb
->nextAllocation
);
1726 mdb
->drClpSiz
= SWAP_BE32 (vcb
->vcbClpSiz
);
1727 mdb
->drNxtCNID
= SWAP_BE32 (vcb
->vcbNxtCNID
);
1728 mdb
->drFreeBks
= SWAP_BE16 (vcb
->freeBlocks
);
1730 namelen
= strlen(vcb
->vcbVN
);
1731 retval
= utf8_to_hfs(vcb
, namelen
, vcb
->vcbVN
, mdb
->drVN
);
1732 /* Retry with MacRoman in case that's how it was exported. */
1734 retval
= utf8_to_mac_roman(namelen
, vcb
->vcbVN
, mdb
->drVN
);
1736 mdb
->drVolBkUp
= SWAP_BE32 (UTCToLocal(to_hfs_time(vcb
->vcbVolBkUp
)));
1737 mdb
->drWrCnt
= SWAP_BE32 (vcb
->vcbWrCnt
);
1738 mdb
->drNmRtDirs
= SWAP_BE16 (vcb
->vcbNmRtDirs
);
1739 mdb
->drFilCnt
= SWAP_BE32 (vcb
->vcbFilCnt
);
1740 mdb
->drDirCnt
= SWAP_BE32 (vcb
->vcbDirCnt
);
1742 bcopy(vcb
->vcbFndrInfo
, mdb
->drFndrInfo
, sizeof(mdb
->drFndrInfo
));
1744 fp
= VTOF(vcb
->extentsRefNum
);
1745 mdb
->drXTExtRec
[0].startBlock
= SWAP_BE16 (fp
->ff_extents
[0].startBlock
);
1746 mdb
->drXTExtRec
[0].blockCount
= SWAP_BE16 (fp
->ff_extents
[0].blockCount
);
1747 mdb
->drXTExtRec
[1].startBlock
= SWAP_BE16 (fp
->ff_extents
[1].startBlock
);
1748 mdb
->drXTExtRec
[1].blockCount
= SWAP_BE16 (fp
->ff_extents
[1].blockCount
);
1749 mdb
->drXTExtRec
[2].startBlock
= SWAP_BE16 (fp
->ff_extents
[2].startBlock
);
1750 mdb
->drXTExtRec
[2].blockCount
= SWAP_BE16 (fp
->ff_extents
[2].blockCount
);
1751 mdb
->drXTFlSize
= SWAP_BE32 (fp
->ff_blocks
* vcb
->blockSize
);
1752 mdb
->drXTClpSiz
= SWAP_BE32 (fp
->ff_clumpsize
);
1754 fp
= VTOF(vcb
->catalogRefNum
);
1755 mdb
->drCTExtRec
[0].startBlock
= SWAP_BE16 (fp
->ff_extents
[0].startBlock
);
1756 mdb
->drCTExtRec
[0].blockCount
= SWAP_BE16 (fp
->ff_extents
[0].blockCount
);
1757 mdb
->drCTExtRec
[1].startBlock
= SWAP_BE16 (fp
->ff_extents
[1].startBlock
);
1758 mdb
->drCTExtRec
[1].blockCount
= SWAP_BE16 (fp
->ff_extents
[1].blockCount
);
1759 mdb
->drCTExtRec
[2].startBlock
= SWAP_BE16 (fp
->ff_extents
[2].startBlock
);
1760 mdb
->drCTExtRec
[2].blockCount
= SWAP_BE16 (fp
->ff_extents
[2].blockCount
);
1761 mdb
->drCTFlSize
= SWAP_BE32 (fp
->ff_blocks
* vcb
->blockSize
);
1762 mdb
->drCTClpSiz
= SWAP_BE32 (fp
->ff_clumpsize
);
1764 /* If requested, flush out the alternate MDB */
1766 struct buf
*alt_bp
= NULL
;
1769 altIDSector
= HFS_ALT_SECTOR(sectorsize
, hfsmp
->hfs_phys_block_count
);
1771 if (meta_bread(hfsmp
->hfs_devvp
, altIDSector
, sectorsize
, NOCRED
, &alt_bp
) == 0) {
1772 bcopy(mdb
, alt_bp
->b_data
+ HFS_ALT_OFFSET(sectorsize
), kMDBSize
);
1773 (void) VOP_BWRITE(alt_bp
);
1778 if (waitfor
!= MNT_WAIT
)
1781 retval
= VOP_BWRITE(bp
);
1783 MarkVCBClean( vcb
);
1791 hfs_flushvolumeheader(struct hfsmount
*hfsmp
, int waitfor
, int altflush
)
1793 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
1794 struct filefork
*fp
;
1795 HFSPlusVolumeHeader
*volumeHeader
;
1803 if (vcb
->vcbSigWord
== kHFSSigWord
)
1804 return hfs_flushMDB(hfsmp
, waitfor
, altflush
);
1808 sectorsize
= hfsmp
->hfs_phys_block_size
;
1809 priIDSector
= (vcb
->hfsPlusIOPosOffset
/ sectorsize
) +
1810 HFS_PRI_SECTOR(sectorsize
);
1812 retval
= meta_bread(hfsmp
->hfs_devvp
, priIDSector
, sectorsize
, NOCRED
, &bp
);
1819 volumeHeader
= (HFSPlusVolumeHeader
*)((char *)bp
->b_data
+ HFS_PRI_OFFSET(sectorsize
));
1822 * For embedded HFS+ volumes, update create date if it changed
1823 * (ie from a setattrlist call)
1825 if ((vcb
->hfsPlusIOPosOffset
!= 0) &&
1826 (SWAP_BE32 (volumeHeader
->createDate
) != vcb
->localCreateDate
)) {
1828 HFSMasterDirectoryBlock
*mdb
;
1830 retval
= meta_bread(hfsmp
->hfs_devvp
, HFS_PRI_SECTOR(sectorsize
),
1831 sectorsize
, NOCRED
, &bp2
);
1837 mdb
= (HFSMasterDirectoryBlock
*)(bp2
->b_data
+
1838 HFS_PRI_OFFSET(sectorsize
));
1840 if ( SWAP_BE32 (mdb
->drCrDate
) != vcb
->localCreateDate
)
1842 mdb
->drCrDate
= SWAP_BE32 (vcb
->localCreateDate
); /* pick up the new create date */
1844 (void) VOP_BWRITE(bp2
); /* write out the changes */
1848 brelse(bp2
); /* just release it */
1853 /* Note: only update the lower 16 bits worth of attributes */
1854 volumeHeader
->attributes
= SWAP_BE32 ((SWAP_BE32 (volumeHeader
->attributes
) & 0xFFFF0000) + (UInt16
) vcb
->vcbAtrb
);
1855 volumeHeader
->lastMountedVersion
= SWAP_BE32 (kHFSPlusMountVersion
);
1856 volumeHeader
->createDate
= SWAP_BE32 (vcb
->localCreateDate
); /* volume create date is in local time */
1857 volumeHeader
->modifyDate
= SWAP_BE32 (to_hfs_time(vcb
->vcbLsMod
));
1858 volumeHeader
->backupDate
= SWAP_BE32 (to_hfs_time(vcb
->vcbVolBkUp
));
1859 volumeHeader
->fileCount
= SWAP_BE32 (vcb
->vcbFilCnt
);
1860 volumeHeader
->folderCount
= SWAP_BE32 (vcb
->vcbDirCnt
);
1861 volumeHeader
->freeBlocks
= SWAP_BE32 (vcb
->freeBlocks
);
1862 volumeHeader
->nextAllocation
= SWAP_BE32 (vcb
->nextAllocation
);
1863 volumeHeader
->rsrcClumpSize
= SWAP_BE32 (vcb
->vcbClpSiz
);
1864 volumeHeader
->dataClumpSize
= SWAP_BE32 (vcb
->vcbClpSiz
);
1865 volumeHeader
->nextCatalogID
= SWAP_BE32 (vcb
->vcbNxtCNID
);
1866 volumeHeader
->writeCount
= SWAP_BE32 (vcb
->vcbWrCnt
);
1867 volumeHeader
->encodingsBitmap
= SWAP_BE64 (vcb
->encodingsBitmap
);
1869 if (bcmp(vcb
->vcbFndrInfo
, volumeHeader
->finderInfo
, sizeof(volumeHeader
->finderInfo
)) != 0)
1871 bcopy(vcb
->vcbFndrInfo
, volumeHeader
->finderInfo
, sizeof(volumeHeader
->finderInfo
));
1873 /* Sync Extents over-flow file meta data */
1874 fp
= VTOF(vcb
->extentsRefNum
);
1875 for (i
= 0; i
< kHFSPlusExtentDensity
; i
++) {
1876 volumeHeader
->extentsFile
.extents
[i
].startBlock
=
1877 SWAP_BE32 (fp
->ff_extents
[i
].startBlock
);
1878 volumeHeader
->extentsFile
.extents
[i
].blockCount
=
1879 SWAP_BE32 (fp
->ff_extents
[i
].blockCount
);
1881 FTOC(fp
)->c_flag
&= ~C_MODIFIED
;
1882 volumeHeader
->extentsFile
.logicalSize
= SWAP_BE64 (fp
->ff_size
);
1883 volumeHeader
->extentsFile
.totalBlocks
= SWAP_BE32 (fp
->ff_blocks
);
1884 volumeHeader
->extentsFile
.clumpSize
= SWAP_BE32 (fp
->ff_clumpsize
);
1886 /* Sync Catalog file meta data */
1887 fp
= VTOF(vcb
->catalogRefNum
);
1888 for (i
= 0; i
< kHFSPlusExtentDensity
; i
++) {
1889 volumeHeader
->catalogFile
.extents
[i
].startBlock
=
1890 SWAP_BE32 (fp
->ff_extents
[i
].startBlock
);
1891 volumeHeader
->catalogFile
.extents
[i
].blockCount
=
1892 SWAP_BE32 (fp
->ff_extents
[i
].blockCount
);
1894 FTOC(fp
)->c_flag
&= ~C_MODIFIED
;
1895 volumeHeader
->catalogFile
.logicalSize
= SWAP_BE64 (fp
->ff_size
);
1896 volumeHeader
->catalogFile
.totalBlocks
= SWAP_BE32 (fp
->ff_blocks
);
1897 volumeHeader
->catalogFile
.clumpSize
= SWAP_BE32 (fp
->ff_clumpsize
);
1899 /* Sync Allocation file meta data */
1900 fp
= VTOF(vcb
->allocationsRefNum
);
1901 for (i
= 0; i
< kHFSPlusExtentDensity
; i
++) {
1902 volumeHeader
->allocationFile
.extents
[i
].startBlock
=
1903 SWAP_BE32 (fp
->ff_extents
[i
].startBlock
);
1904 volumeHeader
->allocationFile
.extents
[i
].blockCount
=
1905 SWAP_BE32 (fp
->ff_extents
[i
].blockCount
);
1907 FTOC(fp
)->c_flag
&= ~C_MODIFIED
;
1908 volumeHeader
->allocationFile
.logicalSize
= SWAP_BE64 (fp
->ff_size
);
1909 volumeHeader
->allocationFile
.totalBlocks
= SWAP_BE32 (fp
->ff_blocks
);
1910 volumeHeader
->allocationFile
.clumpSize
= SWAP_BE32 (fp
->ff_clumpsize
);
1912 /* If requested, flush out the alternate volume header */
1914 struct buf
*alt_bp
= NULL
;
1917 altIDSector
= (vcb
->hfsPlusIOPosOffset
/ sectorsize
) +
1918 HFS_ALT_SECTOR(sectorsize
, hfsmp
->hfs_phys_block_count
);
1920 if (meta_bread(hfsmp
->hfs_devvp
, altIDSector
, sectorsize
, NOCRED
, &alt_bp
) == 0) {
1921 bcopy(volumeHeader
, alt_bp
->b_data
+ HFS_ALT_OFFSET(sectorsize
), kMDBSize
);
1922 (void) VOP_BWRITE(alt_bp
);
1927 if (waitfor
!= MNT_WAIT
)
1930 retval
= VOP_BWRITE(bp
);
1931 /* When critical data changes, flush the device cache */
1932 if (critical
&& (retval
== 0)) {
1933 (void) VOP_IOCTL(hfsmp
->hfs_devvp
, DKIOCSYNCHRONIZECACHE
,
1934 NULL
, FWRITE
, NOCRED
, current_proc());
1938 vcb
->vcbFlags
&= 0x00FF;
1944 * hfs vfs operations.
1946 struct vfsops hfs_vfsops
= {