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