]> git.saurik.com Git - apple/xnu.git/blame - bsd/hfs/hfs_vfsops.c
xnu-344.12.2.tar.gz
[apple/xnu.git] / bsd / hfs / hfs_vfsops.c
CommitLineData
1c79356b 1/*
9bccf70c 2 * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
1c79356b
A
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 *
9bccf70c 62 * (c) Copyright 1997-2002 Apple Computer, Inc. All rights reserved.
1c79356b
A
63 *
64 * hfs_vfsops.c -- VFS layer for loadable HFS file system.
65 *
1c79356b
A
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>
1c79356b 76#include <sys/lock.h>
9bccf70c
A
77#include <sys/quota.h>
78#include <sys/disk.h>
79
b4c24cb9
A
80// XXXdbg
81#include <vfs/vfs_journal.h>
82
1c79356b
A
83#include <miscfs/specfs/specdev.h>
84#include <hfs/hfs_mount.h>
85
86#include "hfs.h"
9bccf70c
A
87#include "hfs_catalog.h"
88#include "hfs_cnode.h"
1c79356b
A
89#include "hfs_dbg.h"
90#include "hfs_endian.h"
9bccf70c 91#include "hfs_quota.h"
1c79356b
A
92
93#include "hfscommon/headers/FileMgrInternal.h"
94#include "hfscommon/headers/BTreesInternal.h"
95
9bccf70c 96
1c79356b
A
97#if HFS_DIAGNOSTIC
98int hfs_dbg_all = 0;
1c79356b 99int hfs_dbg_err = 0;
1c79356b
A
100#endif
101
d52fe63f 102
1c79356b
A
103extern struct vnodeopv_desc hfs_vnodeop_opv_desc;
104
9bccf70c 105extern void hfs_converterinit(void);
1c79356b
A
106
107extern void inittodr( time_t base);
1c79356b 108
1c79356b 109
9bccf70c
A
110static int hfs_changefs __P((struct mount *mp, struct hfs_mount_args *args,
111 struct proc *p));
112static int hfs_reload __P((struct mount *mp, struct ucred *cred, struct proc *p));
1c79356b 113
9bccf70c
A
114static int hfs_mountfs __P((struct vnode *devvp, struct mount *mp, struct proc *p,
115 struct hfs_mount_args *args));
116static int hfs_statfs __P((struct mount *mp, register struct statfs *sbp,
117 struct proc *p));
1c79356b
A
118
119
120/*
121 * Called by vfs_mountroot when mounting HFS Plus as root.
122 */
123int
124hfs_mountroot()
125{
126 extern struct vnode *rootvp;
127 struct mount *mp;
128 struct proc *p = current_proc(); /* XXX */
129 struct hfsmount *hfsmp;
9bccf70c 130 ExtendedVCB *vcb;
1c79356b
A
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 }
9bccf70c
A
140 if ((error = vfs_rootmountalloc("hfs", "root_device", &mp))) {
141 vrele(rootvp); /* release the reference from bdevvp() */
1c79356b 142 return (error);
9bccf70c 143 }
1c79356b
A
144 if ((error = hfs_mountfs(rootvp, mp, p, NULL))) {
145 mp->mnt_vfc->vfc_refcount--;
146 vfs_unbusy(mp, p);
9bccf70c 147 vrele(rootvp); /* release the reference from bdevvp() */
1c79356b
A
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
0b4e3aa0
A
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 */
1c79356b 162
9bccf70c
A
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
1c79356b
A
168 (void)hfs_statfs(mp, &mp->mnt_stat, p);
169
170 vfs_unbusy(mp, p);
9bccf70c 171 inittodr(HFSTOVCB(hfsmp)->vcbLsMod);
1c79356b
A
172 return (0);
173}
174
175
176/*
177 * VFS Operations.
178 *
179 * mount system call
180 */
181
9bccf70c
A
182static int
183hfs_mount(mp, path, data, ndp, p)
1c79356b
A
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;
1c79356b
A
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) {
0b4e3aa0 206
1c79356b
A
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
9bccf70c 219 if ((retval = hfs_flushfiles(mp, flags, p)))
1c79356b 220 goto error_exit;
1c79356b 221 hfsmp->hfs_fs_ronly = 1;
9bccf70c 222 retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT, 0);
1c79356b
A
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) {
1c79356b
A
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 }
9bccf70c 252 retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT, 0);
1c79356b
A
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;
1c79356b
A
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));
b4c24cb9
A
265 if (hfsmp->jnl)
266 hfs_remove_orphans(hfsmp);
1c79356b
A
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
1c79356b
A
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);
b4c24cb9 340
1c79356b
A
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
347error_exit:
348
349 return (retval);
350}
351
352
9bccf70c
A
353/* Change fs mount parameters */
354static int
1c79356b
A
355hfs_changefs(mp, args, p)
356 struct mount *mp;
357 struct hfs_mount_args *args;
358 struct proc *p;
359{
9bccf70c 360 int retval = 0;
1c79356b
A
361 int namefix, permfix, permswitch;
362 struct hfsmount *hfsmp;
9bccf70c 363 struct cnode *cp;
1c79356b 364 ExtendedVCB *vcb;
1c79356b
A
365 register struct vnode *vp, *nvp;
366 hfs_to_unicode_func_t get_unicode_func;
367 unicode_to_hfs_func_t get_hfsname_func;
9bccf70c
A
368 struct cat_desc cndesc;
369 struct cat_attr cnattr;
370 u_long old_encoding;
1c79356b
A
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)));
0b4e3aa0
A
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 };
1c79356b
A
381 hfsmp->hfs_unknownpermissions = ((mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) != 0);
382 namefix = permfix = 0;
383
9bccf70c 384 /* Change the timezone (Note: this affects all hfs volumes and hfs+ volume create dates) */
1c79356b
A
385 if (args->hfs_timezone.tz_minuteswest != VNOVAL) {
386 gTimeZone = args->hfs_timezone;
387 }
388
9bccf70c 389 /* Change the default uid, gid and/or mask */
1c79356b
A
390 if ((args->hfs_uid != (uid_t)VNOVAL) && (hfsmp->hfs_uid != args->hfs_uid)) {
391 hfsmp->hfs_uid = args->hfs_uid;
9bccf70c
A
392 if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
393 ++permfix;
1c79356b
A
394 }
395 if ((args->hfs_gid != (gid_t)VNOVAL) && (hfsmp->hfs_gid != args->hfs_gid)) {
396 hfsmp->hfs_gid = args->hfs_gid;
9bccf70c
A
397 if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
398 ++permfix;
1c79356b
A
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);
9bccf70c
A
406 if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
407 ++permfix;
1c79356b
A
408 }
409 }
410
9bccf70c 411 /* Change the hfs encoding value (hfs only) */
1c79356b
A
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);
9bccf70c
A
417 if (retval)
418 goto exit;
1c79356b
A
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;
9bccf70c
A
431 old_encoding = hfsmp->hfs_encoding;
432 hfsmp->hfs_encoding = args->hfs_encoding;
1c79356b
A
433 ++namefix;
434 }
435
9bccf70c
A
436 if (!(namefix || permfix || permswitch))
437 goto exit;
1c79356b
A
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);
446loop:
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
9bccf70c 470 cp = VTOC(vp);
1c79356b 471
9bccf70c 472 retval = cat_lookup(hfsmp, &cp->c_desc, 0, &cndesc, &cnattr, NULL);
1c79356b
A
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
9bccf70c
A
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 }
1c79356b
A
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);
9bccf70c 495 replace_desc(cp, &cndesc);
1c79356b 496
9bccf70c
A
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);
1c79356b 503 }
1c79356b
A
504 vput(vp);
505 simple_lock(&mntvnode_slock);
506
9bccf70c
A
507 } /* end for (vp...) */
508 simple_unlock(&mntvnode_slock);
1c79356b
A
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) {
1c79356b 515 hfsmp->hfs_get_hfsname = get_hfsname_func;
1c79356b 516 vcb->volumeNameEncodingHint = args->hfs_encoding;
1c79356b
A
517 (void) hfs_relconverter(old_encoding);
518 }
9bccf70c 519exit:
1c79356b
A
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:
9bccf70c
A
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.
1c79356b 537 */
9bccf70c 538static int
1c79356b
A
539hfs_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;
9bccf70c 545 struct cnode *cp;
1c79356b 546 struct buf *bp;
d52fe63f
A
547 int sectorsize;
548 int error, i;
1c79356b
A
549 struct hfsmount *hfsmp;
550 struct HFSPlusVolumeHeader *vhp;
551 ExtendedVCB *vcb;
9bccf70c
A
552 struct filefork *forkp;
553 struct cat_desc cndesc;
1c79356b
A
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
9bccf70c
A
572loop:
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
1c79356b
A
623 /*
624 * Re-read VolumeHeader from disk.
625 */
d52fe63f
A
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);
1c79356b
A
631 if (error) {
632 if (bp != NULL)
633 brelse(bp);
634 return (error);
635 }
636
d52fe63f 637 vhp = (HFSPlusVolumeHeader *) (bp->b_data + HFS_PRI_OFFSET(sectorsize));
1c79356b 638
9bccf70c
A
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) {
1c79356b 643 brelse(bp);
9bccf70c 644 return (EIO);
1c79356b
A
645 }
646
9bccf70c
A
647 vcb->vcbLsMod = to_bsd_time(SWAP_BE32(vhp->modifyDate));
648 vcb->vcbAtrb = (UInt16) SWAP_BE32 (vhp->attributes); /* VCB only uses lower 16 bits */
b4c24cb9 649 vcb->vcbJinfoBlock = SWAP_BE32(vhp->journalInfoBlock);
9bccf70c
A
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);
1c79356b 656 vcb->nextAllocation = SWAP_BE32 (vhp->nextAllocation);
9bccf70c
A
657 vcb->totalBlocks = SWAP_BE32 (vhp->totalBlocks);
658 vcb->freeBlocks = SWAP_BE32 (vhp->freeBlocks);
1c79356b
A
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 */
9bccf70c
A
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);
1c79356b
A
700
701 brelse(bp);
702 vhp = NULL;
703
704 /*
705 * Re-load B-tree header data
706 */
9bccf70c
A
707 forkp = VTOF((struct vnode *)vcb->extentsRefNum);
708 if (error = MacToVFSError( BTReloadData((FCB*)forkp) ))
1c79356b
A
709 return (error);
710
9bccf70c
A
711 forkp = VTOF((struct vnode *)vcb->catalogRefNum);
712 if (error = MacToVFSError( BTReloadData((FCB*)forkp) ))
1c79356b
A
713 return (error);
714
9bccf70c
A
715 /* Reload the volume name */
716 if ((error = cat_idlookup(hfsmp, kHFSRootFolderID, &cndesc, NULL, NULL)))
1c79356b 717 return (error);
9bccf70c
A
718 vcb->volumeNameEncodingHint = cndesc.cd_encoding;
719 bcopy(cndesc.cd_nameptr, vcb->vcbVN, min(255, cndesc.cd_namelen));
720 cat_releasedesc(&cndesc);
1c79356b
A
721
722 /* Re-establish private/hidden directory for unlinked files */
723 hfsmp->hfs_private_metadata_dir = FindMetaDataDirectory(vcb);
724
1c79356b
A
725 return (0);
726}
727
728
b4c24cb9
A
729static int
730get_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
1c79356b
A
807/*
808 * Common code for mount and mountroot
809 */
9bccf70c
A
810static int
811hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p,
812 struct hfs_mount_args *args)
1c79356b 813{
9bccf70c
A
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;
d52fe63f
A
823 u_int64_t disksize;
824 u_int64_t blkcnt;
825 u_int32_t blksize;
826 u_int32_t minblksize;
9bccf70c 827 u_int32_t iswritable;
b4c24cb9 828 daddr_t mdb_offset;
1c79356b 829
9bccf70c
A
830 dev = devvp->v_rdev;
831 cred = p ? p->p_ucred : NOCRED;
832 mntwrapper = 0;
1c79356b
A
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;
1c79356b
A
847 if ((retval = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p)))
848 return (retval);
849
d52fe63f
A
850 bp = NULL;
851 hfsmp = NULL;
9bccf70c 852 mdbp = NULL;
d52fe63f 853 minblksize = kHFSBlockSize;
1c79356b 854
d52fe63f
A
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;
1c79356b 876
d52fe63f 877 /*
9bccf70c
A
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.
1c79356b 881 */
d52fe63f
A
882 if (blkcnt > (u_int64_t)0x000000007fffffff) {
883 minblksize = blksize = 4096;
884 }
d52fe63f
A
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
1c79356b 903 */
1c79356b
A
904 devvp->v_specsize = blksize;
905
0b4e3aa0
A
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
b4c24cb9 913 mdb_offset = HFS_PRI_SECTOR(blksize);
d52fe63f
A
914 if ((retval = meta_bread(devvp, HFS_PRI_SECTOR(blksize), blksize, cred, &bp))) {
915 goto error_exit;
916 }
9bccf70c
A
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;
1c79356b 921
d52fe63f
A
922 MALLOC(hfsmp, struct hfsmount *, sizeof(struct hfsmount), M_HFSMNT, M_WAITOK);
923 bzero(hfsmp, sizeof(struct hfsmount));
1c79356b
A
924
925 simple_lock_init(&hfsmp->hfs_renamelock);
b4c24cb9 926
9bccf70c
A
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
1c79356b
A
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? */
9bccf70c
A
958 }
959 if ((args->flags != (int)VNOVAL) && (args->flags & HFSFSMNT_WRAPPER))
960 mntwrapper = 1;
1c79356b
A
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? */
9bccf70c
A
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 }
1c79356b 978
d52fe63f
A
979 /* Mount a standard HFS disk */
980 if ((SWAP_BE16(mdbp->drSigWord) == kHFSSigWord) &&
9bccf70c 981 (mntwrapper || (SWAP_BE16(mdbp->drEmbedSigWord) != kHFSPlusSigWord))) {
d52fe63f
A
982 if (devvp == rootvp) {
983 retval = EINVAL; /* Cannot root from HFS standard disks */
1c79356b 984 goto error_exit;
d52fe63f
A
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 }
d52fe63f
A
997 devvp->v_specsize = blksize;
998 hfsmp->hfs_phys_block_size = blksize;
999 hfsmp->hfs_phys_block_count = blkcnt;
1000 }
1c79356b
A
1001 if (args) {
1002 hfsmp->hfs_encoding = args->hfs_encoding;
1003 HFSTOVCB(hfsmp)->volumeNameEncodingHint = args->hfs_encoding;
1004
1c79356b
A
1005 /* establish the timezone */
1006 gTimeZone = args->hfs_timezone;
1007 }
1008
9bccf70c
A
1009 retval = hfs_getconverter(hfsmp->hfs_encoding, &hfsmp->hfs_get_unicode,
1010 &hfsmp->hfs_get_hfsname);
d52fe63f
A
1011 if (retval)
1012 goto error_exit;
1c79356b 1013
d52fe63f 1014 retval = hfs_MountHFSVolume(hfsmp, mdbp, p);
1c79356b
A
1015 if (retval)
1016 (void) hfs_relconverter(hfsmp->hfs_encoding);
1017
d52fe63f
A
1018 } else /* Mount an HFS Plus disk */ {
1019 HFSPlusVolumeHeader *vhp;
1020 off_t embeddedOffset;
b4c24cb9 1021 int jnl_disable = 0;
d52fe63f
A
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
d52fe63f
A
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
9bccf70c
A
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
b4c24cb9
A
1063 mdb_offset = (embeddedOffset / blksize) + HFS_PRI_SECTOR(blksize);
1064 retval = meta_bread(devvp, mdb_offset, blksize, cred, &bp);
d52fe63f
A
1065 if (retval)
1066 goto error_exit;
9bccf70c
A
1067 bcopy(bp->b_data + HFS_PRI_OFFSET(blksize), mdbp, 512);
1068 brelse(bp);
1069 bp = NULL;
1070 vhp = (HFSPlusVolumeHeader*) mdbp;
d52fe63f
A
1071
1072 } else /* pure HFS+ */ {
1073 embeddedOffset = 0;
1074 vhp = (HFSPlusVolumeHeader*) mdbp;
1075 }
1076
b4c24cb9
A
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
d52fe63f
A
1110 (void) hfs_getconverter(0, &hfsmp->hfs_get_unicode, &hfsmp->hfs_get_hfsname);
1111
b4c24cb9 1112 retval = hfs_MountHFSPlusVolume(hfsmp, vhp, embeddedOffset, disksize, p, args);
d52fe63f
A
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 }
d52fe63f
A
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... */
b4c24cb9 1135 retval = hfs_MountHFSPlusVolume(hfsmp, vhp, embeddedOffset, disksize, p, args);
d52fe63f
A
1136 }
1137 if (retval)
1138 (void) hfs_relconverter(0);
1139 }
1c79356b
A
1140
1141 if ( retval ) {
1142 goto error_exit;
1143 }
1144
9bccf70c
A
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;
1c79356b 1149
9bccf70c
A
1150 if (ronly == 0) {
1151 (void) hfs_flushvolumeheader(hfsmp, MNT_WAIT, 0);
1152 }
1153 FREE(mdbp, M_TEMP);
1154 return (0);
1c79356b 1155
9bccf70c
A
1156error_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);
b4c24cb9
A
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 }
9bccf70c
A
1166 if (hfsmp) {
1167 FREE(hfsmp, M_HFSMNT);
1168 mp->mnt_data = (qaddr_t)0;
1169 }
1c79356b
A
1170 return (retval);
1171}
1172
1173
1174/*
1175 * Make a filesystem operational.
1176 * Nothing to do at the moment.
1177 */
1178/* ARGSUSED */
9bccf70c
A
1179static int
1180hfs_start(mp, flags, p)
1181 struct mount *mp;
1182 int flags;
1183 struct proc *p;
1c79356b 1184{
9bccf70c 1185 return (0);
1c79356b
A
1186}
1187
1188
1189/*
1190 * unmount system call
1191 */
9bccf70c 1192static int
1c79356b
A
1193hfs_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;
9bccf70c 1201 int force;
b4c24cb9 1202 int started_tr = 0, grabbed_lock = 0;
1c79356b
A
1203
1204 flags = 0;
9bccf70c
A
1205 force = 0;
1206 if (mntflags & MNT_FORCE) {
1c79356b 1207 flags |= FORCECLOSE;
9bccf70c
A
1208 force = 1;
1209 }
1c79356b 1210
9bccf70c 1211 if ((retval = hfs_flushfiles(mp, flags, p)) && !force)
1c79356b
A
1212 return (retval);
1213
1214 /*
1215 * Flush out the b-trees, volume bitmap and Volume Header
1216 */
1217 if (hfsmp->hfs_fs_ronly == 0) {
b4c24cb9
A
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
1c79356b 1225 retval = VOP_FSYNC(HFSTOVCB(hfsmp)->catalogRefNum, NOCRED, MNT_WAIT, p);
9bccf70c 1226 if (retval && !force)
b4c24cb9
A
1227 goto err_exit;
1228
1c79356b 1229 retval = VOP_FSYNC(HFSTOVCB(hfsmp)->extentsRefNum, NOCRED, MNT_WAIT, p);
9bccf70c 1230 if (retval && !force)
b4c24cb9
A
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 }
1c79356b
A
1241
1242 if (retval = VOP_FSYNC(hfsmp->hfs_devvp, NOCRED, MNT_WAIT, p)) {
9bccf70c 1243 if (!force)
b4c24cb9 1244 goto err_exit;
1c79356b
A
1245 }
1246
1247 /* See if this volume is damaged, is so do not unmount cleanly */
1248 if (HFSTOVCB(hfsmp)->vcbFlags & kHFS_DamagedVolume) {
1c79356b
A
1249 HFSTOVCB(hfsmp)->vcbAtrb &= ~kHFSVolumeUnmountedMask;
1250 } else {
9bccf70c 1251 HFSTOVCB(hfsmp)->vcbAtrb |= kHFSVolumeUnmountedMask;
1c79356b 1252 }
9bccf70c 1253
b4c24cb9 1254 retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT, 1);
1c79356b 1255 if (retval) {
1c79356b 1256 HFSTOVCB(hfsmp)->vcbAtrb &= ~kHFSVolumeUnmountedMask;
9bccf70c 1257 if (!force)
b4c24cb9
A
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;
1c79356b
A
1268 }
1269 }
1270
b4c24cb9
A
1271 if (hfsmp->jnl) {
1272 journal_flush(hfsmp->jnl);
1273 }
1274
1c79356b
A
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
b4c24cb9
A
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
1c79356b 1296 hfsmp->hfs_devvp->v_specflags &= ~SI_MOUNTEDON;
9bccf70c
A
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);
1c79356b 1302
9bccf70c 1303 vrele(hfsmp->hfs_devvp);
1c79356b
A
1304 FREE(hfsmp, M_HFSMNT);
1305 mp->mnt_data = (qaddr_t)0;
9bccf70c 1306 return (0);
b4c24cb9
A
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;
1c79356b
A
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 */
9bccf70c
A
1324static int
1325hfs_root(mp, vpp)
1326 struct mount *mp;
1327 struct vnode **vpp;
1c79356b 1328{
9bccf70c
A
1329 struct vnode *nvp;
1330 int retval;
1331 UInt32 rootObjID = kRootDirID;
1c79356b 1332
9bccf70c
A
1333 if ((retval = VFS_VGET(mp, &rootObjID, &nvp)))
1334 return (retval);
1c79356b 1335
9bccf70c
A
1336 *vpp = nvp;
1337 return (0);
1c79356b
A
1338}
1339
1340
1341/*
1342 * Do operations associated with quotas
1343 */
9bccf70c
A
1344int
1345hfs_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;
1c79356b 1351{
9bccf70c
A
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) {
1c79356b 1381
9bccf70c
A
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 */
1c79356b
A
1417}
1418
1419
b4c24cb9
A
1420
1421
1c79356b
A
1422/*
1423 * Get file system statistics.
1424 */
1425static int
1426hfs_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
1c79356b
A
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;
9bccf70c
A
1440 sbp->f_bfree = hfs_freeblks(hfsmp, 0);
1441 sbp->f_bavail = hfs_freeblks(hfsmp, 1);
1c79356b 1442 sbp->f_files = vcb->totalBlocks - 2; /* max files is constrained by total blocks */
9bccf70c 1443 sbp->f_ffree = MIN(freeCNIDs, sbp->f_bavail);
1c79356b
A
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
b4c24cb9
A
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__
1466void
1467hfs_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
1c79356b
A
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 */
9bccf70c
A
1528static int
1529hfs_sync(mp, waitfor, cred, p)
1530 struct mount *mp;
1531 int waitfor;
1532 struct ucred *cred;
1533 struct proc *p;
1c79356b 1534{
9bccf70c
A
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;
1c79356b
A
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
9bccf70c
A
1550 hfsmp = VFSTOHFS(mp);
1551 if (hfsmp->hfs_fs_ronly != 0) {
1552 panic("update: rofs mod");
1553 };
1c79356b 1554
b4c24cb9
A
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
9bccf70c
A
1566 /*
1567 * Write back each 'modified' vnode
1568 */
1c79356b 1569
9bccf70c
A
1570loop:
1571 simple_lock(&mntvnode_slock);
1572 for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
0b4e3aa0 1573 int didhold;
9bccf70c
A
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 }
b4c24cb9 1582
9bccf70c
A
1583 simple_lock(&vp->v_interlock);
1584 nvp = vp->v_mntvnodes.le_next;
b4c24cb9 1585
9bccf70c
A
1586 cp = VTOC(vp);
1587
b4c24cb9
A
1588 // restart our whole search if this guy is locked
1589 // or being reclaimed.
1590 if (cp == NULL || vp->v_flag & (VXLOCK|VORECLAIM)) {
1591 simple_unlock(&vp->v_interlock);
1592 continue;
1593 }
1594
9bccf70c
A
1595 if ((vp->v_flag & VSYSTEM) || (vp->v_type == VNON) ||
1596 (((cp->c_flag & (C_ACCESS | C_CHANGE | C_MODIFIED | C_UPDATE)) == 0) &&
1597 (vp->v_dirtyblkhd.lh_first == NULL) && !(vp->v_flag & VHASDIRTY))) {
1598 simple_unlock(&vp->v_interlock);
1599 simple_unlock(&mntvnode_slock);
1600 simple_lock(&mntvnode_slock);
1601 continue;
1602 }
1603
1604 simple_unlock(&mntvnode_slock);
1605 error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p);
1606 if (error) {
1607 if (error == ENOENT)
1608 goto loop;
1609 simple_lock(&mntvnode_slock);
1610 continue;
1611 }
1c79356b 1612
0b4e3aa0 1613 didhold = ubc_hold(vp);
9bccf70c
A
1614 if ((error = VOP_FSYNC(vp, cred, waitfor, p))) {
1615 allerror = error;
1616 };
1617 VOP_UNLOCK(vp, 0, p);
0b4e3aa0
A
1618 if (didhold)
1619 ubc_rele(vp);
9bccf70c
A
1620 vrele(vp);
1621 simple_lock(&mntvnode_slock);
1622 };
1c79356b 1623
9bccf70c
A
1624 vcb = HFSTOVCB(hfsmp);
1625
1626 meta_vp[0] = vcb->extentsRefNum;
1627 meta_vp[1] = vcb->catalogRefNum;
1628 meta_vp[2] = vcb->allocationsRefNum; /* This is NULL for standard HFS */
1629
1630 /* Now sync our three metadata files */
1631 for (i = 0; i < 3; ++i) {
1632 struct vnode *btvp;
1633
1634 btvp = btvp = meta_vp[i];;
1635 if ((btvp==0) || (btvp->v_type == VNON) || (btvp->v_mount != mp))
1636 continue;
b4c24cb9 1637
9bccf70c
A
1638 simple_lock(&btvp->v_interlock);
1639 cp = VTOC(btvp);
1640 if (((cp->c_flag & (C_ACCESS | C_CHANGE | C_MODIFIED | C_UPDATE)) == 0) &&
1641 (btvp->v_dirtyblkhd.lh_first == NULL) && !(btvp->v_flag & VHASDIRTY)) {
1642 simple_unlock(&btvp->v_interlock);
1643 continue;
1644 }
1645 simple_unlock(&mntvnode_slock);
1646 error = vget(btvp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p);
1647 if (error) {
1648 simple_lock(&mntvnode_slock);
1649 continue;
1650 }
1651 if ((error = VOP_FSYNC(btvp, cred, waitfor, p)))
1652 allerror = error;
1653 VOP_UNLOCK(btvp, 0, p);
1654 vrele(btvp);
1655 simple_lock(&mntvnode_slock);
1656 };
1657
1658 simple_unlock(&mntvnode_slock);
1659
1660 /*
1661 * Force stale file system control information to be flushed.
1662 */
1663 if (vcb->vcbSigWord == kHFSSigWord) {
1664 if ((error = VOP_FSYNC(hfsmp->hfs_devvp, cred, waitfor, p)))
1665 allerror = error;
1666 }
1667#if QUOTA
1668 hfs_qsync(mp);
1669#endif /* QUOTA */
1670 /*
1671 * Write back modified superblock.
1672 */
1673
1674 if (IsVCBDirty(vcb)) {
b4c24cb9
A
1675 // XXXdbg - debugging, remove
1676 if (hfsmp->jnl) {
1677 //printf("hfs: sync: strange, a journaled volume w/dirty VCB? jnl 0x%x hfsmp 0x%x\n",
1678 // hfsmp->jnl, hfsmp);
1679 }
1680
9bccf70c 1681 error = hfs_flushvolumeheader(hfsmp, waitfor, 0);
b4c24cb9
A
1682 if (error)
1683 allerror = error;
9bccf70c 1684 }
1c79356b 1685
b4c24cb9
A
1686 if (hfsmp->jnl) {
1687 journal_flush(hfsmp->jnl);
1688 }
1689
1690 err_exit:
9bccf70c 1691 return (allerror);
1c79356b
A
1692}
1693
1694
1695/*
1696 * File handle to vnode
1697 *
1698 * Have to be really careful about stale file handles:
9bccf70c
A
1699 * - check that the cnode id is valid
1700 * - call hfs_vget() to get the locked cnode
1701 * - check for an unallocated cnode (i_mode == 0)
1c79356b
A
1702 * - check that the given client host has export rights and return
1703 * those rights via. exflagsp and credanonp
1704 */
9bccf70c 1705static int
1c79356b 1706hfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
9bccf70c
A
1707 register struct mount *mp;
1708 struct fid *fhp;
1709 struct mbuf *nam;
1710 struct vnode **vpp;
1711 int *exflagsp;
1712 struct ucred **credanonp;
1c79356b
A
1713{
1714 struct hfsfid *hfsfhp;
1715 struct vnode *nvp;
1716 int result;
1717 struct netcred *np;
1c79356b
A
1718
1719 *vpp = NULL;
1720 hfsfhp = (struct hfsfid *)fhp;
1721
1722 /*
1723 * Get the export permission structure for this <mp, client> tuple.
1724 */
1725 np = vfs_export_lookup(mp, &VFSTOHFS(mp)->hfs_export, nam);
1726 if (np == NULL) {
1727 return EACCES;
1728 };
1729
1730 result = VFS_VGET(mp, &hfsfhp->hfsfid_cnid, &nvp);
1731 if (result) return result;
1732 if (nvp == NULL) return ESTALE;
1733
0b4e3aa0
A
1734 /* The createtime can be changed by hfs_setattr or hfs_setattrlist.
1735 * For NFS, we are assuming that only if the createtime was moved
1736 * forward would it mean the fileID got reused in that session by
1737 * wrapping. We don't have a volume ID or other unique identifier to
1738 * to use here for a generation ID across reboots, crashes where
1739 * metadata noting lastFileID didn't make it to disk but client has
1740 * it, or volume erasures where fileIDs start over again. Lastly,
1741 * with HFS allowing "wraps" of fileIDs now, this becomes more
1742 * error prone. Future, would be change the "wrap bit" to a unique
1743 * wrap number and use that for generation number. For now do this.
1744 */
9bccf70c 1745 if ((hfsfhp->hfsfid_gen < VTOC(nvp)->c_itime)) {
1c79356b 1746 vput(nvp);
9bccf70c 1747 return (ESTALE);
1c79356b
A
1748 };
1749
1750 *vpp = nvp;
1751 *exflagsp = np->netc_exflags;
1752 *credanonp = &np->netc_anon;
1753
9bccf70c 1754 return (0);
1c79356b
A
1755}
1756
1757
1758/*
1759 * Vnode pointer to File handle
1760 */
1761/* ARGSUSED */
9bccf70c
A
1762static int
1763hfs_vptofh(vp, fhp)
1764 struct vnode *vp;
1765 struct fid *fhp;
1c79356b 1766{
9bccf70c 1767 struct cnode *cp;
1c79356b 1768 struct hfsfid *hfsfhp;
1c79356b 1769
9bccf70c
A
1770 if (ISHFS(VTOVCB(vp)))
1771 return (EOPNOTSUPP); /* hfs standard is not exportable */
1c79356b 1772
9bccf70c
A
1773 cp = VTOC(vp);
1774 hfsfhp = (struct hfsfid *)fhp;
1c79356b
A
1775 hfsfhp->hfsfid_len = sizeof(struct hfsfid);
1776 hfsfhp->hfsfid_pad = 0;
9bccf70c
A
1777 hfsfhp->hfsfid_cnid = cp->c_cnid;
1778 hfsfhp->hfsfid_gen = cp->c_itime;
1c79356b 1779
9bccf70c 1780 return (0);
1c79356b
A
1781}
1782
1783
1784/*
1785 * Initial HFS filesystems, done only once.
1786 */
9bccf70c 1787static int
1c79356b 1788hfs_init(vfsp)
9bccf70c 1789 struct vfsconf *vfsp;
1c79356b 1790{
9bccf70c 1791 static int done = 0;
1c79356b 1792
9bccf70c
A
1793 if (done)
1794 return (0);
1795 done = 1;
1796 hfs_chashinit();
1797 hfs_converterinit();
1798#if QUOTA
1799 dqinit();
1800#endif /* QUOTA */
1c79356b 1801
1c79356b
A
1802 /*
1803 * Allocate Catalog Iterator cache...
1804 */
9bccf70c 1805 (void) InitCatalogCache();
1c79356b 1806
9bccf70c 1807 return (0);
1c79356b
A
1808}
1809
1810
b4c24cb9
A
1811// XXXdbg
1812#include <sys/filedesc.h>
1813
1814
1c79356b 1815/*
9bccf70c 1816 * HFS filesystem related variables.
1c79356b 1817 */
9bccf70c
A
1818static int
1819hfs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
1820 int *name;
1821 u_int namelen;
1822 void *oldp;
1823 size_t *oldlenp;
1824 void *newp;
1825 size_t newlen;
1826 struct proc *p;
1c79356b 1827{
9bccf70c
A
1828 extern u_int32_t hfs_encodingbias;
1829
1830 /* all sysctl names at this level are terminal */
1c79356b 1831
9bccf70c
A
1832 if (name[0] == HFS_ENCODINGBIAS)
1833 return (sysctl_int(oldp, oldlenp, newp, newlen,
1834 &hfs_encodingbias));
b4c24cb9
A
1835 else if (name[0] == 0x082969) {
1836 // make the file system journaled...
1837 struct vnode *vp = p->p_fd->fd_cdir, *jvp;
1838 struct hfsmount *hfsmp;
1839 ExtendedVCB *vcb;
1840 int retval;
1841 struct cat_attr jnl_attr, jinfo_attr;
1842 struct cat_fork jnl_fork, jinfo_fork;
1843 void *jnl = NULL;
1844
1845 hfsmp = VTOHFS(vp);
1846 if (hfsmp->hfs_fs_ronly) {
1847 return EROFS;
1848 }
1849 if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord) {
1850 printf("hfs: can't make a plain hfs volume journaled.\n");
1851 return EINVAL;
1852 }
1853
1854 if (hfsmp->jnl) {
1855 printf("hfs: volume @ mp 0x%x is already journaled!\n", vp->v_mount);
1856 return EAGAIN;
1857 }
1858
1859 vcb = HFSTOVCB(hfsmp);
1860 if (BTHasContiguousNodes(VTOF(vcb->catalogRefNum)) == 0 ||
1861 BTHasContiguousNodes(VTOF(vcb->extentsRefNum)) == 0) {
1862
1863 printf("hfs: volume has a btree w/non-contiguous nodes. can not enable journaling.\n");
1864 return EINVAL;
1865 }
1866
1867 // make sure these both exist!
1868 if ( GetFileInfo(vcb, kRootDirID, ".journal_info_block", &jinfo_attr, &jinfo_fork) == 0
1869 || GetFileInfo(vcb, kRootDirID, ".journal", &jnl_attr, &jnl_fork) == 0) {
1870
1871 return EINVAL;
1872 }
1873
1874 hfs_sync(hfsmp->hfs_mp, MNT_WAIT, FSCRED, p);
1875 bflushq(BQ_META);
1876
1877 printf("hfs: Initializing the journal (joffset 0x%llx sz 0x%llx)...\n",
1878 (off_t)name[2], (off_t)name[3]);
1879
1880 jvp = hfsmp->hfs_devvp;
1881 jnl = journal_create(jvp,
1882 (off_t)name[2] * (off_t)HFSTOVCB(hfsmp)->blockSize
1883 + HFSTOVCB(hfsmp)->hfsPlusIOPosOffset,
1884 (off_t)name[3],
1885 hfsmp->hfs_devvp,
1886 hfsmp->hfs_phys_block_size,
1887 0,
1888 0,
1889 hfs_sync_metadata, hfsmp->hfs_mp);
1890
1891 if (jnl == NULL) {
1892 printf("hfs: FAILED to create the journal!\n");
1893 if (jvp && jvp != hfsmp->hfs_devvp) {
1894 VOP_CLOSE(jvp, hfsmp->hfs_fs_ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
1895 }
1896 jvp = NULL;
1897
1898 return EINVAL;
1899 }
1900
1901 hfs_global_exclusive_lock_acquire(hfsmp);
1902
1903 HFSTOVCB(hfsmp)->vcbJinfoBlock = name[1];
1904 HFSTOVCB(hfsmp)->vcbAtrb |= kHFSVolumeJournaledMask;
1905 hfsmp->jvp = jvp;
1906 hfsmp->jnl = jnl;
1907
1908 // save this off for the hack-y check in hfs_remove()
1909 hfsmp->jnl_start = (u_int32_t)name[2];
1910 hfsmp->hfs_jnlinfoblkid = jinfo_attr.ca_fileid;
1911 hfsmp->hfs_jnlfileid = jnl_attr.ca_fileid;
1912
1913 hfsmp->hfs_mp->mnt_flag |= MNT_JOURNALED;
1914
1915 hfs_global_exclusive_lock_release(hfsmp);
1916 hfs_flushvolumeheader(hfsmp, MNT_WAIT, 1);
1917
1918 return 0;
1919 } else if (name[0] == 0x031272) {
1920 // clear the journaling bit
1921 struct vnode *vp = p->p_fd->fd_cdir;
1922 struct hfsmount *hfsmp;
1923 void *jnl;
1924 int retval;
1925
1926 hfsmp = VTOHFS(vp);
1927 if (hfsmp->jnl == NULL) {
1928 return EINVAL;
1929 }
1930
1931 printf("hfs: disabling journaling for mount @ 0x%x\n", vp->v_mount);
1932
1933 jnl = hfsmp->jnl;
1934
1935 hfs_global_exclusive_lock_acquire(hfsmp);
1936
1937 // Lights out for you buddy!
1938 hfsmp->jnl = NULL;
1939 journal_close(jnl);
1940
1941 if (hfsmp->jvp && hfsmp->jvp != hfsmp->hfs_devvp) {
1942 VOP_CLOSE(hfsmp->jvp, hfsmp->hfs_fs_ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
1943 }
1944 hfsmp->jnl = NULL;
1945 hfsmp->jvp = NULL;
1946 hfsmp->hfs_mp->mnt_flag &= ~MNT_JOURNALED;
1947 hfsmp->jnl_start = 0;
1948 hfsmp->hfs_jnlinfoblkid = 0;
1949 hfsmp->hfs_jnlfileid = 0;
1950
1951 HFSTOVCB(hfsmp)->vcbAtrb &= ~kHFSVolumeJournaledMask;
1952
1953 hfs_global_exclusive_lock_release(hfsmp);
1954 hfs_flushvolumeheader(hfsmp, MNT_WAIT, 1);
1955
1956 return 0;
1957 }
9bccf70c
A
1958
1959 return (EOPNOTSUPP);
1c79356b
A
1960}
1961
1962
1963/* This will return a vnode of either a directory or a data vnode based on an object id. If
1964 * it is a file id, its data fork will be returned.
1965 */
9bccf70c
A
1966static int
1967hfs_vget(mp, ino, vpp)
1968 struct mount *mp;
1969 void *ino;
1970 struct vnode **vpp;
1971{
1972 cnid_t cnid = *(cnid_t *)ino;
1973
1974 /* Check for cnids that should't be exported. */
1975 if ((cnid < kHFSFirstUserCatalogNodeID)
1976 && (cnid != kHFSRootFolderID && cnid != kHFSRootParentID))
1977 return (ENOENT);
1978 /* Don't export HFS Private Data dir. */
1979 if (cnid == VFSTOHFS(mp)->hfs_privdir_desc.cd_cnid)
1980 return (ENOENT);
1981
1982 return (hfs_getcnode(VFSTOHFS(mp), cnid, NULL, 0, NULL, NULL, vpp));
1983}
1984
1985/*
1986 * Flush out all the files in a filesystem.
1987 */
1c79356b 1988int
9bccf70c 1989hfs_flushfiles(struct mount *mp, int flags, struct proc *p)
1c79356b 1990{
9bccf70c
A
1991 register struct hfsmount *hfsmp;
1992 int i;
1993 int error;
1c79356b 1994
9bccf70c
A
1995#if QUOTA
1996 hfsmp = VFSTOHFS(mp);
1c79356b 1997
9bccf70c
A
1998 if (mp->mnt_flag & MNT_QUOTA) {
1999 if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags))
2000 return (error);
2001 for (i = 0; i < MAXQUOTAS; i++) {
2002 if (hfsmp->hfs_qfiles[i].qf_vp == NULLVP)
2003 continue;
2004 hfs_quotaoff(p, mp, i);
2005 }
2006 /*
2007 * Here we fall through to vflush again to ensure
2008 * that we have gotten rid of all the system vnodes.
2009 */
1c79356b 2010 }
9bccf70c 2011#endif /* QUOTA */
1c79356b 2012
9bccf70c
A
2013 error = vflush(mp, NULLVP, (SKIPSYSTEM | SKIPSWAP | flags));
2014 error = vflush(mp, NULLVP, (SKIPSYSTEM | flags));
1c79356b 2015
9bccf70c
A
2016 return (error);
2017}
1c79356b 2018
9bccf70c
A
2019/*
2020 * Update volume encoding bitmap (HFS Plus only)
2021 */
2022__private_extern__
2023void
2024hfs_setencodingbits(struct hfsmount *hfsmp, u_int32_t encoding)
2025{
2026#define kIndexMacUkrainian 48 /* MacUkrainian encoding is 152 */
2027#define kIndexMacFarsi 49 /* MacFarsi encoding is 140 */
2028
2029 UInt32 index;
2030
2031 switch (encoding) {
2032 case kTextEncodingMacUkrainian:
2033 index = kIndexMacUkrainian;
2034 break;
2035 case kTextEncodingMacFarsi:
2036 index = kIndexMacFarsi;
2037 break;
2038 default:
2039 index = encoding;
2040 break;
2041 }
1c79356b 2042
9bccf70c
A
2043 if (index < 128) {
2044 HFSTOVCB(hfsmp)->encodingsBitmap |= (1 << index);
2045 HFSTOVCB(hfsmp)->vcbFlags |= 0xFF00;
2046 }
1c79356b
A
2047}
2048
2049/*
9bccf70c 2050 * Update volume stats
1c79356b 2051 */
9bccf70c 2052__private_extern__
1c79356b 2053int
9bccf70c 2054hfs_volupdate(struct hfsmount *hfsmp, enum volop op, int inroot)
1c79356b 2055{
9bccf70c 2056 ExtendedVCB *vcb;
1c79356b 2057
9bccf70c
A
2058 vcb = HFSTOVCB(hfsmp);
2059 vcb->vcbFlags |= 0xFF00;
2060 vcb->vcbLsMod = time.tv_sec;
2061
2062 switch (op) {
2063 case VOL_UPDATE:
2064 break;
2065 case VOL_MKDIR:
2066 if (vcb->vcbDirCnt != 0xFFFFFFFF)
2067 ++vcb->vcbDirCnt;
2068 if (inroot && vcb->vcbNmRtDirs != 0xFFFF)
2069 ++vcb->vcbNmRtDirs;
2070 break;
2071 case VOL_RMDIR:
2072 if (vcb->vcbDirCnt != 0)
2073 --vcb->vcbDirCnt;
2074 if (inroot && vcb->vcbNmRtDirs != 0xFFFF)
2075 --vcb->vcbNmRtDirs;
2076 break;
2077 case VOL_MKFILE:
2078 if (vcb->vcbFilCnt != 0xFFFFFFFF)
2079 ++vcb->vcbFilCnt;
2080 if (inroot && vcb->vcbNmFls != 0xFFFF)
2081 ++vcb->vcbNmFls;
2082 break;
2083 case VOL_RMFILE:
2084 if (vcb->vcbFilCnt != 0)
2085 --vcb->vcbFilCnt;
2086 if (inroot && vcb->vcbNmFls != 0xFFFF)
2087 --vcb->vcbNmFls;
2088 break;
2089 }
b4c24cb9
A
2090
2091 if (hfsmp->jnl) {
2092 hfs_flushvolumeheader(hfsmp, 0, 0);
2093 }
2094
9bccf70c 2095 return (0);
1c79356b
A
2096}
2097
9bccf70c
A
2098
2099static int
2100hfs_flushMDB(struct hfsmount *hfsmp, int waitfor, int altflush)
1c79356b 2101{
9bccf70c
A
2102 ExtendedVCB *vcb = HFSTOVCB(hfsmp);
2103 struct filefork *fp;
1c79356b 2104 HFSMasterDirectoryBlock *mdb;
9bccf70c
A
2105 struct buf *bp = NULL;
2106 int retval;
2107 int sectorsize;
2108 ByteCount namelen;
1c79356b 2109
9bccf70c 2110 sectorsize = hfsmp->hfs_phys_block_size;
9bccf70c 2111 retval = bread(hfsmp->hfs_devvp, HFS_PRI_SECTOR(sectorsize), sectorsize, NOCRED, &bp);
1c79356b 2112 if (retval) {
9bccf70c
A
2113 if (bp)
2114 brelse(bp);
1c79356b
A
2115 return retval;
2116 }
2117
9bccf70c
A
2118 DBG_ASSERT(bp != NULL);
2119 DBG_ASSERT(bp->b_data != NULL);
2120 DBG_ASSERT(bp->b_bcount == size);
1c79356b 2121
b4c24cb9
A
2122 if (hfsmp->jnl) {
2123 panic("hfs: standard hfs volumes should not be journaled!\n");
2124 }
2125
9bccf70c 2126 mdb = (HFSMasterDirectoryBlock *)(bp->b_data + HFS_PRI_OFFSET(sectorsize));
1c79356b 2127
9bccf70c
A
2128 mdb->drCrDate = SWAP_BE32 (UTCToLocal(to_hfs_time(vcb->vcbCrDate)));
2129 mdb->drLsMod = SWAP_BE32 (UTCToLocal(to_hfs_time(vcb->vcbLsMod)));
2130 mdb->drAtrb = SWAP_BE16 (vcb->vcbAtrb);
1c79356b
A
2131 mdb->drNmFls = SWAP_BE16 (vcb->vcbNmFls);
2132 mdb->drAllocPtr = SWAP_BE16 (vcb->nextAllocation);
2133 mdb->drClpSiz = SWAP_BE32 (vcb->vcbClpSiz);
2134 mdb->drNxtCNID = SWAP_BE32 (vcb->vcbNxtCNID);
2135 mdb->drFreeBks = SWAP_BE16 (vcb->freeBlocks);
2136
2137 namelen = strlen(vcb->vcbVN);
2138 retval = utf8_to_hfs(vcb, namelen, vcb->vcbVN, mdb->drVN);
2139 /* Retry with MacRoman in case that's how it was exported. */
2140 if (retval)
2141 retval = utf8_to_mac_roman(namelen, vcb->vcbVN, mdb->drVN);
2142
9bccf70c 2143 mdb->drVolBkUp = SWAP_BE32 (UTCToLocal(to_hfs_time(vcb->vcbVolBkUp)));
1c79356b
A
2144 mdb->drWrCnt = SWAP_BE32 (vcb->vcbWrCnt);
2145 mdb->drNmRtDirs = SWAP_BE16 (vcb->vcbNmRtDirs);
2146 mdb->drFilCnt = SWAP_BE32 (vcb->vcbFilCnt);
2147 mdb->drDirCnt = SWAP_BE32 (vcb->vcbDirCnt);
2148
2149 bcopy(vcb->vcbFndrInfo, mdb->drFndrInfo, sizeof(mdb->drFndrInfo));
2150
9bccf70c
A
2151 fp = VTOF(vcb->extentsRefNum);
2152 mdb->drXTExtRec[0].startBlock = SWAP_BE16 (fp->ff_extents[0].startBlock);
2153 mdb->drXTExtRec[0].blockCount = SWAP_BE16 (fp->ff_extents[0].blockCount);
2154 mdb->drXTExtRec[1].startBlock = SWAP_BE16 (fp->ff_extents[1].startBlock);
2155 mdb->drXTExtRec[1].blockCount = SWAP_BE16 (fp->ff_extents[1].blockCount);
2156 mdb->drXTExtRec[2].startBlock = SWAP_BE16 (fp->ff_extents[2].startBlock);
2157 mdb->drXTExtRec[2].blockCount = SWAP_BE16 (fp->ff_extents[2].blockCount);
2158 mdb->drXTFlSize = SWAP_BE32 (fp->ff_blocks * vcb->blockSize);
2159 mdb->drXTClpSiz = SWAP_BE32 (fp->ff_clumpsize);
1c79356b 2160
9bccf70c
A
2161 fp = VTOF(vcb->catalogRefNum);
2162 mdb->drCTExtRec[0].startBlock = SWAP_BE16 (fp->ff_extents[0].startBlock);
2163 mdb->drCTExtRec[0].blockCount = SWAP_BE16 (fp->ff_extents[0].blockCount);
2164 mdb->drCTExtRec[1].startBlock = SWAP_BE16 (fp->ff_extents[1].startBlock);
2165 mdb->drCTExtRec[1].blockCount = SWAP_BE16 (fp->ff_extents[1].blockCount);
2166 mdb->drCTExtRec[2].startBlock = SWAP_BE16 (fp->ff_extents[2].startBlock);
2167 mdb->drCTExtRec[2].blockCount = SWAP_BE16 (fp->ff_extents[2].blockCount);
2168 mdb->drCTFlSize = SWAP_BE32 (fp->ff_blocks * vcb->blockSize);
2169 mdb->drCTClpSiz = SWAP_BE32 (fp->ff_clumpsize);
2170
2171 /* If requested, flush out the alternate MDB */
2172 if (altflush) {
2173 struct buf *alt_bp = NULL;
2174 u_long altIDSector;
2175
2176 altIDSector = HFS_ALT_SECTOR(sectorsize, hfsmp->hfs_phys_block_count);
2177
2178 if (meta_bread(hfsmp->hfs_devvp, altIDSector, sectorsize, NOCRED, &alt_bp) == 0) {
2179 bcopy(mdb, alt_bp->b_data + HFS_ALT_OFFSET(sectorsize), kMDBSize);
b4c24cb9 2180
9bccf70c
A
2181 (void) VOP_BWRITE(alt_bp);
2182 } else if (alt_bp)
2183 brelse(alt_bp);
2184 }
1c79356b 2185
9bccf70c 2186 if (waitfor != MNT_WAIT)
1c79356b 2187 bawrite(bp);
b4c24cb9 2188 else
1c79356b
A
2189 retval = VOP_BWRITE(bp);
2190
2191 MarkVCBClean( vcb );
2192
2193 return (retval);
2194}
2195
2196
9bccf70c
A
2197__private_extern__
2198int
2199hfs_flushvolumeheader(struct hfsmount *hfsmp, int waitfor, int altflush)
1c79356b 2200{
9bccf70c
A
2201 ExtendedVCB *vcb = HFSTOVCB(hfsmp);
2202 struct filefork *fp;
2203 HFSPlusVolumeHeader *volumeHeader;
2204 int retval;
2205 struct buf *bp;
2206 int i;
d52fe63f
A
2207 int sectorsize;
2208 int priIDSector;
9bccf70c 2209 int critical = 0;
1c79356b 2210
9bccf70c
A
2211 if (vcb->vcbSigWord == kHFSSigWord)
2212 return hfs_flushMDB(hfsmp, waitfor, altflush);
1c79356b 2213
9bccf70c
A
2214 if (altflush)
2215 critical = 1;
d52fe63f
A
2216 sectorsize = hfsmp->hfs_phys_block_size;
2217 priIDSector = (vcb->hfsPlusIOPosOffset / sectorsize) +
2218 HFS_PRI_SECTOR(sectorsize);
2219
b4c24cb9
A
2220 // XXXdbg
2221 hfs_global_shared_lock_acquire(hfsmp);
2222 if (hfsmp->jnl) {
2223 if (journal_start_transaction(hfsmp->jnl) != 0) {
2224 hfs_global_shared_lock_release(hfsmp);
2225 return EINVAL;
2226 }
2227 }
2228
d52fe63f 2229 retval = meta_bread(hfsmp->hfs_devvp, priIDSector, sectorsize, NOCRED, &bp);
1c79356b 2230 if (retval) {
9bccf70c
A
2231 if (bp)
2232 brelse(bp);
b4c24cb9
A
2233
2234 if (hfsmp->jnl) {
2235 journal_end_transaction(hfsmp->jnl);
2236 }
2237 hfs_global_shared_lock_release(hfsmp);
2238
9bccf70c 2239 return (retval);
1c79356b
A
2240 }
2241
b4c24cb9
A
2242 if (hfsmp->jnl) {
2243 journal_modify_block_start(hfsmp->jnl, bp);
2244 }
2245
d52fe63f 2246 volumeHeader = (HFSPlusVolumeHeader *)((char *)bp->b_data + HFS_PRI_OFFSET(sectorsize));
1c79356b
A
2247
2248 /*
2249 * For embedded HFS+ volumes, update create date if it changed
2250 * (ie from a setattrlist call)
2251 */
9bccf70c
A
2252 if ((vcb->hfsPlusIOPosOffset != 0) &&
2253 (SWAP_BE32 (volumeHeader->createDate) != vcb->localCreateDate)) {
2254 struct buf *bp2;
1c79356b
A
2255 HFSMasterDirectoryBlock *mdb;
2256
9bccf70c
A
2257 retval = meta_bread(hfsmp->hfs_devvp, HFS_PRI_SECTOR(sectorsize),
2258 sectorsize, NOCRED, &bp2);
2259 if (retval) {
2260 if (bp2)
2261 brelse(bp2);
2262 retval = 0;
1c79356b 2263 } else {
9bccf70c
A
2264 mdb = (HFSMasterDirectoryBlock *)(bp2->b_data +
2265 HFS_PRI_OFFSET(sectorsize));
1c79356b
A
2266
2267 if ( SWAP_BE32 (mdb->drCrDate) != vcb->localCreateDate )
2268 {
b4c24cb9
A
2269 // XXXdbg
2270 if (hfsmp->jnl) {
2271 journal_modify_block_start(hfsmp->jnl, bp2);
2272 }
2273
1c79356b
A
2274 mdb->drCrDate = SWAP_BE32 (vcb->localCreateDate); /* pick up the new create date */
2275
b4c24cb9
A
2276 // XXXdbg
2277 if (hfsmp->jnl) {
2278 journal_modify_block_end(hfsmp->jnl, bp2);
2279 } else {
2280 (void) VOP_BWRITE(bp2); /* write out the changes */
2281 }
1c79356b
A
2282 }
2283 else
2284 {
2285 brelse(bp2); /* just release it */
2286 }
2287 }
9bccf70c 2288 }
1c79356b 2289
b4c24cb9
A
2290// XXXdbg - only monkey around with the volume signature on non-root volumes
2291//
2292#if 0
2293 if (hfsmp->jnl &&
2294 hfsmp->hfs_fs_ronly == 0 &&
2295 (HFSTOVFS(hfsmp)->mnt_flag & MNT_ROOTFS) == 0) {
2296
2297 int old_sig = volumeHeader->signature;
2298
2299 if (vcb->vcbAtrb & kHFSVolumeUnmountedMask) {
2300 volumeHeader->signature = kHFSPlusSigWord;
2301 } else {
2302 volumeHeader->signature = kHFSJSigWord;
2303 }
2304
2305 if (old_sig != volumeHeader->signature) {
2306 altflush = 1;
2307 }
2308 }
2309#endif
2310// XXXdbg
2311
1c79356b 2312 /* Note: only update the lower 16 bits worth of attributes */
9bccf70c 2313 volumeHeader->attributes = SWAP_BE32 ((SWAP_BE32 (volumeHeader->attributes) & 0xFFFF0000) + (UInt16) vcb->vcbAtrb);
b4c24cb9
A
2314 volumeHeader->journalInfoBlock = SWAP_BE32(vcb->vcbJinfoBlock);
2315 if (hfsmp->jnl) {
2316 volumeHeader->lastMountedVersion = SWAP_BE32 (kHFSJMountVersion);
2317 } else {
2318 volumeHeader->lastMountedVersion = SWAP_BE32 (kHFSPlusMountVersion);
2319 }
9bccf70c
A
2320 volumeHeader->createDate = SWAP_BE32 (vcb->localCreateDate); /* volume create date is in local time */
2321 volumeHeader->modifyDate = SWAP_BE32 (to_hfs_time(vcb->vcbLsMod));
2322 volumeHeader->backupDate = SWAP_BE32 (to_hfs_time(vcb->vcbVolBkUp));
2323 volumeHeader->fileCount = SWAP_BE32 (vcb->vcbFilCnt);
2324 volumeHeader->folderCount = SWAP_BE32 (vcb->vcbDirCnt);
2325 volumeHeader->freeBlocks = SWAP_BE32 (vcb->freeBlocks);
2326 volumeHeader->nextAllocation = SWAP_BE32 (vcb->nextAllocation);
2327 volumeHeader->rsrcClumpSize = SWAP_BE32 (vcb->vcbClpSiz);
2328 volumeHeader->dataClumpSize = SWAP_BE32 (vcb->vcbClpSiz);
2329 volumeHeader->nextCatalogID = SWAP_BE32 (vcb->vcbNxtCNID);
2330 volumeHeader->writeCount = SWAP_BE32 (vcb->vcbWrCnt);
2331 volumeHeader->encodingsBitmap = SWAP_BE64 (vcb->encodingsBitmap);
2332
2333 if (bcmp(vcb->vcbFndrInfo, volumeHeader->finderInfo, sizeof(volumeHeader->finderInfo)) != 0)
2334 critical = 1;
2335 bcopy(vcb->vcbFndrInfo, volumeHeader->finderInfo, sizeof(volumeHeader->finderInfo));
2336
2337 /* Sync Extents over-flow file meta data */
2338 fp = VTOF(vcb->extentsRefNum);
2339 for (i = 0; i < kHFSPlusExtentDensity; i++) {
2340 volumeHeader->extentsFile.extents[i].startBlock =
2341 SWAP_BE32 (fp->ff_extents[i].startBlock);
2342 volumeHeader->extentsFile.extents[i].blockCount =
2343 SWAP_BE32 (fp->ff_extents[i].blockCount);
2344 }
2345 FTOC(fp)->c_flag &= ~C_MODIFIED;
2346 volumeHeader->extentsFile.logicalSize = SWAP_BE64 (fp->ff_size);
2347 volumeHeader->extentsFile.totalBlocks = SWAP_BE32 (fp->ff_blocks);
2348 volumeHeader->extentsFile.clumpSize = SWAP_BE32 (fp->ff_clumpsize);
2349
2350 /* Sync Catalog file meta data */
2351 fp = VTOF(vcb->catalogRefNum);
2352 for (i = 0; i < kHFSPlusExtentDensity; i++) {
2353 volumeHeader->catalogFile.extents[i].startBlock =
2354 SWAP_BE32 (fp->ff_extents[i].startBlock);
2355 volumeHeader->catalogFile.extents[i].blockCount =
2356 SWAP_BE32 (fp->ff_extents[i].blockCount);
2357 }
2358 FTOC(fp)->c_flag &= ~C_MODIFIED;
2359 volumeHeader->catalogFile.logicalSize = SWAP_BE64 (fp->ff_size);
2360 volumeHeader->catalogFile.totalBlocks = SWAP_BE32 (fp->ff_blocks);
2361 volumeHeader->catalogFile.clumpSize = SWAP_BE32 (fp->ff_clumpsize);
2362
2363 /* Sync Allocation file meta data */
2364 fp = VTOF(vcb->allocationsRefNum);
2365 for (i = 0; i < kHFSPlusExtentDensity; i++) {
2366 volumeHeader->allocationFile.extents[i].startBlock =
2367 SWAP_BE32 (fp->ff_extents[i].startBlock);
2368 volumeHeader->allocationFile.extents[i].blockCount =
2369 SWAP_BE32 (fp->ff_extents[i].blockCount);
2370 }
2371 FTOC(fp)->c_flag &= ~C_MODIFIED;
2372 volumeHeader->allocationFile.logicalSize = SWAP_BE64 (fp->ff_size);
2373 volumeHeader->allocationFile.totalBlocks = SWAP_BE32 (fp->ff_blocks);
2374 volumeHeader->allocationFile.clumpSize = SWAP_BE32 (fp->ff_clumpsize);
2375
2376 /* If requested, flush out the alternate volume header */
2377 if (altflush) {
2378 struct buf *alt_bp = NULL;
2379 u_long altIDSector;
2380
2381 altIDSector = (vcb->hfsPlusIOPosOffset / sectorsize) +
2382 HFS_ALT_SECTOR(sectorsize, hfsmp->hfs_phys_block_count);
2383
2384 if (meta_bread(hfsmp->hfs_devvp, altIDSector, sectorsize, NOCRED, &alt_bp) == 0) {
b4c24cb9
A
2385 if (hfsmp->jnl) {
2386 journal_modify_block_start(hfsmp->jnl, alt_bp);
2387 }
2388
9bccf70c 2389 bcopy(volumeHeader, alt_bp->b_data + HFS_ALT_OFFSET(sectorsize), kMDBSize);
b4c24cb9
A
2390
2391 if (hfsmp->jnl) {
2392 journal_modify_block_end(hfsmp->jnl, alt_bp);
2393 } else {
2394 (void) VOP_BWRITE(alt_bp);
2395 }
9bccf70c
A
2396 } else if (alt_bp)
2397 brelse(alt_bp);
2398 }
2399
b4c24cb9
A
2400 // XXXdbg
2401 if (hfsmp->jnl) {
2402 journal_modify_block_end(hfsmp->jnl, bp);
2403 journal_end_transaction(hfsmp->jnl);
2404 } else {
2405 if (waitfor != MNT_WAIT)
2406 bawrite(bp);
2407 else {
2408 retval = VOP_BWRITE(bp);
2409 /* When critical data changes, flush the device cache */
2410 if (critical && (retval == 0)) {
9bccf70c 2411 (void) VOP_IOCTL(hfsmp->hfs_devvp, DKIOCSYNCHRONIZECACHE,
b4c24cb9
A
2412 NULL, FWRITE, NOCRED, current_proc());
2413 }
9bccf70c
A
2414 }
2415 }
b4c24cb9 2416 hfs_global_shared_lock_release(hfsmp);
1c79356b 2417
9bccf70c 2418 vcb->vcbFlags &= 0x00FF;
1c79356b
A
2419 return (retval);
2420}
2421
2422
1c79356b
A
2423/*
2424 * hfs vfs operations.
2425 */
2426struct vfsops hfs_vfsops = {
9bccf70c
A
2427 hfs_mount,
2428 hfs_start,
2429 hfs_unmount,
2430 hfs_root,
2431 hfs_quotactl,
2432 hfs_statfs,
2433 hfs_sync,
2434 hfs_vget,
2435 hfs_fhtovp,
2436 hfs_vptofh,
2437 hfs_init,
2438 hfs_sysctl
1c79356b 2439};