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 <dev/disk.h>
113 #include <sys/lock.h>
114 #include <miscfs/specfs/specdev.h>
115 #include <hfs/hfs_mount.h>
119 #include "hfs_endian.h"
121 #include "hfscommon/headers/FileMgrInternal.h"
122 #include "hfscommon/headers/BTreesInternal.h"
128 int hfs_dbg_load
= 0;
130 int hfs_dbg_utils
= 0;
132 int hfs_dbg_lookup
= 0;
133 int hfs_dbg_tree
= 0;
135 int hfs_dbg_test
= 0;
139 * HFS File System globals:
141 Ptr gBufferAddress
[BUFFERPTRLISTSIZE
];
142 struct buf
*gBufferHeaderPtr
[BUFFERPTRLISTSIZE
];
143 int gBufferListIndex
;
144 simple_lock_data_t gBufferPtrListLock
;
146 //static char hfs_fs_name[MFSNAMELEN] = "hfs";
150 * Global variables defined in other modules:
152 extern struct vnodeopv_desc hfs_vnodeop_opv_desc
;
154 extern struct vnode
*hfs_vhashget(dev_t dev
, UInt32 nodeID
, UInt8 forkType
);
156 extern OSErr
HFSPlusToHFSExtents( const HFSPlusExtentRecord oldExtents
, HFSExtentRecord newExtents
);
159 extern void inittodr( time_t base
);
160 extern OSErr
GetVolumeNameFromCatalog(ExtendedVCB
*vcb
);
161 extern void CopyCatalogToObjectMeta(struct hfsCatalogInfo
*catInfo
, struct vnode
*vp
, struct hfsfilemeta
*fm
);
162 extern void CopyCatalogToFCB(struct hfsCatalogInfo
*catInfo
, struct vnode
*vp
);
163 extern void hfs_name_CatToMeta(CatalogNodeData
*nodeData
, struct hfsfilemeta
*fm
);
165 int hfs_changefs(struct mount
*mp
, struct hfs_mount_args
*args
, struct proc
*p
);
167 int hfs_reload(struct mount
*mp
, struct ucred
*cred
, struct proc
*p
);
168 int hfs_mountfs(struct vnode
*devvp
, struct mount
*mp
, struct proc
*p
, struct hfs_mount_args
*args
);
169 int hfs_vget(struct mount
*mp
, void *objID
, struct vnode
**vpp
);
170 void hfs_vhashinit();
171 void hfs_converterinit(void);
174 static int hfs_statfs();
178 * Called by vfs_mountroot when mounting HFS Plus as root.
183 extern struct vnode
*rootvp
;
185 struct proc
*p
= current_proc(); /* XXX */
186 struct hfsmount
*hfsmp
;
190 * Get vnode for rootdev.
192 if ((error
= bdevvp(rootdev
, &rootvp
))) {
193 printf("hfs_mountroot: can't setup bdevvp");
196 if ((error
= vfs_rootmountalloc("hfs", "root_device", &mp
)))
198 if ((error
= hfs_mountfs(rootvp
, mp
, p
, NULL
))) {
199 mp
->mnt_vfc
->vfc_refcount
--;
201 _FREE_ZONE(mp
, sizeof (struct mount
), M_MOUNT
);
204 simple_lock(&mountlist_slock
);
205 CIRCLEQ_INSERT_TAIL(&mountlist
, mp
, mnt_list
);
206 simple_unlock(&mountlist_slock
);
209 hfsmp
= VFSTOHFS(mp
);
211 hfsmp
->hfs_uid
= UNKNOWNUID
;
212 hfsmp
->hfs_gid
= UNKNOWNGID
;
213 hfsmp
->hfs_dir_mask
= (S_IRWXU
| S_IRGRP
|S_IXGRP
| S_IROTH
|S_IXOTH
); /* 0755 */
214 hfsmp
->hfs_file_mask
= (S_IRWXU
| S_IRGRP
|S_IXGRP
| S_IROTH
|S_IXOTH
); /* 0755 */
216 (void)hfs_statfs(mp
, &mp
->mnt_stat
, p
);
219 inittodr(to_bsd_time(HFSTOVCB(hfsmp
)->vcbLsMod
));
231 hfs_mount (mp
, path
, data
, ndp
, p
)
232 register struct mount
*mp
;
235 struct nameidata
*ndp
;
238 struct hfsmount
*hfsmp
= NULL
;
240 struct hfs_mount_args args
;
247 if ((retval
= copyin(data
, (caddr_t
)&args
, sizeof(args
))))
251 * If updating, check whether changing from read-only to
252 * read/write; if there is no device name, that's all we do.
254 if (mp
->mnt_flag
& MNT_UPDATE
) {
256 hfsmp
= VFSTOHFS(mp
);
257 if ((hfsmp
->hfs_fs_ronly
== 0) && (mp
->mnt_flag
& MNT_RDONLY
)) {
259 /* use VFS_SYNC to push out System (btree) files */
260 retval
= VFS_SYNC(mp
, MNT_WAIT
, p
->p_ucred
, p
);
261 if (retval
&& ((mp
->mnt_flag
& MNT_FORCE
) == 0))
265 if (mp
->mnt_flag
& MNT_FORCE
)
268 if ((retval
= hfs_flushfiles(mp
, flags
)))
270 hfsmp
->hfs_fs_clean
= 1;
271 hfsmp
->hfs_fs_ronly
= 1;
272 if (HFSTOVCB(hfsmp
)->vcbSigWord
== kHFSPlusSigWord
)
273 retval
= hfs_flushvolumeheader(hfsmp
, MNT_WAIT
);
275 retval
= hfs_flushMDB(hfsmp
, MNT_WAIT
);
277 /* also get the volume bitmap blocks */
279 retval
= VOP_FSYNC(hfsmp
->hfs_devvp
, NOCRED
, MNT_WAIT
, p
);
282 hfsmp
->hfs_fs_clean
= 0;
283 hfsmp
->hfs_fs_ronly
= 0;
288 if ((mp
->mnt_flag
& MNT_RELOAD
) &&
289 (retval
= hfs_reload(mp
, ndp
->ni_cnd
.cn_cred
, p
)))
292 if (hfsmp
->hfs_fs_ronly
&& (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)) {
294 * If upgrade to read-write by non-root, then verify
295 * that user has necessary permissions on the device.
297 if (p
->p_ucred
->cr_uid
!= 0) {
298 devvp
= hfsmp
->hfs_devvp
;
299 vn_lock(devvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
300 if ((retval
= VOP_ACCESS(devvp
, VREAD
| VWRITE
, p
->p_ucred
, p
))) {
301 VOP_UNLOCK(devvp
, 0, p
);
304 VOP_UNLOCK(devvp
, 0, p
);
306 if (HFSTOVCB(hfsmp
)->vcbSigWord
== kHFSPlusSigWord
)
307 retval
= hfs_flushvolumeheader(hfsmp
, MNT_WAIT
);
309 retval
= hfs_flushMDB(hfsmp
, MNT_WAIT
);
311 if (retval
!= E_NONE
)
314 /* only change hfs_fs_ronly after a successfull write */
315 hfsmp
->hfs_fs_ronly
= 0;
316 hfsmp
->hfs_fs_clean
= 0;
319 if ((hfsmp
->hfs_fs_ronly
== 0) &&
320 (HFSTOVCB(hfsmp
)->vcbSigWord
== kHFSPlusSigWord
)) {
321 /* setup private/hidden directory for unlinked files */
322 hfsmp
->hfs_private_metadata_dir
= FindMetaDataDirectory(HFSTOVCB(hfsmp
));
325 if (args
.fspec
== 0) {
327 * Process export requests.
329 return vfs_export(mp
, &hfsmp
->hfs_export
, &args
.export
);
334 * Not an update, or updating the name: look up the name
335 * and verify that it refers to a sensible block device.
337 NDINIT(ndp
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, args
.fspec
, p
);
339 if (retval
!= E_NONE
) {
340 DBG_ERR(("hfs_mount: CAN'T GET DEVICE: %s, %x\n", args
.fspec
, ndp
->ni_vp
->v_rdev
));
346 if (devvp
->v_type
!= VBLK
) {
351 if (major(devvp
->v_rdev
) >= nblkdev
) {
358 * If mount by non-root, then verify that user has necessary
359 * permissions on the device.
361 if (p
->p_ucred
->cr_uid
!= 0) {
363 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0)
364 accessmode
|= VWRITE
;
365 vn_lock(devvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
366 if ((retval
= VOP_ACCESS(devvp
, accessmode
, p
->p_ucred
, p
))) {
370 VOP_UNLOCK(devvp
, 0, p
);
373 if ((mp
->mnt_flag
& MNT_UPDATE
) == 0) {
374 retval
= hfs_mountfs(devvp
, mp
, p
, &args
);
375 if (retval
!= E_NONE
)
378 if (devvp
!= hfsmp
->hfs_devvp
)
379 retval
= EINVAL
; /* needs translation */
381 retval
= hfs_changefs(mp
, &args
, p
);
385 if (retval
!= E_NONE
) {
390 /* Set the mount flag to indicate that we support volfs */
391 mp
->mnt_flag
|= MNT_DOVOLFS
;
392 if (VFSTOVCB(mp
)->vcbSigWord
== kHFSSigWord
) {
393 /* HFS volumes only want roman-encoded names: */
394 mp
->mnt_flag
|= MNT_FIXEDSCRIPTENCODING
;
396 (void) copyinstr(path
, mp
->mnt_stat
.f_mntonname
, MNAMELEN
-1, &size
);
397 bzero(mp
->mnt_stat
.f_mntonname
+ size
, MNAMELEN
- size
);
398 (void) copyinstr(args
.fspec
, mp
->mnt_stat
.f_mntfromname
, MNAMELEN
- 1, &size
);
399 bzero(mp
->mnt_stat
.f_mntfromname
+ size
, MNAMELEN
- size
);
400 (void)hfs_statfs(mp
, &mp
->mnt_stat
, p
);
409 /* change fs mount parameters */
411 hfs_changefs(mp
, args
, p
)
413 struct hfs_mount_args
*args
;
417 int namefix
, permfix
, permswitch
;
418 struct hfsmount
*hfsmp
;
420 mode_t hfs_file_mask
;
422 hfsCatalogInfo catInfo
;
423 register struct vnode
*vp
, *nvp
;
424 hfs_to_unicode_func_t get_unicode_func
;
425 unicode_to_hfs_func_t get_hfsname_func
;
427 hfsmp
= VFSTOHFS(mp
);
428 vcb
= HFSTOVCB(hfsmp
);
429 permswitch
= (((hfsmp
->hfs_unknownpermissions
!= 0) && ((mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) == 0)) ||
430 ((hfsmp
->hfs_unknownpermissions
== 0) && ((mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) != 0)));
431 /* The root filesystem must operate with actual permissions: */
432 if (permswitch
&& (mp
->mnt_flag
& MNT_ROOTFS
) && (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
)) {
433 mp
->mnt_flag
&= ~MNT_UNKNOWNPERMISSIONS
; /* Just say "No". */
436 hfsmp
->hfs_unknownpermissions
= ((mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) != 0);
437 namefix
= permfix
= 0;
439 /* change the timezone (Note: this affects all hfs volumes and hfs+ volume create dates) */
440 if (args
->hfs_timezone
.tz_minuteswest
!= VNOVAL
) {
441 gTimeZone
= args
->hfs_timezone
;
444 /* change the default uid, gid and/or mask */
445 if ((args
->hfs_uid
!= (uid_t
)VNOVAL
) && (hfsmp
->hfs_uid
!= args
->hfs_uid
)) {
446 hfsmp
->hfs_uid
= args
->hfs_uid
;
449 if ((args
->hfs_gid
!= (gid_t
)VNOVAL
) && (hfsmp
->hfs_gid
!= args
->hfs_gid
)) {
450 hfsmp
->hfs_gid
= args
->hfs_gid
;
453 if (args
->hfs_mask
!= (mode_t
)VNOVAL
) {
454 if (hfsmp
->hfs_dir_mask
!= (args
->hfs_mask
& ALLPERMS
)) {
455 hfsmp
->hfs_dir_mask
= args
->hfs_mask
& ALLPERMS
;
456 hfsmp
->hfs_file_mask
= args
->hfs_mask
& ALLPERMS
;
457 if ((args
->flags
!= VNOVAL
) && (args
->flags
& HFSFSMNT_NOXONFILES
))
458 hfsmp
->hfs_file_mask
= (args
->hfs_mask
& DEFFILEMODE
);
463 /* change the hfs encoding value (hfs only) */
464 if ((HFSTOVCB(hfsmp
)->vcbSigWord
== kHFSSigWord
) &&
465 (hfsmp
->hfs_encoding
!= (u_long
)VNOVAL
) &&
466 (hfsmp
->hfs_encoding
!= args
->hfs_encoding
)) {
468 retval
= hfs_getconverter(args
->hfs_encoding
, &get_unicode_func
, &get_hfsname_func
);
469 if (retval
) goto error_exit
;
472 * Connect the new hfs_get_unicode converter but leave
473 * the old hfs_get_hfsname converter in place so that
474 * we can lookup existing vnodes to get their correctly
477 * When we're all finished, we can then connect the new
478 * hfs_get_hfsname converter and release our interest
479 * in the old converters.
481 hfsmp
->hfs_get_unicode
= get_unicode_func
;
486 if (!(namefix
|| permfix
|| permswitch
)) goto exit
;
489 * For each active vnode fix things that changed
491 * Note that we can visit a vnode more than once
492 * and we can race with fsync.
494 simple_lock(&mntvnode_slock
);
496 for (vp
= mp
->mnt_vnodelist
.lh_first
; vp
!= NULL
; vp
= nvp
) {
498 * If the vnode that we are about to fix is no longer
499 * associated with this mount point, start over.
501 if (vp
->v_mount
!= mp
)
504 simple_lock(&vp
->v_interlock
);
505 nvp
= vp
->v_mntvnodes
.le_next
;
506 if (vp
->v_flag
& VSYSTEM
) {
507 simple_unlock(&vp
->v_interlock
);
510 simple_unlock(&mntvnode_slock
);
511 retval
= vget(vp
, LK_EXCLUSIVE
| LK_NOWAIT
| LK_INTERLOCK
, p
);
513 simple_lock(&mntvnode_slock
);
514 if (retval
== ENOENT
)
521 INIT_CATALOGDATA(&catInfo
.nodeData
, 0);
523 catInfo
.hint
= kNoHint
;
524 retval
= hfs_getcatalog(vcb
, H_DIRID(hp
), H_NAME(hp
), hp
->h_meta
->h_namelen
, &catInfo
);
525 /* If we couldn't find this guy skip to the next one */
530 simple_lock(&mntvnode_slock
);
534 H_HINT(hp
) = catInfo
.hint
;
535 if (permswitch
|| (permfix
&& (hp
->h_meta
->h_metaflags
& IN_UNSETACCESS
))) {
536 if ((vcb
->vcbSigWord
== kHFSPlusSigWord
) && (catInfo
.nodeData
.cnd_mode
& IFMT
)) {
537 if (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
539 * Override the permissions as determined by the mount auguments
540 * in ALMOST the same way unset permissions are treated but keep
541 * track of whether or not the file or folder is hfs locked
542 * by leaving the h_pflags field unchanged from what was unpacked
543 * out of the catalog.
545 hp
->h_meta
->h_metaflags
|= IN_UNSETACCESS
;
546 hp
->h_meta
->h_uid
= VTOHFS(vp
)->hfs_uid
;
547 hp
->h_meta
->h_gid
= VTOHFS(vp
)->hfs_gid
;
549 hp
->h_meta
->h_uid
= catInfo
.nodeData
.cnd_ownerID
;
550 hp
->h_meta
->h_gid
= catInfo
.nodeData
.cnd_groupID
;
552 hp
->h_meta
->h_mode
= (mode_t
)catInfo
.nodeData
.cnd_mode
;
555 * Set the permissions as determined by the mount auguments
556 * but keep in account if the file or folder is hfs locked
558 hp
->h_meta
->h_metaflags
|= IN_UNSETACCESS
;
559 hp
->h_meta
->h_uid
= VTOHFS(vp
)->hfs_uid
;
560 hp
->h_meta
->h_gid
= VTOHFS(vp
)->hfs_gid
;
562 /* Default access is full read/write/execute: */
563 hp
->h_meta
->h_mode
&= IFMT
;
564 hp
->h_meta
->h_mode
|= ACCESSPERMS
; /* 0777: rwxrwxrwx */
565 /* ... but no more than that permitted by the mount point's: */
566 if ((hp
->h_meta
->h_mode
& IFMT
) == IFDIR
) {
567 hp
->h_meta
->h_mode
&= IFMT
| VTOHFS(vp
)->hfs_dir_mask
;
569 hp
->h_meta
->h_mode
&= IFMT
| VTOHFS(vp
)->hfs_file_mask
;
575 * If we're switching name converters then...
576 * Remove the existing entry from the namei cache.
577 * Update name to one based on new encoder.
581 hfs_name_CatToMeta(&catInfo
.nodeData
, hp
->h_meta
);
583 if (catInfo
.nodeData
.cnd_nodeID
== kHFSRootFolderID
)
584 strncpy(vcb
->vcbVN
, H_NAME(hp
), NAME_MAX
);
587 CLEAN_CATALOGDATA(&catInfo
.nodeData
);
590 simple_lock(&mntvnode_slock
);
592 } /* end for (vp...) */
593 simple_unlock(&mntvnode_slock
);
598 * If we're switching name converters we can now
599 * connect the new hfs_get_hfsname converter and
600 * release our interest in the old converters.
603 u_long old_encoding
= hfsmp
->hfs_encoding
;
605 hfsmp
->hfs_get_hfsname
= get_hfsname_func
;
606 hfsmp
->hfs_encoding
= args
->hfs_encoding
;
607 vcb
->volumeNameEncodingHint
= args
->hfs_encoding
;
609 (void) hfs_relconverter(old_encoding
);
621 * Reload all incore data for a filesystem (used after running fsck on
622 * the root filesystem and finding things to fix). The filesystem must
623 * be mounted read-only.
625 * Things to do to update the mount:
626 * 1) invalidate all cached meta-data.
627 * 2) re-read volume header from disk.
628 * 3) re-load meta-file info (extents, file size).
629 * 4) re-load B-tree header data.
630 * 5) invalidate all inactive vnodes.
631 * 6) invalidate all cached file data.
632 * 7) re-read hfsnode data for all active vnodes.
635 hfs_reload(mountp
, cred
, p
)
636 register struct mount
*mountp
;
640 register struct vnode
*vp
, *nvp
, *devvp
;
644 struct hfsmount
*hfsmp
;
645 struct HFSPlusVolumeHeader
*vhp
;
649 if ((mountp
->mnt_flag
& MNT_RDONLY
) == 0)
652 hfsmp
= VFSTOHFS(mountp
);
653 vcb
= HFSTOVCB(hfsmp
);
655 if (vcb
->vcbSigWord
== kHFSSigWord
)
656 return (EINVAL
); /* rooting from HFS is not supported! */
659 * Invalidate all cached meta-data.
661 devvp
= hfsmp
->hfs_devvp
;
662 if (vinvalbuf(devvp
, 0, cred
, p
, 0, 0))
663 panic("hfs_reload: dirty1");
664 InvalidateCatalogCache(vcb
);
667 * Re-read VolumeHeader from disk.
670 error
= bread( hfsmp
->hfs_devvp
,
671 IOBLKNOFORBLK((vcb
->hfsPlusIOPosOffset
/ 512) + kMasterDirectoryBlock
, size
),
672 IOBYTECCNTFORBLK(kMasterDirectoryBlock
, kMDBSize
, size
),
681 vhp
= (HFSPlusVolumeHeader
*) ((char *)bp
->b_data
+
682 IOBYTEOFFSETFORBLK((vcb
->hfsPlusIOPosOffset
/ 512) + kMasterDirectoryBlock
, size
));
684 if ((ValidVolumeHeader(vhp
) != 0) || (vcb
->blockSize
!= SWAP_BE32 (vhp
->blockSize
))) {
686 return (EIO
); /* XXX needs translation */
689 vcb
->vcbLsMod
= SWAP_BE32 (vhp
->modifyDate
);
690 vcb
->vcbAtrb
= (UInt16
) SWAP_BE32 (vhp
->attributes
); /* VCB only uses lower 16 bits */
691 vcb
->vcbClpSiz
= SWAP_BE32 (vhp
->rsrcClumpSize
);
692 vcb
->vcbNxtCNID
= SWAP_BE32 (vhp
->nextCatalogID
);
693 vcb
->vcbVolBkUp
= SWAP_BE32 (vhp
->backupDate
);
694 vcb
->vcbWrCnt
= SWAP_BE32 (vhp
->writeCount
);
695 vcb
->vcbFilCnt
= SWAP_BE32 (vhp
->fileCount
);
696 vcb
->vcbDirCnt
= SWAP_BE32 (vhp
->folderCount
);
697 vcb
->nextAllocation
= SWAP_BE32 (vhp
->nextAllocation
);
698 vcb
->totalBlocks
= SWAP_BE32 (vhp
->totalBlocks
);
699 vcb
->freeBlocks
= SWAP_BE32 (vhp
->freeBlocks
);
700 vcb
->checkedDate
= SWAP_BE32 (vhp
->checkedDate
);
701 vcb
->encodingsBitmap
= SWAP_BE64 (vhp
->encodingsBitmap
);
702 bcopy(vhp
->finderInfo
, vcb
->vcbFndrInfo
, sizeof(vhp
->finderInfo
));
703 vcb
->localCreateDate
= SWAP_BE32 (vhp
->createDate
); /* hfs+ create date is in local time */
706 * Re-load meta-file vnode data (extent info, file size, etc).
708 fcb
= VTOFCB((struct vnode
*)vcb
->extentsRefNum
);
709 /* bcopy(vhp->extentsFile.extents, fcb->fcbExtents, sizeof(HFSPlusExtentRecord)); */
710 for (i
= 0; i
< kHFSPlusExtentDensity
; i
++) {
711 fcb
->fcbExtents
[i
].startBlock
= SWAP_BE32 (vhp
->extentsFile
.extents
[i
].startBlock
);
712 fcb
->fcbExtents
[i
].blockCount
= SWAP_BE32 (vhp
->extentsFile
.extents
[i
].blockCount
);
714 fcb
->fcbEOF
= SWAP_BE64 (vhp
->extentsFile
.logicalSize
);
715 fcb
->fcbPLen
= SWAP_BE32 (vhp
->extentsFile
.totalBlocks
) * vcb
->blockSize
;
716 fcb
->fcbClmpSize
= SWAP_BE32 (vhp
->extentsFile
.clumpSize
);
718 fcb
= VTOFCB((struct vnode
*)vcb
->catalogRefNum
);
719 /* bcopy(vhp->catalogFile.extents, fcb->fcbExtents, sizeof(HFSPlusExtentRecord)); */
720 for (i
= 0; i
< kHFSPlusExtentDensity
; i
++) {
721 fcb
->fcbExtents
[i
].startBlock
= SWAP_BE32 (vhp
->catalogFile
.extents
[i
].startBlock
);
722 fcb
->fcbExtents
[i
].blockCount
= SWAP_BE32 (vhp
->catalogFile
.extents
[i
].blockCount
);
724 fcb
->fcbPLen
= SWAP_BE64 (vhp
->catalogFile
.logicalSize
);
725 fcb
->fcbPLen
= SWAP_BE32 (vhp
->catalogFile
.totalBlocks
) * vcb
->blockSize
;
726 fcb
->fcbClmpSize
= SWAP_BE32 (vhp
->catalogFile
.clumpSize
);
728 fcb
= VTOFCB((struct vnode
*)vcb
->allocationsRefNum
);
729 /* bcopy(vhp->allocationFile.extents, fcb->fcbExtents, sizeof(HFSPlusExtentRecord)); */
730 for (i
= 0; i
< kHFSPlusExtentDensity
; i
++) {
731 fcb
->fcbExtents
[i
].startBlock
= SWAP_BE32 (vhp
->allocationFile
.extents
[i
].startBlock
);
732 fcb
->fcbExtents
[i
].blockCount
= SWAP_BE32 (vhp
->allocationFile
.extents
[i
].blockCount
);
734 fcb
->fcbEOF
= SWAP_BE64 (vhp
->allocationFile
.logicalSize
);
735 fcb
->fcbPLen
= SWAP_BE32 (vhp
->allocationFile
.totalBlocks
) * vcb
->blockSize
;
736 fcb
->fcbClmpSize
= SWAP_BE32 (vhp
->allocationFile
.clumpSize
);
742 * Re-load B-tree header data
744 fcb
= VTOFCB((struct vnode
*)vcb
->extentsRefNum
);
745 if (error
= MacToVFSError( BTReloadData(fcb
) ))
748 fcb
= VTOFCB((struct vnode
*)vcb
->catalogRefNum
);
749 if (error
= MacToVFSError( BTReloadData(fcb
) ))
752 /* Now that the catalog is ready, get the volume name */
753 /* also picks up the create date in GMT */
754 if ((error
= MacToVFSError( GetVolumeNameFromCatalog(vcb
) )))
757 /* Re-establish private/hidden directory for unlinked files */
758 hfsmp
->hfs_private_metadata_dir
= FindMetaDataDirectory(vcb
);
761 simple_lock(&mntvnode_slock
);
762 for (vp
= mountp
->mnt_vnodelist
.lh_first
; vp
!= NULL
; vp
= nvp
) {
763 if (vp
->v_mount
!= mountp
) {
764 simple_unlock(&mntvnode_slock
);
767 nvp
= vp
->v_mntvnodes
.le_next
;
770 * Invalidate all inactive vnodes.
772 if (vrecycle(vp
, &mntvnode_slock
, p
))
776 * Invalidate all cached file data.
778 simple_lock(&vp
->v_interlock
);
779 simple_unlock(&mntvnode_slock
);
780 if (vget(vp
, LK_EXCLUSIVE
| LK_INTERLOCK
, p
)) {
783 if (vinvalbuf(vp
, 0, cred
, p
, 0, 0))
784 panic("hfs_reload: dirty2");
787 * Re-read hfsnode data for all active vnodes (non-metadata files).
790 if ((vp
->v_flag
& VSYSTEM
) == 0) {
791 hfsCatalogInfo catInfo
;
793 /* lookup by fileID since name could have changed */
794 catInfo
.hint
= kNoHint
;
795 INIT_CATALOGDATA(&catInfo
.nodeData
, 0);
797 if ((error
= hfs_getcatalog(vcb
, H_FILEID(hp
), NULL
, -1, &catInfo
))) {
799 CLEAN_CATALOGDATA(&catInfo
.nodeData
);
803 H_HINT(hp
) = catInfo
.hint
;
804 if (hp
->h_meta
->h_metaflags
& IN_LONGNAME
)
805 FREE(H_NAME(hp
), M_TEMP
);
807 hp
->h_meta
->h_namelen
= 0;
808 CopyCatalogToObjectMeta(&catInfo
, vp
, hp
->h_meta
);
809 CopyCatalogToFCB(&catInfo
, vp
);
811 CLEAN_CATALOGDATA(&catInfo
.nodeData
);
815 simple_lock(&mntvnode_slock
);
817 simple_unlock(&mntvnode_slock
);
824 * Common code for mount and mountroot
827 hfs_mountfs(struct vnode
*devvp
, struct mount
*mp
, struct proc
*p
, struct hfs_mount_args
*args
)
830 register struct hfsmount
*hfsmp
;
833 HFSMasterDirectoryBlock
*mdbp
;
838 DBG_VFS(("hfs_mountfs: mp = 0x%lX\n", (u_long
)mp
));
841 cred
= p
? p
->p_ucred
: NOCRED
;
843 * Disallow multiple mounts of the same device.
844 * Disallow mounting of a device that is currently in use
845 * (except for root, which might share swap device for miniroot).
846 * Flush out any old buffers remaining from a previous use.
848 if ((retval
= vfs_mountedon(devvp
)))
850 if ((vcount(devvp
) > 1) && (devvp
!= rootvp
))
852 if ((retval
= vinvalbuf(devvp
, V_SAVE
, cred
, p
, 0, 0)))
855 ronly
= (mp
->mnt_flag
& MNT_RDONLY
) != 0;
856 DBG_VFS(("hfs_mountfs: opening device...\n"));
857 if ((retval
= VOP_OPEN(devvp
, ronly
? FREAD
: FREAD
|FWRITE
, FSCRED
, p
)))
860 blksize
= kHFSBlockSize
;
861 DBG_VFS(("hfs_mountfs: size = %d (DEV_BSIZE = %d).\n", blksize
, DEV_BSIZE
));
867 * XXX SER Currently we only support 512 block size systems. This might change
868 * So this is a place holder to remind us that the mdb might not be 512 aligned
869 * retval = VOP_IOCTL(devvp, DKIOCGETBLOCKSIZE, &blksize, FWRITE, cred, p);
870 * if (retval) return retval;
874 * the next three lines should probably be replaced
875 * with a call to the yet unimplemented function VOP_SETBLOCKSIZE
877 retval
= VOP_IOCTL(devvp
, DKIOCSETBLOCKSIZE
, &blksize
, FWRITE
, cred
, p
);
878 if (retval
) return retval
;
879 devvp
->v_specsize
= blksize
;
881 /* cache the IO attributes */
882 if ((retval
= vfs_init_io_attributes(devvp
, mp
))) {
883 printf("hfs_mountfs: vfs_init_io_attributes returned %d\n",
888 DBG_VFS(("hfs_mountfs: reading MDB [block no. %d + %d bytes, size %d bytes]...\n",
889 IOBLKNOFORBLK(kMasterDirectoryBlock
, blksize
),
890 IOBYTEOFFSETFORBLK(kMasterDirectoryBlock
, blksize
),
891 IOBYTECCNTFORBLK(kMasterDirectoryBlock
, kMDBSize
, blksize
)));
893 if ((retval
= bread(devvp
, IOBLKNOFORBLK(kMasterDirectoryBlock
, blksize
),
894 IOBYTECCNTFORBLK(kMasterDirectoryBlock
, kMDBSize
, blksize
), cred
, &bp
))) {
897 mdbp
= (HFSMasterDirectoryBlock
*) ((char *)bp
->b_data
+ IOBYTEOFFSETFORBLK(kMasterDirectoryBlock
, blksize
));
899 MALLOC(hfsmp
, struct hfsmount
*, sizeof(struct hfsmount
), M_HFSMNT
, M_WAITOK
);
900 bzero(hfsmp
, sizeof(struct hfsmount
));
902 simple_lock_init(&hfsmp
->hfs_renamelock
);
904 DBG_VFS(("hfs_mountfs: Initializing hfsmount structure at 0x%lX...\n", (u_long
)hfsmp
));
906 * Init the volume information structure
908 mp
->mnt_data
= (qaddr_t
)hfsmp
;
909 hfsmp
->hfs_mp
= mp
; /* Make VFSTOHFS work */
910 hfsmp
->hfs_vcb
.vcb_hfsmp
= hfsmp
; /* Make VCBTOHFS work */
911 hfsmp
->hfs_raw_dev
= devvp
->v_rdev
;
912 hfsmp
->hfs_devvp
= devvp
;
913 hfsmp
->hfs_phys_block_size
= blksize
;
915 /* The hfs_log_block_size field is updated in the respective hfs_MountHFS[Plus]Volume routine */
916 hfsmp
->hfs_logBlockSize
= BestBlockSizeFit(SWAP_BE32 (mdbp
->drAlBlkSiz
), MAXBSIZE
, hfsmp
->hfs_phys_block_size
);
917 hfsmp
->hfs_fs_ronly
= ronly
;
918 hfsmp
->hfs_unknownpermissions
= ((mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) != 0);
920 hfsmp
->hfs_uid
= (args
->hfs_uid
== (uid_t
)VNOVAL
) ? UNKNOWNUID
: args
->hfs_uid
;
921 if (hfsmp
->hfs_uid
== 0xfffffffd) hfsmp
->hfs_uid
= UNKNOWNUID
;
922 hfsmp
->hfs_gid
= (args
->hfs_gid
== (gid_t
)VNOVAL
) ? UNKNOWNGID
: args
->hfs_gid
;
923 if (hfsmp
->hfs_gid
== 0xfffffffd) hfsmp
->hfs_gid
= UNKNOWNGID
;
924 if (args
->hfs_mask
!= (mode_t
)VNOVAL
) {
925 hfsmp
->hfs_dir_mask
= args
->hfs_mask
& ALLPERMS
;
926 if (args
->flags
& HFSFSMNT_NOXONFILES
) {
927 hfsmp
->hfs_file_mask
= (args
->hfs_mask
& DEFFILEMODE
);
929 hfsmp
->hfs_file_mask
= args
->hfs_mask
& ALLPERMS
;
932 hfsmp
->hfs_dir_mask
= UNKNOWNPERMISSIONS
& ALLPERMS
; /* 0777: rwx---rwx */
933 hfsmp
->hfs_file_mask
= UNKNOWNPERMISSIONS
& DEFFILEMODE
; /* 0666: no --x by default? */
936 /* Even w/o explicit mount arguments, MNT_UNKNOWNPERMISSIONS requires setting up uid, gid, and mask: */
937 if (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
938 hfsmp
->hfs_uid
= UNKNOWNUID
;
939 hfsmp
->hfs_gid
= UNKNOWNGID
;
940 hfsmp
->hfs_dir_mask
= UNKNOWNPERMISSIONS
& ALLPERMS
; /* 0777: rwx---rwx */
941 hfsmp
->hfs_file_mask
= UNKNOWNPERMISSIONS
& DEFFILEMODE
; /* 0666: no --x by default? */
945 /* See above comment for DKIOCGETBLOCKSIZE
946 * retval = VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE, &blksize, FWRITE, cred, p);
947 * if (retval) return retval;
950 retval
= VOP_IOCTL(devvp
, DKIOCNUMBLKS
, (caddr_t
)&diskBlks
, 0, cred
, p
);
951 if (retval
) return retval
;
953 if (SWAP_BE16 (mdbp
->drSigWord
) == kHFSPlusSigWord
) {
954 /* Enidan swap volume header in place */
955 /* SWAP_HFS_PLUS_VOLUME_HEADER ((HFSPlusVolumeHeader *)bp->b_data); */
957 /* mount wrapper-less HFS-Plus volume */
958 (void) hfs_getconverter(0, &hfsmp
->hfs_get_unicode
, &hfsmp
->hfs_get_hfsname
);
959 retval
= hfs_MountHFSPlusVolume(hfsmp
, (HFSPlusVolumeHeader
*) bp
->b_data
, 0, diskBlks
, p
);
961 /* Enidan un-swap volume header in place */
962 /* SWAP_HFS_PLUS_VOLUME_HEADER ((HFSPlusVolumeHeader *)bp->b_data); */
964 } else if (SWAP_BE16 (mdbp
->drEmbedSigWord
) == kHFSPlusSigWord
) {
966 HFSPlusVolumeHeader
*vhp
;
968 embBlkOffset
= SWAP_BE16 (mdbp
->drAlBlSt
) +
969 (SWAP_BE16 (mdbp
->drEmbedExtent
.startBlock
) * (SWAP_BE32 (mdbp
->drAlBlkSiz
)/kHFSBlockSize
));
970 /* calculate virtual number of 512-byte sectors */
971 diskBlks
= SWAP_BE16 (mdbp
->drEmbedExtent
.blockCount
) * (SWAP_BE32 (mdbp
->drAlBlkSiz
)/kHFSBlockSize
);
974 bp
= NULL
; /* done with MDB, go grab Volume Header */
977 retval
= bread( devvp
,
978 IOBLKNOFORBLK(kMasterDirectoryBlock
+embBlkOffset
, blksize
),
979 IOBYTECCNTFORBLK(kMasterDirectoryBlock
+embBlkOffset
, kMDBSize
, blksize
),
985 vhp
= (HFSPlusVolumeHeader
*) ((char *)bp
->b_data
+ IOBYTEOFFSETFORBLK(kMasterDirectoryBlock
, blksize
));
987 /* Enidan swap volume header in place */
988 /* SWAP_HFS_PLUS_VOLUME_HEADER (vhp); */
990 /* mount embedded HFS Plus volume */
991 (void) hfs_getconverter(0, &hfsmp
->hfs_get_unicode
, &hfsmp
->hfs_get_hfsname
);
992 retval
= hfs_MountHFSPlusVolume(hfsmp
, vhp
, embBlkOffset
, diskBlks
, p
);
994 /* Enidan un-swap volume header in place */
995 /* SWAP_HFS_PLUS_VOLUME_HEADER (vhp); */
997 } else if (devvp
!= rootvp
) {
999 hfsmp
->hfs_encoding
= args
->hfs_encoding
;
1000 HFSTOVCB(hfsmp
)->volumeNameEncodingHint
= args
->hfs_encoding
;
1003 /* establish the timezone */
1004 gTimeZone
= args
->hfs_timezone
;
1007 retval
= hfs_getconverter(hfsmp
->hfs_encoding
, &hfsmp
->hfs_get_unicode
, &hfsmp
->hfs_get_hfsname
);
1008 if (retval
) goto error_exit
;
1010 /* mount HFS volume */
1011 retval
= hfs_MountHFSVolume( hfsmp
, mdbp
, diskBlks
, p
);
1014 (void) hfs_relconverter(hfsmp
->hfs_encoding
);
1017 /* sorry, we cannot root from HFS */
1028 mp
->mnt_stat
.f_fsid
.val
[0] = (long)dev
;
1029 mp
->mnt_stat
.f_fsid
.val
[1] = mp
->mnt_vfc
->vfc_typenum
;
1030 mp
->mnt_maxsymlinklen
= 0;
1031 devvp
->v_specflags
|= SI_MOUNTEDON
;
1034 hfsmp
->hfs_fs_clean
= 0;
1035 if (HFSTOVCB(hfsmp
)->vcbSigWord
== kHFSPlusSigWord
)
1036 (void) hfs_flushvolumeheader(hfsmp
, MNT_WAIT
);
1038 (void) hfs_flushMDB(hfsmp
, MNT_WAIT
);
1043 DBG_VFS(("hfs_mountfs: exiting with error %d...\n", retval
));
1047 (void)VOP_CLOSE(devvp
, ronly
? FREAD
: FREAD
|FWRITE
, cred
, p
);
1049 FREE(hfsmp
, M_HFSMNT
);
1050 mp
->mnt_data
= (qaddr_t
)0;
1059 * Make a filesystem operational.
1060 * Nothing to do at the moment.
1063 int hfs_start(mp
, flags
, p
)
1068 DBG_FUNC_NAME("hfs_start");
1069 DBG_PRINT_FUNC_NAME();
1076 * unmount system call
1079 hfs_unmount(mp
, mntflags
, p
)
1084 struct hfsmount
*hfsmp
= VFSTOHFS(mp
);
1085 int retval
= E_NONE
;
1089 if (mntflags
& MNT_FORCE
)
1090 flags
|= FORCECLOSE
;
1092 if ((retval
= hfs_flushfiles(mp
, flags
)))
1096 * Flush out the b-trees, volume bitmap and Volume Header
1098 if (hfsmp
->hfs_fs_ronly
== 0) {
1099 retval
= VOP_FSYNC(HFSTOVCB(hfsmp
)->catalogRefNum
, NOCRED
, MNT_WAIT
, p
);
1100 if (retval
&& ((mntflags
& MNT_FORCE
) == 0))
1103 retval
= VOP_FSYNC(HFSTOVCB(hfsmp
)->extentsRefNum
, NOCRED
, MNT_WAIT
, p
);
1104 if (retval
&& ((mntflags
& MNT_FORCE
) == 0))
1107 if (retval
= VOP_FSYNC(hfsmp
->hfs_devvp
, NOCRED
, MNT_WAIT
, p
)) {
1108 if ((mntflags
& MNT_FORCE
) == 0)
1112 /* See if this volume is damaged, is so do not unmount cleanly */
1113 if (HFSTOVCB(hfsmp
)->vcbFlags
& kHFS_DamagedVolume
) {
1114 hfsmp
->hfs_fs_clean
= 0;
1115 HFSTOVCB(hfsmp
)->vcbAtrb
&= ~kHFSVolumeUnmountedMask
;
1117 hfsmp
->hfs_fs_clean
= 1;
1118 HFSTOVCB(hfsmp
)->vcbAtrb
|= kHFSVolumeUnmountedMask
;
1120 if (HFSTOVCB(hfsmp
)->vcbSigWord
== kHFSPlusSigWord
)
1121 retval
= hfs_flushvolumeheader(hfsmp
, MNT_WAIT
);
1123 retval
= hfs_flushMDB(hfsmp
, MNT_WAIT
);
1126 hfsmp
->hfs_fs_clean
= 0;
1127 HFSTOVCB(hfsmp
)->vcbAtrb
&= ~kHFSVolumeUnmountedMask
;
1128 if ((mntflags
& MNT_FORCE
) == 0)
1129 return (retval
); /* could not flush everything */
1134 * Invalidate our caches and release metadata vnodes
1136 (void) hfsUnmount(hfsmp
, p
);
1138 if (HFSTOVCB(hfsmp
)->vcbSigWord
== kHFSSigWord
)
1139 (void) hfs_relconverter(hfsmp
->hfs_encoding
);
1141 hfsmp
->hfs_devvp
->v_specflags
&= ~SI_MOUNTEDON
;
1142 retval
= VOP_CLOSE(hfsmp
->hfs_devvp
, hfsmp
->hfs_fs_ronly
? FREAD
: FREAD
|FWRITE
,
1144 vrele(hfsmp
->hfs_devvp
);
1146 FREE(hfsmp
, M_HFSMNT
);
1147 mp
->mnt_data
= (qaddr_t
)0;
1154 * Return the root of a filesystem.
1156 * OUT - vpp, should be locked and vget()'d (to increment usecount and lock)
1158 int hfs_root(mp
, vpp
)
1164 UInt32 rootObjID
= kRootDirID
;
1166 DBG_FUNC_NAME("hfs_root");
1167 DBG_PRINT_FUNC_NAME();
1169 if ((retval
= VFS_VGET(mp
, &rootObjID
, &nvp
)))
1178 * Do operations associated with quotas
1180 int hfs_quotactl(mp
, cmds
, uid
, arg
, p
)
1187 DBG_FUNC_NAME("hfs_quotactl");
1188 DBG_PRINT_FUNC_NAME();
1190 return (EOPNOTSUPP
);
1195 * Get file system statistics.
1198 hfs_statfs(mp
, sbp
, p
)
1200 register struct statfs
*sbp
;
1203 ExtendedVCB
*vcb
= VFSTOVCB(mp
);
1204 struct hfsmount
*hfsmp
= VFSTOHFS(mp
);
1207 DBG_FUNC_NAME("hfs_statfs");
1208 DBG_PRINT_FUNC_NAME();
1210 freeCNIDs
= (u_long
)0xFFFFFFFF - (u_long
)vcb
->vcbNxtCNID
;
1212 sbp
->f_bsize
= vcb
->blockSize
;
1213 sbp
->f_iosize
= hfsmp
->hfs_logBlockSize
;
1214 sbp
->f_blocks
= vcb
->totalBlocks
;
1215 sbp
->f_bfree
= vcb
->freeBlocks
;
1216 sbp
->f_bavail
= vcb
->freeBlocks
;
1217 sbp
->f_files
= vcb
->totalBlocks
- 2; /* max files is constrained by total blocks */
1218 sbp
->f_ffree
= MIN(freeCNIDs
, vcb
->freeBlocks
);
1221 if (sbp
!= &mp
->mnt_stat
) {
1222 sbp
->f_type
= mp
->mnt_vfc
->vfc_typenum
;
1223 bcopy((caddr_t
)mp
->mnt_stat
.f_mntonname
,
1224 (caddr_t
)&sbp
->f_mntonname
[0], MNAMELEN
);
1225 bcopy((caddr_t
)mp
->mnt_stat
.f_mntfromname
,
1226 (caddr_t
)&sbp
->f_mntfromname
[0], MNAMELEN
);
1233 * Go through the disk queues to initiate sandbagged IO;
1234 * go through the inodes to write those that have been modified;
1235 * initiate the writing of the super block if it has been modified.
1237 * Note: we are always called with the filesystem marked `MPBUSY'.
1239 static int hfs_sync(mp
, waitfor
, cred
, p
)
1245 struct vnode
*nvp
, *vp
;
1247 struct hfsmount
*hfsmp
= VFSTOHFS(mp
);
1249 struct vnode
*meta_vp
[3];
1251 int error
, allerror
= 0;
1253 DBG_FUNC_NAME("hfs_sync");
1254 DBG_PRINT_FUNC_NAME();
1257 * During MNT_UPDATE hfs_changefs might be manipulating
1258 * vnodes so back off
1260 if (mp
->mnt_flag
& MNT_UPDATE
)
1263 hfsmp
= VFSTOHFS(mp
);
1264 if (hfsmp
->hfs_fs_ronly
!= 0) {
1265 panic("update: rofs mod");
1269 * Write back each 'modified' vnode
1273 simple_lock(&mntvnode_slock
);
1274 for (vp
= mp
->mnt_vnodelist
.lh_first
;
1279 * If the vnode that we are about to sync is no longer
1280 * associated with this mount point, start over.
1282 if (vp
->v_mount
!= mp
) {
1283 simple_unlock(&mntvnode_slock
);
1286 simple_lock(&vp
->v_interlock
);
1287 nvp
= vp
->v_mntvnodes
.le_next
;
1290 if ((vp
->v_flag
& VSYSTEM
) || (vp
->v_type
== VNON
) ||
1291 (((hp
->h_nodeflags
& (IN_ACCESS
| IN_CHANGE
| IN_MODIFIED
| IN_UPDATE
)) == 0) &&
1292 (vp
->v_dirtyblkhd
.lh_first
== NULL
) && !(vp
->v_flag
& VHASDIRTY
))) {
1293 simple_unlock(&vp
->v_interlock
);
1294 simple_unlock(&mntvnode_slock
);
1295 simple_lock(&mntvnode_slock
);
1299 simple_unlock(&mntvnode_slock
);
1300 error
= vget(vp
, LK_EXCLUSIVE
| LK_NOWAIT
| LK_INTERLOCK
, p
);
1302 if (error
== ENOENT
)
1304 simple_lock(&mntvnode_slock
);
1308 didhold
= ubc_hold(vp
);
1309 if ((error
= VOP_FSYNC(vp
, cred
, waitfor
, p
))) {
1310 DBG_ERR(("hfs_sync: error %d calling fsync on vnode 0x%X.\n", error
, (u_int
)vp
));
1313 DBG_ASSERT(*((volatile int *)(&(vp
)->v_interlock
))==0);
1314 VOP_UNLOCK(vp
, 0, p
);
1318 simple_lock(&mntvnode_slock
);
1321 vcb
= HFSTOVCB(hfsmp
);
1322 meta_vp
[0] = vcb
->extentsRefNum
;
1323 meta_vp
[1] = vcb
->catalogRefNum
;
1324 meta_vp
[2] = vcb
->allocationsRefNum
; /* This is NULL for standard HFS */
1326 /* Now sync our three metadata files */
1327 for (i
= 0; i
< 3; ++i
) {
1332 if ((btvp
==0) || (btvp
->v_type
== VNON
) || (btvp
->v_mount
!= mp
))
1334 simple_lock(&btvp
->v_interlock
);
1336 if (((hp
->h_nodeflags
& (IN_ACCESS
| IN_CHANGE
| IN_MODIFIED
| IN_UPDATE
)) == 0) &&
1337 (btvp
->v_dirtyblkhd
.lh_first
== NULL
) && !(btvp
->v_flag
& VHASDIRTY
)) {
1338 simple_unlock(&btvp
->v_interlock
);
1341 simple_unlock(&mntvnode_slock
);
1342 error
= vget(btvp
, LK_EXCLUSIVE
| LK_NOWAIT
| LK_INTERLOCK
, p
);
1344 simple_lock(&mntvnode_slock
);
1347 if ((error
= VOP_FSYNC(btvp
, cred
, waitfor
, p
)))
1349 VOP_UNLOCK(btvp
, 0, p
);
1351 simple_lock(&mntvnode_slock
);
1354 simple_unlock(&mntvnode_slock
);
1357 * Force stale file system control information to be flushed.
1359 if (vcb
->vcbSigWord
== kHFSSigWord
) {
1360 if ((error
= VOP_FSYNC(hfsmp
->hfs_devvp
, cred
, waitfor
, p
)))
1364 * Write back modified superblock.
1367 if (IsVCBDirty(vcb
)) {
1368 if (vcb
->vcbSigWord
== kHFSPlusSigWord
)
1369 error
= hfs_flushvolumeheader(hfsmp
, waitfor
);
1371 error
= hfs_flushMDB(hfsmp
, waitfor
);
1382 * File handle to vnode
1384 * Have to be really careful about stale file handles:
1385 * - check that the hfsnode number is valid
1386 * - call hfs_vget() to get the locked hfsnode
1387 * - check for an unallocated hfsnode (i_mode == 0)
1388 * - check that the given client host has export rights and return
1389 * those rights via. exflagsp and credanonp
1392 hfs_fhtovp(mp
, fhp
, nam
, vpp
, exflagsp
, credanonp
)
1393 register struct mount
*mp
;
1398 struct ucred
**credanonp
;
1400 struct hfsfid
*hfsfhp
;
1404 DBG_FUNC_NAME("hfs_fhtovp");
1405 DBG_PRINT_FUNC_NAME();
1408 hfsfhp
= (struct hfsfid
*)fhp
;
1411 * Get the export permission structure for this <mp, client> tuple.
1413 np
= vfs_export_lookup(mp
, &VFSTOHFS(mp
)->hfs_export
, nam
);
1418 result
= VFS_VGET(mp
, &hfsfhp
->hfsfid_cnid
, &nvp
);
1419 if (result
) return result
;
1420 if (nvp
== NULL
) return ESTALE
;
1422 /* The createtime can be changed by hfs_setattr or hfs_setattrlist.
1423 * For NFS, we are assuming that only if the createtime was moved
1424 * forward would it mean the fileID got reused in that session by
1425 * wrapping. We don't have a volume ID or other unique identifier to
1426 * to use here for a generation ID across reboots, crashes where
1427 * metadata noting lastFileID didn't make it to disk but client has
1428 * it, or volume erasures where fileIDs start over again. Lastly,
1429 * with HFS allowing "wraps" of fileIDs now, this becomes more
1430 * error prone. Future, would be change the "wrap bit" to a unique
1431 * wrap number and use that for generation number. For now do this.
1433 if ((hfsfhp
->hfsfid_gen
< VTOH(nvp
)->h_meta
->h_crtime
)) {
1439 *exflagsp
= np
->netc_exflags
;
1440 *credanonp
= &np
->netc_anon
;
1447 * Vnode pointer to File handle
1450 static int hfs_vptofh(vp
, fhp
)
1455 struct hfsfid
*hfsfhp
;
1456 struct proc
*p
= current_proc();
1459 DBG_FUNC_NAME("hfs_vptofh");
1460 DBG_PRINT_FUNC_NAME();
1463 hfsfhp
= (struct hfsfid
*)fhp
;
1465 /* If a file handle is requested for a file on an HFS volume we must be sure
1466 to create the thread record before returning the object id in the filehandle
1467 to make sure the file can be retrieved by fileid if necessary:
1469 if ((vp
->v_type
== VREG
) && ISHFS(VTOVCB(vp
))) {
1470 /* Create a thread record and return the FileID [which is the file's fileNumber] */
1471 /* lock catalog b-tree */
1472 if ((result
= hfs_metafilelocking(VTOHFS(vp
), kHFSCatalogFileID
, LK_EXCLUSIVE
, p
)) != 0) return result
;
1473 result
= hfsCreateFileID(VTOVCB(vp
), H_DIRID(hp
), H_NAME(hp
), H_HINT(hp
), &fileID
);
1474 (void) hfs_metafilelocking(VTOHFS(vp
), kHFSCatalogFileID
, LK_RELEASE
, p
);
1476 DBG_ERR(("hfs_vptofh: error %d on CreateFileIDRef.\n", result
));
1479 DBG_ASSERT(fileID
== H_FILEID(hp
));
1482 hfsfhp
->hfsfid_len
= sizeof(struct hfsfid
);
1483 hfsfhp
->hfsfid_pad
= 0;
1484 hfsfhp
->hfsfid_cnid
= H_FILEID(hp
);
1485 hfsfhp
->hfsfid_gen
= hp
->h_meta
->h_crtime
;
1492 * Initial HFS filesystems, done only once.
1496 struct vfsconf
*vfsp
;
1499 static int done
= 0;
1502 DBG_FUNC_NAME("hfs_init");
1503 DBG_PRINT_FUNC_NAME();
1509 hfs_converterinit();
1511 simple_lock_init (&gBufferPtrListLock
);
1513 for (i
= BUFFERPTRLISTSIZE
- 1; i
>= 0; --i
) {
1514 gBufferAddress
[i
] = NULL
;
1515 gBufferHeaderPtr
[i
] = NULL
;
1517 gBufferListIndex
= 0;
1520 * Allocate Catalog Iterator cache...
1522 err
= InitCatalogCache();
1529 * fast filesystem related variables.
1531 static int hfs_sysctl(name
, namelen
, oldp
, oldlenp
, newp
, newlen
, p
)
1540 DBG_FUNC_NAME("hfs_sysctl");
1541 DBG_PRINT_FUNC_NAME();
1543 return (EOPNOTSUPP
);
1547 /* This will return a vnode of either a directory or a data vnode based on an object id. If
1548 * it is a file id, its data fork will be returned.
1551 hfs_vget(struct mount
*mp
,
1555 struct hfsmount
*hfsmp
;
1557 int retval
= E_NONE
;
1559 DBG_VFS(("hfs_vget: ino = %ld\n", *(UInt32
*)ino
));
1561 /* Check if unmount in progress */
1562 if (mp
->mnt_kern_flag
& MNTK_UNMOUNT
) {
1567 hfsmp
= VFSTOHFS(mp
);
1568 dev
= hfsmp
->hfs_raw_dev
;
1570 /* First check to see if it is in the cache */
1571 *vpp
= hfs_vhashget(dev
, *(UInt32
*)ino
, kDefault
);
1573 /* hide open files that have been deleted */
1575 if ((VTOH(*vpp
)->h_meta
->h_metaflags
& IN_NOEXISTS
) ||
1576 (hfsmp
->hfs_private_metadata_dir
!= 0) &&
1577 (H_DIRID(VTOH(*vpp
)) == hfsmp
->hfs_private_metadata_dir
)) {
1584 /* The vnode is not in the cache, so lets make it */
1587 hfsCatalogInfo catInfo
;
1588 struct proc
*p
= current_proc();
1591 INIT_CATALOGDATA(&catInfo
.nodeData
, 0);
1592 catInfo
.hint
= kNoHint
;
1593 /* Special-case the root's parent directory (DirID = 1) because
1594 it doesn't actually exist in the catalog: */
1595 if ((*vpp
== NULL
) && (*(UInt32
*)ino
== kRootParID
)) {
1596 bzero(&catInfo
, sizeof(catInfo
));
1597 catInfo
.nodeData
.cnd_type
= kCatalogFolderNode
;
1598 catInfo
.nodeData
.cnm_nameptr
= catInfo
.nodeData
.cnm_namespace
;
1599 catInfo
.nodeData
.cnm_namespace
[0] = '/';
1600 catInfo
.nodeData
.cnm_length
= 1;
1601 catInfo
.nodeData
.cnd_nodeID
= kRootParID
;
1602 catInfo
.nodeData
.cnm_parID
= kRootParID
;
1603 catInfo
.nodeData
.cnd_valence
= 1;
1604 catInfo
.nodeData
.cnd_ownerID
= 0;
1605 catInfo
.nodeData
.cnd_groupID
= 0;
1606 catInfo
.nodeData
.cnd_mode
= (S_IFDIR
| S_IRWXU
| S_IRWXG
| S_IRWXO
);
1609 /* lock catalog b-tree */
1610 retval
= hfs_metafilelocking(hfsmp
, kHFSCatalogFileID
, LK_SHARED
, p
);
1611 if (retval
!= E_NONE
) goto Lookup_Err_Exit
;
1613 retval
= hfs_getcatalog(VFSTOVCB(mp
), *(UInt32
*)ino
, NULL
, -1, &catInfo
);
1615 /* unlock catalog b-tree */
1616 (void) hfs_metafilelocking(hfsmp
, kHFSCatalogFileID
, LK_RELEASE
, p
);
1618 if (retval
!= E_NONE
) goto Lookup_Err_Exit
;
1620 /* hide open files that have been deleted */
1621 if ((hfsmp
->hfs_private_metadata_dir
!= 0) &&
1622 (catInfo
.nodeData
.cnm_parID
== hfsmp
->hfs_private_metadata_dir
)) {
1624 goto Lookup_Err_Exit
;
1628 forkType
= (catInfo
.nodeData
.cnd_type
== kCatalogFolderNode
) ? kDirectory
: kDataFork
;
1629 retval
= hfs_vcreate(VFSTOVCB(mp
), &catInfo
, forkType
, vpp
);
1632 CLEAN_CATALOGDATA(&catInfo
.nodeData
);
1635 UBCINFOCHECK("hfs_vget", *vpp
);
1639 /* rember if a parent directory was looked up by CNID */
1640 if (retval
== 0 && ((*vpp
)->v_type
== VDIR
)
1641 && lockstatus(&mp
->mnt_lock
) != LK_SHARED
)
1642 VTOH(*vpp
)->h_nodeflags
|= IN_BYCNID
;
1649 * Flush out all the files in a filesystem.
1652 hfs_flushfiles(struct mount
*mp
, int flags
)
1656 error
= vflush(mp
, NULLVP
, (SKIPSYSTEM
| SKIPSWAP
| flags
));
1657 error
= vflush(mp
, NULLVP
, (SKIPSYSTEM
| flags
));
1662 short hfs_flushMDB(struct hfsmount
*hfsmp
, int waitfor
)
1664 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
1666 HFSMasterDirectoryBlock
*mdb
;
1669 int size
= kMDBSize
; /* 512 */
1672 if (vcb
->vcbSigWord
!= kHFSSigWord
)
1675 DBG_ASSERT(hfsmp
->hfs_devvp
!= NULL
);
1677 retval
= bread(hfsmp
->hfs_devvp
, IOBLKNOFORBLK(kMasterDirectoryBlock
, size
),
1678 IOBYTECCNTFORBLK(kMasterDirectoryBlock
, kMDBSize
, size
), NOCRED
, &bp
);
1680 DBG_VFS((" hfs_flushMDB bread return error! (%d)\n", retval
));
1685 DBG_ASSERT(bp
!= NULL
);
1686 DBG_ASSERT(bp
->b_data
!= NULL
);
1687 DBG_ASSERT(bp
->b_bcount
== size
);
1689 mdb
= (HFSMasterDirectoryBlock
*)((char *)bp
->b_data
+ IOBYTEOFFSETFORBLK(kMasterDirectoryBlock
, size
));
1692 mdb
->drCrDate
= SWAP_BE32 (UTCToLocal(vcb
->vcbCrDate
));
1693 mdb
->drLsMod
= SWAP_BE32 (UTCToLocal(vcb
->vcbLsMod
));
1694 mdb
->drAtrb
= SWAP_BE16 (vcb
->vcbAtrb
);
1695 mdb
->drNmFls
= SWAP_BE16 (vcb
->vcbNmFls
);
1696 mdb
->drAllocPtr
= SWAP_BE16 (vcb
->nextAllocation
);
1697 mdb
->drClpSiz
= SWAP_BE32 (vcb
->vcbClpSiz
);
1698 mdb
->drNxtCNID
= SWAP_BE32 (vcb
->vcbNxtCNID
);
1699 mdb
->drFreeBks
= SWAP_BE16 (vcb
->freeBlocks
);
1701 namelen
= strlen(vcb
->vcbVN
);
1702 retval
= utf8_to_hfs(vcb
, namelen
, vcb
->vcbVN
, mdb
->drVN
);
1703 /* Retry with MacRoman in case that's how it was exported. */
1705 retval
= utf8_to_mac_roman(namelen
, vcb
->vcbVN
, mdb
->drVN
);
1707 mdb
->drVolBkUp
= SWAP_BE32 (UTCToLocal(vcb
->vcbVolBkUp
));
1708 mdb
->drWrCnt
= SWAP_BE32 (vcb
->vcbWrCnt
);
1709 mdb
->drNmRtDirs
= SWAP_BE16 (vcb
->vcbNmRtDirs
);
1710 mdb
->drFilCnt
= SWAP_BE32 (vcb
->vcbFilCnt
);
1711 mdb
->drDirCnt
= SWAP_BE32 (vcb
->vcbDirCnt
);
1713 bcopy(vcb
->vcbFndrInfo
, mdb
->drFndrInfo
, sizeof(mdb
->drFndrInfo
));
1715 fcb
= VTOFCB(vcb
->extentsRefNum
);
1716 /* HFSPlusToHFSExtents(fcb->fcbExtents, mdb->drXTExtRec); */
1717 mdb
->drXTExtRec
[0].startBlock
= SWAP_BE16 (fcb
->fcbExtents
[0].startBlock
);
1718 mdb
->drXTExtRec
[0].blockCount
= SWAP_BE16 (fcb
->fcbExtents
[0].blockCount
);
1719 mdb
->drXTExtRec
[1].startBlock
= SWAP_BE16 (fcb
->fcbExtents
[1].startBlock
);
1720 mdb
->drXTExtRec
[1].blockCount
= SWAP_BE16 (fcb
->fcbExtents
[1].blockCount
);
1721 mdb
->drXTExtRec
[2].startBlock
= SWAP_BE16 (fcb
->fcbExtents
[2].startBlock
);
1722 mdb
->drXTExtRec
[2].blockCount
= SWAP_BE16 (fcb
->fcbExtents
[2].blockCount
);
1724 mdb
->drXTFlSize
= SWAP_BE32 (fcb
->fcbPLen
);
1725 mdb
->drXTClpSiz
= SWAP_BE32 (fcb
->fcbClmpSize
);
1727 fcb
= VTOFCB(vcb
->catalogRefNum
);
1728 /* HFSPlusToHFSExtents(fcb->fcbExtents, mdb->drCTExtRec); */
1729 mdb
->drCTExtRec
[0].startBlock
= SWAP_BE16 (fcb
->fcbExtents
[0].startBlock
);
1730 mdb
->drCTExtRec
[0].blockCount
= SWAP_BE16 (fcb
->fcbExtents
[0].blockCount
);
1731 mdb
->drCTExtRec
[1].startBlock
= SWAP_BE16 (fcb
->fcbExtents
[1].startBlock
);
1732 mdb
->drCTExtRec
[1].blockCount
= SWAP_BE16 (fcb
->fcbExtents
[1].blockCount
);
1733 mdb
->drCTExtRec
[2].startBlock
= SWAP_BE16 (fcb
->fcbExtents
[2].startBlock
);
1734 mdb
->drCTExtRec
[2].blockCount
= SWAP_BE16 (fcb
->fcbExtents
[2].blockCount
);
1736 mdb
->drCTFlSize
= SWAP_BE32 (fcb
->fcbPLen
);
1737 mdb
->drCTClpSiz
= SWAP_BE32 (fcb
->fcbClmpSize
);
1740 if (waitfor
!= MNT_WAIT
)
1743 retval
= VOP_BWRITE(bp
);
1745 MarkVCBClean( vcb
);
1751 short hfs_flushvolumeheader(struct hfsmount
*hfsmp
, int waitfor
)
1753 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
1755 HFSPlusVolumeHeader
*volumeHeader
;
1757 int size
= sizeof(HFSPlusVolumeHeader
);
1761 if (vcb
->vcbSigWord
!= kHFSPlusSigWord
)
1764 retval
= bread(hfsmp
->hfs_devvp
, IOBLKNOFORBLK((vcb
->hfsPlusIOPosOffset
/ 512) + kMasterDirectoryBlock
, size
),
1765 IOBYTECCNTFORBLK(kMasterDirectoryBlock
, kMDBSize
, size
), NOCRED
, &bp
);
1767 DBG_VFS((" hfs_flushvolumeheader 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 volumeHeader
= (HFSPlusVolumeHeader
*)((char *)bp
->b_data
+
1777 IOBYTEOFFSETFORBLK((vcb
->hfsPlusIOPosOffset
/ 512) + kMasterDirectoryBlock
, size
));
1780 * For embedded HFS+ volumes, update create date if it changed
1781 * (ie from a setattrlist call)
1783 if ((vcb
->hfsPlusIOPosOffset
!= 0) && (SWAP_BE32 (volumeHeader
->createDate
) != vcb
->localCreateDate
))
1786 HFSMasterDirectoryBlock
*mdb
;
1788 retval
= bread(hfsmp
->hfs_devvp
, IOBLKNOFORBLK(kMasterDirectoryBlock
, kMDBSize
),
1789 IOBYTECCNTFORBLK(kMasterDirectoryBlock
, kMDBSize
, kMDBSize
), NOCRED
, &bp2
);
1790 if (retval
!= E_NONE
) {
1791 if (bp2
) brelse(bp2
);
1793 mdb
= (HFSMasterDirectoryBlock
*)((char *)bp2
->b_data
+ IOBYTEOFFSETFORBLK(kMasterDirectoryBlock
, kMDBSize
));
1795 if ( SWAP_BE32 (mdb
->drCrDate
) != vcb
->localCreateDate
)
1797 mdb
->drCrDate
= SWAP_BE32 (vcb
->localCreateDate
); /* pick up the new create date */
1799 (void) VOP_BWRITE(bp2
); /* write out the changes */
1803 brelse(bp2
); /* just release it */
1809 /* Note: only update the lower 16 bits worth of attributes */
1810 volumeHeader
->attributes
= SWAP_BE32 ((SWAP_BE32 (volumeHeader
->attributes
) & 0xFFFF0000) + (UInt16
) vcb
->vcbAtrb
);
1811 volumeHeader
->lastMountedVersion
= SWAP_BE32 (kHFSPlusMountVersion
);
1812 volumeHeader
->createDate
= SWAP_BE32 (vcb
->localCreateDate
); /* volume create date is in local time */
1813 volumeHeader
->modifyDate
= SWAP_BE32 (vcb
->vcbLsMod
);
1814 volumeHeader
->backupDate
= SWAP_BE32 (vcb
->vcbVolBkUp
);
1815 volumeHeader
->checkedDate
= SWAP_BE32 (vcb
->checkedDate
);
1816 volumeHeader
->fileCount
= SWAP_BE32 (vcb
->vcbFilCnt
);
1817 volumeHeader
->folderCount
= SWAP_BE32 (vcb
->vcbDirCnt
);
1818 volumeHeader
->freeBlocks
= SWAP_BE32 (vcb
->freeBlocks
);
1819 volumeHeader
->nextAllocation
= SWAP_BE32 (vcb
->nextAllocation
);
1820 volumeHeader
->rsrcClumpSize
= SWAP_BE32 (vcb
->vcbClpSiz
);
1821 volumeHeader
->dataClumpSize
= SWAP_BE32 (vcb
->vcbClpSiz
);
1822 volumeHeader
->nextCatalogID
= SWAP_BE32 (vcb
->vcbNxtCNID
);
1823 volumeHeader
->writeCount
= SWAP_BE32 (vcb
->vcbWrCnt
);
1824 volumeHeader
->encodingsBitmap
= SWAP_BE64 (vcb
->encodingsBitmap
);
1826 bcopy( vcb
->vcbFndrInfo
, volumeHeader
->finderInfo
, sizeof(volumeHeader
->finderInfo
) );
1830 fcb
= VTOFCB(vcb
->extentsRefNum
);
1831 /* bcopy( fcb->fcbExtents, volumeHeader->extentsFile.extents, sizeof(HFSPlusExtentRecord) ); */
1832 for (i
= 0; i
< kHFSPlusExtentDensity
; i
++) {
1833 volumeHeader
->extentsFile
.extents
[i
].startBlock
= SWAP_BE32 (fcb
->fcbExtents
[i
].startBlock
);
1834 volumeHeader
->extentsFile
.extents
[i
].blockCount
= SWAP_BE32 (fcb
->fcbExtents
[i
].blockCount
);
1837 fcb
->fcbFlags
&= ~fcbModifiedMask
;
1838 volumeHeader
->extentsFile
.logicalSize
= SWAP_BE64 (fcb
->fcbEOF
);
1839 volumeHeader
->extentsFile
.totalBlocks
= SWAP_BE32 (fcb
->fcbPLen
/ vcb
->blockSize
);
1840 volumeHeader
->extentsFile
.clumpSize
= SWAP_BE32 (fcb
->fcbClmpSize
);
1842 fcb
= VTOFCB(vcb
->catalogRefNum
);
1843 /* bcopy( fcb->fcbExtents, volumeHeader->catalogFile.extents, sizeof(HFSPlusExtentRecord) ); */
1844 for (i
= 0; i
< kHFSPlusExtentDensity
; i
++) {
1845 volumeHeader
->catalogFile
.extents
[i
].startBlock
= SWAP_BE32 (fcb
->fcbExtents
[i
].startBlock
);
1846 volumeHeader
->catalogFile
.extents
[i
].blockCount
= SWAP_BE32 (fcb
->fcbExtents
[i
].blockCount
);
1849 fcb
->fcbFlags
&= ~fcbModifiedMask
;
1850 volumeHeader
->catalogFile
.logicalSize
= SWAP_BE64 (fcb
->fcbEOF
);
1851 volumeHeader
->catalogFile
.totalBlocks
= SWAP_BE32 (fcb
->fcbPLen
/ vcb
->blockSize
);
1852 volumeHeader
->catalogFile
.clumpSize
= SWAP_BE32 (fcb
->fcbClmpSize
);
1854 fcb
= VTOFCB(vcb
->allocationsRefNum
);
1855 /* bcopy( fcb->fcbExtents, volumeHeader->allocationFile.extents, sizeof(HFSPlusExtentRecord) ); */
1856 for (i
= 0; i
< kHFSPlusExtentDensity
; i
++) {
1857 volumeHeader
->allocationFile
.extents
[i
].startBlock
= SWAP_BE32 (fcb
->fcbExtents
[i
].startBlock
);
1858 volumeHeader
->allocationFile
.extents
[i
].blockCount
= SWAP_BE32 (fcb
->fcbExtents
[i
].blockCount
);
1861 fcb
->fcbFlags
&= ~fcbModifiedMask
;
1862 volumeHeader
->allocationFile
.logicalSize
= SWAP_BE64 (fcb
->fcbEOF
);
1863 volumeHeader
->allocationFile
.totalBlocks
= SWAP_BE32 (fcb
->fcbPLen
/ vcb
->blockSize
);
1864 volumeHeader
->allocationFile
.clumpSize
= SWAP_BE32 (fcb
->fcbClmpSize
);
1866 if (waitfor
!= MNT_WAIT
)
1869 retval
= VOP_BWRITE(bp
);
1871 MarkVCBClean( vcb
);
1878 * Moved here to avoid having to define prototypes
1882 * hfs vfs operations.
1884 struct vfsops hfs_vfsops
= {