]> git.saurik.com Git - apple/xnu.git/blame - bsd/hfs/hfs_vfsops.c
xnu-201.tar.gz
[apple/xnu.git] / bsd / hfs / hfs_vfsops.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 1999-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 * Copyright (c) 1991, 1993, 1994
24 * The Regents of the University of California. All rights reserved.
25 * (c) UNIX System Laboratories, Inc.
26 * All or some portions of this file are derived from material licensed
27 * to the University of California by American Telephone and Telegraph
28 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
29 * the permission of UNIX System Laboratories, Inc.
30 *
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
33 * are met:
34 * 1. Redistributions of source code must retain the above copyright
35 * notice, this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright
37 * notice, this list of conditions and the following disclaimer in the
38 * documentation and/or other materials provided with the distribution.
39 * 3. All advertising materials mentioning features or use of this software
40 * must display the following acknowledgement:
41 * This product includes software developed by the University of
42 * California, Berkeley and its contributors.
43 * 4. Neither the name of the University nor the names of its contributors
44 * may be used to endorse or promote products derived from this software
45 * without specific prior written permission.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 * SUCH DAMAGE.
58 *
59 * hfs_vfsops.c
60 * derived from @(#)ufs_vfsops.c 8.8 (Berkeley) 5/20/95
61 *
62 * (c) Copyright 1997-1998 Apple Computer, Inc. All rights reserved.
63 *
64 * hfs_vfsops.c -- VFS layer for loadable HFS file system.
65 *
66 * HISTORY
67 * 9-Nov-1999 Don Brady Fix error handling in hfs_unmount [2399157].
68 * 9-Sep-1999 Don Brady Clear system file fcbModified flags in hfs_flushvolumeheader/hfs_flushMDB.
69 * 5-Aug-1999 Pat Dirks Moved special HFS flag from f_fsid.val[0][0] to mount flags (#2293117).
70 * 23-Jul-1999 Pat Dirks Added special-case code for root's parent directory in hfs_vget (#2263664).
71 * 9-Jun-1999 Don Brady Fix hfs_mount for reload and read-only downgrade cases.
72 * 2-Jun-1999 Don Brady Fix hfs_statfs to return correct f_files value.
73 * 4-May-1999 Don Brady Remove obsolete loadable module code.
74 * 22-Mar-1999 Don Brady Hide our private meta data in hfs_vget.
75 * 18-May-1999 Don Brady Add hfs_mountroot for HFS Plus rooting.
76 * 22-Mar-1999 Don Brady Hide our private meta data in hfs_vget.
77 * 12-Nov-1998 Pat Dirks Changed hfs_statfs to return volume's actual log. block size (#2286198).
78 * 22-Aug-1998 Scott Roberts Assign uid,gid, and mask for default on objects.
79 * 29-Jul-1998 Pat Dirks Fixed changed hfs_vget() to release complex node when retrying for data fork node.
80 * 27-Jul-1998 Scott Roberts Changes hfs_vget() to return data forks instead of complex.
81 * 14-Jul-1998 CHW Added check for use count of device node in hfs_mountfs
82 * 1-Jul-1998 Don Brady Always set kHFSVolumeUnmountedMask bit of vcb->vcbAtrb in hfs_unmount.
83 * 30-Jun-1998 Don Brady Removed hard-coded EINVAL error in hfs_mountfs (for radar #2249539).
84 * 24-Jun-1998 Don Brady Added setting of timezone to hfs_mount (radar #2226387).
85 * 4-Jun-1998 Don Brady Use VPUT/VRELE macros instead of vput/vrele.
86 * 6-May-1998 Scott Roberts Updated hfs_vget with kernel changes.
87 * 29-Apr-1998 Don Brady Update hfs_statfs to actually fill in statfs fields (radar #2227092).
88 * 23-Apr-1998 Pat Dirks Cleaned up code to call brelse() on errors from bread().
89 * 4/20/1998 Don Brady Remove course-grained hfs metadata locking.
90 * 4/18/1998 Don Brady Add VCB locking.
91 * 4/16/1998 Don Brady hfs_unmount now flushes the volume bitmap. Add b-tree locking to hfs_vget.
92 * 4/8/1998 Don Brady Replace hfs_mdbupdate with hfs_flushvolumeheader and hfs_flushMDB.
93 * 4/8/1998 Don Brady In hfs_unmount call hfs_mdbupdate before trashing metafiles!
94 * 4/3/1998 Don Brady Call InitCatalogCache instead of PostInitFS.
95 * 4/1/1998 Don Brady Get rid of gHFSFlags, gReqstVol and gFlushOnlyFlag globals (not used).
96 * 3/30/1998 Don Brady In hfs_unmount use SKIPSYSTEM option on first vflush.
97 * 3/26/1998 Don Brady Changed hfs_unmount to call vflush before calling hfsUnmount.
98 * In hfs_mountfs don't mount hfs-wrapper.
99 * 3/19/1998 Pat Dirks Fixed bug in hfs_mount where device vnode was being
100 * released on way out.
101 * 11/14/1997 Pat Dirks Derived from hfs_vfsops.c
102 */
103#include <sys/param.h>
104#include <sys/systm.h>
105
106#include <sys/ubc.h>
107#include <sys/namei.h>
108#include <sys/vnode.h>
109#include <sys/mount.h>
110#include <sys/malloc.h>
111#include <sys/stat.h>
112#include <dev/disk.h>
113#include <sys/lock.h>
114#include <miscfs/specfs/specdev.h>
115#include <hfs/hfs_mount.h>
116
117#include "hfs.h"
118#include "hfs_dbg.h"
119#include "hfs_endian.h"
120
121#include "hfscommon/headers/FileMgrInternal.h"
122#include "hfscommon/headers/BTreesInternal.h"
123
124#if HFS_DIAGNOSTIC
125int hfs_dbg_all = 0;
126int hfs_dbg_vfs = 0;
127int hfs_dbg_vop = 0;
128int hfs_dbg_load = 0;
129int hfs_dbg_io = 0;
130int hfs_dbg_utils = 0;
131int hfs_dbg_rw = 0;
132int hfs_dbg_lookup = 0;
133int hfs_dbg_tree = 0;
134int hfs_dbg_err = 0;
135int hfs_dbg_test = 0;
136#endif
137
138/*
139 * HFS File System globals:
140 */
141Ptr gBufferAddress[BUFFERPTRLISTSIZE];
142struct buf *gBufferHeaderPtr[BUFFERPTRLISTSIZE];
143int gBufferListIndex;
144simple_lock_data_t gBufferPtrListLock;
145
146//static char hfs_fs_name[MFSNAMELEN] = "hfs";
147
1c79356b
A
148
149/*
150 * Global variables defined in other modules:
151 */
152extern struct vnodeopv_desc hfs_vnodeop_opv_desc;
153
154extern struct vnode *hfs_vhashget(dev_t dev, UInt32 nodeID, UInt8 forkType);
155
156extern OSErr HFSPlusToHFSExtents( const HFSPlusExtentRecord oldExtents, HFSExtentRecord newExtents);
157
158
159extern void inittodr( time_t base);
160extern OSErr GetVolumeNameFromCatalog(ExtendedVCB *vcb);
161extern void CopyCatalogToObjectMeta(struct hfsCatalogInfo *catInfo, struct vnode *vp, struct hfsfilemeta *fm);
162extern void CopyCatalogToFCB(struct hfsCatalogInfo *catInfo, struct vnode *vp);
163extern void hfs_name_CatToMeta(CatalogNodeData *nodeData, struct hfsfilemeta *fm);
164
165int hfs_changefs(struct mount *mp, struct hfs_mount_args *args, struct proc *p);
166
167int hfs_reload(struct mount *mp, struct ucred *cred, struct proc *p);
168int hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p, struct hfs_mount_args *args);
169int hfs_vget(struct mount *mp, void *objID, struct vnode **vpp);
170void hfs_vhashinit();
171void hfs_converterinit(void);
172
173
174static int hfs_statfs();
175
176
177/*
178 * Called by vfs_mountroot when mounting HFS Plus as root.
179 */
180int
181hfs_mountroot()
182{
183 extern struct vnode *rootvp;
184 struct mount *mp;
185 struct proc *p = current_proc(); /* XXX */
186 struct hfsmount *hfsmp;
187 int error;
188
189 /*
190 * Get vnode for rootdev.
191 */
192 if ((error = bdevvp(rootdev, &rootvp))) {
193 printf("hfs_mountroot: can't setup bdevvp");
194 return (error);
195 }
196 if ((error = vfs_rootmountalloc("hfs", "root_device", &mp)))
197 return (error);
198 if ((error = hfs_mountfs(rootvp, mp, p, NULL))) {
199 mp->mnt_vfc->vfc_refcount--;
200 vfs_unbusy(mp, p);
201 _FREE_ZONE(mp, sizeof (struct mount), M_MOUNT);
202 return (error);
203 }
204 simple_lock(&mountlist_slock);
205 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
206 simple_unlock(&mountlist_slock);
207
208 /* Init hfsmp */
209 hfsmp = VFSTOHFS(mp);
210
0b4e3aa0
A
211 hfsmp->hfs_uid = UNKNOWNUID;
212 hfsmp->hfs_gid = UNKNOWNGID;
213 hfsmp->hfs_dir_mask = (S_IRWXU | S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH); /* 0755 */
214 hfsmp->hfs_file_mask = (S_IRWXU | S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH); /* 0755 */
1c79356b
A
215
216 (void)hfs_statfs(mp, &mp->mnt_stat, p);
217
218 vfs_unbusy(mp, p);
219 inittodr(to_bsd_time(HFSTOVCB(hfsmp)->vcbLsMod));
220 return (0);
221}
222
223
224/*
225 * VFS Operations.
226 *
227 * mount system call
228 */
229
230int
231hfs_mount (mp, path, data, ndp, p)
232 register struct mount *mp;
233 char *path;
234 caddr_t data;
235 struct nameidata *ndp;
236 struct proc *p;
237{
238 struct hfsmount *hfsmp = NULL;
239 struct vnode *devvp;
240 struct hfs_mount_args args;
241 size_t size;
242 int retval = E_NONE;
243 int flags;
244 mode_t accessmode;
245 int loadconv = 0;
246
247 if ((retval = copyin(data, (caddr_t)&args, sizeof(args))))
248 goto error_exit;
249
250 /*
251 * If updating, check whether changing from read-only to
252 * read/write; if there is no device name, that's all we do.
253 */
254 if (mp->mnt_flag & MNT_UPDATE) {
0b4e3aa0 255
1c79356b
A
256 hfsmp = VFSTOHFS(mp);
257 if ((hfsmp->hfs_fs_ronly == 0) && (mp->mnt_flag & MNT_RDONLY)) {
258
259 /* use VFS_SYNC to push out System (btree) files */
260 retval = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p);
261 if (retval && ((mp->mnt_flag & MNT_FORCE) == 0))
262 goto error_exit;
263
264 flags = WRITECLOSE;
265 if (mp->mnt_flag & MNT_FORCE)
266 flags |= FORCECLOSE;
267
268 if ((retval = hfs_flushfiles(mp, flags)))
269 goto error_exit;
270 hfsmp->hfs_fs_clean = 1;
271 hfsmp->hfs_fs_ronly = 1;
272 if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
273 retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT);
274 else
275 retval = hfs_flushMDB(hfsmp, MNT_WAIT);
276
277 /* also get the volume bitmap blocks */
278 if (!retval)
279 retval = VOP_FSYNC(hfsmp->hfs_devvp, NOCRED, MNT_WAIT, p);
280
281 if (retval) {
282 hfsmp->hfs_fs_clean = 0;
283 hfsmp->hfs_fs_ronly = 0;
284 goto error_exit;
285 }
286 }
287
288 if ((mp->mnt_flag & MNT_RELOAD) &&
289 (retval = hfs_reload(mp, ndp->ni_cnd.cn_cred, p)))
290 goto error_exit;
291
292 if (hfsmp->hfs_fs_ronly && (mp->mnt_kern_flag & MNTK_WANTRDWR)) {
293 /*
294 * If upgrade to read-write by non-root, then verify
295 * that user has necessary permissions on the device.
296 */
297 if (p->p_ucred->cr_uid != 0) {
298 devvp = hfsmp->hfs_devvp;
299 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
300 if ((retval = VOP_ACCESS(devvp, VREAD | VWRITE, p->p_ucred, p))) {
301 VOP_UNLOCK(devvp, 0, p);
302 goto error_exit;
303 }
304 VOP_UNLOCK(devvp, 0, p);
305 }
306 if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
307 retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT);
308 else
309 retval = hfs_flushMDB(hfsmp, MNT_WAIT);
310
311 if (retval != E_NONE)
312 goto error_exit;
313
314 /* only change hfs_fs_ronly after a successfull write */
315 hfsmp->hfs_fs_ronly = 0;
316 hfsmp->hfs_fs_clean = 0;
317 }
318
319 if ((hfsmp->hfs_fs_ronly == 0) &&
320 (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)) {
321 /* setup private/hidden directory for unlinked files */
322 hfsmp->hfs_private_metadata_dir = FindMetaDataDirectory(HFSTOVCB(hfsmp));
323 }
324
325 if (args.fspec == 0) {
326 /*
327 * Process export requests.
328 */
329 return vfs_export(mp, &hfsmp->hfs_export, &args.export);
330 }
331 }
332
333 /*
334 * Not an update, or updating the name: look up the name
335 * and verify that it refers to a sensible block device.
336 */
337 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
338 retval = namei(ndp);
339 if (retval != E_NONE) {
340 DBG_ERR(("hfs_mount: CAN'T GET DEVICE: %s, %x\n", args.fspec, ndp->ni_vp->v_rdev));
341 goto error_exit;
342 }
343
344 devvp = ndp->ni_vp;
345
346 if (devvp->v_type != VBLK) {
347 vrele(devvp);
348 retval = ENOTBLK;
349 goto error_exit;
350 }
351 if (major(devvp->v_rdev) >= nblkdev) {
352 vrele(devvp);
353 retval = ENXIO;
354 goto error_exit;
355 }
356
357 /*
358 * If mount by non-root, then verify that user has necessary
359 * permissions on the device.
360 */
361 if (p->p_ucred->cr_uid != 0) {
362 accessmode = VREAD;
363 if ((mp->mnt_flag & MNT_RDONLY) == 0)
364 accessmode |= VWRITE;
365 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
366 if ((retval = VOP_ACCESS(devvp, accessmode, p->p_ucred, p))) {
367 vput(devvp);
368 goto error_exit;
369 }
370 VOP_UNLOCK(devvp, 0, p);
371 }
372
373 if ((mp->mnt_flag & MNT_UPDATE) == 0) {
374 retval = hfs_mountfs(devvp, mp, p, &args);
375 if (retval != E_NONE)
376 vrele(devvp);
377 } else {
378 if (devvp != hfsmp->hfs_devvp)
379 retval = EINVAL; /* needs translation */
380 else
381 retval = hfs_changefs(mp, &args, p);
382 vrele(devvp);
383 }
384
385 if (retval != E_NONE) {
386 goto error_exit;
387 }
388
389
390 /* Set the mount flag to indicate that we support volfs */
391 mp->mnt_flag |= MNT_DOVOLFS;
392 if (VFSTOVCB(mp)->vcbSigWord == kHFSSigWord) {
393 /* HFS volumes only want roman-encoded names: */
394 mp->mnt_flag |= MNT_FIXEDSCRIPTENCODING;
395 }
396 (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN-1, &size);
397 bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
398 (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size);
399 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
400 (void)hfs_statfs(mp, &mp->mnt_stat, p);
401 return (E_NONE);
402
403error_exit:
404
405 return (retval);
406}
407
408
409/* change fs mount parameters */
410int
411hfs_changefs(mp, args, p)
412 struct mount *mp;
413 struct hfs_mount_args *args;
414 struct proc *p;
415{
416 int retval;
417 int namefix, permfix, permswitch;
418 struct hfsmount *hfsmp;
419 struct hfsnode *hp;
420 mode_t hfs_file_mask;
421 ExtendedVCB *vcb;
422 hfsCatalogInfo catInfo;
423 register struct vnode *vp, *nvp;
424 hfs_to_unicode_func_t get_unicode_func;
425 unicode_to_hfs_func_t get_hfsname_func;
426
427 hfsmp = VFSTOHFS(mp);
428 vcb = HFSTOVCB(hfsmp);
429 permswitch = (((hfsmp->hfs_unknownpermissions != 0) && ((mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) == 0)) ||
430 ((hfsmp->hfs_unknownpermissions == 0) && ((mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) != 0)));
0b4e3aa0
A
431 /* The root filesystem must operate with actual permissions: */
432 if (permswitch && (mp->mnt_flag & MNT_ROOTFS) && (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS)) {
433 mp->mnt_flag &= ~MNT_UNKNOWNPERMISSIONS; /* Just say "No". */
434 return EINVAL;
435 };
1c79356b
A
436 hfsmp->hfs_unknownpermissions = ((mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) != 0);
437 namefix = permfix = 0;
438
439 /* change the timezone (Note: this affects all hfs volumes and hfs+ volume create dates) */
440 if (args->hfs_timezone.tz_minuteswest != VNOVAL) {
441 gTimeZone = args->hfs_timezone;
442 }
443
444 /* change the default uid, gid and/or mask */
445 if ((args->hfs_uid != (uid_t)VNOVAL) && (hfsmp->hfs_uid != args->hfs_uid)) {
446 hfsmp->hfs_uid = args->hfs_uid;
447 ++permfix;
448 }
449 if ((args->hfs_gid != (gid_t)VNOVAL) && (hfsmp->hfs_gid != args->hfs_gid)) {
450 hfsmp->hfs_gid = args->hfs_gid;
451 ++permfix;
452 }
453 if (args->hfs_mask != (mode_t)VNOVAL) {
454 if (hfsmp->hfs_dir_mask != (args->hfs_mask & ALLPERMS)) {
455 hfsmp->hfs_dir_mask = args->hfs_mask & ALLPERMS;
456 hfsmp->hfs_file_mask = args->hfs_mask & ALLPERMS;
457 if ((args->flags != VNOVAL) && (args->flags & HFSFSMNT_NOXONFILES))
458 hfsmp->hfs_file_mask = (args->hfs_mask & DEFFILEMODE);
459 ++permfix;
460 }
461 }
462
463 /* change the hfs encoding value (hfs only) */
464 if ((HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord) &&
465 (hfsmp->hfs_encoding != (u_long)VNOVAL) &&
466 (hfsmp->hfs_encoding != args->hfs_encoding)) {
467
468 retval = hfs_getconverter(args->hfs_encoding, &get_unicode_func, &get_hfsname_func);
469 if (retval) goto error_exit;
470
471 /*
472 * Connect the new hfs_get_unicode converter but leave
473 * the old hfs_get_hfsname converter in place so that
474 * we can lookup existing vnodes to get their correctly
475 * encoded names.
476 *
477 * When we're all finished, we can then connect the new
478 * hfs_get_hfsname converter and release our interest
479 * in the old converters.
480 */
481 hfsmp->hfs_get_unicode = get_unicode_func;
482 ++namefix;
483 }
484
485
486 if (!(namefix || permfix || permswitch)) goto exit;
487
488 /*
489 * For each active vnode fix things that changed
490 *
491 * Note that we can visit a vnode more than once
492 * and we can race with fsync.
493 */
494 simple_lock(&mntvnode_slock);
495loop:
496 for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
497 /*
498 * If the vnode that we are about to fix is no longer
499 * associated with this mount point, start over.
500 */
501 if (vp->v_mount != mp)
502 goto loop;
503
504 simple_lock(&vp->v_interlock);
505 nvp = vp->v_mntvnodes.le_next;
506 if (vp->v_flag & VSYSTEM) {
507 simple_unlock(&vp->v_interlock);
508 continue;
509 }
510 simple_unlock(&mntvnode_slock);
511 retval = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p);
512 if (retval) {
513 simple_lock(&mntvnode_slock);
514 if (retval == ENOENT)
515 goto loop;
516 continue;
517 }
518
519 hp = VTOH(vp);
520
521 INIT_CATALOGDATA(&catInfo.nodeData, 0);
522
523 catInfo.hint = kNoHint;
524 retval = hfs_getcatalog(vcb, H_DIRID(hp), H_NAME(hp), hp->h_meta->h_namelen, &catInfo);
525 /* If we couldn't find this guy skip to the next one */
526 if (retval) {
527 if (namefix)
528 cache_purge(vp);
529 vput(vp);
530 simple_lock(&mntvnode_slock);
531 continue;
532 }
533
534 H_HINT(hp) = catInfo.hint;
535 if (permswitch || (permfix && (hp->h_meta->h_metaflags & IN_UNSETACCESS))) {
536 if ((vcb->vcbSigWord == kHFSPlusSigWord) && (catInfo.nodeData.cnd_mode & IFMT)) {
537 if (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) {
538 /*
539 * Override the permissions as determined by the mount auguments
540 * in ALMOST the same way unset permissions are treated but keep
541 * track of whether or not the file or folder is hfs locked
542 * by leaving the h_pflags field unchanged from what was unpacked
543 * out of the catalog.
544 */
545 hp->h_meta->h_metaflags |= IN_UNSETACCESS;
546 hp->h_meta->h_uid = VTOHFS(vp)->hfs_uid;
547 hp->h_meta->h_gid = VTOHFS(vp)->hfs_gid;
548 } else {
549 hp->h_meta->h_uid = catInfo.nodeData.cnd_ownerID;
550 hp->h_meta->h_gid = catInfo.nodeData.cnd_groupID;
551 };
552 hp->h_meta->h_mode = (mode_t)catInfo.nodeData.cnd_mode;
553 } else {
554 /*
555 * Set the permissions as determined by the mount auguments
556 * but keep in account if the file or folder is hfs locked
557 */
558 hp->h_meta->h_metaflags |= IN_UNSETACCESS;
559 hp->h_meta->h_uid = VTOHFS(vp)->hfs_uid;
560 hp->h_meta->h_gid = VTOHFS(vp)->hfs_gid;
561
562 /* Default access is full read/write/execute: */
0b4e3aa0
A
563 hp->h_meta->h_mode &= IFMT;
564 hp->h_meta->h_mode |= ACCESSPERMS; /* 0777: rwxrwxrwx */
1c79356b
A
565 /* ... but no more than that permitted by the mount point's: */
566 if ((hp->h_meta->h_mode & IFMT) == IFDIR) {
0b4e3aa0 567 hp->h_meta->h_mode &= IFMT | VTOHFS(vp)->hfs_dir_mask;
1c79356b 568 } else {
0b4e3aa0 569 hp->h_meta->h_mode &= IFMT | VTOHFS(vp)->hfs_file_mask;
1c79356b
A
570 }
571 };
572 };
573
574 /*
575 * If we're switching name converters then...
576 * Remove the existing entry from the namei cache.
577 * Update name to one based on new encoder.
578 */
579 if (namefix) {
580 cache_purge(vp);
581 hfs_name_CatToMeta(&catInfo.nodeData, hp->h_meta);
582
583 if (catInfo.nodeData.cnd_nodeID == kHFSRootFolderID)
584 strncpy(vcb->vcbVN, H_NAME(hp), NAME_MAX);
585 }
586
587 CLEAN_CATALOGDATA(&catInfo.nodeData);
588
589 vput(vp);
590 simple_lock(&mntvnode_slock);
591
592 } /* end for (vp...) */
593 simple_unlock(&mntvnode_slock);
594
595
596exit:
597 /*
598 * If we're switching name converters we can now
599 * connect the new hfs_get_hfsname converter and
600 * release our interest in the old converters.
601 */
602 if (namefix) {
603 u_long old_encoding = hfsmp->hfs_encoding;
604
605 hfsmp->hfs_get_hfsname = get_hfsname_func;
606 hfsmp->hfs_encoding = args->hfs_encoding;
607 vcb->volumeNameEncodingHint = args->hfs_encoding;
608
609 (void) hfs_relconverter(old_encoding);
610 }
611
612 return (0);
613
614error_exit:
615
616 return (retval);
617}
618
619
620/*
621 * Reload all incore data for a filesystem (used after running fsck on
622 * the root filesystem and finding things to fix). The filesystem must
623 * be mounted read-only.
624 *
625 * Things to do to update the mount:
626 * 1) invalidate all cached meta-data.
627 * 2) re-read volume header from disk.
628 * 3) re-load meta-file info (extents, file size).
629 * 4) re-load B-tree header data.
630 * 5) invalidate all inactive vnodes.
631 * 6) invalidate all cached file data.
632 * 7) re-read hfsnode data for all active vnodes.
633 */
634int
635hfs_reload(mountp, cred, p)
636 register struct mount *mountp;
637 struct ucred *cred;
638 struct proc *p;
639{
640 register struct vnode *vp, *nvp, *devvp;
641 struct hfsnode *hp;
642 struct buf *bp;
643 int size, error, i;
644 struct hfsmount *hfsmp;
645 struct HFSPlusVolumeHeader *vhp;
646 ExtendedVCB *vcb;
647 FCB *fcb;
648
649 if ((mountp->mnt_flag & MNT_RDONLY) == 0)
650 return (EINVAL);
651
652 hfsmp = VFSTOHFS(mountp);
653 vcb = HFSTOVCB(hfsmp);
654
655 if (vcb->vcbSigWord == kHFSSigWord)
656 return (EINVAL); /* rooting from HFS is not supported! */
657
658 /*
659 * Invalidate all cached meta-data.
660 */
661 devvp = hfsmp->hfs_devvp;
662 if (vinvalbuf(devvp, 0, cred, p, 0, 0))
663 panic("hfs_reload: dirty1");
664 InvalidateCatalogCache(vcb);
665
666 /*
667 * Re-read VolumeHeader from disk.
668 */
669 size = kMDBSize;
670 error = bread( hfsmp->hfs_devvp,
671 IOBLKNOFORBLK((vcb->hfsPlusIOPosOffset / 512) + kMasterDirectoryBlock, size),
672 IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, size),
673 NOCRED,
674 &bp);
675 if (error) {
676 if (bp != NULL)
677 brelse(bp);
678 return (error);
679 }
680
681 vhp = (HFSPlusVolumeHeader *) ((char *)bp->b_data +
682 IOBYTEOFFSETFORBLK((vcb->hfsPlusIOPosOffset / 512) + kMasterDirectoryBlock, size));
683
684 if ((ValidVolumeHeader(vhp) != 0) || (vcb->blockSize != SWAP_BE32 (vhp->blockSize))) {
685 brelse(bp);
686 return (EIO); /* XXX needs translation */
687 }
688
689 vcb->vcbLsMod = SWAP_BE32 (vhp->modifyDate);
690 vcb->vcbAtrb = (UInt16) SWAP_BE32 (vhp->attributes); /* VCB only uses lower 16 bits */
691 vcb->vcbClpSiz = SWAP_BE32 (vhp->rsrcClumpSize);
692 vcb->vcbNxtCNID = SWAP_BE32 (vhp->nextCatalogID);
693 vcb->vcbVolBkUp = SWAP_BE32 (vhp->backupDate);
694 vcb->vcbWrCnt = SWAP_BE32 (vhp->writeCount);
695 vcb->vcbFilCnt = SWAP_BE32 (vhp->fileCount);
696 vcb->vcbDirCnt = SWAP_BE32 (vhp->folderCount);
697 vcb->nextAllocation = SWAP_BE32 (vhp->nextAllocation);
698 vcb->totalBlocks = SWAP_BE32 (vhp->totalBlocks);
699 vcb->freeBlocks = SWAP_BE32 (vhp->freeBlocks);
700 vcb->checkedDate = SWAP_BE32 (vhp->checkedDate);
701 vcb->encodingsBitmap = SWAP_BE64 (vhp->encodingsBitmap);
702 bcopy(vhp->finderInfo, vcb->vcbFndrInfo, sizeof(vhp->finderInfo));
703 vcb->localCreateDate = SWAP_BE32 (vhp->createDate); /* hfs+ create date is in local time */
704
705 /*
706 * Re-load meta-file vnode data (extent info, file size, etc).
707 */
708 fcb = VTOFCB((struct vnode *)vcb->extentsRefNum);
709 /* bcopy(vhp->extentsFile.extents, fcb->fcbExtents, sizeof(HFSPlusExtentRecord)); */
710 for (i = 0; i < kHFSPlusExtentDensity; i++) {
711 fcb->fcbExtents[i].startBlock = SWAP_BE32 (vhp->extentsFile.extents[i].startBlock);
712 fcb->fcbExtents[i].blockCount = SWAP_BE32 (vhp->extentsFile.extents[i].blockCount);
713 }
714 fcb->fcbEOF = SWAP_BE64 (vhp->extentsFile.logicalSize);
715 fcb->fcbPLen = SWAP_BE32 (vhp->extentsFile.totalBlocks) * vcb->blockSize;
716 fcb->fcbClmpSize = SWAP_BE32 (vhp->extentsFile.clumpSize);
717
718 fcb = VTOFCB((struct vnode *)vcb->catalogRefNum);
719 /* bcopy(vhp->catalogFile.extents, fcb->fcbExtents, sizeof(HFSPlusExtentRecord)); */
720 for (i = 0; i < kHFSPlusExtentDensity; i++) {
721 fcb->fcbExtents[i].startBlock = SWAP_BE32 (vhp->catalogFile.extents[i].startBlock);
722 fcb->fcbExtents[i].blockCount = SWAP_BE32 (vhp->catalogFile.extents[i].blockCount);
723 }
724 fcb->fcbPLen = SWAP_BE64 (vhp->catalogFile.logicalSize);
725 fcb->fcbPLen = SWAP_BE32 (vhp->catalogFile.totalBlocks) * vcb->blockSize;
726 fcb->fcbClmpSize = SWAP_BE32 (vhp->catalogFile.clumpSize);
727
728 fcb = VTOFCB((struct vnode *)vcb->allocationsRefNum);
729 /* bcopy(vhp->allocationFile.extents, fcb->fcbExtents, sizeof(HFSPlusExtentRecord)); */
730 for (i = 0; i < kHFSPlusExtentDensity; i++) {
731 fcb->fcbExtents[i].startBlock = SWAP_BE32 (vhp->allocationFile.extents[i].startBlock);
732 fcb->fcbExtents[i].blockCount = SWAP_BE32 (vhp->allocationFile.extents[i].blockCount);
733 }
734 fcb->fcbEOF = SWAP_BE64 (vhp->allocationFile.logicalSize);
735 fcb->fcbPLen = SWAP_BE32 (vhp->allocationFile.totalBlocks) * vcb->blockSize;
736 fcb->fcbClmpSize = SWAP_BE32 (vhp->allocationFile.clumpSize);
737
738 brelse(bp);
739 vhp = NULL;
740
741 /*
742 * Re-load B-tree header data
743 */
744 fcb = VTOFCB((struct vnode *)vcb->extentsRefNum);
745 if (error = MacToVFSError( BTReloadData(fcb) ))
746 return (error);
747
748 fcb = VTOFCB((struct vnode *)vcb->catalogRefNum);
749 if (error = MacToVFSError( BTReloadData(fcb) ))
750 return (error);
751
752 /* Now that the catalog is ready, get the volume name */
753 /* also picks up the create date in GMT */
754 if ((error = MacToVFSError( GetVolumeNameFromCatalog(vcb) )))
755 return (error);
756
757 /* Re-establish private/hidden directory for unlinked files */
758 hfsmp->hfs_private_metadata_dir = FindMetaDataDirectory(vcb);
759
760loop:
761 simple_lock(&mntvnode_slock);
762 for (vp = mountp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
763 if (vp->v_mount != mountp) {
764 simple_unlock(&mntvnode_slock);
765 goto loop;
766 }
767 nvp = vp->v_mntvnodes.le_next;
768
769 /*
770 * Invalidate all inactive vnodes.
771 */
772 if (vrecycle(vp, &mntvnode_slock, p))
773 goto loop;
774
775 /*
776 * Invalidate all cached file data.
777 */
778 simple_lock(&vp->v_interlock);
779 simple_unlock(&mntvnode_slock);
780 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) {
781 goto loop;
782 }
783 if (vinvalbuf(vp, 0, cred, p, 0, 0))
784 panic("hfs_reload: dirty2");
785
786 /*
787 * Re-read hfsnode data for all active vnodes (non-metadata files).
788 */
789 hp = VTOH(vp);
790 if ((vp->v_flag & VSYSTEM) == 0) {
791 hfsCatalogInfo catInfo;
792
793 /* lookup by fileID since name could have changed */
794 catInfo.hint = kNoHint;
795 INIT_CATALOGDATA(&catInfo.nodeData, 0);
796
797 if ((error = hfs_getcatalog(vcb, H_FILEID(hp), NULL, -1, &catInfo))) {
798 vput(vp);
799 CLEAN_CATALOGDATA(&catInfo.nodeData);
800 return (error);
801 }
802
803 H_HINT(hp) = catInfo.hint;
804 if (hp->h_meta->h_metaflags & IN_LONGNAME)
805 FREE(H_NAME(hp), M_TEMP);
806 H_NAME(hp) = NULL;
807 hp->h_meta->h_namelen = 0;
808 CopyCatalogToObjectMeta(&catInfo, vp, hp->h_meta);
809 CopyCatalogToFCB(&catInfo, vp);
810
811 CLEAN_CATALOGDATA(&catInfo.nodeData);
812 }
813
814 vput(vp);
815 simple_lock(&mntvnode_slock);
816 }
817 simple_unlock(&mntvnode_slock);
818
819 return (0);
820}
821
822
823/*
824 * Common code for mount and mountroot
825 */
826int
827hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p, struct hfs_mount_args *args)
828{
829 int retval = E_NONE;
830 register struct hfsmount *hfsmp;
831 struct buf *bp;
832 dev_t dev;
833 HFSMasterDirectoryBlock *mdbp;
834 int ronly;
835 struct ucred *cred;
836 u_long diskBlks;
837 u_long blksize;
838 DBG_VFS(("hfs_mountfs: mp = 0x%lX\n", (u_long)mp));
839
840 dev = devvp->v_rdev;
841 cred = p ? p->p_ucred : NOCRED;
842 /*
843 * Disallow multiple mounts of the same device.
844 * Disallow mounting of a device that is currently in use
845 * (except for root, which might share swap device for miniroot).
846 * Flush out any old buffers remaining from a previous use.
847 */
848 if ((retval = vfs_mountedon(devvp)))
849 return (retval);
850 if ((vcount(devvp) > 1) && (devvp != rootvp))
851 return (EBUSY);
852 if ((retval = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0)))
853 return (retval);
854
855 ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
856 DBG_VFS(("hfs_mountfs: opening device...\n"));
857 if ((retval = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p)))
858 return (retval);
859
860 blksize = kHFSBlockSize;
861 DBG_VFS(("hfs_mountfs: size = %d (DEV_BSIZE = %d).\n", blksize, DEV_BSIZE));
862
863 bp = NULL;
864 hfsmp = NULL;
865
866 /*
867 * XXX SER Currently we only support 512 block size systems. This might change
868 * So this is a place holder to remind us that the mdb might not be 512 aligned
869 * retval = VOP_IOCTL(devvp, DKIOCGETBLOCKSIZE, &blksize, FWRITE, cred, p);
870 * if (retval) return retval;
871 */
872
873 /*
874 * the next three lines should probably be replaced
875 * with a call to the yet unimplemented function VOP_SETBLOCKSIZE
876 */
877 retval = VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE, &blksize, FWRITE, cred, p);
878 if (retval) return retval;
879 devvp->v_specsize = blksize;
880
0b4e3aa0
A
881 /* cache the IO attributes */
882 if ((retval = vfs_init_io_attributes(devvp, mp))) {
883 printf("hfs_mountfs: vfs_init_io_attributes returned %d\n",
884 retval);
885 return (retval);
886 }
887
1c79356b
A
888 DBG_VFS(("hfs_mountfs: reading MDB [block no. %d + %d bytes, size %d bytes]...\n",
889 IOBLKNOFORBLK(kMasterDirectoryBlock, blksize),
890 IOBYTEOFFSETFORBLK(kMasterDirectoryBlock, blksize),
891 IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, blksize)));
892
893 if ((retval = bread(devvp, IOBLKNOFORBLK(kMasterDirectoryBlock, blksize),
894 IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, blksize), cred, &bp))) {
895 goto error_exit;
896 };
897 mdbp = (HFSMasterDirectoryBlock*) ((char *)bp->b_data + IOBYTEOFFSETFORBLK(kMasterDirectoryBlock, blksize));
898
899 MALLOC(hfsmp, struct hfsmount *, sizeof(struct hfsmount), M_HFSMNT, M_WAITOK);
900 bzero(hfsmp, sizeof(struct hfsmount));
901
902 simple_lock_init(&hfsmp->hfs_renamelock);
903
904 DBG_VFS(("hfs_mountfs: Initializing hfsmount structure at 0x%lX...\n", (u_long)hfsmp));
905 /*
906 * Init the volume information structure
907 */
908 mp->mnt_data = (qaddr_t)hfsmp;
909 hfsmp->hfs_mp = mp; /* Make VFSTOHFS work */
910 hfsmp->hfs_vcb.vcb_hfsmp = hfsmp; /* Make VCBTOHFS work */
911 hfsmp->hfs_raw_dev = devvp->v_rdev;
912 hfsmp->hfs_devvp = devvp;
913 hfsmp->hfs_phys_block_size = blksize;
914
915 /* The hfs_log_block_size field is updated in the respective hfs_MountHFS[Plus]Volume routine */
916 hfsmp->hfs_logBlockSize = BestBlockSizeFit(SWAP_BE32 (mdbp->drAlBlkSiz), MAXBSIZE, hfsmp->hfs_phys_block_size);
917 hfsmp->hfs_fs_ronly = ronly;
918 hfsmp->hfs_unknownpermissions = ((mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) != 0);
919 if (args) {
920 hfsmp->hfs_uid = (args->hfs_uid == (uid_t)VNOVAL) ? UNKNOWNUID : args->hfs_uid;
921 if (hfsmp->hfs_uid == 0xfffffffd) hfsmp->hfs_uid = UNKNOWNUID;
922 hfsmp->hfs_gid = (args->hfs_gid == (gid_t)VNOVAL) ? UNKNOWNGID : args->hfs_gid;
923 if (hfsmp->hfs_gid == 0xfffffffd) hfsmp->hfs_gid = UNKNOWNGID;
924 if (args->hfs_mask != (mode_t)VNOVAL) {
925 hfsmp->hfs_dir_mask = args->hfs_mask & ALLPERMS;
926 if (args->flags & HFSFSMNT_NOXONFILES) {
927 hfsmp->hfs_file_mask = (args->hfs_mask & DEFFILEMODE);
928 } else {
929 hfsmp->hfs_file_mask = args->hfs_mask & ALLPERMS;
930 }
931 } else {
932 hfsmp->hfs_dir_mask = UNKNOWNPERMISSIONS & ALLPERMS; /* 0777: rwx---rwx */
933 hfsmp->hfs_file_mask = UNKNOWNPERMISSIONS & DEFFILEMODE; /* 0666: no --x by default? */
934 };
935 } else {
936 /* Even w/o explicit mount arguments, MNT_UNKNOWNPERMISSIONS requires setting up uid, gid, and mask: */
937 if (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) {
938 hfsmp->hfs_uid = UNKNOWNUID;
939 hfsmp->hfs_gid = UNKNOWNGID;
940 hfsmp->hfs_dir_mask = UNKNOWNPERMISSIONS & ALLPERMS; /* 0777: rwx---rwx */
941 hfsmp->hfs_file_mask = UNKNOWNPERMISSIONS & DEFFILEMODE; /* 0666: no --x by default? */
942 };
943 };
944
945 /* See above comment for DKIOCGETBLOCKSIZE
946 * retval = VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE, &blksize, FWRITE, cred, p);
947 * if (retval) return retval;
948 */
949
950 retval = VOP_IOCTL(devvp, DKIOCNUMBLKS, (caddr_t)&diskBlks, 0, cred, p);
951 if (retval) return retval;
952
953 if (SWAP_BE16 (mdbp->drSigWord) == kHFSPlusSigWord) {
954 /* Enidan swap volume header in place */
955 /* SWAP_HFS_PLUS_VOLUME_HEADER ((HFSPlusVolumeHeader *)bp->b_data); */
956
957 /* mount wrapper-less HFS-Plus volume */
958 (void) hfs_getconverter(0, &hfsmp->hfs_get_unicode, &hfsmp->hfs_get_hfsname);
959 retval = hfs_MountHFSPlusVolume(hfsmp, (HFSPlusVolumeHeader*) bp->b_data, 0, diskBlks, p);
960
961 /* Enidan un-swap volume header in place */
962 /* SWAP_HFS_PLUS_VOLUME_HEADER ((HFSPlusVolumeHeader *)bp->b_data); */
963
964 } else if (SWAP_BE16 (mdbp->drEmbedSigWord) == kHFSPlusSigWord) {
965 u_long embBlkOffset;
966 HFSPlusVolumeHeader *vhp;
967
968 embBlkOffset = SWAP_BE16 (mdbp->drAlBlSt) +
969 (SWAP_BE16 (mdbp->drEmbedExtent.startBlock) * (SWAP_BE32 (mdbp->drAlBlkSiz)/kHFSBlockSize));
970 /* calculate virtual number of 512-byte sectors */
971 diskBlks = SWAP_BE16 (mdbp->drEmbedExtent.blockCount) * (SWAP_BE32 (mdbp->drAlBlkSiz)/kHFSBlockSize);
972
973 brelse(bp);
974 bp = NULL; /* done with MDB, go grab Volume Header */
975 mdbp = NULL;
976
977 retval = bread( devvp,
978 IOBLKNOFORBLK(kMasterDirectoryBlock+embBlkOffset, blksize),
979 IOBYTECCNTFORBLK(kMasterDirectoryBlock+embBlkOffset, kMDBSize, blksize),
980 cred,
981 &bp);
982 if (retval) {
983 goto error_exit;
984 };
985 vhp = (HFSPlusVolumeHeader*) ((char *)bp->b_data + IOBYTEOFFSETFORBLK(kMasterDirectoryBlock, blksize));
986
987 /* Enidan swap volume header in place */
988 /* SWAP_HFS_PLUS_VOLUME_HEADER (vhp); */
989
990 /* mount embedded HFS Plus volume */
991 (void) hfs_getconverter(0, &hfsmp->hfs_get_unicode, &hfsmp->hfs_get_hfsname);
992 retval = hfs_MountHFSPlusVolume(hfsmp, vhp, embBlkOffset, diskBlks, p);
993
994 /* Enidan un-swap volume header in place */
995 /* SWAP_HFS_PLUS_VOLUME_HEADER (vhp); */
996
997 } else if (devvp != rootvp) {
998 if (args) {
999 hfsmp->hfs_encoding = args->hfs_encoding;
1000 HFSTOVCB(hfsmp)->volumeNameEncodingHint = args->hfs_encoding;
1001
1002
1003 /* establish the timezone */
1004 gTimeZone = args->hfs_timezone;
1005 }
1006
1007 retval = hfs_getconverter(hfsmp->hfs_encoding, &hfsmp->hfs_get_unicode, &hfsmp->hfs_get_hfsname);
1008 if (retval) goto error_exit;
1009
1010 /* mount HFS volume */
1011 retval = hfs_MountHFSVolume( hfsmp, mdbp, diskBlks, p);
1012
1013 if (retval)
1014 (void) hfs_relconverter(hfsmp->hfs_encoding);
1015
1016 } else {
1017 /* sorry, we cannot root from HFS */
1018 retval = EINVAL;
1019 }
1020
1021 if ( retval ) {
1022 goto error_exit;
1023 }
1024
1025 brelse(bp);
1026 bp = NULL;
1027
1028 mp->mnt_stat.f_fsid.val[0] = (long)dev;
1029 mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
1030 mp->mnt_maxsymlinklen = 0;
1031 devvp->v_specflags |= SI_MOUNTEDON;
1032
1033 if (ronly == 0) {
1034 hfsmp->hfs_fs_clean = 0;
1035 if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
1036 (void) hfs_flushvolumeheader(hfsmp, MNT_WAIT);
1037 else
1038 (void) hfs_flushMDB(hfsmp, MNT_WAIT);
1039 }
1040 goto std_exit;
1041
1042error_exit:
1043 DBG_VFS(("hfs_mountfs: exiting with error %d...\n", retval));
1044
1045 if (bp)
1046 brelse(bp);
1047 (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
1048 if (hfsmp) {
1049 FREE(hfsmp, M_HFSMNT);
1050 mp->mnt_data = (qaddr_t)0;
1051 }
1052
1053std_exit:
1054 return (retval);
1055}
1056
1057
1058/*
1059 * Make a filesystem operational.
1060 * Nothing to do at the moment.
1061 */
1062/* ARGSUSED */
1063int hfs_start(mp, flags, p)
1064struct mount *mp;
1065int flags;
1066struct proc *p;
1067{
1068 DBG_FUNC_NAME("hfs_start");
1069 DBG_PRINT_FUNC_NAME();
1070
1071 return (0);
1072}
1073
1074
1075/*
1076 * unmount system call
1077 */
1078int
1079hfs_unmount(mp, mntflags, p)
1080 struct mount *mp;
1081 int mntflags;
1082 struct proc *p;
1083{
1084 struct hfsmount *hfsmp = VFSTOHFS(mp);
1085 int retval = E_NONE;
1086 int flags;
1087
1088 flags = 0;
1089 if (mntflags & MNT_FORCE)
1090 flags |= FORCECLOSE;
1091
1092 if ((retval = hfs_flushfiles(mp, flags)))
1093 return (retval);
1094
1095 /*
1096 * Flush out the b-trees, volume bitmap and Volume Header
1097 */
1098 if (hfsmp->hfs_fs_ronly == 0) {
1099 retval = VOP_FSYNC(HFSTOVCB(hfsmp)->catalogRefNum, NOCRED, MNT_WAIT, p);
1100 if (retval && ((mntflags & MNT_FORCE) == 0))
1101 return (retval);
1102
1103 retval = VOP_FSYNC(HFSTOVCB(hfsmp)->extentsRefNum, NOCRED, MNT_WAIT, p);
1104 if (retval && ((mntflags & MNT_FORCE) == 0))
1105 return (retval);
1106
1107 if (retval = VOP_FSYNC(hfsmp->hfs_devvp, NOCRED, MNT_WAIT, p)) {
1108 if ((mntflags & MNT_FORCE) == 0)
1109 return (retval);
1110 }
1111
1112 /* See if this volume is damaged, is so do not unmount cleanly */
1113 if (HFSTOVCB(hfsmp)->vcbFlags & kHFS_DamagedVolume) {
1114 hfsmp->hfs_fs_clean = 0;
1115 HFSTOVCB(hfsmp)->vcbAtrb &= ~kHFSVolumeUnmountedMask;
1116 } else {
1117 hfsmp->hfs_fs_clean = 1;
1118 HFSTOVCB(hfsmp)->vcbAtrb |= kHFSVolumeUnmountedMask;
1119 }
1120 if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
1121 retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT);
1122 else
1123 retval = hfs_flushMDB(hfsmp, MNT_WAIT);
1124
1125 if (retval) {
1126 hfsmp->hfs_fs_clean = 0;
1127 HFSTOVCB(hfsmp)->vcbAtrb &= ~kHFSVolumeUnmountedMask;
1128 if ((mntflags & MNT_FORCE) == 0)
1129 return (retval); /* could not flush everything */
1130 }
1131 }
1132
1133 /*
1134 * Invalidate our caches and release metadata vnodes
1135 */
1136 (void) hfsUnmount(hfsmp, p);
1137
1138 if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord)
1139 (void) hfs_relconverter(hfsmp->hfs_encoding);
1140
1141 hfsmp->hfs_devvp->v_specflags &= ~SI_MOUNTEDON;
1142 retval = VOP_CLOSE(hfsmp->hfs_devvp, hfsmp->hfs_fs_ronly ? FREAD : FREAD|FWRITE,
1143 NOCRED, p);
1144 vrele(hfsmp->hfs_devvp);
1145
1146 FREE(hfsmp, M_HFSMNT);
1147 mp->mnt_data = (qaddr_t)0;
1148
1149 return (retval);
1150}
1151
1152
1153/*
1154 * Return the root of a filesystem.
1155 *
1156 * OUT - vpp, should be locked and vget()'d (to increment usecount and lock)
1157 */
1158int hfs_root(mp, vpp)
1159struct mount *mp;
1160struct vnode **vpp;
1161{
1162 struct vnode *nvp;
1163 int retval;
1164 UInt32 rootObjID = kRootDirID;
1165
1166 DBG_FUNC_NAME("hfs_root");
1167 DBG_PRINT_FUNC_NAME();
1168
1169 if ((retval = VFS_VGET(mp, &rootObjID, &nvp)))
1170 return (retval);
1171
1172 *vpp = nvp;
1173 return (0);
1174}
1175
1176
1177/*
1178 * Do operations associated with quotas
1179 */
1180int hfs_quotactl(mp, cmds, uid, arg, p)
1181struct mount *mp;
1182int cmds;
1183uid_t uid;
1184caddr_t arg;
1185struct proc *p;
1186{
1187 DBG_FUNC_NAME("hfs_quotactl");
1188 DBG_PRINT_FUNC_NAME();
1189
1190 return (EOPNOTSUPP);
1191}
1192
1193
1194/*
1195 * Get file system statistics.
1196 */
1197static int
1198hfs_statfs(mp, sbp, p)
1199 struct mount *mp;
1200 register struct statfs *sbp;
1201 struct proc *p;
1202{
1203 ExtendedVCB *vcb = VFSTOVCB(mp);
1204 struct hfsmount *hfsmp = VFSTOHFS(mp);
1205 u_long freeCNIDs;
1206
1207 DBG_FUNC_NAME("hfs_statfs");
1208 DBG_PRINT_FUNC_NAME();
1209
1210 freeCNIDs = (u_long)0xFFFFFFFF - (u_long)vcb->vcbNxtCNID;
1211
1212 sbp->f_bsize = vcb->blockSize;
1213 sbp->f_iosize = hfsmp->hfs_logBlockSize;
1214 sbp->f_blocks = vcb->totalBlocks;
1215 sbp->f_bfree = vcb->freeBlocks;
1216 sbp->f_bavail = vcb->freeBlocks;
1217 sbp->f_files = vcb->totalBlocks - 2; /* max files is constrained by total blocks */
1218 sbp->f_ffree = MIN(freeCNIDs, vcb->freeBlocks);
1219
1220 sbp->f_type = 0;
1221 if (sbp != &mp->mnt_stat) {
1222 sbp->f_type = mp->mnt_vfc->vfc_typenum;
1223 bcopy((caddr_t)mp->mnt_stat.f_mntonname,
1224 (caddr_t)&sbp->f_mntonname[0], MNAMELEN);
1225 bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
1226 (caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
1227 }
1228 return (0);
1229}
1230
1231
1232/*
1233 * Go through the disk queues to initiate sandbagged IO;
1234 * go through the inodes to write those that have been modified;
1235 * initiate the writing of the super block if it has been modified.
1236 *
1237 * Note: we are always called with the filesystem marked `MPBUSY'.
1238 */
1239static int hfs_sync(mp, waitfor, cred, p)
1240struct mount *mp;
1241int waitfor;
1242struct ucred *cred;
1243struct proc *p;
1244{
1245 struct vnode *nvp, *vp;
1246 struct hfsnode *hp;
1247 struct hfsmount *hfsmp = VFSTOHFS(mp);
1248 ExtendedVCB *vcb;
1249 int error, allerror = 0;
1250
1251 DBG_FUNC_NAME("hfs_sync");
1252 DBG_PRINT_FUNC_NAME();
1253
1254 /*
1255 * During MNT_UPDATE hfs_changefs might be manipulating
1256 * vnodes so back off
1257 */
1258 if (mp->mnt_flag & MNT_UPDATE)
1259 return (0);
1260
1261 hfsmp = VFSTOHFS(mp);
1262 if (hfsmp->hfs_fs_ronly != 0) {
1263 panic("update: rofs mod");
1264 };
1265
1266 /*
1267 * Write back each 'modified' vnode
1268 */
1269
1270loop:;
1271 simple_lock(&mntvnode_slock);
1272 for (vp = mp->mnt_vnodelist.lh_first;
1273 vp != NULL;
1274 vp = nvp) {
0b4e3aa0 1275 int didhold;
1c79356b
A
1276 /*
1277 * If the vnode that we are about to sync is no longer
1278 * associated with this mount point, start over.
1279 */
1280 if (vp->v_mount != mp) {
1281 simple_unlock(&mntvnode_slock);
1282 goto loop;
1283 }
1284 simple_lock(&vp->v_interlock);
1285 nvp = vp->v_mntvnodes.le_next;
1286 hp = VTOH(vp);
1287
1288 if ((vp->v_type == VNON) || (((hp->h_nodeflags & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0) &&
1289 (vp->v_dirtyblkhd.lh_first == NULL) && !(vp->v_flag & VHASDIRTY))) {
1290 simple_unlock(&vp->v_interlock);
1291 simple_unlock(&mntvnode_slock);
1292 simple_lock(&mntvnode_slock);
1293 continue;
1294 }
1295
1296 simple_unlock(&mntvnode_slock);
1297 error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p);
1298 if (error) {
1299 if (error == ENOENT)
1300 goto loop;
1301 simple_lock(&mntvnode_slock);
1302 continue;
1303 }
1304
0b4e3aa0 1305 didhold = ubc_hold(vp);
1c79356b
A
1306 if ((error = VOP_FSYNC(vp, cred, waitfor, p))) {
1307 DBG_ERR(("hfs_sync: error %d calling fsync on vnode 0x%X.\n", error, (u_int)vp));
1308 allerror = error;
1309 };
1310 DBG_ASSERT(*((volatile int *)(&(vp)->v_interlock))==0);
0b4e3aa0
A
1311 VOP_UNLOCK(vp, 0, p);
1312 if (didhold)
1313 ubc_rele(vp);
1314 vrele(vp);
1c79356b
A
1315 simple_lock(&mntvnode_slock);
1316 };
1317
1318 vcb = HFSTOVCB(hfsmp);
1319
1320 /* Now reprocess the BTree node, stored above */
1321 {
1322 struct vnode *btvp;
1323 /*
1324 * If the vnode that we are about to sync is no longer
1325 * associated with this mount point, start over.
1326 */
1327 btvp = vcb->extentsRefNum;
1328 if ((btvp==0) || (btvp->v_type == VNON) || (btvp->v_mount != mp))
1329 goto skipBtree;
1330 simple_lock(&btvp->v_interlock);
1331 hp = VTOH(btvp);
1332 if (((hp->h_nodeflags & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0) &&
1333 (btvp->v_dirtyblkhd.lh_first == NULL) && !(btvp->v_flag & VHASDIRTY)) {
1334 simple_unlock(&btvp->v_interlock);
1335 goto skipBtree;
1336 }
1337 simple_unlock(&mntvnode_slock);
1338 error = vget(btvp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p);
1339 if (error) {
1340 simple_lock(&mntvnode_slock);
1341 goto skipBtree;
1342 }
1343 if ((error = VOP_FSYNC(btvp, cred, waitfor, p)))
1344 allerror = error;
1345 VOP_UNLOCK(btvp, 0, p);
1346 vrele(btvp);
1347 simple_lock(&mntvnode_slock);
1348 };
1349
1350skipBtree:;
1351
1352 simple_unlock(&mntvnode_slock);
1353
1354 /*
1355 * Force stale file system control information to be flushed.
1356 */
1357 if ((error = VOP_FSYNC(hfsmp->hfs_devvp, cred, waitfor, p)))
1358 allerror = error;
1359 /*
1360 * Write back modified superblock.
1361 */
1362
1363 if (IsVCBDirty(vcb)) {
1364 if (vcb->vcbSigWord == kHFSPlusSigWord)
1365 error = hfs_flushvolumeheader(hfsmp, waitfor);
1366 else
1367 error = hfs_flushMDB(hfsmp, waitfor);
1368
1369 if (error)
1370 allerror = error;
1371 };
1372
1373 return (allerror);
1374}
1375
1376
1377/*
1378 * File handle to vnode
1379 *
1380 * Have to be really careful about stale file handles:
1381 * - check that the hfsnode number is valid
1382 * - call hfs_vget() to get the locked hfsnode
1383 * - check for an unallocated hfsnode (i_mode == 0)
1384 * - check that the given client host has export rights and return
1385 * those rights via. exflagsp and credanonp
1386 */
1387int
1388hfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
1389register struct mount *mp;
1390struct fid *fhp;
1391struct mbuf *nam;
1392struct vnode **vpp;
1393int *exflagsp;
1394struct ucred **credanonp;
1395{
1396 struct hfsfid *hfsfhp;
1397 struct vnode *nvp;
1398 int result;
1399 struct netcred *np;
1400 DBG_FUNC_NAME("hfs_fhtovp");
1401 DBG_PRINT_FUNC_NAME();
1402
1403 *vpp = NULL;
1404 hfsfhp = (struct hfsfid *)fhp;
1405
1406 /*
1407 * Get the export permission structure for this <mp, client> tuple.
1408 */
1409 np = vfs_export_lookup(mp, &VFSTOHFS(mp)->hfs_export, nam);
1410 if (np == NULL) {
1411 return EACCES;
1412 };
1413
1414 result = VFS_VGET(mp, &hfsfhp->hfsfid_cnid, &nvp);
1415 if (result) return result;
1416 if (nvp == NULL) return ESTALE;
1417
0b4e3aa0
A
1418 /* The createtime can be changed by hfs_setattr or hfs_setattrlist.
1419 * For NFS, we are assuming that only if the createtime was moved
1420 * forward would it mean the fileID got reused in that session by
1421 * wrapping. We don't have a volume ID or other unique identifier to
1422 * to use here for a generation ID across reboots, crashes where
1423 * metadata noting lastFileID didn't make it to disk but client has
1424 * it, or volume erasures where fileIDs start over again. Lastly,
1425 * with HFS allowing "wraps" of fileIDs now, this becomes more
1426 * error prone. Future, would be change the "wrap bit" to a unique
1427 * wrap number and use that for generation number. For now do this.
1428 */
1429 if ((hfsfhp->hfsfid_gen < VTOH(nvp)->h_meta->h_crtime)) {
1c79356b
A
1430 vput(nvp);
1431 return ESTALE;
1432 };
1433
1434 *vpp = nvp;
1435 *exflagsp = np->netc_exflags;
1436 *credanonp = &np->netc_anon;
1437
1438 return 0;
1439}
1440
1441
1442/*
1443 * Vnode pointer to File handle
1444 */
1445/* ARGSUSED */
1446static int hfs_vptofh(vp, fhp)
1447struct vnode *vp;
1448struct fid *fhp;
1449{
1450 struct hfsnode *hp;
1451 struct hfsfid *hfsfhp;
1452 struct proc *p = current_proc();
1453 int result;
1454 u_int32_t fileID;
1455 DBG_FUNC_NAME("hfs_vptofh");
1456 DBG_PRINT_FUNC_NAME();
1457
1458 hp = VTOH(vp);
1459 hfsfhp = (struct hfsfid *)fhp;
1460
1461 /* If a file handle is requested for a file on an HFS volume we must be sure
1462 to create the thread record before returning the object id in the filehandle
1463 to make sure the file can be retrieved by fileid if necessary:
1464 */
1465 if ((vp->v_type == VREG) && ISHFS(VTOVCB(vp))) {
1466 /* Create a thread record and return the FileID [which is the file's fileNumber] */
1467 /* lock catalog b-tree */
1468 if ((result = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_EXCLUSIVE, p)) != 0) return result;
1469 result = hfsCreateFileID(VTOVCB(vp), H_DIRID(hp), H_NAME(hp), H_HINT(hp), &fileID);
1470 (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, p);
1471 if (result) {
1472 DBG_ERR(("hfs_vptofh: error %d on CreateFileIDRef.\n", result));
1473 return result;
1474 };
1475 DBG_ASSERT(fileID == H_FILEID(hp));
1476 };
1477
1478 hfsfhp->hfsfid_len = sizeof(struct hfsfid);
1479 hfsfhp->hfsfid_pad = 0;
1480 hfsfhp->hfsfid_cnid = H_FILEID(hp);
1481 hfsfhp->hfsfid_gen = hp->h_meta->h_crtime;
1482
1483 return 0;
1484}
1485
1486
1487/*
1488 * Initial HFS filesystems, done only once.
1489 */
1490int
1491hfs_init(vfsp)
1492struct vfsconf *vfsp;
1493{
1494 int i;
1495 static int done = 0;
1496 OSErr err;
1497
1498 DBG_FUNC_NAME("hfs_init");
1499 DBG_PRINT_FUNC_NAME();
1500
1501 if (done)
1502 return (0);
1503 done = 1;
1504 hfs_vhashinit();
1505 hfs_converterinit();
1506
1507 simple_lock_init (&gBufferPtrListLock);
1508
1509 for (i = BUFFERPTRLISTSIZE - 1; i >= 0; --i) {
1510 gBufferAddress[i] = NULL;
1511 gBufferHeaderPtr[i] = NULL;
1512 };
1513 gBufferListIndex = 0;
1514
1c79356b
A
1515 /*
1516 * Allocate Catalog Iterator cache...
1517 */
1518 err = InitCatalogCache();
1c79356b
A
1519
1520 return E_NONE;
1521}
1522
1523
1524/*
1525 * fast filesystem related variables.
1526 */
1527static int hfs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
1528int *name;
1529u_int namelen;
1530void *oldp;
1531size_t *oldlenp;
1532void *newp;
1533size_t newlen;
1534struct proc *p;
1535{
1536 DBG_FUNC_NAME("hfs_sysctl");
1537 DBG_PRINT_FUNC_NAME();
1538
1539 return (EOPNOTSUPP);
1540}
1541
1542
1543/* This will return a vnode of either a directory or a data vnode based on an object id. If
1544 * it is a file id, its data fork will be returned.
1545 */
1546int
1547hfs_vget(struct mount *mp,
1548 void *ino,
1549 struct vnode **vpp)
1550{
1551 struct hfsmount *hfsmp;
1552 dev_t dev;
1553 int retval = E_NONE;
1554
1555 DBG_VFS(("hfs_vget: ino = %ld\n", *(UInt32 *)ino));
1556
1557 /* Check if unmount in progress */
1558 if (mp->mnt_kern_flag & MNTK_UNMOUNT) {
1559 *vpp = NULL;
1560 return (EPERM);
1561 }
1562
1563 hfsmp = VFSTOHFS(mp);
1564 dev = hfsmp->hfs_raw_dev;
1565
1566 /* First check to see if it is in the cache */
1567 *vpp = hfs_vhashget(dev, *(UInt32 *)ino, kDefault);
1568
1569 /* hide open files that have been deleted */
1570 if (*vpp != NULL) {
1571 if ((VTOH(*vpp)->h_meta->h_metaflags & IN_NOEXISTS) ||
1572 (hfsmp->hfs_private_metadata_dir != 0) &&
1573 (H_DIRID(VTOH(*vpp)) == hfsmp->hfs_private_metadata_dir)) {
1574 vput(*vpp);
1575 retval = ENOENT;
1576 goto Err_Exit;
1577 }
1578 }
1579
1580 /* The vnode is not in the cache, so lets make it */
1581 if (*vpp == NULL)
1582 {
1583 hfsCatalogInfo catInfo;
1584 struct proc *p = current_proc();
1585 UInt8 forkType;
1586
1587 INIT_CATALOGDATA(&catInfo.nodeData, 0);
1588 catInfo.hint = kNoHint;
1589 /* Special-case the root's parent directory (DirID = 1) because
1590 it doesn't actually exist in the catalog: */
1591 if ((*vpp == NULL) && (*(UInt32 *)ino == kRootParID)) {
1592 bzero(&catInfo, sizeof(catInfo));
1593 catInfo.nodeData.cnd_type = kCatalogFolderNode;
1594 catInfo.nodeData.cnm_nameptr = catInfo.nodeData.cnm_namespace;
1595 catInfo.nodeData.cnm_namespace[0] = '/';
1596 catInfo.nodeData.cnm_length = 1;
1597 catInfo.nodeData.cnd_nodeID = kRootParID;
1598 catInfo.nodeData.cnm_parID = kRootParID;
1599 catInfo.nodeData.cnd_valence = 1;
1600 catInfo.nodeData.cnd_ownerID = 0;
1601 catInfo.nodeData.cnd_groupID = 0;
1602 catInfo.nodeData.cnd_mode = (S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO);
1603 } else {
1604
1605 /* lock catalog b-tree */
1606 retval = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_SHARED, p);
1607 if (retval != E_NONE) goto Lookup_Err_Exit;
1608
1609 retval = hfs_getcatalog(VFSTOVCB(mp), *(UInt32 *)ino, NULL, -1, &catInfo);
1610
1611 /* unlock catalog b-tree */
1612 (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p);
1613
1614 if (retval != E_NONE) goto Lookup_Err_Exit;
1615
1616 /* hide open files that have been deleted */
1617 if ((hfsmp->hfs_private_metadata_dir != 0) &&
1618 (catInfo.nodeData.cnm_parID == hfsmp->hfs_private_metadata_dir)) {
1619 retval = ENOENT;
1620 goto Lookup_Err_Exit;
1621 };
1622 };
1623
1624 forkType = (catInfo.nodeData.cnd_type == kCatalogFolderNode) ? kDirectory : kDataFork;
1625 retval = hfs_vcreate(VFSTOVCB(mp), &catInfo, forkType, vpp);
1626
1627Lookup_Err_Exit:
1628 CLEAN_CATALOGDATA(&catInfo.nodeData);
1629 };
1630
1631 UBCINFOCHECK("hfs_vget", *vpp);
1632
1633Err_Exit:
1634
0b4e3aa0
A
1635 /* rember if a parent directory was looked up by CNID */
1636 if (retval == 0 && ((*vpp)->v_type == VDIR)
1637 && lockstatus(&mp->mnt_lock) != LK_SHARED)
1638 VTOH(*vpp)->h_nodeflags |= IN_BYCNID;
1c79356b
A
1639
1640 return (retval);
1641
1642}
1643
1644/*
1645 * Flush out all the files in a filesystem.
1646 */
1647int
1648hfs_flushfiles(struct mount *mp, int flags)
1649{
1650 int error;
1651
1652 error = vflush(mp, NULLVP, (SKIPSYSTEM | SKIPSWAP | flags));
1653 error = vflush(mp, NULLVP, (SKIPSYSTEM | flags));
1654
1655 return (error);
1656}
1657
1658short hfs_flushMDB(struct hfsmount *hfsmp, int waitfor)
1659{
1660 ExtendedVCB *vcb = HFSTOVCB(hfsmp);
1661 FCB *fcb;
1662 HFSMasterDirectoryBlock *mdb;
1663 struct buf *bp;
1664 int retval;
1665 int size = kMDBSize; /* 512 */
1666 ByteCount namelen;
1667
1668 if (vcb->vcbSigWord != kHFSSigWord)
1669 return EINVAL;
1670
1671 DBG_ASSERT(hfsmp->hfs_devvp != NULL);
1672
1673 retval = bread(hfsmp->hfs_devvp, IOBLKNOFORBLK(kMasterDirectoryBlock, size),
1674 IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, size), NOCRED, &bp);
1675 if (retval) {
1676 DBG_VFS((" hfs_flushMDB bread return error! (%d)\n", retval));
1677 if (bp) brelse(bp);
1678 return retval;
1679 }
1680
1681 DBG_ASSERT(bp != NULL);
1682 DBG_ASSERT(bp->b_data != NULL);
1683 DBG_ASSERT(bp->b_bcount == size);
1684
1685 mdb = (HFSMasterDirectoryBlock *)((char *)bp->b_data + IOBYTEOFFSETFORBLK(kMasterDirectoryBlock, size));
1686
1687 VCB_LOCK(vcb);
1688 mdb->drCrDate = SWAP_BE32 (UTCToLocal(vcb->vcbCrDate));
1689 mdb->drLsMod = SWAP_BE32 (UTCToLocal(vcb->vcbLsMod));
1690 mdb->drAtrb = SWAP_BE16 (vcb->vcbAtrb);
1691 mdb->drNmFls = SWAP_BE16 (vcb->vcbNmFls);
1692 mdb->drAllocPtr = SWAP_BE16 (vcb->nextAllocation);
1693 mdb->drClpSiz = SWAP_BE32 (vcb->vcbClpSiz);
1694 mdb->drNxtCNID = SWAP_BE32 (vcb->vcbNxtCNID);
1695 mdb->drFreeBks = SWAP_BE16 (vcb->freeBlocks);
1696
1697 namelen = strlen(vcb->vcbVN);
1698 retval = utf8_to_hfs(vcb, namelen, vcb->vcbVN, mdb->drVN);
1699 /* Retry with MacRoman in case that's how it was exported. */
1700 if (retval)
1701 retval = utf8_to_mac_roman(namelen, vcb->vcbVN, mdb->drVN);
1702
1703 mdb->drVolBkUp = SWAP_BE32 (UTCToLocal(vcb->vcbVolBkUp));
1c79356b
A
1704 mdb->drWrCnt = SWAP_BE32 (vcb->vcbWrCnt);
1705 mdb->drNmRtDirs = SWAP_BE16 (vcb->vcbNmRtDirs);
1706 mdb->drFilCnt = SWAP_BE32 (vcb->vcbFilCnt);
1707 mdb->drDirCnt = SWAP_BE32 (vcb->vcbDirCnt);
1708
1709 bcopy(vcb->vcbFndrInfo, mdb->drFndrInfo, sizeof(mdb->drFndrInfo));
1710
1711 fcb = VTOFCB(vcb->extentsRefNum);
1712 /* HFSPlusToHFSExtents(fcb->fcbExtents, mdb->drXTExtRec); */
1713 mdb->drXTExtRec[0].startBlock = SWAP_BE16 (fcb->fcbExtents[0].startBlock);
1714 mdb->drXTExtRec[0].blockCount = SWAP_BE16 (fcb->fcbExtents[0].blockCount);
1715 mdb->drXTExtRec[1].startBlock = SWAP_BE16 (fcb->fcbExtents[1].startBlock);
1716 mdb->drXTExtRec[1].blockCount = SWAP_BE16 (fcb->fcbExtents[1].blockCount);
1717 mdb->drXTExtRec[2].startBlock = SWAP_BE16 (fcb->fcbExtents[2].startBlock);
1718 mdb->drXTExtRec[2].blockCount = SWAP_BE16 (fcb->fcbExtents[2].blockCount);
1719
1720 mdb->drXTFlSize = SWAP_BE32 (fcb->fcbPLen);
1721 mdb->drXTClpSiz = SWAP_BE32 (fcb->fcbClmpSize);
1722
1723 fcb = VTOFCB(vcb->catalogRefNum);
1724 /* HFSPlusToHFSExtents(fcb->fcbExtents, mdb->drCTExtRec); */
1725 mdb->drCTExtRec[0].startBlock = SWAP_BE16 (fcb->fcbExtents[0].startBlock);
1726 mdb->drCTExtRec[0].blockCount = SWAP_BE16 (fcb->fcbExtents[0].blockCount);
1727 mdb->drCTExtRec[1].startBlock = SWAP_BE16 (fcb->fcbExtents[1].startBlock);
1728 mdb->drCTExtRec[1].blockCount = SWAP_BE16 (fcb->fcbExtents[1].blockCount);
1729 mdb->drCTExtRec[2].startBlock = SWAP_BE16 (fcb->fcbExtents[2].startBlock);
1730 mdb->drCTExtRec[2].blockCount = SWAP_BE16 (fcb->fcbExtents[2].blockCount);
1731
1732 mdb->drCTFlSize = SWAP_BE32 (fcb->fcbPLen);
1733 mdb->drCTClpSiz = SWAP_BE32 (fcb->fcbClmpSize);
1734 VCB_UNLOCK(vcb);
1735
1736 if (waitfor != MNT_WAIT)
1737 bawrite(bp);
1738 else
1739 retval = VOP_BWRITE(bp);
1740
1741 MarkVCBClean( vcb );
1742
1743 return (retval);
1744}
1745
1746
1747short hfs_flushvolumeheader(struct hfsmount *hfsmp, int waitfor)
1748{
1749 ExtendedVCB *vcb = HFSTOVCB(hfsmp);
1750 FCB *fcb;
1751 HFSPlusVolumeHeader *volumeHeader;
1752 int retval;
1753 int size = sizeof(HFSPlusVolumeHeader);
1754 struct buf *bp;
1755 int i;
1756
1757 if (vcb->vcbSigWord != kHFSPlusSigWord)
1758 return EINVAL;
1759
1760 retval = bread(hfsmp->hfs_devvp, IOBLKNOFORBLK((vcb->hfsPlusIOPosOffset / 512) + kMasterDirectoryBlock, size),
1761 IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, size), NOCRED, &bp);
1762 if (retval) {
1763 DBG_VFS((" hfs_flushvolumeheader bread return error! (%d)\n", retval));
1764 if (bp) brelse(bp);
1765 return retval;
1766 }
1767
1768 DBG_ASSERT(bp != NULL);
1769 DBG_ASSERT(bp->b_data != NULL);
1770 DBG_ASSERT(bp->b_bcount == size);
1771
1772 volumeHeader = (HFSPlusVolumeHeader *)((char *)bp->b_data +
1773 IOBYTEOFFSETFORBLK((vcb->hfsPlusIOPosOffset / 512) + kMasterDirectoryBlock, size));
1774
1775 /*
1776 * For embedded HFS+ volumes, update create date if it changed
1777 * (ie from a setattrlist call)
1778 */
1779 if ((vcb->hfsPlusIOPosOffset != 0) && (SWAP_BE32 (volumeHeader->createDate) != vcb->localCreateDate))
1780 {
1781 struct buf *bp2;
1782 HFSMasterDirectoryBlock *mdb;
1783
1784 retval = bread(hfsmp->hfs_devvp, IOBLKNOFORBLK(kMasterDirectoryBlock, kMDBSize),
1785 IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, kMDBSize), NOCRED, &bp2);
1786 if (retval != E_NONE) {
1787 if (bp2) brelse(bp2);
1788 } else {
1789 mdb = (HFSMasterDirectoryBlock *)((char *)bp2->b_data + IOBYTEOFFSETFORBLK(kMasterDirectoryBlock, kMDBSize));
1790
1791 if ( SWAP_BE32 (mdb->drCrDate) != vcb->localCreateDate )
1792 {
1793 mdb->drCrDate = SWAP_BE32 (vcb->localCreateDate); /* pick up the new create date */
1794
1795 (void) VOP_BWRITE(bp2); /* write out the changes */
1796 }
1797 else
1798 {
1799 brelse(bp2); /* just release it */
1800 }
1801 }
1802 }
1803
1804 VCB_LOCK(vcb);
1805 /* Note: only update the lower 16 bits worth of attributes */
1806 volumeHeader->attributes = SWAP_BE32 ((SWAP_BE32 (volumeHeader->attributes) & 0xFFFF0000) + (UInt16) vcb->vcbAtrb);
1807 volumeHeader->lastMountedVersion = SWAP_BE32 (kHFSPlusMountVersion);
1808 volumeHeader->createDate = SWAP_BE32 (vcb->localCreateDate); /* volume create date is in local time */
1809 volumeHeader->modifyDate = SWAP_BE32 (vcb->vcbLsMod);
1810 volumeHeader->backupDate = SWAP_BE32 (vcb->vcbVolBkUp);
1811 volumeHeader->checkedDate = SWAP_BE32 (vcb->checkedDate);
1812 volumeHeader->fileCount = SWAP_BE32 (vcb->vcbFilCnt);
1813 volumeHeader->folderCount = SWAP_BE32 (vcb->vcbDirCnt);
1814 volumeHeader->freeBlocks = SWAP_BE32 (vcb->freeBlocks);
1815 volumeHeader->nextAllocation = SWAP_BE32 (vcb->nextAllocation);
1816 volumeHeader->rsrcClumpSize = SWAP_BE32 (vcb->vcbClpSiz);
1817 volumeHeader->dataClumpSize = SWAP_BE32 (vcb->vcbClpSiz);
1818 volumeHeader->nextCatalogID = SWAP_BE32 (vcb->vcbNxtCNID);
1819 volumeHeader->writeCount = SWAP_BE32 (vcb->vcbWrCnt);
1820 volumeHeader->encodingsBitmap = SWAP_BE64 (vcb->encodingsBitmap);
1821
1822 bcopy( vcb->vcbFndrInfo, volumeHeader->finderInfo, sizeof(volumeHeader->finderInfo) );
1823
1824 VCB_UNLOCK(vcb);
1825
1826 fcb = VTOFCB(vcb->extentsRefNum);
1827 /* bcopy( fcb->fcbExtents, volumeHeader->extentsFile.extents, sizeof(HFSPlusExtentRecord) ); */
1828 for (i = 0; i < kHFSPlusExtentDensity; i++) {
1829 volumeHeader->extentsFile.extents[i].startBlock = SWAP_BE32 (fcb->fcbExtents[i].startBlock);
1830 volumeHeader->extentsFile.extents[i].blockCount = SWAP_BE32 (fcb->fcbExtents[i].blockCount);
1831 }
1832
1833 fcb->fcbFlags &= ~fcbModifiedMask;
1834 volumeHeader->extentsFile.logicalSize = SWAP_BE64 (fcb->fcbEOF);
1835 volumeHeader->extentsFile.totalBlocks = SWAP_BE32 (fcb->fcbPLen / vcb->blockSize);
1836 volumeHeader->extentsFile.clumpSize = SWAP_BE32 (fcb->fcbClmpSize);
1837
1838 fcb = VTOFCB(vcb->catalogRefNum);
1839 /* bcopy( fcb->fcbExtents, volumeHeader->catalogFile.extents, sizeof(HFSPlusExtentRecord) ); */
1840 for (i = 0; i < kHFSPlusExtentDensity; i++) {
1841 volumeHeader->catalogFile.extents[i].startBlock = SWAP_BE32 (fcb->fcbExtents[i].startBlock);
1842 volumeHeader->catalogFile.extents[i].blockCount = SWAP_BE32 (fcb->fcbExtents[i].blockCount);
1843 }
1844
1845 fcb->fcbFlags &= ~fcbModifiedMask;
1846 volumeHeader->catalogFile.logicalSize = SWAP_BE64 (fcb->fcbEOF);
1847 volumeHeader->catalogFile.totalBlocks = SWAP_BE32 (fcb->fcbPLen / vcb->blockSize);
1848 volumeHeader->catalogFile.clumpSize = SWAP_BE32 (fcb->fcbClmpSize);
1849
1850 fcb = VTOFCB(vcb->allocationsRefNum);
1851 /* bcopy( fcb->fcbExtents, volumeHeader->allocationFile.extents, sizeof(HFSPlusExtentRecord) ); */
1852 for (i = 0; i < kHFSPlusExtentDensity; i++) {
1853 volumeHeader->allocationFile.extents[i].startBlock = SWAP_BE32 (fcb->fcbExtents[i].startBlock);
1854 volumeHeader->allocationFile.extents[i].blockCount = SWAP_BE32 (fcb->fcbExtents[i].blockCount);
1855 }
1856
1857 fcb->fcbFlags &= ~fcbModifiedMask;
1858 volumeHeader->allocationFile.logicalSize = SWAP_BE64 (fcb->fcbEOF);
1859 volumeHeader->allocationFile.totalBlocks = SWAP_BE32 (fcb->fcbPLen / vcb->blockSize);
1860 volumeHeader->allocationFile.clumpSize = SWAP_BE32 (fcb->fcbClmpSize);
1861
1862 if (waitfor != MNT_WAIT)
1863 bawrite(bp);
1864 else
1865 retval = VOP_BWRITE(bp);
1866
1867 MarkVCBClean( vcb );
1868
1869 return (retval);
1870}
1871
1872
1873/*
1874 * Moved here to avoid having to define prototypes
1875 */
1876
1877/*
1878 * hfs vfs operations.
1879 */
1880struct vfsops hfs_vfsops = {
1881 hfs_mount,
1882 hfs_start,
1883 hfs_unmount,
1884 hfs_root,
1885 hfs_quotactl,
1886 hfs_statfs,
1887 hfs_sync,
1888 hfs_vget,
1889 hfs_fhtovp,
1890 hfs_vptofh,
1891 hfs_init,
1892 hfs_sysctl
1893};