2 * Copyright (c) 1999-2000 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-1998 Apple Computer, Inc. All rights reserved.
64 * hfs_vfsops.c -- VFS layer for loadable HFS file system.
67 * 9-Nov-1999 Don Brady Fix error handling in hfs_unmount [2399157].
68 * 9-Sep-1999 Don Brady Clear system file fcbModified flags in hfs_flushvolumeheader/hfs_flushMDB.
69 * 5-Aug-1999 Pat Dirks Moved special HFS flag from f_fsid.val[0][0] to mount flags (#2293117).
70 * 23-Jul-1999 Pat Dirks Added special-case code for root's parent directory in hfs_vget (#2263664).
71 * 9-Jun-1999 Don Brady Fix hfs_mount for reload and read-only downgrade cases.
72 * 2-Jun-1999 Don Brady Fix hfs_statfs to return correct f_files value.
73 * 4-May-1999 Don Brady Remove obsolete loadable module code.
74 * 22-Mar-1999 Don Brady Hide our private meta data in hfs_vget.
75 * 18-May-1999 Don Brady Add hfs_mountroot for HFS Plus rooting.
76 * 22-Mar-1999 Don Brady Hide our private meta data in hfs_vget.
77 * 12-Nov-1998 Pat Dirks Changed hfs_statfs to return volume's actual log. block size (#2286198).
78 * 22-Aug-1998 Scott Roberts Assign uid,gid, and mask for default on objects.
79 * 29-Jul-1998 Pat Dirks Fixed changed hfs_vget() to release complex node when retrying for data fork node.
80 * 27-Jul-1998 Scott Roberts Changes hfs_vget() to return data forks instead of complex.
81 * 14-Jul-1998 CHW Added check for use count of device node in hfs_mountfs
82 * 1-Jul-1998 Don Brady Always set kHFSVolumeUnmountedMask bit of vcb->vcbAtrb in hfs_unmount.
83 * 30-Jun-1998 Don Brady Removed hard-coded EINVAL error in hfs_mountfs (for radar #2249539).
84 * 24-Jun-1998 Don Brady Added setting of timezone to hfs_mount (radar #2226387).
85 * 4-Jun-1998 Don Brady Use VPUT/VRELE macros instead of vput/vrele.
86 * 6-May-1998 Scott Roberts Updated hfs_vget with kernel changes.
87 * 29-Apr-1998 Don Brady Update hfs_statfs to actually fill in statfs fields (radar #2227092).
88 * 23-Apr-1998 Pat Dirks Cleaned up code to call brelse() on errors from bread().
89 * 4/20/1998 Don Brady Remove course-grained hfs metadata locking.
90 * 4/18/1998 Don Brady Add VCB locking.
91 * 4/16/1998 Don Brady hfs_unmount now flushes the volume bitmap. Add b-tree locking to hfs_vget.
92 * 4/8/1998 Don Brady Replace hfs_mdbupdate with hfs_flushvolumeheader and hfs_flushMDB.
93 * 4/8/1998 Don Brady In hfs_unmount call hfs_mdbupdate before trashing metafiles!
94 * 4/3/1998 Don Brady Call InitCatalogCache instead of PostInitFS.
95 * 4/1/1998 Don Brady Get rid of gHFSFlags, gReqstVol and gFlushOnlyFlag globals (not used).
96 * 3/30/1998 Don Brady In hfs_unmount use SKIPSYSTEM option on first vflush.
97 * 3/26/1998 Don Brady Changed hfs_unmount to call vflush before calling hfsUnmount.
98 * In hfs_mountfs don't mount hfs-wrapper.
99 * 3/19/1998 Pat Dirks Fixed bug in hfs_mount where device vnode was being
100 * released on way out.
101 * 11/14/1997 Pat Dirks Derived from hfs_vfsops.c
103 #include <sys/param.h>
104 #include <sys/systm.h>
107 #include <sys/namei.h>
108 #include <sys/vnode.h>
109 #include <sys/mount.h>
110 #include <sys/malloc.h>
111 #include <sys/stat.h>
112 #include <sys/lock.h>
113 #include <miscfs/specfs/specdev.h>
114 #include <hfs/hfs_mount.h>
118 #include "hfs_endian.h"
120 #include "hfscommon/headers/FileMgrInternal.h"
121 #include "hfscommon/headers/BTreesInternal.h"
127 int hfs_dbg_load
= 0;
129 int hfs_dbg_utils
= 0;
131 int hfs_dbg_lookup
= 0;
132 int hfs_dbg_tree
= 0;
134 int hfs_dbg_test
= 0;
139 * These come from IOKit/storage/IOMediaBSDClient.h
141 #define DKIOCGETBLOCKSIZE _IOR('d', 24, u_int32_t)
142 #define DKIOCSETBLOCKSIZE _IOW('d', 24, u_int32_t)
143 #define DKIOCGETBLOCKCOUNT _IOR('d', 25, u_int64_t)
146 * HFS File System globals:
148 Ptr gBufferAddress
[BUFFERPTRLISTSIZE
];
149 struct buf
*gBufferHeaderPtr
[BUFFERPTRLISTSIZE
];
150 int gBufferListIndex
;
151 simple_lock_data_t gBufferPtrListLock
;
153 //static char hfs_fs_name[MFSNAMELEN] = "hfs";
157 * Global variables defined in other modules:
159 extern struct vnodeopv_desc hfs_vnodeop_opv_desc
;
161 extern struct vnode
*hfs_vhashget(dev_t dev
, UInt32 nodeID
, UInt8 forkType
);
163 extern OSErr
HFSPlusToHFSExtents( const HFSPlusExtentRecord oldExtents
, HFSExtentRecord newExtents
);
166 extern void inittodr( time_t base
);
167 extern OSErr
GetVolumeNameFromCatalog(ExtendedVCB
*vcb
);
168 extern void CopyCatalogToObjectMeta(struct hfsCatalogInfo
*catInfo
, struct vnode
*vp
, struct hfsfilemeta
*fm
);
169 extern void CopyCatalogToFCB(struct hfsCatalogInfo
*catInfo
, struct vnode
*vp
);
170 extern void hfs_name_CatToMeta(CatalogNodeData
*nodeData
, struct hfsfilemeta
*fm
);
172 int hfs_changefs(struct mount
*mp
, struct hfs_mount_args
*args
, struct proc
*p
);
174 int hfs_reload(struct mount
*mp
, struct ucred
*cred
, struct proc
*p
);
175 int hfs_mountfs(struct vnode
*devvp
, struct mount
*mp
, struct proc
*p
, struct hfs_mount_args
*args
);
176 int hfs_vget(struct mount
*mp
, void *objID
, struct vnode
**vpp
);
177 void hfs_vhashinit();
178 void hfs_converterinit(void);
181 static int hfs_statfs();
185 * Called by vfs_mountroot when mounting HFS Plus as root.
190 extern struct vnode
*rootvp
;
192 struct proc
*p
= current_proc(); /* XXX */
193 struct hfsmount
*hfsmp
;
197 * Get vnode for rootdev.
199 if ((error
= bdevvp(rootdev
, &rootvp
))) {
200 printf("hfs_mountroot: can't setup bdevvp");
203 if ((error
= vfs_rootmountalloc("hfs", "root_device", &mp
)))
205 if ((error
= hfs_mountfs(rootvp
, mp
, p
, NULL
))) {
206 mp
->mnt_vfc
->vfc_refcount
--;
208 _FREE_ZONE(mp
, sizeof (struct mount
), M_MOUNT
);
211 simple_lock(&mountlist_slock
);
212 CIRCLEQ_INSERT_TAIL(&mountlist
, mp
, mnt_list
);
213 simple_unlock(&mountlist_slock
);
216 hfsmp
= VFSTOHFS(mp
);
218 hfsmp
->hfs_uid
= UNKNOWNUID
;
219 hfsmp
->hfs_gid
= UNKNOWNGID
;
220 hfsmp
->hfs_dir_mask
= (S_IRWXU
| S_IRGRP
|S_IXGRP
| S_IROTH
|S_IXOTH
); /* 0755 */
221 hfsmp
->hfs_file_mask
= (S_IRWXU
| S_IRGRP
|S_IXGRP
| S_IROTH
|S_IXOTH
); /* 0755 */
223 (void)hfs_statfs(mp
, &mp
->mnt_stat
, p
);
226 inittodr(to_bsd_time(HFSTOVCB(hfsmp
)->vcbLsMod
));
238 hfs_mount (mp
, path
, data
, ndp
, p
)
239 register struct mount
*mp
;
242 struct nameidata
*ndp
;
245 struct hfsmount
*hfsmp
= NULL
;
247 struct hfs_mount_args args
;
254 if ((retval
= copyin(data
, (caddr_t
)&args
, sizeof(args
))))
258 * If updating, check whether changing from read-only to
259 * read/write; if there is no device name, that's all we do.
261 if (mp
->mnt_flag
& MNT_UPDATE
) {
263 hfsmp
= VFSTOHFS(mp
);
264 if ((hfsmp
->hfs_fs_ronly
== 0) && (mp
->mnt_flag
& MNT_RDONLY
)) {
266 /* use VFS_SYNC to push out System (btree) files */
267 retval
= VFS_SYNC(mp
, MNT_WAIT
, p
->p_ucred
, p
);
268 if (retval
&& ((mp
->mnt_flag
& MNT_FORCE
) == 0))
272 if (mp
->mnt_flag
& MNT_FORCE
)
275 if ((retval
= hfs_flushfiles(mp
, flags
)))
277 hfsmp
->hfs_fs_clean
= 1;
278 hfsmp
->hfs_fs_ronly
= 1;
279 if (HFSTOVCB(hfsmp
)->vcbSigWord
== kHFSPlusSigWord
)
280 retval
= hfs_flushvolumeheader(hfsmp
, MNT_WAIT
);
282 retval
= hfs_flushMDB(hfsmp
, MNT_WAIT
);
284 /* also get the volume bitmap blocks */
286 retval
= VOP_FSYNC(hfsmp
->hfs_devvp
, NOCRED
, MNT_WAIT
, p
);
289 hfsmp
->hfs_fs_clean
= 0;
290 hfsmp
->hfs_fs_ronly
= 0;
295 if ((mp
->mnt_flag
& MNT_RELOAD
) &&
296 (retval
= hfs_reload(mp
, ndp
->ni_cnd
.cn_cred
, p
)))
299 if (hfsmp
->hfs_fs_ronly
&& (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)) {
301 * If upgrade to read-write by non-root, then verify
302 * that user has necessary permissions on the device.
304 if (p
->p_ucred
->cr_uid
!= 0) {
305 devvp
= hfsmp
->hfs_devvp
;
306 vn_lock(devvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
307 if ((retval
= VOP_ACCESS(devvp
, VREAD
| VWRITE
, p
->p_ucred
, p
))) {
308 VOP_UNLOCK(devvp
, 0, p
);
311 VOP_UNLOCK(devvp
, 0, p
);
313 if (HFSTOVCB(hfsmp
)->vcbSigWord
== kHFSPlusSigWord
)
314 retval
= hfs_flushvolumeheader(hfsmp
, MNT_WAIT
);
316 retval
= hfs_flushMDB(hfsmp
, MNT_WAIT
);
318 if (retval
!= E_NONE
)
321 /* only change hfs_fs_ronly after a successfull write */
322 hfsmp
->hfs_fs_ronly
= 0;
323 hfsmp
->hfs_fs_clean
= 0;
326 if ((hfsmp
->hfs_fs_ronly
== 0) &&
327 (HFSTOVCB(hfsmp
)->vcbSigWord
== kHFSPlusSigWord
)) {
328 /* setup private/hidden directory for unlinked files */
329 hfsmp
->hfs_private_metadata_dir
= FindMetaDataDirectory(HFSTOVCB(hfsmp
));
332 if (args
.fspec
== 0) {
334 * Process export requests.
336 return vfs_export(mp
, &hfsmp
->hfs_export
, &args
.export
);
341 * Not an update, or updating the name: look up the name
342 * and verify that it refers to a sensible block device.
344 NDINIT(ndp
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, args
.fspec
, p
);
346 if (retval
!= E_NONE
) {
347 DBG_ERR(("hfs_mount: CAN'T GET DEVICE: %s, %x\n", args
.fspec
, ndp
->ni_vp
->v_rdev
));
353 if (devvp
->v_type
!= VBLK
) {
358 if (major(devvp
->v_rdev
) >= nblkdev
) {
365 * If mount by non-root, then verify that user has necessary
366 * permissions on the device.
368 if (p
->p_ucred
->cr_uid
!= 0) {
370 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0)
371 accessmode
|= VWRITE
;
372 vn_lock(devvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
373 if ((retval
= VOP_ACCESS(devvp
, accessmode
, p
->p_ucred
, p
))) {
377 VOP_UNLOCK(devvp
, 0, p
);
380 if ((mp
->mnt_flag
& MNT_UPDATE
) == 0) {
381 retval
= hfs_mountfs(devvp
, mp
, p
, &args
);
382 if (retval
!= E_NONE
)
385 if (devvp
!= hfsmp
->hfs_devvp
)
386 retval
= EINVAL
; /* needs translation */
388 retval
= hfs_changefs(mp
, &args
, p
);
392 if (retval
!= E_NONE
) {
397 /* Set the mount flag to indicate that we support volfs */
398 mp
->mnt_flag
|= MNT_DOVOLFS
;
399 if (VFSTOVCB(mp
)->vcbSigWord
== kHFSSigWord
) {
400 /* HFS volumes only want roman-encoded names: */
401 mp
->mnt_flag
|= MNT_FIXEDSCRIPTENCODING
;
403 (void) copyinstr(path
, mp
->mnt_stat
.f_mntonname
, MNAMELEN
-1, &size
);
404 bzero(mp
->mnt_stat
.f_mntonname
+ size
, MNAMELEN
- size
);
405 (void) copyinstr(args
.fspec
, mp
->mnt_stat
.f_mntfromname
, MNAMELEN
- 1, &size
);
406 bzero(mp
->mnt_stat
.f_mntfromname
+ size
, MNAMELEN
- size
);
407 (void)hfs_statfs(mp
, &mp
->mnt_stat
, p
);
416 /* change fs mount parameters */
418 hfs_changefs(mp
, args
, p
)
420 struct hfs_mount_args
*args
;
424 int namefix
, permfix
, permswitch
;
425 struct hfsmount
*hfsmp
;
427 mode_t hfs_file_mask
;
429 hfsCatalogInfo catInfo
;
430 register struct vnode
*vp
, *nvp
;
431 hfs_to_unicode_func_t get_unicode_func
;
432 unicode_to_hfs_func_t get_hfsname_func
;
434 hfsmp
= VFSTOHFS(mp
);
435 vcb
= HFSTOVCB(hfsmp
);
436 permswitch
= (((hfsmp
->hfs_unknownpermissions
!= 0) && ((mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) == 0)) ||
437 ((hfsmp
->hfs_unknownpermissions
== 0) && ((mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) != 0)));
438 /* The root filesystem must operate with actual permissions: */
439 if (permswitch
&& (mp
->mnt_flag
& MNT_ROOTFS
) && (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
)) {
440 mp
->mnt_flag
&= ~MNT_UNKNOWNPERMISSIONS
; /* Just say "No". */
443 hfsmp
->hfs_unknownpermissions
= ((mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) != 0);
444 namefix
= permfix
= 0;
446 /* change the timezone (Note: this affects all hfs volumes and hfs+ volume create dates) */
447 if (args
->hfs_timezone
.tz_minuteswest
!= VNOVAL
) {
448 gTimeZone
= args
->hfs_timezone
;
451 /* change the default uid, gid and/or mask */
452 if ((args
->hfs_uid
!= (uid_t
)VNOVAL
) && (hfsmp
->hfs_uid
!= args
->hfs_uid
)) {
453 hfsmp
->hfs_uid
= args
->hfs_uid
;
456 if ((args
->hfs_gid
!= (gid_t
)VNOVAL
) && (hfsmp
->hfs_gid
!= args
->hfs_gid
)) {
457 hfsmp
->hfs_gid
= args
->hfs_gid
;
460 if (args
->hfs_mask
!= (mode_t
)VNOVAL
) {
461 if (hfsmp
->hfs_dir_mask
!= (args
->hfs_mask
& ALLPERMS
)) {
462 hfsmp
->hfs_dir_mask
= args
->hfs_mask
& ALLPERMS
;
463 hfsmp
->hfs_file_mask
= args
->hfs_mask
& ALLPERMS
;
464 if ((args
->flags
!= VNOVAL
) && (args
->flags
& HFSFSMNT_NOXONFILES
))
465 hfsmp
->hfs_file_mask
= (args
->hfs_mask
& DEFFILEMODE
);
470 /* change the hfs encoding value (hfs only) */
471 if ((HFSTOVCB(hfsmp
)->vcbSigWord
== kHFSSigWord
) &&
472 (hfsmp
->hfs_encoding
!= (u_long
)VNOVAL
) &&
473 (hfsmp
->hfs_encoding
!= args
->hfs_encoding
)) {
475 retval
= hfs_getconverter(args
->hfs_encoding
, &get_unicode_func
, &get_hfsname_func
);
476 if (retval
) goto error_exit
;
479 * Connect the new hfs_get_unicode converter but leave
480 * the old hfs_get_hfsname converter in place so that
481 * we can lookup existing vnodes to get their correctly
484 * When we're all finished, we can then connect the new
485 * hfs_get_hfsname converter and release our interest
486 * in the old converters.
488 hfsmp
->hfs_get_unicode
= get_unicode_func
;
493 if (!(namefix
|| permfix
|| permswitch
)) goto exit
;
496 * For each active vnode fix things that changed
498 * Note that we can visit a vnode more than once
499 * and we can race with fsync.
501 simple_lock(&mntvnode_slock
);
503 for (vp
= mp
->mnt_vnodelist
.lh_first
; vp
!= NULL
; vp
= nvp
) {
505 * If the vnode that we are about to fix is no longer
506 * associated with this mount point, start over.
508 if (vp
->v_mount
!= mp
)
511 simple_lock(&vp
->v_interlock
);
512 nvp
= vp
->v_mntvnodes
.le_next
;
513 if (vp
->v_flag
& VSYSTEM
) {
514 simple_unlock(&vp
->v_interlock
);
517 simple_unlock(&mntvnode_slock
);
518 retval
= vget(vp
, LK_EXCLUSIVE
| LK_NOWAIT
| LK_INTERLOCK
, p
);
520 simple_lock(&mntvnode_slock
);
521 if (retval
== ENOENT
)
528 INIT_CATALOGDATA(&catInfo
.nodeData
, 0);
530 catInfo
.hint
= kNoHint
;
531 retval
= hfs_getcatalog(vcb
, H_DIRID(hp
), H_NAME(hp
), hp
->h_meta
->h_namelen
, &catInfo
);
532 /* If we couldn't find this guy skip to the next one */
537 simple_lock(&mntvnode_slock
);
541 H_HINT(hp
) = catInfo
.hint
;
542 if (permswitch
|| (permfix
&& (hp
->h_meta
->h_metaflags
& IN_UNSETACCESS
))) {
543 if ((vcb
->vcbSigWord
== kHFSPlusSigWord
) && (catInfo
.nodeData
.cnd_mode
& IFMT
)) {
544 if (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
546 * Override the permissions as determined by the mount auguments
547 * in ALMOST the same way unset permissions are treated but keep
548 * track of whether or not the file or folder is hfs locked
549 * by leaving the h_pflags field unchanged from what was unpacked
550 * out of the catalog.
552 hp
->h_meta
->h_metaflags
|= IN_UNSETACCESS
;
553 hp
->h_meta
->h_uid
= VTOHFS(vp
)->hfs_uid
;
554 hp
->h_meta
->h_gid
= VTOHFS(vp
)->hfs_gid
;
556 hp
->h_meta
->h_uid
= catInfo
.nodeData
.cnd_ownerID
;
557 hp
->h_meta
->h_gid
= catInfo
.nodeData
.cnd_groupID
;
559 hp
->h_meta
->h_mode
= (mode_t
)catInfo
.nodeData
.cnd_mode
;
562 * Set the permissions as determined by the mount auguments
563 * but keep in account if the file or folder is hfs locked
565 hp
->h_meta
->h_metaflags
|= IN_UNSETACCESS
;
566 hp
->h_meta
->h_uid
= VTOHFS(vp
)->hfs_uid
;
567 hp
->h_meta
->h_gid
= VTOHFS(vp
)->hfs_gid
;
569 /* Default access is full read/write/execute: */
570 hp
->h_meta
->h_mode
&= IFMT
;
571 hp
->h_meta
->h_mode
|= ACCESSPERMS
; /* 0777: rwxrwxrwx */
572 /* ... but no more than that permitted by the mount point's: */
573 if ((hp
->h_meta
->h_mode
& IFMT
) == IFDIR
) {
574 hp
->h_meta
->h_mode
&= IFMT
| VTOHFS(vp
)->hfs_dir_mask
;
576 hp
->h_meta
->h_mode
&= IFMT
| VTOHFS(vp
)->hfs_file_mask
;
582 * If we're switching name converters then...
583 * Remove the existing entry from the namei cache.
584 * Update name to one based on new encoder.
588 hfs_name_CatToMeta(&catInfo
.nodeData
, hp
->h_meta
);
590 if (catInfo
.nodeData
.cnd_nodeID
== kHFSRootFolderID
)
591 strncpy(vcb
->vcbVN
, H_NAME(hp
), NAME_MAX
);
594 CLEAN_CATALOGDATA(&catInfo
.nodeData
);
597 simple_lock(&mntvnode_slock
);
599 } /* end for (vp...) */
600 simple_unlock(&mntvnode_slock
);
605 * If we're switching name converters we can now
606 * connect the new hfs_get_hfsname converter and
607 * release our interest in the old converters.
610 u_long old_encoding
= hfsmp
->hfs_encoding
;
612 hfsmp
->hfs_get_hfsname
= get_hfsname_func
;
613 hfsmp
->hfs_encoding
= args
->hfs_encoding
;
614 vcb
->volumeNameEncodingHint
= args
->hfs_encoding
;
616 (void) hfs_relconverter(old_encoding
);
628 * Reload all incore data for a filesystem (used after running fsck on
629 * the root filesystem and finding things to fix). The filesystem must
630 * be mounted read-only.
632 * Things to do to update the mount:
633 * 1) invalidate all cached meta-data.
634 * 2) re-read volume header from disk.
635 * 3) re-load meta-file info (extents, file size).
636 * 4) re-load B-tree header data.
637 * 5) invalidate all inactive vnodes.
638 * 6) invalidate all cached file data.
639 * 7) re-read hfsnode data for all active vnodes.
642 hfs_reload(mountp
, cred
, p
)
643 register struct mount
*mountp
;
647 register struct vnode
*vp
, *nvp
, *devvp
;
652 struct hfsmount
*hfsmp
;
653 struct HFSPlusVolumeHeader
*vhp
;
657 if ((mountp
->mnt_flag
& MNT_RDONLY
) == 0)
660 hfsmp
= VFSTOHFS(mountp
);
661 vcb
= HFSTOVCB(hfsmp
);
663 if (vcb
->vcbSigWord
== kHFSSigWord
)
664 return (EINVAL
); /* rooting from HFS is not supported! */
667 * Invalidate all cached meta-data.
669 devvp
= hfsmp
->hfs_devvp
;
670 if (vinvalbuf(devvp
, 0, cred
, p
, 0, 0))
671 panic("hfs_reload: dirty1");
672 InvalidateCatalogCache(vcb
);
675 * Re-read VolumeHeader from disk.
677 sectorsize
= hfsmp
->hfs_phys_block_size
;
679 error
= meta_bread(hfsmp
->hfs_devvp
,
680 (vcb
->hfsPlusIOPosOffset
/ sectorsize
) + HFS_PRI_SECTOR(sectorsize
),
681 sectorsize
, NOCRED
, &bp
);
688 vhp
= (HFSPlusVolumeHeader
*) (bp
->b_data
+ HFS_PRI_OFFSET(sectorsize
));
690 if ((ValidVolumeHeader(vhp
) != 0) || (vcb
->blockSize
!= SWAP_BE32 (vhp
->blockSize
))) {
692 return (EIO
); /* XXX needs translation */
695 vcb
->vcbLsMod
= SWAP_BE32 (vhp
->modifyDate
);
696 vcb
->vcbAtrb
= (UInt16
) SWAP_BE32 (vhp
->attributes
); /* VCB only uses lower 16 bits */
697 vcb
->vcbClpSiz
= SWAP_BE32 (vhp
->rsrcClumpSize
);
698 vcb
->vcbNxtCNID
= SWAP_BE32 (vhp
->nextCatalogID
);
699 vcb
->vcbVolBkUp
= SWAP_BE32 (vhp
->backupDate
);
700 vcb
->vcbWrCnt
= SWAP_BE32 (vhp
->writeCount
);
701 vcb
->vcbFilCnt
= SWAP_BE32 (vhp
->fileCount
);
702 vcb
->vcbDirCnt
= SWAP_BE32 (vhp
->folderCount
);
703 vcb
->nextAllocation
= SWAP_BE32 (vhp
->nextAllocation
);
704 vcb
->totalBlocks
= SWAP_BE32 (vhp
->totalBlocks
);
705 vcb
->freeBlocks
= SWAP_BE32 (vhp
->freeBlocks
);
706 vcb
->checkedDate
= SWAP_BE32 (vhp
->checkedDate
);
707 vcb
->encodingsBitmap
= SWAP_BE64 (vhp
->encodingsBitmap
);
708 bcopy(vhp
->finderInfo
, vcb
->vcbFndrInfo
, sizeof(vhp
->finderInfo
));
709 vcb
->localCreateDate
= SWAP_BE32 (vhp
->createDate
); /* hfs+ create date is in local time */
712 * Re-load meta-file vnode data (extent info, file size, etc).
714 fcb
= VTOFCB((struct vnode
*)vcb
->extentsRefNum
);
715 /* bcopy(vhp->extentsFile.extents, fcb->fcbExtents, sizeof(HFSPlusExtentRecord)); */
716 for (i
= 0; i
< kHFSPlusExtentDensity
; i
++) {
717 fcb
->fcbExtents
[i
].startBlock
= SWAP_BE32 (vhp
->extentsFile
.extents
[i
].startBlock
);
718 fcb
->fcbExtents
[i
].blockCount
= SWAP_BE32 (vhp
->extentsFile
.extents
[i
].blockCount
);
720 fcb
->fcbEOF
= SWAP_BE64 (vhp
->extentsFile
.logicalSize
);
721 fcb
->fcbPLen
= SWAP_BE32 (vhp
->extentsFile
.totalBlocks
) * vcb
->blockSize
;
722 fcb
->fcbClmpSize
= SWAP_BE32 (vhp
->extentsFile
.clumpSize
);
724 fcb
= VTOFCB((struct vnode
*)vcb
->catalogRefNum
);
725 /* bcopy(vhp->catalogFile.extents, fcb->fcbExtents, sizeof(HFSPlusExtentRecord)); */
726 for (i
= 0; i
< kHFSPlusExtentDensity
; i
++) {
727 fcb
->fcbExtents
[i
].startBlock
= SWAP_BE32 (vhp
->catalogFile
.extents
[i
].startBlock
);
728 fcb
->fcbExtents
[i
].blockCount
= SWAP_BE32 (vhp
->catalogFile
.extents
[i
].blockCount
);
730 fcb
->fcbPLen
= SWAP_BE64 (vhp
->catalogFile
.logicalSize
);
731 fcb
->fcbPLen
= SWAP_BE32 (vhp
->catalogFile
.totalBlocks
) * vcb
->blockSize
;
732 fcb
->fcbClmpSize
= SWAP_BE32 (vhp
->catalogFile
.clumpSize
);
734 fcb
= VTOFCB((struct vnode
*)vcb
->allocationsRefNum
);
735 /* bcopy(vhp->allocationFile.extents, fcb->fcbExtents, sizeof(HFSPlusExtentRecord)); */
736 for (i
= 0; i
< kHFSPlusExtentDensity
; i
++) {
737 fcb
->fcbExtents
[i
].startBlock
= SWAP_BE32 (vhp
->allocationFile
.extents
[i
].startBlock
);
738 fcb
->fcbExtents
[i
].blockCount
= SWAP_BE32 (vhp
->allocationFile
.extents
[i
].blockCount
);
740 fcb
->fcbEOF
= SWAP_BE64 (vhp
->allocationFile
.logicalSize
);
741 fcb
->fcbPLen
= SWAP_BE32 (vhp
->allocationFile
.totalBlocks
) * vcb
->blockSize
;
742 fcb
->fcbClmpSize
= SWAP_BE32 (vhp
->allocationFile
.clumpSize
);
748 * Re-load B-tree header data
750 fcb
= VTOFCB((struct vnode
*)vcb
->extentsRefNum
);
751 if (error
= MacToVFSError( BTReloadData(fcb
) ))
754 fcb
= VTOFCB((struct vnode
*)vcb
->catalogRefNum
);
755 if (error
= MacToVFSError( BTReloadData(fcb
) ))
758 /* Now that the catalog is ready, get the volume name */
759 /* also picks up the create date in GMT */
760 if ((error
= MacToVFSError( GetVolumeNameFromCatalog(vcb
) )))
763 /* Re-establish private/hidden directory for unlinked files */
764 hfsmp
->hfs_private_metadata_dir
= FindMetaDataDirectory(vcb
);
767 simple_lock(&mntvnode_slock
);
768 for (vp
= mountp
->mnt_vnodelist
.lh_first
; vp
!= NULL
; vp
= nvp
) {
769 if (vp
->v_mount
!= mountp
) {
770 simple_unlock(&mntvnode_slock
);
773 nvp
= vp
->v_mntvnodes
.le_next
;
776 * Invalidate all inactive vnodes.
778 if (vrecycle(vp
, &mntvnode_slock
, p
))
782 * Invalidate all cached file data.
784 simple_lock(&vp
->v_interlock
);
785 simple_unlock(&mntvnode_slock
);
786 if (vget(vp
, LK_EXCLUSIVE
| LK_INTERLOCK
, p
)) {
789 if (vinvalbuf(vp
, 0, cred
, p
, 0, 0))
790 panic("hfs_reload: dirty2");
793 * Re-read hfsnode data for all active vnodes (non-metadata files).
796 if ((vp
->v_flag
& VSYSTEM
) == 0) {
797 hfsCatalogInfo catInfo
;
799 /* lookup by fileID since name could have changed */
800 catInfo
.hint
= kNoHint
;
801 INIT_CATALOGDATA(&catInfo
.nodeData
, 0);
803 if ((error
= hfs_getcatalog(vcb
, H_FILEID(hp
), NULL
, -1, &catInfo
))) {
805 CLEAN_CATALOGDATA(&catInfo
.nodeData
);
809 H_HINT(hp
) = catInfo
.hint
;
810 if (hp
->h_meta
->h_metaflags
& IN_LONGNAME
)
811 FREE(H_NAME(hp
), M_TEMP
);
813 hp
->h_meta
->h_namelen
= 0;
814 CopyCatalogToObjectMeta(&catInfo
, vp
, hp
->h_meta
);
815 CopyCatalogToFCB(&catInfo
, vp
);
817 CLEAN_CATALOGDATA(&catInfo
.nodeData
);
821 simple_lock(&mntvnode_slock
);
823 simple_unlock(&mntvnode_slock
);
830 * Common code for mount and mountroot
833 hfs_mountfs(struct vnode
*devvp
, struct mount
*mp
, struct proc
*p
, struct hfs_mount_args
*args
)
836 register struct hfsmount
*hfsmp
;
839 HFSMasterDirectoryBlock
*mdbp
;
845 u_int32_t minblksize
;
846 DBG_VFS(("hfs_mountfs: mp = 0x%lX\n", (u_long
)mp
));
849 cred
= p
? p
->p_ucred
: NOCRED
;
851 * Disallow multiple mounts of the same device.
852 * Disallow mounting of a device that is currently in use
853 * (except for root, which might share swap device for miniroot).
854 * Flush out any old buffers remaining from a previous use.
856 if ((retval
= vfs_mountedon(devvp
)))
858 if ((vcount(devvp
) > 1) && (devvp
!= rootvp
))
860 if ((retval
= vinvalbuf(devvp
, V_SAVE
, cred
, p
, 0, 0)))
863 ronly
= (mp
->mnt_flag
& MNT_RDONLY
) != 0;
864 DBG_VFS(("hfs_mountfs: opening device...\n"));
865 if ((retval
= VOP_OPEN(devvp
, ronly
? FREAD
: FREAD
|FWRITE
, FSCRED
, p
)))
870 minblksize
= kHFSBlockSize
;
872 /* Get the real physical block size. */
873 if (VOP_IOCTL(devvp
, DKIOCGETBLOCKSIZE
, (caddr_t
)&blksize
, 0, cred
, p
)) {
877 /* Switch to 512 byte sectors (temporarily) */
879 u_int32_t size512
= 512;
881 if (VOP_IOCTL(devvp
, DKIOCSETBLOCKSIZE
, (caddr_t
)&size512
, FWRITE
, cred
, p
)) {
886 /* Get the number of 512 byte physical blocks. */
887 if (VOP_IOCTL(devvp
, DKIOCGETBLOCKCOUNT
, (caddr_t
)&blkcnt
, 0, cred
, p
)) {
891 /* Compute an accurate disk size (i.e. within 512 bytes) */
892 disksize
= blkcnt
* (u_int64_t
)512;
895 * For large volumes use a 4K physical block size.
897 if (blkcnt
> (u_int64_t
)0x000000007fffffff) {
898 minblksize
= blksize
= 4096;
901 /* Now switch to our prefered physical block size. */
903 if (VOP_IOCTL(devvp
, DKIOCSETBLOCKSIZE
, (caddr_t
)&blksize
, FWRITE
, cred
, p
)) {
907 /* Get the count of physical blocks. */
908 if (VOP_IOCTL(devvp
, DKIOCGETBLOCKCOUNT
, (caddr_t
)&blkcnt
, 0, cred
, p
)) {
916 * minblksize is the minimum physical block size
917 * blksize has our prefered physical block size
918 * blkcnt has the total number of physical blocks
921 devvp
->v_specsize
= blksize
;
923 /* cache the IO attributes */
924 if ((retval
= vfs_init_io_attributes(devvp
, mp
))) {
925 printf("hfs_mountfs: vfs_init_io_attributes returned %d\n",
930 if ((retval
= meta_bread(devvp
, HFS_PRI_SECTOR(blksize
), blksize
, cred
, &bp
))) {
933 mdbp
= (HFSMasterDirectoryBlock
*) (bp
->b_data
+ HFS_PRI_OFFSET(blksize
));
935 MALLOC(hfsmp
, struct hfsmount
*, sizeof(struct hfsmount
), M_HFSMNT
, M_WAITOK
);
936 bzero(hfsmp
, sizeof(struct hfsmount
));
938 simple_lock_init(&hfsmp
->hfs_renamelock
);
941 * Init the volume information structure
943 mp
->mnt_data
= (qaddr_t
)hfsmp
;
944 hfsmp
->hfs_mp
= mp
; /* Make VFSTOHFS work */
945 hfsmp
->hfs_vcb
.vcb_hfsmp
= hfsmp
; /* Make VCBTOHFS work */
946 hfsmp
->hfs_raw_dev
= devvp
->v_rdev
;
947 hfsmp
->hfs_devvp
= devvp
;
948 hfsmp
->hfs_phys_block_size
= blksize
;
949 hfsmp
->hfs_phys_block_count
= blkcnt
;
950 hfsmp
->hfs_fs_ronly
= ronly
;
951 hfsmp
->hfs_unknownpermissions
= ((mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) != 0);
953 hfsmp
->hfs_uid
= (args
->hfs_uid
== (uid_t
)VNOVAL
) ? UNKNOWNUID
: args
->hfs_uid
;
954 if (hfsmp
->hfs_uid
== 0xfffffffd) hfsmp
->hfs_uid
= UNKNOWNUID
;
955 hfsmp
->hfs_gid
= (args
->hfs_gid
== (gid_t
)VNOVAL
) ? UNKNOWNGID
: args
->hfs_gid
;
956 if (hfsmp
->hfs_gid
== 0xfffffffd) hfsmp
->hfs_gid
= UNKNOWNGID
;
957 if (args
->hfs_mask
!= (mode_t
)VNOVAL
) {
958 hfsmp
->hfs_dir_mask
= args
->hfs_mask
& ALLPERMS
;
959 if (args
->flags
& HFSFSMNT_NOXONFILES
) {
960 hfsmp
->hfs_file_mask
= (args
->hfs_mask
& DEFFILEMODE
);
962 hfsmp
->hfs_file_mask
= args
->hfs_mask
& ALLPERMS
;
965 hfsmp
->hfs_dir_mask
= UNKNOWNPERMISSIONS
& ALLPERMS
; /* 0777: rwx---rwx */
966 hfsmp
->hfs_file_mask
= UNKNOWNPERMISSIONS
& DEFFILEMODE
; /* 0666: no --x by default? */
969 /* Even w/o explicit mount arguments, MNT_UNKNOWNPERMISSIONS requires setting up uid, gid, and mask: */
970 if (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
971 hfsmp
->hfs_uid
= UNKNOWNUID
;
972 hfsmp
->hfs_gid
= UNKNOWNGID
;
973 hfsmp
->hfs_dir_mask
= UNKNOWNPERMISSIONS
& ALLPERMS
; /* 0777: rwx---rwx */
974 hfsmp
->hfs_file_mask
= UNKNOWNPERMISSIONS
& DEFFILEMODE
; /* 0666: no --x by default? */
978 /* Mount a standard HFS disk */
979 if ((SWAP_BE16(mdbp
->drSigWord
) == kHFSSigWord
) &&
980 (SWAP_BE16(mdbp
->drEmbedSigWord
) != kHFSPlusSigWord
)) {
981 if (devvp
== rootvp
) {
982 retval
= EINVAL
; /* Cannot root from HFS standard disks */
985 /* HFS disks can only use 512 byte physical blocks */
986 if (blksize
> kHFSBlockSize
) {
987 blksize
= kHFSBlockSize
;
988 if (VOP_IOCTL(devvp
, DKIOCSETBLOCKSIZE
, (caddr_t
)&blksize
, FWRITE
, cred
, p
)) {
992 if (VOP_IOCTL(devvp
, DKIOCGETBLOCKCOUNT
, (caddr_t
)&blkcnt
, 0, cred
, p
)) {
996 /* XXX do we need to call vfs_init_io_attributes again ? */
997 devvp
->v_specsize
= blksize
;
998 hfsmp
->hfs_phys_block_size
= blksize
;
999 hfsmp
->hfs_phys_block_count
= blkcnt
;
1002 hfsmp
->hfs_encoding
= args
->hfs_encoding
;
1003 HFSTOVCB(hfsmp
)->volumeNameEncodingHint
= args
->hfs_encoding
;
1005 /* establish the timezone */
1006 gTimeZone
= args
->hfs_timezone
;
1009 retval
= hfs_getconverter(hfsmp
->hfs_encoding
, &hfsmp
->hfs_get_unicode
, &hfsmp
->hfs_get_hfsname
);
1013 retval
= hfs_MountHFSVolume(hfsmp
, mdbp
, p
);
1015 (void) hfs_relconverter(hfsmp
->hfs_encoding
);
1017 } else /* Mount an HFS Plus disk */ {
1018 HFSPlusVolumeHeader
*vhp
;
1019 off_t embeddedOffset
;
1021 /* Get the embedded Volume Header */
1022 if (SWAP_BE16(mdbp
->drEmbedSigWord
) == kHFSPlusSigWord
) {
1023 embeddedOffset
= SWAP_BE16(mdbp
->drAlBlSt
) * kHFSBlockSize
;
1024 embeddedOffset
+= (u_int64_t
)SWAP_BE16(mdbp
->drEmbedExtent
.startBlock
) *
1025 (u_int64_t
)SWAP_BE32(mdbp
->drAlBlkSiz
);
1027 disksize
= (u_int64_t
)SWAP_BE16(mdbp
->drEmbedExtent
.blockCount
) *
1028 (u_int64_t
)SWAP_BE32(mdbp
->drAlBlkSiz
);
1030 hfsmp
->hfs_phys_block_count
= disksize
/ blksize
;
1037 * If the embedded volume doesn't start on a block
1038 * boundary, then switch the device to a 512-byte
1039 * block size so everything will line up on a block
1042 if ((embeddedOffset
% blksize
) != 0) {
1043 printf("HFS Mount: embedded volume offset not"
1044 " a multiple of physical block size (%d);"
1045 " switching to 512\n", blksize
);
1047 if (VOP_IOCTL(devvp
, DKIOCSETBLOCKSIZE
,
1048 (caddr_t
)&blksize
, FWRITE
, cred
, p
)) {
1052 if (VOP_IOCTL(devvp
, DKIOCGETBLOCKCOUNT
,
1053 (caddr_t
)&blkcnt
, 0, cred
, p
)) {
1057 /* XXX do we need to call vfs_init_io_attributes again? */
1058 devvp
->v_specsize
= blksize
;
1059 /* Note: relative block count adjustment */
1060 hfsmp
->hfs_phys_block_count
*=
1061 hfsmp
->hfs_phys_block_size
/ blksize
;
1062 hfsmp
->hfs_phys_block_size
= blksize
;
1065 retval
= meta_bread(devvp
, (embeddedOffset
/ blksize
) + HFS_PRI_SECTOR(blksize
),
1066 blksize
, cred
, &bp
);
1069 vhp
= (HFSPlusVolumeHeader
*) (bp
->b_data
+ HFS_PRI_OFFSET(blksize
));
1071 } else /* pure HFS+ */ {
1073 vhp
= (HFSPlusVolumeHeader
*) mdbp
;
1076 (void) hfs_getconverter(0, &hfsmp
->hfs_get_unicode
, &hfsmp
->hfs_get_hfsname
);
1078 retval
= hfs_MountHFSPlusVolume(hfsmp
, vhp
, embeddedOffset
, disksize
, p
);
1080 * If the backend didn't like our physical blocksize
1081 * then retry with physical blocksize of 512.
1083 if ((retval
== ENXIO
) && (blksize
> 512) && (blksize
!= minblksize
)) {
1084 printf("HFS Mount: could not use physical block size "
1085 "(%d) switching to 512\n", blksize
);
1087 if (VOP_IOCTL(devvp
, DKIOCSETBLOCKSIZE
, (caddr_t
)&blksize
, FWRITE
, cred
, p
)) {
1091 if (VOP_IOCTL(devvp
, DKIOCGETBLOCKCOUNT
, (caddr_t
)&blkcnt
, 0, cred
, p
)) {
1095 /* XXX do we need to call vfs_init_io_attributes again ? */
1096 devvp
->v_specsize
= blksize
;
1097 /* Note: relative block count adjustment (in case this is an embedded volume). */
1098 hfsmp
->hfs_phys_block_count
*= hfsmp
->hfs_phys_block_size
/ blksize
;
1099 hfsmp
->hfs_phys_block_size
= blksize
;
1101 /* Try again with a smaller block size... */
1102 retval
= hfs_MountHFSPlusVolume(hfsmp
, vhp
, embeddedOffset
, disksize
, p
);
1105 (void) hfs_relconverter(0);
1115 mp
->mnt_stat
.f_fsid
.val
[0] = (long)dev
;
1116 mp
->mnt_stat
.f_fsid
.val
[1] = mp
->mnt_vfc
->vfc_typenum
;
1117 mp
->mnt_maxsymlinklen
= 0;
1118 devvp
->v_specflags
|= SI_MOUNTEDON
;
1121 hfsmp
->hfs_fs_clean
= 0;
1122 if (HFSTOVCB(hfsmp
)->vcbSigWord
== kHFSPlusSigWord
)
1123 (void) hfs_flushvolumeheader(hfsmp
, MNT_WAIT
);
1125 (void) hfs_flushMDB(hfsmp
, MNT_WAIT
);
1130 DBG_VFS(("hfs_mountfs: exiting with error %d...\n", retval
));
1134 (void)VOP_CLOSE(devvp
, ronly
? FREAD
: FREAD
|FWRITE
, cred
, p
);
1136 FREE(hfsmp
, M_HFSMNT
);
1137 mp
->mnt_data
= (qaddr_t
)0;
1146 * Make a filesystem operational.
1147 * Nothing to do at the moment.
1150 int hfs_start(mp
, flags
, p
)
1155 DBG_FUNC_NAME("hfs_start");
1156 DBG_PRINT_FUNC_NAME();
1163 * unmount system call
1166 hfs_unmount(mp
, mntflags
, p
)
1171 struct hfsmount
*hfsmp
= VFSTOHFS(mp
);
1172 int retval
= E_NONE
;
1176 if (mntflags
& MNT_FORCE
)
1177 flags
|= FORCECLOSE
;
1179 if ((retval
= hfs_flushfiles(mp
, flags
)))
1183 * Flush out the b-trees, volume bitmap and Volume Header
1185 if (hfsmp
->hfs_fs_ronly
== 0) {
1186 retval
= VOP_FSYNC(HFSTOVCB(hfsmp
)->catalogRefNum
, NOCRED
, MNT_WAIT
, p
);
1187 if (retval
&& ((mntflags
& MNT_FORCE
) == 0))
1190 retval
= VOP_FSYNC(HFSTOVCB(hfsmp
)->extentsRefNum
, NOCRED
, MNT_WAIT
, p
);
1191 if (retval
&& ((mntflags
& MNT_FORCE
) == 0))
1194 if (retval
= VOP_FSYNC(hfsmp
->hfs_devvp
, NOCRED
, MNT_WAIT
, p
)) {
1195 if ((mntflags
& MNT_FORCE
) == 0)
1199 /* See if this volume is damaged, is so do not unmount cleanly */
1200 if (HFSTOVCB(hfsmp
)->vcbFlags
& kHFS_DamagedVolume
) {
1201 hfsmp
->hfs_fs_clean
= 0;
1202 HFSTOVCB(hfsmp
)->vcbAtrb
&= ~kHFSVolumeUnmountedMask
;
1204 hfsmp
->hfs_fs_clean
= 1;
1205 HFSTOVCB(hfsmp
)->vcbAtrb
|= kHFSVolumeUnmountedMask
;
1207 if (HFSTOVCB(hfsmp
)->vcbSigWord
== kHFSPlusSigWord
)
1208 retval
= hfs_flushvolumeheader(hfsmp
, MNT_WAIT
);
1210 retval
= hfs_flushMDB(hfsmp
, MNT_WAIT
);
1213 hfsmp
->hfs_fs_clean
= 0;
1214 HFSTOVCB(hfsmp
)->vcbAtrb
&= ~kHFSVolumeUnmountedMask
;
1215 if ((mntflags
& MNT_FORCE
) == 0)
1216 return (retval
); /* could not flush everything */
1221 * Invalidate our caches and release metadata vnodes
1223 (void) hfsUnmount(hfsmp
, p
);
1225 if (HFSTOVCB(hfsmp
)->vcbSigWord
== kHFSSigWord
)
1226 (void) hfs_relconverter(hfsmp
->hfs_encoding
);
1228 hfsmp
->hfs_devvp
->v_specflags
&= ~SI_MOUNTEDON
;
1229 retval
= VOP_CLOSE(hfsmp
->hfs_devvp
, hfsmp
->hfs_fs_ronly
? FREAD
: FREAD
|FWRITE
,
1231 vrele(hfsmp
->hfs_devvp
);
1233 FREE(hfsmp
, M_HFSMNT
);
1234 mp
->mnt_data
= (qaddr_t
)0;
1241 * Return the root of a filesystem.
1243 * OUT - vpp, should be locked and vget()'d (to increment usecount and lock)
1245 int hfs_root(mp
, vpp
)
1251 UInt32 rootObjID
= kRootDirID
;
1253 DBG_FUNC_NAME("hfs_root");
1254 DBG_PRINT_FUNC_NAME();
1256 if ((retval
= VFS_VGET(mp
, &rootObjID
, &nvp
)))
1265 * Do operations associated with quotas
1267 int hfs_quotactl(mp
, cmds
, uid
, arg
, p
)
1274 DBG_FUNC_NAME("hfs_quotactl");
1275 DBG_PRINT_FUNC_NAME();
1277 return (EOPNOTSUPP
);
1282 * Get file system statistics.
1285 hfs_statfs(mp
, sbp
, p
)
1287 register struct statfs
*sbp
;
1290 ExtendedVCB
*vcb
= VFSTOVCB(mp
);
1291 struct hfsmount
*hfsmp
= VFSTOHFS(mp
);
1294 DBG_FUNC_NAME("hfs_statfs");
1295 DBG_PRINT_FUNC_NAME();
1297 freeCNIDs
= (u_long
)0xFFFFFFFF - (u_long
)vcb
->vcbNxtCNID
;
1299 sbp
->f_bsize
= vcb
->blockSize
;
1300 sbp
->f_iosize
= hfsmp
->hfs_logBlockSize
;
1301 sbp
->f_blocks
= vcb
->totalBlocks
;
1302 sbp
->f_bfree
= vcb
->freeBlocks
;
1303 sbp
->f_bavail
= vcb
->freeBlocks
;
1304 sbp
->f_files
= vcb
->totalBlocks
- 2; /* max files is constrained by total blocks */
1305 sbp
->f_ffree
= MIN(freeCNIDs
, vcb
->freeBlocks
);
1308 if (sbp
!= &mp
->mnt_stat
) {
1309 sbp
->f_type
= mp
->mnt_vfc
->vfc_typenum
;
1310 bcopy((caddr_t
)mp
->mnt_stat
.f_mntonname
,
1311 (caddr_t
)&sbp
->f_mntonname
[0], MNAMELEN
);
1312 bcopy((caddr_t
)mp
->mnt_stat
.f_mntfromname
,
1313 (caddr_t
)&sbp
->f_mntfromname
[0], MNAMELEN
);
1320 * Go through the disk queues to initiate sandbagged IO;
1321 * go through the inodes to write those that have been modified;
1322 * initiate the writing of the super block if it has been modified.
1324 * Note: we are always called with the filesystem marked `MPBUSY'.
1326 static int hfs_sync(mp
, waitfor
, cred
, p
)
1332 struct vnode
*nvp
, *vp
;
1334 struct hfsmount
*hfsmp
= VFSTOHFS(mp
);
1336 struct vnode
*meta_vp
[3];
1338 int error
, allerror
= 0;
1340 DBG_FUNC_NAME("hfs_sync");
1341 DBG_PRINT_FUNC_NAME();
1344 * During MNT_UPDATE hfs_changefs might be manipulating
1345 * vnodes so back off
1347 if (mp
->mnt_flag
& MNT_UPDATE
)
1350 hfsmp
= VFSTOHFS(mp
);
1351 if (hfsmp
->hfs_fs_ronly
!= 0) {
1352 panic("update: rofs mod");
1356 * Write back each 'modified' vnode
1360 simple_lock(&mntvnode_slock
);
1361 for (vp
= mp
->mnt_vnodelist
.lh_first
;
1366 * If the vnode that we are about to sync is no longer
1367 * associated with this mount point, start over.
1369 if (vp
->v_mount
!= mp
) {
1370 simple_unlock(&mntvnode_slock
);
1373 simple_lock(&vp
->v_interlock
);
1374 nvp
= vp
->v_mntvnodes
.le_next
;
1377 if ((vp
->v_flag
& VSYSTEM
) || (vp
->v_type
== VNON
) ||
1378 (((hp
->h_nodeflags
& (IN_ACCESS
| IN_CHANGE
| IN_MODIFIED
| IN_UPDATE
)) == 0) &&
1379 (vp
->v_dirtyblkhd
.lh_first
== NULL
) && !(vp
->v_flag
& VHASDIRTY
))) {
1380 simple_unlock(&vp
->v_interlock
);
1381 simple_unlock(&mntvnode_slock
);
1382 simple_lock(&mntvnode_slock
);
1386 simple_unlock(&mntvnode_slock
);
1387 error
= vget(vp
, LK_EXCLUSIVE
| LK_NOWAIT
| LK_INTERLOCK
, p
);
1389 if (error
== ENOENT
)
1391 simple_lock(&mntvnode_slock
);
1395 didhold
= ubc_hold(vp
);
1396 if ((error
= VOP_FSYNC(vp
, cred
, waitfor
, p
))) {
1397 DBG_ERR(("hfs_sync: error %d calling fsync on vnode 0x%X.\n", error
, (u_int
)vp
));
1400 DBG_ASSERT(*((volatile int *)(&(vp
)->v_interlock
))==0);
1401 VOP_UNLOCK(vp
, 0, p
);
1405 simple_lock(&mntvnode_slock
);
1408 vcb
= HFSTOVCB(hfsmp
);
1409 meta_vp
[0] = vcb
->extentsRefNum
;
1410 meta_vp
[1] = vcb
->catalogRefNum
;
1411 meta_vp
[2] = vcb
->allocationsRefNum
; /* This is NULL for standard HFS */
1413 /* Now sync our three metadata files */
1414 for (i
= 0; i
< 3; ++i
) {
1419 if ((btvp
==0) || (btvp
->v_type
== VNON
) || (btvp
->v_mount
!= mp
))
1421 simple_lock(&btvp
->v_interlock
);
1423 if (((hp
->h_nodeflags
& (IN_ACCESS
| IN_CHANGE
| IN_MODIFIED
| IN_UPDATE
)) == 0) &&
1424 (btvp
->v_dirtyblkhd
.lh_first
== NULL
) && !(btvp
->v_flag
& VHASDIRTY
)) {
1425 simple_unlock(&btvp
->v_interlock
);
1428 simple_unlock(&mntvnode_slock
);
1429 error
= vget(btvp
, LK_EXCLUSIVE
| LK_NOWAIT
| LK_INTERLOCK
, p
);
1431 simple_lock(&mntvnode_slock
);
1434 if ((error
= VOP_FSYNC(btvp
, cred
, waitfor
, p
)))
1436 VOP_UNLOCK(btvp
, 0, p
);
1438 simple_lock(&mntvnode_slock
);
1441 simple_unlock(&mntvnode_slock
);
1444 * Force stale file system control information to be flushed.
1446 if (vcb
->vcbSigWord
== kHFSSigWord
) {
1447 if ((error
= VOP_FSYNC(hfsmp
->hfs_devvp
, cred
, waitfor
, p
)))
1451 * Write back modified superblock.
1454 if (IsVCBDirty(vcb
)) {
1455 if (vcb
->vcbSigWord
== kHFSPlusSigWord
)
1456 error
= hfs_flushvolumeheader(hfsmp
, waitfor
);
1458 error
= hfs_flushMDB(hfsmp
, waitfor
);
1469 * File handle to vnode
1471 * Have to be really careful about stale file handles:
1472 * - check that the hfsnode number is valid
1473 * - call hfs_vget() to get the locked hfsnode
1474 * - check for an unallocated hfsnode (i_mode == 0)
1475 * - check that the given client host has export rights and return
1476 * those rights via. exflagsp and credanonp
1479 hfs_fhtovp(mp
, fhp
, nam
, vpp
, exflagsp
, credanonp
)
1480 register struct mount
*mp
;
1485 struct ucred
**credanonp
;
1487 struct hfsfid
*hfsfhp
;
1491 DBG_FUNC_NAME("hfs_fhtovp");
1492 DBG_PRINT_FUNC_NAME();
1495 hfsfhp
= (struct hfsfid
*)fhp
;
1498 * Get the export permission structure for this <mp, client> tuple.
1500 np
= vfs_export_lookup(mp
, &VFSTOHFS(mp
)->hfs_export
, nam
);
1505 result
= VFS_VGET(mp
, &hfsfhp
->hfsfid_cnid
, &nvp
);
1506 if (result
) return result
;
1507 if (nvp
== NULL
) return ESTALE
;
1509 /* The createtime can be changed by hfs_setattr or hfs_setattrlist.
1510 * For NFS, we are assuming that only if the createtime was moved
1511 * forward would it mean the fileID got reused in that session by
1512 * wrapping. We don't have a volume ID or other unique identifier to
1513 * to use here for a generation ID across reboots, crashes where
1514 * metadata noting lastFileID didn't make it to disk but client has
1515 * it, or volume erasures where fileIDs start over again. Lastly,
1516 * with HFS allowing "wraps" of fileIDs now, this becomes more
1517 * error prone. Future, would be change the "wrap bit" to a unique
1518 * wrap number and use that for generation number. For now do this.
1520 if ((hfsfhp
->hfsfid_gen
< VTOH(nvp
)->h_meta
->h_crtime
)) {
1526 *exflagsp
= np
->netc_exflags
;
1527 *credanonp
= &np
->netc_anon
;
1534 * Vnode pointer to File handle
1537 static int hfs_vptofh(vp
, fhp
)
1542 struct hfsfid
*hfsfhp
;
1543 struct proc
*p
= current_proc();
1546 DBG_FUNC_NAME("hfs_vptofh");
1547 DBG_PRINT_FUNC_NAME();
1550 hfsfhp
= (struct hfsfid
*)fhp
;
1552 /* If a file handle is requested for a file on an HFS volume we must be sure
1553 to create the thread record before returning the object id in the filehandle
1554 to make sure the file can be retrieved by fileid if necessary:
1556 if ((vp
->v_type
== VREG
) && ISHFS(VTOVCB(vp
))) {
1557 /* Create a thread record and return the FileID [which is the file's fileNumber] */
1558 /* lock catalog b-tree */
1559 if ((result
= hfs_metafilelocking(VTOHFS(vp
), kHFSCatalogFileID
, LK_EXCLUSIVE
, p
)) != 0) return result
;
1560 result
= hfsCreateFileID(VTOVCB(vp
), H_DIRID(hp
), H_NAME(hp
), H_HINT(hp
), &fileID
);
1561 (void) hfs_metafilelocking(VTOHFS(vp
), kHFSCatalogFileID
, LK_RELEASE
, p
);
1563 DBG_ERR(("hfs_vptofh: error %d on CreateFileIDRef.\n", result
));
1566 DBG_ASSERT(fileID
== H_FILEID(hp
));
1569 hfsfhp
->hfsfid_len
= sizeof(struct hfsfid
);
1570 hfsfhp
->hfsfid_pad
= 0;
1571 hfsfhp
->hfsfid_cnid
= H_FILEID(hp
);
1572 hfsfhp
->hfsfid_gen
= hp
->h_meta
->h_crtime
;
1579 * Initial HFS filesystems, done only once.
1583 struct vfsconf
*vfsp
;
1586 static int done
= 0;
1589 DBG_FUNC_NAME("hfs_init");
1590 DBG_PRINT_FUNC_NAME();
1596 hfs_converterinit();
1598 simple_lock_init (&gBufferPtrListLock
);
1600 for (i
= BUFFERPTRLISTSIZE
- 1; i
>= 0; --i
) {
1601 gBufferAddress
[i
] = NULL
;
1602 gBufferHeaderPtr
[i
] = NULL
;
1604 gBufferListIndex
= 0;
1607 * Allocate Catalog Iterator cache...
1609 err
= InitCatalogCache();
1616 * fast filesystem related variables.
1618 static int hfs_sysctl(name
, namelen
, oldp
, oldlenp
, newp
, newlen
, p
)
1627 DBG_FUNC_NAME("hfs_sysctl");
1628 DBG_PRINT_FUNC_NAME();
1630 return (EOPNOTSUPP
);
1634 /* This will return a vnode of either a directory or a data vnode based on an object id. If
1635 * it is a file id, its data fork will be returned.
1638 hfs_vget(struct mount
*mp
,
1642 struct hfsmount
*hfsmp
;
1644 int retval
= E_NONE
;
1646 DBG_VFS(("hfs_vget: ino = %ld\n", *(UInt32
*)ino
));
1648 /* Check if unmount in progress */
1649 if (mp
->mnt_kern_flag
& MNTK_UNMOUNT
) {
1654 hfsmp
= VFSTOHFS(mp
);
1655 dev
= hfsmp
->hfs_raw_dev
;
1657 /* First check to see if it is in the cache */
1658 *vpp
= hfs_vhashget(dev
, *(UInt32
*)ino
, kDefault
);
1660 /* hide open files that have been deleted */
1662 if ((VTOH(*vpp
)->h_meta
->h_metaflags
& IN_NOEXISTS
) ||
1663 (hfsmp
->hfs_private_metadata_dir
!= 0) &&
1664 (H_DIRID(VTOH(*vpp
)) == hfsmp
->hfs_private_metadata_dir
)) {
1671 /* The vnode is not in the cache, so lets make it */
1674 hfsCatalogInfo catInfo
;
1675 struct proc
*p
= current_proc();
1678 INIT_CATALOGDATA(&catInfo
.nodeData
, 0);
1679 catInfo
.hint
= kNoHint
;
1680 /* Special-case the root's parent directory (DirID = 1) because
1681 it doesn't actually exist in the catalog: */
1682 if ((*vpp
== NULL
) && (*(UInt32
*)ino
== kRootParID
)) {
1683 bzero(&catInfo
, sizeof(catInfo
));
1684 catInfo
.nodeData
.cnd_type
= kCatalogFolderNode
;
1685 catInfo
.nodeData
.cnm_nameptr
= catInfo
.nodeData
.cnm_namespace
;
1686 catInfo
.nodeData
.cnm_namespace
[0] = '/';
1687 catInfo
.nodeData
.cnm_length
= 1;
1688 catInfo
.nodeData
.cnd_nodeID
= kRootParID
;
1689 catInfo
.nodeData
.cnm_parID
= kRootParID
;
1690 catInfo
.nodeData
.cnd_valence
= 1;
1691 catInfo
.nodeData
.cnd_ownerID
= 0;
1692 catInfo
.nodeData
.cnd_groupID
= 0;
1693 catInfo
.nodeData
.cnd_mode
= (S_IFDIR
| S_IRWXU
| S_IRWXG
| S_IRWXO
);
1696 /* lock catalog b-tree */
1697 retval
= hfs_metafilelocking(hfsmp
, kHFSCatalogFileID
, LK_SHARED
, p
);
1698 if (retval
!= E_NONE
) goto Lookup_Err_Exit
;
1700 retval
= hfs_getcatalog(VFSTOVCB(mp
), *(UInt32
*)ino
, NULL
, -1, &catInfo
);
1702 /* unlock catalog b-tree */
1703 (void) hfs_metafilelocking(hfsmp
, kHFSCatalogFileID
, LK_RELEASE
, p
);
1705 if (retval
!= E_NONE
) goto Lookup_Err_Exit
;
1707 /* hide open files that have been deleted */
1708 if ((hfsmp
->hfs_private_metadata_dir
!= 0) &&
1709 (catInfo
.nodeData
.cnm_parID
== hfsmp
->hfs_private_metadata_dir
)) {
1711 goto Lookup_Err_Exit
;
1715 forkType
= (catInfo
.nodeData
.cnd_type
== kCatalogFolderNode
) ? kDirectory
: kDataFork
;
1716 retval
= hfs_vcreate(VFSTOVCB(mp
), &catInfo
, forkType
, vpp
);
1719 CLEAN_CATALOGDATA(&catInfo
.nodeData
);
1722 UBCINFOCHECK("hfs_vget", *vpp
);
1726 /* rember if a parent directory was looked up by CNID */
1727 if (retval
== 0 && ((*vpp
)->v_type
== VDIR
)
1728 && lockstatus(&mp
->mnt_lock
) != LK_SHARED
)
1729 VTOH(*vpp
)->h_nodeflags
|= IN_BYCNID
;
1736 * Flush out all the files in a filesystem.
1739 hfs_flushfiles(struct mount
*mp
, int flags
)
1743 error
= vflush(mp
, NULLVP
, (SKIPSYSTEM
| SKIPSWAP
| flags
));
1744 error
= vflush(mp
, NULLVP
, (SKIPSYSTEM
| flags
));
1749 short hfs_flushMDB(struct hfsmount
*hfsmp
, int waitfor
)
1751 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
1753 HFSMasterDirectoryBlock
*mdb
;
1756 int size
= kMDBSize
; /* 512 */
1759 if (vcb
->vcbSigWord
!= kHFSSigWord
)
1762 DBG_ASSERT(hfsmp
->hfs_devvp
!= NULL
);
1764 retval
= bread(hfsmp
->hfs_devvp
, IOBLKNOFORBLK(kMasterDirectoryBlock
, size
),
1765 IOBYTECCNTFORBLK(kMasterDirectoryBlock
, kMDBSize
, size
), NOCRED
, &bp
);
1767 DBG_VFS((" hfs_flushMDB bread return error! (%d)\n", retval
));
1772 DBG_ASSERT(bp
!= NULL
);
1773 DBG_ASSERT(bp
->b_data
!= NULL
);
1774 DBG_ASSERT(bp
->b_bcount
== size
);
1776 mdb
= (HFSMasterDirectoryBlock
*)((char *)bp
->b_data
+ IOBYTEOFFSETFORBLK(kMasterDirectoryBlock
, size
));
1779 mdb
->drCrDate
= SWAP_BE32 (UTCToLocal(vcb
->vcbCrDate
));
1780 mdb
->drLsMod
= SWAP_BE32 (UTCToLocal(vcb
->vcbLsMod
));
1781 mdb
->drAtrb
= SWAP_BE16 (vcb
->vcbAtrb
);
1782 mdb
->drNmFls
= SWAP_BE16 (vcb
->vcbNmFls
);
1783 mdb
->drAllocPtr
= SWAP_BE16 (vcb
->nextAllocation
);
1784 mdb
->drClpSiz
= SWAP_BE32 (vcb
->vcbClpSiz
);
1785 mdb
->drNxtCNID
= SWAP_BE32 (vcb
->vcbNxtCNID
);
1786 mdb
->drFreeBks
= SWAP_BE16 (vcb
->freeBlocks
);
1788 namelen
= strlen(vcb
->vcbVN
);
1789 retval
= utf8_to_hfs(vcb
, namelen
, vcb
->vcbVN
, mdb
->drVN
);
1790 /* Retry with MacRoman in case that's how it was exported. */
1792 retval
= utf8_to_mac_roman(namelen
, vcb
->vcbVN
, mdb
->drVN
);
1794 mdb
->drVolBkUp
= SWAP_BE32 (UTCToLocal(vcb
->vcbVolBkUp
));
1795 mdb
->drWrCnt
= SWAP_BE32 (vcb
->vcbWrCnt
);
1796 mdb
->drNmRtDirs
= SWAP_BE16 (vcb
->vcbNmRtDirs
);
1797 mdb
->drFilCnt
= SWAP_BE32 (vcb
->vcbFilCnt
);
1798 mdb
->drDirCnt
= SWAP_BE32 (vcb
->vcbDirCnt
);
1800 bcopy(vcb
->vcbFndrInfo
, mdb
->drFndrInfo
, sizeof(mdb
->drFndrInfo
));
1802 fcb
= VTOFCB(vcb
->extentsRefNum
);
1803 /* HFSPlusToHFSExtents(fcb->fcbExtents, mdb->drXTExtRec); */
1804 mdb
->drXTExtRec
[0].startBlock
= SWAP_BE16 (fcb
->fcbExtents
[0].startBlock
);
1805 mdb
->drXTExtRec
[0].blockCount
= SWAP_BE16 (fcb
->fcbExtents
[0].blockCount
);
1806 mdb
->drXTExtRec
[1].startBlock
= SWAP_BE16 (fcb
->fcbExtents
[1].startBlock
);
1807 mdb
->drXTExtRec
[1].blockCount
= SWAP_BE16 (fcb
->fcbExtents
[1].blockCount
);
1808 mdb
->drXTExtRec
[2].startBlock
= SWAP_BE16 (fcb
->fcbExtents
[2].startBlock
);
1809 mdb
->drXTExtRec
[2].blockCount
= SWAP_BE16 (fcb
->fcbExtents
[2].blockCount
);
1811 mdb
->drXTFlSize
= SWAP_BE32 (fcb
->fcbPLen
);
1812 mdb
->drXTClpSiz
= SWAP_BE32 (fcb
->fcbClmpSize
);
1814 fcb
= VTOFCB(vcb
->catalogRefNum
);
1815 /* HFSPlusToHFSExtents(fcb->fcbExtents, mdb->drCTExtRec); */
1816 mdb
->drCTExtRec
[0].startBlock
= SWAP_BE16 (fcb
->fcbExtents
[0].startBlock
);
1817 mdb
->drCTExtRec
[0].blockCount
= SWAP_BE16 (fcb
->fcbExtents
[0].blockCount
);
1818 mdb
->drCTExtRec
[1].startBlock
= SWAP_BE16 (fcb
->fcbExtents
[1].startBlock
);
1819 mdb
->drCTExtRec
[1].blockCount
= SWAP_BE16 (fcb
->fcbExtents
[1].blockCount
);
1820 mdb
->drCTExtRec
[2].startBlock
= SWAP_BE16 (fcb
->fcbExtents
[2].startBlock
);
1821 mdb
->drCTExtRec
[2].blockCount
= SWAP_BE16 (fcb
->fcbExtents
[2].blockCount
);
1823 mdb
->drCTFlSize
= SWAP_BE32 (fcb
->fcbPLen
);
1824 mdb
->drCTClpSiz
= SWAP_BE32 (fcb
->fcbClmpSize
);
1827 if (waitfor
!= MNT_WAIT
)
1830 retval
= VOP_BWRITE(bp
);
1832 MarkVCBClean( vcb
);
1838 short hfs_flushvolumeheader(struct hfsmount
*hfsmp
, int waitfor
)
1840 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
1842 HFSPlusVolumeHeader
*volumeHeader
;
1849 if (vcb
->vcbSigWord
!= kHFSPlusSigWord
)
1852 sectorsize
= hfsmp
->hfs_phys_block_size
;
1853 priIDSector
= (vcb
->hfsPlusIOPosOffset
/ sectorsize
) +
1854 HFS_PRI_SECTOR(sectorsize
);
1856 retval
= meta_bread(hfsmp
->hfs_devvp
, priIDSector
, sectorsize
, NOCRED
, &bp
);
1858 DBG_VFS((" hfs_flushvolumeheader bread return error! (%d)\n", retval
));
1863 DBG_ASSERT(bp
!= NULL
);
1864 DBG_ASSERT(bp
->b_data
!= NULL
);
1865 DBG_ASSERT(bp
->b_bcount
== size
);
1867 volumeHeader
= (HFSPlusVolumeHeader
*)((char *)bp
->b_data
+ HFS_PRI_OFFSET(sectorsize
));
1870 * For embedded HFS+ volumes, update create date if it changed
1871 * (ie from a setattrlist call)
1873 if ((vcb
->hfsPlusIOPosOffset
!= 0) && (SWAP_BE32 (volumeHeader
->createDate
) != vcb
->localCreateDate
))
1876 HFSMasterDirectoryBlock
*mdb
;
1878 retval
= meta_bread(hfsmp
->hfs_devvp
, HFS_PRI_SECTOR(sectorsize
), sectorsize
, NOCRED
, &bp2
);
1879 if (retval
!= E_NONE
) {
1880 if (bp2
) brelse(bp2
);
1882 mdb
= (HFSMasterDirectoryBlock
*)(bp2
->b_data
+ HFS_PRI_OFFSET(sectorsize
));
1884 if ( SWAP_BE32 (mdb
->drCrDate
) != vcb
->localCreateDate
)
1886 mdb
->drCrDate
= SWAP_BE32 (vcb
->localCreateDate
); /* pick up the new create date */
1888 (void) VOP_BWRITE(bp2
); /* write out the changes */
1892 brelse(bp2
); /* just release it */
1898 /* Note: only update the lower 16 bits worth of attributes */
1899 volumeHeader
->attributes
= SWAP_BE32 ((SWAP_BE32 (volumeHeader
->attributes
) & 0xFFFF0000) + (UInt16
) vcb
->vcbAtrb
);
1900 volumeHeader
->lastMountedVersion
= SWAP_BE32 (kHFSPlusMountVersion
);
1901 volumeHeader
->createDate
= SWAP_BE32 (vcb
->localCreateDate
); /* volume create date is in local time */
1902 volumeHeader
->modifyDate
= SWAP_BE32 (vcb
->vcbLsMod
);
1903 volumeHeader
->backupDate
= SWAP_BE32 (vcb
->vcbVolBkUp
);
1904 volumeHeader
->checkedDate
= SWAP_BE32 (vcb
->checkedDate
);
1905 volumeHeader
->fileCount
= SWAP_BE32 (vcb
->vcbFilCnt
);
1906 volumeHeader
->folderCount
= SWAP_BE32 (vcb
->vcbDirCnt
);
1907 volumeHeader
->freeBlocks
= SWAP_BE32 (vcb
->freeBlocks
);
1908 volumeHeader
->nextAllocation
= SWAP_BE32 (vcb
->nextAllocation
);
1909 volumeHeader
->rsrcClumpSize
= SWAP_BE32 (vcb
->vcbClpSiz
);
1910 volumeHeader
->dataClumpSize
= SWAP_BE32 (vcb
->vcbClpSiz
);
1911 volumeHeader
->nextCatalogID
= SWAP_BE32 (vcb
->vcbNxtCNID
);
1912 volumeHeader
->writeCount
= SWAP_BE32 (vcb
->vcbWrCnt
);
1913 volumeHeader
->encodingsBitmap
= SWAP_BE64 (vcb
->encodingsBitmap
);
1915 bcopy( vcb
->vcbFndrInfo
, volumeHeader
->finderInfo
, sizeof(volumeHeader
->finderInfo
) );
1919 fcb
= VTOFCB(vcb
->extentsRefNum
);
1920 /* bcopy( fcb->fcbExtents, volumeHeader->extentsFile.extents, sizeof(HFSPlusExtentRecord) ); */
1921 for (i
= 0; i
< kHFSPlusExtentDensity
; i
++) {
1922 volumeHeader
->extentsFile
.extents
[i
].startBlock
= SWAP_BE32 (fcb
->fcbExtents
[i
].startBlock
);
1923 volumeHeader
->extentsFile
.extents
[i
].blockCount
= SWAP_BE32 (fcb
->fcbExtents
[i
].blockCount
);
1926 fcb
->fcbFlags
&= ~fcbModifiedMask
;
1927 volumeHeader
->extentsFile
.logicalSize
= SWAP_BE64 (fcb
->fcbEOF
);
1928 volumeHeader
->extentsFile
.totalBlocks
= SWAP_BE32 (fcb
->fcbPLen
/ vcb
->blockSize
);
1929 volumeHeader
->extentsFile
.clumpSize
= SWAP_BE32 (fcb
->fcbClmpSize
);
1931 fcb
= VTOFCB(vcb
->catalogRefNum
);
1932 /* bcopy( fcb->fcbExtents, volumeHeader->catalogFile.extents, sizeof(HFSPlusExtentRecord) ); */
1933 for (i
= 0; i
< kHFSPlusExtentDensity
; i
++) {
1934 volumeHeader
->catalogFile
.extents
[i
].startBlock
= SWAP_BE32 (fcb
->fcbExtents
[i
].startBlock
);
1935 volumeHeader
->catalogFile
.extents
[i
].blockCount
= SWAP_BE32 (fcb
->fcbExtents
[i
].blockCount
);
1938 fcb
->fcbFlags
&= ~fcbModifiedMask
;
1939 volumeHeader
->catalogFile
.logicalSize
= SWAP_BE64 (fcb
->fcbEOF
);
1940 volumeHeader
->catalogFile
.totalBlocks
= SWAP_BE32 (fcb
->fcbPLen
/ vcb
->blockSize
);
1941 volumeHeader
->catalogFile
.clumpSize
= SWAP_BE32 (fcb
->fcbClmpSize
);
1943 fcb
= VTOFCB(vcb
->allocationsRefNum
);
1944 /* bcopy( fcb->fcbExtents, volumeHeader->allocationFile.extents, sizeof(HFSPlusExtentRecord) ); */
1945 for (i
= 0; i
< kHFSPlusExtentDensity
; i
++) {
1946 volumeHeader
->allocationFile
.extents
[i
].startBlock
= SWAP_BE32 (fcb
->fcbExtents
[i
].startBlock
);
1947 volumeHeader
->allocationFile
.extents
[i
].blockCount
= SWAP_BE32 (fcb
->fcbExtents
[i
].blockCount
);
1950 fcb
->fcbFlags
&= ~fcbModifiedMask
;
1951 volumeHeader
->allocationFile
.logicalSize
= SWAP_BE64 (fcb
->fcbEOF
);
1952 volumeHeader
->allocationFile
.totalBlocks
= SWAP_BE32 (fcb
->fcbPLen
/ vcb
->blockSize
);
1953 volumeHeader
->allocationFile
.clumpSize
= SWAP_BE32 (fcb
->fcbClmpSize
);
1955 if (waitfor
!= MNT_WAIT
)
1958 retval
= VOP_BWRITE(bp
);
1960 MarkVCBClean( vcb
);
1967 * Moved here to avoid having to define prototypes
1971 * hfs vfs operations.
1973 struct vfsops hfs_vfsops
= {