]> git.saurik.com Git - apple/xnu.git/blob - bsd/hfs/hfs_vfsops.c
xnu-344.32.tar.gz
[apple/xnu.git] / bsd / hfs / hfs_vfsops.c
1 /*
2 * Copyright (c) 1999-2002 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-2002 Apple Computer, Inc. All rights reserved.
63 *
64 * hfs_vfsops.c -- VFS layer for loadable HFS file system.
65 *
66 */
67 #include <sys/param.h>
68 #include <sys/systm.h>
69
70 #include <sys/ubc.h>
71 #include <sys/namei.h>
72 #include <sys/vnode.h>
73 #include <sys/mount.h>
74 #include <sys/malloc.h>
75 #include <sys/stat.h>
76 #include <sys/lock.h>
77 #include <sys/quota.h>
78 #include <sys/disk.h>
79
80 // XXXdbg
81 #include <vfs/vfs_journal.h>
82
83 #include <miscfs/specfs/specdev.h>
84 #include <hfs/hfs_mount.h>
85
86 #include "hfs.h"
87 #include "hfs_catalog.h"
88 #include "hfs_cnode.h"
89 #include "hfs_dbg.h"
90 #include "hfs_endian.h"
91 #include "hfs_quota.h"
92
93 #include "hfscommon/headers/FileMgrInternal.h"
94 #include "hfscommon/headers/BTreesInternal.h"
95
96
97 #if HFS_DIAGNOSTIC
98 int hfs_dbg_all = 0;
99 int hfs_dbg_err = 0;
100 #endif
101
102
103 extern struct vnodeopv_desc hfs_vnodeop_opv_desc;
104
105 extern void hfs_converterinit(void);
106
107 extern void inittodr( time_t base);
108
109
110 static int hfs_changefs __P((struct mount *mp, struct hfs_mount_args *args,
111 struct proc *p));
112 static int hfs_reload __P((struct mount *mp, struct ucred *cred, struct proc *p));
113
114 static int hfs_mountfs __P((struct vnode *devvp, struct mount *mp, struct proc *p,
115 struct hfs_mount_args *args));
116 static int hfs_statfs __P((struct mount *mp, register struct statfs *sbp,
117 struct proc *p));
118
119
120 /*
121 * Called by vfs_mountroot when mounting HFS Plus as root.
122 */
123 int
124 hfs_mountroot()
125 {
126 extern struct vnode *rootvp;
127 struct mount *mp;
128 struct proc *p = current_proc(); /* XXX */
129 struct hfsmount *hfsmp;
130 ExtendedVCB *vcb;
131 int error;
132
133 /*
134 * Get vnode for rootdev.
135 */
136 if ((error = bdevvp(rootdev, &rootvp))) {
137 printf("hfs_mountroot: can't setup bdevvp");
138 return (error);
139 }
140 if ((error = vfs_rootmountalloc("hfs", "root_device", &mp))) {
141 vrele(rootvp); /* release the reference from bdevvp() */
142 return (error);
143 }
144 if ((error = hfs_mountfs(rootvp, mp, p, NULL))) {
145 mp->mnt_vfc->vfc_refcount--;
146 vfs_unbusy(mp, p);
147 vrele(rootvp); /* release the reference from bdevvp() */
148 _FREE_ZONE(mp, sizeof (struct mount), M_MOUNT);
149 return (error);
150 }
151 simple_lock(&mountlist_slock);
152 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
153 simple_unlock(&mountlist_slock);
154
155 /* Init hfsmp */
156 hfsmp = VFSTOHFS(mp);
157
158 hfsmp->hfs_uid = UNKNOWNUID;
159 hfsmp->hfs_gid = UNKNOWNGID;
160 hfsmp->hfs_dir_mask = (S_IRWXU | S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH); /* 0755 */
161 hfsmp->hfs_file_mask = (S_IRWXU | S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH); /* 0755 */
162
163 /* Establish the free block reserve. */
164 vcb = HFSTOVCB(hfsmp);
165 vcb->reserveBlocks = ((u_int64_t)vcb->totalBlocks * HFS_MINFREE) / 100;
166 vcb->reserveBlocks = MIN(vcb->reserveBlocks, HFS_MAXRESERVE / vcb->blockSize);
167
168 (void)hfs_statfs(mp, &mp->mnt_stat, p);
169
170 vfs_unbusy(mp, p);
171 inittodr(HFSTOVCB(hfsmp)->vcbLsMod);
172 return (0);
173 }
174
175
176 /*
177 * VFS Operations.
178 *
179 * mount system call
180 */
181
182 static int
183 hfs_mount(mp, path, data, ndp, p)
184 register struct mount *mp;
185 char *path;
186 caddr_t data;
187 struct nameidata *ndp;
188 struct proc *p;
189 {
190 struct hfsmount *hfsmp = NULL;
191 struct vnode *devvp;
192 struct hfs_mount_args args;
193 size_t size;
194 int retval = E_NONE;
195 int flags;
196 mode_t accessmode;
197
198 if ((retval = copyin(data, (caddr_t)&args, sizeof(args))))
199 goto error_exit;
200
201 /*
202 * If updating, check whether changing from read-only to
203 * read/write; if there is no device name, that's all we do.
204 */
205 if (mp->mnt_flag & MNT_UPDATE) {
206
207 hfsmp = VFSTOHFS(mp);
208 if ((hfsmp->hfs_fs_ronly == 0) && (mp->mnt_flag & MNT_RDONLY)) {
209
210 /* use VFS_SYNC to push out System (btree) files */
211 retval = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p);
212 if (retval && ((mp->mnt_flag & MNT_FORCE) == 0))
213 goto error_exit;
214
215 flags = WRITECLOSE;
216 if (mp->mnt_flag & MNT_FORCE)
217 flags |= FORCECLOSE;
218
219 if ((retval = hfs_flushfiles(mp, flags, p)))
220 goto error_exit;
221 hfsmp->hfs_fs_ronly = 1;
222 retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT, 0);
223
224 /* also get the volume bitmap blocks */
225 if (!retval)
226 retval = VOP_FSYNC(hfsmp->hfs_devvp, NOCRED, MNT_WAIT, p);
227
228 if (retval) {
229 hfsmp->hfs_fs_ronly = 0;
230 goto error_exit;
231 }
232 }
233
234 if ((mp->mnt_flag & MNT_RELOAD) &&
235 (retval = hfs_reload(mp, ndp->ni_cnd.cn_cred, p)))
236 goto error_exit;
237
238 if (hfsmp->hfs_fs_ronly && (mp->mnt_kern_flag & MNTK_WANTRDWR)) {
239 /*
240 * If upgrade to read-write by non-root, then verify
241 * that user has necessary permissions on the device.
242 */
243 if (p->p_ucred->cr_uid != 0) {
244 devvp = hfsmp->hfs_devvp;
245 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
246 if ((retval = VOP_ACCESS(devvp, VREAD | VWRITE, p->p_ucred, p))) {
247 VOP_UNLOCK(devvp, 0, p);
248 goto error_exit;
249 }
250 VOP_UNLOCK(devvp, 0, p);
251 }
252 retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT, 0);
253
254 if (retval != E_NONE)
255 goto error_exit;
256
257 /* only change hfs_fs_ronly after a successfull write */
258 hfsmp->hfs_fs_ronly = 0;
259 }
260
261 if ((hfsmp->hfs_fs_ronly == 0) &&
262 (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)) {
263 /* setup private/hidden directory for unlinked files */
264 hfsmp->hfs_private_metadata_dir = FindMetaDataDirectory(HFSTOVCB(hfsmp));
265 if (hfsmp->jnl)
266 hfs_remove_orphans(hfsmp);
267 }
268
269 if (args.fspec == 0) {
270 /*
271 * Process export requests.
272 */
273 return vfs_export(mp, &hfsmp->hfs_export, &args.export);
274 }
275 }
276
277 /*
278 * Not an update, or updating the name: look up the name
279 * and verify that it refers to a sensible block device.
280 */
281 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
282 retval = namei(ndp);
283 if (retval != E_NONE) {
284 DBG_ERR(("hfs_mount: CAN'T GET DEVICE: %s, %x\n", args.fspec, ndp->ni_vp->v_rdev));
285 goto error_exit;
286 }
287
288 devvp = ndp->ni_vp;
289
290 if (devvp->v_type != VBLK) {
291 vrele(devvp);
292 retval = ENOTBLK;
293 goto error_exit;
294 }
295 if (major(devvp->v_rdev) >= nblkdev) {
296 vrele(devvp);
297 retval = ENXIO;
298 goto error_exit;
299 }
300
301 /*
302 * If mount by non-root, then verify that user has necessary
303 * permissions on the device.
304 */
305 if (p->p_ucred->cr_uid != 0) {
306 accessmode = VREAD;
307 if ((mp->mnt_flag & MNT_RDONLY) == 0)
308 accessmode |= VWRITE;
309 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
310 if ((retval = VOP_ACCESS(devvp, accessmode, p->p_ucred, p))) {
311 vput(devvp);
312 goto error_exit;
313 }
314 VOP_UNLOCK(devvp, 0, p);
315 }
316
317 if ((mp->mnt_flag & MNT_UPDATE) == 0) {
318 retval = hfs_mountfs(devvp, mp, p, &args);
319 if (retval != E_NONE)
320 vrele(devvp);
321 } else {
322 if (devvp != hfsmp->hfs_devvp)
323 retval = EINVAL; /* needs translation */
324 else
325 retval = hfs_changefs(mp, &args, p);
326 vrele(devvp);
327 }
328
329 if (retval != E_NONE) {
330 goto error_exit;
331 }
332
333 /* Set the mount flag to indicate that we support volfs */
334 mp->mnt_flag |= MNT_DOVOLFS;
335 if (VFSTOVCB(mp)->vcbSigWord == kHFSSigWord) {
336 /* HFS volumes only want roman-encoded names: */
337 mp->mnt_flag |= MNT_FIXEDSCRIPTENCODING;
338 }
339 (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN-1, &size);
340
341 bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
342 (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size);
343 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
344 (void)hfs_statfs(mp, &mp->mnt_stat, p);
345 return (E_NONE);
346
347 error_exit:
348
349 return (retval);
350 }
351
352
353 /* Change fs mount parameters */
354 static int
355 hfs_changefs(mp, args, p)
356 struct mount *mp;
357 struct hfs_mount_args *args;
358 struct proc *p;
359 {
360 int retval = 0;
361 int namefix, permfix, permswitch;
362 struct hfsmount *hfsmp;
363 struct cnode *cp;
364 ExtendedVCB *vcb;
365 register struct vnode *vp, *nvp;
366 hfs_to_unicode_func_t get_unicode_func;
367 unicode_to_hfs_func_t get_hfsname_func;
368 struct cat_desc cndesc;
369 struct cat_attr cnattr;
370 u_long old_encoding;
371
372 hfsmp = VFSTOHFS(mp);
373 vcb = HFSTOVCB(hfsmp);
374 permswitch = (((hfsmp->hfs_unknownpermissions != 0) && ((mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) == 0)) ||
375 ((hfsmp->hfs_unknownpermissions == 0) && ((mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) != 0)));
376 /* The root filesystem must operate with actual permissions: */
377 if (permswitch && (mp->mnt_flag & MNT_ROOTFS) && (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS)) {
378 mp->mnt_flag &= ~MNT_UNKNOWNPERMISSIONS; /* Just say "No". */
379 return EINVAL;
380 };
381 hfsmp->hfs_unknownpermissions = ((mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) != 0);
382 namefix = permfix = 0;
383
384 /* Change the timezone (Note: this affects all hfs volumes and hfs+ volume create dates) */
385 if (args->hfs_timezone.tz_minuteswest != VNOVAL) {
386 gTimeZone = args->hfs_timezone;
387 }
388
389 /* Change the default uid, gid and/or mask */
390 if ((args->hfs_uid != (uid_t)VNOVAL) && (hfsmp->hfs_uid != args->hfs_uid)) {
391 hfsmp->hfs_uid = args->hfs_uid;
392 if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
393 ++permfix;
394 }
395 if ((args->hfs_gid != (gid_t)VNOVAL) && (hfsmp->hfs_gid != args->hfs_gid)) {
396 hfsmp->hfs_gid = args->hfs_gid;
397 if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
398 ++permfix;
399 }
400 if (args->hfs_mask != (mode_t)VNOVAL) {
401 if (hfsmp->hfs_dir_mask != (args->hfs_mask & ALLPERMS)) {
402 hfsmp->hfs_dir_mask = args->hfs_mask & ALLPERMS;
403 hfsmp->hfs_file_mask = args->hfs_mask & ALLPERMS;
404 if ((args->flags != VNOVAL) && (args->flags & HFSFSMNT_NOXONFILES))
405 hfsmp->hfs_file_mask = (args->hfs_mask & DEFFILEMODE);
406 if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
407 ++permfix;
408 }
409 }
410
411 /* Change the hfs encoding value (hfs only) */
412 if ((HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord) &&
413 (hfsmp->hfs_encoding != (u_long)VNOVAL) &&
414 (hfsmp->hfs_encoding != args->hfs_encoding)) {
415
416 retval = hfs_getconverter(args->hfs_encoding, &get_unicode_func, &get_hfsname_func);
417 if (retval)
418 goto exit;
419
420 /*
421 * Connect the new hfs_get_unicode converter but leave
422 * the old hfs_get_hfsname converter in place so that
423 * we can lookup existing vnodes to get their correctly
424 * encoded names.
425 *
426 * When we're all finished, we can then connect the new
427 * hfs_get_hfsname converter and release our interest
428 * in the old converters.
429 */
430 hfsmp->hfs_get_unicode = get_unicode_func;
431 old_encoding = hfsmp->hfs_encoding;
432 hfsmp->hfs_encoding = args->hfs_encoding;
433 ++namefix;
434 }
435
436 if (!(namefix || permfix || permswitch))
437 goto exit;
438
439 /*
440 * For each active vnode fix things that changed
441 *
442 * Note that we can visit a vnode more than once
443 * and we can race with fsync.
444 */
445 simple_lock(&mntvnode_slock);
446 loop:
447 for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
448 /*
449 * If the vnode that we are about to fix is no longer
450 * associated with this mount point, start over.
451 */
452 if (vp->v_mount != mp)
453 goto loop;
454
455 simple_lock(&vp->v_interlock);
456 nvp = vp->v_mntvnodes.le_next;
457 if (vp->v_flag & VSYSTEM) {
458 simple_unlock(&vp->v_interlock);
459 continue;
460 }
461 simple_unlock(&mntvnode_slock);
462 retval = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p);
463 if (retval) {
464 simple_lock(&mntvnode_slock);
465 if (retval == ENOENT)
466 goto loop;
467 continue;
468 }
469
470 cp = VTOC(vp);
471
472 retval = cat_lookup(hfsmp, &cp->c_desc, 0, &cndesc, &cnattr, NULL);
473 /* If we couldn't find this guy skip to the next one */
474 if (retval) {
475 if (namefix)
476 cache_purge(vp);
477 vput(vp);
478 simple_lock(&mntvnode_slock);
479 continue;
480 }
481
482 if (permswitch || permfix) {
483 cp->c_uid = cnattr.ca_uid;
484 cp->c_gid = cnattr.ca_gid;
485 cp->c_mode = cnattr.ca_mode;
486 }
487
488 /*
489 * If we're switching name converters then...
490 * Remove the existing entry from the namei cache.
491 * Update name to one based on new encoder.
492 */
493 if (namefix) {
494 cache_purge(vp);
495 replace_desc(cp, &cndesc);
496
497 if (cndesc.cd_cnid == kHFSRootFolderID) {
498 strncpy(vcb->vcbVN, cp->c_desc.cd_nameptr, NAME_MAX);
499 cp->c_desc.cd_encoding = hfsmp->hfs_encoding;
500 }
501 } else {
502 cat_releasedesc(&cndesc);
503 }
504 vput(vp);
505 simple_lock(&mntvnode_slock);
506
507 } /* end for (vp...) */
508 simple_unlock(&mntvnode_slock);
509 /*
510 * If we're switching name converters we can now
511 * connect the new hfs_get_hfsname converter and
512 * release our interest in the old converters.
513 */
514 if (namefix) {
515 hfsmp->hfs_get_hfsname = get_hfsname_func;
516 vcb->volumeNameEncodingHint = args->hfs_encoding;
517 (void) hfs_relconverter(old_encoding);
518 }
519 exit:
520 return (retval);
521 }
522
523
524 /*
525 * Reload all incore data for a filesystem (used after running fsck on
526 * the root filesystem and finding things to fix). The filesystem must
527 * be mounted read-only.
528 *
529 * Things to do to update the mount:
530 * invalidate all cached meta-data.
531 * invalidate all inactive vnodes.
532 * invalidate all cached file data.
533 * re-read volume header from disk.
534 * re-load meta-file info (extents, file size).
535 * re-load B-tree header data.
536 * re-read cnode data for all active vnodes.
537 */
538 static int
539 hfs_reload(mountp, cred, p)
540 register struct mount *mountp;
541 struct ucred *cred;
542 struct proc *p;
543 {
544 register struct vnode *vp, *nvp, *devvp;
545 struct cnode *cp;
546 struct buf *bp;
547 int sectorsize;
548 int error, i;
549 struct hfsmount *hfsmp;
550 struct HFSPlusVolumeHeader *vhp;
551 ExtendedVCB *vcb;
552 struct filefork *forkp;
553 struct cat_desc cndesc;
554
555 if ((mountp->mnt_flag & MNT_RDONLY) == 0)
556 return (EINVAL);
557
558 hfsmp = VFSTOHFS(mountp);
559 vcb = HFSTOVCB(hfsmp);
560
561 if (vcb->vcbSigWord == kHFSSigWord)
562 return (EINVAL); /* rooting from HFS is not supported! */
563
564 /*
565 * Invalidate all cached meta-data.
566 */
567 devvp = hfsmp->hfs_devvp;
568 if (vinvalbuf(devvp, 0, cred, p, 0, 0))
569 panic("hfs_reload: dirty1");
570 InvalidateCatalogCache(vcb);
571
572 loop:
573 simple_lock(&mntvnode_slock);
574 for (vp = mountp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
575 if (vp->v_mount != mountp) {
576 simple_unlock(&mntvnode_slock);
577 goto loop;
578 }
579 nvp = vp->v_mntvnodes.le_next;
580
581 /*
582 * Invalidate all inactive vnodes.
583 */
584 if (vrecycle(vp, &mntvnode_slock, p))
585 goto loop;
586
587 /*
588 * Invalidate all cached file data.
589 */
590 simple_lock(&vp->v_interlock);
591 simple_unlock(&mntvnode_slock);
592 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) {
593 goto loop;
594 }
595 if (vinvalbuf(vp, 0, cred, p, 0, 0))
596 panic("hfs_reload: dirty2");
597
598 /*
599 * Re-read cnode data for all active vnodes (non-metadata files).
600 */
601 cp = VTOC(vp);
602 if ((vp->v_flag & VSYSTEM) == 0 && !VNODE_IS_RSRC(vp)) {
603 struct cat_fork *datafork;
604 struct cat_desc desc;
605
606 datafork = cp->c_datafork ? &cp->c_datafork->ff_data : NULL;
607
608 /* lookup by fileID since name could have changed */
609 if ((error = cat_idlookup(hfsmp, cp->c_fileid, &desc, &cp->c_attr, datafork))) {
610 vput(vp);
611 return (error);
612 }
613
614
615 /* update cnode's catalog descriptor */
616 (void) replace_desc(cp, &desc);
617 }
618 vput(vp);
619 simple_lock(&mntvnode_slock);
620 }
621 simple_unlock(&mntvnode_slock);
622
623 /*
624 * Re-read VolumeHeader from disk.
625 */
626 sectorsize = hfsmp->hfs_phys_block_size;
627
628 error = meta_bread(hfsmp->hfs_devvp,
629 (vcb->hfsPlusIOPosOffset / sectorsize) + HFS_PRI_SECTOR(sectorsize),
630 sectorsize, NOCRED, &bp);
631 if (error) {
632 if (bp != NULL)
633 brelse(bp);
634 return (error);
635 }
636
637 vhp = (HFSPlusVolumeHeader *) (bp->b_data + HFS_PRI_OFFSET(sectorsize));
638
639 /* Do a quick sanity check */
640 if (SWAP_BE16(vhp->signature) != kHFSPlusSigWord ||
641 SWAP_BE16(vhp->version) != kHFSPlusVersion ||
642 SWAP_BE32(vhp->blockSize) != vcb->blockSize) {
643 brelse(bp);
644 return (EIO);
645 }
646
647 vcb->vcbLsMod = to_bsd_time(SWAP_BE32(vhp->modifyDate));
648 vcb->vcbAtrb = (UInt16) SWAP_BE32 (vhp->attributes); /* VCB only uses lower 16 bits */
649 vcb->vcbJinfoBlock = SWAP_BE32(vhp->journalInfoBlock);
650 vcb->vcbClpSiz = SWAP_BE32 (vhp->rsrcClumpSize);
651 vcb->vcbNxtCNID = SWAP_BE32 (vhp->nextCatalogID);
652 vcb->vcbVolBkUp = to_bsd_time(SWAP_BE32(vhp->backupDate));
653 vcb->vcbWrCnt = SWAP_BE32 (vhp->writeCount);
654 vcb->vcbFilCnt = SWAP_BE32 (vhp->fileCount);
655 vcb->vcbDirCnt = SWAP_BE32 (vhp->folderCount);
656 vcb->nextAllocation = SWAP_BE32 (vhp->nextAllocation);
657 vcb->totalBlocks = SWAP_BE32 (vhp->totalBlocks);
658 vcb->freeBlocks = SWAP_BE32 (vhp->freeBlocks);
659 vcb->encodingsBitmap = SWAP_BE64 (vhp->encodingsBitmap);
660 bcopy(vhp->finderInfo, vcb->vcbFndrInfo, sizeof(vhp->finderInfo));
661 vcb->localCreateDate = SWAP_BE32 (vhp->createDate); /* hfs+ create date is in local time */
662
663 /*
664 * Re-load meta-file vnode data (extent info, file size, etc).
665 */
666 forkp = VTOF((struct vnode *)vcb->extentsRefNum);
667 for (i = 0; i < kHFSPlusExtentDensity; i++) {
668 forkp->ff_extents[i].startBlock =
669 SWAP_BE32 (vhp->extentsFile.extents[i].startBlock);
670 forkp->ff_extents[i].blockCount =
671 SWAP_BE32 (vhp->extentsFile.extents[i].blockCount);
672 }
673 forkp->ff_size = SWAP_BE64 (vhp->extentsFile.logicalSize);
674 forkp->ff_blocks = SWAP_BE32 (vhp->extentsFile.totalBlocks);
675 forkp->ff_clumpsize = SWAP_BE32 (vhp->extentsFile.clumpSize);
676
677
678 forkp = VTOF((struct vnode *)vcb->catalogRefNum);
679 for (i = 0; i < kHFSPlusExtentDensity; i++) {
680 forkp->ff_extents[i].startBlock =
681 SWAP_BE32 (vhp->catalogFile.extents[i].startBlock);
682 forkp->ff_extents[i].blockCount =
683 SWAP_BE32 (vhp->catalogFile.extents[i].blockCount);
684 }
685 forkp->ff_size = SWAP_BE64 (vhp->catalogFile.logicalSize);
686 forkp->ff_blocks = SWAP_BE32 (vhp->catalogFile.totalBlocks);
687 forkp->ff_clumpsize = SWAP_BE32 (vhp->catalogFile.clumpSize);
688
689
690 forkp = VTOF((struct vnode *)vcb->allocationsRefNum);
691 for (i = 0; i < kHFSPlusExtentDensity; i++) {
692 forkp->ff_extents[i].startBlock =
693 SWAP_BE32 (vhp->allocationFile.extents[i].startBlock);
694 forkp->ff_extents[i].blockCount =
695 SWAP_BE32 (vhp->allocationFile.extents[i].blockCount);
696 }
697 forkp->ff_size = SWAP_BE64 (vhp->allocationFile.logicalSize);
698 forkp->ff_blocks = SWAP_BE32 (vhp->allocationFile.totalBlocks);
699 forkp->ff_clumpsize = SWAP_BE32 (vhp->allocationFile.clumpSize);
700
701 brelse(bp);
702 vhp = NULL;
703
704 /*
705 * Re-load B-tree header data
706 */
707 forkp = VTOF((struct vnode *)vcb->extentsRefNum);
708 if (error = MacToVFSError( BTReloadData((FCB*)forkp) ))
709 return (error);
710
711 forkp = VTOF((struct vnode *)vcb->catalogRefNum);
712 if (error = MacToVFSError( BTReloadData((FCB*)forkp) ))
713 return (error);
714
715 /* Reload the volume name */
716 if ((error = cat_idlookup(hfsmp, kHFSRootFolderID, &cndesc, NULL, NULL)))
717 return (error);
718 vcb->volumeNameEncodingHint = cndesc.cd_encoding;
719 bcopy(cndesc.cd_nameptr, vcb->vcbVN, min(255, cndesc.cd_namelen));
720 cat_releasedesc(&cndesc);
721
722 /* Re-establish private/hidden directory for unlinked files */
723 hfsmp->hfs_private_metadata_dir = FindMetaDataDirectory(vcb);
724
725 return (0);
726 }
727
728
729 static int
730 get_raw_device(char *fspec, int is_user, int ronly, struct vnode **rvp, struct ucred *cred, struct proc *p)
731 {
732 char *rawbuf;
733 char *dp;
734 size_t namelen;
735 struct nameidata nd;
736 int retval;
737
738 *rvp = NULL;
739
740 MALLOC(rawbuf, char *, MAXPATHLEN, M_HFSMNT, M_WAITOK);
741 if (rawbuf == NULL) {
742 retval = ENOMEM;
743 goto error_exit;
744 }
745
746 if (is_user) {
747 retval = copyinstr(fspec, rawbuf, MAXPATHLEN - 1, &namelen);
748 if (retval != E_NONE) {
749 FREE(rawbuf, M_HFSMNT);
750 goto error_exit;
751 }
752 } else {
753 strcpy(rawbuf, fspec);
754 namelen = strlen(rawbuf);
755 }
756
757 /* make sure it's null terminated */
758 rawbuf[MAXPATHLEN-1] = '\0';
759
760 dp = &rawbuf[namelen-1];
761 while(dp >= rawbuf && *dp != '/') {
762 dp--;
763 }
764
765 if (dp != NULL) {
766 dp++;
767 } else {
768 dp = rawbuf;
769 }
770
771 /* make room for and insert the 'r' for the raw device */
772 memmove(dp+1, dp, strlen(dp)+1);
773 *dp = 'r';
774
775 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, rawbuf, p);
776 retval = namei(&nd);
777 if (retval != E_NONE) {
778 DBG_ERR(("hfs_mountfs: can't open raw device for journal: %s, %x\n", rawbuf, nd.ni_vp->v_rdev));
779 FREE(rawbuf, M_HFSMNT);
780 goto error_exit;
781 }
782
783 *rvp = nd.ni_vp;
784 if ((retval = VOP_OPEN(*rvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p))) {
785 *rvp = NULL;
786 goto error_exit;
787 }
788
789 // don't need this any more
790 FREE(rawbuf, M_HFSMNT);
791
792 return 0;
793
794 error_exit:
795 if (*rvp) {
796 (void)VOP_CLOSE(*rvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
797 }
798
799 if (rawbuf) {
800 FREE(rawbuf, M_HFSMNT);
801 }
802 return retval;
803 }
804
805
806
807 /*
808 * Common code for mount and mountroot
809 */
810 static int
811 hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p,
812 struct hfs_mount_args *args)
813 {
814 int retval = E_NONE;
815 struct hfsmount *hfsmp;
816 struct buf *bp;
817 dev_t dev;
818 HFSMasterDirectoryBlock *mdbp;
819 int ronly;
820 int i;
821 int mntwrapper;
822 struct ucred *cred;
823 u_int64_t disksize;
824 u_int64_t blkcnt;
825 u_int32_t blksize;
826 u_int32_t minblksize;
827 u_int32_t iswritable;
828 daddr_t mdb_offset;
829
830 dev = devvp->v_rdev;
831 cred = p ? p->p_ucred : NOCRED;
832 mntwrapper = 0;
833 /*
834 * Disallow multiple mounts of the same device.
835 * Disallow mounting of a device that is currently in use
836 * (except for root, which might share swap device for miniroot).
837 * Flush out any old buffers remaining from a previous use.
838 */
839 if ((retval = vfs_mountedon(devvp)))
840 return (retval);
841 if ((vcount(devvp) > 1) && (devvp != rootvp))
842 return (EBUSY);
843 if ((retval = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0)))
844 return (retval);
845
846 ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
847 if ((retval = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p)))
848 return (retval);
849
850 bp = NULL;
851 hfsmp = NULL;
852 mdbp = NULL;
853 minblksize = kHFSBlockSize;
854
855 /* Get the real physical block size. */
856 if (VOP_IOCTL(devvp, DKIOCGETBLOCKSIZE, (caddr_t)&blksize, 0, cred, p)) {
857 retval = ENXIO;
858 goto error_exit;
859 }
860 /* Switch to 512 byte sectors (temporarily) */
861 if (blksize > 512) {
862 u_int32_t size512 = 512;
863
864 if (VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE, (caddr_t)&size512, FWRITE, cred, p)) {
865 retval = ENXIO;
866 goto error_exit;
867 }
868 }
869 /* Get the number of 512 byte physical blocks. */
870 if (VOP_IOCTL(devvp, DKIOCGETBLOCKCOUNT, (caddr_t)&blkcnt, 0, cred, p)) {
871 retval = ENXIO;
872 goto error_exit;
873 }
874 /* Compute an accurate disk size (i.e. within 512 bytes) */
875 disksize = blkcnt * (u_int64_t)512;
876
877 /*
878 * There are only 31 bits worth of block count in
879 * the buffer cache. So for large volumes a 4K
880 * physical block size is needed.
881 */
882 if (blkcnt > (u_int64_t)0x000000007fffffff) {
883 minblksize = blksize = 4096;
884 }
885 /* Now switch to our prefered physical block size. */
886 if (blksize > 512) {
887 if (VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE, (caddr_t)&blksize, FWRITE, cred, p)) {
888 retval = ENXIO;
889 goto error_exit;
890 }
891 /* Get the count of physical blocks. */
892 if (VOP_IOCTL(devvp, DKIOCGETBLOCKCOUNT, (caddr_t)&blkcnt, 0, cred, p)) {
893 retval = ENXIO;
894 goto error_exit;
895 }
896 }
897
898 /*
899 * At this point:
900 * minblksize is the minimum physical block size
901 * blksize has our prefered physical block size
902 * blkcnt has the total number of physical blocks
903 */
904 devvp->v_specsize = blksize;
905
906 /* cache the IO attributes */
907 if ((retval = vfs_init_io_attributes(devvp, mp))) {
908 printf("hfs_mountfs: vfs_init_io_attributes returned %d\n",
909 retval);
910 return (retval);
911 }
912
913 mdb_offset = HFS_PRI_SECTOR(blksize);
914 if ((retval = meta_bread(devvp, HFS_PRI_SECTOR(blksize), blksize, cred, &bp))) {
915 goto error_exit;
916 }
917 MALLOC(mdbp, HFSMasterDirectoryBlock *, kMDBSize, M_TEMP, M_WAITOK);
918 bcopy(bp->b_data + HFS_PRI_OFFSET(blksize), mdbp, kMDBSize);
919 brelse(bp);
920 bp = NULL;
921
922 MALLOC(hfsmp, struct hfsmount *, sizeof(struct hfsmount), M_HFSMNT, M_WAITOK);
923 bzero(hfsmp, sizeof(struct hfsmount));
924
925 simple_lock_init(&hfsmp->hfs_renamelock);
926
927 /*
928 * Init the volume information structure
929 */
930 mp->mnt_data = (qaddr_t)hfsmp;
931 hfsmp->hfs_mp = mp; /* Make VFSTOHFS work */
932 hfsmp->hfs_vcb.vcb_hfsmp = hfsmp; /* Make VCBTOHFS work */
933 hfsmp->hfs_raw_dev = devvp->v_rdev;
934 hfsmp->hfs_devvp = devvp;
935 hfsmp->hfs_phys_block_size = blksize;
936 hfsmp->hfs_phys_block_count = blkcnt;
937 hfsmp->hfs_media_writeable = 1;
938 hfsmp->hfs_fs_ronly = ronly;
939 hfsmp->hfs_unknownpermissions = ((mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) != 0);
940 for (i = 0; i < MAXQUOTAS; i++)
941 hfsmp->hfs_qfiles[i].qf_vp = NULLVP;
942
943 if (args) {
944 hfsmp->hfs_uid = (args->hfs_uid == (uid_t)VNOVAL) ? UNKNOWNUID : args->hfs_uid;
945 if (hfsmp->hfs_uid == 0xfffffffd) hfsmp->hfs_uid = UNKNOWNUID;
946 hfsmp->hfs_gid = (args->hfs_gid == (gid_t)VNOVAL) ? UNKNOWNGID : args->hfs_gid;
947 if (hfsmp->hfs_gid == 0xfffffffd) hfsmp->hfs_gid = UNKNOWNGID;
948 if (args->hfs_mask != (mode_t)VNOVAL) {
949 hfsmp->hfs_dir_mask = args->hfs_mask & ALLPERMS;
950 if (args->flags & HFSFSMNT_NOXONFILES) {
951 hfsmp->hfs_file_mask = (args->hfs_mask & DEFFILEMODE);
952 } else {
953 hfsmp->hfs_file_mask = args->hfs_mask & ALLPERMS;
954 }
955 } else {
956 hfsmp->hfs_dir_mask = UNKNOWNPERMISSIONS & ALLPERMS; /* 0777: rwx---rwx */
957 hfsmp->hfs_file_mask = UNKNOWNPERMISSIONS & DEFFILEMODE; /* 0666: no --x by default? */
958 }
959 if ((args->flags != (int)VNOVAL) && (args->flags & HFSFSMNT_WRAPPER))
960 mntwrapper = 1;
961 } else {
962 /* Even w/o explicit mount arguments, MNT_UNKNOWNPERMISSIONS requires setting up uid, gid, and mask: */
963 if (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) {
964 hfsmp->hfs_uid = UNKNOWNUID;
965 hfsmp->hfs_gid = UNKNOWNGID;
966 hfsmp->hfs_dir_mask = UNKNOWNPERMISSIONS & ALLPERMS; /* 0777: rwx---rwx */
967 hfsmp->hfs_file_mask = UNKNOWNPERMISSIONS & DEFFILEMODE; /* 0666: no --x by default? */
968 }
969 }
970
971 /* Find out if disk media is writable. */
972 if (VOP_IOCTL(devvp, DKIOCISWRITABLE, (caddr_t)&iswritable, 0, cred, p) == 0) {
973 if (iswritable)
974 hfsmp->hfs_media_writeable = 1;
975 else
976 hfsmp->hfs_media_writeable = 0;
977 }
978
979 /* Mount a standard HFS disk */
980 if ((SWAP_BE16(mdbp->drSigWord) == kHFSSigWord) &&
981 (mntwrapper || (SWAP_BE16(mdbp->drEmbedSigWord) != kHFSPlusSigWord))) {
982 if (devvp == rootvp) {
983 retval = EINVAL; /* Cannot root from HFS standard disks */
984 goto error_exit;
985 }
986 /* HFS disks can only use 512 byte physical blocks */
987 if (blksize > kHFSBlockSize) {
988 blksize = kHFSBlockSize;
989 if (VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE, (caddr_t)&blksize, FWRITE, cred, p)) {
990 retval = ENXIO;
991 goto error_exit;
992 }
993 if (VOP_IOCTL(devvp, DKIOCGETBLOCKCOUNT, (caddr_t)&blkcnt, 0, cred, p)) {
994 retval = ENXIO;
995 goto error_exit;
996 }
997 devvp->v_specsize = blksize;
998 hfsmp->hfs_phys_block_size = blksize;
999 hfsmp->hfs_phys_block_count = blkcnt;
1000 }
1001 if (args) {
1002 hfsmp->hfs_encoding = args->hfs_encoding;
1003 HFSTOVCB(hfsmp)->volumeNameEncodingHint = args->hfs_encoding;
1004
1005 /* establish the timezone */
1006 gTimeZone = args->hfs_timezone;
1007 }
1008
1009 retval = hfs_getconverter(hfsmp->hfs_encoding, &hfsmp->hfs_get_unicode,
1010 &hfsmp->hfs_get_hfsname);
1011 if (retval)
1012 goto error_exit;
1013
1014 retval = hfs_MountHFSVolume(hfsmp, mdbp, p);
1015 if (retval)
1016 (void) hfs_relconverter(hfsmp->hfs_encoding);
1017
1018 } else /* Mount an HFS Plus disk */ {
1019 HFSPlusVolumeHeader *vhp;
1020 off_t embeddedOffset;
1021 int jnl_disable = 0;
1022
1023 /* Get the embedded Volume Header */
1024 if (SWAP_BE16(mdbp->drEmbedSigWord) == kHFSPlusSigWord) {
1025 embeddedOffset = SWAP_BE16(mdbp->drAlBlSt) * kHFSBlockSize;
1026 embeddedOffset += (u_int64_t)SWAP_BE16(mdbp->drEmbedExtent.startBlock) *
1027 (u_int64_t)SWAP_BE32(mdbp->drAlBlkSiz);
1028
1029 /*
1030 * If the embedded volume doesn't start on a block
1031 * boundary, then switch the device to a 512-byte
1032 * block size so everything will line up on a block
1033 * boundary.
1034 */
1035 if ((embeddedOffset % blksize) != 0) {
1036 printf("HFS Mount: embedded volume offset not"
1037 " a multiple of physical block size (%d);"
1038 " switching to 512\n", blksize);
1039 blksize = 512;
1040 if (VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE,
1041 (caddr_t)&blksize, FWRITE, cred, p)) {
1042 retval = ENXIO;
1043 goto error_exit;
1044 }
1045 if (VOP_IOCTL(devvp, DKIOCGETBLOCKCOUNT,
1046 (caddr_t)&blkcnt, 0, cred, p)) {
1047 retval = ENXIO;
1048 goto error_exit;
1049 }
1050 /* XXX do we need to call vfs_init_io_attributes again? */
1051 devvp->v_specsize = blksize;
1052 /* Note: relative block count adjustment */
1053 hfsmp->hfs_phys_block_count *=
1054 hfsmp->hfs_phys_block_size / blksize;
1055 hfsmp->hfs_phys_block_size = blksize;
1056 }
1057
1058 disksize = (u_int64_t)SWAP_BE16(mdbp->drEmbedExtent.blockCount) *
1059 (u_int64_t)SWAP_BE32(mdbp->drAlBlkSiz);
1060
1061 hfsmp->hfs_phys_block_count = disksize / blksize;
1062
1063 mdb_offset = (embeddedOffset / blksize) + HFS_PRI_SECTOR(blksize);
1064 retval = meta_bread(devvp, mdb_offset, blksize, cred, &bp);
1065 if (retval)
1066 goto error_exit;
1067 bcopy(bp->b_data + HFS_PRI_OFFSET(blksize), mdbp, 512);
1068 brelse(bp);
1069 bp = NULL;
1070 vhp = (HFSPlusVolumeHeader*) mdbp;
1071
1072 } else /* pure HFS+ */ {
1073 embeddedOffset = 0;
1074 vhp = (HFSPlusVolumeHeader*) mdbp;
1075 }
1076
1077 // XXXdbg
1078 //
1079 hfsmp->jnl = NULL;
1080 hfsmp->jvp = NULL;
1081 if (args != NULL && (args->flags & HFSFSMNT_EXTENDED_ARGS) && args->journal_disable) {
1082 jnl_disable = 1;
1083 }
1084
1085 //
1086 // We only initialize the journal here if the last person
1087 // to mount this volume was journaling aware. Otherwise
1088 // we delay journal initialization until later at the end
1089 // of hfs_MountHFSPlusVolume() because the last person who
1090 // mounted it could have messed things up behind our back
1091 // (so we need to go find the .journal file, make sure it's
1092 // the right size, re-sync up if it was moved, etc).
1093 //
1094 if ( (SWAP_BE32(vhp->lastMountedVersion) == kHFSJMountVersion)
1095 && (SWAP_BE32(vhp->attributes) & kHFSVolumeJournaledMask)
1096 && !jnl_disable) {
1097
1098 // if we're able to init the journal, mark the mount
1099 // point as journaled.
1100 //
1101 if (hfs_early_journal_init(hfsmp, vhp, args, embeddedOffset, mdb_offset, mdbp, cred) == 0) {
1102 mp->mnt_flag |= MNT_JOURNALED;
1103 } else {
1104 retval = EINVAL;
1105 goto error_exit;
1106 }
1107 }
1108 // XXXdbg
1109
1110 (void) hfs_getconverter(0, &hfsmp->hfs_get_unicode, &hfsmp->hfs_get_hfsname);
1111
1112 retval = hfs_MountHFSPlusVolume(hfsmp, vhp, embeddedOffset, disksize, p, args);
1113 /*
1114 * If the backend didn't like our physical blocksize
1115 * then retry with physical blocksize of 512.
1116 */
1117 if ((retval == ENXIO) && (blksize > 512) && (blksize != minblksize)) {
1118 printf("HFS Mount: could not use physical block size "
1119 "(%d) switching to 512\n", blksize);
1120 blksize = 512;
1121 if (VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE, (caddr_t)&blksize, FWRITE, cred, p)) {
1122 retval = ENXIO;
1123 goto error_exit;
1124 }
1125 if (VOP_IOCTL(devvp, DKIOCGETBLOCKCOUNT, (caddr_t)&blkcnt, 0, cred, p)) {
1126 retval = ENXIO;
1127 goto error_exit;
1128 }
1129 devvp->v_specsize = blksize;
1130 /* Note: relative block count adjustment (in case this is an embedded volume). */
1131 hfsmp->hfs_phys_block_count *= hfsmp->hfs_phys_block_size / blksize;
1132 hfsmp->hfs_phys_block_size = blksize;
1133
1134 /* Try again with a smaller block size... */
1135 retval = hfs_MountHFSPlusVolume(hfsmp, vhp, embeddedOffset, disksize, p, args);
1136 }
1137 if (retval)
1138 (void) hfs_relconverter(0);
1139 }
1140
1141 if ( retval ) {
1142 goto error_exit;
1143 }
1144
1145 mp->mnt_stat.f_fsid.val[0] = (long)dev;
1146 mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
1147 mp->mnt_maxsymlinklen = 0;
1148 devvp->v_specflags |= SI_MOUNTEDON;
1149
1150 if (ronly == 0) {
1151 (void) hfs_flushvolumeheader(hfsmp, MNT_WAIT, 0);
1152 }
1153 FREE(mdbp, M_TEMP);
1154 return (0);
1155
1156 error_exit:
1157 if (bp)
1158 brelse(bp);
1159 if (mdbp)
1160 FREE(mdbp, M_TEMP);
1161 (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
1162 if (hfsmp && hfsmp->jvp && hfsmp->jvp != hfsmp->hfs_devvp) {
1163 (void)VOP_CLOSE(hfsmp->jvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
1164 hfsmp->jvp = NULL;
1165 }
1166 if (hfsmp) {
1167 FREE(hfsmp, M_HFSMNT);
1168 mp->mnt_data = (qaddr_t)0;
1169 }
1170 return (retval);
1171 }
1172
1173
1174 /*
1175 * Make a filesystem operational.
1176 * Nothing to do at the moment.
1177 */
1178 /* ARGSUSED */
1179 static int
1180 hfs_start(mp, flags, p)
1181 struct mount *mp;
1182 int flags;
1183 struct proc *p;
1184 {
1185 return (0);
1186 }
1187
1188
1189 /*
1190 * unmount system call
1191 */
1192 static int
1193 hfs_unmount(mp, mntflags, p)
1194 struct mount *mp;
1195 int mntflags;
1196 struct proc *p;
1197 {
1198 struct hfsmount *hfsmp = VFSTOHFS(mp);
1199 int retval = E_NONE;
1200 int flags;
1201 int force;
1202 int started_tr = 0, grabbed_lock = 0;
1203
1204 flags = 0;
1205 force = 0;
1206 if (mntflags & MNT_FORCE) {
1207 flags |= FORCECLOSE;
1208 force = 1;
1209 }
1210
1211 if ((retval = hfs_flushfiles(mp, flags, p)) && !force)
1212 return (retval);
1213
1214 /*
1215 * Flush out the b-trees, volume bitmap and Volume Header
1216 */
1217 if (hfsmp->hfs_fs_ronly == 0) {
1218 hfs_global_shared_lock_acquire(hfsmp);
1219 grabbed_lock = 1;
1220 if (hfsmp->jnl) {
1221 journal_start_transaction(hfsmp->jnl);
1222 started_tr = 1;
1223 }
1224
1225 retval = VOP_FSYNC(HFSTOVCB(hfsmp)->catalogRefNum, NOCRED, MNT_WAIT, p);
1226 if (retval && !force)
1227 goto err_exit;
1228
1229 retval = VOP_FSYNC(HFSTOVCB(hfsmp)->extentsRefNum, NOCRED, MNT_WAIT, p);
1230 if (retval && !force)
1231 goto err_exit;
1232
1233 // if we have an allocation file, sync it too so we don't leave dirty
1234 // blocks around
1235 if (HFSTOVCB(hfsmp)->allocationsRefNum) {
1236 if (retval = VOP_FSYNC(HFSTOVCB(hfsmp)->allocationsRefNum, NOCRED, MNT_WAIT, p)) {
1237 if (!force)
1238 goto err_exit;
1239 }
1240 }
1241
1242 if (retval = VOP_FSYNC(hfsmp->hfs_devvp, NOCRED, MNT_WAIT, p)) {
1243 if (!force)
1244 goto err_exit;
1245 }
1246
1247 /* See if this volume is damaged, is so do not unmount cleanly */
1248 if (HFSTOVCB(hfsmp)->vcbFlags & kHFS_DamagedVolume) {
1249 HFSTOVCB(hfsmp)->vcbAtrb &= ~kHFSVolumeUnmountedMask;
1250 } else {
1251 HFSTOVCB(hfsmp)->vcbAtrb |= kHFSVolumeUnmountedMask;
1252 }
1253
1254 retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT, 1);
1255 if (retval) {
1256 HFSTOVCB(hfsmp)->vcbAtrb &= ~kHFSVolumeUnmountedMask;
1257 if (!force)
1258 goto err_exit; /* could not flush everything */
1259 }
1260
1261 if (hfsmp->jnl) {
1262 journal_end_transaction(hfsmp->jnl);
1263 started_tr = 0;
1264 }
1265 if (grabbed_lock) {
1266 hfs_global_shared_lock_release(hfsmp);
1267 grabbed_lock = 0;
1268 }
1269 }
1270
1271 if (hfsmp->jnl) {
1272 journal_flush(hfsmp->jnl);
1273 }
1274
1275 /*
1276 * Invalidate our caches and release metadata vnodes
1277 */
1278 (void) hfsUnmount(hfsmp, p);
1279
1280 if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord)
1281 (void) hfs_relconverter(hfsmp->hfs_encoding);
1282
1283 // XXXdbg
1284 if (hfsmp->jnl) {
1285 journal_close(hfsmp->jnl);
1286 }
1287
1288 if (hfsmp->jvp && hfsmp->jvp != hfsmp->hfs_devvp) {
1289 retval = VOP_CLOSE(hfsmp->jvp, hfsmp->hfs_fs_ronly ? FREAD : FREAD|FWRITE,
1290 NOCRED, p);
1291 vrele(hfsmp->jvp);
1292 hfsmp->jvp = NULL;
1293 }
1294 // XXXdbg
1295
1296 hfsmp->hfs_devvp->v_specflags &= ~SI_MOUNTEDON;
1297 retval = VOP_CLOSE(hfsmp->hfs_devvp,
1298 hfsmp->hfs_fs_ronly ? FREAD : FREAD|FWRITE,
1299 NOCRED, p);
1300 if (retval && !force)
1301 return(retval);
1302
1303 vrele(hfsmp->hfs_devvp);
1304 FREE(hfsmp, M_HFSMNT);
1305 mp->mnt_data = (qaddr_t)0;
1306 return (0);
1307
1308 err_exit:
1309 if (hfsmp->jnl && started_tr) {
1310 journal_end_transaction(hfsmp->jnl);
1311 }
1312 if (grabbed_lock) {
1313 hfs_global_shared_lock_release(hfsmp);
1314 }
1315 return retval;
1316 }
1317
1318
1319 /*
1320 * Return the root of a filesystem.
1321 *
1322 * OUT - vpp, should be locked and vget()'d (to increment usecount and lock)
1323 */
1324 static int
1325 hfs_root(mp, vpp)
1326 struct mount *mp;
1327 struct vnode **vpp;
1328 {
1329 struct vnode *nvp;
1330 int retval;
1331 UInt32 rootObjID = kRootDirID;
1332
1333 if ((retval = VFS_VGET(mp, &rootObjID, &nvp)))
1334 return (retval);
1335
1336 *vpp = nvp;
1337 return (0);
1338 }
1339
1340
1341 /*
1342 * Do operations associated with quotas
1343 */
1344 int
1345 hfs_quotactl(mp, cmds, uid, arg, p)
1346 struct mount *mp;
1347 int cmds;
1348 uid_t uid;
1349 caddr_t arg;
1350 struct proc *p;
1351 {
1352 int cmd, type, error;
1353
1354 #if !QUOTA
1355 return (EOPNOTSUPP);
1356 #else
1357 if (uid == -1)
1358 uid = p->p_cred->p_ruid;
1359 cmd = cmds >> SUBCMDSHIFT;
1360
1361 switch (cmd) {
1362 case Q_SYNC:
1363 case Q_QUOTASTAT:
1364 break;
1365 case Q_GETQUOTA:
1366 if (uid == p->p_cred->p_ruid)
1367 break;
1368 /* fall through */
1369 default:
1370 if (error = suser(p->p_ucred, &p->p_acflag))
1371 return (error);
1372 }
1373
1374 type = cmds & SUBCMDMASK;
1375 if ((u_int)type >= MAXQUOTAS)
1376 return (EINVAL);
1377 if (vfs_busy(mp, LK_NOWAIT, 0, p))
1378 return (0);
1379
1380 switch (cmd) {
1381
1382 case Q_QUOTAON:
1383 error = hfs_quotaon(p, mp, type, arg, UIO_USERSPACE);
1384 break;
1385
1386 case Q_QUOTAOFF:
1387 error = hfs_quotaoff(p, mp, type);
1388 break;
1389
1390 case Q_SETQUOTA:
1391 error = hfs_setquota(mp, uid, type, arg);
1392 break;
1393
1394 case Q_SETUSE:
1395 error = hfs_setuse(mp, uid, type, arg);
1396 break;
1397
1398 case Q_GETQUOTA:
1399 error = hfs_getquota(mp, uid, type, arg);
1400 break;
1401
1402 case Q_SYNC:
1403 error = hfs_qsync(mp);
1404 break;
1405
1406 case Q_QUOTASTAT:
1407 error = hfs_quotastat(mp, type, arg);
1408 break;
1409
1410 default:
1411 error = EINVAL;
1412 break;
1413 }
1414 vfs_unbusy(mp, p);
1415 return (error);
1416 #endif /* QUOTA */
1417 }
1418
1419
1420
1421
1422 /*
1423 * Get file system statistics.
1424 */
1425 static int
1426 hfs_statfs(mp, sbp, p)
1427 struct mount *mp;
1428 register struct statfs *sbp;
1429 struct proc *p;
1430 {
1431 ExtendedVCB *vcb = VFSTOVCB(mp);
1432 struct hfsmount *hfsmp = VFSTOHFS(mp);
1433 u_long freeCNIDs;
1434
1435 freeCNIDs = (u_long)0xFFFFFFFF - (u_long)vcb->vcbNxtCNID;
1436
1437 sbp->f_bsize = vcb->blockSize;
1438 sbp->f_iosize = hfsmp->hfs_logBlockSize;
1439 sbp->f_blocks = vcb->totalBlocks;
1440 sbp->f_bfree = hfs_freeblks(hfsmp, 0);
1441 sbp->f_bavail = hfs_freeblks(hfsmp, 1);
1442 sbp->f_files = vcb->totalBlocks - 2; /* max files is constrained by total blocks */
1443 sbp->f_ffree = MIN(freeCNIDs, sbp->f_bavail);
1444
1445 sbp->f_type = 0;
1446 if (sbp != &mp->mnt_stat) {
1447 sbp->f_type = mp->mnt_vfc->vfc_typenum;
1448 bcopy((caddr_t)mp->mnt_stat.f_mntonname,
1449 (caddr_t)&sbp->f_mntonname[0], MNAMELEN);
1450 bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
1451 (caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
1452 }
1453 return (0);
1454 }
1455
1456
1457 //
1458 // XXXdbg -- this is a callback to be used by the journal to
1459 // get meta data blocks flushed out to disk.
1460 //
1461 // XXXdbg -- be smarter and don't flush *every* block on each
1462 // call. try to only flush some so we don't wind up
1463 // being too synchronous.
1464 //
1465 __private_extern__
1466 void
1467 hfs_sync_metadata(void *arg)
1468 {
1469 struct mount *mp = (struct mount *)arg;
1470 struct cnode *cp;
1471 struct hfsmount *hfsmp;
1472 ExtendedVCB *vcb;
1473 struct vnode *meta_vp[3];
1474 struct buf *bp;
1475 int i, sectorsize, priIDSector, altIDSector, retval;
1476 int error, allerror = 0;
1477
1478 hfsmp = VFSTOHFS(mp);
1479 vcb = HFSTOVCB(hfsmp);
1480
1481 bflushq(BQ_META, mp);
1482
1483
1484 #if 1 // XXXdbg - I do not believe this is necessary...
1485 // but if I pull it out, then the journal
1486 // does not seem to get flushed properly
1487 // when it is closed....
1488
1489 // now make sure the super block is flushed
1490 sectorsize = hfsmp->hfs_phys_block_size;
1491 priIDSector = (vcb->hfsPlusIOPosOffset / sectorsize) +
1492 HFS_PRI_SECTOR(sectorsize);
1493 retval = meta_bread(hfsmp->hfs_devvp, priIDSector, sectorsize, NOCRED, &bp);
1494 if (retval != 0) {
1495 panic("hfs: sync_metadata: can't read super-block?! (retval 0x%x, priIDSector)\n",
1496 retval, priIDSector);
1497 }
1498
1499 if (retval == 0 && (bp->b_flags & B_DELWRI) && (bp->b_flags & B_LOCKED) == 0) {
1500 bwrite(bp);
1501 } else if (bp) {
1502 brelse(bp);
1503 }
1504
1505 // the alternate super block...
1506 // XXXdbg - we probably don't need to do this each and every time.
1507 // hfs_btreeio.c:FlushAlternate() should flag when it was
1508 // written...
1509 altIDSector = (vcb->hfsPlusIOPosOffset / sectorsize) +
1510 HFS_ALT_SECTOR(sectorsize, hfsmp->hfs_phys_block_count);
1511 retval = meta_bread(hfsmp->hfs_devvp, altIDSector, sectorsize, NOCRED, &bp);
1512 if (retval == 0 && (bp->b_flags & B_DELWRI) && (bp->b_flags & B_LOCKED) == 0) {
1513 bwrite(bp);
1514 } else if (bp) {
1515 brelse(bp);
1516 }
1517 #endif
1518
1519 }
1520
1521 /*
1522 * Go through the disk queues to initiate sandbagged IO;
1523 * go through the inodes to write those that have been modified;
1524 * initiate the writing of the super block if it has been modified.
1525 *
1526 * Note: we are always called with the filesystem marked `MPBUSY'.
1527 */
1528 static int
1529 hfs_sync(mp, waitfor, cred, p)
1530 struct mount *mp;
1531 int waitfor;
1532 struct ucred *cred;
1533 struct proc *p;
1534 {
1535 struct vnode *nvp, *vp;
1536 struct cnode *cp;
1537 struct hfsmount *hfsmp;
1538 ExtendedVCB *vcb;
1539 struct vnode *meta_vp[3];
1540 int i;
1541 int error, allerror = 0;
1542
1543 /*
1544 * During MNT_UPDATE hfs_changefs might be manipulating
1545 * vnodes so back off
1546 */
1547 if (mp->mnt_flag & MNT_UPDATE)
1548 return (0);
1549
1550 hfsmp = VFSTOHFS(mp);
1551 if (hfsmp->hfs_fs_ronly != 0) {
1552 panic("update: rofs mod");
1553 };
1554
1555 #if 0
1556 // XXXdbg first go through and flush out any modified
1557 // meta data blocks so they go out in order...
1558 bflushq(BQ_META, mp);
1559 bflushq(BQ_LRU, mp);
1560 // only flush locked blocks if we're not doing journaling
1561 if (hfsmp->jnl == NULL) {
1562 bflushq(BQ_LOCKED, mp);
1563 }
1564 #endif
1565
1566 /*
1567 * Write back each 'modified' vnode
1568 */
1569
1570 loop:
1571 simple_lock(&mntvnode_slock);
1572 for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
1573 int didhold;
1574 /*
1575 * If the vnode that we are about to sync is no longer
1576 * associated with this mount point, start over.
1577 */
1578 if (vp->v_mount != mp) {
1579 simple_unlock(&mntvnode_slock);
1580 goto loop;
1581 }
1582
1583 simple_lock(&vp->v_interlock);
1584 nvp = vp->v_mntvnodes.le_next;
1585
1586 cp = VTOC(vp);
1587
1588 // restart our whole search if this guy is locked
1589 // or being reclaimed.
1590 // XXXdbg - at some point this should go away or we
1591 // need to change all file systems to have
1592 // this same code. vget() should never return
1593 // success if either of these conditions is
1594 // true.
1595 if (vp->v_tag != VT_HFS || cp == NULL) {
1596 simple_unlock(&vp->v_interlock);
1597 continue;
1598 }
1599
1600 if ((vp->v_flag & VSYSTEM) || (vp->v_type == VNON) ||
1601 (((cp->c_flag & (C_ACCESS | C_CHANGE | C_MODIFIED | C_UPDATE)) == 0) &&
1602 (vp->v_dirtyblkhd.lh_first == NULL) && !(vp->v_flag & VHASDIRTY))) {
1603 simple_unlock(&vp->v_interlock);
1604 simple_unlock(&mntvnode_slock);
1605 simple_lock(&mntvnode_slock);
1606 continue;
1607 }
1608
1609 simple_unlock(&mntvnode_slock);
1610 error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p);
1611 if (error) {
1612 if (error == ENOENT)
1613 goto loop;
1614 simple_lock(&mntvnode_slock);
1615 continue;
1616 }
1617
1618 didhold = ubc_hold(vp);
1619 if ((error = VOP_FSYNC(vp, cred, waitfor, p))) {
1620 allerror = error;
1621 };
1622 VOP_UNLOCK(vp, 0, p);
1623 if (didhold)
1624 ubc_rele(vp);
1625 vrele(vp);
1626 simple_lock(&mntvnode_slock);
1627 };
1628
1629 vcb = HFSTOVCB(hfsmp);
1630
1631 meta_vp[0] = vcb->extentsRefNum;
1632 meta_vp[1] = vcb->catalogRefNum;
1633 meta_vp[2] = vcb->allocationsRefNum; /* This is NULL for standard HFS */
1634
1635 /* Now sync our three metadata files */
1636 for (i = 0; i < 3; ++i) {
1637 struct vnode *btvp;
1638
1639 btvp = btvp = meta_vp[i];;
1640 if ((btvp==0) || (btvp->v_type == VNON) || (btvp->v_mount != mp))
1641 continue;
1642
1643 simple_lock(&btvp->v_interlock);
1644 cp = VTOC(btvp);
1645 if (((cp->c_flag & (C_ACCESS | C_CHANGE | C_MODIFIED | C_UPDATE)) == 0) &&
1646 (btvp->v_dirtyblkhd.lh_first == NULL) && !(btvp->v_flag & VHASDIRTY)) {
1647 simple_unlock(&btvp->v_interlock);
1648 continue;
1649 }
1650 simple_unlock(&mntvnode_slock);
1651 error = vget(btvp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p);
1652 if (error) {
1653 simple_lock(&mntvnode_slock);
1654 continue;
1655 }
1656 if ((error = VOP_FSYNC(btvp, cred, waitfor, p)))
1657 allerror = error;
1658 VOP_UNLOCK(btvp, 0, p);
1659 vrele(btvp);
1660 simple_lock(&mntvnode_slock);
1661 };
1662
1663 simple_unlock(&mntvnode_slock);
1664
1665 /*
1666 * Force stale file system control information to be flushed.
1667 */
1668 if (vcb->vcbSigWord == kHFSSigWord) {
1669 if ((error = VOP_FSYNC(hfsmp->hfs_devvp, cred, waitfor, p)))
1670 allerror = error;
1671 }
1672 #if QUOTA
1673 hfs_qsync(mp);
1674 #endif /* QUOTA */
1675 /*
1676 * Write back modified superblock.
1677 */
1678
1679 if (IsVCBDirty(vcb)) {
1680 // XXXdbg - debugging, remove
1681 if (hfsmp->jnl) {
1682 //printf("hfs: sync: strange, a journaled volume w/dirty VCB? jnl 0x%x hfsmp 0x%x\n",
1683 // hfsmp->jnl, hfsmp);
1684 }
1685
1686 error = hfs_flushvolumeheader(hfsmp, waitfor, 0);
1687 if (error)
1688 allerror = error;
1689 }
1690
1691 if (hfsmp->jnl) {
1692 journal_flush(hfsmp->jnl);
1693 }
1694
1695 err_exit:
1696 return (allerror);
1697 }
1698
1699
1700 /*
1701 * File handle to vnode
1702 *
1703 * Have to be really careful about stale file handles:
1704 * - check that the cnode id is valid
1705 * - call hfs_vget() to get the locked cnode
1706 * - check for an unallocated cnode (i_mode == 0)
1707 * - check that the given client host has export rights and return
1708 * those rights via. exflagsp and credanonp
1709 */
1710 static int
1711 hfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
1712 register struct mount *mp;
1713 struct fid *fhp;
1714 struct mbuf *nam;
1715 struct vnode **vpp;
1716 int *exflagsp;
1717 struct ucred **credanonp;
1718 {
1719 struct hfsfid *hfsfhp;
1720 struct vnode *nvp;
1721 int result;
1722 struct netcred *np;
1723
1724 *vpp = NULL;
1725 hfsfhp = (struct hfsfid *)fhp;
1726
1727 /*
1728 * Get the export permission structure for this <mp, client> tuple.
1729 */
1730 np = vfs_export_lookup(mp, &VFSTOHFS(mp)->hfs_export, nam);
1731 if (np == NULL) {
1732 return EACCES;
1733 };
1734
1735 result = VFS_VGET(mp, &hfsfhp->hfsfid_cnid, &nvp);
1736 if (result) return result;
1737 if (nvp == NULL) return ESTALE;
1738
1739 /* The createtime can be changed by hfs_setattr or hfs_setattrlist.
1740 * For NFS, we are assuming that only if the createtime was moved
1741 * forward would it mean the fileID got reused in that session by
1742 * wrapping. We don't have a volume ID or other unique identifier to
1743 * to use here for a generation ID across reboots, crashes where
1744 * metadata noting lastFileID didn't make it to disk but client has
1745 * it, or volume erasures where fileIDs start over again. Lastly,
1746 * with HFS allowing "wraps" of fileIDs now, this becomes more
1747 * error prone. Future, would be change the "wrap bit" to a unique
1748 * wrap number and use that for generation number. For now do this.
1749 */
1750 if ((hfsfhp->hfsfid_gen < VTOC(nvp)->c_itime)) {
1751 vput(nvp);
1752 return (ESTALE);
1753 };
1754
1755 *vpp = nvp;
1756 *exflagsp = np->netc_exflags;
1757 *credanonp = &np->netc_anon;
1758
1759 return (0);
1760 }
1761
1762
1763 /*
1764 * Vnode pointer to File handle
1765 */
1766 /* ARGSUSED */
1767 static int
1768 hfs_vptofh(vp, fhp)
1769 struct vnode *vp;
1770 struct fid *fhp;
1771 {
1772 struct cnode *cp;
1773 struct hfsfid *hfsfhp;
1774
1775 if (ISHFS(VTOVCB(vp)))
1776 return (EOPNOTSUPP); /* hfs standard is not exportable */
1777
1778 cp = VTOC(vp);
1779 hfsfhp = (struct hfsfid *)fhp;
1780 hfsfhp->hfsfid_len = sizeof(struct hfsfid);
1781 hfsfhp->hfsfid_pad = 0;
1782 hfsfhp->hfsfid_cnid = cp->c_cnid;
1783 hfsfhp->hfsfid_gen = cp->c_itime;
1784
1785 return (0);
1786 }
1787
1788
1789 /*
1790 * Initial HFS filesystems, done only once.
1791 */
1792 static int
1793 hfs_init(vfsp)
1794 struct vfsconf *vfsp;
1795 {
1796 static int done = 0;
1797
1798 if (done)
1799 return (0);
1800 done = 1;
1801 hfs_chashinit();
1802 hfs_converterinit();
1803 #if QUOTA
1804 dqinit();
1805 #endif /* QUOTA */
1806
1807 /*
1808 * Allocate Catalog Iterator cache...
1809 */
1810 (void) InitCatalogCache();
1811
1812 return (0);
1813 }
1814
1815
1816 // XXXdbg
1817 #include <sys/filedesc.h>
1818
1819
1820 /*
1821 * HFS filesystem related variables.
1822 */
1823 static int
1824 hfs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
1825 int *name;
1826 u_int namelen;
1827 void *oldp;
1828 size_t *oldlenp;
1829 void *newp;
1830 size_t newlen;
1831 struct proc *p;
1832 {
1833 extern u_int32_t hfs_encodingbias;
1834
1835 /* all sysctl names at this level are terminal */
1836
1837 if (name[0] == HFS_ENCODINGBIAS)
1838 return (sysctl_int(oldp, oldlenp, newp, newlen,
1839 &hfs_encodingbias));
1840 else if (name[0] == 0x082969) {
1841 // make the file system journaled...
1842 struct vnode *vp = p->p_fd->fd_cdir, *jvp;
1843 struct hfsmount *hfsmp;
1844 ExtendedVCB *vcb;
1845 int retval;
1846 struct cat_attr jnl_attr, jinfo_attr;
1847 struct cat_fork jnl_fork, jinfo_fork;
1848 void *jnl = NULL;
1849
1850 /* Only root can enable journaling */
1851 if (current_proc()->p_ucred->cr_uid != 0) {
1852 return (EPERM);
1853 }
1854 hfsmp = VTOHFS(vp);
1855 if (hfsmp->hfs_fs_ronly) {
1856 return EROFS;
1857 }
1858 if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord) {
1859 printf("hfs: can't make a plain hfs volume journaled.\n");
1860 return EINVAL;
1861 }
1862
1863 if (hfsmp->jnl) {
1864 printf("hfs: volume @ mp 0x%x is already journaled!\n", vp->v_mount);
1865 return EAGAIN;
1866 }
1867
1868 vcb = HFSTOVCB(hfsmp);
1869 if (BTHasContiguousNodes(VTOF(vcb->catalogRefNum)) == 0 ||
1870 BTHasContiguousNodes(VTOF(vcb->extentsRefNum)) == 0) {
1871
1872 printf("hfs: volume has a btree w/non-contiguous nodes. can not enable journaling.\n");
1873 return EINVAL;
1874 }
1875
1876 // make sure these both exist!
1877 if ( GetFileInfo(vcb, kRootDirID, ".journal_info_block", &jinfo_attr, &jinfo_fork) == 0
1878 || GetFileInfo(vcb, kRootDirID, ".journal", &jnl_attr, &jnl_fork) == 0) {
1879
1880 return EINVAL;
1881 }
1882
1883 hfs_sync(hfsmp->hfs_mp, MNT_WAIT, FSCRED, p);
1884 bflushq(BQ_META);
1885
1886 printf("hfs: Initializing the journal (joffset 0x%llx sz 0x%llx)...\n",
1887 (off_t)name[2], (off_t)name[3]);
1888
1889 jvp = hfsmp->hfs_devvp;
1890 jnl = journal_create(jvp,
1891 (off_t)name[2] * (off_t)HFSTOVCB(hfsmp)->blockSize
1892 + HFSTOVCB(hfsmp)->hfsPlusIOPosOffset,
1893 (off_t)name[3],
1894 hfsmp->hfs_devvp,
1895 hfsmp->hfs_phys_block_size,
1896 0,
1897 0,
1898 hfs_sync_metadata, hfsmp->hfs_mp);
1899
1900 if (jnl == NULL) {
1901 printf("hfs: FAILED to create the journal!\n");
1902 if (jvp && jvp != hfsmp->hfs_devvp) {
1903 VOP_CLOSE(jvp, hfsmp->hfs_fs_ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
1904 }
1905 jvp = NULL;
1906
1907 return EINVAL;
1908 }
1909
1910 hfs_global_exclusive_lock_acquire(hfsmp);
1911
1912 HFSTOVCB(hfsmp)->vcbJinfoBlock = name[1];
1913 HFSTOVCB(hfsmp)->vcbAtrb |= kHFSVolumeJournaledMask;
1914 hfsmp->jvp = jvp;
1915 hfsmp->jnl = jnl;
1916
1917 // save this off for the hack-y check in hfs_remove()
1918 hfsmp->jnl_start = (u_int32_t)name[2];
1919 hfsmp->hfs_jnlinfoblkid = jinfo_attr.ca_fileid;
1920 hfsmp->hfs_jnlfileid = jnl_attr.ca_fileid;
1921
1922 hfsmp->hfs_mp->mnt_flag |= MNT_JOURNALED;
1923
1924 hfs_global_exclusive_lock_release(hfsmp);
1925 hfs_flushvolumeheader(hfsmp, MNT_WAIT, 1);
1926
1927 return 0;
1928 } else if (name[0] == 0x031272) {
1929 // clear the journaling bit
1930 struct vnode *vp = p->p_fd->fd_cdir;
1931 struct hfsmount *hfsmp;
1932 void *jnl;
1933 int retval;
1934
1935 /* Only root can disable journaling */
1936 if (current_proc()->p_ucred->cr_uid != 0) {
1937 return (EPERM);
1938 }
1939 hfsmp = VTOHFS(vp);
1940 if (hfsmp->jnl == NULL) {
1941 return EINVAL;
1942 }
1943
1944 printf("hfs: disabling journaling for mount @ 0x%x\n", vp->v_mount);
1945
1946 jnl = hfsmp->jnl;
1947
1948 hfs_global_exclusive_lock_acquire(hfsmp);
1949
1950 // Lights out for you buddy!
1951 hfsmp->jnl = NULL;
1952 journal_close(jnl);
1953
1954 if (hfsmp->jvp && hfsmp->jvp != hfsmp->hfs_devvp) {
1955 VOP_CLOSE(hfsmp->jvp, hfsmp->hfs_fs_ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
1956 }
1957 hfsmp->jnl = NULL;
1958 hfsmp->jvp = NULL;
1959 hfsmp->hfs_mp->mnt_flag &= ~MNT_JOURNALED;
1960 hfsmp->jnl_start = 0;
1961 hfsmp->hfs_jnlinfoblkid = 0;
1962 hfsmp->hfs_jnlfileid = 0;
1963
1964 HFSTOVCB(hfsmp)->vcbAtrb &= ~kHFSVolumeJournaledMask;
1965
1966 hfs_global_exclusive_lock_release(hfsmp);
1967 hfs_flushvolumeheader(hfsmp, MNT_WAIT, 1);
1968
1969 return 0;
1970 }
1971
1972 return (EOPNOTSUPP);
1973 }
1974
1975
1976 /* This will return a vnode of either a directory or a data vnode based on an object id. If
1977 * it is a file id, its data fork will be returned.
1978 */
1979 static int
1980 hfs_vget(mp, ino, vpp)
1981 struct mount *mp;
1982 void *ino;
1983 struct vnode **vpp;
1984 {
1985 cnid_t cnid = *(cnid_t *)ino;
1986
1987 /* Check for cnids that should't be exported. */
1988 if ((cnid < kHFSFirstUserCatalogNodeID)
1989 && (cnid != kHFSRootFolderID && cnid != kHFSRootParentID))
1990 return (ENOENT);
1991 /* Don't export HFS Private Data dir. */
1992 if (cnid == VFSTOHFS(mp)->hfs_privdir_desc.cd_cnid)
1993 return (ENOENT);
1994
1995 return (hfs_getcnode(VFSTOHFS(mp), cnid, NULL, 0, NULL, NULL, vpp));
1996 }
1997
1998 /*
1999 * Flush out all the files in a filesystem.
2000 */
2001 int
2002 hfs_flushfiles(struct mount *mp, int flags, struct proc *p)
2003 {
2004 register struct hfsmount *hfsmp;
2005 int i;
2006 int error;
2007
2008 #if QUOTA
2009 hfsmp = VFSTOHFS(mp);
2010
2011 if (mp->mnt_flag & MNT_QUOTA) {
2012 if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags))
2013 return (error);
2014 for (i = 0; i < MAXQUOTAS; i++) {
2015 if (hfsmp->hfs_qfiles[i].qf_vp == NULLVP)
2016 continue;
2017 hfs_quotaoff(p, mp, i);
2018 }
2019 /*
2020 * Here we fall through to vflush again to ensure
2021 * that we have gotten rid of all the system vnodes.
2022 */
2023 }
2024 #endif /* QUOTA */
2025
2026 error = vflush(mp, NULLVP, (SKIPSYSTEM | SKIPSWAP | flags));
2027 error = vflush(mp, NULLVP, (SKIPSYSTEM | flags));
2028
2029 return (error);
2030 }
2031
2032 /*
2033 * Update volume encoding bitmap (HFS Plus only)
2034 */
2035 __private_extern__
2036 void
2037 hfs_setencodingbits(struct hfsmount *hfsmp, u_int32_t encoding)
2038 {
2039 #define kIndexMacUkrainian 48 /* MacUkrainian encoding is 152 */
2040 #define kIndexMacFarsi 49 /* MacFarsi encoding is 140 */
2041
2042 UInt32 index;
2043
2044 switch (encoding) {
2045 case kTextEncodingMacUkrainian:
2046 index = kIndexMacUkrainian;
2047 break;
2048 case kTextEncodingMacFarsi:
2049 index = kIndexMacFarsi;
2050 break;
2051 default:
2052 index = encoding;
2053 break;
2054 }
2055
2056 if (index < 128) {
2057 HFSTOVCB(hfsmp)->encodingsBitmap |= (1 << index);
2058 HFSTOVCB(hfsmp)->vcbFlags |= 0xFF00;
2059 }
2060 }
2061
2062 /*
2063 * Update volume stats
2064 */
2065 __private_extern__
2066 int
2067 hfs_volupdate(struct hfsmount *hfsmp, enum volop op, int inroot)
2068 {
2069 ExtendedVCB *vcb;
2070
2071 vcb = HFSTOVCB(hfsmp);
2072 vcb->vcbFlags |= 0xFF00;
2073 vcb->vcbLsMod = time.tv_sec;
2074
2075 switch (op) {
2076 case VOL_UPDATE:
2077 break;
2078 case VOL_MKDIR:
2079 if (vcb->vcbDirCnt != 0xFFFFFFFF)
2080 ++vcb->vcbDirCnt;
2081 if (inroot && vcb->vcbNmRtDirs != 0xFFFF)
2082 ++vcb->vcbNmRtDirs;
2083 break;
2084 case VOL_RMDIR:
2085 if (vcb->vcbDirCnt != 0)
2086 --vcb->vcbDirCnt;
2087 if (inroot && vcb->vcbNmRtDirs != 0xFFFF)
2088 --vcb->vcbNmRtDirs;
2089 break;
2090 case VOL_MKFILE:
2091 if (vcb->vcbFilCnt != 0xFFFFFFFF)
2092 ++vcb->vcbFilCnt;
2093 if (inroot && vcb->vcbNmFls != 0xFFFF)
2094 ++vcb->vcbNmFls;
2095 break;
2096 case VOL_RMFILE:
2097 if (vcb->vcbFilCnt != 0)
2098 --vcb->vcbFilCnt;
2099 if (inroot && vcb->vcbNmFls != 0xFFFF)
2100 --vcb->vcbNmFls;
2101 break;
2102 }
2103
2104 if (hfsmp->jnl) {
2105 hfs_flushvolumeheader(hfsmp, 0, 0);
2106 }
2107
2108 return (0);
2109 }
2110
2111
2112 static int
2113 hfs_flushMDB(struct hfsmount *hfsmp, int waitfor, int altflush)
2114 {
2115 ExtendedVCB *vcb = HFSTOVCB(hfsmp);
2116 struct filefork *fp;
2117 HFSMasterDirectoryBlock *mdb;
2118 struct buf *bp = NULL;
2119 int retval;
2120 int sectorsize;
2121 ByteCount namelen;
2122
2123 sectorsize = hfsmp->hfs_phys_block_size;
2124 retval = bread(hfsmp->hfs_devvp, HFS_PRI_SECTOR(sectorsize), sectorsize, NOCRED, &bp);
2125 if (retval) {
2126 if (bp)
2127 brelse(bp);
2128 return retval;
2129 }
2130
2131 DBG_ASSERT(bp != NULL);
2132 DBG_ASSERT(bp->b_data != NULL);
2133 DBG_ASSERT(bp->b_bcount == size);
2134
2135 if (hfsmp->jnl) {
2136 panic("hfs: standard hfs volumes should not be journaled!\n");
2137 }
2138
2139 mdb = (HFSMasterDirectoryBlock *)(bp->b_data + HFS_PRI_OFFSET(sectorsize));
2140
2141 mdb->drCrDate = SWAP_BE32 (UTCToLocal(to_hfs_time(vcb->vcbCrDate)));
2142 mdb->drLsMod = SWAP_BE32 (UTCToLocal(to_hfs_time(vcb->vcbLsMod)));
2143 mdb->drAtrb = SWAP_BE16 (vcb->vcbAtrb);
2144 mdb->drNmFls = SWAP_BE16 (vcb->vcbNmFls);
2145 mdb->drAllocPtr = SWAP_BE16 (vcb->nextAllocation);
2146 mdb->drClpSiz = SWAP_BE32 (vcb->vcbClpSiz);
2147 mdb->drNxtCNID = SWAP_BE32 (vcb->vcbNxtCNID);
2148 mdb->drFreeBks = SWAP_BE16 (vcb->freeBlocks);
2149
2150 namelen = strlen(vcb->vcbVN);
2151 retval = utf8_to_hfs(vcb, namelen, vcb->vcbVN, mdb->drVN);
2152 /* Retry with MacRoman in case that's how it was exported. */
2153 if (retval)
2154 retval = utf8_to_mac_roman(namelen, vcb->vcbVN, mdb->drVN);
2155
2156 mdb->drVolBkUp = SWAP_BE32 (UTCToLocal(to_hfs_time(vcb->vcbVolBkUp)));
2157 mdb->drWrCnt = SWAP_BE32 (vcb->vcbWrCnt);
2158 mdb->drNmRtDirs = SWAP_BE16 (vcb->vcbNmRtDirs);
2159 mdb->drFilCnt = SWAP_BE32 (vcb->vcbFilCnt);
2160 mdb->drDirCnt = SWAP_BE32 (vcb->vcbDirCnt);
2161
2162 bcopy(vcb->vcbFndrInfo, mdb->drFndrInfo, sizeof(mdb->drFndrInfo));
2163
2164 fp = VTOF(vcb->extentsRefNum);
2165 mdb->drXTExtRec[0].startBlock = SWAP_BE16 (fp->ff_extents[0].startBlock);
2166 mdb->drXTExtRec[0].blockCount = SWAP_BE16 (fp->ff_extents[0].blockCount);
2167 mdb->drXTExtRec[1].startBlock = SWAP_BE16 (fp->ff_extents[1].startBlock);
2168 mdb->drXTExtRec[1].blockCount = SWAP_BE16 (fp->ff_extents[1].blockCount);
2169 mdb->drXTExtRec[2].startBlock = SWAP_BE16 (fp->ff_extents[2].startBlock);
2170 mdb->drXTExtRec[2].blockCount = SWAP_BE16 (fp->ff_extents[2].blockCount);
2171 mdb->drXTFlSize = SWAP_BE32 (fp->ff_blocks * vcb->blockSize);
2172 mdb->drXTClpSiz = SWAP_BE32 (fp->ff_clumpsize);
2173
2174 fp = VTOF(vcb->catalogRefNum);
2175 mdb->drCTExtRec[0].startBlock = SWAP_BE16 (fp->ff_extents[0].startBlock);
2176 mdb->drCTExtRec[0].blockCount = SWAP_BE16 (fp->ff_extents[0].blockCount);
2177 mdb->drCTExtRec[1].startBlock = SWAP_BE16 (fp->ff_extents[1].startBlock);
2178 mdb->drCTExtRec[1].blockCount = SWAP_BE16 (fp->ff_extents[1].blockCount);
2179 mdb->drCTExtRec[2].startBlock = SWAP_BE16 (fp->ff_extents[2].startBlock);
2180 mdb->drCTExtRec[2].blockCount = SWAP_BE16 (fp->ff_extents[2].blockCount);
2181 mdb->drCTFlSize = SWAP_BE32 (fp->ff_blocks * vcb->blockSize);
2182 mdb->drCTClpSiz = SWAP_BE32 (fp->ff_clumpsize);
2183
2184 /* If requested, flush out the alternate MDB */
2185 if (altflush) {
2186 struct buf *alt_bp = NULL;
2187 u_long altIDSector;
2188
2189 altIDSector = HFS_ALT_SECTOR(sectorsize, hfsmp->hfs_phys_block_count);
2190
2191 if (meta_bread(hfsmp->hfs_devvp, altIDSector, sectorsize, NOCRED, &alt_bp) == 0) {
2192 bcopy(mdb, alt_bp->b_data + HFS_ALT_OFFSET(sectorsize), kMDBSize);
2193
2194 (void) VOP_BWRITE(alt_bp);
2195 } else if (alt_bp)
2196 brelse(alt_bp);
2197 }
2198
2199 if (waitfor != MNT_WAIT)
2200 bawrite(bp);
2201 else
2202 retval = VOP_BWRITE(bp);
2203
2204 MarkVCBClean( vcb );
2205
2206 return (retval);
2207 }
2208
2209
2210 __private_extern__
2211 int
2212 hfs_flushvolumeheader(struct hfsmount *hfsmp, int waitfor, int altflush)
2213 {
2214 ExtendedVCB *vcb = HFSTOVCB(hfsmp);
2215 struct filefork *fp;
2216 HFSPlusVolumeHeader *volumeHeader;
2217 int retval;
2218 struct buf *bp;
2219 int i;
2220 int sectorsize;
2221 int priIDSector;
2222 int critical = 0;
2223
2224 if (vcb->vcbSigWord == kHFSSigWord)
2225 return hfs_flushMDB(hfsmp, waitfor, altflush);
2226
2227 if (altflush)
2228 critical = 1;
2229 sectorsize = hfsmp->hfs_phys_block_size;
2230 priIDSector = (vcb->hfsPlusIOPosOffset / sectorsize) +
2231 HFS_PRI_SECTOR(sectorsize);
2232
2233 // XXXdbg
2234 hfs_global_shared_lock_acquire(hfsmp);
2235 if (hfsmp->jnl) {
2236 if (journal_start_transaction(hfsmp->jnl) != 0) {
2237 hfs_global_shared_lock_release(hfsmp);
2238 return EINVAL;
2239 }
2240 }
2241
2242 retval = meta_bread(hfsmp->hfs_devvp, priIDSector, sectorsize, NOCRED, &bp);
2243 if (retval) {
2244 if (bp)
2245 brelse(bp);
2246
2247 if (hfsmp->jnl) {
2248 journal_end_transaction(hfsmp->jnl);
2249 }
2250 hfs_global_shared_lock_release(hfsmp);
2251
2252 return (retval);
2253 }
2254
2255 if (hfsmp->jnl) {
2256 journal_modify_block_start(hfsmp->jnl, bp);
2257 }
2258
2259 volumeHeader = (HFSPlusVolumeHeader *)((char *)bp->b_data + HFS_PRI_OFFSET(sectorsize));
2260
2261 /*
2262 * For embedded HFS+ volumes, update create date if it changed
2263 * (ie from a setattrlist call)
2264 */
2265 if ((vcb->hfsPlusIOPosOffset != 0) &&
2266 (SWAP_BE32 (volumeHeader->createDate) != vcb->localCreateDate)) {
2267 struct buf *bp2;
2268 HFSMasterDirectoryBlock *mdb;
2269
2270 retval = meta_bread(hfsmp->hfs_devvp, HFS_PRI_SECTOR(sectorsize),
2271 sectorsize, NOCRED, &bp2);
2272 if (retval) {
2273 if (bp2)
2274 brelse(bp2);
2275 retval = 0;
2276 } else {
2277 mdb = (HFSMasterDirectoryBlock *)(bp2->b_data +
2278 HFS_PRI_OFFSET(sectorsize));
2279
2280 if ( SWAP_BE32 (mdb->drCrDate) != vcb->localCreateDate )
2281 {
2282 // XXXdbg
2283 if (hfsmp->jnl) {
2284 journal_modify_block_start(hfsmp->jnl, bp2);
2285 }
2286
2287 mdb->drCrDate = SWAP_BE32 (vcb->localCreateDate); /* pick up the new create date */
2288
2289 // XXXdbg
2290 if (hfsmp->jnl) {
2291 journal_modify_block_end(hfsmp->jnl, bp2);
2292 } else {
2293 (void) VOP_BWRITE(bp2); /* write out the changes */
2294 }
2295 }
2296 else
2297 {
2298 brelse(bp2); /* just release it */
2299 }
2300 }
2301 }
2302
2303 // XXXdbg - only monkey around with the volume signature on non-root volumes
2304 //
2305 #if 0
2306 if (hfsmp->jnl &&
2307 hfsmp->hfs_fs_ronly == 0 &&
2308 (HFSTOVFS(hfsmp)->mnt_flag & MNT_ROOTFS) == 0) {
2309
2310 int old_sig = volumeHeader->signature;
2311
2312 if (vcb->vcbAtrb & kHFSVolumeUnmountedMask) {
2313 volumeHeader->signature = kHFSPlusSigWord;
2314 } else {
2315 volumeHeader->signature = kHFSJSigWord;
2316 }
2317
2318 if (old_sig != volumeHeader->signature) {
2319 altflush = 1;
2320 }
2321 }
2322 #endif
2323 // XXXdbg
2324
2325 /* Note: only update the lower 16 bits worth of attributes */
2326 volumeHeader->attributes = SWAP_BE32 ((SWAP_BE32 (volumeHeader->attributes) & 0xFFFF0000) + (UInt16) vcb->vcbAtrb);
2327 volumeHeader->journalInfoBlock = SWAP_BE32(vcb->vcbJinfoBlock);
2328 if (hfsmp->jnl) {
2329 volumeHeader->lastMountedVersion = SWAP_BE32 (kHFSJMountVersion);
2330 } else {
2331 volumeHeader->lastMountedVersion = SWAP_BE32 (kHFSPlusMountVersion);
2332 }
2333 volumeHeader->createDate = SWAP_BE32 (vcb->localCreateDate); /* volume create date is in local time */
2334 volumeHeader->modifyDate = SWAP_BE32 (to_hfs_time(vcb->vcbLsMod));
2335 volumeHeader->backupDate = SWAP_BE32 (to_hfs_time(vcb->vcbVolBkUp));
2336 volumeHeader->fileCount = SWAP_BE32 (vcb->vcbFilCnt);
2337 volumeHeader->folderCount = SWAP_BE32 (vcb->vcbDirCnt);
2338 volumeHeader->freeBlocks = SWAP_BE32 (vcb->freeBlocks);
2339 volumeHeader->nextAllocation = SWAP_BE32 (vcb->nextAllocation);
2340 volumeHeader->rsrcClumpSize = SWAP_BE32 (vcb->vcbClpSiz);
2341 volumeHeader->dataClumpSize = SWAP_BE32 (vcb->vcbClpSiz);
2342 volumeHeader->nextCatalogID = SWAP_BE32 (vcb->vcbNxtCNID);
2343 volumeHeader->writeCount = SWAP_BE32 (vcb->vcbWrCnt);
2344 volumeHeader->encodingsBitmap = SWAP_BE64 (vcb->encodingsBitmap);
2345
2346 if (bcmp(vcb->vcbFndrInfo, volumeHeader->finderInfo, sizeof(volumeHeader->finderInfo)) != 0)
2347 critical = 1;
2348 bcopy(vcb->vcbFndrInfo, volumeHeader->finderInfo, sizeof(volumeHeader->finderInfo));
2349
2350 /* Sync Extents over-flow file meta data */
2351 fp = VTOF(vcb->extentsRefNum);
2352 for (i = 0; i < kHFSPlusExtentDensity; i++) {
2353 volumeHeader->extentsFile.extents[i].startBlock =
2354 SWAP_BE32 (fp->ff_extents[i].startBlock);
2355 volumeHeader->extentsFile.extents[i].blockCount =
2356 SWAP_BE32 (fp->ff_extents[i].blockCount);
2357 }
2358 FTOC(fp)->c_flag &= ~C_MODIFIED;
2359 volumeHeader->extentsFile.logicalSize = SWAP_BE64 (fp->ff_size);
2360 volumeHeader->extentsFile.totalBlocks = SWAP_BE32 (fp->ff_blocks);
2361 volumeHeader->extentsFile.clumpSize = SWAP_BE32 (fp->ff_clumpsize);
2362
2363 /* Sync Catalog file meta data */
2364 fp = VTOF(vcb->catalogRefNum);
2365 for (i = 0; i < kHFSPlusExtentDensity; i++) {
2366 volumeHeader->catalogFile.extents[i].startBlock =
2367 SWAP_BE32 (fp->ff_extents[i].startBlock);
2368 volumeHeader->catalogFile.extents[i].blockCount =
2369 SWAP_BE32 (fp->ff_extents[i].blockCount);
2370 }
2371 FTOC(fp)->c_flag &= ~C_MODIFIED;
2372 volumeHeader->catalogFile.logicalSize = SWAP_BE64 (fp->ff_size);
2373 volumeHeader->catalogFile.totalBlocks = SWAP_BE32 (fp->ff_blocks);
2374 volumeHeader->catalogFile.clumpSize = SWAP_BE32 (fp->ff_clumpsize);
2375
2376 /* Sync Allocation file meta data */
2377 fp = VTOF(vcb->allocationsRefNum);
2378 for (i = 0; i < kHFSPlusExtentDensity; i++) {
2379 volumeHeader->allocationFile.extents[i].startBlock =
2380 SWAP_BE32 (fp->ff_extents[i].startBlock);
2381 volumeHeader->allocationFile.extents[i].blockCount =
2382 SWAP_BE32 (fp->ff_extents[i].blockCount);
2383 }
2384 FTOC(fp)->c_flag &= ~C_MODIFIED;
2385 volumeHeader->allocationFile.logicalSize = SWAP_BE64 (fp->ff_size);
2386 volumeHeader->allocationFile.totalBlocks = SWAP_BE32 (fp->ff_blocks);
2387 volumeHeader->allocationFile.clumpSize = SWAP_BE32 (fp->ff_clumpsize);
2388
2389 /* If requested, flush out the alternate volume header */
2390 if (altflush) {
2391 struct buf *alt_bp = NULL;
2392 u_long altIDSector;
2393
2394 altIDSector = (vcb->hfsPlusIOPosOffset / sectorsize) +
2395 HFS_ALT_SECTOR(sectorsize, hfsmp->hfs_phys_block_count);
2396
2397 if (meta_bread(hfsmp->hfs_devvp, altIDSector, sectorsize, NOCRED, &alt_bp) == 0) {
2398 if (hfsmp->jnl) {
2399 journal_modify_block_start(hfsmp->jnl, alt_bp);
2400 }
2401
2402 bcopy(volumeHeader, alt_bp->b_data + HFS_ALT_OFFSET(sectorsize), kMDBSize);
2403
2404 if (hfsmp->jnl) {
2405 journal_modify_block_end(hfsmp->jnl, alt_bp);
2406 } else {
2407 (void) VOP_BWRITE(alt_bp);
2408 }
2409 } else if (alt_bp)
2410 brelse(alt_bp);
2411 }
2412
2413 // XXXdbg
2414 if (hfsmp->jnl) {
2415 journal_modify_block_end(hfsmp->jnl, bp);
2416 journal_end_transaction(hfsmp->jnl);
2417 } else {
2418 if (waitfor != MNT_WAIT)
2419 bawrite(bp);
2420 else {
2421 retval = VOP_BWRITE(bp);
2422 /* When critical data changes, flush the device cache */
2423 if (critical && (retval == 0)) {
2424 (void) VOP_IOCTL(hfsmp->hfs_devvp, DKIOCSYNCHRONIZECACHE,
2425 NULL, FWRITE, NOCRED, current_proc());
2426 }
2427 }
2428 }
2429 hfs_global_shared_lock_release(hfsmp);
2430
2431 vcb->vcbFlags &= 0x00FF;
2432 return (retval);
2433 }
2434
2435
2436 /*
2437 * hfs vfs operations.
2438 */
2439 struct vfsops hfs_vfsops = {
2440 hfs_mount,
2441 hfs_start,
2442 hfs_unmount,
2443 hfs_root,
2444 hfs_quotactl,
2445 hfs_statfs,
2446 hfs_sync,
2447 hfs_vget,
2448 hfs_fhtovp,
2449 hfs_vptofh,
2450 hfs_init,
2451 hfs_sysctl
2452 };