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