]> git.saurik.com Git - apple/xnu.git/blob - bsd/hfs/hfs_vfsops.c
xnu-201.19.3.tar.gz
[apple/xnu.git] / bsd / hfs / hfs_vfsops.c
1 /*
2 * Copyright (c) 1999-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
11 *
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
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
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.
30 *
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
33 * are met:
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.
46 *
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
57 * SUCH DAMAGE.
58 *
59 * hfs_vfsops.c
60 * derived from @(#)ufs_vfsops.c 8.8 (Berkeley) 5/20/95
61 *
62 * (c) Copyright 1997-1998 Apple Computer, Inc. All rights reserved.
63 *
64 * hfs_vfsops.c -- VFS layer for loadable HFS file system.
65 *
66 * HISTORY
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
102 */
103 #include <sys/param.h>
104 #include <sys/systm.h>
105
106 #include <sys/ubc.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>
116
117 #include "hfs.h"
118 #include "hfs_dbg.h"
119 #include "hfs_endian.h"
120
121 #include "hfscommon/headers/FileMgrInternal.h"
122 #include "hfscommon/headers/BTreesInternal.h"
123
124 #if HFS_DIAGNOSTIC
125 int hfs_dbg_all = 0;
126 int hfs_dbg_vfs = 0;
127 int hfs_dbg_vop = 0;
128 int hfs_dbg_load = 0;
129 int hfs_dbg_io = 0;
130 int hfs_dbg_utils = 0;
131 int hfs_dbg_rw = 0;
132 int hfs_dbg_lookup = 0;
133 int hfs_dbg_tree = 0;
134 int hfs_dbg_err = 0;
135 int hfs_dbg_test = 0;
136 #endif
137
138 /*
139 * HFS File System globals:
140 */
141 Ptr gBufferAddress[BUFFERPTRLISTSIZE];
142 struct buf *gBufferHeaderPtr[BUFFERPTRLISTSIZE];
143 int gBufferListIndex;
144 simple_lock_data_t gBufferPtrListLock;
145
146 //static char hfs_fs_name[MFSNAMELEN] = "hfs";
147
148
149 /*
150 * Global variables defined in other modules:
151 */
152 extern struct vnodeopv_desc hfs_vnodeop_opv_desc;
153
154 extern struct vnode *hfs_vhashget(dev_t dev, UInt32 nodeID, UInt8 forkType);
155
156 extern OSErr HFSPlusToHFSExtents( const HFSPlusExtentRecord oldExtents, HFSExtentRecord newExtents);
157
158
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);
164
165 int hfs_changefs(struct mount *mp, struct hfs_mount_args *args, struct proc *p);
166
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);
172
173
174 static int hfs_statfs();
175
176
177 /*
178 * Called by vfs_mountroot when mounting HFS Plus as root.
179 */
180 int
181 hfs_mountroot()
182 {
183 extern struct vnode *rootvp;
184 struct mount *mp;
185 struct proc *p = current_proc(); /* XXX */
186 struct hfsmount *hfsmp;
187 int error;
188
189 /*
190 * Get vnode for rootdev.
191 */
192 if ((error = bdevvp(rootdev, &rootvp))) {
193 printf("hfs_mountroot: can't setup bdevvp");
194 return (error);
195 }
196 if ((error = vfs_rootmountalloc("hfs", "root_device", &mp)))
197 return (error);
198 if ((error = hfs_mountfs(rootvp, mp, p, NULL))) {
199 mp->mnt_vfc->vfc_refcount--;
200 vfs_unbusy(mp, p);
201 _FREE_ZONE(mp, sizeof (struct mount), M_MOUNT);
202 return (error);
203 }
204 simple_lock(&mountlist_slock);
205 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
206 simple_unlock(&mountlist_slock);
207
208 /* Init hfsmp */
209 hfsmp = VFSTOHFS(mp);
210
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 */
215
216 (void)hfs_statfs(mp, &mp->mnt_stat, p);
217
218 vfs_unbusy(mp, p);
219 inittodr(to_bsd_time(HFSTOVCB(hfsmp)->vcbLsMod));
220 return (0);
221 }
222
223
224 /*
225 * VFS Operations.
226 *
227 * mount system call
228 */
229
230 int
231 hfs_mount (mp, path, data, ndp, p)
232 register struct mount *mp;
233 char *path;
234 caddr_t data;
235 struct nameidata *ndp;
236 struct proc *p;
237 {
238 struct hfsmount *hfsmp = NULL;
239 struct vnode *devvp;
240 struct hfs_mount_args args;
241 size_t size;
242 int retval = E_NONE;
243 int flags;
244 mode_t accessmode;
245 int loadconv = 0;
246
247 if ((retval = copyin(data, (caddr_t)&args, sizeof(args))))
248 goto error_exit;
249
250 /*
251 * If updating, check whether changing from read-only to
252 * read/write; if there is no device name, that's all we do.
253 */
254 if (mp->mnt_flag & MNT_UPDATE) {
255
256 hfsmp = VFSTOHFS(mp);
257 if ((hfsmp->hfs_fs_ronly == 0) && (mp->mnt_flag & MNT_RDONLY)) {
258
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))
262 goto error_exit;
263
264 flags = WRITECLOSE;
265 if (mp->mnt_flag & MNT_FORCE)
266 flags |= FORCECLOSE;
267
268 if ((retval = hfs_flushfiles(mp, flags)))
269 goto error_exit;
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);
274 else
275 retval = hfs_flushMDB(hfsmp, MNT_WAIT);
276
277 /* also get the volume bitmap blocks */
278 if (!retval)
279 retval = VOP_FSYNC(hfsmp->hfs_devvp, NOCRED, MNT_WAIT, p);
280
281 if (retval) {
282 hfsmp->hfs_fs_clean = 0;
283 hfsmp->hfs_fs_ronly = 0;
284 goto error_exit;
285 }
286 }
287
288 if ((mp->mnt_flag & MNT_RELOAD) &&
289 (retval = hfs_reload(mp, ndp->ni_cnd.cn_cred, p)))
290 goto error_exit;
291
292 if (hfsmp->hfs_fs_ronly && (mp->mnt_kern_flag & MNTK_WANTRDWR)) {
293 /*
294 * If upgrade to read-write by non-root, then verify
295 * that user has necessary permissions on the device.
296 */
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);
302 goto error_exit;
303 }
304 VOP_UNLOCK(devvp, 0, p);
305 }
306 if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
307 retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT);
308 else
309 retval = hfs_flushMDB(hfsmp, MNT_WAIT);
310
311 if (retval != E_NONE)
312 goto error_exit;
313
314 /* only change hfs_fs_ronly after a successfull write */
315 hfsmp->hfs_fs_ronly = 0;
316 hfsmp->hfs_fs_clean = 0;
317 }
318
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));
323 }
324
325 if (args.fspec == 0) {
326 /*
327 * Process export requests.
328 */
329 return vfs_export(mp, &hfsmp->hfs_export, &args.export);
330 }
331 }
332
333 /*
334 * Not an update, or updating the name: look up the name
335 * and verify that it refers to a sensible block device.
336 */
337 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
338 retval = namei(ndp);
339 if (retval != E_NONE) {
340 DBG_ERR(("hfs_mount: CAN'T GET DEVICE: %s, %x\n", args.fspec, ndp->ni_vp->v_rdev));
341 goto error_exit;
342 }
343
344 devvp = ndp->ni_vp;
345
346 if (devvp->v_type != VBLK) {
347 vrele(devvp);
348 retval = ENOTBLK;
349 goto error_exit;
350 }
351 if (major(devvp->v_rdev) >= nblkdev) {
352 vrele(devvp);
353 retval = ENXIO;
354 goto error_exit;
355 }
356
357 /*
358 * If mount by non-root, then verify that user has necessary
359 * permissions on the device.
360 */
361 if (p->p_ucred->cr_uid != 0) {
362 accessmode = VREAD;
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))) {
367 vput(devvp);
368 goto error_exit;
369 }
370 VOP_UNLOCK(devvp, 0, p);
371 }
372
373 if ((mp->mnt_flag & MNT_UPDATE) == 0) {
374 retval = hfs_mountfs(devvp, mp, p, &args);
375 if (retval != E_NONE)
376 vrele(devvp);
377 } else {
378 if (devvp != hfsmp->hfs_devvp)
379 retval = EINVAL; /* needs translation */
380 else
381 retval = hfs_changefs(mp, &args, p);
382 vrele(devvp);
383 }
384
385 if (retval != E_NONE) {
386 goto error_exit;
387 }
388
389
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;
395 }
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);
401 return (E_NONE);
402
403 error_exit:
404
405 return (retval);
406 }
407
408
409 /* change fs mount parameters */
410 int
411 hfs_changefs(mp, args, p)
412 struct mount *mp;
413 struct hfs_mount_args *args;
414 struct proc *p;
415 {
416 int retval;
417 int namefix, permfix, permswitch;
418 struct hfsmount *hfsmp;
419 struct hfsnode *hp;
420 mode_t hfs_file_mask;
421 ExtendedVCB *vcb;
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;
426
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". */
434 return EINVAL;
435 };
436 hfsmp->hfs_unknownpermissions = ((mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) != 0);
437 namefix = permfix = 0;
438
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;
442 }
443
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;
447 ++permfix;
448 }
449 if ((args->hfs_gid != (gid_t)VNOVAL) && (hfsmp->hfs_gid != args->hfs_gid)) {
450 hfsmp->hfs_gid = args->hfs_gid;
451 ++permfix;
452 }
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);
459 ++permfix;
460 }
461 }
462
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)) {
467
468 retval = hfs_getconverter(args->hfs_encoding, &get_unicode_func, &get_hfsname_func);
469 if (retval) goto error_exit;
470
471 /*
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
475 * encoded names.
476 *
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.
480 */
481 hfsmp->hfs_get_unicode = get_unicode_func;
482 ++namefix;
483 }
484
485
486 if (!(namefix || permfix || permswitch)) goto exit;
487
488 /*
489 * For each active vnode fix things that changed
490 *
491 * Note that we can visit a vnode more than once
492 * and we can race with fsync.
493 */
494 simple_lock(&mntvnode_slock);
495 loop:
496 for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
497 /*
498 * If the vnode that we are about to fix is no longer
499 * associated with this mount point, start over.
500 */
501 if (vp->v_mount != mp)
502 goto loop;
503
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);
508 continue;
509 }
510 simple_unlock(&mntvnode_slock);
511 retval = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p);
512 if (retval) {
513 simple_lock(&mntvnode_slock);
514 if (retval == ENOENT)
515 goto loop;
516 continue;
517 }
518
519 hp = VTOH(vp);
520
521 INIT_CATALOGDATA(&catInfo.nodeData, 0);
522
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 */
526 if (retval) {
527 if (namefix)
528 cache_purge(vp);
529 vput(vp);
530 simple_lock(&mntvnode_slock);
531 continue;
532 }
533
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) {
538 /*
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.
544 */
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;
548 } else {
549 hp->h_meta->h_uid = catInfo.nodeData.cnd_ownerID;
550 hp->h_meta->h_gid = catInfo.nodeData.cnd_groupID;
551 };
552 hp->h_meta->h_mode = (mode_t)catInfo.nodeData.cnd_mode;
553 } else {
554 /*
555 * Set the permissions as determined by the mount auguments
556 * but keep in account if the file or folder is hfs locked
557 */
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;
561
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;
568 } else {
569 hp->h_meta->h_mode &= IFMT | VTOHFS(vp)->hfs_file_mask;
570 }
571 };
572 };
573
574 /*
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.
578 */
579 if (namefix) {
580 cache_purge(vp);
581 hfs_name_CatToMeta(&catInfo.nodeData, hp->h_meta);
582
583 if (catInfo.nodeData.cnd_nodeID == kHFSRootFolderID)
584 strncpy(vcb->vcbVN, H_NAME(hp), NAME_MAX);
585 }
586
587 CLEAN_CATALOGDATA(&catInfo.nodeData);
588
589 vput(vp);
590 simple_lock(&mntvnode_slock);
591
592 } /* end for (vp...) */
593 simple_unlock(&mntvnode_slock);
594
595
596 exit:
597 /*
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.
601 */
602 if (namefix) {
603 u_long old_encoding = hfsmp->hfs_encoding;
604
605 hfsmp->hfs_get_hfsname = get_hfsname_func;
606 hfsmp->hfs_encoding = args->hfs_encoding;
607 vcb->volumeNameEncodingHint = args->hfs_encoding;
608
609 (void) hfs_relconverter(old_encoding);
610 }
611
612 return (0);
613
614 error_exit:
615
616 return (retval);
617 }
618
619
620 /*
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.
624 *
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.
633 */
634 int
635 hfs_reload(mountp, cred, p)
636 register struct mount *mountp;
637 struct ucred *cred;
638 struct proc *p;
639 {
640 register struct vnode *vp, *nvp, *devvp;
641 struct hfsnode *hp;
642 struct buf *bp;
643 int size, error, i;
644 struct hfsmount *hfsmp;
645 struct HFSPlusVolumeHeader *vhp;
646 ExtendedVCB *vcb;
647 FCB *fcb;
648
649 if ((mountp->mnt_flag & MNT_RDONLY) == 0)
650 return (EINVAL);
651
652 hfsmp = VFSTOHFS(mountp);
653 vcb = HFSTOVCB(hfsmp);
654
655 if (vcb->vcbSigWord == kHFSSigWord)
656 return (EINVAL); /* rooting from HFS is not supported! */
657
658 /*
659 * Invalidate all cached meta-data.
660 */
661 devvp = hfsmp->hfs_devvp;
662 if (vinvalbuf(devvp, 0, cred, p, 0, 0))
663 panic("hfs_reload: dirty1");
664 InvalidateCatalogCache(vcb);
665
666 /*
667 * Re-read VolumeHeader from disk.
668 */
669 size = kMDBSize;
670 error = bread( hfsmp->hfs_devvp,
671 IOBLKNOFORBLK((vcb->hfsPlusIOPosOffset / 512) + kMasterDirectoryBlock, size),
672 IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, size),
673 NOCRED,
674 &bp);
675 if (error) {
676 if (bp != NULL)
677 brelse(bp);
678 return (error);
679 }
680
681 vhp = (HFSPlusVolumeHeader *) ((char *)bp->b_data +
682 IOBYTEOFFSETFORBLK((vcb->hfsPlusIOPosOffset / 512) + kMasterDirectoryBlock, size));
683
684 if ((ValidVolumeHeader(vhp) != 0) || (vcb->blockSize != SWAP_BE32 (vhp->blockSize))) {
685 brelse(bp);
686 return (EIO); /* XXX needs translation */
687 }
688
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 */
704
705 /*
706 * Re-load meta-file vnode data (extent info, file size, etc).
707 */
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);
713 }
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);
717
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);
723 }
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);
727
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);
733 }
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);
737
738 brelse(bp);
739 vhp = NULL;
740
741 /*
742 * Re-load B-tree header data
743 */
744 fcb = VTOFCB((struct vnode *)vcb->extentsRefNum);
745 if (error = MacToVFSError( BTReloadData(fcb) ))
746 return (error);
747
748 fcb = VTOFCB((struct vnode *)vcb->catalogRefNum);
749 if (error = MacToVFSError( BTReloadData(fcb) ))
750 return (error);
751
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) )))
755 return (error);
756
757 /* Re-establish private/hidden directory for unlinked files */
758 hfsmp->hfs_private_metadata_dir = FindMetaDataDirectory(vcb);
759
760 loop:
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);
765 goto loop;
766 }
767 nvp = vp->v_mntvnodes.le_next;
768
769 /*
770 * Invalidate all inactive vnodes.
771 */
772 if (vrecycle(vp, &mntvnode_slock, p))
773 goto loop;
774
775 /*
776 * Invalidate all cached file data.
777 */
778 simple_lock(&vp->v_interlock);
779 simple_unlock(&mntvnode_slock);
780 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) {
781 goto loop;
782 }
783 if (vinvalbuf(vp, 0, cred, p, 0, 0))
784 panic("hfs_reload: dirty2");
785
786 /*
787 * Re-read hfsnode data for all active vnodes (non-metadata files).
788 */
789 hp = VTOH(vp);
790 if ((vp->v_flag & VSYSTEM) == 0) {
791 hfsCatalogInfo catInfo;
792
793 /* lookup by fileID since name could have changed */
794 catInfo.hint = kNoHint;
795 INIT_CATALOGDATA(&catInfo.nodeData, 0);
796
797 if ((error = hfs_getcatalog(vcb, H_FILEID(hp), NULL, -1, &catInfo))) {
798 vput(vp);
799 CLEAN_CATALOGDATA(&catInfo.nodeData);
800 return (error);
801 }
802
803 H_HINT(hp) = catInfo.hint;
804 if (hp->h_meta->h_metaflags & IN_LONGNAME)
805 FREE(H_NAME(hp), M_TEMP);
806 H_NAME(hp) = NULL;
807 hp->h_meta->h_namelen = 0;
808 CopyCatalogToObjectMeta(&catInfo, vp, hp->h_meta);
809 CopyCatalogToFCB(&catInfo, vp);
810
811 CLEAN_CATALOGDATA(&catInfo.nodeData);
812 }
813
814 vput(vp);
815 simple_lock(&mntvnode_slock);
816 }
817 simple_unlock(&mntvnode_slock);
818
819 return (0);
820 }
821
822
823 /*
824 * Common code for mount and mountroot
825 */
826 int
827 hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p, struct hfs_mount_args *args)
828 {
829 int retval = E_NONE;
830 register struct hfsmount *hfsmp;
831 struct buf *bp;
832 dev_t dev;
833 HFSMasterDirectoryBlock *mdbp;
834 int ronly;
835 struct ucred *cred;
836 u_long diskBlks;
837 u_long blksize;
838 DBG_VFS(("hfs_mountfs: mp = 0x%lX\n", (u_long)mp));
839
840 dev = devvp->v_rdev;
841 cred = p ? p->p_ucred : NOCRED;
842 /*
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.
847 */
848 if ((retval = vfs_mountedon(devvp)))
849 return (retval);
850 if ((vcount(devvp) > 1) && (devvp != rootvp))
851 return (EBUSY);
852 if ((retval = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0)))
853 return (retval);
854
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)))
858 return (retval);
859
860 blksize = kHFSBlockSize;
861 DBG_VFS(("hfs_mountfs: size = %d (DEV_BSIZE = %d).\n", blksize, DEV_BSIZE));
862
863 bp = NULL;
864 hfsmp = NULL;
865
866 /*
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;
871 */
872
873 /*
874 * the next three lines should probably be replaced
875 * with a call to the yet unimplemented function VOP_SETBLOCKSIZE
876 */
877 retval = VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE, &blksize, FWRITE, cred, p);
878 if (retval) return retval;
879 devvp->v_specsize = blksize;
880
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",
884 retval);
885 return (retval);
886 }
887
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)));
892
893 if ((retval = bread(devvp, IOBLKNOFORBLK(kMasterDirectoryBlock, blksize),
894 IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, blksize), cred, &bp))) {
895 goto error_exit;
896 };
897 mdbp = (HFSMasterDirectoryBlock*) ((char *)bp->b_data + IOBYTEOFFSETFORBLK(kMasterDirectoryBlock, blksize));
898
899 MALLOC(hfsmp, struct hfsmount *, sizeof(struct hfsmount), M_HFSMNT, M_WAITOK);
900 bzero(hfsmp, sizeof(struct hfsmount));
901
902 simple_lock_init(&hfsmp->hfs_renamelock);
903
904 DBG_VFS(("hfs_mountfs: Initializing hfsmount structure at 0x%lX...\n", (u_long)hfsmp));
905 /*
906 * Init the volume information structure
907 */
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;
914
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);
919 if (args) {
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);
928 } else {
929 hfsmp->hfs_file_mask = args->hfs_mask & ALLPERMS;
930 }
931 } else {
932 hfsmp->hfs_dir_mask = UNKNOWNPERMISSIONS & ALLPERMS; /* 0777: rwx---rwx */
933 hfsmp->hfs_file_mask = UNKNOWNPERMISSIONS & DEFFILEMODE; /* 0666: no --x by default? */
934 };
935 } else {
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? */
942 };
943 };
944
945 /* See above comment for DKIOCGETBLOCKSIZE
946 * retval = VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE, &blksize, FWRITE, cred, p);
947 * if (retval) return retval;
948 */
949
950 retval = VOP_IOCTL(devvp, DKIOCNUMBLKS, (caddr_t)&diskBlks, 0, cred, p);
951 if (retval) return retval;
952
953 if (SWAP_BE16 (mdbp->drSigWord) == kHFSPlusSigWord) {
954 /* Enidan swap volume header in place */
955 /* SWAP_HFS_PLUS_VOLUME_HEADER ((HFSPlusVolumeHeader *)bp->b_data); */
956
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);
960
961 /* Enidan un-swap volume header in place */
962 /* SWAP_HFS_PLUS_VOLUME_HEADER ((HFSPlusVolumeHeader *)bp->b_data); */
963
964 } else if (SWAP_BE16 (mdbp->drEmbedSigWord) == kHFSPlusSigWord) {
965 u_long embBlkOffset;
966 HFSPlusVolumeHeader *vhp;
967
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);
972
973 brelse(bp);
974 bp = NULL; /* done with MDB, go grab Volume Header */
975 mdbp = NULL;
976
977 retval = bread( devvp,
978 IOBLKNOFORBLK(kMasterDirectoryBlock+embBlkOffset, blksize),
979 IOBYTECCNTFORBLK(kMasterDirectoryBlock+embBlkOffset, kMDBSize, blksize),
980 cred,
981 &bp);
982 if (retval) {
983 goto error_exit;
984 };
985 vhp = (HFSPlusVolumeHeader*) ((char *)bp->b_data + IOBYTEOFFSETFORBLK(kMasterDirectoryBlock, blksize));
986
987 /* Enidan swap volume header in place */
988 /* SWAP_HFS_PLUS_VOLUME_HEADER (vhp); */
989
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);
993
994 /* Enidan un-swap volume header in place */
995 /* SWAP_HFS_PLUS_VOLUME_HEADER (vhp); */
996
997 } else if (devvp != rootvp) {
998 if (args) {
999 hfsmp->hfs_encoding = args->hfs_encoding;
1000 HFSTOVCB(hfsmp)->volumeNameEncodingHint = args->hfs_encoding;
1001
1002
1003 /* establish the timezone */
1004 gTimeZone = args->hfs_timezone;
1005 }
1006
1007 retval = hfs_getconverter(hfsmp->hfs_encoding, &hfsmp->hfs_get_unicode, &hfsmp->hfs_get_hfsname);
1008 if (retval) goto error_exit;
1009
1010 /* mount HFS volume */
1011 retval = hfs_MountHFSVolume( hfsmp, mdbp, diskBlks, p);
1012
1013 if (retval)
1014 (void) hfs_relconverter(hfsmp->hfs_encoding);
1015
1016 } else {
1017 /* sorry, we cannot root from HFS */
1018 retval = EINVAL;
1019 }
1020
1021 if ( retval ) {
1022 goto error_exit;
1023 }
1024
1025 brelse(bp);
1026 bp = NULL;
1027
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;
1032
1033 if (ronly == 0) {
1034 hfsmp->hfs_fs_clean = 0;
1035 if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
1036 (void) hfs_flushvolumeheader(hfsmp, MNT_WAIT);
1037 else
1038 (void) hfs_flushMDB(hfsmp, MNT_WAIT);
1039 }
1040 goto std_exit;
1041
1042 error_exit:
1043 DBG_VFS(("hfs_mountfs: exiting with error %d...\n", retval));
1044
1045 if (bp)
1046 brelse(bp);
1047 (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
1048 if (hfsmp) {
1049 FREE(hfsmp, M_HFSMNT);
1050 mp->mnt_data = (qaddr_t)0;
1051 }
1052
1053 std_exit:
1054 return (retval);
1055 }
1056
1057
1058 /*
1059 * Make a filesystem operational.
1060 * Nothing to do at the moment.
1061 */
1062 /* ARGSUSED */
1063 int hfs_start(mp, flags, p)
1064 struct mount *mp;
1065 int flags;
1066 struct proc *p;
1067 {
1068 DBG_FUNC_NAME("hfs_start");
1069 DBG_PRINT_FUNC_NAME();
1070
1071 return (0);
1072 }
1073
1074
1075 /*
1076 * unmount system call
1077 */
1078 int
1079 hfs_unmount(mp, mntflags, p)
1080 struct mount *mp;
1081 int mntflags;
1082 struct proc *p;
1083 {
1084 struct hfsmount *hfsmp = VFSTOHFS(mp);
1085 int retval = E_NONE;
1086 int flags;
1087
1088 flags = 0;
1089 if (mntflags & MNT_FORCE)
1090 flags |= FORCECLOSE;
1091
1092 if ((retval = hfs_flushfiles(mp, flags)))
1093 return (retval);
1094
1095 /*
1096 * Flush out the b-trees, volume bitmap and Volume Header
1097 */
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))
1101 return (retval);
1102
1103 retval = VOP_FSYNC(HFSTOVCB(hfsmp)->extentsRefNum, NOCRED, MNT_WAIT, p);
1104 if (retval && ((mntflags & MNT_FORCE) == 0))
1105 return (retval);
1106
1107 if (retval = VOP_FSYNC(hfsmp->hfs_devvp, NOCRED, MNT_WAIT, p)) {
1108 if ((mntflags & MNT_FORCE) == 0)
1109 return (retval);
1110 }
1111
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;
1116 } else {
1117 hfsmp->hfs_fs_clean = 1;
1118 HFSTOVCB(hfsmp)->vcbAtrb |= kHFSVolumeUnmountedMask;
1119 }
1120 if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
1121 retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT);
1122 else
1123 retval = hfs_flushMDB(hfsmp, MNT_WAIT);
1124
1125 if (retval) {
1126 hfsmp->hfs_fs_clean = 0;
1127 HFSTOVCB(hfsmp)->vcbAtrb &= ~kHFSVolumeUnmountedMask;
1128 if ((mntflags & MNT_FORCE) == 0)
1129 return (retval); /* could not flush everything */
1130 }
1131 }
1132
1133 /*
1134 * Invalidate our caches and release metadata vnodes
1135 */
1136 (void) hfsUnmount(hfsmp, p);
1137
1138 if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord)
1139 (void) hfs_relconverter(hfsmp->hfs_encoding);
1140
1141 hfsmp->hfs_devvp->v_specflags &= ~SI_MOUNTEDON;
1142 retval = VOP_CLOSE(hfsmp->hfs_devvp, hfsmp->hfs_fs_ronly ? FREAD : FREAD|FWRITE,
1143 NOCRED, p);
1144 vrele(hfsmp->hfs_devvp);
1145
1146 FREE(hfsmp, M_HFSMNT);
1147 mp->mnt_data = (qaddr_t)0;
1148
1149 return (retval);
1150 }
1151
1152
1153 /*
1154 * Return the root of a filesystem.
1155 *
1156 * OUT - vpp, should be locked and vget()'d (to increment usecount and lock)
1157 */
1158 int hfs_root(mp, vpp)
1159 struct mount *mp;
1160 struct vnode **vpp;
1161 {
1162 struct vnode *nvp;
1163 int retval;
1164 UInt32 rootObjID = kRootDirID;
1165
1166 DBG_FUNC_NAME("hfs_root");
1167 DBG_PRINT_FUNC_NAME();
1168
1169 if ((retval = VFS_VGET(mp, &rootObjID, &nvp)))
1170 return (retval);
1171
1172 *vpp = nvp;
1173 return (0);
1174 }
1175
1176
1177 /*
1178 * Do operations associated with quotas
1179 */
1180 int hfs_quotactl(mp, cmds, uid, arg, p)
1181 struct mount *mp;
1182 int cmds;
1183 uid_t uid;
1184 caddr_t arg;
1185 struct proc *p;
1186 {
1187 DBG_FUNC_NAME("hfs_quotactl");
1188 DBG_PRINT_FUNC_NAME();
1189
1190 return (EOPNOTSUPP);
1191 }
1192
1193
1194 /*
1195 * Get file system statistics.
1196 */
1197 static int
1198 hfs_statfs(mp, sbp, p)
1199 struct mount *mp;
1200 register struct statfs *sbp;
1201 struct proc *p;
1202 {
1203 ExtendedVCB *vcb = VFSTOVCB(mp);
1204 struct hfsmount *hfsmp = VFSTOHFS(mp);
1205 u_long freeCNIDs;
1206
1207 DBG_FUNC_NAME("hfs_statfs");
1208 DBG_PRINT_FUNC_NAME();
1209
1210 freeCNIDs = (u_long)0xFFFFFFFF - (u_long)vcb->vcbNxtCNID;
1211
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);
1219
1220 sbp->f_type = 0;
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);
1227 }
1228 return (0);
1229 }
1230
1231
1232 /*
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.
1236 *
1237 * Note: we are always called with the filesystem marked `MPBUSY'.
1238 */
1239 static int hfs_sync(mp, waitfor, cred, p)
1240 struct mount *mp;
1241 int waitfor;
1242 struct ucred *cred;
1243 struct proc *p;
1244 {
1245 struct vnode *nvp, *vp;
1246 struct hfsnode *hp;
1247 struct hfsmount *hfsmp = VFSTOHFS(mp);
1248 ExtendedVCB *vcb;
1249 struct vnode *meta_vp[3];
1250 int i;
1251 int error, allerror = 0;
1252
1253 DBG_FUNC_NAME("hfs_sync");
1254 DBG_PRINT_FUNC_NAME();
1255
1256 /*
1257 * During MNT_UPDATE hfs_changefs might be manipulating
1258 * vnodes so back off
1259 */
1260 if (mp->mnt_flag & MNT_UPDATE)
1261 return (0);
1262
1263 hfsmp = VFSTOHFS(mp);
1264 if (hfsmp->hfs_fs_ronly != 0) {
1265 panic("update: rofs mod");
1266 };
1267
1268 /*
1269 * Write back each 'modified' vnode
1270 */
1271
1272 loop:;
1273 simple_lock(&mntvnode_slock);
1274 for (vp = mp->mnt_vnodelist.lh_first;
1275 vp != NULL;
1276 vp = nvp) {
1277 int didhold;
1278 /*
1279 * If the vnode that we are about to sync is no longer
1280 * associated with this mount point, start over.
1281 */
1282 if (vp->v_mount != mp) {
1283 simple_unlock(&mntvnode_slock);
1284 goto loop;
1285 }
1286 simple_lock(&vp->v_interlock);
1287 nvp = vp->v_mntvnodes.le_next;
1288 hp = VTOH(vp);
1289
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);
1296 continue;
1297 }
1298
1299 simple_unlock(&mntvnode_slock);
1300 error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p);
1301 if (error) {
1302 if (error == ENOENT)
1303 goto loop;
1304 simple_lock(&mntvnode_slock);
1305 continue;
1306 }
1307
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));
1311 allerror = error;
1312 };
1313 DBG_ASSERT(*((volatile int *)(&(vp)->v_interlock))==0);
1314 VOP_UNLOCK(vp, 0, p);
1315 if (didhold)
1316 ubc_rele(vp);
1317 vrele(vp);
1318 simple_lock(&mntvnode_slock);
1319 };
1320
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 */
1325
1326 /* Now sync our three metadata files */
1327 for (i = 0; i < 3; ++i) {
1328 struct vnode *btvp;
1329
1330 btvp = meta_vp[i];
1331
1332 if ((btvp==0) || (btvp->v_type == VNON) || (btvp->v_mount != mp))
1333 continue;
1334 simple_lock(&btvp->v_interlock);
1335 hp = VTOH(btvp);
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);
1339 continue;
1340 }
1341 simple_unlock(&mntvnode_slock);
1342 error = vget(btvp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p);
1343 if (error) {
1344 simple_lock(&mntvnode_slock);
1345 continue;
1346 }
1347 if ((error = VOP_FSYNC(btvp, cred, waitfor, p)))
1348 allerror = error;
1349 VOP_UNLOCK(btvp, 0, p);
1350 vrele(btvp);
1351 simple_lock(&mntvnode_slock);
1352 };
1353
1354 simple_unlock(&mntvnode_slock);
1355
1356 /*
1357 * Force stale file system control information to be flushed.
1358 */
1359 if (vcb->vcbSigWord == kHFSSigWord) {
1360 if ((error = VOP_FSYNC(hfsmp->hfs_devvp, cred, waitfor, p)))
1361 allerror = error;
1362 }
1363 /*
1364 * Write back modified superblock.
1365 */
1366
1367 if (IsVCBDirty(vcb)) {
1368 if (vcb->vcbSigWord == kHFSPlusSigWord)
1369 error = hfs_flushvolumeheader(hfsmp, waitfor);
1370 else
1371 error = hfs_flushMDB(hfsmp, waitfor);
1372
1373 if (error)
1374 allerror = error;
1375 };
1376
1377 return (allerror);
1378 }
1379
1380
1381 /*
1382 * File handle to vnode
1383 *
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
1390 */
1391 int
1392 hfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
1393 register struct mount *mp;
1394 struct fid *fhp;
1395 struct mbuf *nam;
1396 struct vnode **vpp;
1397 int *exflagsp;
1398 struct ucred **credanonp;
1399 {
1400 struct hfsfid *hfsfhp;
1401 struct vnode *nvp;
1402 int result;
1403 struct netcred *np;
1404 DBG_FUNC_NAME("hfs_fhtovp");
1405 DBG_PRINT_FUNC_NAME();
1406
1407 *vpp = NULL;
1408 hfsfhp = (struct hfsfid *)fhp;
1409
1410 /*
1411 * Get the export permission structure for this <mp, client> tuple.
1412 */
1413 np = vfs_export_lookup(mp, &VFSTOHFS(mp)->hfs_export, nam);
1414 if (np == NULL) {
1415 return EACCES;
1416 };
1417
1418 result = VFS_VGET(mp, &hfsfhp->hfsfid_cnid, &nvp);
1419 if (result) return result;
1420 if (nvp == NULL) return ESTALE;
1421
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.
1432 */
1433 if ((hfsfhp->hfsfid_gen < VTOH(nvp)->h_meta->h_crtime)) {
1434 vput(nvp);
1435 return ESTALE;
1436 };
1437
1438 *vpp = nvp;
1439 *exflagsp = np->netc_exflags;
1440 *credanonp = &np->netc_anon;
1441
1442 return 0;
1443 }
1444
1445
1446 /*
1447 * Vnode pointer to File handle
1448 */
1449 /* ARGSUSED */
1450 static int hfs_vptofh(vp, fhp)
1451 struct vnode *vp;
1452 struct fid *fhp;
1453 {
1454 struct hfsnode *hp;
1455 struct hfsfid *hfsfhp;
1456 struct proc *p = current_proc();
1457 int result;
1458 u_int32_t fileID;
1459 DBG_FUNC_NAME("hfs_vptofh");
1460 DBG_PRINT_FUNC_NAME();
1461
1462 hp = VTOH(vp);
1463 hfsfhp = (struct hfsfid *)fhp;
1464
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:
1468 */
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);
1475 if (result) {
1476 DBG_ERR(("hfs_vptofh: error %d on CreateFileIDRef.\n", result));
1477 return result;
1478 };
1479 DBG_ASSERT(fileID == H_FILEID(hp));
1480 };
1481
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;
1486
1487 return 0;
1488 }
1489
1490
1491 /*
1492 * Initial HFS filesystems, done only once.
1493 */
1494 int
1495 hfs_init(vfsp)
1496 struct vfsconf *vfsp;
1497 {
1498 int i;
1499 static int done = 0;
1500 OSErr err;
1501
1502 DBG_FUNC_NAME("hfs_init");
1503 DBG_PRINT_FUNC_NAME();
1504
1505 if (done)
1506 return (0);
1507 done = 1;
1508 hfs_vhashinit();
1509 hfs_converterinit();
1510
1511 simple_lock_init (&gBufferPtrListLock);
1512
1513 for (i = BUFFERPTRLISTSIZE - 1; i >= 0; --i) {
1514 gBufferAddress[i] = NULL;
1515 gBufferHeaderPtr[i] = NULL;
1516 };
1517 gBufferListIndex = 0;
1518
1519 /*
1520 * Allocate Catalog Iterator cache...
1521 */
1522 err = InitCatalogCache();
1523
1524 return E_NONE;
1525 }
1526
1527
1528 /*
1529 * fast filesystem related variables.
1530 */
1531 static int hfs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
1532 int *name;
1533 u_int namelen;
1534 void *oldp;
1535 size_t *oldlenp;
1536 void *newp;
1537 size_t newlen;
1538 struct proc *p;
1539 {
1540 DBG_FUNC_NAME("hfs_sysctl");
1541 DBG_PRINT_FUNC_NAME();
1542
1543 return (EOPNOTSUPP);
1544 }
1545
1546
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.
1549 */
1550 int
1551 hfs_vget(struct mount *mp,
1552 void *ino,
1553 struct vnode **vpp)
1554 {
1555 struct hfsmount *hfsmp;
1556 dev_t dev;
1557 int retval = E_NONE;
1558
1559 DBG_VFS(("hfs_vget: ino = %ld\n", *(UInt32 *)ino));
1560
1561 /* Check if unmount in progress */
1562 if (mp->mnt_kern_flag & MNTK_UNMOUNT) {
1563 *vpp = NULL;
1564 return (EPERM);
1565 }
1566
1567 hfsmp = VFSTOHFS(mp);
1568 dev = hfsmp->hfs_raw_dev;
1569
1570 /* First check to see if it is in the cache */
1571 *vpp = hfs_vhashget(dev, *(UInt32 *)ino, kDefault);
1572
1573 /* hide open files that have been deleted */
1574 if (*vpp != NULL) {
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)) {
1578 vput(*vpp);
1579 retval = ENOENT;
1580 goto Err_Exit;
1581 }
1582 }
1583
1584 /* The vnode is not in the cache, so lets make it */
1585 if (*vpp == NULL)
1586 {
1587 hfsCatalogInfo catInfo;
1588 struct proc *p = current_proc();
1589 UInt8 forkType;
1590
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);
1607 } else {
1608
1609 /* lock catalog b-tree */
1610 retval = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_SHARED, p);
1611 if (retval != E_NONE) goto Lookup_Err_Exit;
1612
1613 retval = hfs_getcatalog(VFSTOVCB(mp), *(UInt32 *)ino, NULL, -1, &catInfo);
1614
1615 /* unlock catalog b-tree */
1616 (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p);
1617
1618 if (retval != E_NONE) goto Lookup_Err_Exit;
1619
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)) {
1623 retval = ENOENT;
1624 goto Lookup_Err_Exit;
1625 };
1626 };
1627
1628 forkType = (catInfo.nodeData.cnd_type == kCatalogFolderNode) ? kDirectory : kDataFork;
1629 retval = hfs_vcreate(VFSTOVCB(mp), &catInfo, forkType, vpp);
1630
1631 Lookup_Err_Exit:
1632 CLEAN_CATALOGDATA(&catInfo.nodeData);
1633 };
1634
1635 UBCINFOCHECK("hfs_vget", *vpp);
1636
1637 Err_Exit:
1638
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;
1643
1644 return (retval);
1645
1646 }
1647
1648 /*
1649 * Flush out all the files in a filesystem.
1650 */
1651 int
1652 hfs_flushfiles(struct mount *mp, int flags)
1653 {
1654 int error;
1655
1656 error = vflush(mp, NULLVP, (SKIPSYSTEM | SKIPSWAP | flags));
1657 error = vflush(mp, NULLVP, (SKIPSYSTEM | flags));
1658
1659 return (error);
1660 }
1661
1662 short hfs_flushMDB(struct hfsmount *hfsmp, int waitfor)
1663 {
1664 ExtendedVCB *vcb = HFSTOVCB(hfsmp);
1665 FCB *fcb;
1666 HFSMasterDirectoryBlock *mdb;
1667 struct buf *bp;
1668 int retval;
1669 int size = kMDBSize; /* 512 */
1670 ByteCount namelen;
1671
1672 if (vcb->vcbSigWord != kHFSSigWord)
1673 return EINVAL;
1674
1675 DBG_ASSERT(hfsmp->hfs_devvp != NULL);
1676
1677 retval = bread(hfsmp->hfs_devvp, IOBLKNOFORBLK(kMasterDirectoryBlock, size),
1678 IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, size), NOCRED, &bp);
1679 if (retval) {
1680 DBG_VFS((" hfs_flushMDB bread return error! (%d)\n", retval));
1681 if (bp) brelse(bp);
1682 return retval;
1683 }
1684
1685 DBG_ASSERT(bp != NULL);
1686 DBG_ASSERT(bp->b_data != NULL);
1687 DBG_ASSERT(bp->b_bcount == size);
1688
1689 mdb = (HFSMasterDirectoryBlock *)((char *)bp->b_data + IOBYTEOFFSETFORBLK(kMasterDirectoryBlock, size));
1690
1691 VCB_LOCK(vcb);
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);
1700
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. */
1704 if (retval)
1705 retval = utf8_to_mac_roman(namelen, vcb->vcbVN, mdb->drVN);
1706
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);
1712
1713 bcopy(vcb->vcbFndrInfo, mdb->drFndrInfo, sizeof(mdb->drFndrInfo));
1714
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);
1723
1724 mdb->drXTFlSize = SWAP_BE32 (fcb->fcbPLen);
1725 mdb->drXTClpSiz = SWAP_BE32 (fcb->fcbClmpSize);
1726
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);
1735
1736 mdb->drCTFlSize = SWAP_BE32 (fcb->fcbPLen);
1737 mdb->drCTClpSiz = SWAP_BE32 (fcb->fcbClmpSize);
1738 VCB_UNLOCK(vcb);
1739
1740 if (waitfor != MNT_WAIT)
1741 bawrite(bp);
1742 else
1743 retval = VOP_BWRITE(bp);
1744
1745 MarkVCBClean( vcb );
1746
1747 return (retval);
1748 }
1749
1750
1751 short hfs_flushvolumeheader(struct hfsmount *hfsmp, int waitfor)
1752 {
1753 ExtendedVCB *vcb = HFSTOVCB(hfsmp);
1754 FCB *fcb;
1755 HFSPlusVolumeHeader *volumeHeader;
1756 int retval;
1757 int size = sizeof(HFSPlusVolumeHeader);
1758 struct buf *bp;
1759 int i;
1760
1761 if (vcb->vcbSigWord != kHFSPlusSigWord)
1762 return EINVAL;
1763
1764 retval = bread(hfsmp->hfs_devvp, IOBLKNOFORBLK((vcb->hfsPlusIOPosOffset / 512) + kMasterDirectoryBlock, size),
1765 IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, size), NOCRED, &bp);
1766 if (retval) {
1767 DBG_VFS((" hfs_flushvolumeheader bread return error! (%d)\n", retval));
1768 if (bp) brelse(bp);
1769 return retval;
1770 }
1771
1772 DBG_ASSERT(bp != NULL);
1773 DBG_ASSERT(bp->b_data != NULL);
1774 DBG_ASSERT(bp->b_bcount == size);
1775
1776 volumeHeader = (HFSPlusVolumeHeader *)((char *)bp->b_data +
1777 IOBYTEOFFSETFORBLK((vcb->hfsPlusIOPosOffset / 512) + kMasterDirectoryBlock, size));
1778
1779 /*
1780 * For embedded HFS+ volumes, update create date if it changed
1781 * (ie from a setattrlist call)
1782 */
1783 if ((vcb->hfsPlusIOPosOffset != 0) && (SWAP_BE32 (volumeHeader->createDate) != vcb->localCreateDate))
1784 {
1785 struct buf *bp2;
1786 HFSMasterDirectoryBlock *mdb;
1787
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);
1792 } else {
1793 mdb = (HFSMasterDirectoryBlock *)((char *)bp2->b_data + IOBYTEOFFSETFORBLK(kMasterDirectoryBlock, kMDBSize));
1794
1795 if ( SWAP_BE32 (mdb->drCrDate) != vcb->localCreateDate )
1796 {
1797 mdb->drCrDate = SWAP_BE32 (vcb->localCreateDate); /* pick up the new create date */
1798
1799 (void) VOP_BWRITE(bp2); /* write out the changes */
1800 }
1801 else
1802 {
1803 brelse(bp2); /* just release it */
1804 }
1805 }
1806 }
1807
1808 VCB_LOCK(vcb);
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);
1825
1826 bcopy( vcb->vcbFndrInfo, volumeHeader->finderInfo, sizeof(volumeHeader->finderInfo) );
1827
1828 VCB_UNLOCK(vcb);
1829
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);
1835 }
1836
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);
1841
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);
1847 }
1848
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);
1853
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);
1859 }
1860
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);
1865
1866 if (waitfor != MNT_WAIT)
1867 bawrite(bp);
1868 else
1869 retval = VOP_BWRITE(bp);
1870
1871 MarkVCBClean( vcb );
1872
1873 return (retval);
1874 }
1875
1876
1877 /*
1878 * Moved here to avoid having to define prototypes
1879 */
1880
1881 /*
1882 * hfs vfs operations.
1883 */
1884 struct vfsops hfs_vfsops = {
1885 hfs_mount,
1886 hfs_start,
1887 hfs_unmount,
1888 hfs_root,
1889 hfs_quotactl,
1890 hfs_statfs,
1891 hfs_sync,
1892 hfs_vget,
1893 hfs_fhtovp,
1894 hfs_vptofh,
1895 hfs_init,
1896 hfs_sysctl
1897 };