|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24: /*
25: * Copyright (c) 1991, 1993, 1994
26: * The Regents of the University of California. All rights reserved.
27: * (c) UNIX System Laboratories, Inc.
28: * All or some portions of this file are derived from material licensed
29: * to the University of California by American Telephone and Telegraph
30: * Co. or Unix System Laboratories, Inc. and are reproduced herein with
31: * the permission of UNIX System Laboratories, Inc.
32: *
33: * Redistribution and use in source and binary forms, with or without
34: * modification, are permitted provided that the following conditions
35: * are met:
36: * 1. Redistributions of source code must retain the above copyright
37: * notice, this list of conditions and the following disclaimer.
38: * 2. Redistributions in binary form must reproduce the above copyright
39: * notice, this list of conditions and the following disclaimer in the
40: * documentation and/or other materials provided with the distribution.
41: * 3. All advertising materials mentioning features or use of this software
42: * must display the following acknowledgement:
43: * This product includes software developed by the University of
44: * California, Berkeley and its contributors.
45: * 4. Neither the name of the University nor the names of its contributors
46: * may be used to endorse or promote products derived from this software
47: * without specific prior written permission.
48: *
49: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59: * SUCH DAMAGE.
60: *
61: * hfs_vfsops.c
62: * derived from @(#)ufs_vfsops.c 8.8 (Berkeley) 5/20/95
63: *
64: * (c) Copyright 1997-1998 Apple Computer, Inc. All rights reserved.
65: *
66: * hfs_vfsops.c -- VFS layer for loadable HFS file system.
67: *
68: * HISTORY
69: * 12-Nov-1998 Pat Dirks Changed hfs_statfs to return volume's actual log. block size (#2286198).
70: * 22-Aug-1998 Scott Roberts Assign uid,gid, and mask for default on objects.
71: * 29-Jul-1998 Pat Dirks Fixed changed hfs_vget() to release complex node when retrying for data fork node.
72: * 27-Jul-1998 Scott Roberts Changes hfs_vget() to return data forks instead of complex.
73: * 14-Jul-1998 CHW Added check for use count of device node in hfs_mountfs
74: * 1-Jul-1998 Don Brady Always set kHFSVolumeUnmountedMask bit of vcb->vcbAtrb in hfs_unmount.
75: * 30-Jun-1998 Don Brady Removed hard-coded EINVAL error in hfs_mountfs (for radar #2249539).
76: * 24-Jun-1998 Don Brady Added setting of timezone to hfs_mount (radar #2226387).
77: * 4-Jun-1998 Don Brady Use VPUT/VRELE macros instead of vput/vrele.
78: * 6-May-1998 Scott Roberts Updated hfs_vget with kernel changes.
79: * 29-Apr-1998 Don Brady Update hfs_statfs to actually fill in statfs fields (radar #2227092).
80: * 23-Apr-1998 Pat Dirks Cleaned up code to call brelse() on errors from bread().
81: * 4/20/1998 Don Brady Remove course-grained hfs metadata locking.
82: * 4/18/1998 Don Brady Add VCB locking.
83: * 4/16/1998 Don Brady hfs_unmount now flushes the volume bitmap. Add b-tree locking to hfs_vget.
84: * 4/8/1998 Don Brady Replace hfs_mdbupdate with hfs_flushvolumeheader and hfs_flushMDB.
85: * 4/8/1998 Don Brady In hfs_unmount call hfs_mdbupdate before trashing metafiles!
86: * 4/3/1998 Don Brady Call InitCatalogCache instead of PostInitFS.
87: * 4/1/1998 Don Brady Get rid of gHFSFlags, gReqstVol and gFlushOnlyFlag globals (not used).
88: * 3/30/1998 Don Brady In hfs_unmount use SKIPSYSTEM option on first vflush.
89: * 3/26/1998 Don Brady Changed hfs_unmount to call vflush before calling hfsUnmount.
90: * In hfs_mountfs don't mount hfs-wrapper.
91: * 3/19/1998 Pat Dirks Fixed bug in hfs_mount where device vnode was being
92: * released on way out.
93: * 11/14/1997 Pat Dirks Derived from hfs_vfsops.c
94: */
95:
96: #include <sys/types.h>
97: #include <sys/namei.h>
98: #include <sys/param.h>
99: #include <sys/proc.h>
100: #include <mach/machine/vm_types.h>
101: #include <sys/vnode.h>
102: #include <sys/mount.h>
103: #include <sys/malloc.h>
104: #include <sys/fcntl.h>
105: #include <sys/stat.h>
106: #include <libkern/libkern.h>
107: #include <bsd/dev/disk.h>
108: #include <mach/machine/simple_lock.h>
109: #include <miscfs/specfs/specdev.h>
110: #include <sys/systm.h>
111: #include <mach/features.h>
112: #include <kern/mapfs.h>
113:
114: #include "hfs.h"
115: #include "hfs_dbg.h"
116: #include "mount_hfs.h"
117:
118: #include "hfscommon/headers/FileMgrInternal.h"
119:
120: typedef (*PFI)();
121:
122: extern char *strncpy __P((char *, const char *, size_t)); /* Kernel already includes a copy of strncpy somewhere... */
123: extern int strcmp __P((const char *, const char *)); /* Kernel already includes a copy of strcmp somewhere... */
124:
125: extern struct proc * current_proc_EXTERNAL();
126:
127: /* The following refer to kernel global variables used in the loading/initialization: */
128: extern int maxvfsslots; /* Total number of slots in the system's vfsconf table */
129: extern int maxvfsconf; /* The highest fs type number [old-style ID] in use [dispite its name] */
130: extern int vfs_opv_numops; /* The total number of defined vnode operations */
131: extern int kdp_flag;
132:
133: #if DIAGNOSTIC
134: int hfs_dbg_all = 0;
135: int hfs_dbg_vfs = 0;
136: int hfs_dbg_vop = 1;
137: int hfs_dbg_load = 0;
138: int hfs_dbg_io = 1;
139: int hfs_dbg_utils = 1;
140: int hfs_dbg_rw = 1;
141: int hfs_dbg_DIT = 0;
142: int hfs_dbg_tree = 0;
143: int hfs_dbg_err = 0;
144: int hfs_dbg_test = 0;
145: #endif
146:
147: /*
148: * HFS File System globals:
149: */
150: Ptr gBufferAddress[BUFFERPTRLISTSIZE];
151: struct buf *gBufferHeaderPtr[BUFFERPTRLISTSIZE];
152: int gBufferListIndex;
153: simple_lock_data_t gBufferPtrListLock;
154:
155: static char hfs_fs_name[MFSNAMELEN] = "hfs";
156:
157: /* The following represent information held in low-memory on the MacOS: */
158:
159: struct FSVarsRec *gFSMVars;
160:
161: /*
162: * Global variables defined in other modules:
163: */
164: extern struct vnodeopv_desc hfs_vnodeop_opv_desc;
165:
166:
167: int hfs_reload(struct mount *mp, struct ucred *cred, struct proc *p);
168: int hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p);
169: int hfs_vget(struct mount *mp, void *objID, struct vnode **vpp);
170: void hfs_vhashinit();
171:
172: static int hfs_statfs();
173:
174:
175: /*
176: * VFS Operations.
177: *
178: * mount system call
179: */
180:
181: static int hfs_mount (mp, path, data, ndp, p)
182: register struct mount *mp;
183: char *path;
184: caddr_t data;
185: struct nameidata *ndp;
186: struct proc *p;
187: {
188: struct hfsmount *hfsmp;
189: struct vnode *devvp;
190: struct hfs_mount_args args;
191: size_t size;
192: int retval = E_NONE;
193: mode_t accessmode;
194:
195: DBG_FUNC_NAME("hfs_mount");
196: DBG_PRINT_FUNC_NAME();
197:
198: #if DIAGNOSTIC
199: // call_kdp();
200: #endif
201:
202: #if FORCE_READONLY
203: // DBG_ASSERT((mp->mnt_flag & MNT_RDONLY) == MNT_RDONLY); /* Should already be set */
204: mp->mnt_flag |= MNT_RDONLY; /* ALWAYS act as if it's mounted read-only */
205: #endif /* FORCE_READONLY */
206:
207: if ((retval = copyin(data, (caddr_t)&args, sizeof(args))))
208: goto error_exit;
209:
210: /*
211: * If updating, check whether changing from read-only to
212: * read/write; if there is no device name, that's all we do.
213: */
214: if (mp->mnt_flag & MNT_UPDATE) {
215: unsigned short flags;
216:
217: DBG_VFS(("hfs_mount: handling update...\n"));
218:
219: hfsmp = VFSTOHFS(mp);
220: if (hfsmp->hfs_fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
221: flags = WRITECLOSE;
222: if (mp->mnt_flag & MNT_FORCE)
223: flags |= FORCECLOSE;
224: if ((retval = hfs_flushfiles(mp, flags)))
225: goto error_exit;
226: hfsmp->hfs_fs_clean = 1;
227: hfsmp->hfs_fs_ronly = 1;
228: if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
229: retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT);
230: else
231: retval = hfs_flushMDB(hfsmp, MNT_WAIT);
232:
233: if (retval) {
234: hfsmp->hfs_fs_clean = 0;
235: hfsmp->hfs_fs_ronly = 0;
236: goto error_exit;
237: }
238: }
239:
240: if ((mp->mnt_flag & MNT_RELOAD) &&
241: (retval = hfs_reload(mp, ndp->ni_cnd.cn_cred, p)))
242: goto error_exit;
243:
244: if (hfsmp->hfs_fs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) {
245: /*
246: * If upgrade to read-write by non-root, then verify
247: * that user has necessary permissions on the device.
248: */
249: if (p->p_ucred->cr_uid != 0) {
250: devvp = hfsmp->hfs_devvp;
251: vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
252: if ((retval = VOP_ACCESS(devvp, VREAD | VWRITE, p->p_ucred, p))) {
253: VOP_UNLOCK(devvp, 0, p);
254: goto error_exit;
255: }
256: VOP_UNLOCK(devvp, 0, p);
257: }
258: hfsmp->hfs_fs_ronly = 0;
259: hfsmp->hfs_fs_clean = 0;
260: if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
261: retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT);
262: else
263: retval = hfs_flushMDB(hfsmp, MNT_WAIT);
264:
265: if (retval != E_NONE)
266: goto error_exit;
267: }
268:
269: #if 0 /* XXX PPD */
270: if (args.ma_fspec == 0) {
271: /*
272: * Process export requests.
273: */
274: retval = (vfs_export(mp, &hfsmp->hfs_export, &args.ma_export));
275: }
276: #endif
277:
278: goto std_exit;
279: }
280:
281: /*
282: * Not an update, or updating the name: look up the name
283: * and verify that it refers to a sensible block device.
284: */
285: DBG_VFS(("hfs_mount: looking up device name (%s)...\n", args.ma_fspec));
286:
287: NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.ma_fspec, p);
288: retval = namei(ndp);
289: if (retval != E_NONE) {
290: DBG_ERR(("hfs_mount: CAN'T GET DEVICE: %s, %x\n", args.ma_fspec, ndp->ni_vp->v_rdev));
291: goto error_exit;
292: }
293:
294: devvp = ndp->ni_vp;
295: DBG_VFS(("hfs_mount: Device is %x\n",(uint)devvp));
296:
297: if (devvp->v_type != VBLK) {
298: VRELE(devvp);
299: retval = ENOTBLK;
300: goto error_exit;
301: };
302: if (major(devvp->v_rdev) >= nblkdev) {
303: VRELE(devvp);
304: retval = ENXIO;
305: goto error_exit;
306: };
307:
308: /*
309: * If mount by non-root, then verify that user has necessary
310: * permissions on the device.
311: */
312: if (p->p_ucred->cr_uid != 0) {
313: DBG_VFS(("hfs_mount: Checking mounting access\n"));
314: accessmode = VREAD;
315: if ((mp->mnt_flag & MNT_RDONLY) == 0)
316: accessmode |= VWRITE;
317: vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
318: if ((retval = VOP_ACCESS(devvp, accessmode, p->p_ucred, p))) {
319: VPUT(devvp);
320: goto error_exit;
321: }
322: VOP_UNLOCK(devvp, 0, p);
323: }
324:
325: /* establish the zimezone (not used by HFS Plus) */
326: gTimeZone = args.ma_timezone;
327:
328: DBG_VFS(("hfs_mount: Attempting to mount on %s\n", path));
329: retval = hfs_mountfs(devvp, mp, p);
330:
331: if (retval != E_NONE) {
332: VRELE(devvp);
333: goto error_exit;
334: };
335:
336: hfsmp = VFSTOHFS(mp);
337:
338: hfsmp->hfs_uid = args.ma_uid;
339: hfsmp->hfs_gid = args.ma_gid;
340: hfsmp->hfs_dir_mask = args.ma_mask & ALLPERMS;
341: if (args.ma_flags & HFSFSMNT_NOXONFILES)
342: hfsmp->hfs_file_mask = (args.ma_mask & DEFFILEMODE);
343: else
344: hfsmp->hfs_file_mask = args.ma_mask & ALLPERMS;
345:
346: hfsmp->hfs_encoding = args.ma_encoding;
347:
348: /* Set the mount flag to indicate that we support volfs */
349: mp->mnt_flag |= MNT_DOVOLFS;
350:
351:
352: (void) copyinstr(path, hfsmp->hfs_mountpoint, sizeof(hfsmp->hfs_mountpoint) - 1, &size);
353: bzero(hfsmp->hfs_mountpoint + size, sizeof(hfsmp->hfs_mountpoint) - size);
354: bcopy((caddr_t)hfsmp->hfs_mountpoint, (caddr_t)mp->mnt_stat.f_mntonname, MNAMELEN);
355: (void) copyinstr(args.ma_fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size);
356: bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
357: (void)hfs_statfs(mp, &mp->mnt_stat, p);
358: retval = E_NONE;
359: DBG_VFS(("hfs_mount: SUCCESSFULL MOUNT of %s on %s\n", mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname));
360:
361: goto std_exit;
362:
363: error_exit:
364: /* No special exit-path processing to do */
365: DBG_VFS(("hfs_mount: BAD MOUNT of %s on %s with an error of %d\n", mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname, retval));
366:
367: std_exit:
368: return (retval);
369:
370: }
371:
372:
373: /*
374: * Reload all incore data for a filesystem (used after running fsck on
375: * the root filesystem and finding things to fix). The filesystem must
376: * be mounted read-only.
377: *
378: * Things to do to update the mount:
379: * 1) invalidate all cached meta-data.
380: * 2) re-read superblock from disk.
381: * 3) re-read summary information from disk.
382: * 4) invalidate all inactive vnodes.
383: * 5) invalidate all cached file data.
384: * 6) re-read hfsnode data for all active vnodes.
385: */
386: int hfs_reload(mountp, cred, p)
387: register struct mount *mountp;
388: struct ucred *cred;
389: struct proc *p;
390: {
391: #if 0 /* XXX PPD */
392: register struct vnode *vp, *nvp, *devvp;
393: struct hfsnode *hp;
394: struct csum *space;
395: struct buf *bp;
396: struct hfsmount *hfsmp, *newfs;
397: struct disk_label *lab;
398: int i, blks, size, retval;
399: int32_t *lp;
400:
401: if ((mountp->mnt_flag & MNT_RDONLY) == 0)
402: return (EINVAL);
403: /*
404: * Step 1: invalidate all cached meta-data.
405: */
406: devvp = VFSTOUFS(mountp)->um_devvp;
407: if (vinvalbuf(devvp, 0, cred, p, 0, 0))
408: panic("ffs_reload: dirty1");
409: /*
410: * Step 2: re-read superblock from disk.
411: */
412:
413:
414: if (retval = bread(devvp, (ufs_daddr_t)(SBOFF/size), SBSIZE, NOCRED,&bp)) {
415: if (bp) brelse(bp);
416: return (retval);
417: };
418:
419: /*
420: * Copy pointer fields back into superblock before copying in XXX
421: * new superblock. These should really be in the HFS mount point. XXX
422: * Note that important parameters (eg fs_ncg) are unchanged.
423: */
424: bcopy(&hfsmp->hfs_fs_csp[0], &newfs->fs_csp[0], sizeof(hfsmp->hfs_fs_csp));
425: newfs->fs_maxcluster = hfsmp->hfs_fs_maxcluster;
426: bcopy(newfs, hfsmp, (u_int)hfsmp->hfs_fs_sbsize);
427: if (hfsmp->hfs_fs_sbsize < SBSIZE)
428: bp->b_flags |= B_INVAL;
429: brelse(bp);
430: mountp->mnt_maxsymlinklen = 0;
431: ffs_oldfscompat(hfsmp);
432: /*
433: * Step 3: re-read summary information from disk.
434: */
435: blks = howmany(hfsmp->hfs_fs_cssize, hfsmp->hfs_fs_fsize);
436: space = hfsmp->hfs_fs_csp[0];
437: for (i = 0; i < blks; i += hfsmp->hfs_fs_frag) {
438: size = hfsmp->hfs_fs_bsize;
439: if (i + hfsmp->hfs_fs_frag > blks)
440: size = (blks - i) * hfsmp->hfs_fs_fsize;
441: if (retval = bread(devvp, fsbtodb(hfsmp, hfsmp->hfs_fs_csaddr + i), size, NOCRED, &bp)) {
442: if (bp) brelse(bp);
443: return (retval);
444: };
445: bcopy(bp->b_data, hfsmp->hfs_fs_csp[fragstoblks(hfsmp, i)], (u_int)size);
446: brelse(bp);
447: }
448: /*
449: * We no longer know anything about clusters per cylinder group.
450: */
451: if (hfsmp->hfs_fs_contigsumsize > 0) {
452: lp = hfsmp->hfs_fs_maxcluster;
453: for (i = 0; i < hfsmp->hfs_fs_ncg; i++)
454: *lp++ = hfsmp->hfs_fs_contigsumsize;
455: }
456:
457: loop:
458: simple_lock(&mntvnode_slock);
459: for (vp = mountp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
460: if (vp->v_mount != mountp) {
461: simple_unlock(&mntvnode_slock);
462: goto loop;
463: }
464: nvp = vp->v_mntvnodes.le_next;
465: /*
466: * Step 4: invalidate all inactive vnodes.
467: */
468: if (vrecycle(vp, &mntvnode_slock, p))
469: goto loop;
470: /*
471: * Step 5: invalidate all cached file data.
472: */
473: simple_lock(&vp->v_interlock);
474: simple_unlock(&mntvnode_slock);
475: if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) {
476: goto loop;
477: }
478: if (vinvalbuf(vp, 0, cred, p, 0, 0))
479: panic("hfs_reload: dirty2");
480: /*
481: * Step 6: re-read hfsnode data for all active vnodes.
482: */
483: hp = VTOI(vp);
484: if ((retval = bread(devvp, fsbtodb(hfsmp, ino_to_fsba(hfsmp, hp->h_i_number)),
485: (int)hfsmp->hfs_fs_bsize, NOCRED, &bp))) {
486: VPUT(vp);
487: if (bp) brelse(bp);
488: return (retval);
489: }
490: hp->h_i_din = *((struct dinode *)bp->b_data +
491: ino_to_fsbo(hfsmp, hp->h_i_number));
492: brelse(bp);
493: VPUT(vp);
494: simple_lock(&mntvnode_slock);
495: }
496: simple_unlock(&mntvnode_slock);
497: #endif
498: return (0);
499: }
500:
501: /*
502: * Common code for mount and mountroot
503: */
504: int
505: hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p)
506: {
507: int retval = E_NONE;
508: register struct hfsmount *hfsmp;
509: struct buf *bp;
510: dev_t dev;
511: HFSMasterDirectoryBlock *mdbp;
512: int size, ronly;
513: struct ucred *cred;
514:
515: DBG_VFS(("hfs_mountfs: mp = 0x%lX\n", (u_long)mp));
516:
517: dev = devvp->v_rdev;
518: cred = p ? p->p_ucred : NOCRED;
519: /*
520: * Disallow multiple mounts of the same device.
521: * Disallow mounting of a device that is currently in use
522: * (except for root, which might share swap device for miniroot).
523: * Flush out any old buffers remaining from a previous use.
524: */
525: if ((retval = vfs_mountedon(devvp)))
526: return (retval);
527: if (vcount(devvp) > 1 && devvp != rootvp)
528: return (EBUSY);
529: if ((retval = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0)))
530: return (retval);
531:
532: ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
533: DBG_VFS(("hfs_mountfs: opening device...\n"));
534: if ((retval = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p)))
535: return (retval);
536:
537: size = 512;
538: DBG_VFS(("hfs_mountfs: size = %d (DEV_BSIZE = %d).\n", size, DEV_BSIZE));
539:
540: bp = NULL;
541: hfsmp = NULL;
542: DBG_VFS(("hfs_mountfs: reading MDB [block no. %d + %d bytes, size %d bytes]...\n",
543: IOBLKNOFORBLK(kMasterDirectoryBlock, size),
544: IOBYTEOFFSETFORBLK(kMasterDirectoryBlock, size),
545: IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, size)));
546:
547: if ((retval = bread(devvp, IOBLKNOFORBLK(kMasterDirectoryBlock, size),
548: IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, size), cred, &bp))) {
549: if (bp) brelse(bp);
550: goto error_exit;
551: };
552: mdbp = (HFSMasterDirectoryBlock*) ((char *)bp->b_data + IOBYTEOFFSETFORBLK(kMasterDirectoryBlock, size));
553:
554: DBG_VFS(("hfs_mountfs: allocating hfsmount structure...\n"));
555: MALLOC(hfsmp, struct hfsmount *, sizeof(struct hfsmount), M_HFSMNT, M_WAITOK);
556: bzero(hfsmp, sizeof(struct hfsmount));
557:
558: DBG_VFS(("hfs_mountfs: Initializing hfsmount structure at 0x%lX...\n", (u_long)hfsmp));
559: /*
560: * Init the volume information structure
561: */
562: mp->mnt_data = (qaddr_t)hfsmp;
563: hfsmp->hfs_mp = mp; /* Make VFSTOHFS work */
564: hfsmp->hfs_vcb.vcb_hfsmp = hfsmp; /* Make VCBTOHFS work */
565: hfsmp->hfs_raw_dev = devvp->v_rdev;
566: hfsmp->hfs_devvp = devvp;
567: hfsmp->hfs_phys_block_size = size;
568: /* The hfs_log_block_size field is updated in the respective hfs_MountHFS[Plus]Volume routine */
569: hfsmp->hfs_log_block_size = BestBlockSizeFit(mdbp->drAlBlkSiz, MAXBSIZE, hfsmp->hfs_phys_block_size);
570: hfsmp->hfs_fs_ronly = ronly;
571:
572: if (mdbp->drSigWord == kHFSPlusSigWord) {
573: DBG_VFS(("hfs_mountfs: mounting wrapper-less HFS-Plus volume...\n"));
574: retval = hfs_MountHFSPlusVolume(hfsmp, (HFSPlusVolumeHeader*) bp->b_data, 0, p);
575: }
576: else if (mdbp->drEmbedSigWord == kHFSPlusSigWord) {
577: u_long embBlkOffset;
578: HFSPlusVolumeHeader *vhp;
579:
580: embBlkOffset = (mdbp->drEmbedExtent.startBlock * (mdbp->drAlBlkSiz)/kHFSBlockSize) + mdbp->drAlBlSt;
581: DBG_VFS(("hfs_mountfs: mounting embedded HFS-Plus volume at sector %ld...\n", embBlkOffset));
582: brelse(bp);
583: bp = NULL; /* done with MDB, go grab Volume Header */
584: mdbp = NULL;
585:
586: retval = bread( devvp,
587: IOBLKNOFORBLK(kMasterDirectoryBlock+embBlkOffset, size),
588: IOBYTECCNTFORBLK(kMasterDirectoryBlock+embBlkOffset, kMDBSize, size),
589: cred,
590: &bp);
591: if (retval) {
592: if (bp) brelse(bp);
593: goto error_exit;
594: };
595: vhp = (HFSPlusVolumeHeader*) ((char *)bp->b_data + IOBYTEOFFSETFORBLK(kMasterDirectoryBlock, size));
596:
597: retval = hfs_MountHFSPlusVolume(hfsmp, vhp, embBlkOffset, p);
598: }
599: else { // pass all other volume formats to MountHFSVolume
600: DBG_VFS(("hfs_mountfs: mounting regular HFS volume...\n"));
601: retval = hfs_MountHFSVolume( hfsmp, mdbp, p);
602: }
603:
604: if ( retval ) {
605: goto error_exit;
606: }
607:
608: brelse(bp);
609: bp = NULL;
610:
611: if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
612: mp->mnt_stat.f_fsid.val[0] = (long)dev;
613: else
614: mp->mnt_stat.f_fsid.val[0] = (long)dev | HFSFSMNT_HFSSTDMASK;
615: mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
616: mp->mnt_maxsymlinklen = 0;
617: devvp->v_specflags |= SI_MOUNTEDON;
618:
619: if (ronly == 0) {
620: hfsmp->hfs_fs_clean = 0;
621: if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
622: (void) hfs_flushvolumeheader(hfsmp, MNT_WAIT);
623: else
624: (void) hfs_flushMDB(hfsmp, MNT_WAIT);
625: }
626: goto std_exit;
627:
628: error_exit:
629: DBG_VFS(("hfs_mountfs: exiting with error %d...\n", retval));
630:
631: if (bp)
632: brelse(bp);
633: (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
634: if (hfsmp) {
635: FREE(hfsmp, M_HFSMNT);
636: mp->mnt_data = (qaddr_t)0;
637: }
638:
639: std_exit:
640: return (retval);
641: }
642:
643:
644: /*
645: * Make a filesystem operational.
646: * Nothing to do at the moment.
647: */
648: /* ARGSUSED */
649: int hfs_start(mp, flags, p)
650: struct mount *mp;
651: int flags;
652: struct proc *p;
653: {
654: DBG_FUNC_NAME("hfs_start");
655: DBG_PRINT_FUNC_NAME();
656:
657: return (0);
658: }
659:
660:
661: /*
662: * unmount system call
663: */
664: int hfs_unmount(mp, mntflags, p)
665: struct mount *mp;
666: int mntflags;
667: struct proc *p;
668: {
669: struct hfsmount *hfsmp = VFSTOHFS(mp);
670: int retval = E_NONE;
671: int uflags; /* vflush flag for user vnodes pass */
672:
673: DBG_VFS(("hfs_unmount: volume: 0x%x\n", (uint)hfsmp));
674: uflags = SKIPSYSTEM;
675: if (mntflags & MNT_FORCE)
676: uflags |= FORCECLOSE;
677:
678: /*
679: * Remove any user vnodes (non-system)
680: */
681: retval = vflush(mp, NULL, uflags);
682:
683: /* Run it again, if we were busy...there might be complex nodes left */
684: if (retval == EBUSY)
685: retval = vflush(mp, NULL, uflags);
686:
687: if (retval != E_NONE)
688: return (retval);
689:
690: /*
691: * Flush out the volume bitmap and MDB/Volume Header
692: */
693: if (hfsmp->hfs_fs_ronly == 0) {
694: hfsmp->hfs_fs_clean = 1;
695: HFSTOVCB(hfsmp)->vcbAtrb |= kHFSVolumeUnmountedMask;
696: if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
697: retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT);
698: else
699: retval = hfs_flushMDB(hfsmp, MNT_WAIT);
700:
701: if (retval == 0)
702: retval = VOP_FSYNC(hfsmp->hfs_devvp, NOCRED, MNT_WAIT, p);
703:
704: if (retval) {
705: hfsmp->hfs_fs_clean = 0;
706: if ((mntflags & MNT_FORCE) == 0)
707: return (retval); /* could not flush everything */
708: }
709: }
710:
711: /*
712: * Invalidate our caches and release metadata vnodes
713: */
714: retval = hfsUnmount(hfsmp, p);
715: if(retval != E_NONE) {
716: DBG_ERR(("hfs_unmount: hfsUnmount FAILED: %d\n", retval));
717: }
718:
719: /*
720: * Remove the metadata vnodes (they should not be busy)
721: */
722: retval = vflush(mp, NULL, 0);
723: ASSERT(retval != EBUSY);
724: if (retval != E_NONE)
725: return (retval); /* XXX leaving now would be bad - we're in an inconsistent state! */
726:
727: hfsmp->hfs_devvp->v_specflags &= ~SI_MOUNTEDON;
728:
729: retval = VOP_CLOSE(hfsmp->hfs_devvp, hfsmp->hfs_fs_ronly ? FREAD : FREAD|FWRITE,
730: NOCRED, p);
731: VRELE(hfsmp->hfs_devvp);
732:
733: FREE(hfsmp, M_HFSMNT);
734: mp->mnt_data = (qaddr_t)0;
735:
736: DBG_VFS(("hfs_unmount: Finished, returning %d\n", retval));
737:
738: return(retval);
739: }
740:
741:
742: /*
743: * Return the root of a filesystem.
744: *
745: * OUT - vpp, should be locked and vget()'d (to increment usecount and lock)
746: */
747: int hfs_root(mp, vpp)
748: struct mount *mp;
749: struct vnode **vpp;
750: {
751: struct vnode *nvp;
752: int retval;
753: UInt32 rootObjID = kRootDirID;
754:
755: DBG_FUNC_NAME("hfs_root");
756: DBG_PRINT_FUNC_NAME();
757:
758: if ((retval = VFS_VGET(mp, &rootObjID, &nvp)))
759: return (retval);
760:
761: *vpp = nvp;
762: return (0);
763: }
764:
765: /*
766: * Do operations associated with quotas
767: */
768: int hfs_quotactl(mp, cmds, uid, arg, p)
769: struct mount *mp;
770: int cmds;
771: uid_t uid;
772: caddr_t arg;
773: struct proc *p;
774: {
775: DBG_FUNC_NAME("hfs_quotactl");
776: DBG_PRINT_FUNC_NAME();
777:
778: return (EOPNOTSUPP);
779: }
780:
781:
782:
783: /*
784: * Get file system statistics.
785: */
786: static int hfs_statfs(mp, sbp, p)
787: struct mount *mp;
788: register struct statfs *sbp;
789: struct proc *p;
790: {
791: ExtendedVCB *vcb = VFSTOVCB(mp);
792: struct hfsmount *hfsmp = VFSTOHFS(mp);
793: u_long freeCNIDs;
794:
795: DBG_FUNC_NAME("hfs_statfs");
796: DBG_PRINT_FUNC_NAME();
797:
798: freeCNIDs = (u_long)0xFFFFFFFF - (u_long)vcb->vcbNxtCNID;
799:
800: sbp->f_bsize = vcb->blockSize;
801: sbp->f_iosize = hfsmp->hfs_log_block_size;
802: sbp->f_blocks = vcb->totalBlocks;
803: sbp->f_bfree = vcb->freeBlocks;
804: sbp->f_bavail = vcb->freeBlocks;
805: sbp->f_files = (u_long)vcb->vcbFilCnt + (u_long)vcb->vcbDirCnt;
806: sbp->f_ffree = MIN(freeCNIDs, vcb->freeBlocks);
807:
808: sbp->f_type = 0;
809: if (sbp != &mp->mnt_stat) {
810: sbp->f_type = mp->mnt_vfc->vfc_typenum;
811: bcopy((caddr_t)mp->mnt_stat.f_mntonname,
812: (caddr_t)&sbp->f_mntonname[0], MNAMELEN);
813: bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
814: (caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
815: }
816: return (0);
817: }
818:
819:
820: /*
821: * Go through the disk queues to initiate sandbagged IO;
822: * go through the inodes to write those that have been modified;
823: * initiate the writing of the super block if it has been modified.
824: *
825: * Note: we are always called with the filesystem marked `MPBUSY'.
826: */
827: static int hfs_sync(mp, waitfor, cred, p)
828: struct mount *mp;
829: int waitfor;
830: struct ucred *cred;
831: struct proc *p;
832: {
833: struct vnode *nvp, *vp, *btvp;
834: struct hfsnode *hp;
835: struct hfsmount *hfsmp = VFSTOHFS(mp);
836: ExtendedVCB *vcb;
837: int error, allerror = 0;
838:
839: DBG_FUNC_NAME("hfs_sync");
840: DBG_PRINT_FUNC_NAME();
841:
842: hfsmp = VFSTOHFS(mp);
843: if (hfsmp->hfs_fs_ronly != 0) {
844: panic("update: rofs mod");
845: };
846:
847: /*
848: * Write back each 'modified' vnode
849: */
850: btvp = 0;
851: simple_lock(&mntvnode_slock);
852:
853: loop:;
854:
855: for (vp = mp->mnt_vnodelist.lh_first;
856: vp != NULL;
857: vp = nvp) {
858: /*
859: * If the vnode that we are about to sync is no longer
860: * associated with this mount point, start over.
861: */
862: if (vp->v_mount != mp)
863: goto loop;
864: simple_lock(&vp->v_interlock);
865: nvp = vp->v_mntvnodes.le_next;
866: hp = VTOH(vp);
867: if (H_FILEID(hp) == 3)
868: btvp = vp;
869: if ((hp->h_meta->h_nodeflags & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 &&
870: vp->v_dirtyblkhd.lh_first == NULL) {
871: simple_unlock(&vp->v_interlock);
872: continue;
873: }
874:
875: simple_unlock(&mntvnode_slock);
876: error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p);
877: DBG_ASSERT(*((int*)&vp->v_interlock) == 0);
878: if (error) {
879: DBG_ERR(("hfs_sync: error %d on vget for vnode 0x%lX.\n", error, (u_long)vp));
880: simple_lock(&mntvnode_slock);
881: if (error == ENOENT)
882: goto loop;
883: continue;
884: }
885:
886: if ((error = VOP_FSYNC(vp, cred, waitfor, p))) {
887: DBG_ERR(("hfs_sync: error %d calling fsync on vnode 0x%X.\n", error, (u_int)vp));
888: allerror = error;
889: };
890: DBG_ASSERT(*((volatile int *)(&(vp)->v_interlock))==0);
891: VPUT(vp);
892: simple_lock(&mntvnode_slock);
893: };
894:
895: /* Now reprocess the BTree node, stored above */
896: {
897: /*
898: * If the vnode that we are about to sync is no longer
899: * associated with this mount point, start over.
900: */
901: if ((btvp==0) || (btvp->v_mount != mp))
902: goto skipBtree;
903: simple_lock(&btvp->v_interlock);
904: hp = VTOH(btvp);
905: if ((hp->h_meta->h_nodeflags & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 &&
906: btvp->v_dirtyblkhd.lh_first == NULL) {
907: simple_unlock(&btvp->v_interlock);
908: goto skipBtree;
909: }
910: simple_unlock(&mntvnode_slock);
911: error = vget(btvp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p);
912: if (error) {
913: simple_lock(&mntvnode_slock);
914: goto skipBtree;
915: }
916: if ((error = VOP_FSYNC(btvp, cred, waitfor, p)))
917: allerror = error;
918: VOP_UNLOCK(btvp, 0, p);
919: VRELE(btvp);
920: simple_lock(&mntvnode_slock);
921: };
922:
923: skipBtree:;
924:
925: simple_unlock(&mntvnode_slock);
926:
927: /*
928: * Force stale file system control information to be flushed.
929: */
930: if ((error = VOP_FSYNC(hfsmp->hfs_devvp, cred, waitfor, p)))
931: allerror = error;
932: /*
933: * Write back modified superblock.
934: */
935: vcb = HFSTOVCB(hfsmp);
936:
937: if (IsVCBDirty(vcb)) {
938: if (vcb->vcbSigWord == kHFSPlusSigWord)
939: error = hfs_flushvolumeheader(hfsmp, waitfor);
940: else
941: error = hfs_flushMDB(hfsmp, waitfor);
942:
943: if (error)
944: allerror = error;
945: };
946:
947: return (allerror);
948: }
949:
950:
951: /*
952: * File handle to vnode
953: *
954: * Have to be really careful about stale file handles:
955: * - check that the hfsnode number is valid
956: * - call hfs_vget() to get the locked hfsnode
957: * - check for an unallocated hfsnode (i_mode == 0)
958: * - check that the given client host has export rights and return
959: * those rights via. exflagsp and credanonp
960: */
961: int
962: hfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
963: register struct mount *mp;
964: struct fid *fhp;
965: struct mbuf *nam;
966: struct vnode **vpp;
967: int *exflagsp;
968: struct ucred **credanonp;
969: {
970: DBG_FUNC_NAME("hfs_fhtovp");
971: DBG_PRINT_FUNC_NAME();
972:
973: return (EOPNOTSUPP);
974: }
975:
976: /*
977: * Vnode pointer to File handle
978: */
979: /* ARGSUSED */
980: static int hfs_vptofh(vp, fhp)
981: struct vnode *vp;
982: struct fid *fhp;
983: {
984: DBG_FUNC_NAME("hfs_vptofh");
985: DBG_PRINT_FUNC_NAME();
986:
987: return (EOPNOTSUPP);
988: }
989:
990:
991:
992: /*
993: * Initial HFS filesystems, done only once.
994: */
995: int
996: hfs_init(vfsp)
997: struct vfsconf *vfsp;
998: {
999: int i;
1000: static int done = 0;
1001: OSErr err;
1002:
1003: DBG_FUNC_NAME("hfs_init");
1004: DBG_PRINT_FUNC_NAME();
1005:
1006: if (done)
1007: return (0);
1008: done = 1;
1009: hfs_vhashinit();
1010:
1011: simple_lock_init (&gBufferPtrListLock);
1012:
1013: for (i = BUFFERPTRLISTSIZE - 1; i >= 0; --i) {
1014: gBufferAddress[i] = NULL;
1015: gBufferHeaderPtr[i] = NULL;
1016: };
1017: gBufferListIndex = 0;
1018:
1019: /*
1020: * Do any initialization that the MacOS/Rhapsody shared code relies on
1021: * (normally done as part of MacOS's startup):
1022: */
1023: MALLOC(gFSMVars, FSVarsRec *, sizeof(FSVarsRec), M_HFSMNT, M_WAITOK);
1024: bzero(gFSMVars, sizeof(FSVarsRec));
1025:
1026: /*
1027: * Allocate Catalog Iterator cache...
1028: */
1029: err = InitCatalogCache();
1030: #if DIAGNOSTIC
1031: if (err) PANIC("hfs_init: Error returned from InitCatalogCache() call.");
1032: #endif
1033: /*
1034: * XXX do we need to setup the following?
1035: *
1036: * GMT offset, Unicode globals, CatSearch Buffers, BTSscanner
1037: */
1038:
1039: return E_NONE;
1040: }
1041:
1042: /*
1043: * fast filesystem related variables.
1044: */
1045: static int hfs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
1046: int *name;
1047: u_int namelen;
1048: void *oldp;
1049: size_t *oldlenp;
1050: void *newp;
1051: size_t newlen;
1052: struct proc *p;
1053: {
1054: DBG_FUNC_NAME("hfs_sysctl");
1055: DBG_PRINT_FUNC_NAME();
1056:
1057: return (EOPNOTSUPP);
1058: }
1059:
1060: /* This will return a vnode or either a directory or a data vnode based on an object id. If
1061: * it is a file id, its data fork will be returned.
1062: */
1063:
1064: int hfs_vget(struct mount *mp,
1065: void *ino,
1066: struct vnode **vpp)
1067: {
1068: struct hfsmount *hfsmp;
1069: struct proc *p;
1070: dev_t dev;
1071: hfsCatalogInfo catInfo;
1072: UInt8 forkType;
1073: int retval = E_NONE;
1074:
1075: DBG_VFS(("hfs_vget: ino = %ld\n", *(UInt32 *)ino));
1076:
1077: hfsmp = VFSTOHFS(mp);
1078: p = CURRENT_PROC;
1079: dev = hfsmp->hfs_raw_dev;
1080:
1081: /* First check to see if it is in the cache */
1082: /* If it is, and it is complex, check again if its data fork is there */
1083: *vpp = hfs_vhashget(dev, *(UInt32 *)ino, kDirCmplx);
1084: if (*vpp && (*vpp)->v_type == VCPLX) {
1085: vput(*vpp);
1086: *vpp = hfs_vhashget(dev, *(UInt32 *)ino, kDataFork);
1087: }
1088:
1089: /* The vnode is not in the cache, so lets make it */
1090: if (*vpp == NULL)
1091: {
1092: /* lock catalog b-tree */
1093: retval = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_SHARED, p);
1094: if (retval != E_NONE) goto Err_Exit;
1095:
1096: retval = hfsLookup(VFSTOVCB(mp), *(UInt32 *)ino, NULL, -1, 0, &catInfo);
1097:
1098: /* unlock catalog b-tree */
1099: (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p);
1100:
1101: if (retval != E_NONE) goto Err_Exit;
1102:
1103: forkType = (catInfo.nodeData.nodeType == kCatalogFolderNode) ? kDirCmplx : kDataFork;
1104: retval = hfsGet(VFSTOVCB(mp), &catInfo, forkType, NULL, vpp);
1105: }
1106:
1107: #if MACH_NBC
1108: if (*vpp && ((*vpp)->v_type == VREG) && !((*vpp)->v_vm_info)){
1109: vm_info_init(*vpp);
1110: }
1111: #endif /* MACH_NBC */
1112:
1113: Err_Exit:
1114:
1115: if (retval != E_NONE) {
1116: DBG_VFS(("hfs_vget: Error returned of %d\n", retval));
1117: }
1118: else {
1119: DBG_VFS(("hfs_vget: vp = 0x%x\n", (u_int)*vpp));
1120: }
1121:
1122: return (retval);
1123:
1124: }
1125:
1126: short hfs_flushfiles(struct mount *mp, unsigned short flags)
1127: {
1128: int retval;
1129:
1130: DBG_FUNC_NAME("hfs_flushfiles");
1131: DBG_PRINT_FUNC_NAME();
1132:
1133: retval = vflush(mp, VFSTOVCB(mp)->catalogRefNum, flags);
1134: if (retval) return retval;
1135: DBG_VFS(("\tAll files except Catalog is flushed\n"));
1136:
1137: /* Now 'close' the catalog Btree, and then flush it */
1138: VRELE(VFSTOVCB(mp)->catalogRefNum);
1139: retval = vflush(mp, NULL, flags);
1140: DBG_VFS(("\tCatalog is now flushed\n"));
1141: return (retval);
1142: }
1143:
1144:
1145: short hfs_flushMDB(struct hfsmount *hfsmp, int waitfor)
1146: {
1147: ExtendedVCB *vcb = HFSTOVCB(hfsmp);
1148: FCB *fcb;
1149: HFSMasterDirectoryBlock *mdb;
1150: struct buf *bp;
1151: int retval;
1152: int size = kMDBSize; /* 512 */
1153: size_t namelen;
1154:
1155: if (vcb->vcbSigWord != kHFSSigWord)
1156: return EINVAL;
1157:
1158: ASSERT(hfsmp->hfs_devvp != NULL);
1159:
1160: retval = bread(hfsmp->hfs_devvp, IOBLKNOFORBLK(kMasterDirectoryBlock, size),
1161: IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, size), NOCRED, &bp);
1162: if (retval) {
1163: DBG_VFS((" hfs_flushMDB bread return error! (%d)\n", retval));
1164: if (bp) brelse(bp);
1165: return retval;
1166: }
1167:
1168: ASSERT(bp != NULL);
1169: ASSERT(bp->b_data != NULL);
1170: ASSERT(bp->b_bcount == size);
1171:
1172: mdb = (HFSMasterDirectoryBlock *)((char *)bp->b_data + IOBYTEOFFSETFORBLK(kMasterDirectoryBlock, size));
1173:
1174: VCB_LOCK(vcb);
1175: mdb->drCrDate = vcb->vcbCrDate;
1176: mdb->drLsMod = vcb->vcbLsMod;
1177: mdb->drAtrb = vcb->vcbAtrb;
1178: mdb->drNmFls = vcb->vcbNmFls;
1179: mdb->drAllocPtr = vcb->nextAllocation;
1180: mdb->drClpSiz = vcb->vcbClpSiz;
1181: mdb->drNxtCNID = vcb->vcbNxtCNID;
1182: mdb->drFreeBks = vcb->freeBlocks;
1183:
1184: copystr(vcb->vcbVN, &mdb->drVN[1], sizeof(mdb->drVN)-1, &namelen);
1185: mdb->drVN[0] = namelen-1;
1186: mdb->drVN[namelen] = '\0';
1187:
1188: mdb->drVolBkUp = vcb->vcbVolBkUp;
1189: mdb->drVSeqNum = vcb->vcbVSeqNum;
1190: mdb->drWrCnt = vcb->vcbWrCnt;
1191: mdb->drNmRtDirs = vcb->vcbNmRtDirs;
1192: mdb->drFilCnt = vcb->vcbFilCnt;
1193: mdb->drDirCnt = vcb->vcbDirCnt;
1194:
1195: bcopy(vcb->vcbFndrInfo, mdb->drFndrInfo, sizeof(mdb->drFndrInfo));
1196:
1197: fcb = VTOFCB(vcb->extentsRefNum);
1198: bcopy(fcb->fcbExtRec, mdb->drXTExtRec, sizeof(HFSExtentRecord));
1199: mdb->drXTFlSize = fcb->fcbPLen;
1200: mdb->drXTClpSiz = fcb->fcbClmpSize;
1201:
1202: fcb = VTOFCB(vcb->catalogRefNum);
1203: bcopy(fcb->fcbExtRec, mdb->drCTExtRec, sizeof(HFSExtentRecord));
1204: mdb->drCTFlSize = fcb->fcbPLen;
1205: mdb->drCTClpSiz = fcb->fcbClmpSize;
1206: VCB_UNLOCK(vcb);
1207:
1208:
1209: if (waitfor != MNT_WAIT)
1210: bawrite(bp);
1211: else
1212: retval = bwrite(bp);
1213:
1214: MarkVCBClean( vcb );
1215:
1216: return (retval);
1217: }
1218:
1219:
1220: short hfs_flushvolumeheader(struct hfsmount *hfsmp, int waitfor)
1221: {
1222: ExtendedVCB *vcb = HFSTOVCB(hfsmp);
1223: ExtendedFCB *extendedFCB;
1224: FCB *fcb;
1225: HFSPlusVolumeHeader *volumeHeader;
1226: struct vnode *vp;
1227: int retval;
1228: int size = sizeof(HFSPlusVolumeHeader);
1229: struct buf *bp;
1230:
1231: if (vcb->vcbSigWord != kHFSPlusSigWord)
1232: return EINVAL;
1233:
1234: retval = bread(hfsmp->hfs_devvp, IOBLKNOFORBLK((vcb->hfsPlusIOPosOffset / 512) + kMasterDirectoryBlock, size),
1235: IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, size), NOCRED, &bp);
1236: if (retval) {
1237: DBG_VFS((" hfs_flushvolumeheader bread return error! (%d)\n", retval));
1238: if (bp) brelse(bp);
1239: return retval;
1240: }
1241:
1242: ASSERT(bp != NULL);
1243: ASSERT(bp->b_data != NULL);
1244: ASSERT(bp->b_bcount == size);
1245:
1246: volumeHeader = (HFSPlusVolumeHeader *)((char *)bp->b_data +
1247: IOBYTEOFFSETFORBLK((vcb->hfsPlusIOPosOffset / 512) + kMasterDirectoryBlock, size));
1248:
1249: /*
1250: * For embedded HFS+ volumes, update create date if neccessary
1251: */
1252: if (vcb->hfsPlusIOPosOffset != 0 && volumeHeader->createDate != vcb->vcbCrDate)
1253: {
1254: struct buf *bp2;
1255: HFSMasterDirectoryBlock *mdb;
1256:
1257: retval = bread(hfsmp->hfs_devvp, IOBLKNOFORBLK(kMasterDirectoryBlock, kMDBSize),
1258: IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, kMDBSize), NOCRED, &bp2);
1259: if (retval != E_NONE) {
1260: if (bp2) brelse(bp2);
1261: } else {
1262: mdb = (HFSMasterDirectoryBlock *)((char *)bp2->b_data + IOBYTEOFFSETFORBLK(kMasterDirectoryBlock, kMDBSize));
1263: if ( mdb->drCrDate != vcb->vcbCrDate )
1264: {
1265: mdb->drCrDate = vcb->vcbCrDate; /* ppick up the new create date */
1266: (void) bwrite(bp2); /* write out the changes */
1267: }
1268: else
1269: {
1270: brelse(bp2); /* just release it */
1271: }
1272: }
1273: }
1274:
1275: VCB_LOCK(vcb);
1276: /* Note: only update the lower 16 bits worth of attributes */
1277: volumeHeader->attributes = (volumeHeader->attributes & 0xFFFF0000) + (UInt16) vcb->vcbAtrb;
1278: volumeHeader->lastMountedVersion = kHFSPlusMountVersion;
1279: volumeHeader->createDate = vcb->vcbCrDate;
1280: volumeHeader->modifyDate = LocalToUTC(vcb->vcbLsMod);
1281: volumeHeader->backupDate = LocalToUTC(vcb->vcbVolBkUp);
1282: volumeHeader->checkedDate = vcb->checkedDate;
1283: volumeHeader->fileCount = vcb->vcbFilCnt;
1284: volumeHeader->folderCount = vcb->vcbDirCnt;
1285: // volumeHeader->blockSize = vcb->blockSize;
1286: // volumeHeader->totalBlocks = vcb->totalBlocks;
1287: volumeHeader->freeBlocks = vcb->freeBlocks;
1288: volumeHeader->nextAllocation = vcb->nextAllocation;
1289: volumeHeader->rsrcClumpSize = vcb->vcbClpSiz;
1290: volumeHeader->dataClumpSize = vcb->vcbClpSiz;
1291: volumeHeader->nextCatalogID = vcb->vcbNxtCNID;
1292: volumeHeader->writeCount = vcb->vcbWrCnt;
1293: volumeHeader->encodingsBitmap = vcb->encodingsBitmap;
1294:
1295: //XXX djb should we use the vcb or fcb clumpSize values?
1296: volumeHeader->allocationFile.clumpSize = vcb->allocationsClumpSize;
1297: volumeHeader->extentsFile.clumpSize = vcb->vcbXTClpSiz;
1298: volumeHeader->catalogFile.clumpSize = vcb->vcbCTClpSiz;
1299:
1300: bcopy( vcb->vcbFndrInfo, volumeHeader->finderInfo, sizeof(volumeHeader->finderInfo) );
1301:
1302: VCB_UNLOCK(vcb);
1303:
1304: vp = vcb->extentsRefNum;
1305: extendedFCB = GetParallelFCB(vp);
1306: bcopy( extendedFCB->extents, volumeHeader->extentsFile.extents, sizeof(HFSPlusExtentRecord) );
1307: fcb = VTOFCB(vp);
1308: volumeHeader->extentsFile.logicalSize.lo = fcb->fcbEOF;
1309: volumeHeader->extentsFile.logicalSize.hi = 0;
1310: volumeHeader->extentsFile.totalBlocks = fcb->fcbPLen / vcb->blockSize;
1311:
1312: vp = vcb->catalogRefNum;
1313: extendedFCB = GetParallelFCB(vp);
1314: bcopy( extendedFCB->extents, volumeHeader->catalogFile.extents, sizeof(HFSPlusExtentRecord) );
1315: fcb = VTOFCB(vp);
1316: volumeHeader->catalogFile.logicalSize.lo = fcb->fcbPLen;
1317: volumeHeader->catalogFile.logicalSize.hi = 0;
1318: volumeHeader->catalogFile.totalBlocks = fcb->fcbPLen / vcb->blockSize;
1319:
1320: vp = vcb->allocationsRefNum;
1321: extendedFCB = GetParallelFCB(vp);
1322: bcopy( extendedFCB->extents, volumeHeader->allocationFile.extents, sizeof(HFSPlusExtentRecord) );
1323: fcb = VTOFCB(vp);
1324: volumeHeader->allocationFile.logicalSize.lo = fcb->fcbPLen;
1325: volumeHeader->allocationFile.logicalSize.hi = 0;
1326: volumeHeader->allocationFile.totalBlocks = fcb->fcbPLen / vcb->blockSize;
1327:
1328: vp = vcb->attributesRefNum;
1329: if (vp != 0) // Only update fields if an attributes file existed and was open
1330: {
1331: extendedFCB = GetParallelFCB(vp);
1332: bcopy( extendedFCB->extents, volumeHeader->attributesFile.extents, sizeof(HFSPlusExtentRecord) );
1333: fcb = VTOFCB(vp);
1334: volumeHeader->attributesFile.logicalSize.lo = fcb->fcbPLen;
1335: volumeHeader->attributesFile.logicalSize.hi = 0;
1336: volumeHeader->attributesFile.clumpSize = fcb->fcbClmpSize;
1337: volumeHeader->attributesFile.totalBlocks = fcb->fcbPLen / vcb->blockSize;
1338: }
1339:
1340: if (waitfor != MNT_WAIT)
1341: bawrite(bp);
1342: else
1343: retval = bwrite(bp);
1344:
1345: MarkVCBClean( vcb );
1346:
1347: return (retval);
1348: }
1349:
1350:
1351: /*
1352: * Moved here to avoid having to define prototypes
1353: */
1354:
1355: /*
1356: * hfs vfs operations.
1357: */
1358: struct vfsops hfs_vfsops = {
1359: hfs_mount,
1360: hfs_start,
1361: hfs_unmount,
1362: hfs_root,
1363: hfs_quotactl,
1364: hfs_statfs,
1365: hfs_sync,
1366: hfs_vget,
1367: hfs_fhtovp,
1368: hfs_vptofh,
1369: hfs_init,
1370: hfs_sysctl
1371: };
1372:
1373: void
1374: load_hfs(int loadArgument) {
1375: struct vfsconf *vfsconflistentry;
1376: int entriesRemaining;
1377: struct vfsconf *newvfsconf = NULL;
1378: struct vfsconf *lastentry = NULL;
1379: int j;
1380: int (***opv_desc_vector_p)();
1381: int (**opv_desc_vector)();
1382: struct vnodeopv_entry_desc *opve_descp;
1383:
1384: #pragma unused(loadArgument)
1385:
1386: /*
1387: * This routine is responsible for all the initialization that would
1388: * ordinarily be done as part of the system startup; it calls hfs_init
1389: * to do the initialization that is strictly HFS-specific.
1390: */
1391:
1392: #if DIAGNOSTIC
1393: // call_kdp();
1394: #endif
1395: DBG_LOAD(("load_hfs: Starting...\n"));
1396:
1397: /*
1398: prevvfsconf is supposed to be the entry preceding the new entry.
1399: To make sure we can always get hooked in SOMEWHERE in the list,
1400: start it out at the first entry of the list. This assumes the
1401: first entry in the list will be non-empty and not HFS.
1402:
1403: This becomes irrelevant when HFS is compiled into the list.
1404: */
1405: DBG_LOAD(("load_hfs: Scanning vfsconf list...\n"));
1406: vfsconflistentry = vfsconf;
1407: for (entriesRemaining = maxvfsslots; entriesRemaining > 0; --entriesRemaining) {
1408: if (vfsconflistentry->vfc_vfsops != NULL) {
1409: /*
1410: * Check to see if we're reloading a new version of hfs during debugging
1411: * and overwrite the previously assigned entry if we find one:
1412: */
1413: if (strcmp(vfsconflistentry->vfc_name, hfs_fs_name) == 0) {
1414: newvfsconf = vfsconflistentry;
1415: break;
1416: } else {
1417: lastentry = vfsconflistentry;
1418: };
1419: } else {
1420: /*
1421: * This is at least a POSSIBLE place to insert the new entry...
1422: */
1423: newvfsconf = vfsconflistentry;
1424: };
1425: ++vfsconflistentry;
1426: };
1427:
1428: if (newvfsconf) {
1429: DBG_LOAD(("load_hfs: filling in vfsconf entry at 0x%X; lastentry = 0x%X.\n", (u_int)newvfsconf, (u_int)lastentry));
1430: newvfsconf->vfc_vfsops = &hfs_vfsops;
1431: strncpy(&newvfsconf->vfc_name[0], hfs_fs_name, MFSNAMELEN);
1432: newvfsconf->vfc_typenum = maxvfsconf++;
1433: newvfsconf->vfc_refcount = 0;
1434: newvfsconf->vfc_flags = 0;
1435: newvfsconf->vfc_mountroot = NULL; /* Can't mount root of file system [yet] */
1436:
1437: /* Hook into the list: */
1438: newvfsconf->vfc_next = NULL;
1439: if (lastentry) {
1440: newvfsconf->vfc_next = lastentry->vfc_next;
1441: lastentry->vfc_next = newvfsconf;
1442: };
1443:
1444: /* Based on vfs_op_init and ... */
1445: opv_desc_vector_p = hfs_vnodeop_opv_desc.opv_desc_vector_p;
1446:
1447: DBG_LOAD(("load_hfs: Allocating and initializing VNode ops vector...\n"));
1448:
1449: /*
1450: * Allocate and init the vector.
1451: * Also handle backwards compatibility.
1452: */
1453: MALLOC(*opv_desc_vector_p, PFI *, vfs_opv_numops*sizeof(PFI), M_TEMP, M_WAITOK);
1454: bzero (*opv_desc_vector_p, vfs_opv_numops*sizeof(PFI));
1455:
1456: opv_desc_vector = *opv_desc_vector_p;
1457: for (j=0; hfs_vnodeop_opv_desc.opv_desc_ops[j].opve_op; j++) {
1458: opve_descp = &(hfs_vnodeop_opv_desc.opv_desc_ops[j]);
1459:
1460: /*
1461: * Sanity check: is this operation listed
1462: * in the list of operations? We check this
1463: * by seeing if its offest is zero. Since
1464: * the default routine should always be listed
1465: * first, it should be the only one with a zero
1466: * offset. Any other operation with a zero
1467: * offset is probably not listed in
1468: * vfs_op_descs, and so is probably an error.
1469: *
1470: * A panic here means the layer programmer
1471: * has committed the all-too common bug
1472: * of adding a new operation to the layer's
1473: * list of vnode operations but
1474: * not adding the operation to the system-wide
1475: * list of supported operations.
1476: */
1477: if (opve_descp->opve_op->vdesc_offset == 0 &&
1478: opve_descp->opve_op->vdesc_offset != VOFFSET(vop_default)) {
1479: printf("load_hfs: operation %s not listed in %s.\n",
1480: opve_descp->opve_op->vdesc_name,
1481: "vfs_op_descs");
1482: panic ("load_hfs: bad operation");
1483: }
1484: /*
1485: * Fill in this entry.
1486: */
1487: opv_desc_vector[opve_descp->opve_op->vdesc_offset] =
1488: opve_descp->opve_impl;
1489: }
1490:
1491: /*
1492: * Finally, go back and replace unfilled routines
1493: * with their default. (Sigh, an O(n^3) algorithm. I
1494: * could make it better, but that'd be work, and n is small.)
1495: */
1496: opv_desc_vector_p = hfs_vnodeop_opv_desc.opv_desc_vector_p;
1497:
1498: /*
1499: * Force every operations vector to have a default routine.
1500: */
1501: opv_desc_vector = *opv_desc_vector_p;
1502: if (opv_desc_vector[VOFFSET(vop_default)]==NULL) {
1503: panic("load_hfs: operation vector without default routine.");
1504: }
1505: for (j = 0;j<vfs_opv_numops; j++)
1506: if (opv_desc_vector[j] == NULL)
1507: opv_desc_vector[j] =
1508: opv_desc_vector[VOFFSET(vop_default)];
1509:
1510: DBG_LOAD(("load_hfs: calling hfs_init()...\n"));
1511: hfs_init(newvfsconf);
1512: };
1513: }
1514:
1515: void
1516: unload_hfs(int unloadArgument) {
1517: int entriesRemaining;
1518: struct vfsconf *vfsconflistentry;
1519: struct vfsconf *prevconf = NULL;
1520: struct vfsconf *hfsconf = NULL;
1521:
1522: DBG_LOAD(("unload_hfs: removing HFS from vfs conf. list...\n"));
1523:
1524: prevconf = vfsconflistentry = vfsconf;
1525: for (entriesRemaining = maxvfsslots;
1526: (entriesRemaining > 0) && (vfsconflistentry != NULL);
1527: --entriesRemaining) {
1528: if ((vfsconflistentry->vfc_vfsops != NULL) && (strcmp(vfsconflistentry->vfc_name, hfs_fs_name) == 0)) {
1529: hfsconf = vfsconflistentry;
1530: break;
1531: };
1532: prevconf = vfsconflistentry;
1533: vfsconflistentry = vfsconflistentry->vfc_next;
1534: };
1535:
1536: if (hfsconf != NULL) {
1537: if (prevconf != NULL) {
1538: /* Unlink the HFS entry from the list: */
1539: prevconf->vfc_next = hfsconf->vfc_next;
1540: } else {
1541: DBG_LOAD(("unload_hfs: no previous entry in list.\n"));
1542: }
1543: } else {
1544: DBG_LOAD(("unload_hfs: couldn't find hfs conf. list entry.\n"));
1545: };
1546:
1547: FREE(*hfs_vnodeop_opv_desc.opv_desc_vector_p, M_TEMP);
1548: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.