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