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