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";
148 /* The following represent information held in low-memory on the MacOS: */
150 struct FSVarsRec
*gFSMVars
;
153 * Global variables defined in other modules:
155 extern struct vnodeopv_desc hfs_vnodeop_opv_desc
;
157 extern struct vnode
*hfs_vhashget(dev_t dev
, UInt32 nodeID
, UInt8 forkType
);
159 extern OSErr
HFSPlusToHFSExtents( const HFSPlusExtentRecord oldExtents
, HFSExtentRecord newExtents
);
162 extern void inittodr( time_t base
);
163 extern OSErr
GetVolumeNameFromCatalog(ExtendedVCB
*vcb
);
164 extern void CopyCatalogToObjectMeta(struct hfsCatalogInfo
*catInfo
, struct vnode
*vp
, struct hfsfilemeta
*fm
);
165 extern void CopyCatalogToFCB(struct hfsCatalogInfo
*catInfo
, struct vnode
*vp
);
166 extern void hfs_name_CatToMeta(CatalogNodeData
*nodeData
, struct hfsfilemeta
*fm
);
168 int hfs_changefs(struct mount
*mp
, struct hfs_mount_args
*args
, struct proc
*p
);
170 int hfs_reload(struct mount
*mp
, struct ucred
*cred
, struct proc
*p
);
171 int hfs_mountfs(struct vnode
*devvp
, struct mount
*mp
, struct proc
*p
, struct hfs_mount_args
*args
);
172 int hfs_vget(struct mount
*mp
, void *objID
, struct vnode
**vpp
);
173 void hfs_vhashinit();
174 void hfs_converterinit(void);
177 static int hfs_statfs();
181 * Called by vfs_mountroot when mounting HFS Plus as root.
186 extern struct vnode
*rootvp
;
188 struct proc
*p
= current_proc(); /* XXX */
189 struct hfsmount
*hfsmp
;
193 * Get vnode for rootdev.
195 if ((error
= bdevvp(rootdev
, &rootvp
))) {
196 printf("hfs_mountroot: can't setup bdevvp");
199 if ((error
= vfs_rootmountalloc("hfs", "root_device", &mp
)))
201 if ((error
= hfs_mountfs(rootvp
, mp
, p
, NULL
))) {
202 mp
->mnt_vfc
->vfc_refcount
--;
204 _FREE_ZONE(mp
, sizeof (struct mount
), M_MOUNT
);
207 simple_lock(&mountlist_slock
);
208 CIRCLEQ_INSERT_TAIL(&mountlist
, mp
, mnt_list
);
209 simple_unlock(&mountlist_slock
);
212 hfsmp
= VFSTOHFS(mp
);
214 hfsmp
->hfs_dir_mask
= (S_IRWXU
|S_IRWXG
|S_IRWXO
); /* 0777 */
215 hfsmp
->hfs_file_mask
= (S_IRWXU
|S_IRWXG
|S_IRWXO
); /* 0777 */
217 (void)hfs_statfs(mp
, &mp
->mnt_stat
, p
);
220 inittodr(to_bsd_time(HFSTOVCB(hfsmp
)->vcbLsMod
));
232 hfs_mount (mp
, path
, data
, ndp
, p
)
233 register struct mount
*mp
;
236 struct nameidata
*ndp
;
239 struct hfsmount
*hfsmp
= NULL
;
241 struct hfs_mount_args args
;
248 if ((retval
= copyin(data
, (caddr_t
)&args
, sizeof(args
))))
252 * If updating, check whether changing from read-only to
253 * read/write; if there is no device name, that's all we do.
255 if (mp
->mnt_flag
& MNT_UPDATE
) {
257 hfsmp
= VFSTOHFS(mp
);
258 if ((hfsmp
->hfs_fs_ronly
== 0) && (mp
->mnt_flag
& MNT_RDONLY
)) {
260 /* use VFS_SYNC to push out System (btree) files */
261 retval
= VFS_SYNC(mp
, MNT_WAIT
, p
->p_ucred
, p
);
262 if (retval
&& ((mp
->mnt_flag
& MNT_FORCE
) == 0))
266 if (mp
->mnt_flag
& MNT_FORCE
)
269 if ((retval
= hfs_flushfiles(mp
, flags
)))
271 hfsmp
->hfs_fs_clean
= 1;
272 hfsmp
->hfs_fs_ronly
= 1;
273 if (HFSTOVCB(hfsmp
)->vcbSigWord
== kHFSPlusSigWord
)
274 retval
= hfs_flushvolumeheader(hfsmp
, MNT_WAIT
);
276 retval
= hfs_flushMDB(hfsmp
, MNT_WAIT
);
278 /* also get the volume bitmap blocks */
280 retval
= VOP_FSYNC(hfsmp
->hfs_devvp
, NOCRED
, MNT_WAIT
, p
);
283 hfsmp
->hfs_fs_clean
= 0;
284 hfsmp
->hfs_fs_ronly
= 0;
289 if ((mp
->mnt_flag
& MNT_RELOAD
) &&
290 (retval
= hfs_reload(mp
, ndp
->ni_cnd
.cn_cred
, p
)))
293 if (hfsmp
->hfs_fs_ronly
&& (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)) {
295 * If upgrade to read-write by non-root, then verify
296 * that user has necessary permissions on the device.
298 if (p
->p_ucred
->cr_uid
!= 0) {
299 devvp
= hfsmp
->hfs_devvp
;
300 vn_lock(devvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
301 if ((retval
= VOP_ACCESS(devvp
, VREAD
| VWRITE
, p
->p_ucred
, p
))) {
302 VOP_UNLOCK(devvp
, 0, p
);
305 VOP_UNLOCK(devvp
, 0, p
);
307 if (HFSTOVCB(hfsmp
)->vcbSigWord
== kHFSPlusSigWord
)
308 retval
= hfs_flushvolumeheader(hfsmp
, MNT_WAIT
);
310 retval
= hfs_flushMDB(hfsmp
, MNT_WAIT
);
312 if (retval
!= E_NONE
)
315 /* only change hfs_fs_ronly after a successfull write */
316 hfsmp
->hfs_fs_ronly
= 0;
317 hfsmp
->hfs_fs_clean
= 0;
320 if ((hfsmp
->hfs_fs_ronly
== 0) &&
321 (HFSTOVCB(hfsmp
)->vcbSigWord
== kHFSPlusSigWord
)) {
322 /* setup private/hidden directory for unlinked files */
323 hfsmp
->hfs_private_metadata_dir
= FindMetaDataDirectory(HFSTOVCB(hfsmp
));
326 if (args
.fspec
== 0) {
328 * Process export requests.
330 return vfs_export(mp
, &hfsmp
->hfs_export
, &args
.export
);
335 * Not an update, or updating the name: look up the name
336 * and verify that it refers to a sensible block device.
338 NDINIT(ndp
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, args
.fspec
, p
);
340 if (retval
!= E_NONE
) {
341 DBG_ERR(("hfs_mount: CAN'T GET DEVICE: %s, %x\n", args
.fspec
, ndp
->ni_vp
->v_rdev
));
347 if (devvp
->v_type
!= VBLK
) {
352 if (major(devvp
->v_rdev
) >= nblkdev
) {
359 * If mount by non-root, then verify that user has necessary
360 * permissions on the device.
362 if (p
->p_ucred
->cr_uid
!= 0) {
364 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0)
365 accessmode
|= VWRITE
;
366 vn_lock(devvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
367 if ((retval
= VOP_ACCESS(devvp
, accessmode
, p
->p_ucred
, p
))) {
371 VOP_UNLOCK(devvp
, 0, p
);
374 if ((mp
->mnt_flag
& MNT_UPDATE
) == 0) {
375 retval
= hfs_mountfs(devvp
, mp
, p
, &args
);
376 if (retval
!= E_NONE
)
379 if (devvp
!= hfsmp
->hfs_devvp
)
380 retval
= EINVAL
; /* needs translation */
382 retval
= hfs_changefs(mp
, &args
, p
);
386 if (retval
!= E_NONE
) {
391 /* Set the mount flag to indicate that we support volfs */
392 mp
->mnt_flag
|= MNT_DOVOLFS
;
393 if (VFSTOVCB(mp
)->vcbSigWord
== kHFSSigWord
) {
394 /* HFS volumes only want roman-encoded names: */
395 mp
->mnt_flag
|= MNT_FIXEDSCRIPTENCODING
;
397 (void) copyinstr(path
, mp
->mnt_stat
.f_mntonname
, MNAMELEN
-1, &size
);
398 bzero(mp
->mnt_stat
.f_mntonname
+ size
, MNAMELEN
- size
);
399 (void) copyinstr(args
.fspec
, mp
->mnt_stat
.f_mntfromname
, MNAMELEN
- 1, &size
);
400 bzero(mp
->mnt_stat
.f_mntfromname
+ size
, MNAMELEN
- size
);
401 (void)hfs_statfs(mp
, &mp
->mnt_stat
, p
);
410 /* change fs mount parameters */
412 hfs_changefs(mp
, args
, p
)
414 struct hfs_mount_args
*args
;
418 int namefix
, permfix
, permswitch
;
419 struct hfsmount
*hfsmp
;
421 mode_t hfs_file_mask
;
423 hfsCatalogInfo catInfo
;
424 register struct vnode
*vp
, *nvp
;
425 hfs_to_unicode_func_t get_unicode_func
;
426 unicode_to_hfs_func_t get_hfsname_func
;
428 hfsmp
= VFSTOHFS(mp
);
429 vcb
= HFSTOVCB(hfsmp
);
430 permswitch
= (((hfsmp
->hfs_unknownpermissions
!= 0) && ((mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) == 0)) ||
431 ((hfsmp
->hfs_unknownpermissions
== 0) && ((mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) != 0)));
432 hfsmp
->hfs_unknownpermissions
= ((mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) != 0);
433 namefix
= permfix
= 0;
435 /* change the timezone (Note: this affects all hfs volumes and hfs+ volume create dates) */
436 if (args
->hfs_timezone
.tz_minuteswest
!= VNOVAL
) {
437 gTimeZone
= args
->hfs_timezone
;
440 /* change the default uid, gid and/or mask */
441 if ((args
->hfs_uid
!= (uid_t
)VNOVAL
) && (hfsmp
->hfs_uid
!= args
->hfs_uid
)) {
442 hfsmp
->hfs_uid
= args
->hfs_uid
;
445 if ((args
->hfs_gid
!= (gid_t
)VNOVAL
) && (hfsmp
->hfs_gid
!= args
->hfs_gid
)) {
446 hfsmp
->hfs_gid
= args
->hfs_gid
;
449 if (args
->hfs_mask
!= (mode_t
)VNOVAL
) {
450 if (hfsmp
->hfs_dir_mask
!= (args
->hfs_mask
& ALLPERMS
)) {
451 hfsmp
->hfs_dir_mask
= args
->hfs_mask
& ALLPERMS
;
452 hfsmp
->hfs_file_mask
= args
->hfs_mask
& ALLPERMS
;
453 if ((args
->flags
!= VNOVAL
) && (args
->flags
& HFSFSMNT_NOXONFILES
))
454 hfsmp
->hfs_file_mask
= (args
->hfs_mask
& DEFFILEMODE
);
459 /* change the hfs encoding value (hfs only) */
460 if ((HFSTOVCB(hfsmp
)->vcbSigWord
== kHFSSigWord
) &&
461 (hfsmp
->hfs_encoding
!= (u_long
)VNOVAL
) &&
462 (hfsmp
->hfs_encoding
!= args
->hfs_encoding
)) {
464 retval
= hfs_getconverter(args
->hfs_encoding
, &get_unicode_func
, &get_hfsname_func
);
465 if (retval
) goto error_exit
;
468 * Connect the new hfs_get_unicode converter but leave
469 * the old hfs_get_hfsname converter in place so that
470 * we can lookup existing vnodes to get their correctly
473 * When we're all finished, we can then connect the new
474 * hfs_get_hfsname converter and release our interest
475 * in the old converters.
477 hfsmp
->hfs_get_unicode
= get_unicode_func
;
482 if (!(namefix
|| permfix
|| permswitch
)) goto exit
;
485 * For each active vnode fix things that changed
487 * Note that we can visit a vnode more than once
488 * and we can race with fsync.
490 simple_lock(&mntvnode_slock
);
492 for (vp
= mp
->mnt_vnodelist
.lh_first
; vp
!= NULL
; vp
= nvp
) {
494 * If the vnode that we are about to fix is no longer
495 * associated with this mount point, start over.
497 if (vp
->v_mount
!= mp
)
500 simple_lock(&vp
->v_interlock
);
501 nvp
= vp
->v_mntvnodes
.le_next
;
502 if (vp
->v_flag
& VSYSTEM
) {
503 simple_unlock(&vp
->v_interlock
);
506 simple_unlock(&mntvnode_slock
);
507 retval
= vget(vp
, LK_EXCLUSIVE
| LK_NOWAIT
| LK_INTERLOCK
, p
);
509 simple_lock(&mntvnode_slock
);
510 if (retval
== ENOENT
)
517 INIT_CATALOGDATA(&catInfo
.nodeData
, 0);
519 catInfo
.hint
= kNoHint
;
520 retval
= hfs_getcatalog(vcb
, H_DIRID(hp
), H_NAME(hp
), hp
->h_meta
->h_namelen
, &catInfo
);
521 /* If we couldn't find this guy skip to the next one */
526 simple_lock(&mntvnode_slock
);
530 H_HINT(hp
) = catInfo
.hint
;
531 if (permswitch
|| (permfix
&& (hp
->h_meta
->h_metaflags
& IN_UNSETACCESS
))) {
532 if ((vcb
->vcbSigWord
== kHFSPlusSigWord
) && (catInfo
.nodeData
.cnd_mode
& IFMT
)) {
533 if (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
535 * Override the permissions as determined by the mount auguments
536 * in ALMOST the same way unset permissions are treated but keep
537 * track of whether or not the file or folder is hfs locked
538 * by leaving the h_pflags field unchanged from what was unpacked
539 * out of the catalog.
541 hp
->h_meta
->h_metaflags
|= IN_UNSETACCESS
;
542 hp
->h_meta
->h_uid
= VTOHFS(vp
)->hfs_uid
;
543 hp
->h_meta
->h_gid
= VTOHFS(vp
)->hfs_gid
;
545 hp
->h_meta
->h_uid
= catInfo
.nodeData
.cnd_ownerID
;
546 hp
->h_meta
->h_gid
= catInfo
.nodeData
.cnd_groupID
;
548 hp
->h_meta
->h_mode
= (mode_t
)catInfo
.nodeData
.cnd_mode
;
551 * Set the permissions as determined by the mount auguments
552 * but keep in account if the file or folder is hfs locked
554 hp
->h_meta
->h_metaflags
|= IN_UNSETACCESS
;
555 hp
->h_meta
->h_uid
= VTOHFS(vp
)->hfs_uid
;
556 hp
->h_meta
->h_gid
= VTOHFS(vp
)->hfs_gid
;
558 /* Default access is full read/write/execute: */
559 hp
->h_meta
->h_mode
= ACCESSPERMS
; /* 0777: rwxrwxrwx */
560 /* ... but no more than that permitted by the mount point's: */
561 if ((hp
->h_meta
->h_mode
& IFMT
) == IFDIR
) {
562 hp
->h_meta
->h_mode
&= VTOHFS(vp
)->hfs_dir_mask
;
564 hp
->h_meta
->h_mode
&= VTOHFS(vp
)->hfs_file_mask
;
570 * If we're switching name converters then...
571 * Remove the existing entry from the namei cache.
572 * Update name to one based on new encoder.
576 hfs_name_CatToMeta(&catInfo
.nodeData
, hp
->h_meta
);
578 if (catInfo
.nodeData
.cnd_nodeID
== kHFSRootFolderID
)
579 strncpy(vcb
->vcbVN
, H_NAME(hp
), NAME_MAX
);
582 CLEAN_CATALOGDATA(&catInfo
.nodeData
);
585 simple_lock(&mntvnode_slock
);
587 } /* end for (vp...) */
588 simple_unlock(&mntvnode_slock
);
593 * If we're switching name converters we can now
594 * connect the new hfs_get_hfsname converter and
595 * release our interest in the old converters.
598 u_long old_encoding
= hfsmp
->hfs_encoding
;
600 hfsmp
->hfs_get_hfsname
= get_hfsname_func
;
601 hfsmp
->hfs_encoding
= args
->hfs_encoding
;
602 vcb
->volumeNameEncodingHint
= args
->hfs_encoding
;
604 (void) hfs_relconverter(old_encoding
);
616 * Reload all incore data for a filesystem (used after running fsck on
617 * the root filesystem and finding things to fix). The filesystem must
618 * be mounted read-only.
620 * Things to do to update the mount:
621 * 1) invalidate all cached meta-data.
622 * 2) re-read volume header from disk.
623 * 3) re-load meta-file info (extents, file size).
624 * 4) re-load B-tree header data.
625 * 5) invalidate all inactive vnodes.
626 * 6) invalidate all cached file data.
627 * 7) re-read hfsnode data for all active vnodes.
630 hfs_reload(mountp
, cred
, p
)
631 register struct mount
*mountp
;
635 register struct vnode
*vp
, *nvp
, *devvp
;
639 struct hfsmount
*hfsmp
;
640 struct HFSPlusVolumeHeader
*vhp
;
644 if ((mountp
->mnt_flag
& MNT_RDONLY
) == 0)
647 hfsmp
= VFSTOHFS(mountp
);
648 vcb
= HFSTOVCB(hfsmp
);
650 if (vcb
->vcbSigWord
== kHFSSigWord
)
651 return (EINVAL
); /* rooting from HFS is not supported! */
654 * Invalidate all cached meta-data.
656 devvp
= hfsmp
->hfs_devvp
;
657 if (vinvalbuf(devvp
, 0, cred
, p
, 0, 0))
658 panic("hfs_reload: dirty1");
659 InvalidateCatalogCache(vcb
);
662 * Re-read VolumeHeader from disk.
665 error
= bread( hfsmp
->hfs_devvp
,
666 IOBLKNOFORBLK((vcb
->hfsPlusIOPosOffset
/ 512) + kMasterDirectoryBlock
, size
),
667 IOBYTECCNTFORBLK(kMasterDirectoryBlock
, kMDBSize
, size
),
676 vhp
= (HFSPlusVolumeHeader
*) ((char *)bp
->b_data
+
677 IOBYTEOFFSETFORBLK((vcb
->hfsPlusIOPosOffset
/ 512) + kMasterDirectoryBlock
, size
));
679 if ((ValidVolumeHeader(vhp
) != 0) || (vcb
->blockSize
!= SWAP_BE32 (vhp
->blockSize
))) {
681 return (EIO
); /* XXX needs translation */
684 vcb
->vcbLsMod
= SWAP_BE32 (vhp
->modifyDate
);
685 vcb
->vcbAtrb
= (UInt16
) SWAP_BE32 (vhp
->attributes
); /* VCB only uses lower 16 bits */
686 vcb
->vcbClpSiz
= SWAP_BE32 (vhp
->rsrcClumpSize
);
687 vcb
->vcbNxtCNID
= SWAP_BE32 (vhp
->nextCatalogID
);
688 vcb
->vcbVolBkUp
= SWAP_BE32 (vhp
->backupDate
);
689 vcb
->vcbWrCnt
= SWAP_BE32 (vhp
->writeCount
);
690 vcb
->vcbFilCnt
= SWAP_BE32 (vhp
->fileCount
);
691 vcb
->vcbDirCnt
= SWAP_BE32 (vhp
->folderCount
);
692 vcb
->nextAllocation
= SWAP_BE32 (vhp
->nextAllocation
);
693 vcb
->totalBlocks
= SWAP_BE32 (vhp
->totalBlocks
);
694 vcb
->freeBlocks
= SWAP_BE32 (vhp
->freeBlocks
);
695 vcb
->checkedDate
= SWAP_BE32 (vhp
->checkedDate
);
696 vcb
->encodingsBitmap
= SWAP_BE64 (vhp
->encodingsBitmap
);
697 bcopy(vhp
->finderInfo
, vcb
->vcbFndrInfo
, sizeof(vhp
->finderInfo
));
698 vcb
->localCreateDate
= SWAP_BE32 (vhp
->createDate
); /* hfs+ create date is in local time */
701 * Re-load meta-file vnode data (extent info, file size, etc).
703 fcb
= VTOFCB((struct vnode
*)vcb
->extentsRefNum
);
704 /* bcopy(vhp->extentsFile.extents, fcb->fcbExtents, sizeof(HFSPlusExtentRecord)); */
705 for (i
= 0; i
< kHFSPlusExtentDensity
; i
++) {
706 fcb
->fcbExtents
[i
].startBlock
= SWAP_BE32 (vhp
->extentsFile
.extents
[i
].startBlock
);
707 fcb
->fcbExtents
[i
].blockCount
= SWAP_BE32 (vhp
->extentsFile
.extents
[i
].blockCount
);
709 fcb
->fcbEOF
= SWAP_BE64 (vhp
->extentsFile
.logicalSize
);
710 fcb
->fcbPLen
= SWAP_BE32 (vhp
->extentsFile
.totalBlocks
) * vcb
->blockSize
;
711 fcb
->fcbClmpSize
= SWAP_BE32 (vhp
->extentsFile
.clumpSize
);
713 fcb
= VTOFCB((struct vnode
*)vcb
->catalogRefNum
);
714 /* bcopy(vhp->catalogFile.extents, fcb->fcbExtents, sizeof(HFSPlusExtentRecord)); */
715 for (i
= 0; i
< kHFSPlusExtentDensity
; i
++) {
716 fcb
->fcbExtents
[i
].startBlock
= SWAP_BE32 (vhp
->catalogFile
.extents
[i
].startBlock
);
717 fcb
->fcbExtents
[i
].blockCount
= SWAP_BE32 (vhp
->catalogFile
.extents
[i
].blockCount
);
719 fcb
->fcbPLen
= SWAP_BE64 (vhp
->catalogFile
.logicalSize
);
720 fcb
->fcbPLen
= SWAP_BE32 (vhp
->catalogFile
.totalBlocks
) * vcb
->blockSize
;
721 fcb
->fcbClmpSize
= SWAP_BE32 (vhp
->catalogFile
.clumpSize
);
723 fcb
= VTOFCB((struct vnode
*)vcb
->allocationsRefNum
);
724 /* bcopy(vhp->allocationFile.extents, fcb->fcbExtents, sizeof(HFSPlusExtentRecord)); */
725 for (i
= 0; i
< kHFSPlusExtentDensity
; i
++) {
726 fcb
->fcbExtents
[i
].startBlock
= SWAP_BE32 (vhp
->allocationFile
.extents
[i
].startBlock
);
727 fcb
->fcbExtents
[i
].blockCount
= SWAP_BE32 (vhp
->allocationFile
.extents
[i
].blockCount
);
729 fcb
->fcbEOF
= SWAP_BE64 (vhp
->allocationFile
.logicalSize
);
730 fcb
->fcbPLen
= SWAP_BE32 (vhp
->allocationFile
.totalBlocks
) * vcb
->blockSize
;
731 fcb
->fcbClmpSize
= SWAP_BE32 (vhp
->allocationFile
.clumpSize
);
737 * Re-load B-tree header data
739 fcb
= VTOFCB((struct vnode
*)vcb
->extentsRefNum
);
740 if (error
= MacToVFSError( BTReloadData(fcb
) ))
743 fcb
= VTOFCB((struct vnode
*)vcb
->catalogRefNum
);
744 if (error
= MacToVFSError( BTReloadData(fcb
) ))
747 /* Now that the catalog is ready, get the volume name */
748 /* also picks up the create date in GMT */
749 if ((error
= MacToVFSError( GetVolumeNameFromCatalog(vcb
) )))
752 /* Re-establish private/hidden directory for unlinked files */
753 hfsmp
->hfs_private_metadata_dir
= FindMetaDataDirectory(vcb
);
756 simple_lock(&mntvnode_slock
);
757 for (vp
= mountp
->mnt_vnodelist
.lh_first
; vp
!= NULL
; vp
= nvp
) {
758 if (vp
->v_mount
!= mountp
) {
759 simple_unlock(&mntvnode_slock
);
762 nvp
= vp
->v_mntvnodes
.le_next
;
765 * Invalidate all inactive vnodes.
767 if (vrecycle(vp
, &mntvnode_slock
, p
))
771 * Invalidate all cached file data.
773 simple_lock(&vp
->v_interlock
);
774 simple_unlock(&mntvnode_slock
);
775 if (vget(vp
, LK_EXCLUSIVE
| LK_INTERLOCK
, p
)) {
778 if (vinvalbuf(vp
, 0, cred
, p
, 0, 0))
779 panic("hfs_reload: dirty2");
782 * Re-read hfsnode data for all active vnodes (non-metadata files).
785 if ((vp
->v_flag
& VSYSTEM
) == 0) {
786 hfsCatalogInfo catInfo
;
788 /* lookup by fileID since name could have changed */
789 catInfo
.hint
= kNoHint
;
790 INIT_CATALOGDATA(&catInfo
.nodeData
, 0);
792 if ((error
= hfs_getcatalog(vcb
, H_FILEID(hp
), NULL
, -1, &catInfo
))) {
794 CLEAN_CATALOGDATA(&catInfo
.nodeData
);
798 H_HINT(hp
) = catInfo
.hint
;
799 if (hp
->h_meta
->h_metaflags
& IN_LONGNAME
)
800 FREE(H_NAME(hp
), M_TEMP
);
802 hp
->h_meta
->h_namelen
= 0;
803 CopyCatalogToObjectMeta(&catInfo
, vp
, hp
->h_meta
);
804 CopyCatalogToFCB(&catInfo
, vp
);
806 CLEAN_CATALOGDATA(&catInfo
.nodeData
);
810 simple_lock(&mntvnode_slock
);
812 simple_unlock(&mntvnode_slock
);
819 * Common code for mount and mountroot
822 hfs_mountfs(struct vnode
*devvp
, struct mount
*mp
, struct proc
*p
, struct hfs_mount_args
*args
)
825 register struct hfsmount
*hfsmp
;
828 HFSMasterDirectoryBlock
*mdbp
;
833 DBG_VFS(("hfs_mountfs: mp = 0x%lX\n", (u_long
)mp
));
836 cred
= p
? p
->p_ucred
: NOCRED
;
838 * Disallow multiple mounts of the same device.
839 * Disallow mounting of a device that is currently in use
840 * (except for root, which might share swap device for miniroot).
841 * Flush out any old buffers remaining from a previous use.
843 if ((retval
= vfs_mountedon(devvp
)))
845 if ((vcount(devvp
) > 1) && (devvp
!= rootvp
))
847 if ((retval
= vinvalbuf(devvp
, V_SAVE
, cred
, p
, 0, 0)))
850 ronly
= (mp
->mnt_flag
& MNT_RDONLY
) != 0;
851 DBG_VFS(("hfs_mountfs: opening device...\n"));
852 if ((retval
= VOP_OPEN(devvp
, ronly
? FREAD
: FREAD
|FWRITE
, FSCRED
, p
)))
855 blksize
= kHFSBlockSize
;
856 DBG_VFS(("hfs_mountfs: size = %d (DEV_BSIZE = %d).\n", blksize
, DEV_BSIZE
));
862 * XXX SER Currently we only support 512 block size systems. This might change
863 * So this is a place holder to remind us that the mdb might not be 512 aligned
864 * retval = VOP_IOCTL(devvp, DKIOCGETBLOCKSIZE, &blksize, FWRITE, cred, p);
865 * if (retval) return retval;
869 * the next three lines should probably be replaced
870 * with a call to the yet unimplemented function VOP_SETBLOCKSIZE
872 retval
= VOP_IOCTL(devvp
, DKIOCSETBLOCKSIZE
, &blksize
, FWRITE
, cred
, p
);
873 if (retval
) return retval
;
874 devvp
->v_specsize
= blksize
;
876 DBG_VFS(("hfs_mountfs: reading MDB [block no. %d + %d bytes, size %d bytes]...\n",
877 IOBLKNOFORBLK(kMasterDirectoryBlock
, blksize
),
878 IOBYTEOFFSETFORBLK(kMasterDirectoryBlock
, blksize
),
879 IOBYTECCNTFORBLK(kMasterDirectoryBlock
, kMDBSize
, blksize
)));
881 if ((retval
= bread(devvp
, IOBLKNOFORBLK(kMasterDirectoryBlock
, blksize
),
882 IOBYTECCNTFORBLK(kMasterDirectoryBlock
, kMDBSize
, blksize
), cred
, &bp
))) {
885 mdbp
= (HFSMasterDirectoryBlock
*) ((char *)bp
->b_data
+ IOBYTEOFFSETFORBLK(kMasterDirectoryBlock
, blksize
));
887 MALLOC(hfsmp
, struct hfsmount
*, sizeof(struct hfsmount
), M_HFSMNT
, M_WAITOK
);
888 bzero(hfsmp
, sizeof(struct hfsmount
));
890 simple_lock_init(&hfsmp
->hfs_renamelock
);
892 DBG_VFS(("hfs_mountfs: Initializing hfsmount structure at 0x%lX...\n", (u_long
)hfsmp
));
894 * Init the volume information structure
896 mp
->mnt_data
= (qaddr_t
)hfsmp
;
897 hfsmp
->hfs_mp
= mp
; /* Make VFSTOHFS work */
898 hfsmp
->hfs_vcb
.vcb_hfsmp
= hfsmp
; /* Make VCBTOHFS work */
899 hfsmp
->hfs_raw_dev
= devvp
->v_rdev
;
900 hfsmp
->hfs_devvp
= devvp
;
901 hfsmp
->hfs_phys_block_size
= blksize
;
903 /* The hfs_log_block_size field is updated in the respective hfs_MountHFS[Plus]Volume routine */
904 hfsmp
->hfs_logBlockSize
= BestBlockSizeFit(SWAP_BE32 (mdbp
->drAlBlkSiz
), MAXBSIZE
, hfsmp
->hfs_phys_block_size
);
905 hfsmp
->hfs_fs_ronly
= ronly
;
906 hfsmp
->hfs_unknownpermissions
= ((mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) != 0);
908 hfsmp
->hfs_uid
= (args
->hfs_uid
== (uid_t
)VNOVAL
) ? UNKNOWNUID
: args
->hfs_uid
;
909 if (hfsmp
->hfs_uid
== 0xfffffffd) hfsmp
->hfs_uid
= UNKNOWNUID
;
910 hfsmp
->hfs_gid
= (args
->hfs_gid
== (gid_t
)VNOVAL
) ? UNKNOWNGID
: args
->hfs_gid
;
911 if (hfsmp
->hfs_gid
== 0xfffffffd) hfsmp
->hfs_gid
= UNKNOWNGID
;
912 if (args
->hfs_mask
!= (mode_t
)VNOVAL
) {
913 hfsmp
->hfs_dir_mask
= args
->hfs_mask
& ALLPERMS
;
914 if (args
->flags
& HFSFSMNT_NOXONFILES
) {
915 hfsmp
->hfs_file_mask
= (args
->hfs_mask
& DEFFILEMODE
);
917 hfsmp
->hfs_file_mask
= args
->hfs_mask
& ALLPERMS
;
920 hfsmp
->hfs_dir_mask
= UNKNOWNPERMISSIONS
& ALLPERMS
; /* 0777: rwx---rwx */
921 hfsmp
->hfs_file_mask
= UNKNOWNPERMISSIONS
& DEFFILEMODE
; /* 0666: no --x by default? */
924 /* Even w/o explicit mount arguments, MNT_UNKNOWNPERMISSIONS requires setting up uid, gid, and mask: */
925 if (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
926 hfsmp
->hfs_uid
= UNKNOWNUID
;
927 hfsmp
->hfs_gid
= UNKNOWNGID
;
928 hfsmp
->hfs_dir_mask
= UNKNOWNPERMISSIONS
& ALLPERMS
; /* 0777: rwx---rwx */
929 hfsmp
->hfs_file_mask
= UNKNOWNPERMISSIONS
& DEFFILEMODE
; /* 0666: no --x by default? */
933 /* See above comment for DKIOCGETBLOCKSIZE
934 * retval = VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE, &blksize, FWRITE, cred, p);
935 * if (retval) return retval;
938 retval
= VOP_IOCTL(devvp
, DKIOCNUMBLKS
, (caddr_t
)&diskBlks
, 0, cred
, p
);
939 if (retval
) return retval
;
941 if (SWAP_BE16 (mdbp
->drSigWord
) == kHFSPlusSigWord
) {
942 /* Enidan swap volume header in place */
943 /* SWAP_HFS_PLUS_VOLUME_HEADER ((HFSPlusVolumeHeader *)bp->b_data); */
945 /* mount wrapper-less HFS-Plus volume */
946 (void) hfs_getconverter(0, &hfsmp
->hfs_get_unicode
, &hfsmp
->hfs_get_hfsname
);
947 retval
= hfs_MountHFSPlusVolume(hfsmp
, (HFSPlusVolumeHeader
*) bp
->b_data
, 0, diskBlks
, p
);
949 /* Enidan un-swap volume header in place */
950 /* SWAP_HFS_PLUS_VOLUME_HEADER ((HFSPlusVolumeHeader *)bp->b_data); */
952 } else if (SWAP_BE16 (mdbp
->drEmbedSigWord
) == kHFSPlusSigWord
) {
954 HFSPlusVolumeHeader
*vhp
;
956 embBlkOffset
= SWAP_BE16 (mdbp
->drAlBlSt
) +
957 (SWAP_BE16 (mdbp
->drEmbedExtent
.startBlock
) * (SWAP_BE32 (mdbp
->drAlBlkSiz
)/kHFSBlockSize
));
958 /* calculate virtual number of 512-byte sectors */
959 diskBlks
= SWAP_BE16 (mdbp
->drEmbedExtent
.blockCount
) * (SWAP_BE32 (mdbp
->drAlBlkSiz
)/kHFSBlockSize
);
962 bp
= NULL
; /* done with MDB, go grab Volume Header */
965 retval
= bread( devvp
,
966 IOBLKNOFORBLK(kMasterDirectoryBlock
+embBlkOffset
, blksize
),
967 IOBYTECCNTFORBLK(kMasterDirectoryBlock
+embBlkOffset
, kMDBSize
, blksize
),
973 vhp
= (HFSPlusVolumeHeader
*) ((char *)bp
->b_data
+ IOBYTEOFFSETFORBLK(kMasterDirectoryBlock
, blksize
));
975 /* Enidan swap volume header in place */
976 /* SWAP_HFS_PLUS_VOLUME_HEADER (vhp); */
978 /* mount embedded HFS Plus volume */
979 (void) hfs_getconverter(0, &hfsmp
->hfs_get_unicode
, &hfsmp
->hfs_get_hfsname
);
980 retval
= hfs_MountHFSPlusVolume(hfsmp
, vhp
, embBlkOffset
, diskBlks
, p
);
982 /* Enidan un-swap volume header in place */
983 /* SWAP_HFS_PLUS_VOLUME_HEADER (vhp); */
985 } else if (devvp
!= rootvp
) {
987 hfsmp
->hfs_encoding
= args
->hfs_encoding
;
988 HFSTOVCB(hfsmp
)->volumeNameEncodingHint
= args
->hfs_encoding
;
991 /* establish the timezone */
992 gTimeZone
= args
->hfs_timezone
;
995 retval
= hfs_getconverter(hfsmp
->hfs_encoding
, &hfsmp
->hfs_get_unicode
, &hfsmp
->hfs_get_hfsname
);
996 if (retval
) goto error_exit
;
998 /* mount HFS volume */
999 retval
= hfs_MountHFSVolume( hfsmp
, mdbp
, diskBlks
, p
);
1002 (void) hfs_relconverter(hfsmp
->hfs_encoding
);
1005 /* sorry, we cannot root from HFS */
1016 mp
->mnt_stat
.f_fsid
.val
[0] = (long)dev
;
1017 mp
->mnt_stat
.f_fsid
.val
[1] = mp
->mnt_vfc
->vfc_typenum
;
1018 mp
->mnt_maxsymlinklen
= 0;
1019 devvp
->v_specflags
|= SI_MOUNTEDON
;
1022 hfsmp
->hfs_fs_clean
= 0;
1023 if (HFSTOVCB(hfsmp
)->vcbSigWord
== kHFSPlusSigWord
)
1024 (void) hfs_flushvolumeheader(hfsmp
, MNT_WAIT
);
1026 (void) hfs_flushMDB(hfsmp
, MNT_WAIT
);
1031 DBG_VFS(("hfs_mountfs: exiting with error %d...\n", retval
));
1035 (void)VOP_CLOSE(devvp
, ronly
? FREAD
: FREAD
|FWRITE
, cred
, p
);
1037 FREE(hfsmp
, M_HFSMNT
);
1038 mp
->mnt_data
= (qaddr_t
)0;
1047 * Make a filesystem operational.
1048 * Nothing to do at the moment.
1051 int hfs_start(mp
, flags
, p
)
1056 DBG_FUNC_NAME("hfs_start");
1057 DBG_PRINT_FUNC_NAME();
1064 * unmount system call
1067 hfs_unmount(mp
, mntflags
, p
)
1072 struct hfsmount
*hfsmp
= VFSTOHFS(mp
);
1073 int retval
= E_NONE
;
1077 if (mntflags
& MNT_FORCE
)
1078 flags
|= FORCECLOSE
;
1080 if ((retval
= hfs_flushfiles(mp
, flags
)))
1084 * Flush out the b-trees, volume bitmap and Volume Header
1086 if (hfsmp
->hfs_fs_ronly
== 0) {
1087 retval
= VOP_FSYNC(HFSTOVCB(hfsmp
)->catalogRefNum
, NOCRED
, MNT_WAIT
, p
);
1088 if (retval
&& ((mntflags
& MNT_FORCE
) == 0))
1091 retval
= VOP_FSYNC(HFSTOVCB(hfsmp
)->extentsRefNum
, NOCRED
, MNT_WAIT
, p
);
1092 if (retval
&& ((mntflags
& MNT_FORCE
) == 0))
1095 if (retval
= VOP_FSYNC(hfsmp
->hfs_devvp
, NOCRED
, MNT_WAIT
, p
)) {
1096 if ((mntflags
& MNT_FORCE
) == 0)
1100 /* See if this volume is damaged, is so do not unmount cleanly */
1101 if (HFSTOVCB(hfsmp
)->vcbFlags
& kHFS_DamagedVolume
) {
1102 hfsmp
->hfs_fs_clean
= 0;
1103 HFSTOVCB(hfsmp
)->vcbAtrb
&= ~kHFSVolumeUnmountedMask
;
1105 hfsmp
->hfs_fs_clean
= 1;
1106 HFSTOVCB(hfsmp
)->vcbAtrb
|= kHFSVolumeUnmountedMask
;
1108 if (HFSTOVCB(hfsmp
)->vcbSigWord
== kHFSPlusSigWord
)
1109 retval
= hfs_flushvolumeheader(hfsmp
, MNT_WAIT
);
1111 retval
= hfs_flushMDB(hfsmp
, MNT_WAIT
);
1114 hfsmp
->hfs_fs_clean
= 0;
1115 HFSTOVCB(hfsmp
)->vcbAtrb
&= ~kHFSVolumeUnmountedMask
;
1116 if ((mntflags
& MNT_FORCE
) == 0)
1117 return (retval
); /* could not flush everything */
1122 * Invalidate our caches and release metadata vnodes
1124 (void) hfsUnmount(hfsmp
, p
);
1126 if (HFSTOVCB(hfsmp
)->vcbSigWord
== kHFSSigWord
)
1127 (void) hfs_relconverter(hfsmp
->hfs_encoding
);
1129 hfsmp
->hfs_devvp
->v_specflags
&= ~SI_MOUNTEDON
;
1130 retval
= VOP_CLOSE(hfsmp
->hfs_devvp
, hfsmp
->hfs_fs_ronly
? FREAD
: FREAD
|FWRITE
,
1132 vrele(hfsmp
->hfs_devvp
);
1134 FREE(hfsmp
, M_HFSMNT
);
1135 mp
->mnt_data
= (qaddr_t
)0;
1142 * Return the root of a filesystem.
1144 * OUT - vpp, should be locked and vget()'d (to increment usecount and lock)
1146 int hfs_root(mp
, vpp
)
1152 UInt32 rootObjID
= kRootDirID
;
1154 DBG_FUNC_NAME("hfs_root");
1155 DBG_PRINT_FUNC_NAME();
1157 if ((retval
= VFS_VGET(mp
, &rootObjID
, &nvp
)))
1166 * Do operations associated with quotas
1168 int hfs_quotactl(mp
, cmds
, uid
, arg
, p
)
1175 DBG_FUNC_NAME("hfs_quotactl");
1176 DBG_PRINT_FUNC_NAME();
1178 return (EOPNOTSUPP
);
1183 * Get file system statistics.
1186 hfs_statfs(mp
, sbp
, p
)
1188 register struct statfs
*sbp
;
1191 ExtendedVCB
*vcb
= VFSTOVCB(mp
);
1192 struct hfsmount
*hfsmp
= VFSTOHFS(mp
);
1195 DBG_FUNC_NAME("hfs_statfs");
1196 DBG_PRINT_FUNC_NAME();
1198 freeCNIDs
= (u_long
)0xFFFFFFFF - (u_long
)vcb
->vcbNxtCNID
;
1200 sbp
->f_bsize
= vcb
->blockSize
;
1201 sbp
->f_iosize
= hfsmp
->hfs_logBlockSize
;
1202 sbp
->f_blocks
= vcb
->totalBlocks
;
1203 sbp
->f_bfree
= vcb
->freeBlocks
;
1204 sbp
->f_bavail
= vcb
->freeBlocks
;
1205 sbp
->f_files
= vcb
->totalBlocks
- 2; /* max files is constrained by total blocks */
1206 sbp
->f_ffree
= MIN(freeCNIDs
, vcb
->freeBlocks
);
1209 if (sbp
!= &mp
->mnt_stat
) {
1210 sbp
->f_type
= mp
->mnt_vfc
->vfc_typenum
;
1211 bcopy((caddr_t
)mp
->mnt_stat
.f_mntonname
,
1212 (caddr_t
)&sbp
->f_mntonname
[0], MNAMELEN
);
1213 bcopy((caddr_t
)mp
->mnt_stat
.f_mntfromname
,
1214 (caddr_t
)&sbp
->f_mntfromname
[0], MNAMELEN
);
1221 * Go through the disk queues to initiate sandbagged IO;
1222 * go through the inodes to write those that have been modified;
1223 * initiate the writing of the super block if it has been modified.
1225 * Note: we are always called with the filesystem marked `MPBUSY'.
1227 static int hfs_sync(mp
, waitfor
, cred
, p
)
1233 struct vnode
*nvp
, *vp
;
1235 struct hfsmount
*hfsmp
= VFSTOHFS(mp
);
1237 int error
, allerror
= 0;
1239 DBG_FUNC_NAME("hfs_sync");
1240 DBG_PRINT_FUNC_NAME();
1243 * During MNT_UPDATE hfs_changefs might be manipulating
1244 * vnodes so back off
1246 if (mp
->mnt_flag
& MNT_UPDATE
)
1249 hfsmp
= VFSTOHFS(mp
);
1250 if (hfsmp
->hfs_fs_ronly
!= 0) {
1251 panic("update: rofs mod");
1255 * Write back each 'modified' vnode
1259 simple_lock(&mntvnode_slock
);
1260 for (vp
= mp
->mnt_vnodelist
.lh_first
;
1264 * If the vnode that we are about to sync is no longer
1265 * associated with this mount point, start over.
1267 if (vp
->v_mount
!= mp
) {
1268 simple_unlock(&mntvnode_slock
);
1271 simple_lock(&vp
->v_interlock
);
1272 nvp
= vp
->v_mntvnodes
.le_next
;
1275 if ((vp
->v_type
== VNON
) || (((hp
->h_nodeflags
& (IN_ACCESS
| IN_CHANGE
| IN_MODIFIED
| IN_UPDATE
)) == 0) &&
1276 (vp
->v_dirtyblkhd
.lh_first
== NULL
) && !(vp
->v_flag
& VHASDIRTY
))) {
1277 simple_unlock(&vp
->v_interlock
);
1278 simple_unlock(&mntvnode_slock
);
1279 simple_lock(&mntvnode_slock
);
1283 simple_unlock(&mntvnode_slock
);
1284 error
= vget(vp
, LK_EXCLUSIVE
| LK_NOWAIT
| LK_INTERLOCK
, p
);
1286 if (error
== ENOENT
)
1288 simple_lock(&mntvnode_slock
);
1292 if ((error
= VOP_FSYNC(vp
, cred
, waitfor
, p
))) {
1293 DBG_ERR(("hfs_sync: error %d calling fsync on vnode 0x%X.\n", error
, (u_int
)vp
));
1296 DBG_ASSERT(*((volatile int *)(&(vp
)->v_interlock
))==0);
1298 simple_lock(&mntvnode_slock
);
1301 vcb
= HFSTOVCB(hfsmp
);
1303 /* Now reprocess the BTree node, stored above */
1307 * If the vnode that we are about to sync is no longer
1308 * associated with this mount point, start over.
1310 btvp
= vcb
->extentsRefNum
;
1311 if ((btvp
==0) || (btvp
->v_type
== VNON
) || (btvp
->v_mount
!= mp
))
1313 simple_lock(&btvp
->v_interlock
);
1315 if (((hp
->h_nodeflags
& (IN_ACCESS
| IN_CHANGE
| IN_MODIFIED
| IN_UPDATE
)) == 0) &&
1316 (btvp
->v_dirtyblkhd
.lh_first
== NULL
) && !(btvp
->v_flag
& VHASDIRTY
)) {
1317 simple_unlock(&btvp
->v_interlock
);
1320 simple_unlock(&mntvnode_slock
);
1321 error
= vget(btvp
, LK_EXCLUSIVE
| LK_NOWAIT
| LK_INTERLOCK
, p
);
1323 simple_lock(&mntvnode_slock
);
1326 if ((error
= VOP_FSYNC(btvp
, cred
, waitfor
, p
)))
1328 VOP_UNLOCK(btvp
, 0, p
);
1330 simple_lock(&mntvnode_slock
);
1335 simple_unlock(&mntvnode_slock
);
1338 * Force stale file system control information to be flushed.
1340 if ((error
= VOP_FSYNC(hfsmp
->hfs_devvp
, cred
, waitfor
, p
)))
1343 * Write back modified superblock.
1346 if (IsVCBDirty(vcb
)) {
1347 if (vcb
->vcbSigWord
== kHFSPlusSigWord
)
1348 error
= hfs_flushvolumeheader(hfsmp
, waitfor
);
1350 error
= hfs_flushMDB(hfsmp
, waitfor
);
1361 * File handle to vnode
1363 * Have to be really careful about stale file handles:
1364 * - check that the hfsnode number is valid
1365 * - call hfs_vget() to get the locked hfsnode
1366 * - check for an unallocated hfsnode (i_mode == 0)
1367 * - check that the given client host has export rights and return
1368 * those rights via. exflagsp and credanonp
1371 hfs_fhtovp(mp
, fhp
, nam
, vpp
, exflagsp
, credanonp
)
1372 register struct mount
*mp
;
1377 struct ucred
**credanonp
;
1379 struct hfsfid
*hfsfhp
;
1383 DBG_FUNC_NAME("hfs_fhtovp");
1384 DBG_PRINT_FUNC_NAME();
1387 hfsfhp
= (struct hfsfid
*)fhp
;
1390 * Get the export permission structure for this <mp, client> tuple.
1392 np
= vfs_export_lookup(mp
, &VFSTOHFS(mp
)->hfs_export
, nam
);
1397 result
= VFS_VGET(mp
, &hfsfhp
->hfsfid_cnid
, &nvp
);
1398 if (result
) return result
;
1399 if (nvp
== NULL
) return ESTALE
;
1401 if ((hfsfhp
->hfsfid_gen
!= VTOH(nvp
)->h_meta
->h_crtime
)) {
1407 *exflagsp
= np
->netc_exflags
;
1408 *credanonp
= &np
->netc_anon
;
1415 * Vnode pointer to File handle
1418 static int hfs_vptofh(vp
, fhp
)
1423 struct hfsfid
*hfsfhp
;
1424 struct proc
*p
= current_proc();
1427 DBG_FUNC_NAME("hfs_vptofh");
1428 DBG_PRINT_FUNC_NAME();
1431 hfsfhp
= (struct hfsfid
*)fhp
;
1433 /* If a file handle is requested for a file on an HFS volume we must be sure
1434 to create the thread record before returning the object id in the filehandle
1435 to make sure the file can be retrieved by fileid if necessary:
1437 if ((vp
->v_type
== VREG
) && ISHFS(VTOVCB(vp
))) {
1438 /* Create a thread record and return the FileID [which is the file's fileNumber] */
1439 /* lock catalog b-tree */
1440 if ((result
= hfs_metafilelocking(VTOHFS(vp
), kHFSCatalogFileID
, LK_EXCLUSIVE
, p
)) != 0) return result
;
1441 result
= hfsCreateFileID(VTOVCB(vp
), H_DIRID(hp
), H_NAME(hp
), H_HINT(hp
), &fileID
);
1442 (void) hfs_metafilelocking(VTOHFS(vp
), kHFSCatalogFileID
, LK_RELEASE
, p
);
1444 DBG_ERR(("hfs_vptofh: error %d on CreateFileIDRef.\n", result
));
1447 DBG_ASSERT(fileID
== H_FILEID(hp
));
1450 hfsfhp
->hfsfid_len
= sizeof(struct hfsfid
);
1451 hfsfhp
->hfsfid_pad
= 0;
1452 hfsfhp
->hfsfid_cnid
= H_FILEID(hp
);
1453 hfsfhp
->hfsfid_gen
= hp
->h_meta
->h_crtime
;
1460 * Initial HFS filesystems, done only once.
1464 struct vfsconf
*vfsp
;
1467 static int done
= 0;
1470 DBG_FUNC_NAME("hfs_init");
1471 DBG_PRINT_FUNC_NAME();
1477 hfs_converterinit();
1479 simple_lock_init (&gBufferPtrListLock
);
1481 for (i
= BUFFERPTRLISTSIZE
- 1; i
>= 0; --i
) {
1482 gBufferAddress
[i
] = NULL
;
1483 gBufferHeaderPtr
[i
] = NULL
;
1485 gBufferListIndex
= 0;
1488 * Do any initialization that the MacOS/MacOS X shared code relies on
1489 * (normally done as part of MacOS's startup):
1491 MALLOC(gFSMVars
, FSVarsRec
*, sizeof(FSVarsRec
), M_TEMP
, M_WAITOK
);
1492 bzero(gFSMVars
, sizeof(FSVarsRec
));
1495 * Allocate Catalog Iterator cache...
1497 err
= InitCatalogCache();
1499 if (err
) panic("hfs_init: Error returned from InitCatalogCache() call.");
1502 * XXX do we need to setup the following?
1504 * GMT offset, Unicode globals, CatSearch Buffers, BTSscanner
1512 * fast filesystem related variables.
1514 static int hfs_sysctl(name
, namelen
, oldp
, oldlenp
, newp
, newlen
, p
)
1523 DBG_FUNC_NAME("hfs_sysctl");
1524 DBG_PRINT_FUNC_NAME();
1526 return (EOPNOTSUPP
);
1530 /* This will return a vnode of either a directory or a data vnode based on an object id. If
1531 * it is a file id, its data fork will be returned.
1534 hfs_vget(struct mount
*mp
,
1538 struct hfsmount
*hfsmp
;
1540 int retval
= E_NONE
;
1542 DBG_VFS(("hfs_vget: ino = %ld\n", *(UInt32
*)ino
));
1544 /* Check if unmount in progress */
1545 if (mp
->mnt_kern_flag
& MNTK_UNMOUNT
) {
1550 hfsmp
= VFSTOHFS(mp
);
1551 dev
= hfsmp
->hfs_raw_dev
;
1553 /* First check to see if it is in the cache */
1554 *vpp
= hfs_vhashget(dev
, *(UInt32
*)ino
, kDefault
);
1556 /* hide open files that have been deleted */
1558 if ((VTOH(*vpp
)->h_meta
->h_metaflags
& IN_NOEXISTS
) ||
1559 (hfsmp
->hfs_private_metadata_dir
!= 0) &&
1560 (H_DIRID(VTOH(*vpp
)) == hfsmp
->hfs_private_metadata_dir
)) {
1567 /* The vnode is not in the cache, so lets make it */
1570 hfsCatalogInfo catInfo
;
1571 struct proc
*p
= current_proc();
1574 INIT_CATALOGDATA(&catInfo
.nodeData
, 0);
1575 catInfo
.hint
= kNoHint
;
1576 /* Special-case the root's parent directory (DirID = 1) because
1577 it doesn't actually exist in the catalog: */
1578 if ((*vpp
== NULL
) && (*(UInt32
*)ino
== kRootParID
)) {
1579 bzero(&catInfo
, sizeof(catInfo
));
1580 catInfo
.nodeData
.cnd_type
= kCatalogFolderNode
;
1581 catInfo
.nodeData
.cnm_nameptr
= catInfo
.nodeData
.cnm_namespace
;
1582 catInfo
.nodeData
.cnm_namespace
[0] = '/';
1583 catInfo
.nodeData
.cnm_length
= 1;
1584 catInfo
.nodeData
.cnd_nodeID
= kRootParID
;
1585 catInfo
.nodeData
.cnm_parID
= kRootParID
;
1586 catInfo
.nodeData
.cnd_valence
= 1;
1587 catInfo
.nodeData
.cnd_ownerID
= 0;
1588 catInfo
.nodeData
.cnd_groupID
= 0;
1589 catInfo
.nodeData
.cnd_mode
= (S_IFDIR
| S_IRWXU
| S_IRWXG
| S_IRWXO
);
1592 /* lock catalog b-tree */
1593 retval
= hfs_metafilelocking(hfsmp
, kHFSCatalogFileID
, LK_SHARED
, p
);
1594 if (retval
!= E_NONE
) goto Lookup_Err_Exit
;
1596 retval
= hfs_getcatalog(VFSTOVCB(mp
), *(UInt32
*)ino
, NULL
, -1, &catInfo
);
1598 /* unlock catalog b-tree */
1599 (void) hfs_metafilelocking(hfsmp
, kHFSCatalogFileID
, LK_RELEASE
, p
);
1601 if (retval
!= E_NONE
) goto Lookup_Err_Exit
;
1603 /* hide open files that have been deleted */
1604 if ((hfsmp
->hfs_private_metadata_dir
!= 0) &&
1605 (catInfo
.nodeData
.cnm_parID
== hfsmp
->hfs_private_metadata_dir
)) {
1607 goto Lookup_Err_Exit
;
1611 forkType
= (catInfo
.nodeData
.cnd_type
== kCatalogFolderNode
) ? kDirectory
: kDataFork
;
1612 retval
= hfs_vcreate(VFSTOVCB(mp
), &catInfo
, forkType
, vpp
);
1615 CLEAN_CATALOGDATA(&catInfo
.nodeData
);
1618 UBCINFOCHECK("hfs_vget", *vpp
);
1622 if (retval
!= E_NONE
) {
1623 DBG_VFS(("hfs_vget: Error returned of %d\n", retval
));
1626 DBG_VFS(("hfs_vget: vp = 0x%x\n", (u_int
)*vpp
));
1634 * Flush out all the files in a filesystem.
1637 hfs_flushfiles(struct mount
*mp
, int flags
)
1641 error
= vflush(mp
, NULLVP
, (SKIPSYSTEM
| SKIPSWAP
| flags
));
1642 error
= vflush(mp
, NULLVP
, (SKIPSYSTEM
| flags
));
1647 short hfs_flushMDB(struct hfsmount
*hfsmp
, int waitfor
)
1649 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
1651 HFSMasterDirectoryBlock
*mdb
;
1654 int size
= kMDBSize
; /* 512 */
1657 if (vcb
->vcbSigWord
!= kHFSSigWord
)
1660 DBG_ASSERT(hfsmp
->hfs_devvp
!= NULL
);
1662 retval
= bread(hfsmp
->hfs_devvp
, IOBLKNOFORBLK(kMasterDirectoryBlock
, size
),
1663 IOBYTECCNTFORBLK(kMasterDirectoryBlock
, kMDBSize
, size
), NOCRED
, &bp
);
1665 DBG_VFS((" hfs_flushMDB bread return error! (%d)\n", retval
));
1670 DBG_ASSERT(bp
!= NULL
);
1671 DBG_ASSERT(bp
->b_data
!= NULL
);
1672 DBG_ASSERT(bp
->b_bcount
== size
);
1674 mdb
= (HFSMasterDirectoryBlock
*)((char *)bp
->b_data
+ IOBYTEOFFSETFORBLK(kMasterDirectoryBlock
, size
));
1677 mdb
->drCrDate
= SWAP_BE32 (UTCToLocal(vcb
->vcbCrDate
));
1678 mdb
->drLsMod
= SWAP_BE32 (UTCToLocal(vcb
->vcbLsMod
));
1679 mdb
->drAtrb
= SWAP_BE16 (vcb
->vcbAtrb
);
1680 mdb
->drNmFls
= SWAP_BE16 (vcb
->vcbNmFls
);
1681 mdb
->drAllocPtr
= SWAP_BE16 (vcb
->nextAllocation
);
1682 mdb
->drClpSiz
= SWAP_BE32 (vcb
->vcbClpSiz
);
1683 mdb
->drNxtCNID
= SWAP_BE32 (vcb
->vcbNxtCNID
);
1684 mdb
->drFreeBks
= SWAP_BE16 (vcb
->freeBlocks
);
1686 namelen
= strlen(vcb
->vcbVN
);
1687 retval
= utf8_to_hfs(vcb
, namelen
, vcb
->vcbVN
, mdb
->drVN
);
1688 /* Retry with MacRoman in case that's how it was exported. */
1690 retval
= utf8_to_mac_roman(namelen
, vcb
->vcbVN
, mdb
->drVN
);
1692 mdb
->drVolBkUp
= SWAP_BE32 (UTCToLocal(vcb
->vcbVolBkUp
));
1693 mdb
->drVSeqNum
= SWAP_BE16 (vcb
->vcbVSeqNum
);
1694 mdb
->drWrCnt
= SWAP_BE32 (vcb
->vcbWrCnt
);
1695 mdb
->drNmRtDirs
= SWAP_BE16 (vcb
->vcbNmRtDirs
);
1696 mdb
->drFilCnt
= SWAP_BE32 (vcb
->vcbFilCnt
);
1697 mdb
->drDirCnt
= SWAP_BE32 (vcb
->vcbDirCnt
);
1699 bcopy(vcb
->vcbFndrInfo
, mdb
->drFndrInfo
, sizeof(mdb
->drFndrInfo
));
1701 fcb
= VTOFCB(vcb
->extentsRefNum
);
1702 /* HFSPlusToHFSExtents(fcb->fcbExtents, mdb->drXTExtRec); */
1703 mdb
->drXTExtRec
[0].startBlock
= SWAP_BE16 (fcb
->fcbExtents
[0].startBlock
);
1704 mdb
->drXTExtRec
[0].blockCount
= SWAP_BE16 (fcb
->fcbExtents
[0].blockCount
);
1705 mdb
->drXTExtRec
[1].startBlock
= SWAP_BE16 (fcb
->fcbExtents
[1].startBlock
);
1706 mdb
->drXTExtRec
[1].blockCount
= SWAP_BE16 (fcb
->fcbExtents
[1].blockCount
);
1707 mdb
->drXTExtRec
[2].startBlock
= SWAP_BE16 (fcb
->fcbExtents
[2].startBlock
);
1708 mdb
->drXTExtRec
[2].blockCount
= SWAP_BE16 (fcb
->fcbExtents
[2].blockCount
);
1710 mdb
->drXTFlSize
= SWAP_BE32 (fcb
->fcbPLen
);
1711 mdb
->drXTClpSiz
= SWAP_BE32 (fcb
->fcbClmpSize
);
1713 fcb
= VTOFCB(vcb
->catalogRefNum
);
1714 /* HFSPlusToHFSExtents(fcb->fcbExtents, mdb->drCTExtRec); */
1715 mdb
->drCTExtRec
[0].startBlock
= SWAP_BE16 (fcb
->fcbExtents
[0].startBlock
);
1716 mdb
->drCTExtRec
[0].blockCount
= SWAP_BE16 (fcb
->fcbExtents
[0].blockCount
);
1717 mdb
->drCTExtRec
[1].startBlock
= SWAP_BE16 (fcb
->fcbExtents
[1].startBlock
);
1718 mdb
->drCTExtRec
[1].blockCount
= SWAP_BE16 (fcb
->fcbExtents
[1].blockCount
);
1719 mdb
->drCTExtRec
[2].startBlock
= SWAP_BE16 (fcb
->fcbExtents
[2].startBlock
);
1720 mdb
->drCTExtRec
[2].blockCount
= SWAP_BE16 (fcb
->fcbExtents
[2].blockCount
);
1722 mdb
->drCTFlSize
= SWAP_BE32 (fcb
->fcbPLen
);
1723 mdb
->drCTClpSiz
= SWAP_BE32 (fcb
->fcbClmpSize
);
1726 if (waitfor
!= MNT_WAIT
)
1729 retval
= VOP_BWRITE(bp
);
1731 MarkVCBClean( vcb
);
1737 short hfs_flushvolumeheader(struct hfsmount
*hfsmp
, int waitfor
)
1739 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
1741 HFSPlusVolumeHeader
*volumeHeader
;
1743 int size
= sizeof(HFSPlusVolumeHeader
);
1747 if (vcb
->vcbSigWord
!= kHFSPlusSigWord
)
1750 retval
= bread(hfsmp
->hfs_devvp
, IOBLKNOFORBLK((vcb
->hfsPlusIOPosOffset
/ 512) + kMasterDirectoryBlock
, size
),
1751 IOBYTECCNTFORBLK(kMasterDirectoryBlock
, kMDBSize
, size
), NOCRED
, &bp
);
1753 DBG_VFS((" hfs_flushvolumeheader bread return error! (%d)\n", retval
));
1758 DBG_ASSERT(bp
!= NULL
);
1759 DBG_ASSERT(bp
->b_data
!= NULL
);
1760 DBG_ASSERT(bp
->b_bcount
== size
);
1762 volumeHeader
= (HFSPlusVolumeHeader
*)((char *)bp
->b_data
+
1763 IOBYTEOFFSETFORBLK((vcb
->hfsPlusIOPosOffset
/ 512) + kMasterDirectoryBlock
, size
));
1766 * For embedded HFS+ volumes, update create date if it changed
1767 * (ie from a setattrlist call)
1769 if ((vcb
->hfsPlusIOPosOffset
!= 0) && (SWAP_BE32 (volumeHeader
->createDate
) != vcb
->localCreateDate
))
1772 HFSMasterDirectoryBlock
*mdb
;
1774 retval
= bread(hfsmp
->hfs_devvp
, IOBLKNOFORBLK(kMasterDirectoryBlock
, kMDBSize
),
1775 IOBYTECCNTFORBLK(kMasterDirectoryBlock
, kMDBSize
, kMDBSize
), NOCRED
, &bp2
);
1776 if (retval
!= E_NONE
) {
1777 if (bp2
) brelse(bp2
);
1779 mdb
= (HFSMasterDirectoryBlock
*)((char *)bp2
->b_data
+ IOBYTEOFFSETFORBLK(kMasterDirectoryBlock
, kMDBSize
));
1781 if ( SWAP_BE32 (mdb
->drCrDate
) != vcb
->localCreateDate
)
1783 mdb
->drCrDate
= SWAP_BE32 (vcb
->localCreateDate
); /* pick up the new create date */
1785 (void) VOP_BWRITE(bp2
); /* write out the changes */
1789 brelse(bp2
); /* just release it */
1795 /* Note: only update the lower 16 bits worth of attributes */
1796 volumeHeader
->attributes
= SWAP_BE32 ((SWAP_BE32 (volumeHeader
->attributes
) & 0xFFFF0000) + (UInt16
) vcb
->vcbAtrb
);
1797 volumeHeader
->lastMountedVersion
= SWAP_BE32 (kHFSPlusMountVersion
);
1798 volumeHeader
->createDate
= SWAP_BE32 (vcb
->localCreateDate
); /* volume create date is in local time */
1799 volumeHeader
->modifyDate
= SWAP_BE32 (vcb
->vcbLsMod
);
1800 volumeHeader
->backupDate
= SWAP_BE32 (vcb
->vcbVolBkUp
);
1801 volumeHeader
->checkedDate
= SWAP_BE32 (vcb
->checkedDate
);
1802 volumeHeader
->fileCount
= SWAP_BE32 (vcb
->vcbFilCnt
);
1803 volumeHeader
->folderCount
= SWAP_BE32 (vcb
->vcbDirCnt
);
1804 volumeHeader
->freeBlocks
= SWAP_BE32 (vcb
->freeBlocks
);
1805 volumeHeader
->nextAllocation
= SWAP_BE32 (vcb
->nextAllocation
);
1806 volumeHeader
->rsrcClumpSize
= SWAP_BE32 (vcb
->vcbClpSiz
);
1807 volumeHeader
->dataClumpSize
= SWAP_BE32 (vcb
->vcbClpSiz
);
1808 volumeHeader
->nextCatalogID
= SWAP_BE32 (vcb
->vcbNxtCNID
);
1809 volumeHeader
->writeCount
= SWAP_BE32 (vcb
->vcbWrCnt
);
1810 volumeHeader
->encodingsBitmap
= SWAP_BE64 (vcb
->encodingsBitmap
);
1812 bcopy( vcb
->vcbFndrInfo
, volumeHeader
->finderInfo
, sizeof(volumeHeader
->finderInfo
) );
1816 fcb
= VTOFCB(vcb
->extentsRefNum
);
1817 /* bcopy( fcb->fcbExtents, volumeHeader->extentsFile.extents, sizeof(HFSPlusExtentRecord) ); */
1818 for (i
= 0; i
< kHFSPlusExtentDensity
; i
++) {
1819 volumeHeader
->extentsFile
.extents
[i
].startBlock
= SWAP_BE32 (fcb
->fcbExtents
[i
].startBlock
);
1820 volumeHeader
->extentsFile
.extents
[i
].blockCount
= SWAP_BE32 (fcb
->fcbExtents
[i
].blockCount
);
1823 fcb
->fcbFlags
&= ~fcbModifiedMask
;
1824 volumeHeader
->extentsFile
.logicalSize
= SWAP_BE64 (fcb
->fcbEOF
);
1825 volumeHeader
->extentsFile
.totalBlocks
= SWAP_BE32 (fcb
->fcbPLen
/ vcb
->blockSize
);
1826 volumeHeader
->extentsFile
.clumpSize
= SWAP_BE32 (fcb
->fcbClmpSize
);
1828 fcb
= VTOFCB(vcb
->catalogRefNum
);
1829 /* bcopy( fcb->fcbExtents, volumeHeader->catalogFile.extents, sizeof(HFSPlusExtentRecord) ); */
1830 for (i
= 0; i
< kHFSPlusExtentDensity
; i
++) {
1831 volumeHeader
->catalogFile
.extents
[i
].startBlock
= SWAP_BE32 (fcb
->fcbExtents
[i
].startBlock
);
1832 volumeHeader
->catalogFile
.extents
[i
].blockCount
= SWAP_BE32 (fcb
->fcbExtents
[i
].blockCount
);
1835 fcb
->fcbFlags
&= ~fcbModifiedMask
;
1836 volumeHeader
->catalogFile
.logicalSize
= SWAP_BE64 (fcb
->fcbEOF
);
1837 volumeHeader
->catalogFile
.totalBlocks
= SWAP_BE32 (fcb
->fcbPLen
/ vcb
->blockSize
);
1838 volumeHeader
->catalogFile
.clumpSize
= SWAP_BE32 (fcb
->fcbClmpSize
);
1840 fcb
= VTOFCB(vcb
->allocationsRefNum
);
1841 /* bcopy( fcb->fcbExtents, volumeHeader->allocationFile.extents, sizeof(HFSPlusExtentRecord) ); */
1842 for (i
= 0; i
< kHFSPlusExtentDensity
; i
++) {
1843 volumeHeader
->allocationFile
.extents
[i
].startBlock
= SWAP_BE32 (fcb
->fcbExtents
[i
].startBlock
);
1844 volumeHeader
->allocationFile
.extents
[i
].blockCount
= SWAP_BE32 (fcb
->fcbExtents
[i
].blockCount
);
1847 fcb
->fcbFlags
&= ~fcbModifiedMask
;
1848 volumeHeader
->allocationFile
.logicalSize
= SWAP_BE64 (fcb
->fcbEOF
);
1849 volumeHeader
->allocationFile
.totalBlocks
= SWAP_BE32 (fcb
->fcbPLen
/ vcb
->blockSize
);
1850 volumeHeader
->allocationFile
.clumpSize
= SWAP_BE32 (fcb
->fcbClmpSize
);
1852 if (waitfor
!= MNT_WAIT
)
1855 retval
= VOP_BWRITE(bp
);
1857 MarkVCBClean( vcb
);
1864 * Moved here to avoid having to define prototypes
1868 * hfs vfs operations.
1870 struct vfsops hfs_vfsops
= {