|
|
1.1 root 1: /*
2: * Copyright (c) 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: /* @(#)hfs_vnodeops.c 3.0
23: *
24: * (c) 1997-1999 Apple Computer, Inc. All Rights Reserved
25: * (c) 1990, 1992 NeXT Computer, Inc. All Rights Reserved
26: *
27: *
28: * hfs_vnodeops.c -- vnode layer for loadable Macintosh file system
29: *
30: * MODIFICATION HISTORY:
31: * 11-Nov-1999 Scott Roberts Does not update if times have not changed (#2409116)
32: * 9-Nov-1999 Scott Roberts Added cluster_close to hfs_fsync(#2398208)
33: * 9-Nov-1999 Don Brady Fix locking bug in hfs_close [#2399157].
34: * 15-Sep-1999 Pat Dirks Changed hfs_setattrlist to allow changing flags on plain-HFS volumes w/o ownership [#2365108];
35: * Changed to use hfs_write_access instead of obsolete hfs_writepermission uniformly throughout.
36: * 7-Sep-1999 Don Brady Add HFS Plus hard-link support.
37: * 8-Sep-1999 Pat Dirks Changed hfs_rename to change mod. date on parent directory [#2297825].
38: * 26-Aug-1999 Pat Dirks Changed hfs_chflags to allow locking on HFS volumes w. write access only as workaround [#2313439].
39: * 2-Sep-1999 Pat Dirks Fixed hfs_pathconf to return same info for hfs/hfs+ for max. name length [#2382208]
40: * 26-Aug-1999 Pat Dirks Changed hfs_chflags to allow locking on HFS volumes w. write access only as workaround [#2313439].
41: * 24-Jul-1999 Earsh Nandkeshwar Rewrote readdirattr.
42: * 15-Jul-1999 Pat Dirks Fixed hfs_readdir to return EINVAL if design assumption of uio->uio_iovcnt�== 1 is violated
43: * and cleaned up call to uiomove to check space available first.
44: * 2-Jul-1999 Pat Dirks Fixed hfs_setattrlist to ignore attempts to set null volume name (#2331829).
45: * 18-May-1999 Don Brady Add support for rooting from HFS Plus.
46: * 4-May-1999 Don Brady Split off hfs_search.c
47: * 15-Apr-1999 Don Brady Change va_nlink back to 1 for directories in hfs_getattr.
48: * 6-Apr-1999 Don Brady Fix deference of NULL h_sibling in hfs_chid.
49: * 29-Mar-1999 Scott Roberts Put in the correct . and .. entries for readdir
50: * 22-Mar-1999 Don Brady Add UFS delete semantic support to hfs_remove.
51: * 1-Mar-1999 Scott Roberts h_meta is now released when the complex vnode is relesed
52: * 26-Feb-1999 Pat Dirks (copied by Chw) Fixed hfs_lookup to check for
53: * error return on vget.
54: * 25-Feb-1999 Pat Dirks Fixed hfs_remove to use a local copy of the h_sibling pointer around vnode_uncache.
55: * 3-Feb-1999 Pat Dirks Changed to stop updating wrapper volume name in MDB since wrapper volume's
56: * catalog isn't updated and this inconsistency trips Disk First Aid's checks.
57: * 22-Jan-1999 Pat Dirks Changed hfs_rename, hfs_remove, and hfs_rmdir to call cache_purge.
58: * 22-Jan-1999 Don Brady After calling hfsMoveRename call hfsLookup to get new name.
59: * 12-Jan-1999 Don Brady Fixed the size of ATTR_CMN_NAME buffer to NAME_MAX + 1.
60: * 8-Jan-1999 Pat Dirks Added hfs_writepermission and change hfs_setattrlist to use it instead of
61: * including an incorrect derivative of hfs_access in-line.
62: * 15-Dec-1998 Pat Dirks Changed setattrlist to do permission checking as appropriate (Radar #2290212).
63: * 17-Nov-1998 Scott Roberts Added support for long volume names in SetAttrList().
64: * 6-Nov-1998 Don Brady Add support for UTF-8 names.
65: * 3-Nov-1998 Umesh Vaishampayan Changes to deal with "struct timespec"
66: * change in the kernel.
67: * 21-Oct-1998 Scott Roberts Added support for advisory locking (Radar #2237914).
68: * 25-Sep-1998 Don Brady Changed hfs_exchange to call hfs_chid after updating catalog (radar #2276605).
69: * 23-Sep-1998 Don Brady hfs_setattrlist now calls hfs_chown and hfs_chmod to change values.
70: * 15-Sep-1998 Pat Dirks Cleaned up vnode unlocking on various error exit paths and changed
71: * to use new error stub routines in place of hfs_mknod and hfs_link.
72: * 16-Sep-1998 Don Brady When renaming a volume in hfs_setattrlist, also update hfs+ wrapper name (radar #2272925).
73: * 1-Sep-1998 Don Brady Fix uninitiazed time variable in hfs_makenode (radar #2270372).
74: * 31-Aug-1998 Don Brady Adjust change time for DST in hfs_update (radar #2265075).
75: * 12-Aug-1998 Don Brady Update complex node name in hfs_rename (radar #2262111).
76: * 5-Aug-1998 Don Brady In hfs_setattrlist call MacToVFSError after calling UpdateCatalogNode (radar #2261247).
77: * 21-Jul-1998 Don Brady Fixed broken preflight in hfs_getattrlist.
78: * 17-Jul-1998 Clark Warner Fixed the one left out case of freeing M_NAMEI in hfs_abort
79: * 13-Jul-1998 Don Brady Add uio_resid preflight check to hfs_search (radar #2251855).
80: * 30-Jun-1998 Scott Roberts Changed hfs_makenode and its callers to free M_NAMEI.
81: * 29-Jun-1998 Don Brady Fix unpacking order in UnpackSearchAttributeBlock (radar #2249248).
82: * 13-Jun-1998 Scott Roberts Integrated changes to hfs_lock (radar #2237243).
83: * 4-Jun-1998 Pat Dirks Split off hfs_lookup.c and hfs_readwrite.c
84: * 3-Jun-1998 Don Brady Fix hfs_rename bugs (radar #2229259, #2239823, 2231108 and #2237380).
85: * Removed extra vputs in hfs_rmdir (radar #2240309).
86: * 28-May-1998 Don Brady Fix hfs_truncate to correctly extend files (radar #2237242).
87: * 20-May-1998 Don Brady In hfs_close shrink the peof to the smallest size neccessary (radar #2230094).
88: * 5-May-1998 Don Brady Fixed typo in hfs_rename (apply H_FILEID macro to VTOH result).
89: * 29-Apr-1998 Joe Sokol Don't do cluster I/O when logical block size is not 4K multiple.
90: * 28-Apr-1998 Pat Dirks Cleaned up unused variable physBlockNo in hfs_write.
91: * 28-Apr-1998 Joe Sokol Touched up support for cluster_read/cluster_write and enabled it.
92: * 27-Apr-1998 Don Brady Remove some DEBUG_BREAK calls in DbgVopTest.
93: * 24-Apr-1998 Pat Dirks Fixed read logic to read-ahead only ONE block, and of only logBlockSize instead of 64K...
94: * Added calls to brelse() on errors from bread[n]().
95: * Changed logic to add overall length field to AttrBlockSize only on attribute return operations.
96: * 23-Apr-1998 Don Brady The hfs_symlink call is only supported on HFS Plus disks.
97: * 23-Apr-1998 Deric Horn Fixed hfs_search bug where matches were skipped when buffer was full.
98: * 22-Apr-1998 Scott Roberts Return on error if catalog mgr returns an error in truncate.
99: * 21-Apr-1998 Don Brady Fix up time/date conversions.
100: * 20-Apr-1998 Don Brady Remove course-grained hfs metadata locking.
101: * 17-Apr-1998 Pat Dirks Officially enabled searchfs in vops table.
102: * 17-Apr-1998 Deric Horn Bug fixes to hfs_search, reenabled searchfs trap for upcoming kernel build.
103: * 15-Apr-1998 Don Brady Add locking for HFS B-trees. Don't lock file meta lock for VSYSTEM files.
104: * Don't call VOP_UPDATE for system files. Roll set_time into hfs_update.
105: * 14-Apr-1998 Pat Dirks Cleaned up fsync to skip complex nodes and not hit sibling nodes.
106: * 14-Apr-1998 Deric Horn Added hfs_search() and related routines for searchfs() support.
107: * 14-Apr-1998 Scott Roberts Fixed paramaters to ExchangeFileIDs()
108: * 13-Apr-1998 Pat Dirks Changed to update H_HINT whenever hfsLookup was called.
109: * 8-Apr-1998 Pat Dirks Added page-in and page-out passthrough routines to keep MapFS happy.
110: * 6-Apr-1998 Pat Dirks Changed hfs_write to clean up code and fix bug that caused
111: * zeroes to be interspersed in data. Added debug printf to hfs_read.
112: * 6-Apr-1998 Scott Roberts Added complex file support.
113: * 02-apr-1998 Don Brady UpdateCatalogNode now takes parID and name as input.
114: * 31-mar-1998 Don Brady Sync up with final HFSVolumes.h header file.
115: * 27-mar-1998 Don Brady Check result from UFSToHFSStr to make sure hfs/hfs+ names are not greater than 31 characters.
116: * 27-mar-1998 chw minor link fixes.
117: * 19-Mar-1998 ser Added hfs_readdirattr.
118: * 17-Mar-1998 ser Removed CheckUserAccess. Added code to implement ExchangeFileIDs
119: * 16-Mar-1998 Pat Dirks Fixed logic in hfs_read to properly account for space
120: * remaining past selected offset and avoid premature panic.
121: * 16-jun-1997 Scott Roberts
122: * Dec-1991 Kevin Wells at NeXT:
123: * Significantly modified for Macintosh file system.
124: * Added support for NFS exportability.
125: * 25-Jun-1990 Doug Mitchell at NeXT:
126: * Created (for DOS file system).
127: */
128:
129: #include <sys/systm.h>
130: #include <sys/kernel.h>
131: #include <sys/file.h>
132: #include <sys/dirent.h>
133: #include <sys/stat.h>
134: #include <sys/buf.h>
135: #include <sys/mount.h>
136: #include <sys/vnode.h>
137: #include <sys/malloc.h>
138: #include <sys/namei.h>
139: #include <sys/attr.h>
140: #include <miscfs/specfs/specdev.h>
141: #include <miscfs/fifofs/fifo.h>
142:
143: #include <machine/spl.h>
144: #include <kern/mapfs.h>
145:
146: #include "hfs.h"
147: #include "hfs_lockf.h"
148: #include "hfs_dbg.h"
149:
150: #include "hfscommon/headers/CatalogPrivate.h"
151: #include "hfscommon/headers/BTreesInternal.h"
152: #include "hfscommon/headers/FileMgrInternal.h"
153: #include "hfscommon/headers/HFSUnicodeWrappers.h"
154:
155: #define OWNERSHIP_ONLY_ATTRS (ATTR_CMN_OWNERID | ATTR_CMN_GRPID | ATTR_CMN_ACCESSMASK | ATTR_CMN_FLAGS)
156:
157: #define MAKE_DELETED_NAME(NAME,FID) \
158: (void) sprintf((NAME), "%s%d", HFS_DELETE_PREFIX, (FID))
159:
160:
161: /* Global vfs data structures for hfs */
162: int (**hfs_vnodeop_p)();
163:
164: /* external routines defined in hfs_vhash.c */
165: extern void hfs_vhashrem(struct hfsnode *hp);
166: extern int vinvalbuf_vhash(register struct vnode *vp, int flags, struct ucred *cred, struct proc *p);
167: extern void hfs_vhashmove( struct hfsnode *hp,UInt32 nodeID);
168:
169: /* external routines defined in vfs_cache.c */
170:
171: void hfs_vhashrem(struct hfsnode *hp);
172:
173: extern OSErr PositionIterator(CatalogIterator *cip, UInt32 offset, BTreeIterator *bip, UInt16 *op);
174:
175: extern void cache_purge (struct vnode *vp);
176: extern int cache_lookup (struct vnode *dvp, struct vnode **vpp, struct componentname *cnp);
177: extern void cache_enter (struct vnode *dvp, struct vnode *vpp, struct componentname *cnp);
178:
179: extern void vnode_pager_setsize( struct vnode *vp, u_long nsize);
180: extern int vnode_uncache( struct vnode *vp);
181:
182: extern cluster_close(struct vnode *vp, int bsize, long secsize);
183:
184: extern void hfs_set_metaname(char *name, struct hfsfilemeta *fm);
185:
186: extern groupmember(gid_t gid, struct ucred *cred);
187:
188: static int hfs_makenode( int mode, dev_t rawdev, struct vnode *dvp, struct vnode **vpp, struct componentname *cnp);
189:
190: static void hfs_chid(struct hfsnode *hp, u_int32_t fid, u_int32_t pid, char* name);
191:
192: static int hfs_write_access(struct vnode *vp, struct ucred *cred, struct proc *p, Boolean considerFlags);
193:
194: static int hfs_chown( struct vnode *vp, uid_t uid, gid_t gid, struct ucred *cred, struct proc *p);
195: static int hfs_chmod( struct vnode *vp, int mode, struct ucred *cred, struct proc *p);
196: static int hfs_chflags( struct vnode *vp, u_long flags, struct ucred *cred, struct proc *p);
197:
198: /*
199: * Enabling cluster read/write operations.
200: */
201: extern int doclusterread;
202: extern int doclusterwrite;
203:
204: int hfs_cache_lookup(); /* in hfs_lookup.c */
205: int hfs_lookup(); /* in hfs_lookup.c */
206: int hfs_read(); /* in hfs_readwrite.c */
207: int hfs_write(); /* in hfs_readwrite.c */
208: int hfs_ioctl(); /* in hfs_readwrite.c */
209: int hfs_select(); /* in hfs_readwrite.c */
210: int hfs_mmap(); /* in hfs_readwrite.c */
211: int hfs_seek(); /* in hfs_readwrite.c */
212: int hfs_bmap(); /* in hfs_readwrite.c */
213: int hfs_strategy(); /* in hfs_readwrite.c */
214: int hfs_reallocblks(); /* in hfs_readwrite.c */
215: int hfs_truncate(); /* in hfs_readwrite.c */
216: int hfs_allocate(); /* in hfs_readwrite.c */
217: int hfs_pagein(); /* in hfs_readwrite.c */
218: int hfs_pageout(); /* in hfs_readwrite.c */
219: int hfs_search(); /* in hfs_search.c */
220: int hfs_link(); /* in hfs_link.c */
221:
222: /*****************************************************************************
223: *
224: * Operations on vnodes
225: *
226: *****************************************************************************/
227:
228: /*
229: * Create a regular file
230: #% create dvp L U U
231: #% create vpp - L -
232: #
233: vop_create {
234: IN WILLRELE struct vnode *dvp;
235: OUT struct vnode **vpp;
236: IN struct componentname *cnp;
237: IN struct vattr *vap;
238:
239: We are responsible for freeing the namei buffer, it is done in hfs_makenode(), unless there is
240: a previous error.
241:
242: */
243:
244: static int
245: hfs_create(ap)
246: struct vop_create_args /* {
247: struct vnode *a_dvp;
248: struct vnode **a_vpp;
249: struct componentname *a_cnp;
250: struct vattr *a_vap;
251: } */ *ap;
252: {
253: struct proc *p = current_proc();
254: int retval;
255: int mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode);
256: DBG_FUNC_NAME("create");
257: DBG_VOP_LOCKS_DECL(2);
258: DBG_VOP_PRINT_FUNCNAME();
259: DBG_VOP_PRINT_VNODE_INFO(ap->a_dvp);
260: DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);
261:
262: DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
263: DBG_VOP_LOCKS_INIT(1,*ap->a_vpp, VOPDBG_IGNORE, VOPDBG_LOCKED, VOPDBG_IGNORE, VOPDBG_POS);
264: DBG_VOP_CONT(("\tva_type %d va_mode 0x%x\n",
265: ap->a_vap->va_type, ap->a_vap->va_mode));
266:
267: #if HFS_DIAGNOSTIC
268: DBG_HFS_NODE_CHECK(ap->a_dvp);
269: DBG_ASSERT(ap->a_dvp->v_type == VDIR);
270: if(ap->a_vap == NULL) {
271: panic("NULL attr on create");
272: }
273:
274: switch(ap->a_vap->va_type) {
275: case VDIR:
276: VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
277: VPUT(ap->a_dvp);
278: DBG_VOP_LOCKS_TEST(EISDIR);
279: return (EISDIR); /* use hfs_mkdir instead */
280: case VREG:
281: case VLNK:
282: break;
283: default:
284: DBG_ERR(("%s: INVALID va_type: %d, %s, %s\n", funcname, ap->a_vap->va_type, H_NAME(VTOH(ap->a_dvp)), ap->a_cnp->cn_nameptr));
285: VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
286: VPUT(ap->a_dvp);
287: DBG_VOP_LOCKS_TEST(EINVAL);
288: return (EINVAL);
289: }
290: // if(ap->a_vap->va_mode & (VSUID | VSGID | VSVTX)) {
291: // DBG_ERR(("%s: INVALID va_mode (%o): %s, %s\n", funcname, ap->a_vap->va_mode, H_NAME(VTOH(ap->a_dvp)), ap->a_cnp->cn_nameptr));
292: // DBG_VOP_LOCKS_TEST(EINVAL);
293: // VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
294: // VPUT(ap->a_dvp);
295: // return (EINVAL); /* Can't do these */
296: // };
297: #endif
298:
299: /* lock catalog b-tree */
300: retval = hfs_metafilelocking(VTOHFS(ap->a_dvp), kHFSCatalogFileID, LK_EXCLUSIVE, p);
301: if (retval != E_NONE) {
302: VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
303: VPUT(ap->a_dvp);
304: DBG_VOP_LOCKS_TEST( retval);
305: return (retval);
306: }
307:
308: /* Create the vnode */
309: retval = hfs_makenode(mode, 0, ap->a_dvp, ap->a_vpp, ap->a_cnp);
310: DBG_VOP_UPDATE_VP(1, *ap->a_vpp);
311:
312: /* unlock catalog b-tree */
313: (void) hfs_metafilelocking(VTOHFS(ap->a_dvp), kHFSCatalogFileID, LK_RELEASE, p);
314:
315: if (retval != E_NONE) {
316: DBG_ERR(("%s: hfs_makenode FAILED: %s, %s\n", funcname, ap->a_cnp->cn_nameptr, H_NAME(VTOH(ap->a_dvp))));
317: }
318: DBG_VOP_LOCKS_TEST(retval);
319: return (retval);
320: }
321:
322:
323: /*
324: * Mknod vnode call
325:
326: #% mknod dvp L U U
327: #% mknod vpp - X -
328: #
329: vop_mknod {
330: IN WILLRELE struct vnode *dvp;
331: OUT WILLRELE struct vnode **vpp;
332: IN struct componentname *cnp;
333: IN struct vattr *vap;
334: */
335: /* ARGSUSED */
336:
337: static int
338: hfs_mknod(ap)
339: struct vop_mknod_args /* {
340: struct vnode *a_dvp;
341: struct vnode **a_vpp;
342: struct componentname *a_cnp;
343: struct vattr *a_vap;
344: } */ *ap;
345: {
346: struct vattr *vap = ap->a_vap;
347: struct vnode **vpp = ap->a_vpp;
348: struct proc *p = current_proc();
349: dev_t rawdev = 0;
350: int error;
351:
352: if (VTOVCB(ap->a_dvp)->vcbSigWord != kHFSPlusSigWord) {
353: VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
354: VPUT(ap->a_dvp);
355: return (EOPNOTSUPP);
356: }
357:
358: if (vap->va_rdev != VNOVAL) {
359: /*
360: * Want to be able to use this to make badblock
361: * inodes, so don't truncate the dev number.
362: */
363: rawdev = vap->va_rdev;
364: }
365:
366: /* lock catalog b-tree */
367: error = hfs_metafilelocking(VTOHFS(ap->a_dvp), kHFSCatalogFileID, LK_EXCLUSIVE, p);
368: if (error != E_NONE) {
369: VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
370: VPUT(ap->a_dvp);
371: return (error);
372: }
373:
374: /* Create the vnode */
375: error = hfs_makenode(MAKEIMODE(vap->va_type, vap->va_mode), rawdev, ap->a_dvp, vpp, ap->a_cnp);
376:
377: /* unlock catalog b-tree */
378: (void) hfs_metafilelocking(VTOHFS(ap->a_dvp), kHFSCatalogFileID, LK_RELEASE, p);
379:
380: if (error != E_NONE) {
381: return (error);
382: }
383:
384: /*
385: * Remove inode so that it will be reloaded by lookup and
386: * checked to see if it is an alias of an existing vnode.
387: * Note: unlike UFS, we don't bash v_type here.
388: */
389: VPUT(*vpp);
390: vgone(*vpp);
391: *vpp = 0;
392: return (0);
393: }
394:
395:
396: /*
397: * mkcomplex vnode call
398: *
399:
400: #% mkcomplex dvp L U U
401: #% mkcomplex vpp - L -
402: #
403: vop_mkcomplex {
404: IN WILLRELE struct vnode *dvp;
405: OUT struct vnode **vpp;
406: IN struct componentname *cnp;
407: IN struct vattr *vap;
408: IN u_long type;
409: }
410:
411: */
412:
413: static int
414: hfs_mkcomplex(ap)
415: struct vop_mkcomplex_args /* {
416: struct vnode *a_dvp;
417: struct vnode **a_vpp;
418: struct componentname *a_cnp;
419: struct vattr *a_vap;
420: u_long a_type;
421: } */ *ap;
422: {
423: int retval = E_NONE;
424: DBG_FUNC_NAME("make_complex");
425: DBG_VOP_LOCKS_DECL(2);
426: DBG_VOP_PRINT_FUNCNAME();
427: DBG_VOP_PRINT_VNODE_INFO(ap->a_dvp);
428: DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);DBG_VOP_CONT(("\n"));
429:
430: DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
431: DBG_VOP_LOCKS_INIT(1,*ap->a_vpp, VOPDBG_IGNORE, VOPDBG_LOCKED, VOPDBG_IGNORE, VOPDBG_POS);
432:
433: retval = VOP_CREATE(ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap);
434:
435: DBG_VOP_LOCKS_TEST(retval);
436: return retval;
437: }
438:
439:
440: /*
441: * Open called.
442: #% open vp L L L
443: #
444: vop_open {
445: IN struct vnode *vp;
446: IN int mode;
447: IN struct ucred *cred;
448: IN struct proc *p;
449: */
450:
451:
452: static int
453: hfs_open(ap)
454: struct vop_open_args /* {
455: struct vnode *a_vp;
456: int a_mode;
457: struct ucred *a_cred;
458: struct proc *a_p;
459: } */ *ap;
460: {
461: struct hfsnode *hp = VTOH(ap->a_vp);
462: int retval = E_NONE;
463: DBG_FUNC_NAME("open");
464: DBG_VOP_LOCKS_DECL(1);
465: DBG_VOP_PRINT_FUNCNAME();
466: DBG_VOP_CONT((" "));DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
467: DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS);
468:
469: if (ap->a_vp->v_type == VREG) /* Only files */
470: {
471: /*
472: * Files marked append-only must be opened for appending.
473: */
474: if ((hp->h_meta->h_pflags & APPEND) &&
475: (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
476: retval = EPERM;
477: }
478:
479:
480: DBG_VOP_LOCKS_TEST(retval);
481: return (retval);
482: }
483:
484: /*
485: * Close called.
486: *
487: * Update the times on the hfsnode.
488: #% close vp U U U
489: #
490: vop_close {
491: IN struct vnode *vp;
492: IN int fflag;
493: IN struct ucred *cred;
494: IN struct proc *p;
495: */
496:
497:
498: static int
499: hfs_close(ap)
500: struct vop_close_args /* {
501: struct vnode *a_vp;
502: int a_fflag;
503: struct ucred *a_cred;
504: struct proc *a_p;
505: } */ *ap;
506: {
507: register struct vnode *vp = ap->a_vp;
508: struct hfsnode *hp = VTOH(vp);
509: struct proc *p = ap->a_p;
510: FCB *fcb;
511: struct timeval tv;
512: off_t leof;
513: u_long blks, blocksize;
514: int retval = E_NONE;
515:
516: DBG_FUNC_NAME("close");
517: DBG_VOP_LOCKS_DECL(1);
518: DBG_VOP_PRINT_FUNCNAME();
519: DBG_VOP_CONT((" "));DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
520: DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
521:
522: simple_lock(&vp->v_interlock);
523: if (vp->v_usecount > 1) {
524: tv = time;
525: HFSTIMES(hp, &tv, &tv);
526: }
527: simple_unlock(&vp->v_interlock);
528:
529: /*
530: * VOP_CLOSE can be called with vp locked (from vclean).
531: * We check for this case using VOP_ISLOCKED and bail.
532: *
533: * also, ignore complex nodes; there's no data associated with them.
534: */
535: if (H_FORKTYPE(hp) == kDirectory || VOP_ISLOCKED(vp)) {
536: DBG_VOP_LOCKS_TEST(E_NONE);
537: return E_NONE;
538: };
539:
540: fcb = HTOFCB(hp);
541: leof = fcb->fcbEOF;
542:
543: if (leof != 0) {
544: enum vtype our_type = vp->v_type;
545: u_long our_id = vp->v_id;
546:
547: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
548: /*
549: * Since we can contact switch in vn_lock our vnode
550: * could get recycled (eg umount -f). Double check
551: * that its still ours.
552: */
553: if (vp->v_type != our_type || vp->v_id != our_id) {
554: VOP_UNLOCK(vp, 0, p);
555: DBG_VOP_LOCKS_TEST(E_NONE);
556: return(E_NONE);
557: }
558:
559: blocksize = HTOVCB(hp)->blockSize;
560: blks = leof / blocksize;
561: if ((blks * blocksize) != leof)
562: blks++;
563:
564: /*
565: * Shrink the peof to the smallest size neccessary to contain the leof.
566: */
567: if ((blks * blocksize) < fcb->fcbPLen) {
568: retval = VOP_TRUNCATE(vp, leof, 0, ap->a_cred, p);
569: }
570:
571: if (doclusterwrite) {
572: long devBlockSize = 0;
573:
574: VOP_DEVBLOCKSIZE(hp->h_meta->h_devvp, &devBlockSize);
575: cluster_close(vp, PAGE_SIZE, devBlockSize);
576: }
577:
578: VOP_UNLOCK(vp, 0, p);
579: }
580:
581: DBG_VOP_LOCKS_TEST(retval);
582: return (retval);
583: }
584:
585: /*
586: #% access vp L L L
587: #
588: vop_access {
589: IN struct vnode *vp;
590: IN int mode;
591: IN struct ucred *cred;
592: IN struct proc *p;
593:
594: */
595:
596: static int
597: hfs_access(ap)
598: struct vop_access_args /* {
599: struct vnode *a_vp;
600: int a_mode;
601: struct ucred *a_cred;
602: struct proc *a_p;
603: } */ *ap;
604: {
605: struct vnode *vp = ap->a_vp;
606: struct ucred *cred = ap->a_cred;
607: struct hfsnode *hp = VTOH(vp);
608: ExtendedVCB *vcb = HTOVCB(hp);
609: register gid_t *gp;
610: mode_t mask, mode;
611: Boolean isHFSPlus;
612: int retval = E_NONE;
613: int i;
614: DBG_FUNC_NAME("access");
615: DBG_VOP_LOCKS_DECL(1);
616: // DBG_VOP_PRINT_FUNCNAME();
617: // DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
618:
619: DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS);
620:
621: mode = ap->a_mode;
622: isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord );
623:
624: /*
625: * Disallow write attempts on read-only file systems;
626: * unless the file is a socket, fifo, or a block or
627: * character device resident on the file system.
628: */
629: if (mode & VWRITE) {
630: switch (vp->v_type) {
631: case VDIR:
632: case VLNK:
633: case VREG:
634: if (VTOVFS(vp)->mnt_flag & MNT_RDONLY)
635: return (EROFS);
636: break;
637: default:
638: break;
639: }
640: }
641:
642: /* If immutable bit set, nobody gets to write it. */
643: if ((mode & VWRITE) && (hp->h_meta->h_pflags & IMMUTABLE))
644: return (EPERM);
645:
646: /* Otherwise, user id 0 always gets access. */
647: if (ap->a_cred->cr_uid == 0) {
648: retval = 0;
649: goto Exit;
650: };
651:
652: mask = 0;
653:
654: /* Otherwise, check the owner. */
655: if (cred->cr_uid == hp->h_meta->h_uid) {
656: if (mode & VEXEC)
657: mask |= S_IXUSR;
658: if (mode & VREAD)
659: mask |= S_IRUSR;
660: if (mode & VWRITE)
661: mask |= S_IWUSR;
662: retval = ((hp->h_meta->h_mode & mask) == mask ? 0 : EACCES);
663: goto Exit;
664: }
665:
666: /* Otherwise, check the groups. */
667: for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++)
668: if (hp->h_meta->h_gid == *gp) {
669: if (mode & VEXEC)
670: mask |= S_IXGRP;
671: if (mode & VREAD)
672: mask |= S_IRGRP;
673: if (mode & VWRITE)
674: mask |= S_IWGRP;
675: retval = ((hp->h_meta->h_mode & mask) == mask ? 0 : EACCES);
676: goto Exit;
677: }
678:
679: /* Otherwise, check everyone else. */
680: if (mode & VEXEC)
681: mask |= S_IXOTH;
682: if (mode & VREAD)
683: mask |= S_IROTH;
684: if (mode & VWRITE)
685: mask |= S_IWOTH;
686: retval = ((hp->h_meta->h_mode & mask) == mask ? 0 : EACCES);
687:
688: Exit:
689: DBG_VOP_LOCKS_TEST(retval);
690: return (retval);
691: }
692:
693:
694:
695: /*
696: #% getattr vp = = =
697: #
698: vop_getattr {
699: IN struct vnode *vp;
700: IN struct vattr *vap;
701: IN struct ucred *cred;
702: IN struct proc *p;
703:
704: */
705:
706:
707: /* ARGSUSED */
708: static int
709: hfs_getattr(ap)
710: struct vop_getattr_args /* {
711: struct vnode *a_vp;
712: struct vattr *a_vap;
713: struct ucred *a_cred;
714: struct proc *a_p;
715: } */ *ap;
716: {
717: register struct vnode *vp = ap->a_vp;
718: register struct hfsnode *hp = VTOH(vp);
719: register struct vattr *vap = ap->a_vap;
720: struct timeval tv;
721: DBG_FUNC_NAME("getattr");
722: DBG_VOP_LOCKS_DECL(1);
723: DBG_VOP_PRINT_FUNCNAME();
724: DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
725:
726: DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_SAME, VOPDBG_SAME, VOPDBG_SAME, VOPDBG_POS);
727:
728: DBG_HFS_NODE_CHECK(ap->a_vp);
729:
730: tv = time;
731: HFSTIMES(hp, &tv, &tv);
732:
733: vap->va_fsid = H_DEV(hp);
734: vap->va_fileid = H_FILEID(hp);
735: vap->va_mode = hp->h_meta->h_mode;
736: vap->va_uid = hp->h_meta->h_uid;
737: vap->va_gid = hp->h_meta->h_gid;
738: vap->va_rdev = hp->h_meta->h_rdev;
739: #if MACH_NBC
740: if ((vp->v_type == VREG) && vp->v_vm_info && vp->v_vm_info->mapped &&
741: (!vp->v_vm_info->filesize)) {
742: vap->va_size = vp->v_vm_info->vnode_size;
743: }
744: else
745: #endif /* MACH_NBC */
746: if (vp->v_type == VDIR) {
747: vap->va_size = hp->h_meta->h_size;
748: vap->va_bytes = 0;
749: vap->va_nlink = 2 + hp->h_meta->h_valence;
750: /*
751: * account for hidden data nodes directory
752: */
753: if ((H_FILEID(hp) == kRootDirID) &&
754: (VTOHFS(vp)->hfs_private_metadata_dir != 0)) {
755: vap->va_size -= AVERAGE_HFSDIRENTRY_SIZE;
756: vap->va_nlink--;
757: }
758: }
759: else {
760: vap->va_size = hp->fcbEOF;
761: vap->va_bytes = hp->h_meta->h_size;
762:
763: if (hp->h_meta->h_metaflags & IN_DELETED)
764: vap->va_nlink = 0;
765: #if HFS_HARDLINKS
766: else if ((hp->h_meta->h_metaflags & IN_DATANODE) &&
767: (hp->h_meta->h_nlink > 0))
768: vap->va_nlink = hp->h_meta->h_nlink;
769: #endif
770: else
771: vap->va_nlink = 1;
772:
773: }
774:
775: vap->va_atime.tv_nsec = 0;
776: vap->va_atime.tv_sec = hp->h_meta->h_atime;
777: vap->va_mtime.tv_nsec = 0;
778: vap->va_mtime.tv_sec = hp->h_meta->h_mtime;
779: vap->va_ctime.tv_nsec = 0;
780: vap->va_ctime.tv_sec = hp->h_meta->h_ctime;
781: vap->va_flags = hp->h_meta->h_pflags;
782: vap->va_gen = 0;
783: /* this doesn't belong here */
784: if (vp->v_type == VBLK)
785: vap->va_blocksize = BLKDEV_IOSIZE;
786: else if (vp->v_type == VCHR)
787: vap->va_blocksize = MAXPHYSIO;
788: else
789: vap->va_blocksize = VTOVFS(vp)->mnt_stat.f_iosize;
790: vap->va_type = vp->v_type;
791: vap->va_filerev = 0;
792:
793: DBG_VOP_LOCKS_TEST(E_NONE);
794: return (E_NONE);
795: }
796:
797: /*
798: * Set attribute vnode op. called from several syscalls
799: #% setattr vp L L L
800: #
801: vop_setattr {
802: IN struct vnode *vp;
803: IN struct vattr *vap;
804: IN struct ucred *cred;
805: IN struct proc *p;
806:
807: */
808:
809: static int
810: hfs_setattr(ap)
811: struct vop_setattr_args /* {
812: struct vnode *a_vp;
813: struct vattr *a_vap;
814: struct ucred *a_cred;
815: struct proc *a_p;
816: } */ *ap;
817: {
818: struct vnode *vp = ap->a_vp;
819: struct hfsnode *hp = VTOH(vp);
820: struct vattr *vap = ap->a_vap;
821: struct ucred *cred = ap->a_cred;
822: struct proc *p = ap->a_p;
823: struct timeval atimeval, mtimeval;
824: int retval;
825: DBG_FUNC_NAME("setattr");
826: DBG_VOP_LOCKS_DECL(1);
827: DBG_VOP_PRINT_FUNCNAME();
828: DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
829: DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS);
830: WRITE_CK(vp, funcname);
831: DBG_HFS_NODE_CHECK(ap->a_vp);
832:
833: /*
834: * Check for unsettable attributes.
835: */
836: if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
837: (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
838: (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
839: ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
840: retval = EINVAL;
841: goto ErrorExit;
842: }
843:
844: if (vap->va_flags != VNOVAL) {
845: if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) {
846: retval = EROFS;
847: goto ErrorExit;
848: };
849: if ((retval = hfs_chflags(vp, vap->va_flags, cred, p))) {
850: goto ErrorExit;
851: };
852: if (vap->va_flags & (IMMUTABLE | APPEND)) {
853: retval = 0;
854: goto ErrorExit;
855: };
856: }
857:
858: if (hp->h_meta->h_pflags & (IMMUTABLE | APPEND)) {
859: retval = EPERM;
860: goto ErrorExit;
861: };
862: /*
863: * Go through the fields and update iff not VNOVAL.
864: */
865: if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
866: if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) {
867: retval = EROFS;
868: goto ErrorExit;
869: };
870: if ((retval = hfs_chown(vp, vap->va_uid, vap->va_gid, cred, p))) {
871: goto ErrorExit;
872: };
873: }
874: if (vap->va_size != VNOVAL) {
875: /*
876: * Disallow write attempts on read-only file systems;
877: * unless the file is a socket, fifo, or a block or
878: * character device resident on the file system.
879: */
880: switch (vp->v_type) {
881: case VDIR:
882: retval = EISDIR;
883: goto ErrorExit;
884: case VLNK:
885: case VREG:
886: if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) {
887: retval = EROFS;
888: goto ErrorExit;
889: };
890: break;
891: default:
892: break;
893: }
894: if ((retval = VOP_TRUNCATE(vp, vap->va_size, 0, cred, p))) {
895: goto ErrorExit;
896: };
897: }
898: hp = VTOH(vp);
899: if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
900: if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) {
901: retval = EROFS;
902: goto ErrorExit;
903: };
904: if (cred->cr_uid != hp->h_meta->h_uid &&
905: (retval = suser(cred, &p->p_acflag)) &&
906: ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
907: (retval = VOP_ACCESS(vp, VWRITE, cred, p)))) {
908: goto ErrorExit;
909: };
910: if (vap->va_atime.tv_sec != VNOVAL)
911: hp->h_nodeflags |= IN_ACCESS;
912: if (vap->va_mtime.tv_sec != VNOVAL)
913: hp->h_nodeflags |= IN_CHANGE | IN_UPDATE;
914: atimeval.tv_sec = vap->va_atime.tv_sec;
915: atimeval.tv_usec = 0;
916: mtimeval.tv_sec = vap->va_mtime.tv_sec;
917: mtimeval.tv_usec = 0;
918: if ((retval = VOP_UPDATE(vp, &atimeval, &mtimeval, 1))) {
919: goto ErrorExit;
920: };
921: }
922: retval = 0;
923: if (vap->va_mode != (mode_t)VNOVAL) {
924: if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) {
925: retval = EROFS;
926: goto ErrorExit;
927: };
928: retval = hfs_chmod(vp, (int)vap->va_mode, cred, p);
929: };
930:
931: ErrorExit: ;
932:
933: DBG_VOP(("hfs_setattr: returning %d...\n", retval));
934: DBG_VOP_LOCKS_TEST(retval);
935: return (retval);
936: }
937:
938:
939: /*
940:
941: #
942: #% getattrlist vp = = =
943: #
944: vop_getattrlist {
945: IN struct vnode *vp;
946: IN struct attrlist *alist;
947: INOUT struct uio *uio;
948: IN struct ucred *cred;
949: IN struct proc *p;
950: };
951:
952: */
953:
954: static int
955: hfs_getattrlist(ap)
956: struct vop_getattrlist_args /* {
957: struct vnode *a_vp;
958: struct attrlist *a_alist
959: struct uio *a_uio;
960: struct ucred *a_cred;
961: struct proc *a_p;
962: } */ *ap;
963: {
964: struct vnode *vp = ap->a_vp;
965: struct hfsnode *hp = VTOH(vp);
966: struct attrlist *alist = ap->a_alist;
967: int error = 0;
968: struct hfsCatalogInfo catalogInfo;
969: struct hfsCatalogInfo *catInfoPtr = NULL;
970: int fixedblocksize;
971: int attrblocksize;
972: int attrbufsize;
973: void *attrbufptr;
974: void *attrptr;
975: void *varptr;
976: u_int32_t fileID;
977: DBG_FUNC_NAME("getattrlist");
978: DBG_VOP_LOCKS_DECL(1);
979:
980: DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_SAME, VOPDBG_SAME, VOPDBG_SAME, VOPDBG_POS);
981: DBG_HFS_NODE_CHECK(ap->a_vp);
982: DBG_VOP(("%s: Common attr:0x%lx, buff size Ox%lX,\n",funcname, (u_long)alist->commonattr,(u_long)ap->a_uio->uio_resid));
983:
984: DBG_ASSERT(ap->a_uio->uio_rw == UIO_READ);
985:
986: if ((alist->bitmapcount != ATTR_BIT_MAP_COUNT) ||
987: ((alist->commonattr & ~ATTR_CMN_VALIDMASK) != 0) ||
988: ((alist->volattr & ~ATTR_VOL_VALIDMASK) != 0) ||
989: ((alist->dirattr & ~ATTR_DIR_VALIDMASK) != 0) ||
990: ((alist->fileattr & ~ATTR_FILE_VALIDMASK) != 0) ||
991: ((alist->forkattr & ~ATTR_FORK_VALIDMASK) != 0)) {
992: DBG_ERR(("%s: bad attrlist\n", funcname));
993: DBG_VOP_LOCKS_TEST(EINVAL);
994: return EINVAL;
995: };
996:
997: /* Requesting volume information requires setting the ATTR_VOL_INFO bit and
998: volume info requests are mutually exclusive with all other info requests: */
999: if ((alist->volattr != 0) && (((alist->volattr & ATTR_VOL_INFO) == 0) ||
1000: (alist->dirattr != 0) || (alist->fileattr != 0) || (alist->forkattr != 0)
1001: )) {
1002: DBG_ERR(("%s: conflicting information requested\n", funcname));
1003: DBG_VOP_LOCKS_TEST(EINVAL);
1004: return EINVAL;
1005: };
1006:
1007: /* Reject requests for unsupported options for now: */
1008: if ((alist->commonattr & (ATTR_CMN_NAMEDATTRCOUNT | ATTR_CMN_NAMEDATTRLIST)) ||
1009: (alist->fileattr & (ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT | ATTR_FILE_FORKLIST))) {
1010: DBG_ERR(("%s: illegal bits in attlist\n", funcname));
1011: DBG_VOP_LOCKS_TEST(EINVAL);
1012: return EINVAL;
1013: };
1014:
1015: /* Requesting volume information requires root vnode */
1016: if ((alist->volattr) && (H_FILEID(hp) != kRootDirID)) {
1017: DBG_ERR(("%s: not root vnode\n", funcname));
1018: DBG_VOP_LOCKS_TEST(EINVAL);
1019: return EINVAL;
1020: };
1021:
1022: /* If a FileID (ATTR_CMN_OBJPERMANENTID) is requested on an HFS volume we must be sure
1023: to create the thread record before returning it:
1024: */
1025: if ((vp->v_type == VREG) &&
1026: (alist->commonattr & ATTR_CMN_OBJPERMANENTID)) {
1027: /* Only HFS-Plus volumes are guaranteed to have a thread record in place already: */
1028: if (VTOVCB(vp)->vcbSigWord != kHFSPlusSigWord) {
1029: /* Create a thread record and return the FileID [which is the file's fileNumber] */
1030: /* lock catalog b-tree */
1031: error = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_EXCLUSIVE, ap->a_p);
1032: error = hfsCreateFileID(VTOVCB(vp), H_DIRID(hp), H_NAME(hp), H_HINT(hp), &fileID);
1033: (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, ap->a_p);
1034: if (error) {
1035: DBG_VOP_LOCKS_TEST(error);
1036: DBG_ERR(("hfs_getattrlist: error %d on CreateFileIDRef.\n", error));
1037: return error;
1038: };
1039: DBG_ASSERT(fileID == H_FILEID(hp));
1040: };
1041: };
1042:
1043: /*
1044: * Avoid unnecessary catalog lookups for volume info which is available directly
1045: * in the VCB and root vnode, or can be synthesized.
1046: */
1047: if (((alist->volattr == 0) && ((alist->commonattr & HFS_ATTR_CMN_LOOKUPMASK) != 0)) ||
1048: ((alist->dirattr & HFS_ATTR_DIR_LOOKUPMASK) != 0) ||
1049: ((alist->fileattr & HFS_ATTR_FILE_LOOKUPMASK) != 0)) {
1050:
1051: /* lock catalog b-tree */
1052: error = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_SHARED, ap->a_p);
1053: if (error) {
1054: DBG_VOP_LOCKS_TEST(error);
1055: return (error);
1056: }
1057:
1058: if (alist->volattr != 0) {
1059: /* Look up the root info, regardless of the vnode provided */
1060: catalogInfo.hint = kNoHint;
1061: error = hfsLookup(VTOVCB(vp), 2, NULL, -1, &catalogInfo);
1062: } else {
1063: catalogInfo.hint = kNoHint;
1064: error = hfsLookup(VTOVCB(vp), H_DIRID(hp), H_NAME(hp), -1, &catalogInfo);
1065: if (error == 0) H_HINT(hp) = catalogInfo.hint; /* Remember the last valid hint */
1066: };
1067: catInfoPtr = &catalogInfo;
1068:
1069: /* unlock catalog b-tree */
1070: (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, ap->a_p);
1071: };
1072:
1073: fixedblocksize = AttributeBlockSize(alist);
1074: attrblocksize = fixedblocksize + (sizeof(u_long)); /* u_long for length longword */
1075: if (alist->commonattr & ATTR_CMN_NAME) attrblocksize += NAME_MAX + 1;
1076: if (alist->commonattr & ATTR_CMN_NAMEDATTRLIST) attrblocksize += 0; /* XXX PPD */
1077: if (alist->volattr & ATTR_VOL_MOUNTPOINT) attrblocksize += PATH_MAX;
1078: if (alist->volattr & ATTR_VOL_NAME) attrblocksize += NAME_MAX + 1;
1079: if (alist->fileattr & ATTR_FILE_FORKLIST) attrblocksize += 0; /* XXX PPD */
1080:
1081: attrbufsize = MIN(ap->a_uio->uio_resid, attrblocksize);
1082: DBG_VOP(("hfs_getattrlist: allocating Ox%X byte buffer (Ox%X + Ox%X) for attributes...\n",
1083: attrblocksize,
1084: fixedblocksize,
1085: attrblocksize - fixedblocksize));
1086: MALLOC(attrbufptr, void *, attrblocksize, M_TEMP, M_WAITOK);
1087: attrptr = attrbufptr;
1088: *((u_long *)attrptr) = 0; /* Set buffer length in case of errors */
1089: ++((u_long *)attrptr); /* Reserve space for length field */
1090: varptr = ((char *)attrptr) + fixedblocksize; /* Point to variable-length storage */
1091: DBG_VOP(("hfs_getattrlist: attrptr = 0x%08X, varptr = 0x%08X...\n", (u_int)attrptr, (u_int)varptr));
1092:
1093: PackAttributeBlock(alist, vp, catInfoPtr, &attrptr, &varptr);
1094: attrbufsize = MIN(attrbufsize, (u_int)varptr - (u_int)attrbufptr); /* Don't copy out more data than was generated */
1095: DBG_VOP(("hfs_getattrlist: copying Ox%X bytes to user address 0x%08X.\n", attrbufsize, (u_int)ap->a_uio->uio_iov->iov_base));
1096: error = uiomove((caddr_t)attrbufptr, attrbufsize, ap->a_uio);
1097: if (error != E_NONE) {
1098: DBG_ERR(("hfs_getattrlist: error %d on uiomove.\n", error));
1099: };
1100:
1101: FREE(attrbufptr, M_TEMP);
1102:
1103: DBG_VOP_LOCKS_TEST(error);
1104: return error;
1105: }
1106:
1107:
1108:
1109: #if 0 // OBSOLETE
1110: /* This is a special permission-checking routine that tests for "write" access without
1111: regard for the UF_IMMUTABLE or SF_IMMUTABLE bits in the flags. hfs_setattrlist cannot
1112: use VOP_ACCESS for this check so this is a derivative of that code that does this check.
1113: */
1114: static int hfs_writepermission(struct vnode *vp, struct ucred *cred, struct proc *p) {
1115: struct hfsnode *hp = VTOH(vp);
1116: int i;
1117: register gid_t *gp;
1118:
1119: /* Start by checking for root */
1120: if (suser(cred, &p->p_acflag) == 0) return 0;
1121:
1122: /* Check the owner: */
1123: if (cred->cr_uid == hp->h_meta->h_uid) {
1124: return (hp->h_meta->h_mode & S_IWUSR) ? 0 : EACCES;
1125: };
1126:
1127: /* Otherwise, check the groups: */
1128: for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++) {
1129: if (hp->h_meta->h_gid == *gp) {
1130: return (hp->h_meta->h_mode & S_IWGRP) ? 0 : EACCES;
1131: };
1132: };
1133:
1134: /* Otherwise, check everyone else. */
1135: return (hp->h_meta->h_mode & S_IWOTH) ? 0 : EACCES;
1136: }
1137: #endif
1138:
1139:
1140:
1141: /*
1142:
1143: #
1144: #% setattrlist vp L L L
1145: #
1146: vop_setattrlist {
1147: IN struct vnode *vp;
1148: IN struct attrlist *alist;
1149: INOUT struct uio *uio;
1150: IN struct ucred *cred;
1151: IN struct proc *p;
1152: };
1153:
1154: */
1155:
1156: static int
1157: hfs_setattrlist(ap)
1158: struct vop_setattrlist_args /* {
1159: struct vnode *a_vp;
1160: struct attrlist *a_alist
1161: struct uio *a_uio;
1162: struct ucred *a_cred;
1163: struct proc *a_p;
1164: } */ *ap;
1165: {
1166: struct vnode *vp = ap->a_vp;
1167: struct hfsnode *hp = VTOH(vp);
1168: struct attrlist *alist = ap->a_alist;
1169: struct ucred *cred = ap->a_cred;
1170: struct proc *p = ap->a_p;
1171: int error;
1172: struct hfsCatalogInfo catalogInfo;
1173: int attrblocksize;
1174: void *attrbufptr = NULL;
1175: void *attrptr;
1176: void *varptr = NULL;
1177: uid_t saved_uid;
1178: gid_t saved_gid;
1179: mode_t saved_mode;
1180: u_long saved_flags;
1181: char * filename;
1182: u_int32_t pid;
1183: int retval = 0;
1184:
1185: DBG_FUNC_NAME("setattrlist");
1186: DBG_VOP_LOCKS_DECL(1);
1187:
1188: DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_SAME, VOPDBG_SAME, VOPDBG_SAME, VOPDBG_POS);
1189: DBG_HFS_NODE_CHECK(ap->a_vp);
1190: DBG_VOP(("%s: Common attr:0x%x, buff size Ox%X,\n",funcname, (u_int)alist->commonattr,(u_int)ap->a_uio->uio_resid));
1191:
1192: DBG_ASSERT(ap->a_uio->uio_rw == UIO_WRITE);
1193:
1194: if ((alist->bitmapcount != ATTR_BIT_MAP_COUNT) ||
1195: ((alist->commonattr & ~ATTR_CMN_SETMASK) != 0) ||
1196: ((alist->volattr & ~ATTR_VOL_SETMASK) != 0) ||
1197: ((alist->dirattr & ~ATTR_DIR_SETMASK) != 0) ||
1198: ((alist->fileattr & ~ATTR_FILE_SETMASK) != 0) ||
1199: ((alist->forkattr & ~ATTR_FORK_SETMASK) != 0)) {
1200: DBG_ERR(("%s: Bad attrlist\n", funcname));
1201: DBG_VOP_LOCKS_TEST(EINVAL);
1202: return EINVAL;
1203: };
1204:
1205: if ((alist->volattr != 0) && /* Setting volume info */
1206: (((alist->volattr & ATTR_VOL_INFO) == 0) || /* Not explicitly indicating this or ... */
1207: (alist->commonattr & ~ATTR_CMN_VOLSETMASK))) /* ... setting invalid attributes for volume */
1208: {
1209: DBG_ERR(("%s: Bad attrlist\n", funcname));
1210: DBG_VOP_LOCKS_TEST(EINVAL);
1211: return EINVAL;
1212: };
1213:
1214: if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) {
1215: DBG_VOP_LOCKS_TEST(EROFS);
1216: return EROFS;
1217: };
1218:
1219: /*
1220: Ownership of the file (in addition to write access, checked below,
1221: is required in one of two classes of calls:
1222:
1223: (a) When setting any ownership-requiring attribute other than ATTR_CMN_FLAGS, or
1224: (b) When setting ATTR_CMN_FLAGS on a volume that's not plain HFS (for which no
1225: real per-object ownership information is stored):
1226: */
1227: if ((alist->commonattr & (OWNERSHIP_ONLY_ATTRS & ~ATTR_CMN_FLAGS)) ||
1228: ((alist->commonattr & ATTR_CMN_FLAGS) && (VTOVCB(vp)->vcbSigWord != kHFSSigWord))) {
1229: /* NOTE: The following isn't ENTIRELY complete: even if you're the superuser
1230: you cannot change the flags as long as SF_IMMUTABLE or SF_APPEND is
1231: set and securelevel > 0. This is verified in hfs_chflags which gets
1232: invoked to do the actual flags field change so this check is sufficient
1233: for now.
1234: */
1235: /* Check to see if the user owns the object [or is superuser]: */
1236: if (cred->cr_uid != hp->h_meta->h_uid &&
1237: (retval = suser(cred, &p->p_acflag))) {
1238: DBG_VOP_LOCKS_TEST(retval);
1239: return retval;
1240: };
1241: } else {
1242: DBG_ASSERT(((alist->commonattr & OWNERSHIP_ONLY_ATTRS) == 0) ||
1243: (((alist->commonattr & OWNERSHIP_ONLY_ATTRS) == ATTR_CMN_FLAGS) &&
1244: (VTOVCB(vp)->vcbSigWord == kHFSSigWord)));
1245: /* No ownership access is required: mere write access (checked below) will do... */
1246: };
1247:
1248: /* For any other attributes, check to see if the user has write access to
1249: the object in question [unlike VOP_ACCESS, ignore IMMUTABLE here]: */
1250:
1251: if ((((alist->commonattr & ~(OWNERSHIP_ONLY_ATTRS)) != 0) ||
1252: (alist->volattr != 0) ||
1253: (alist->dirattr != 0) ||
1254: (alist->fileattr != 0) ||
1255: (alist->forkattr != 0)) &&
1256: ((retval = hfs_write_access(vp, cred, p, false)) != 0)) {
1257: DBG_VOP_LOCKS_TEST(retval);
1258: return retval;
1259: }; /* end of if ownership attr */
1260:
1261: /* Allocate the buffer now to minimize the time we might be blocked holding the catalog lock */
1262: attrblocksize = ap->a_uio->uio_resid;
1263: if (attrblocksize < AttributeBlockSize(alist)) {
1264: DBG_ERR(("%s: bad attrblocksize\n", funcname));
1265: DBG_VOP_LOCKS_TEST(EINVAL);
1266: return EINVAL;
1267: };
1268:
1269: MALLOC(attrbufptr, void *, attrblocksize, M_TEMP, M_WAITOK);
1270:
1271: /* lock catalog b-tree */
1272: error = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_EXCLUSIVE, p);
1273: if (error != E_NONE) {
1274: goto FreeBuffer;
1275: };
1276:
1277: filename = H_NAME(hp);
1278: pid = H_DIRID(hp);
1279:
1280: #if HFS_HARDLINKS
1281: /*
1282: * Force an update of the data node instead of the link node
1283: * by passing the fileID instead of parID and name.
1284: */
1285: if (hp->h_meta->h_metaflags & IN_DATANODE) {
1286: filename = NULL;
1287: pid = H_FILEID(hp);
1288: }
1289: #endif
1290: catalogInfo.hint = kNoHint;
1291: error = hfsLookup(VTOVCB(vp), pid, filename, -1, &catalogInfo);
1292: if (error != E_NONE) {
1293: DBG_ERR(("%s: Lookup failed on file '%s'\n", funcname, filename));
1294: goto ErrorExit;
1295: };
1296: H_HINT(hp) = catalogInfo.hint; /* Remember the last valid hint */
1297:
1298: error = uiomove((caddr_t)attrbufptr, attrblocksize, ap->a_uio);
1299: if (error) goto ErrorExit;
1300:
1301: if ((alist->volattr) && (H_FILEID(hp) != kRootDirID)) {
1302: error = EINVAL;
1303: goto ErrorExit;
1304: };
1305:
1306: /* do we have permission to change the dates? */
1307: // if (alist->commonattr & (ATTR_CMN_CRTIME | ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | ATTR_CMN_ACCTIME | ATTR_CMN_BKUPTIME)) {
1308: if (alist->commonattr & (ATTR_CMN_CHGTIME | ATTR_CMN_ACCTIME)) {
1309: if (cred->cr_uid != hp->h_meta->h_uid && (error = suser(cred, &p->p_acflag))) {
1310: goto ErrorExit;
1311: };
1312: };
1313:
1314: /* save these in case hfs_chown() or hfs_chmod() fail */
1315: saved_uid = hp->h_meta->h_uid;
1316: saved_gid = hp->h_meta->h_gid;
1317: saved_mode = hp->h_meta->h_mode;
1318: saved_flags = hp->h_meta->h_pflags;
1319:
1320: attrptr = attrbufptr;
1321: UnpackAttributeBlock(alist, vp, &catalogInfo, &attrptr, &varptr);
1322:
1323: /* if unpacking changed the owner or group then call hfs_chown() */
1324: if (saved_uid != hp->h_meta->h_uid || saved_gid != hp->h_meta->h_gid) {
1325: uid_t uid;
1326: gid_t gid;
1327:
1328: uid = hp->h_meta->h_uid;
1329: hp->h_meta->h_uid = saved_uid;
1330: gid = hp->h_meta->h_gid;
1331: hp->h_meta->h_gid = saved_gid;
1332: if ((error = hfs_chown(vp, uid, gid, cred, p)))
1333: goto ErrorExit;
1334: }
1335:
1336: /* if unpacking changed the mode then call hfs_chmod() */
1337: if (saved_mode != hp->h_meta->h_mode) {
1338: mode_t mode;
1339:
1340: mode = hp->h_meta->h_mode;
1341: hp->h_meta->h_mode = saved_mode;
1342: if ((error = hfs_chmod(vp, mode, cred, p)))
1343: goto ErrorExit;
1344: };
1345:
1346: /* if unpacking changed the flags then call hfs_chflags */
1347: if (saved_flags != hp->h_meta->h_pflags) {
1348: u_long flags;
1349:
1350: flags = hp->h_meta->h_pflags;
1351: hp->h_meta->h_pflags = saved_flags;
1352: if ((error = hfs_chflags(vp, flags, cred, p)))
1353: goto ErrorExit;
1354: };
1355:
1356: if (alist->volattr == 0) {
1357: error = MacToVFSError( UpdateCatalogNode(HTOVCB(hp), pid, filename, H_HINT(hp), &catalogInfo.nodeData));
1358: }
1359:
1360: if (alist->volattr & ATTR_VOL_NAME) {
1361: ExtendedVCB *vcb = VTOVCB(vp);
1362: int namelen = strlen(vcb->vcbVN);
1363:
1364: if (vcb->vcbVN[0] == 0) {
1365: /*
1366: Ignore attempts to rename a volume to a zero-length name:
1367: restore the original name from the metadata.
1368: */
1369: copystr(H_NAME(hp), vcb->vcbVN, sizeof(vcb->vcbVN), NULL);
1370: } else {
1371: error = MoveRenameCatalogNode(vcb, kRootParID, H_NAME(hp), H_HINT(hp), kRootParID, vcb->vcbVN, &H_HINT(hp));
1372: if (error) {
1373: VCB_LOCK(vcb);
1374: copystr(H_NAME(hp), vcb->vcbVN, sizeof(vcb->vcbVN), NULL); /* Restore the old name in the VCB */
1375: vcb->vcbFlags |= 0xFF00; // Mark the VCB dirty
1376: VCB_UNLOCK(vcb);
1377: goto ErrorExit;
1378: };
1379:
1380: hfs_set_metaname(vcb->vcbVN, hp->h_meta);
1381: hp->h_nodeflags |= IN_CHANGE;
1382:
1383: #if 0
1384: /* if hfs wrapper exists, update its name too */
1385: if (vcb->vcbSigWord == kHFSPlusSigWord && vcb->vcbAlBlSt != 0) {
1386: HFSMasterDirectoryBlock *mdb;
1387: struct buf *bp = NULL;
1388: int size = kMDBSize; /* 512 */
1389: int volnamelen = MIN(sizeof(Str27), namelen);
1390:
1391: if ( bread(VTOHFS(vp)->hfs_devvp, IOBLKNOFORBLK(kMasterDirectoryBlock, size),
1392: IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, size), NOCRED, &bp) == 0) {
1393:
1394: mdb = (HFSMasterDirectoryBlock *)((char *)bp->b_data + IOBYTEOFFSETFORBLK(kMasterDirectoryBlock, size));
1395: if (mdb->drSigWord == kHFSSigWord) {
1396: /* Convert the string to MacRoman, ignoring any errors, */
1397: (void) utf8_to_hfs(vcb, volnamelen, vcb->vcbVN, Str31 mdb->drVN)
1398: bawrite(bp);
1399: bp = NULL;
1400: }
1401: }
1402:
1403: if (bp) brelse(bp);
1404: }
1405: #endif
1406: }; /* vcb->vcbVN[0] == 0 ... else ... */
1407: }; /* alist->volattr & ATTR_VOL_NAME */
1408:
1409: ErrorExit:
1410: /* unlock catalog b-tree */
1411: (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, p);
1412:
1413: FreeBuffer:
1414: if (attrbufptr) FREE(attrbufptr, M_TEMP);
1415:
1416: DBG_VOP_LOCKS_TEST(error);
1417: return error;
1418: }
1419:
1420: /*
1421: * Change the mode on a file.
1422: * Inode must be locked before calling.
1423: */
1424: static int
1425: hfs_chmod(vp, mode, cred, p)
1426: register struct vnode *vp;
1427: register int mode;
1428: register struct ucred *cred;
1429: struct proc *p;
1430: {
1431: register struct hfsnode *hp = VTOH(vp);
1432: int retval;
1433:
1434: if (VTOVCB(vp)->vcbSigWord != kHFSPlusSigWord)
1435: return E_NONE;
1436:
1437: if (cred->cr_uid != hp->h_meta->h_uid &&
1438: (retval = suser(cred, &p->p_acflag)))
1439: return (retval);
1440: if (cred->cr_uid) {
1441: if (vp->v_type != VDIR && (mode & S_ISTXT))
1442: return (EFTYPE);
1443: if (!groupmember(hp->h_meta->h_gid, cred) && (mode & ISGID))
1444: return (EPERM);
1445: }
1446: hp->h_meta->h_mode &= ~ALLPERMS;
1447: hp->h_meta->h_mode |= (mode & ALLPERMS);
1448: hp->h_meta->h_metaflags &= ~IN_UNSETACCESS;
1449: hp->h_nodeflags |= IN_CHANGE;
1450: if ((vp->v_flag & VTEXT) && (hp->h_meta->h_mode & S_ISTXT) == 0)
1451: (void) vnode_uncache(vp);
1452: return (0);
1453: }
1454:
1455:
1456: static int
1457: hfs_write_access(struct vnode *vp, struct ucred *cred, struct proc *p, Boolean considerFlags)
1458: {
1459: struct hfsnode *hp = VTOH(vp);
1460: ExtendedVCB *vcb = HTOVCB(hp);
1461: gid_t *gp;
1462: Boolean isHFSPlus;
1463: int retval = E_NONE;
1464: int i;
1465:
1466: isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord );
1467:
1468: /*
1469: * Disallow write attempts on read-only file systems;
1470: * unless the file is a socket, fifo, or a block or
1471: * character device resident on the file system.
1472: */
1473: switch (vp->v_type) {
1474: case VDIR:
1475: case VLNK:
1476: case VREG:
1477: if (VTOVFS(vp)->mnt_flag & MNT_RDONLY)
1478: return (EROFS);
1479: break;
1480: default:
1481: break;
1482: }
1483:
1484: /* If immutable bit set, nobody gets to write it. */
1485: if (considerFlags && (hp->h_meta->h_pflags & IMMUTABLE))
1486: return (EPERM);
1487:
1488: /* Otherwise, user id 0 always gets access. */
1489: if (cred->cr_uid == 0) {
1490: retval = 0;
1491: goto Exit;
1492: };
1493:
1494: /* Otherwise, check the owner. */
1495: if (cred->cr_uid == hp->h_meta->h_uid) {
1496: retval = ((hp->h_meta->h_mode & S_IWUSR) == S_IWUSR ? 0 : EACCES);
1497: goto Exit;
1498: }
1499:
1500: /* Otherwise, check the groups. */
1501: for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++)
1502: if (hp->h_meta->h_gid == *gp) {
1503: retval = ((hp->h_meta->h_mode & S_IWGRP) == S_IWGRP ? 0 : EACCES);
1504: goto Exit;
1505: }
1506:
1507: /* Otherwise, check everyone else. */
1508: retval = ((hp->h_meta->h_mode & S_IWOTH) == S_IWOTH ? 0 : EACCES);
1509:
1510: Exit:
1511: return (retval);
1512: }
1513:
1514: /*
1515: * Change the flags on a file or directory.
1516: * Inode must be locked before calling.
1517: */
1518: static int
1519: hfs_chflags(vp, flags, cred, p)
1520: register struct vnode *vp;
1521: register u_long flags;
1522: register struct ucred *cred;
1523: struct proc *p;
1524: {
1525: register struct hfsnode *hp = VTOH(vp);
1526: int retval;
1527:
1528: if (VTOVCB(vp)->vcbSigWord == kHFSSigWord) {
1529: if ((retval = hfs_write_access(vp, cred, p, false)) != 0) {
1530: return retval;
1531: };
1532: } else if ((cred->cr_uid != hp->h_meta->h_uid) &&
1533: (retval = suser(cred, &p->p_acflag))) {
1534: return retval;
1535: };
1536:
1537: if (cred->cr_uid == 0) {
1538: if ((hp->h_meta->h_pflags & (SF_IMMUTABLE | SF_APPEND)) &&
1539: securelevel > 0) {
1540: return EPERM;
1541: };
1542: hp->h_meta->h_pflags = flags;
1543: } else {
1544: if (hp->h_meta->h_pflags & (SF_IMMUTABLE | SF_APPEND) ||
1545: (flags & UF_SETTABLE) != flags) {
1546: return EPERM;
1547: };
1548: hp->h_meta->h_pflags &= SF_SETTABLE;
1549: hp->h_meta->h_pflags |= (flags & UF_SETTABLE);
1550: }
1551: hp->h_meta->h_metaflags &= ~IN_UNSETACCESS;
1552: hp->h_nodeflags |= IN_CHANGE;
1553:
1554: return 0;
1555: }
1556:
1557:
1558: /*
1559: * Perform chown operation on hfsnode hp;
1560: * hfsnode must be locked prior to call.
1561: */
1562: static int
1563: hfs_chown(vp, uid, gid, cred, p)
1564: register struct vnode *vp;
1565: uid_t uid;
1566: gid_t gid;
1567: struct ucred *cred;
1568: struct proc *p;
1569: {
1570: register struct hfsnode *hp = VTOH(vp);
1571: uid_t ouid;
1572: gid_t ogid;
1573: int retval = 0;
1574:
1575: if (VTOVCB(vp)->vcbSigWord != kHFSPlusSigWord)
1576: return EOPNOTSUPP;
1577:
1578: if (uid == (uid_t)VNOVAL)
1579: uid = hp->h_meta->h_uid;
1580: if (gid == (gid_t)VNOVAL)
1581: gid = hp->h_meta->h_gid;
1582: /*
1583: * If we don't own the file, are trying to change the owner
1584: * of the file, or are not a member of the target group,
1585: * the caller must be superuser or the call fails.
1586: */
1587: if ((cred->cr_uid != hp->h_meta->h_uid || uid != hp->h_meta->h_uid ||
1588: (gid != hp->h_meta->h_gid && !groupmember((gid_t)gid, cred))) &&
1589: (retval = suser(cred, &p->p_acflag)))
1590: return (retval);
1591: ogid = hp->h_meta->h_gid;
1592: ouid = hp->h_meta->h_uid;
1593:
1594: hp->h_meta->h_gid = gid;
1595: hp->h_meta->h_uid = uid;
1596:
1597: hp->h_meta->h_metaflags &= ~IN_UNSETACCESS;
1598: if (ouid != uid || ogid != gid)
1599: hp->h_nodeflags |= IN_CHANGE;
1600: if (ouid != uid && cred->cr_uid != 0)
1601: hp->h_meta->h_mode &= ~ISUID;
1602: if (ogid != gid && cred->cr_uid != 0)
1603: hp->h_meta->h_mode &= ~ISGID;
1604: return (0);
1605: }
1606:
1607:
1608:
1609: /*
1610: #
1611: #% exchange fvp L L L
1612: #% exchange tvp L L L
1613: #
1614: vop_exchange {
1615: IN struct vnode *fvp;
1616: IN struct vnode *tvp;
1617: IN struct ucred *cred;
1618: IN struct proc *p;
1619: };
1620:
1621: */
1622: /*
1623: * exchange is a very tricky routine, because we might have to unlock the
1624: * passed in vnode, and then retry locking it and all its siblings, and then
1625: * unlocking them in reverse.
1626: * Also the sibling list lock must be kept during the whole operation to
1627: * make sure nothing changes underneath us.
1628: * Also it depends on behavior of the sibling list and hash, so
1629: * careful if you change anything.
1630: */
1631:
1632: static int
1633: hfs_exchange(ap)
1634: struct vop_exchange_args /* {
1635: struct vnode *a_fvp;
1636: struct vnode *a_tvp;
1637: struct ucred *a_cred;
1638: struct proc *a_p;
1639: } */ *ap;
1640: {
1641: struct hfsnode *from_hp, *to_hp, *nhp;
1642: struct hfsnode *fromSkipIfFirst, *toSkipIfFirst;
1643: struct vnode *from_vp, *to_vp;
1644: struct hfsmount *hfsmp;
1645: u_char tmp_name[NAME_MAX+1]; /* 256 bytes! */
1646: ExtendedVCB *vcb;
1647: u_int32_t fromFileID, toFileID;
1648: u_int32_t fromParID;
1649: u_int32_t tmpLong;
1650: int retval = E_NONE;
1651: DBG_FUNC_NAME("exchange");
1652: DBG_VOP_LOCKS_DECL(2);
1653: DBG_VOP_PRINT_FUNCNAME();
1654: DBG_VOP_PRINT_VNODE_INFO(ap->a_fvp);DBG_VOP_CONT(("\n"));
1655: DBG_VOP_PRINT_VNODE_INFO(ap->a_tvp);DBG_VOP_CONT(("\n"));
1656:
1657: DBG_VOP_LOCKS_INIT(0,ap->a_fvp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS);
1658: DBG_VOP_LOCKS_INIT(1,ap->a_tvp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS);
1659:
1660: /* Set up variables and checks */
1661: from_vp = ap->a_fvp;
1662: to_vp = ap->a_tvp;
1663: from_hp = VTOH(from_vp);
1664: to_hp = VTOH(to_vp);
1665: hfsmp = VTOHFS(from_vp);
1666: vcb = HTOVCB(from_hp);
1667: toFileID = H_FILEID(to_hp);
1668: fromFileID = H_FILEID(from_hp);
1669: fromParID = H_DIRID(from_hp);
1670:
1671: if (from_vp->v_mount != to_vp->v_mount) {
1672: DBG_VOP_LOCKS_TEST(EXDEV);
1673: return EXDEV;
1674: }
1675:
1676: /* Can only exchange file objects */
1677: if (from_vp->v_type != VREG || to_vp->v_type != VREG) {
1678: DBG_VOP_LOCKS_TEST(EINVAL);
1679: return EINVAL;
1680: }
1681:
1682: /*
1683: * Lock the siblink list
1684: * Check for multiple forks
1685: * If there are, we would need to:
1686: * 1. Unlock ourselves
1687: * 3. Traverse the list in a forward order...locking all vnodes
1688: * 4. Flush all buffers
1689: * 5. Perform the exchange
1690: * 6. Traverse the list in a reverse order...unlocking all vnodes, except orignal
1691: * Notice that the sibling lock is kept during the whole operation. This quarentees
1692: * that no new forks are taken off or put on
1693: */
1694: DBG_ASSERT(H_FORKTYPE(from_hp)==kDataFork && H_FORKTYPE(to_hp)==kDataFork);
1695: fromSkipIfFirst = toSkipIfFirst = NULL;
1696: simple_lock(&from_hp->h_meta->h_siblinglock);
1697: if (from_hp->h_meta->h_usecount > 1) {
1698: /*
1699: * This has siblings, so remember the passed-in vnode,
1700: * unlock it if it is not the 'first' sibling,
1701: * and then lock the rest of the vnodes by sibling order.
1702: * Notice that the passed-in vnode is not vrele(), this
1703: * keeps the usecount>0, so it wont go away.
1704: */
1705: if (from_hp->h_meta->h_siblinghead.cqh_first == from_hp) {
1706: fromSkipIfFirst = from_hp;
1707: nhp = from_hp->h_sibling.cqe_next;
1708: }
1709: else {
1710: VOP_UNLOCK(from_vp, 0, ap->a_p);
1711: nhp = from_hp->h_meta->h_siblinghead.cqh_first;
1712: };
1713:
1714: for (; nhp != (void *)&from_hp->h_meta->h_siblinghead; nhp = nhp->h_sibling.cqe_next) {
1715:
1716: if (vget(HTOV(nhp), LK_EXCLUSIVE | LK_RETRY, ap->a_p))
1717: continue; /* skip it, this shouldnt happen */
1718:
1719: /* Ignore any errors, we are doing a 'best effort' on flushing */
1720: (void) vinvalbuf(HTOV(nhp), V_SAVE, ap->a_cred, ap->a_p, 0, 0);
1721: };
1722: };
1723:
1724: simple_lock(&to_hp->h_meta->h_siblinglock);
1725: if (to_hp->h_meta->h_usecount > 1) {
1726:
1727: if (to_hp->h_meta->h_siblinghead.cqh_first == to_hp) {
1728: toSkipIfFirst = to_hp;
1729: nhp = to_hp->h_sibling.cqe_next;
1730: }
1731: else {
1732: VOP_UNLOCK(to_vp, 0, ap->a_p);
1733: nhp = to_hp->h_meta->h_siblinghead.cqh_first;
1734: };
1735:
1736:
1737: for (; nhp != (void *)&to_hp->h_meta->h_siblinghead; nhp = nhp->h_sibling.cqe_next) {
1738:
1739:
1740: if (vget(HTOV(nhp), LK_EXCLUSIVE | LK_RETRY, ap->a_p))
1741: continue; /* skip it, this shouldnt happen */
1742:
1743: /* Ignore any errors, we are doing a 'best effort' on flushing */
1744: (void) vinvalbuf(HTOV(nhp), V_SAVE, ap->a_cred, ap->a_p, 0, 0);
1745: };
1746: };
1747:
1748: /* lock catalog b-tree */
1749: retval = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, ap->a_p);
1750: if (retval) goto Err_Exit;
1751:
1752: /* lock extents b-tree iff there are overflow extents */
1753: /* XXX SER ExchangeFileIDs() always tries to delete the virtual extent id for exchanging files
1754: so we neeed the tree to be always locked.
1755: */
1756: retval = hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_EXCLUSIVE, ap->a_p);
1757: if (retval) goto Err_Exit_Relse;
1758:
1759: /* Do the exchange */
1760: retval = MacToVFSError( ExchangeFileIDs(vcb, H_NAME(from_hp), H_NAME(to_hp), H_DIRID(from_hp), H_DIRID(to_hp), H_HINT(from_hp), H_HINT(to_hp) ));
1761:
1762: (void) hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_RELEASE, ap->a_p);
1763:
1764: if (retval != E_NONE) {
1765: DBG_ERR(("/tError trying to exchange: %d\n", retval));
1766: goto Err_Exit_Relse;
1767: }
1768:
1769:
1770: /* Now exchange fileID, parID, name for the vnode itself */
1771: copystr(H_NAME(from_hp), (char*) tmp_name, strlen(H_NAME(from_hp))+1, NULL);
1772: hfs_chid(from_hp, toFileID, H_DIRID(to_hp), H_NAME(to_hp));
1773: hfs_chid(to_hp, fromFileID, fromParID, (char*) tmp_name);
1774:
1775: /* copy rest */
1776: tmpLong = HTOFCB(from_hp)->fcbFlags;
1777: HTOFCB(from_hp)->fcbFlags = HTOFCB(to_hp)->fcbFlags;
1778: HTOFCB(to_hp)->fcbFlags = tmpLong;
1779:
1780: tmpLong = from_hp->h_meta->h_crtime;
1781: from_hp->h_meta->h_crtime = to_hp->h_meta->h_crtime;
1782: to_hp->h_meta->h_crtime = tmpLong;
1783:
1784: tmpLong = from_hp->h_meta->h_butime;
1785: from_hp->h_meta->h_butime = to_hp->h_meta->h_butime;
1786: to_hp->h_meta->h_butime = tmpLong;
1787:
1788: tmpLong = from_hp->h_meta->h_atime;
1789: from_hp->h_meta->h_atime = to_hp->h_meta->h_atime;
1790: to_hp->h_meta->h_atime = tmpLong;
1791:
1792: tmpLong = from_hp->h_meta->h_ctime;
1793: from_hp->h_meta->h_ctime = to_hp->h_meta->h_ctime;
1794: to_hp->h_meta->h_ctime = tmpLong;
1795:
1796:
1797: tmpLong = from_hp->h_meta->h_gid;
1798: from_hp->h_meta->h_gid = to_hp->h_meta->h_gid;
1799: to_hp->h_meta->h_gid = tmpLong;
1800:
1801: tmpLong = from_hp->h_meta->h_uid;
1802: from_hp->h_meta->h_uid = to_hp->h_meta->h_uid;
1803: to_hp->h_meta->h_uid = tmpLong;
1804:
1805: tmpLong = from_hp->h_meta->h_pflags;
1806: from_hp->h_meta->h_pflags = to_hp->h_meta->h_pflags;
1807: to_hp->h_meta->h_pflags = tmpLong;
1808:
1809: tmpLong = from_hp->h_meta->h_mode;
1810: from_hp->h_meta->h_mode = to_hp->h_meta->h_mode;
1811: to_hp->h_meta->h_mode = tmpLong;
1812:
1813: tmpLong = from_hp->h_meta->h_rdev;
1814: from_hp->h_meta->h_rdev = to_hp->h_meta->h_rdev;
1815: to_hp->h_meta->h_rdev = tmpLong;
1816:
1817: tmpLong = from_hp->h_meta->h_size;
1818: from_hp->h_meta->h_size = to_hp->h_meta->h_size;
1819: to_hp->h_meta->h_size = tmpLong;
1820:
1821:
1822:
1823: Err_Exit_Relse:;
1824:
1825: /* unlock catalog b-tree */
1826: (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, ap->a_p);
1827:
1828:
1829:
1830: Err_Exit:;
1831:
1832: /* Unlock any forks, and the sibling list */
1833: if (to_hp->h_meta->h_usecount > 1) {
1834: for (nhp = to_hp->h_meta->h_siblinghead.cqh_last;
1835: nhp != (void *)&to_hp->h_meta->h_siblinghead; nhp = nhp->h_sibling.cqe_prev) {
1836: if (toSkipIfFirst && (nhp == toSkipIfFirst))
1837: continue;
1838: else if (HTOV(nhp)==to_vp)
1839: VRELE(HTOV(nhp)); /* decrement, return it locked */
1840: /*
1841: * A gotcha here, is that when locking, it might of failed
1842: * because the vnode was going away. Since vput() does not test for this,
1843: * we have to do this ourselves....but using the VXLOCK is bad, because
1844: * it should be private to vfs routines...but until another way is thought of...
1845: */
1846: else if (!(HTOV(nhp)->v_flag & VXLOCK)) {
1847: cache_purge(HTOV(nhp));
1848: VPUT(HTOV(nhp));
1849: };
1850: };
1851: };
1852:
1853: simple_unlock(&to_hp->h_meta->h_siblinglock);
1854:
1855: if (from_hp->h_meta->h_usecount > 1) {
1856: for (nhp = from_hp->h_meta->h_siblinghead.cqh_last;
1857: nhp != (void *)&from_hp->h_meta->h_siblinghead; nhp = nhp->h_sibling.cqe_prev) {
1858: if (fromSkipIfFirst && (nhp == fromSkipIfFirst))
1859: continue;
1860: else if (HTOV(nhp)==from_vp)
1861: VRELE(HTOV(nhp)); /* decrement, return it locked */
1862: else if (!(HTOV(nhp)->v_flag & VXLOCK)){
1863: cache_purge(HTOV(nhp));
1864: VPUT(HTOV(nhp));
1865: };
1866: };
1867: };
1868:
1869: simple_unlock(&from_hp->h_meta->h_siblinglock);
1870:
1871: /* Purge the vnodes from the namei...the names do not match vnodes now */
1872: cache_purge(from_vp);
1873: cache_purge(to_vp);
1874:
1875: /* XXX SER
1876: * At this point, the vnodes' data is switched, but are on the old hash list.
1877: * so move them to the right bucket. This couldnt be done until now, because the h_siblinglock
1878: * was being held.
1879: * Scenario:
1880: * A fork is trying to be added while exchanging...It got the hash lock,
1881: * but is waiting for the h_siblinglock. So we cannot try get the hash lock
1882: * until we release h_siblinglock, so it could continue, so it adds to the sibling list
1883: * and at the old place, so hfs_vhashmove has to move all vnodes with the old file id.
1884: * Not very pretty, becarefull that this works ok
1885: * Scenario 2:
1886: * Same as the above, but before the move is made (like at this very spot), the new vnode
1887: * is added and a vget is requested for that new vnode, it would have old data
1888: * WE MIGHT NEED TO LOCK THE HASH BECAUSE OF THIS !!!
1889: * Scenario 3:
1890: * Hey! Same as above, but it is added after all the moving
1891: * So now there is a vnode with the old data, on the old hash...it will become
1892: * lost next time that a vget() is done
1893: *
1894: * XXX SER A solution might be to NOT move the hash, but the data (extents) or the
1895: * opposite that we are doing now
1896: */
1897: hfs_vhashmove(from_hp, fromFileID);
1898: hfs_vhashmove(to_hp, toFileID);
1899:
1900: DBG_VOP_LOCKS_TEST(retval);
1901: return (retval);
1902: }
1903:
1904:
1905: /*
1906: * Change a vnode's file id, parent id and name
1907: *
1908: * Assumes the vnode is locked and is of type VREG
1909: */
1910: static void
1911: hfs_chid(struct hfsnode *hp, u_int32_t fid, u_int32_t pid, char* name)
1912: {
1913: DBG_ASSERT(HTOV(hp)->v_type == VREG);
1914:
1915: H_HINT(hp) = 0;
1916: H_FILEID(hp) = fid; /* change h_nodeID */
1917: H_DIRID(hp) = pid;
1918:
1919: hfs_set_metaname(name, hp->h_meta);
1920:
1921:
1922: }
1923:
1924:
1925: /*
1926:
1927: #% fsync vp L L L
1928: #
1929: vop_fsync {
1930: IN struct vnode *vp;
1931: IN struct ucred *cred;
1932: IN int waitfor;
1933: IN struct proc *p;
1934:
1935: */
1936:
1937:
1938: static int
1939: hfs_fsync(ap)
1940: struct vop_fsync_args /* {
1941: struct vnode *a_vp;
1942: struct ucred *a_cred;
1943: int a_waitfor;
1944: struct proc *a_p;
1945: } */ *ap;
1946: {
1947: struct vnode *vp = ap->a_vp ;
1948: struct hfsnode *hp = VTOH(vp);
1949: int retval = 0;
1950: register struct buf *bp;
1951: struct timeval tv;
1952: struct buf *nbp;
1953: int s;
1954:
1955: DBG_FUNC_NAME("fsync");
1956: DBG_VOP_LOCKS_DECL(1);
1957: DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT((" "));
1958: DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
1959: DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_ZERO);
1960: DBG_HFS_NODE_CHECK(ap->a_vp);
1961:
1962: #if HFS_DIAGNOSTIC
1963: DBG_ASSERT(*((int*)&vp->v_interlock) == 0);
1964: #endif
1965:
1966:
1967: /*
1968: * First of all, write out any clusters.
1969: */
1970: if (doclusterwrite) {
1971: long devBlockSize = 0;
1972:
1973: VOP_DEVBLOCKSIZE(hp->h_meta->h_devvp, &devBlockSize);
1974: cluster_close(vp, PAGE_SIZE, devBlockSize);
1975: };
1976:
1977: /*
1978: * Flush all dirty buffers associated with a vnode.
1979: */
1980: loop:
1981: s = splbio();
1982: for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
1983: nbp = bp->b_vnbufs.le_next;
1984: if ((bp->b_flags & B_BUSY))
1985: continue;
1986: if ((bp->b_flags & B_DELWRI) == 0)
1987: panic("hfs_fsync: not dirty");
1988: bremfree(bp);
1989: bp->b_flags |= B_BUSY;
1990: bp->b_flags &= ~B_LOCKED; /* Clear flag, should only be set on meta files */
1991: splx(s);
1992: /*
1993: * Wait for I/O associated with indirect blocks to complete,
1994: * since there is no way to quickly wait for them below.
1995: */
1996: DBG_VOP(("\t\t\tFlushing out phys block %d == log block %d\n", bp->b_blkno, bp->b_lblkno));
1997: if (bp->b_vp == vp || ap->a_waitfor == MNT_NOWAIT) {
1998: (void) bawrite(bp);
1999: } else {
2000: (void) bwrite(bp);
2001: }
2002: goto loop;
2003: }
2004:
2005: if (ap->a_waitfor == MNT_WAIT) {
2006: while (vp->v_numoutput) {
2007: vp->v_flag |= VBWAIT;
2008: tsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "hfs_fsync", 0);
2009: }
2010:
2011: /* I have seen this happen for swapfile. So it is safer to
2012: * check for dirty buffers again. --Umesh
2013: */
2014: if (vp->v_dirtyblkhd.lh_first) {
2015: vprint("hfs_fsync: dirty", vp);
2016: splx(s);
2017: goto loop;
2018: }
2019: }
2020: splx(s);
2021:
2022: #if HFS_DIAGNOSTIC
2023: DBG_ASSERT(*((int*)&vp->v_interlock) == 0);
2024: #endif
2025:
2026: tv = time;
2027: if ((vp->v_flag & VSYSTEM) && (hp->fcbBTCBPtr!=NULL))
2028: BTSetLastSync(HTOFCB(hp), tv.tv_sec);
2029:
2030: if (H_FORKTYPE(hp) != kSysFile) {
2031: retval = VOP_UPDATE(ap->a_vp, &tv, &tv, ap->a_waitfor == MNT_WAIT);
2032:
2033: if (retval != E_NONE) {
2034: DBG_ERR(("%s: FLUSH FAILED: %s\n", funcname, H_NAME(hp)));
2035: }
2036: }
2037: else
2038: hp->h_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE);
2039:
2040: if (ap->a_waitfor == MNT_WAIT) {
2041: DBG_ASSERT(vp->v_dirtyblkhd.lh_first == NULL);
2042: };
2043: DBG_VOP_LOCKS_TEST(retval);
2044: DBG_ASSERT(*((int*)&vp->v_interlock) == 0);
2045: return (retval);
2046: }
2047:
2048:
2049: int
2050: hfs_fsync_transaction(struct vnode *vp)
2051: {
2052: struct hfsnode *hp = VTOH(vp);
2053: register struct buf *bp;
2054: struct timeval tv;
2055: struct buf *nbp;
2056: int s;
2057:
2058: /*
2059: * Flush all dirty buffers associated with a vnode.
2060: */
2061: loop:
2062: s = splbio();
2063:
2064: for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
2065: nbp = bp->b_vnbufs.le_next;
2066: if ((bp->b_flags & B_BUSY))
2067: continue;
2068: if ((bp->b_flags & B_DELWRI) == 0)
2069: panic("hfs_fsync: not dirty");
2070: if ( !(bp->b_flags & B_LOCKED))
2071: continue;
2072:
2073: bremfree(bp);
2074: bp->b_flags |= B_BUSY;
2075: bp->b_flags &= ~B_LOCKED; /* Clear flag, should only be set on meta files */
2076: splx(s);
2077:
2078: (void) bawrite(bp);
2079:
2080: goto loop;
2081: }
2082: splx(s);
2083:
2084: tv = time;
2085: if ((vp->v_flag & VSYSTEM) && (hp->fcbBTCBPtr!=NULL))
2086: (void) BTSetLastSync(VTOFCB(vp), tv.tv_sec);
2087: hp->h_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE);
2088:
2089: return 0;
2090: }
2091:
2092: /*
2093:
2094: #% remove dvp L U U
2095: #% remove vp L U U
2096: #
2097: vop_remove {
2098: IN WILLRELE struct vnode *dvp;
2099: IN WILLRELE struct vnode *vp;
2100: IN struct componentname *cnp;
2101:
2102: */
2103:
2104: int
2105: hfs_remove(ap)
2106: struct vop_remove_args /* {
2107: struct vnode *a_dvp;
2108: struct vnode *a_vp;
2109: struct componentname *a_cnp;
2110: } */ *ap;
2111: {
2112: struct vnode *vp = ap->a_vp;
2113: struct vnode *dvp = ap->a_dvp;
2114: struct hfsnode *hp = VTOH(ap->a_vp);
2115: struct hfsmount *hfsmp = HTOHFS(hp);
2116: struct proc *p = current_proc();
2117: struct timeval tv;
2118: int retval, use_count, hasSiblings;
2119: int filebusy = 0;
2120: DBG_FUNC_NAME("remove");
2121: DBG_VOP_LOCKS_DECL(2);
2122: DBG_VOP_PRINT_FUNCNAME();
2123: DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);
2124: DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);DBG_VOP_CONT(("\n"));
2125: DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
2126: DBG_VOP_LOCKS_INIT(1,ap->a_vp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
2127:
2128: hasSiblings = false;
2129: retval = E_NONE;
2130:
2131: if ((hp->h_meta->h_pflags & (IMMUTABLE | APPEND)) ||
2132: (VTOH(dvp)->h_meta->h_pflags & APPEND)) {
2133: retval = EPERM;
2134: goto out;
2135: }
2136:
2137: if (vp->v_usecount > 1) {
2138: /* Mac OS clients can't delete busy files */
2139: if ((ap->a_cnp->cn_flags & NODELETEBUSY) || (hfsmp->hfs_private_metadata_dir == 0)) {
2140: retval = EBUSY;
2141: goto out;
2142: } else
2143: filebusy = 1;
2144: }
2145:
2146: tv = time; /* Done here, so all times are the same */
2147:
2148: /* Check other siblings for in use also */
2149: /* XXX SER MUST BE CHANGED BY MACOS X because of vnode_uncache */
2150: /* Uncache everything and make sure no other usecount */
2151: /*
2152: * a. loop through the siblings looking for matches
2153: * b. If we find ourselves...skip it
2154: * If there was a sibling:
2155: * a. Check for a positve usecount
2156: * b. uncache any pages
2157: * c. Write out and memory changes
2158: * The idea is to keep the h_siblinglock as little as possible
2159: */
2160: if (hp->h_meta->h_siblinghead.cqh_first && (hp->h_meta->h_siblinghead.cqh_first != hp->h_meta->h_siblinghead.cqh_last)) {
2161: simple_lock(&hp->h_meta->h_siblinglock);
2162: hasSiblings = true;
2163: }
2164:
2165: if (hasSiblings) {
2166: struct vnode *tvp;
2167: struct hfsnode *nhp;
2168:
2169: DBG_ASSERT(H_FORKTYPE(hp)==kDataFork || H_FORKTYPE(hp)==kRsrcFork);
2170: /* Lock the sibling list, this ensures no entry leaves or is added unexpectanly */
2171:
2172: /* Loop through all siblings, skipping ourselves */
2173: for (nhp = hp->h_meta->h_siblinghead.cqh_first; nhp != (void *)&hp->h_meta->h_siblinghead; nhp = nhp->h_sibling.cqe_next) {
2174: if (nhp == hp) /* skip ourselves */
2175: continue;
2176: tvp = HTOV(nhp);
2177:
2178: /* Check to see if other forks are in use */
2179: simple_lock(&tvp->v_interlock);
2180: use_count = tvp->v_usecount;
2181: simple_unlock(&tvp->v_interlock);
2182: if (use_count > 0) {
2183: if (ap->a_cnp->cn_flags & NODELETEBUSY || hfsmp->hfs_private_metadata_dir == 0) {
2184: retval = EBUSY;
2185: break;
2186: }
2187: else
2188: filebusy = 1;
2189: };
2190:
2191: /* Get a lock, for the rest */
2192: /* The only error that vget returns is when the vnode is going away, so ignore it */
2193: if (vget(tvp, LK_EXCLUSIVE | LK_RETRY, p))
2194: continue;
2195:
2196: /*
2197: * XXX SER vnode_uncache() unlocks the vnode and the wait
2198: * to regain the lock. VERY BAD. This behavior should be changed in
2199: * the future.
2200: * See the comment in vnode_uncache()
2201: */
2202: (void) vnode_uncache(tvp);
2203:
2204: /*
2205: * Should be relocked at this point..now flush out the memory
2206: * XXX SER An intelligient person would ask, why flush out changes
2207: * that are going to be deleted? See the next comment.
2208: */
2209: if ((nhp->h_nodeflags & IN_MODIFIED) || (VTOFCB(tvp)->fcbFlags & fcbModifiedMask))
2210: {
2211: DBG_ASSERT((VTOH(tvp)->h_nodeflags & IN_MODIFIED) != 0);
2212: VOP_UPDATE(tvp, &tv, &tv, 0);
2213: };
2214:
2215: VPUT(tvp);
2216:
2217: };
2218:
2219: simple_unlock(&hp->h_meta->h_siblinglock);
2220:
2221: if (retval)
2222: goto out;
2223:
2224: };
2225:
2226: /*
2227: * remove the entry from the namei cache:
2228: * We do it early before any linking/busy file wierdness, make sure the
2229: * original is gone
2230: */
2231: cache_purge(vp);
2232:
2233: /* Flush out any catalog changes */
2234: /* XXX SER: This is a hack, becasue hfsDelete reads the data from the disk
2235: * and not from memory which is more correct
2236: */
2237: if ((hp->h_nodeflags & IN_MODIFIED) || (HTOFCB(hp)->fcbFlags & fcbModifiedMask))
2238: {
2239: DBG_ASSERT((hp->h_nodeflags & IN_MODIFIED) != 0);
2240: VOP_UPDATE(vp, &tv, &tv, 0);
2241: }
2242:
2243: /* lock catalog b-tree */
2244: retval = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p);
2245: if (retval != E_NONE) {
2246: retval = EBUSY;
2247: goto out;
2248: }
2249:
2250:
2251: #if HFS_HARDLINKS
2252: /*
2253: * Multi-linked files just need their link node deleted from the catalog
2254: */
2255: if (hp->h_meta->h_metaflags & IN_DATANODE) {
2256:
2257: if ((ap->a_cnp->cn_flags & HASBUF) == 0 ||
2258: ap->a_cnp->cn_nameptr[0] == '\0') {
2259: retval = ENOENT; /* name missing */
2260: goto out2;
2261: }
2262:
2263: /* lock extents b-tree (also protects volume bitmap) */
2264: retval = hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_EXCLUSIVE, p);
2265: if (retval != E_NONE) {
2266: retval = EBUSY;
2267: goto out2; /* unlock catalog b-tree on the way out */
2268: }
2269:
2270: retval = hfsDelete (HTOVCB(hp), H_FILEID(VTOH(dvp)),
2271: ap->a_cnp->cn_nameptr, TRUE, H_HINT(hp));
2272:
2273: (void) hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_RELEASE, p);
2274:
2275: if (retval != 0)
2276: goto out2;
2277:
2278: hp->h_nodeflags |= IN_CHANGE;
2279: if (--hp->h_meta->h_nlink < 1)
2280: hp->h_meta->h_metaflags |= IN_DELETED;
2281:
2282: /* name and parent fields are no longer valid so invalidate them */
2283: H_DIRID(hp) = kUnknownID;
2284: hfs_set_metaname("\0", hp->h_meta);
2285:
2286: if ((ap->a_cnp->cn_flags & (HASBUF | SAVENAME)) == (HASBUF | SAVENAME))
2287: FREE_ZONE(ap->a_cnp->cn_pnbuf, ap->a_cnp->cn_pnlen, M_NAMEI);
2288:
2289: goto out2; /* link deleted, all done */
2290: }
2291: #endif
2292:
2293: /*
2294: * To make the HFS filesystem follow UFS unlink semantics, a remove of
2295: * an active vnode is translated to a move/rename so the file appears
2296: * deleted. Later, the file is removed by hfs_inactive on the hfsnode.
2297: */
2298: if (filebusy) {
2299: UInt32 hint = H_HINT(hp);
2300: char nodeName[32];
2301:
2302: MAKE_DELETED_NAME(nodeName, H_FILEID(hp));
2303:
2304: retval = hfsMoveRename (HTOVCB(hp), H_DIRID(hp), H_NAME(hp),
2305: hfsmp->hfs_private_metadata_dir, nodeName, &hint);
2306: if (retval) goto out2;
2307:
2308: hp->h_meta->h_metaflags |= IN_DELETED;
2309: hp->h_nodeflags |= IN_CHANGE;
2310:
2311: /* update name so Catalog lookups succeed */
2312: H_HINT(hp) = hint;
2313: H_DIRID(hp) = hfsmp->hfs_private_metadata_dir;
2314: hfs_set_metaname(nodeName, hp->h_meta);
2315:
2316: goto out2; /* all done, unlock the catalog */
2317: }
2318:
2319: /* Invalidate the buffers */
2320: if ((retval= vinvalbuf(vp, 0, NOCRED, p, 0, 0)))
2321: goto out2;
2322:
2323: /* lock extents b-tree (also protects volume bitmap) */
2324: retval = hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_EXCLUSIVE, p);
2325: if (retval != E_NONE) {
2326: retval = EBUSY;
2327: goto out2; /* unlock catalog b-tree on the way out */
2328: }
2329:
2330: /* remove entry from catalog and free any blocks used */
2331: retval = hfsDelete (HTOVCB(hp), H_DIRID(hp), H_NAME(hp), TRUE, H_HINT(hp));
2332:
2333: /* Clean up */
2334: (void) hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_RELEASE, p);
2335:
2336: hp->h_meta->h_mode = 0; /* Makes the node go away...see inactive */
2337: /* XXX SER Anything else so that sibling, if any, goes away */
2338:
2339: out2:
2340: (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p);
2341:
2342: out:;
2343:
2344: if (! retval)
2345: VTOH(dvp)->h_nodeflags |= IN_CHANGE | IN_UPDATE;
2346:
2347: if (dvp == vp) {
2348: VRELE(vp);
2349: } else {
2350: VPUT(vp);
2351: };
2352:
2353: VPUT(dvp);
2354: DBG_VOP_LOCKS_TEST(retval);
2355: return (retval);
2356: }
2357:
2358:
2359: /*
2360:
2361: #% rename sourcePar_vp U U U
2362: #% rename source_vp U U U
2363: #% rename targetPar_vp L U U
2364: #% rename target_vp X U U
2365: #
2366: vop_rename {
2367: IN WILLRELE struct vnode *sourcePar_vp;
2368: IN WILLRELE struct vnode *source_vp;
2369: IN struct componentname *source_cnp;
2370: IN WILLRELE struct vnode *targetPar_vp;
2371: IN WILLRELE struct vnode *target_vp;
2372: IN struct componentname *target_cnp;
2373:
2374:
2375: */
2376: /*
2377: * On entry:
2378: * source's parent directory is unlocked
2379: * source file or directory is unlocked
2380: * destination's parent directory is locked
2381: * destination file or directory is locked if it exists
2382: *
2383: * On exit:
2384: * all denodes should be released
2385: *
2386: */
2387:
2388: static int
2389: hfs_rename(ap)
2390: struct vop_rename_args /* {
2391: struct vnode *a_fdvp;
2392: struct vnode *a_fvp;
2393: struct componentname *a_fcnp;
2394: struct vnode *a_tdvp;
2395: struct vnode *a_tvp;
2396: struct componentname *a_tcnp;
2397: } */ *ap;
2398: {
2399: struct vnode *target_vp = ap->a_tvp;
2400: struct vnode *targetPar_vp = ap->a_tdvp;
2401: struct vnode *source_vp = ap->a_fvp;
2402: struct vnode *sourcePar_vp = ap->a_fdvp;
2403: struct componentname *target_cnp = ap->a_tcnp;
2404: struct componentname *source_cnp = ap->a_fcnp;
2405: struct proc *p = source_cnp->cn_proc;
2406: struct hfsnode *target_hp, *targetPar_hp, *source_hp, *sourcePar_hp;
2407: u_short doingdirectory = 0, oldparent = 0, newparent = 0;
2408: int retval = 0;
2409: struct timeval tv;
2410: struct hfsCatalogInfo catInfo;
2411: DBG_VOP_LOCKS_DECL(4);
2412:
2413: DBG_FUNC_NAME("rename");DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT(("\n"));
2414: DBG_VOP_CONT(("\t"));DBG_VOP_CONT(("Source:\t"));DBG_VOP_PRINT_VNODE_INFO(ap->a_fvp);DBG_VOP_CONT(("\n"));
2415: DBG_VOP_CONT(("\t"));DBG_VOP_CONT(("SourcePar: "));DBG_VOP_PRINT_VNODE_INFO(ap->a_fdvp);DBG_VOP_CONT(("\n"));
2416: DBG_VOP_CONT(("\t"));DBG_VOP_CONT(("Target:\t"));DBG_VOP_PRINT_VNODE_INFO(ap->a_tvp);DBG_VOP_CONT(("\n"));
2417: DBG_VOP_CONT(("\t"));DBG_VOP_CONT(("TargetPar: "));DBG_VOP_PRINT_VNODE_INFO(ap->a_tdvp);DBG_VOP_CONT(("\n"));
2418: DBG_VOP_CONT(("\t"));DBG_VOP_CONT(("SourceName:\t"));DBG_VOP_PRINT_CPN_INFO(ap->a_fcnp);DBG_VOP_CONT(("\n"));
2419: DBG_VOP_CONT(("\t"));DBG_VOP_CONT(("TargetName:\t"));DBG_VOP_PRINT_CPN_INFO(ap->a_tcnp);DBG_VOP_CONT(("\n"));
2420: DBG_VOP_LOCKS_INIT(0,ap->a_fdvp, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
2421: DBG_VOP_LOCKS_INIT(1,ap->a_fvp, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
2422: DBG_VOP_LOCKS_INIT(2,ap->a_tdvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
2423: DBG_VOP_LOCKS_INIT(3,ap->a_tvp, VOPDBG_LOCKNOTNIL, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
2424: WRITE_CK(ap->a_fdvp, funcname);
2425: DBG_HFS_NODE_CHECK(ap->a_fdvp);
2426: DBG_HFS_NODE_CHECK(ap->a_tdvp);
2427:
2428: #if HFS_DIAGNOSTIC
2429: if ((target_cnp->cn_flags & HASBUF) == 0 ||
2430: (source_cnp->cn_flags & HASBUF) == 0)
2431: panic("hfs_rename: no name");
2432: #endif
2433:
2434: DBG_ASSERT((ap->a_fdvp->v_type == VDIR) && (ap->a_tdvp->v_type == VDIR));
2435: target_hp = targetPar_hp = source_hp = sourcePar_hp = 0;
2436:
2437: /*
2438: * Check for cross-device rename.
2439: */
2440: if ((source_vp->v_mount != targetPar_vp->v_mount) ||
2441: (target_vp && (source_vp->v_mount != target_vp->v_mount))) {
2442: retval = EXDEV;
2443: goto abortit;
2444: }
2445:
2446: /*
2447: * Check for access permissions
2448: */
2449: if (target_vp && ((VTOH(target_vp)->h_meta->h_pflags & (IMMUTABLE | APPEND)) ||
2450: (VTOH(targetPar_vp)->h_meta->h_pflags & APPEND))) {
2451: retval = EPERM;
2452: goto abortit;
2453: }
2454:
2455: if ((retval = vn_lock(source_vp, LK_EXCLUSIVE, p)))
2456: goto abortit;
2457:
2458: sourcePar_hp = VTOH(sourcePar_vp);
2459: source_hp = VTOH(source_vp);
2460: oldparent = H_FILEID(sourcePar_hp);
2461: if ((source_hp->h_meta->h_pflags & (IMMUTABLE | APPEND)) || (sourcePar_hp->h_meta->h_pflags & APPEND)) {
2462: VOP_UNLOCK(source_vp, 0, p);
2463: retval = EPERM;
2464: goto abortit;
2465: }
2466:
2467: /*
2468: * Be sure we are not renaming ".", "..", or an alias of ".". This
2469: * leads to a crippled directory tree. It's pretty tough to do a
2470: * "ls" or "pwd" with the "." directory entry missing, and "cd .."
2471: * doesn't work if the ".." entry is missing.
2472: */
2473: if ((source_hp->h_meta->h_mode & IFMT) == IFDIR) {
2474: if ((source_cnp->cn_namelen == 1 && source_cnp->cn_nameptr[0] == '.')
2475: || sourcePar_hp == source_hp
2476: || (source_cnp->cn_flags&ISDOTDOT)
2477: || (source_hp->h_nodeflags & IN_RENAME)) {
2478: VOP_UNLOCK(source_vp, 0, p);
2479: retval = EINVAL;
2480: goto abortit;
2481: }
2482: source_hp->h_nodeflags |= IN_RENAME;
2483: doingdirectory = TRUE;
2484: }
2485:
2486: /*
2487: *
2488: * >>>> Transit between abort and bad <<<<
2489: *
2490: */
2491:
2492: targetPar_hp = VTOH(targetPar_vp);
2493: if (target_vp)
2494: target_hp = VTOH(target_vp);
2495: else
2496: DBG_ASSERT(target_hp == NULL);
2497:
2498: newparent = H_FILEID(targetPar_hp);
2499:
2500: /* Test to make sure we are not crossing devices */
2501: /* XXX SER Is this necesary, does catalog manager take care of this? */
2502: if (target_vp) {
2503: if (H_DEV(target_hp) != H_DEV(targetPar_hp) || H_DEV(target_hp) != H_DEV(source_hp))
2504: panic("rename: EXDEV");
2505: }
2506: else {
2507: if (H_DEV(targetPar_hp) != H_DEV(source_hp))
2508: panic("rename: EXDEV");
2509: };
2510:
2511: retval = VOP_ACCESS(source_vp, VWRITE, target_cnp->cn_cred, target_cnp->cn_proc);
2512: if (doingdirectory && (newparent != oldparent)) {
2513: if (retval) /* write access check above */
2514: goto bad;
2515: }
2516: retval = 0; /* Reset value from above, we dont care about it anymore */
2517:
2518: /*
2519: * If the destination exists, then be sure its type (file or dir)
2520: * matches that of the source. And, if it is a directory make sure
2521: * it is empty. Then delete the destination.
2522: */
2523: if (target_vp) {
2524:
2525: /*
2526: * If the parent directory is "sticky", then the user must
2527: * own the parent directory, or the destination of the rename,
2528: * otherwise the destination may not be changed (except by
2529: * root). This implements append-only directories.
2530: */
2531: if ((targetPar_hp->h_meta->h_mode & S_ISTXT) && (target_cnp->cn_cred->cr_uid != 0) &&
2532: target_cnp->cn_cred->cr_uid != targetPar_hp->h_meta->h_uid &&
2533: target_cnp->cn_cred->cr_uid != target_hp->h_meta->h_uid) {
2534: retval = EPERM;
2535: goto bad;
2536: }
2537:
2538: /*
2539: * VOP_REMOVE will vput targetPar_vp so we better bump
2540: * its ref count and relockit, always set target_vp to
2541: * NULL afterwards to indicate that were done with it.
2542: */
2543: VREF(targetPar_vp);
2544: if (target_vp->v_type == VREG) {
2545: (void) vnode_uncache(target_vp);
2546: if (ISMAPPEDFILE(target_vp)) {
2547: ubc_unlink(target_vp);
2548: }
2549: }
2550: cache_purge(target_vp);
2551:
2552: #if HFS_HARDLINKS
2553: target_cnp->cn_flags &= ~SAVENAME;
2554: #endif
2555: retval = VOP_REMOVE(targetPar_vp, target_vp, target_cnp);
2556: (void) vn_lock(targetPar_vp, LK_EXCLUSIVE | LK_RETRY, p);
2557:
2558: target_vp = NULL;
2559: target_hp = NULL;
2560:
2561: if (retval) goto bad;
2562:
2563: };
2564:
2565:
2566: if (newparent != oldparent)
2567: vn_lock(sourcePar_vp, LK_EXCLUSIVE | LK_RETRY, p);
2568:
2569: /* lock catalog b-tree */
2570: retval = hfs_metafilelocking(VTOHFS(source_vp), kHFSCatalogFileID, LK_EXCLUSIVE, p);
2571: if (retval) {
2572: if (newparent != oldparent) /* unlock the lock we just got */
2573: VOP_UNLOCK(sourcePar_vp, 0, p);
2574: goto bad;
2575: };
2576:
2577: /* remove the existing entry from the namei cache: */
2578: cache_purge(source_vp);
2579:
2580: /* use source_cnp instead of H_NAME(source_hp) in case source is a hard link */
2581: retval = hfsMoveRename( HTOVCB(source_hp), H_DIRID(source_hp), source_cnp->cn_nameptr,
2582: H_FILEID(VTOH(targetPar_vp)), target_cnp->cn_nameptr, &H_HINT(source_hp));
2583:
2584: if (retval == 0) {
2585: /* Look up the catalog entry just renamed since it might have been auto-decomposed */
2586: catInfo.hint = H_HINT(source_hp);
2587: retval = hfsLookup(HTOVCB(source_hp), H_FILEID(targetPar_hp), target_cnp->cn_nameptr, target_cnp->cn_namelen, &catInfo);
2588: }
2589:
2590: /* unlock catalog b-tree */
2591: (void) hfs_metafilelocking(VTOHFS(source_vp), kHFSCatalogFileID, LK_RELEASE, p);
2592:
2593: if (newparent != oldparent)
2594: VOP_UNLOCK(sourcePar_vp, 0, p);
2595:
2596: if (retval) goto bad;
2597:
2598: H_DIRID(source_hp) = H_FILEID(targetPar_hp);
2599:
2600: hfs_set_metaname(catInfo.spec.name, source_hp->h_meta);
2601:
2602: source_hp->h_nodeflags &= ~IN_RENAME;
2603:
2604:
2605: /*
2606: * Timestamp both parent directories.
2607: * Note that if this is a rename within the same directory,
2608: * (where targetPar_hp == sourcePar_hp)
2609: * the code below is still safe and correct.
2610: */
2611: targetPar_hp->h_nodeflags |= IN_UPDATE;
2612: sourcePar_hp->h_nodeflags |= IN_UPDATE;
2613: tv = time;
2614: HFSTIMES(targetPar_hp, &tv, &tv);
2615: HFSTIMES(sourcePar_hp, &tv, &tv);
2616:
2617: VPUT(targetPar_vp);
2618: VRELE(sourcePar_vp);
2619: VPUT(source_vp);
2620:
2621: DBG_VOP_LOCKS_TEST(retval);
2622: if (retval != E_NONE) {
2623: DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT(("\tReturning with error %d\n",retval));
2624: }
2625: return (retval);
2626:
2627: bad:;
2628: if (retval && doingdirectory)
2629: source_hp->h_nodeflags &= ~IN_RENAME;
2630:
2631: if (targetPar_vp == target_vp)
2632: VRELE(targetPar_vp);
2633: else
2634: VPUT(targetPar_vp);
2635:
2636: if (target_vp)
2637: VPUT(target_vp);
2638:
2639: VRELE(sourcePar_vp);
2640:
2641: if (VOP_ISLOCKED(source_vp))
2642: VPUT(source_vp);
2643: else
2644: VRELE(source_vp);
2645:
2646: DBG_VOP_LOCKS_TEST(retval);
2647: if (retval != E_NONE) {
2648: DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT(("\tReturning with error %d\n",retval));
2649: }
2650: return (retval);
2651:
2652: abortit:;
2653:
2654: VOP_ABORTOP(targetPar_vp, target_cnp); /* XXX, why not in NFS? */
2655:
2656: if (targetPar_vp == target_vp)
2657: VRELE(targetPar_vp);
2658: else
2659: VPUT(targetPar_vp);
2660:
2661: if (target_vp)
2662: VPUT(target_vp);
2663:
2664: VOP_ABORTOP(sourcePar_vp, source_cnp); /* XXX, why not in NFS? */
2665:
2666: VRELE(sourcePar_vp);
2667: VRELE(source_vp);
2668:
2669: DBG_VOP_LOCKS_TEST(retval);
2670: if (retval != E_NONE) {
2671: DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT(("\tReturning with error %d\n",retval));
2672: }
2673: return (retval);
2674: }
2675:
2676:
2677:
2678: /*
2679: * Mkdir system call
2680: #% mkdir dvp L U U
2681: #% mkdir vpp - L -
2682: #
2683: vop_mkdir {
2684: IN WILLRELE struct vnode *dvp;
2685: OUT struct vnode **vpp;
2686: IN struct componentname *cnp;
2687: IN struct vattr *vap;
2688:
2689: We are responsible for freeing the namei buffer, it is done in hfs_makenode(), unless there is
2690: a previous error.
2691:
2692: */
2693:
2694: int
2695: hfs_mkdir(ap)
2696: struct vop_mkdir_args /* {
2697: struct vnode *a_dvp;
2698: struct vnode **a_vpp;
2699: struct componentname *a_cnp;
2700: struct vattr *a_vap;
2701: } */ *ap;
2702: {
2703: struct proc *p = current_proc();
2704: int retval;
2705: int mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode);
2706:
2707: DBG_FUNC_NAME("mkdir");
2708: DBG_VOP_LOCKS_DECL(2);
2709: DBG_VOP_PRINT_FUNCNAME();
2710: DBG_VOP_PRINT_VNODE_INFO(ap->a_dvp);
2711: DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);DBG_VOP_CONT(("\n"));
2712:
2713: DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
2714: DBG_VOP_LOCKS_INIT(1,*ap->a_vpp, VOPDBG_IGNORE, VOPDBG_LOCKED, VOPDBG_IGNORE, VOPDBG_POS);
2715:
2716: DBG_VOP(("%s: parent 0x%x (%s) ap->a_cnp->cn_nameptr %s\n", funcname, (u_int)VTOH(ap->a_dvp), H_NAME(VTOH(ap->a_dvp)), ap->a_cnp->cn_nameptr));
2717: WRITE_CK( ap->a_dvp, funcname);
2718: DBG_HFS_NODE_CHECK(ap->a_dvp);
2719: DBG_ASSERT(ap->a_dvp->v_type == VDIR);
2720:
2721: /* lock catalog b-tree */
2722: retval = hfs_metafilelocking(VTOHFS(ap->a_dvp), kHFSCatalogFileID, LK_EXCLUSIVE, p);
2723: if (retval != E_NONE) {
2724: VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
2725: VPUT(ap->a_dvp);
2726: DBG_VOP_LOCKS_TEST( retval);
2727: return (retval);
2728: }
2729:
2730: /* Create the vnode */
2731: DBG_ASSERT((ap->a_cnp->cn_flags & SAVESTART) == 0);
2732: retval = hfs_makenode(mode, 0, ap->a_dvp, ap->a_vpp, ap->a_cnp);
2733: DBG_VOP_UPDATE_VP(1, *ap->a_vpp);
2734:
2735: /* unlock catalog b-tree */
2736: (void) hfs_metafilelocking(VTOHFS(ap->a_dvp), kHFSCatalogFileID, LK_RELEASE, p);
2737:
2738: if (retval != E_NONE) {
2739: DBG_ERR(("%s: hfs_makenode FAILED: %s, %s\n", funcname, ap->a_cnp->cn_nameptr, H_NAME(VTOH(ap->a_dvp))));
2740: DBG_VOP_LOCKS_TEST(retval);
2741: return (retval);
2742: }
2743:
2744: DBG_VOP_LOCKS_TEST(E_NONE);
2745: return (E_NONE);
2746: }
2747:
2748: /*
2749: * Rmdir system call.
2750: #% rmdir dvp L U U
2751: #% rmdir vp L U U
2752: #
2753: vop_rmdir {
2754: IN WILLRELE struct vnode *dvp;
2755: IN WILLRELE struct vnode *vp;
2756: IN struct componentname *cnp;
2757:
2758: */
2759:
2760: int
2761: hfs_rmdir(ap)
2762: struct vop_rmdir_args /* {
2763: struct vnode *a_dvp;
2764: struct vnode *a_vp;
2765: struct componentname *a_cnp;
2766: } */ *ap;
2767: {
2768: struct vnode *vp = ap->a_vp;
2769: struct vnode *dvp = ap->a_dvp;
2770: struct hfsnode *hp = VTOH(vp);
2771: struct proc *p = current_proc();
2772: int retval;
2773: DBG_FUNC_NAME("rmdir");
2774: DBG_VOP_LOCKS_DECL(2);
2775: DBG_VOP_PRINT_FUNCNAME();
2776: DBG_VOP(("\tParent: "));DBG_VOP_PRINT_VNODE_INFO(ap->a_dvp);DBG_VOP_CONT(("\n"));
2777: DBG_VOP(("\tTarget: "));DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
2778: DBG_VOP(("\tTarget Name: "));DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);DBG_VOP_CONT(("\n"));
2779:
2780: DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
2781: DBG_VOP_LOCKS_INIT(1,ap->a_vp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
2782:
2783: if (dvp == vp) {
2784: VRELE(vp);
2785: VPUT(vp);
2786: DBG_VOP_LOCKS_TEST(EINVAL);
2787: return (EINVAL);
2788: }
2789:
2790: /*
2791: * HFS differs from UFS here in that we don't allow removing
2792: * a directory that in use by others - even if its empty.
2793: *
2794: * In the future we might want to allow this just like we do
2795: * for files (by renaming the busy directory).
2796: */
2797: #if 0
2798: if (vp->v_usecount > 1) {
2799: DBG_ERR(("%s: dir is busy, usecount is %d\n", funcname, vp->v_usecount ));
2800: retval = EBUSY;
2801: goto Err_Exit;
2802: }
2803: #endif
2804: /* remove the entry from the namei cache: */
2805: cache_purge(vp);
2806:
2807: /* lock catalog b-tree */
2808: retval = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_EXCLUSIVE, p);
2809: if (retval != E_NONE) {
2810: goto Err_Exit;
2811: }
2812:
2813: /* remove entry from catalog */
2814: retval = hfsDelete (HTOVCB(hp), H_DIRID(hp), H_NAME(hp), FALSE, H_HINT(hp));
2815: hp->h_meta->h_mode = 0; /* Makes the vnode go away...see inactive */
2816:
2817: /* unlock catalog b-tree */
2818: (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, p);
2819:
2820: /* Set the parent to be updated */
2821: if (! retval)
2822: VTOH(dvp)->h_nodeflags |= IN_CHANGE | IN_UPDATE;
2823:
2824: Err_Exit:;
2825: if (dvp != 0)
2826: VPUT(dvp);
2827: VPUT(vp);
2828:
2829: DBG_VOP_LOCKS_TEST(retval);
2830: return (retval);
2831: }
2832:
2833: /*
2834: * symlink -- make a symbolic link
2835: #% symlink dvp L U U
2836: #% symlink vpp - U -
2837: #
2838: # XXX - note that the return vnode has already been VRELE'ed
2839: # by the filesystem layer. To use it you must use vget,
2840: # possibly with a further namei.
2841: #
2842: vop_symlink {
2843: IN WILLRELE struct vnode *dvp;
2844: OUT WILLRELE struct vnode **vpp;
2845: IN struct componentname *cnp;
2846: IN struct vattr *vap;
2847: IN char *target;
2848:
2849: We are responsible for freeing the namei buffer, it is done in hfs_makenode(), unless there is
2850: a previous error.
2851:
2852:
2853: */
2854:
2855: int
2856: hfs_symlink(ap)
2857: struct vop_symlink_args /* {
2858: struct vnode *a_dvp;
2859: struct vnode **a_vpp;
2860: struct componentname *a_cnp;
2861: struct vattr *a_vap;
2862: char *a_target;
2863: } */ *ap;
2864: {
2865: register struct vnode *vp, **vpp = ap->a_vpp;
2866: struct proc *p = current_proc();
2867: struct hfsnode *hp;
2868: u_int32_t dfltClump;
2869: int len, retval;
2870: DBG_FUNC_NAME("symlink");
2871: DBG_VOP_LOCKS_DECL(2);
2872: DBG_VOP_PRINT_FUNCNAME();
2873: DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
2874: DBG_VOP_LOCKS_INIT(1,*ap->a_vpp, VOPDBG_IGNORE, VOPDBG_UNLOCKED, VOPDBG_IGNORE, VOPDBG_POS);
2875:
2876: if (VTOVCB(ap->a_dvp)->vcbSigWord != kHFSPlusSigWord) {
2877: VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
2878: VPUT(ap->a_dvp);
2879: DBG_VOP((" ...sorry HFS disks don't support symbolic links.\n"));
2880: DBG_VOP_LOCKS_TEST(EOPNOTSUPP);
2881: return (EOPNOTSUPP);
2882: }
2883:
2884: /* lock catalog b-tree */
2885: retval = hfs_metafilelocking(VTOHFS(ap->a_dvp), kHFSCatalogFileID, LK_EXCLUSIVE, p);
2886: if (retval != E_NONE) {
2887: VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
2888: VPUT(ap->a_dvp);
2889: DBG_VOP_LOCKS_TEST( retval);
2890: return (retval);
2891: }
2892:
2893: /* Create the vnode */
2894: retval = hfs_makenode(IFLNK | ap->a_vap->va_mode, 0, ap->a_dvp, vpp, ap->a_cnp);
2895: DBG_VOP_UPDATE_VP(1, *ap->a_vpp);
2896:
2897: /* unlock catalog b-tree */
2898: (void) hfs_metafilelocking(VTOHFS(ap->a_dvp), kHFSCatalogFileID, LK_RELEASE, p);
2899:
2900: if (retval != E_NONE) {
2901: DBG_VOP_LOCKS_TEST(retval);
2902: return (retval);
2903: }
2904:
2905:
2906: vp = *vpp;
2907: len = strlen(ap->a_target);
2908: hp = VTOH(vp);
2909: dfltClump = hp->fcbClmpSize;
2910: /* make clump size minimal */
2911: hp->fcbClmpSize = VTOVCB(vp)->blockSize;
2912: retval = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
2913: UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred, (int *)0,
2914: (struct proc *)0);
2915: hp->fcbClmpSize = dfltClump;
2916:
2917:
2918: VPUT(vp);
2919: DBG_VOP_LOCKS_TEST(retval);
2920: return (retval);
2921: }
2922:
2923:
2924: /*
2925: * Dummy dirents to simulate the "." and ".." entries of the directory
2926: * in a hfs filesystem. HFS doesn't provide these on disk. Note that
2927: * the size of these entries is the smallest needed to represent them
2928: * (only 12 byte each).
2929: */
2930: static hfsdotentry rootdots[2] = {
2931: {
2932: 1, /* d_fileno */
2933: sizeof(struct hfsdotentry), /* d_reclen */
2934: DT_DIR, /* d_type */
2935: 1, /* d_namlen */
2936: "." /* d_name */
2937: },
2938: {
2939: 1, /* d_fileno */
2940: sizeof(struct hfsdotentry), /* d_reclen */
2941: DT_DIR, /* d_type */
2942: 2, /* d_namlen */
2943: ".." /* d_name */
2944: }
2945: };
2946:
2947: static hfsdotentry emptyentry = { 0 };
2948:
2949: /* 4.3 Note:
2950: * There is some confusion as to what the semantics of uio_offset are.
2951: * In ufs, it represents the actual byte offset within the directory
2952: * "file." HFS, however, just uses it as an entry counter - essentially
2953: * assuming that it has no meaning except to the hfs_readdir function.
2954: * This approach would be more efficient here, but some callers may
2955: * assume the uio_offset acts like a byte offset. NFS in fact
2956: * monkeys around with the offset field a lot between readdir calls.
2957: *
2958: * The use of the resid uiop->uio_resid and uiop->uio_iov->iov_len
2959: * fields is a mess as well. The libc function readdir() returns
2960: * NULL (indicating the end of a directory) when either
2961: * the getdirentries() syscall (which calls this and returns
2962: * the size of the buffer passed in less the value of uiop->uio_resid)
2963: * returns 0, or a direct record with a d_reclen of zero.
2964: * nfs_server.c:rfs_readdir(), on the other hand, checks for the end
2965: * of the directory by testing uiop->uio_resid == 0. The solution
2966: * is to pad the size of the last struct direct in a given
2967: * block to fill the block if we are not at the end of the directory.
2968: */
2969:
2970: struct callbackstate {
2971: u_int32_t cbs_parentID;
2972: u_int32_t cbs_hiddenDirID;
2973: off_t cbs_lastoffset;
2974: struct uio * cbs_uio;
2975: ExtendedVCB * cbs_vcb;
2976: int16_t cbs_hfsPlus;
2977: int16_t cbs_result;
2978: };
2979:
2980:
2981: SInt32
2982: ProcessCatalogEntry(const CatalogKey *ckp, const CatalogRecord *crp,
2983: u_int16_t recordLen, struct callbackstate *state)
2984: {
2985: CatalogName *cnp;
2986: ByteCount utf8chars;
2987: u_int32_t curID;
2988: OSErr result;
2989: struct dirent catent;
2990:
2991: if (state->cbs_hfsPlus)
2992: curID = ckp->hfsPlus.parentID;
2993: else
2994: curID = ckp->hfs.parentID;
2995:
2996: /* We're done when parent directory changes */
2997: if (state->cbs_parentID != curID) {
2998: lastitem:
2999: /*
3000: * The NSDirectoryList class chokes on empty records (it doesnt check d_reclen!)
3001: * so remove padding for now...
3002: */
3003: #if 0
3004: /*
3005: * Pad the end of list with an empty record.
3006: * This eliminates an extra call by readdir(3c).
3007: */
3008: catent.d_fileno = 0;
3009: catent.d_reclen = 0;
3010: catent.d_type = 0;
3011: catent.d_namlen = 0;
3012: *(int32_t*)&catent.d_name[0] = 0;
3013:
3014: state->cbs_lastoffset = state->cbs_uio->uio_offset;
3015:
3016: state->cbs_result = uiomove((caddr_t) &catent, 12, state->cbs_uio);
3017: if (state->cbs_result == 0)
3018: state->cbs_result = ENOENT;
3019: #else
3020: state->cbs_lastoffset = state->cbs_uio->uio_offset;
3021: state->cbs_result = ENOENT;
3022: #endif
3023: return (0); /* stop */
3024: }
3025:
3026: if (state->cbs_hfsPlus) {
3027: switch(crp->recordType) {
3028: case kHFSPlusFolderRecord:
3029: catent.d_type = DT_DIR;
3030: catent.d_fileno = crp->hfsPlusFolder.folderID;
3031: break;
3032: case kHFSPlusFileRecord:
3033: catent.d_type = DT_REG;
3034: catent.d_fileno = crp->hfsPlusFile.fileID;
3035: break;
3036: default:
3037: return (0); /* stop */
3038: };
3039:
3040: cnp = (CatalogName*) &ckp->hfsPlus.nodeName;
3041: /*XXX need to add name mangling for long names */
3042: result = ConvertUnicodeToUTF8(cnp->ustr.length * sizeof(UniChar),
3043: cnp->ustr.unicode, NAME_MAX + 1, &utf8chars, catent.d_name);
3044: } else { /* hfs */
3045: switch(crp->recordType) {
3046: case kHFSFolderRecord:
3047: catent.d_type = DT_DIR;
3048: catent.d_fileno = crp->hfsFolder.folderID;
3049: break;
3050: case kHFSFileRecord:
3051: catent.d_type = DT_REG;
3052: catent.d_fileno = crp->hfsFile.fileID;
3053: break;
3054: default:
3055: return (0); /* stop */
3056: };
3057:
3058: cnp = (CatalogName*) ckp->hfs.nodeName;
3059: result = hfs_to_utf8(state->cbs_vcb, cnp->pstr, NAME_MAX + 1,
3060: &utf8chars, catent.d_name);
3061: }
3062:
3063: catent.d_namlen = utf8chars;
3064: catent.d_reclen = DIRENTRY_SIZE(utf8chars);
3065:
3066: /* hide our private meta data directory */
3067: if (curID == kRootDirID &&
3068: catent.d_fileno == state->cbs_hiddenDirID &&
3069: catent.d_type == DT_DIR)
3070: goto lastitem;
3071:
3072: /* if this entry won't fit then we're done */
3073: if (catent.d_reclen > state->cbs_uio->uio_resid)
3074: return (0); /* stop */
3075:
3076: state->cbs_lastoffset = state->cbs_uio->uio_offset;
3077:
3078: state->cbs_result = uiomove((caddr_t) &catent, catent.d_reclen, state->cbs_uio);
3079:
3080: /* continue iteration if there's room */
3081: return (state->cbs_result == 0 &&
3082: state->cbs_uio->uio_resid >= AVERAGE_HFSDIRENTRY_SIZE);
3083: }
3084:
3085: /*
3086: * NOTE: We require a minimal buffer size of DIRBLKSIZ for two reasons. One, it is the same value
3087: * returned be stat() call as the block size. This is mentioned in the man page for getdirentries():
3088: * "Nbytes must be greater than or equal to the block size associated with the file,
3089: * see stat(2)". Might as well settle on the same size of ufs. Second, this makes sure there is enough
3090: * room for the . and .. entries that have to added manually.
3091: */
3092:
3093: /*
3094: #% readdir vp L L L
3095: #
3096: vop_readdir {
3097: IN struct vnode *vp;
3098: INOUT struct uio *uio;
3099: IN struct ucred *cred;
3100: INOUT int *eofflag;
3101: OUT int *ncookies;
3102: INOUT u_long **cookies;
3103: */
3104: static int
3105: hfs_readdir(ap)
3106: struct vop_readdir_args /* {
3107: struct vnode *vp;
3108: struct uio *uio;
3109: struct ucred *cred;
3110: int *eofflag;
3111: int *ncookies;
3112: u_long **cookies;
3113: } */ *ap;
3114: {
3115: register struct uio *uio = ap->a_uio;
3116: struct hfsnode *hp = VTOH(ap->a_vp);
3117: struct proc *p = current_proc();
3118: ExtendedVCB *vcb = HTOVCB(hp);
3119: off_t off = uio->uio_offset;
3120: u_int32_t dirID = H_FILEID(hp);
3121: int retval = 0;
3122: OSErr result = noErr;
3123: u_int32_t diroffset;
3124: BTreeIterator bi;
3125: CatalogIterator *cip;
3126: u_int16_t op;
3127: struct callbackstate state;
3128: int eofflag = 0;
3129:
3130: DBG_FUNC_NAME("readdir");
3131: DBG_VOP_LOCKS_DECL(1);
3132:
3133: DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS);
3134: DBG_VOP_PRINT_FUNCNAME();
3135: DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
3136: DBG_HFS_NODE_CHECK(ap->a_vp);
3137:
3138: /* We assume it's all one big buffer... */
3139: if (uio->uio_iovcnt > 1 || uio->uio_resid < AVERAGE_HFSDIRENTRY_SIZE) {
3140: return EINVAL;
3141: };
3142:
3143: /* Create the entries for . and .. */
3144: if (uio->uio_offset < sizeof(rootdots)) {
3145: caddr_t dep;
3146: size_t dotsize;
3147:
3148: rootdots[0].d_fileno = dirID;
3149: rootdots[1].d_fileno = H_DIRID(hp);
3150:
3151: if (uio->uio_offset == 0) {
3152: dep = (caddr_t) &rootdots[0];
3153: dotsize = 2* sizeof(struct hfsdotentry);
3154: } else if (uio->uio_offset == sizeof(struct hfsdotentry)) {
3155: dep = (caddr_t) &rootdots[1];
3156: dotsize = sizeof(struct hfsdotentry);
3157: } else {
3158: retval = EINVAL;
3159: goto Exit;
3160: }
3161:
3162: retval = uiomove(dep, dotsize, uio);
3163: if (retval != 0)
3164: goto Exit;
3165: }
3166:
3167: diroffset = uio->uio_offset;
3168:
3169: /* lock catalog b-tree */
3170: retval = hfs_metafilelocking(VTOHFS(ap->a_vp), kHFSCatalogFileID, LK_SHARED, p);
3171: if (retval != E_NONE)
3172: goto Exit;
3173:
3174: /* get an iterator and position it */
3175: cip = GetCatalogIterator(vcb, dirID, diroffset);
3176:
3177: result = PositionIterator(cip, diroffset, &bi, &op);
3178: if (result == cmNotFound) {
3179: eofflag = 1;
3180: retval = 0;
3181: AgeCatalogIterator(cip);
3182: goto cleanup;
3183: } else if ((retval = MacToVFSError(result)))
3184: goto cleanup;
3185:
3186: state.cbs_hiddenDirID = VCBTOHFS(vcb)->hfs_private_metadata_dir;
3187: state.cbs_lastoffset = cip->currentOffset;
3188: state.cbs_vcb = vcb;
3189: state.cbs_uio = uio;
3190: state.cbs_result = 0;
3191: state.cbs_parentID = dirID;
3192:
3193: if (vcb->vcbSigWord == kHFSPlusSigWord)
3194: state.cbs_hfsPlus = 1;
3195: else
3196: state.cbs_hfsPlus = 0;
3197:
3198: /* process as many entries as possible... */
3199: result = BTIterateRecords(GetFileControlBlock(vcb->catalogRefNum), op, &bi,
3200: (IterateCallBackProcPtr)ProcessCatalogEntry, &state);
3201:
3202: if (state.cbs_result)
3203: retval = state.cbs_result;
3204: else
3205: retval = MacToVFSError(result);
3206:
3207: if (retval == ENOENT) {
3208: eofflag = 1;
3209: retval = 0;
3210: }
3211:
3212: if (retval == 0) {
3213: cip->currentOffset = state.cbs_lastoffset;
3214: cip->nextOffset = uio->uio_offset;
3215: UpdateCatalogIterator(&bi, cip);
3216: }
3217:
3218: cleanup:
3219: if (retval) {
3220: cip->volume = 0;
3221: cip->folderID = 0;
3222: AgeCatalogIterator(cip);
3223: }
3224:
3225: (void) ReleaseCatalogIterator(cip);
3226:
3227: /* unlock catalog b-tree */
3228: (void) hfs_metafilelocking(VTOHFS(ap->a_vp), kHFSCatalogFileID, LK_RELEASE, p);
3229:
3230: if (retval != E_NONE) {
3231: DBG_ERR(("%s: retval %d when trying to read directory %ld: %s\n",funcname, retval,
3232: H_FILEID(hp), H_NAME(hp)));
3233: goto Exit;
3234:
3235: }
3236:
3237: /* were we already past eof ? */
3238: if (uio->uio_offset == off) {
3239: uio->uio_offset = 0;
3240: retval = E_NONE;
3241: goto Exit;
3242: }
3243:
3244: if (vcb->vcbSigWord == kHFSPlusSigWord)
3245: hp->h_nodeflags |= IN_ACCESS;
3246:
3247: #if 0
3248: /* Bake any cookies */
3249: if (!retval && ap->a_ncookies != NULL) {
3250: struct dirent* dpStart;
3251: struct dirent* dpEnd;
3252: struct dirent* dp;
3253: int ncookies;
3254: u_long *cookies;
3255: u_long *cookiep;
3256:
3257: /*
3258: * Only the NFS server uses cookies, and it loads the
3259: * directory block into system space, so we can just look at
3260: * it directly.
3261: */
3262: if (uio->uio_segflg != UIO_SYSSPACE)
3263: panic("hfs_readdir: unexpected uio from NFS server");
3264: dpStart = (struct dirent *)
3265: (uio->uio_iov->iov_base - (uio->uio_offset - off));
3266: dpEnd = (struct dirent *) uio->uio_iov->iov_base;
3267: for (dp = dpStart, ncookies = 0;
3268: dp < dpEnd && dp->d_reclen != 0;
3269: dp = (struct dirent *)((caddr_t)dp + dp->d_reclen))
3270: ncookies++;
3271: MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
3272: M_WAITOK);
3273: for (dp = dpStart, cookiep = cookies;
3274: dp < dpEnd;
3275: dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) {
3276: off += dp->d_reclen;
3277: *cookiep++ = (u_long) off;
3278: }
3279: *ap->a_ncookies = ncookies;
3280: *ap->a_cookies = cookies;
3281: }
3282: #endif
3283:
3284: Exit:;
3285:
3286: if (ap->a_eofflag)
3287: *ap->a_eofflag = eofflag;
3288:
3289: DBG_VOP_LOCKS_TEST(retval);
3290: return (retval);
3291: }
3292:
3293:
3294: /*
3295: * readdirattr operation will return attributes for the items in the
3296: * directory specified.
3297: *
3298: * It does not do . and .. entries. The problem is if you are at the root of the
3299: * hfs directory and go to .. you could be crossing a mountpoint into a
3300: * different (ufs) file system. The attributes that apply for it may not
3301: * apply for the file system you are doing the readdirattr on. To make life
3302: * simpler, this call will only return entries in its directory, hfs like.
3303: * TO DO LATER:
3304: * 1.getattrlist creates a thread record if the objpermanentid attribute
3305: * is requested. Just do EINVAL for now and fix later.
3306: * 2. more than one for uiovcnt support.
3307: * 3. put knohint (hints) in state for next call in
3308: * 4. credentials checking when rest of hfs does it.
3309: * 5. Do return permissions concatenation ???
3310: */
3311:
3312: /*
3313: #
3314: #% readdirattr vp L L L
3315: #
3316: vop_readdirattr {
3317: IN struct vnode *vp;
3318: IN struct attrlist *alist;
3319: INOUT struct uio *uio;
3320: IN u_long maxcount:
3321: IN u_long options;
3322: OUT u_long *newstate;
3323: OUT int *eofflag;
3324: OUT u_long *actualCount;
3325: OUT u_long **cookies;
3326: IN struct ucred *cred;
3327: };
3328: */
3329: static int
3330: hfs_readdirattr(ap)
3331: struct vop_readdirattr_args /* {
3332: struct vnode *vp;
3333: struct attrlist *alist;
3334: struct uio *uio;
3335: u_long maxcount:
3336: u_long options;
3337: int *newstate;
3338: int *eofflag;
3339: u_long *actualcount;
3340: u_long **cookies;
3341: struct ucred *cred;
3342: } */ *ap;
3343: {
3344: struct vnode *vp = ap->a_vp;
3345: struct attrlist *alist = ap->a_alist;
3346: register struct uio *uio = ap->a_uio;
3347: u_long maxcount = ap->a_maxcount;
3348: u_long ncookies;
3349: ExtendedVCB *vcb = HTOVCB(VTOH(vp));
3350: UInt32 dirID = H_FILEID(VTOH(vp));
3351: struct proc *proc = current_proc(); /* could get this out of uio */
3352: off_t startoffset = uio->uio_offset;
3353: struct hfsCatalogInfo catalogInfo;
3354: UInt32 index;
3355: int retval = 0;
3356: u_long fixedblocksize;
3357: u_long maxattrblocksize;
3358: u_long currattrbufsize;
3359: void *attrbufptr = NULL;
3360: void *attrptr;
3361: void *varptr;
3362:
3363:
3364: *(ap->a_actualcount) = 0;
3365: *(ap->a_eofflag) = 0;
3366:
3367: /* not using options (don't follow symlinks = 0), check vnode, and buffer space */
3368: if ((ap->a_options != 0) || (vp == NULL) ||
3369: (uio->uio_resid <= 0) || (uio->uio_iovcnt > 1))
3370: return EINVAL;
3371:
3372: /* this call doesn't take volume attributes */
3373: if ((alist->bitmapcount != ATTR_BIT_MAP_COUNT) ||
3374: ((alist->commonattr & ~ATTR_CMN_VALIDMASK) != 0) ||
3375: (alist->volattr != 0) ||
3376: ((alist->dirattr & ~ATTR_DIR_VALIDMASK) != 0) ||
3377: ((alist->fileattr & ~ATTR_FILE_VALIDMASK) != 0) ||
3378: ((alist->forkattr & ~ATTR_FORK_VALIDMASK) != 0))
3379: return EINVAL;
3380:
3381: /* Reject requests for unsupported options for now: */
3382: if ((alist->commonattr & (ATTR_CMN_NAMEDATTRCOUNT | ATTR_CMN_NAMEDATTRLIST)) ||
3383: (alist->fileattr & (ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT | ATTR_FILE_FORKLIST)) ||
3384: (alist->commonattr & ATTR_CMN_OBJPERMANENTID) )
3385: return EINVAL;
3386:
3387: /* getattrlist and searchfs use a secondary buffer to malloc and then use
3388: * uiomove afterwards. It's an extra copy, but for now leave it alone
3389: */
3390: fixedblocksize = (sizeof(u_long) + AttributeBlockSize(alist)); /* u_long for length */
3391: maxattrblocksize = fixedblocksize;
3392: if (alist->commonattr & ATTR_CMN_NAME)
3393: maxattrblocksize += NAME_MAX + 1;
3394: MALLOC(attrbufptr, void *, maxattrblocksize, M_TEMP, M_WAITOK);
3395: attrptr = attrbufptr;
3396: varptr = (char *)attrbufptr + fixedblocksize; /* Point to variable-length storage */
3397:
3398: /* Since attributes passed back can contain variable ones (name), we can't just use
3399: * uio_offset as is. We thus force it to represent fixed size of hfsdirentries
3400: * as hfs_readdir was originally doing. If this all we need to represent the current
3401: * state, then ap->a_state is not needed at all.
3402: */
3403: /* index = ap->a_state; should not be less than 1 */
3404: index = (uio->uio_offset / sizeof(struct dirent)) + 1;
3405:
3406: /* Lock catalog b-tree */
3407: if ((retval = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_SHARED, proc)) != E_NONE)
3408: goto exit;
3409:
3410: /* HFS Catalog does not have a bulk directory enumeration call. Do it one at
3411: * time, using hints. GetCatalogOffspring takes care of hfsplus and name issues
3412: * for us, so that's a win. Later, implement GetCatalogOffspringBulk.
3413: */
3414: catalogInfo.hint = kNoHint; /* note, we may want to save the latest in state */
3415: while ((uio->uio_resid >= 0) && (maxcount !=0 )) {
3416: /* better to check uio_resid against max or fixedblocksize, but won't work.
3417: * Depending on if dir or file, the attributes returned will be different.
3418: * Thus fixedblocksize is too large in some cases.Also, the variable
3419: * part (like name) could be between fixedblocksize and the max.
3420: */
3421: OSErr result = GetCatalogOffspring(vcb, dirID, index, &catalogInfo.spec,
3422: &catalogInfo.nodeData, NULL, NULL);
3423: if (result != noErr) {
3424: if (result == cmNotFound) {
3425: *(ap->a_eofflag) = TRUE;
3426: retval = E_NONE;
3427: }
3428: else retval = MacToVFSError(result);
3429: break;
3430: }
3431:
3432: /* hide our private meta data directory as does hfs_readdir */
3433: if ((dirID == kRootDirID) &&
3434: catalogInfo.nodeData.cnd_nodeID == VCBTOHFS(vcb)->hfs_private_metadata_dir &&
3435: catalogInfo.nodeData.cnd_type == kCatalogFolderNode) {
3436:
3437: ++index;
3438: continue;
3439: }
3440:
3441: *((u_long *)attrptr)++ = 0; /* move it past length */
3442:
3443: /* vp okay to use instead of root vp */
3444: PackCatalogInfoAttributeBlock(alist, vp, &catalogInfo, &attrptr, &varptr);
3445: currattrbufsize = *((u_long *)attrbufptr) = ((char *)varptr - (char *)attrbufptr);
3446:
3447: /* now check if we can't fit in the buffer space remaining */
3448: if (currattrbufsize > uio->uio_resid)
3449: break;
3450: else {
3451: retval = uiomove((caddr_t)attrbufptr, currattrbufsize, ap->a_uio);
3452: if (retval != E_NONE)
3453: break;
3454: attrptr = attrbufptr;
3455: index++;
3456: *ap->a_actualcount += 1;
3457: maxcount--;
3458: }
3459: };
3460: *ap->a_newstate = VTOH(vp)->h_meta->h_mtime;/* before we unlock, know the mod date */
3461: /* Unlock catalog b-tree, finally. Ties up the everything during enumeration */
3462: (void) hfs_metafilelocking( VTOHFS(ap->a_vp), kHFSCatalogFileID, LK_RELEASE, proc );
3463:
3464: if (!retval && ap->a_cookies != NULL) { /* CHECK THAT 0 wasn't passed in */
3465: void* dpStart;
3466: void* dpEnd;
3467: void* dp;
3468: u_long *cookies;
3469: u_long *cookiep;
3470:
3471: /* Only the NFS server uses cookies, and it loads the
3472: * directory block into system space, so we can just look at
3473: * it directly.
3474: */
3475: if (uio->uio_segflg != UIO_SYSSPACE) /* || uio->uio_iovcnt != 1 checked earlier */
3476: panic("hfs_readdirattr: unexpected uio from NFS server");
3477: dpStart = uio->uio_iov->iov_base - (uio->uio_offset - startoffset);
3478: dpEnd = uio->uio_iov->iov_base;
3479: MALLOC(cookies, u_long *, (*ap->a_actualcount)*sizeof(u_long), M_TEMP, M_WAITOK);
3480: for (dp = dpStart, cookiep = cookies;
3481: dp < dpEnd;
3482: dp = ((caddr_t) dp + *((u_long *)dp))) {
3483: *cookiep++ = (u_long)((caddr_t)dp + sizeof(u_long));
3484: }
3485: *ap->a_cookies = cookies;
3486: }
3487:
3488: uio->uio_offset = startoffset + (*ap->a_actualcount)*sizeof(struct dirent);
3489:
3490: exit:
3491: if (attrbufptr != NULL)
3492: FREE(attrbufptr, M_TEMP);
3493: return (retval);
3494: }
3495:
3496:
3497: /*
3498: * Return target name of a symbolic link
3499: #% readlink vp L L L
3500: #
3501: vop_readlink {
3502: IN struct vnode *vp;
3503: INOUT struct uio *uio;
3504: IN struct ucred *cred;
3505: */
3506:
3507: int
3508: hfs_readlink(ap)
3509: struct vop_readlink_args /* {
3510: struct vnode *a_vp;
3511: struct uio *a_uio;
3512: struct ucred *a_cred;
3513: } */ *ap;
3514: {
3515: int retval;
3516: DBG_FUNC_NAME("readlink");
3517: DBG_VOP_LOCKS_DECL(1);
3518: DBG_VOP_PRINT_FUNCNAME();
3519: DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
3520:
3521: DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS);
3522: retval = VOP_READ(ap->a_vp, ap->a_uio, 0, ap->a_cred);
3523: /* clear IN_ACCESS to prevent needless update of symlink vnode */
3524: VTOH(ap->a_vp)->h_nodeflags &= ~IN_ACCESS;
3525:
3526: DBG_VOP_LOCKS_TEST(retval);
3527: return (retval);
3528:
3529: }
3530:
3531:
3532: /*
3533: * hfs abort op, called after namei() when a CREATE/DELETE isn't actually
3534: * done. If a buffer has been saved in anticipation of a CREATE, delete it.
3535: #% abortop dvp = = =
3536: #
3537: vop_abortop {
3538: IN struct vnode *dvp;
3539: IN struct componentname *cnp;
3540:
3541: */
3542:
3543: /* ARGSUSED */
3544:
3545: static int
3546: hfs_abortop(ap)
3547: struct vop_abortop_args /* {
3548: struct vnode *a_dvp;
3549: struct componentname *a_cnp;
3550: } */ *ap;
3551: {
3552: DBG_FUNC_NAME("abortop");
3553: DBG_VOP_LOCKS_DECL(1);
3554: DBG_VOP_PRINT_FUNCNAME();
3555: DBG_VOP_PRINT_VNODE_INFO(ap->a_dvp);
3556: DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);DBG_VOP_CONT(("\n"));
3557:
3558:
3559: DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_POS);
3560:
3561: if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) {
3562: FREE_ZONE(ap->a_cnp->cn_pnbuf, ap->a_cnp->cn_pnlen, M_NAMEI);
3563: }
3564: DBG_VOP_LOCKS_TEST(E_NONE);
3565: return (E_NONE);
3566: }
3567:
3568: // int prthfsactive = 0; /* 1 => print out reclaim of active vnodes */
3569:
3570: /*
3571: #% inactive vp L U U
3572: #
3573: vop_inactive {
3574: IN struct vnode *vp;
3575: IN struct proc *p;
3576:
3577: */
3578:
3579: static int
3580: hfs_inactive(ap)
3581: struct vop_inactive_args /* {
3582: struct vnode *a_vp;
3583: } */ *ap;
3584: {
3585: struct vnode *vp = ap->a_vp;
3586: struct hfsnode *hp = VTOH(vp);
3587: struct proc *p = ap->a_p;
3588: struct timeval tv;
3589: int error = 0;
3590: extern int prtactive;
3591:
3592: DBG_FUNC_NAME("inactive");
3593: DBG_VOP_LOCKS_DECL(1);
3594: DBG_VOP_PRINT_FUNCNAME();
3595: DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
3596:
3597: DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_ZERO);
3598:
3599:
3600: if (prtactive && vp->v_usecount <= 0)
3601: vprint("hfs_inactive: pushing active", vp);
3602:
3603: if (vp->v_usecount != 0)
3604: DBG_VOP(("%s: bad usecount = %d\n",funcname,vp->v_usecount ));
3605:
3606: /*
3607: * Ignore nodes related to stale file handles.
3608: */
3609: if ((vp->v_type == VNON) || (hp->h_meta->h_mode == 0))
3610: goto out;
3611:
3612: /*
3613: * Check for a postponed deletion
3614: */
3615: if (hp->h_meta->h_metaflags & IN_DELETED) {
3616: hp->h_meta->h_metaflags &= ~IN_DELETED;
3617:
3618: error = vinvalbuf(vp, 0, NOCRED, p, 0, 0);
3619: if (error) goto out;
3620:
3621: /* Lock both trees
3622: * Note: we do not need a lock on the private metadata directory
3623: * since it never has a vnode associated with it.
3624: */
3625: error = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_EXCLUSIVE, p);
3626: if (error) goto out;
3627: error = hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_EXCLUSIVE, p);
3628: if (error) {
3629: (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, p);
3630: goto out;
3631: }
3632:
3633: /* XXX can we leave orphaned sibling? */
3634: error = hfsDelete(HTOVCB(hp), H_DIRID(hp), H_NAME(hp), TRUE, H_HINT(hp));
3635: if (error == ENOENT) {
3636: /* try by fileID as a backup */
3637: error = hfsDelete(HTOVCB(hp), H_FILEID(hp), NULL, TRUE, H_HINT(hp));
3638: }
3639: (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_RELEASE, p);
3640: (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, p);
3641: if (error) goto out;
3642:
3643: #if MACH_NBC
3644: if ((vp->v_type == VREG) && (vp->v_vm_info && !(vp->v_vm_info->mapped))) {
3645: #endif /* MACH_NBC */
3646: vnode_pager_setsize(vp, 0);
3647: #if MACH_NBC
3648: }
3649: #endif /* MACH_NBC */
3650:
3651: hp->h_meta->h_mode = 0;
3652: hp->h_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE);
3653: }
3654:
3655: if (hp->h_nodeflags & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) {
3656: tv = time;
3657: VOP_UPDATE(vp, &tv, &tv, 0);
3658: }
3659:
3660: out:
3661: VOP_UNLOCK(vp, 0, p);
3662: /*
3663: * If we are done with the inode, reclaim it
3664: * so that it can be reused immediately.
3665: */
3666: if ((vp->v_type == VNON) || (hp->h_meta->h_mode == 0))
3667: vrecycle(vp, (struct slock *)0, p);
3668:
3669: /* XXX SER Here we might want to get rid of any other forks
3670: * The problem is that if we call vrecycle(), our structure
3671: * disappear from under us, we would need to remember, and expect
3672: * things to go to null or to disappear
3673: * But it stillw would be a good thing to remove vnodes
3674: * referencing stale data
3675: */
3676:
3677: DBG_VOP_LOCKS_TEST(E_NONE);
3678: return (E_NONE);
3679: }
3680:
3681: /*
3682: Ignored since the locks are gone......
3683: #% reclaim vp U I I
3684: #
3685: vop_reclaim {
3686: IN struct vnode *vp;
3687: IN struct proc *p;
3688:
3689: */
3690:
3691: static int
3692: hfs_reclaim(ap)
3693: struct vop_reclaim_args /* {
3694: struct vnode *a_vp;
3695: } */ *ap;
3696: {
3697: struct vnode *vp = ap->a_vp;
3698: struct hfsnode *hp = VTOH(vp);
3699: void *tdata = vp->v_data;
3700: char *tname;
3701: Boolean freeMeta = true;
3702: struct vnode *devvp = NULL;
3703:
3704: extern int prtactive;
3705: DBG_FUNC_NAME("reclaim");
3706: DBG_VOP_LOCKS_DECL(1);
3707: DBG_VOP_PRINT_FUNCNAME();
3708: DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
3709:
3710: DBG_VOP_LOCKS_INIT(0, ap->a_vp, VOPDBG_UNLOCKED, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_ZERO);
3711:
3712: /*
3713: NOTE: XXX vnodes need careful handling because fork vnodes that failed to be
3714: created in their entirity could be getting cleaned up here, in which
3715: case v_type == VNON and h_meta == NULL... (when????)
3716: */
3717:
3718: if (prtactive && vp->v_usecount != 0)
3719: vprint("hfs_reclaim(): pushing active", vp);
3720:
3721: hp->h_nodeflags |= IN_ALLOCATING; /* Mark this as being incomplete */
3722: /*
3723: * This will remove the entry from the hash AND the sibling list
3724: * This will make sure everything is in a stable state to see if we can remove the meta
3725: * i.e. if this is the only fork...the sibling list will be empty
3726: */
3727: hfs_vhashrem(hp);
3728:
3729: DBG_ASSERT(tdata != NULL);
3730: DBG_ASSERT(hp->h_meta != NULL);
3731:
3732: devvp = hp->h_meta->h_devvp; /* For later releasing */
3733: hp->h_meta->h_usecount--;
3734:
3735: /* release the file meta if this is the last fork */
3736: if (H_FORKTYPE(hp)==kDataFork || H_FORKTYPE(hp)==kRsrcFork) {
3737: if (hp->h_meta->h_siblinghead.cqh_first != (void *) &hp->h_meta->h_siblinghead)
3738: freeMeta = false;
3739: };
3740:
3741: if (freeMeta) {
3742: DBG_ASSERT(hp->h_meta->h_usecount == 0);
3743: if (hp->h_meta->h_metaflags & IN_LONGNAME) {
3744: tname = H_NAME(hp);
3745: DBG_ASSERT(tname != NULL);
3746: FREE(tname, M_TEMP);
3747: }
3748: FREE(hp->h_meta, M_HFSFMETA);
3749: hp->h_meta = NULL;
3750: }
3751: else
3752: DBG_ASSERT(hp->h_meta->h_usecount == 1);
3753:
3754:
3755:
3756: /*
3757: * Purge old data structures associated with the inode.
3758: */
3759: cache_purge(vp);
3760: if ((vp->v_type != VNON) && devvp) {
3761: VRELE(devvp);
3762: };
3763:
3764: /* Free our data structs */
3765: if (vp->v_type != VNON) {
3766: FREE(tdata, M_HFSNODE);
3767: vp->v_data = NULL;
3768: };
3769:
3770: DBG_VOP_LOCKS_TEST(E_NONE);
3771: return (E_NONE);
3772: }
3773:
3774:
3775: /*
3776: * Lock an hfsnode. If its already locked, set the WANT bit and sleep.
3777: #% lock vp U L U
3778: #
3779: vop_lock {
3780: IN struct vnode *vp;
3781: IN int flags;
3782: IN struct proc *p;
3783: */
3784:
3785: static int
3786: hfs_lock(ap)
3787: struct vop_lock_args /* {
3788: struct vnode *a_vp;
3789: int a_flags;
3790: struct proc *a_p;
3791: } */ *ap;
3792: {
3793: struct vnode * vp = ap->a_vp;
3794: struct hfsnode *hp = VTOH(ap->a_vp);
3795: int retval;
3796:
3797: DBG_FUNC_NAME("lock");
3798: DBG_VOP_LOCKS_DECL(1);
3799: DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT((" "));
3800: DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT((" flags = 0x%08X.\n", ap->a_flags));
3801: DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_UNLOCKED, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_ZERO);
3802:
3803: retval = lockmgr(&hp->h_lock, ap->a_flags, &vp->v_interlock, ap->a_p);
3804: if (retval != E_NONE) {
3805: if ((ap->a_flags & LK_NOWAIT) == 0)
3806: DBG_ERR(("hfs_lock: error %d trying to lock vnode (flags = 0x%08X).\n", retval, ap->a_flags));
3807: goto Err_Exit;
3808: };
3809:
3810: Err_Exit:;
3811: DBG_ASSERT(*((int*)&vp->v_interlock) == 0);
3812: DBG_VOP_LOCKS_TEST(retval);
3813: return (retval);
3814: }
3815:
3816: /*
3817: * Unlock an hfsnode.
3818: #% unlock vp L U L
3819: #
3820: vop_unlock {
3821: IN struct vnode *vp;
3822: IN int flags;
3823: IN struct proc *p;
3824:
3825: */
3826: int
3827: hfs_unlock(ap)
3828: struct vop_unlock_args /* {
3829: struct vnode *a_vp;
3830: int a_flags;
3831: struct proc *a_p;
3832: } */ *ap;
3833: {
3834: struct hfsnode *hp = VTOH(ap->a_vp);
3835: struct vnode *vp = ap->a_vp;
3836: int retval = E_NONE;
3837:
3838: DBG_FUNC_NAME("unlock");
3839: DBG_VOP_LOCKS_DECL(1);
3840: DBG_VOP_PRINT_FUNCNAME();
3841: DBG_VOP_PRINT_VNODE_INFO(vp);DBG_VOP_CONT((" flags = 0x%08X.\n", ap->a_flags));
3842: DBG_VOP_LOCKS_INIT(0,vp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_LOCKED, VOPDBG_ZERO);
3843:
3844:
3845: DBG_ASSERT((ap->a_flags & (LK_EXCLUSIVE|LK_SHARED)) == 0);
3846: retval = lockmgr(&hp->h_lock, ap->a_flags | LK_RELEASE, &vp->v_interlock, ap->a_p);
3847: if (retval != E_NONE) {
3848: DEBUG_BREAK_MSG(("hfs_unlock: error %d trying to unlock vnode (forktype = %d).\n", retval, H_FORKTYPE(hp)));
3849: };
3850:
3851: DBG_ASSERT(*((int*)&vp->v_interlock) == 0);
3852: DBG_VOP_LOCKS_TEST(retval);
3853: return (retval);
3854: }
3855:
3856:
3857: /*
3858: * Print out the contents of an hfsnode.
3859: #% print vp = = =
3860: #
3861: vop_print {
3862: IN struct vnode *vp;
3863: */
3864: int
3865: hfs_print(ap)
3866: struct vop_print_args /* {
3867: struct vnode *a_vp;
3868: } */ *ap;
3869: {
3870: register struct vnode * vp = ap->a_vp;
3871: register struct hfsnode *hp = VTOH( vp);
3872: DBG_FUNC_NAME("print");
3873: DBG_VOP_LOCKS_DECL(1);
3874: DBG_VOP_PRINT_FUNCNAME();
3875: DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);
3876:
3877: DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_POS);
3878:
3879: printf("tag VT_HFS, dirID %d, on dev %d, %d", H_DIRID(hp),
3880: major(H_DEV(hp)), minor(H_DEV(hp)));
3881: /* lockmgr_printinfo(&hp->h_lock); */
3882: printf("\n");
3883: DBG_VOP_LOCKS_TEST(E_NONE);
3884: return (E_NONE);
3885: }
3886:
3887:
3888: /*
3889: * Check for a locked hfsnode.
3890: #% islocked vp = = =
3891: #
3892: vop_islocked {
3893: IN struct vnode *vp;
3894:
3895: */
3896: int
3897: hfs_islocked(ap)
3898: struct vop_islocked_args /* {
3899: struct vnode *a_vp;
3900: } */ *ap;
3901: {
3902: int lockStatus;
3903: //DBG_FUNC_NAME("islocked");
3904: //DBG_VOP_LOCKS_DECL(1);
3905: //DBG_VOP_PRINT_FUNCNAME();
3906: //DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);
3907:
3908: //DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_ZERO);
3909:
3910: lockStatus = lockstatus(&VTOH( ap->a_vp)->h_lock);
3911: //DBG_VOP_LOCKS_TEST(E_NONE);
3912: return (lockStatus);
3913: }
3914:
3915: /*
3916:
3917: #% pathconf vp L L L
3918: #
3919: vop_pathconf {
3920: IN struct vnode *vp;
3921: IN int name;
3922: OUT register_t *retval;
3923:
3924: */
3925: static int
3926: hfs_pathconf(ap)
3927: struct vop_pathconf_args /* {
3928: struct vnode *a_vp;
3929: int a_name;
3930: int *a_retval;
3931: } */ *ap;
3932: {
3933: int retval = E_NONE;
3934: DBG_FUNC_NAME("pathconf");
3935: DBG_VOP_LOCKS_DECL(1);
3936: DBG_VOP_PRINT_FUNCNAME();
3937: DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);
3938:
3939: DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS);
3940:
3941: DBG_HFS_NODE_CHECK (ap->a_vp);
3942:
3943: switch (ap->a_name) {
3944: case _PC_LINK_MAX:
3945: #if HFS_HARDLINKS
3946: if (VTOVCB(ap->a_vp)->vcbSigWord == kHFSPlusSigWord)
3947: *ap->a_retval = HFS_LINK_MAX;
3948: else
3949: *ap->a_retval = 1;
3950: #else
3951: *ap->a_retval = 1;
3952: #endif
3953: break;
3954: case _PC_NAME_MAX:
3955: *ap->a_retval = (kHFSPlusMaxFileNameChars * 3); /* max # of characters x max utf8 representation */
3956: break;
3957: case _PC_PATH_MAX:
3958: *ap->a_retval = PATH_MAX; /* 1024 */
3959: break;
3960: case _PC_CHOWN_RESTRICTED:
3961: *ap->a_retval = 1;
3962: break;
3963: case _PC_NO_TRUNC:
3964: *ap->a_retval = 0;
3965: break;
3966: default:
3967: retval = EINVAL;
3968: }
3969:
3970: DBG_VOP_LOCKS_TEST(retval);
3971: return (retval);
3972: }
3973:
3974:
3975:
3976:
3977:
3978: /*
3979: * Advisory record locking support
3980: #% advlock vp U U U
3981: #
3982: vop_advlock {
3983: IN struct vnode *vp;
3984: IN caddr_t id;
3985: IN int op;
3986: IN struct flock *fl;
3987: IN int flags;
3988:
3989: */
3990: int
3991: hfs_advlock(ap)
3992: struct vop_advlock_args /* {
3993: struct vnode *a_vp;
3994: caddr_t a_id;
3995: int a_op;
3996: struct flock *a_fl;
3997: int a_flags;
3998: } */ *ap;
3999: {
4000: register struct hfsnode *hp = VTOH(ap->a_vp);
4001: register struct flock *fl = ap->a_fl;
4002: register struct hfslockf *lock;
4003: off_t start, end;
4004: int retval;
4005: DBG_FUNC_NAME("advlock");
4006: DBG_VOP_LOCKS_DECL(1);
4007: DBG_VOP_PRINT_FUNCNAME();
4008: DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP(("\n"));
4009: DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS);
4010: /*
4011: * Avoid the common case of unlocking when inode has no locks.
4012: */
4013: if (hp->h_lockf == (struct hfslockf *)0) {
4014: if (ap->a_op != F_SETLK) {
4015: fl->l_type = F_UNLCK;
4016: return (0);
4017: }
4018: }
4019: /*
4020: * Convert the flock structure into a start and end.
4021: */
4022: start = 0;
4023: switch (fl->l_whence) {
4024: case SEEK_SET:
4025: case SEEK_CUR:
4026: /*
4027: * Caller is responsible for adding any necessary offset
4028: * when SEEK_CUR is used.
4029: */
4030: start = fl->l_start;
4031: break;
4032:
4033: case SEEK_END:
4034: start = HTOFCB(hp)->fcbEOF + fl->l_start;
4035: break;
4036:
4037: default:
4038: return (EINVAL);
4039: }
4040:
4041: if (start < 0)
4042: return (EINVAL);
4043: if (fl->l_len == 0)
4044: end = -1;
4045: else
4046: end = start + fl->l_len - 1;
4047:
4048: /*
4049: * Create the hfslockf structure
4050: */
4051: MALLOC(lock, struct hfslockf *, sizeof *lock, M_LOCKF, M_WAITOK);
4052: lock->lf_start = start;
4053: lock->lf_end = end;
4054: lock->lf_id = ap->a_id;
4055: lock->lf_hfsnode = hp;
4056: lock->lf_type = fl->l_type;
4057: lock->lf_next = (struct hfslockf *)0;
4058: TAILQ_INIT(&lock->lf_blkhd);
4059: lock->lf_flags = ap->a_flags;
4060: /*
4061: * Do the requested operation.
4062: */
4063: switch(ap->a_op) {
4064: case F_SETLK:
4065: retval = hfs_setlock(lock);
4066: break;
4067:
4068: case F_UNLCK:
4069: retval = hfs_clearlock(lock);
4070: FREE(lock, M_LOCKF);
4071: break;
4072:
4073: case F_GETLK:
4074: retval = hfs_getlock(lock, fl);
4075: FREE(lock, M_LOCKF);
4076: break;
4077:
4078: default:
4079: retval = EINVAL;
4080: _FREE(lock, M_LOCKF);
4081: break;
4082: }
4083:
4084: DBG_VOP_LOCKS_TEST(retval);
4085: return (retval);
4086: }
4087:
4088:
4089:
4090: /*
4091: * Update the access, modified, and node change times as specified by the
4092: * IACCESS, IUPDATE, and ICHANGE flags respectively. The IMODIFIED flag is
4093: * used to specify that the node needs to be updated but that the times have
4094: * already been set. The access and modified times are taken from the second
4095: * and third parameters; the node change time is always taken from the current
4096: * time. If waitfor is set, then wait for the disk write of the node to
4097: * complete.
4098: */
4099: /*
4100: #% update vp L L L
4101: IN struct vnode *vp;
4102: IN struct timeval *access;
4103: IN struct timeval *modify;
4104: IN int waitfor;
4105: */
4106:
4107: int
4108: hfs_update(ap)
4109: struct vop_update_args /* {
4110: struct vnode *a_vp;
4111: struct timeval *a_access;
4112: struct timeval *a_modify;
4113: int a_waitfor;
4114: } */ *ap;
4115: {
4116: struct hfsnode *hp;
4117: struct proc *p;
4118: hfsCatalogInfo catInfo;
4119: char *filename;
4120: u_int32_t pid;
4121: int retval;
4122: ExtendedVCB *vcb;
4123: DBG_FUNC_NAME("update");
4124: DBG_VOP_LOCKS_DECL(1);
4125: DBG_VOP_PRINT_FUNCNAME();
4126: DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n"));
4127: DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_ZERO);
4128:
4129: hp = VTOH(ap->a_vp);
4130:
4131: DBG_ASSERT(hp && hp->h_meta);
4132: DBG_ASSERT(*((int*)&ap->a_vp->v_interlock) == 0);
4133:
4134: if ((H_FORKTYPE(hp) == kSysFile) ||
4135: (VTOVFS(ap->a_vp)->mnt_flag & MNT_RDONLY) ||
4136: (hp->h_meta->h_mode == 0)) {
4137: hp->h_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE);
4138: DBG_VOP_LOCKS_TEST(0);
4139: return (0);
4140: }
4141:
4142: if (H_FORKTYPE(hp) == kSysFile) {
4143: hp->h_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE);
4144: DBG_VOP_LOCKS_TEST(0);
4145: return (0);
4146: }
4147:
4148: if (VTOVFS(ap->a_vp)->mnt_flag & MNT_RDONLY) {
4149: hp->h_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE);
4150: DBG_VOP_LOCKS_TEST(0);
4151: DBG_VOP(("hfs_update: returning 0 (all flags were cleared because the volume is read-only.\n"));
4152: return (0);
4153: }
4154:
4155: /* Check to see if MacOS set the fcb to be dirty, if so, translate it to IN_MODIFIED */
4156: if (HTOFCB(hp)->fcbFlags &fcbModifiedMask)
4157: hp->h_nodeflags |= IN_MODIFIED;
4158:
4159: if ((hp->h_nodeflags & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0) {
4160: DBG_VOP_LOCKS_TEST(0);
4161: DBG_VOP(("hfs_update: returning 0 because the metadata is unchanged.\n"));
4162: return (0);
4163: };
4164:
4165: if (hp->h_nodeflags & IN_ACCESS)
4166: hp->h_meta->h_atime = ap->a_access->tv_sec;
4167: if (hp->h_nodeflags & IN_UPDATE)
4168: hp->h_meta->h_mtime = ap->a_modify->tv_sec;
4169: if (hp->h_nodeflags & IN_CHANGE) {
4170: hp->h_meta->h_ctime = time.tv_sec;
4171: /*
4172: * HFS dates that WE set must be adjusted for DST
4173: */
4174: if ((HTOVCB(hp)->vcbSigWord == kHFSSigWord) && gTimeZone.tz_dsttime) {
4175: hp->h_meta->h_ctime += 3600;
4176: hp->h_meta->h_mtime = hp->h_meta->h_ctime;
4177: }
4178: }
4179:
4180: p = current_proc();
4181: /*
4182: * Since VOP_UPDATE can be called from withing another VOP (eg VOP_RENAME),
4183: * the Catalog b-tree may aready be locked by the current thread. So we
4184: * allow recursive locking of the Catalog from within VOP_UPDATE.
4185: */
4186:
4187: /* Lock the Catalog b-tree file */
4188: retval = hfs_metafilelocking(HTOHFS(hp), kHFSCatalogFileID, LK_EXCLUSIVE | LK_CANRECURSE, p);
4189: if (retval) {
4190: DBG_ERR(("Could not lock catalog tree"));
4191: DBG_VOP_LOCKS_TEST(retval);
4192: DBG_ASSERT(*((int*)&ap->a_vp->v_interlock) == 0);
4193: return (retval);
4194: };
4195: DBG_ASSERT(*((int*)&ap->a_vp->v_interlock) == 0);
4196:
4197: filename = H_NAME(hp);
4198: pid = H_DIRID(hp);
4199:
4200: #if HFS_HARDLINKS
4201: /*
4202: * Force an update of the data node instead of the link node
4203: * by passing the fileID instead of parID and name.
4204: */
4205: if (hp->h_meta->h_metaflags & IN_DATANODE) {
4206: filename = NULL;
4207: pid = H_FILEID(hp);
4208: }
4209: #endif
4210: vcb = HTOVCB(hp);
4211: catInfo.hint = H_HINT(hp);
4212: retval = hfsLookup(vcb, pid, filename, -1, &catInfo);
4213:
4214: H_HINT(hp) = catInfo.hint;
4215: if (retval != noErr) {
4216: DBG_ERR(("hfs_update: error %d on GetCatalogNode...\n", retval));
4217: goto exit_relse;
4218: };
4219:
4220: CopyVNodeToCatalogNode (HTOV(hp), &catInfo.nodeData);
4221:
4222: retval = UpdateCatalogNode(vcb, pid, filename, H_HINT(hp), &catInfo.nodeData);
4223:
4224: if (retval != noErr) {
4225: DBG_ERR(("hfs_update: error %d on UpdateCatalogNode...\n", retval));
4226: retval = MacToVFSError(retval);
4227: goto exit_relse;
4228: };
4229:
4230: /* After the updates are finished, clear the flags */
4231: hp->h_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE);
4232: HTOFCB(hp)->fcbFlags &= ~fcbModifiedMask;
4233:
4234: /* Update general data */
4235: if (ap->a_vp->v_type == VDIR) {
4236: hp->h_meta->h_valence = catInfo.nodeData.cnd_valence;
4237: hp->h_meta->h_size = sizeof(rootdots) +
4238: (catInfo.nodeData.cnd_valence * AVERAGE_HFSDIRENTRY_SIZE);
4239: if (hp->h_meta->h_size < MAX_HFSDIRENTRY_SIZE)
4240: hp->h_meta->h_size < MAX_HFSDIRENTRY_SIZE;
4241: } else {
4242: hp->h_meta->h_size = vcb->blockSize *
4243: (catInfo.nodeData.cnd_rsrcfork.totalBlocks +
4244: catInfo.nodeData.cnd_datafork.totalBlocks);
4245: }
4246:
4247:
4248: exit_relse:
4249: /* unlock the Catalog b-tree file */
4250: (void) hfs_metafilelocking(HTOHFS(hp), kHFSCatalogFileID, LK_RELEASE, p);
4251:
4252: DBG_VOP(("hfs_update: returning %d.\n", retval));
4253: DBG_VOP_LOCKS_TEST(retval);
4254: DBG_ASSERT(*((int*)&ap->a_vp->v_interlock) == 0);
4255: return (retval);
4256: }
4257:
4258:
4259: /*
4260: * Initialize the vnode associated with a new hfsnode,
4261: * handle aliased vnodes.
4262: */
4263: int
4264: hfs_vinit(mntp, specops, fifoops, vpp)
4265: struct mount *mntp;
4266: int (**specops)();
4267: int (**fifoops)();
4268: struct vnode **vpp;
4269: {
4270: struct hfsnode *hp;
4271: struct vnode *vp, *nvp;
4272:
4273: vp = *vpp;
4274: hp = VTOH(vp);
4275: /* vp->v_type set in CopyCatalogToHFSNode */
4276: switch(vp->v_type) {
4277: case VCHR:
4278: case VBLK:
4279: vp->v_op = specops;
4280: if ((nvp = checkalias(vp, hp->h_meta->h_rdev, mntp))) {
4281: /*
4282: * Discard unneeded vnode, but save its hfsnode.
4283: * Note that the lock is carried over in the hfsnode
4284: * to the replacement vnode.
4285: */
4286: nvp->v_data = vp->v_data;
4287: vp->v_data = NULL;
4288: vp->v_op = spec_vnodeop_p;
4289: VRELE(vp);
4290: vgone(vp);
4291: /*
4292: * Reinitialize aliased hfsnode.
4293: */
4294:
4295: hp->h_vp = nvp;
4296: vp = nvp;
4297: }
4298: break;
4299: case VFIFO:
4300: #if FIFO
4301: vp->v_op = fifoops;
4302: break;
4303: #else
4304: return (EOPNOTSUPP);
4305: #endif
4306: default:
4307: break;
4308: }
4309: if (H_FILEID(hp) == kRootDirID)
4310: vp->v_flag |= VROOT;
4311:
4312: *vpp = vp;
4313: return (0);
4314: }
4315:
4316: /*
4317: * Allocate a new node
4318: *
4319: * Assumes that the catalog b-tree is locked
4320: *
4321: * Upon leaving, namei buffer must be freed.
4322: *
4323: */
4324: static int
4325: hfs_makenode(mode, rawdev, dvp, vpp, cnp)
4326: int mode;
4327: dev_t rawdev;
4328: struct vnode *dvp;
4329: struct vnode **vpp;
4330: struct componentname *cnp;
4331: {
4332: register struct hfsnode *hp, *parhp;
4333: struct timeval tv;
4334: struct vnode *tvp;
4335: struct hfsCatalogInfo catInfo;
4336: ExtendedVCB *vcb;
4337: UInt8 forkType;
4338: int retval;
4339: DBG_FUNC_NAME("makenode");
4340:
4341: parhp = VTOH(dvp);
4342: vcb = HTOVCB(parhp);
4343: *vpp = NULL;
4344: tvp = NULL;
4345: if ((mode & IFMT) == 0)
4346: mode |= IFREG;
4347:
4348: #if HFS_DIAGNOSTIC
4349: if ((cnp->cn_flags & HASBUF) == 0)
4350: panic("hfs_makenode: no name");
4351: #endif
4352:
4353: /* Create the Catalog B*-Tree entry */
4354: retval = hfsCreate(vcb, H_FILEID(parhp), cnp->cn_nameptr, mode);
4355: if (retval != E_NONE) {
4356: DBG_ERR(("%s: hfsCreate FAILED: %s, %s\n", funcname, cnp->cn_nameptr, H_NAME(parhp)));
4357: goto bad1;
4358: }
4359:
4360: /* Look up the catalog entry just created: */
4361: catInfo.hint = kNoHint;
4362: retval = hfsLookup(vcb, H_FILEID(parhp), cnp->cn_nameptr, cnp->cn_namelen, &catInfo);
4363: if (retval != E_NONE) {
4364: DBG_ERR(("%s: hfsLookup FAILED: %s, %s\n", funcname, cnp->cn_nameptr, H_NAME(parhp)));
4365: goto bad1;
4366: }
4367:
4368: /* hfs plus has additional metadata to initialize */
4369: if (vcb->vcbSigWord == kHFSPlusSigWord) {
4370: u_int32_t pflags;
4371: int catmode;
4372:
4373: catmode = mode;
4374: catInfo.nodeData.cnd_ownerID = cnp->cn_cred->cr_uid;
4375: catInfo.nodeData.cnd_groupID = parhp->h_meta->h_gid;
4376: /* XXX should we move this to post hfsGet? */
4377: catInfo.nodeData.cnd_specialDevice = rawdev;
4378:
4379: switch (catmode & IFMT) {
4380: case IFLNK:
4381: catInfo.nodeData.cnd_ownerID = parhp->h_meta->h_uid;
4382: break;
4383:
4384: case IFCHR:
4385: case IFBLK:
4386: /*
4387: * Don't tag as a special file (BLK or CHR) until *after*
4388: * hfsGet is called. This insures that the checkalias call
4389: * is defered until hfs_mknod completes.
4390: */
4391: catmode = (catmode & ~IFMT) | IFREG;
4392: break;
4393: }
4394:
4395: if ((catmode & ISGID) && !groupmember(parhp->h_meta->h_gid, cnp->cn_cred) &&
4396: suser(cnp->cn_cred, NULL))
4397: catmode &= ~ISGID;
4398:
4399: if (cnp->cn_flags & ISWHITEOUT)
4400: pflags = UF_OPAQUE;
4401: else
4402: pflags = 0;
4403:
4404: /*
4405: * The 32-bit pflags field has two bytes of significance which are
4406: * combined with the mode to yield a 32-bit permissions field as follows:
4407: *
4408: * +------------------------------------+
4409: * pflags: |XXXXXXXX| A |XXXXXXXX| B |
4410: * +------------------------------------+
4411: * |
4412: * V
4413: * +------------------------------------+
4414: * permissions: | A | B | mode |
4415: * +------------------------------------+
4416: */
4417: catInfo.nodeData.cnd_permissions =
4418: (((pflags << 8) & 0xFF000000) | /* A */
4419: ((pflags << 16) & 0x00FF0000) | /* B */
4420: (catmode & 0x0000FFFF)); /* mode */
4421: }
4422:
4423: /* Create a vnode for the object just created: */
4424: forkType = (catInfo.nodeData.cnd_type == kCatalogFolderNode) ? kDirectory : kDataFork;
4425: if ((retval = hfs_vcreate(vcb, &catInfo, forkType, &tvp))) {
4426: goto bad1;
4427: }
4428:
4429: /* flush out pflags, mode, gid, uid and rdev */
4430: tv = time;
4431: if (vcb->vcbSigWord == kHFSPlusSigWord) {
4432: hp = VTOH(tvp);
4433: /* reset mode and v_type in case it was BLK/CHR */
4434: hp->h_meta->h_mode = mode;
4435: tvp->v_type = IFTOVT(mode);
4436: hp->h_meta->h_metaflags &= ~IN_UNSETACCESS;
4437: hp->h_nodeflags |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
4438: if ((retval = VOP_UPDATE(tvp, &tv, &tv, 1)))
4439: goto bad2;
4440: }
4441:
4442: VTOH(dvp)->h_nodeflags |= IN_CHANGE | IN_UPDATE;
4443: if ((retval = VOP_UPDATE(dvp, &tv, &tv, 1)))
4444: goto bad2;
4445:
4446: if ((cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) {
4447: FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
4448: };
4449: VPUT(dvp);
4450: #if MACH_NBC
4451: if ((tvp->v_type == VREG) && !(tvp->v_vm_info)){
4452: vm_info_init(tvp);
4453: }
4454: #endif /* MACH_NBC */
4455: *vpp = tvp;
4456: return (0);
4457:
4458: bad2:
4459: /*
4460: * Write retval occurred trying to update the node
4461: * or the directory so must deallocate the node.
4462: */
4463: /* XXX SER In the future maybe set *vpp to 0xdeadbeef for testing */
4464: VPUT(tvp);
4465:
4466: bad1:
4467: if ((cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) {
4468: FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
4469: };
4470: VPUT(dvp);
4471:
4472: return (retval);
4473:
4474: }
4475:
4476:
4477: #if DBG_VOP_TEST_LOCKS
4478:
4479: /* XXX SER Add passing in the flags...might not be a serious error if locked */
4480:
4481: void DbgVopTest( int maxSlots,
4482: int retval,
4483: VopDbgStoreRec *VopDbgStore,
4484: char *funcname)
4485: {
4486: int index;
4487:
4488: for (index = 0; index < maxSlots; index++)
4489: {
4490: if (VopDbgStore[index].id != index) {
4491: DEBUG_BREAK_MSG(("%s: DBG_VOP_LOCK: invalid id field (%d) in target entry (#%d).\n", funcname, VopDbgStore[index].id, index));
4492: };
4493:
4494: if ((VopDbgStore[index].vp != NULL) &&
4495: ((VopDbgStore[index].vp->v_data==NULL) || (VTOH(VopDbgStore[index].vp)->h_valid != HFS_VNODE_MAGIC)))
4496: continue;
4497:
4498: if (VopDbgStore[index].vp != NULL)
4499: debug_check_vnode(VopDbgStore[index].vp, 0);
4500:
4501: switch (VopDbgStore[index].inState)
4502: {
4503: case VOPDBG_IGNORE:
4504: case VOPDBG_SAME:
4505: /* Do Nothing !!! */
4506: break;
4507: case VOPDBG_LOCKED:
4508: case VOPDBG_UNLOCKED:
4509: case VOPDBG_LOCKNOTNIL:
4510: {
4511: if (VopDbgStore[index].vp == NULL && (VopDbgStore[index].inState != VOPDBG_LOCKNOTNIL)) {
4512: DBG_ERR (("%s: InState check: Null vnode ptr in entry #%d\n", funcname, index));
4513: } else if (VopDbgStore[index].vp != NULL) {
4514: switch (VopDbgStore[index].inState)
4515: {
4516: case VOPDBG_LOCKED:
4517: case VOPDBG_LOCKNOTNIL:
4518: if (VopDbgStore[index].inValue == 0)
4519: {
4520: DBG_ERR (("%s: Entry: not LOCKED:", funcname));
4521: DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp);
4522: DBG_ERR (("\n"));
4523: }
4524: break;
4525: case VOPDBG_UNLOCKED:
4526: if (VopDbgStore[index].inValue != 0)
4527: {
4528: DBG_ERR (("%s: Entry: not UNLOCKED:", funcname));
4529: DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp);
4530: DBG_ERR (("\n"));
4531: }
4532: break;
4533: }
4534: }
4535: break;
4536: }
4537: default:
4538: DBG_ERR (("%s: DBG_VOP_LOCK on entry: bad lock test value: %d\n", funcname, VopDbgStore[index].errState));
4539: }
4540:
4541:
4542: if (retval != 0)
4543: {
4544: switch (VopDbgStore[index].errState)
4545: {
4546: case VOPDBG_IGNORE:
4547: /* Do Nothing !!! */
4548: break;
4549: case VOPDBG_LOCKED:
4550: case VOPDBG_UNLOCKED:
4551: case VOPDBG_SAME:
4552: {
4553: if (VopDbgStore[index].vp == NULL) {
4554: DBG_ERR (("%s: ErrState check: Null vnode ptr in entry #%d\n", funcname, index));
4555: } else {
4556: VopDbgStore[index].outValue = lockstatus(&VTOH(VopDbgStore[index].vp)->h_lock);
4557: switch (VopDbgStore[index].errState)
4558: {
4559: case VOPDBG_LOCKED:
4560: if (VopDbgStore[index].outValue == 0)
4561: {
4562: DBG_ERR (("%s: Error: not LOCKED:", funcname));
4563: DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp);
4564: DBG_ERR(("\n"));
4565: }
4566: break;
4567: case VOPDBG_UNLOCKED:
4568: if (VopDbgStore[index].outValue != 0)
4569: {
4570: DBG_ERR (("%s: Error: not UNLOCKED:", funcname));
4571: DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp);
4572: DBG_ERR(("\n"));
4573: }
4574: break;
4575: case VOPDBG_SAME:
4576: if (VopDbgStore[index].outValue != VopDbgStore[index].inValue)
4577: DBG_ERR (("%s: Error: In/Out locks are DIFFERENT: 0x%x, inis %d and out is %d\n", funcname, (u_int)VopDbgStore[index].vp, VopDbgStore[index].inValue, VopDbgStore[index].outValue));
4578: break;
4579: }
4580: }
4581: break;
4582: }
4583: case VOPDBG_LOCKNOTNIL:
4584: if (VopDbgStore[index].vp != NULL) {
4585: VopDbgStore[index].outValue = lockstatus(&VTOH(VopDbgStore[index].vp)->h_lock);
4586: if (VopDbgStore[index].outValue == 0)
4587: DBG_ERR (("%s: Error: Not LOCKED: 0x%x\n", funcname, (u_int)VopDbgStore[index].vp));
4588: }
4589: break;
4590: default:
4591: DBG_ERR (("%s: Error: bad lock test value: %d\n", funcname, VopDbgStore[index].errState));
4592: }
4593: }
4594: else
4595: {
4596: switch (VopDbgStore[index].outState)
4597: {
4598: case VOPDBG_IGNORE:
4599: /* Do Nothing !!! */
4600: break;
4601: case VOPDBG_LOCKED:
4602: case VOPDBG_UNLOCKED:
4603: case VOPDBG_SAME:
4604: if (VopDbgStore[index].vp == NULL) {
4605: DBG_ERR (("%s: OutState: Null vnode ptr in entry #%d\n", funcname, index));
4606: };
4607: if (VopDbgStore[index].vp != NULL)
4608: {
4609: VopDbgStore[index].outValue = lockstatus(&VTOH(VopDbgStore[index].vp)->h_lock);
4610: switch (VopDbgStore[index].outState)
4611: {
4612: case VOPDBG_LOCKED:
4613: if (VopDbgStore[index].outValue == 0)
4614: {
4615: DBG_ERR (("%s: Out: not LOCKED:", funcname));
4616: DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp);
4617: DBG_ERR (("\n"));
4618: }
4619: break;
4620: case VOPDBG_UNLOCKED:
4621: if (VopDbgStore[index].outValue != 0)
4622: {
4623: DBG_ERR (("%s: Out: not UNLOCKED:", funcname));
4624: DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp);
4625: DBG_ERR (("\n"));
4626: }
4627: break;
4628: case VOPDBG_SAME:
4629: if (VopDbgStore[index].outValue != VopDbgStore[index].inValue)
4630: DBG_ERR (("%s: Out: In/Out locks are DIFFERENT: 0x%x, in is %d and out is %d\n", funcname, (u_int)VopDbgStore[index].vp, VopDbgStore[index].inValue, VopDbgStore[index].outValue));
4631: break;
4632: }
4633: }
4634: break;
4635: case VOPDBG_LOCKNOTNIL:
4636: if (VopDbgStore[index].vp != NULL) {
4637: if (&VTOH(VopDbgStore[index].vp)->h_lock == NULL) {
4638: DBG_ERR (("%s: DBG_VOP_LOCK on out: Null lock on vnode 0x%x\n", funcname, (u_int)VopDbgStore[index].vp));
4639: }
4640: else {
4641: VopDbgStore[index].outValue = lockstatus(&VTOH(VopDbgStore[index].vp)->h_lock);
4642: if (VopDbgStore[index].outValue == 0)
4643: {
4644: DBG_ERR (("%s: DBG_VOP_LOCK on out: Should be LOCKED:", funcname));
4645: DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp); DBG_ERR (("\n"));
4646: }
4647: }
4648: }
4649: break;
4650: default:
4651: DBG_ERR (("%s: DBG_VOP_LOCK on out: bad lock test value: %d\n", funcname, VopDbgStore[index].outState));
4652: }
4653: }
4654:
4655: VopDbgStore[index].id = -1; /* Invalidate the entry to allow panic-free re-use */
4656: }
4657: }
4658:
4659: #endif /* DBG_VOP_TEST_LOCKS */
4660:
4661: /*
4662: * Wrapper for special device reads
4663: */
4664: int
4665: hfsspec_read(ap)
4666: struct vop_read_args /* {
4667: struct vnode *a_vp;
4668: struct uio *a_uio;
4669: int a_ioflag;
4670: struct ucred *a_cred;
4671: } */ *ap;
4672: {
4673:
4674: /*
4675: * Set access flag.
4676: */
4677: VTOH(ap->a_vp)->h_nodeflags |= IN_ACCESS;
4678: return (VOCALL (spec_vnodeop_p, VOFFSET(vop_read), ap));
4679: }
4680:
4681: /*
4682: * Wrapper for special device writes
4683: */
4684: int
4685: hfsspec_write(ap)
4686: struct vop_write_args /* {
4687: struct vnode *a_vp;
4688: struct uio *a_uio;
4689: int a_ioflag;
4690: struct ucred *a_cred;
4691: } */ *ap;
4692: {
4693:
4694: /*
4695: * Set update and change flags.
4696: */
4697: VTOH(ap->a_vp)->h_nodeflags |= IN_CHANGE | IN_UPDATE;
4698: return (VOCALL (spec_vnodeop_p, VOFFSET(vop_write), ap));
4699: }
4700:
4701: /*
4702: * Wrapper for special device close
4703: *
4704: * Update the times on the hfsnode then do device close.
4705: */
4706: int
4707: hfsspec_close(ap)
4708: struct vop_close_args /* {
4709: struct vnode *a_vp;
4710: int a_fflag;
4711: struct ucred *a_cred;
4712: struct proc *a_p;
4713: } */ *ap;
4714: {
4715: struct vnode *vp = ap->a_vp;
4716: struct hfsnode *hp = VTOH(vp);
4717:
4718: simple_lock(&vp->v_interlock);
4719: if (ap->a_vp->v_usecount > 1)
4720: HFSTIMES(hp, &time, &time);
4721: simple_unlock(&vp->v_interlock);
4722: return (VOCALL (spec_vnodeop_p, VOFFSET(vop_close), ap));
4723: }
4724:
4725: #if FIFO
4726: /*
4727: * Wrapper for fifo reads
4728: */
4729: int
4730: hfsfifo_read(ap)
4731: struct vop_read_args /* {
4732: struct vnode *a_vp;
4733: struct uio *a_uio;
4734: int a_ioflag;
4735: struct ucred *a_cred;
4736: } */ *ap;
4737: {
4738: extern int (**fifo_vnodeop_p)();
4739:
4740: /*
4741: * Set access flag.
4742: */
4743: VTOH(ap->a_vp)->h_nodeflags |= IN_ACCESS;
4744: return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_read), ap));
4745: }
4746:
4747: /*
4748: * Wrapper for fifo writes
4749: */
4750: int
4751: hfsfifo_write(ap)
4752: struct vop_write_args /* {
4753: struct vnode *a_vp;
4754: struct uio *a_uio;
4755: int a_ioflag;
4756: struct ucred *a_cred;
4757: } */ *ap;
4758: {
4759: extern int (**fifo_vnodeop_p)();
4760:
4761: /*
4762: * Set update and change flags.
4763: */
4764: VTOH(ap->a_vp)->h_nodeflags |= IN_CHANGE | IN_UPDATE;
4765: return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_write), ap));
4766: }
4767:
4768: /*
4769: * Wrapper for fifo close
4770: *
4771: * Update the times on the hfsnode then do device close.
4772: */
4773: int
4774: hfsfifo_close(ap)
4775: struct vop_close_args /* {
4776: struct vnode *a_vp;
4777: int a_fflag;
4778: struct ucred *a_cred;
4779: struct proc *a_p;
4780: } */ *ap;
4781: {
4782: extern int (**fifo_vnodeop_p)();
4783: struct vnode *vp = ap->a_vp;
4784: struct hfsnode *hp = VTOH(vp);
4785:
4786: simple_lock(&vp->v_interlock);
4787: if (ap->a_vp->v_usecount > 1)
4788: HFSTIMES(hp, &time, &time);
4789: simple_unlock(&vp->v_interlock);
4790: return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_close), ap));
4791: }
4792: #endif /* FIFO */
4793:
4794:
4795: /*****************************************************************************
4796: *
4797: * VOP Tables
4798: *
4799: *****************************************************************************/
4800:
4801: struct vnodeopv_entry_desc hfs_vnodeop_entries[] = {
4802: { &vop_default_desc, vn_default_error },
4803: { &vop_lookup_desc, hfs_cache_lookup }, /* lookup */
4804: { &vop_create_desc, hfs_create }, /* create */
4805: { &vop_mknod_desc, hfs_mknod }, /* mknod */
4806: { &vop_open_desc, hfs_open }, /* open */
4807: { &vop_close_desc, hfs_close }, /* close */
4808: { &vop_access_desc, hfs_access }, /* access */
4809: { &vop_getattr_desc, hfs_getattr }, /* getattr */
4810: { &vop_setattr_desc, hfs_setattr }, /* setattr */
4811: { &vop_read_desc, hfs_read }, /* read */
4812: { &vop_write_desc, hfs_write }, /* write */
4813: { &vop_ioctl_desc, hfs_ioctl }, /* ioctl */
4814: { &vop_select_desc, hfs_select }, /* select */
4815: { &vop_exchange_desc, hfs_exchange }, /* exchange */
4816: { &vop_mmap_desc, hfs_mmap }, /* mmap */
4817: { &vop_fsync_desc, hfs_fsync }, /* fsync */
4818: { &vop_seek_desc, hfs_seek }, /* seek */
4819: { &vop_remove_desc, hfs_remove }, /* remove */
4820: #if HFS_HARDLINKS
4821: { &vop_link_desc, hfs_link }, /* link */
4822: #else
4823: { &vop_link_desc, err_link }, /* link (NOT SUPPORTED) */
4824: #endif
4825: { &vop_rename_desc, hfs_rename }, /* rename */
4826: { &vop_mkdir_desc, hfs_mkdir }, /* mkdir */
4827: { &vop_rmdir_desc, hfs_rmdir }, /* rmdir */
4828: { &vop_mkcomplex_desc,hfs_mkcomplex }, /* mkcomplex */
4829: { &vop_getattrlist_desc,hfs_getattrlist }, /* getattrlist */
4830: { &vop_setattrlist_desc,hfs_setattrlist }, /* setattrlist */
4831: { &vop_symlink_desc, hfs_symlink }, /* symlink */
4832: { &vop_readdir_desc, hfs_readdir }, /* readdir */
4833: { &vop_readdirattr_desc, hfs_readdirattr }, /* readdirattr */
4834: { &vop_readlink_desc, hfs_readlink }, /* readlink */
4835: { &vop_abortop_desc, hfs_abortop }, /* abortop */
4836: { &vop_inactive_desc, hfs_inactive }, /* inactive */
4837: { &vop_reclaim_desc, hfs_reclaim }, /* reclaim */
4838: { &vop_lock_desc, hfs_lock }, /* lock */
4839: { &vop_unlock_desc, hfs_unlock }, /* unlock */
4840: { &vop_bmap_desc, hfs_bmap }, /* bmap */
4841: { &vop_strategy_desc, hfs_strategy }, /* strategy */
4842: { &vop_print_desc, hfs_print }, /* print */
4843: { &vop_islocked_desc, hfs_islocked }, /* islocked */
4844: { &vop_pathconf_desc, hfs_pathconf }, /* pathconf */
4845: { &vop_advlock_desc, hfs_advlock }, /* advlock */
4846: { &vop_reallocblks_desc, hfs_reallocblks }, /* reallocblks */
4847: { &vop_truncate_desc, hfs_truncate }, /* truncate */
4848: { &vop_allocate_desc, hfs_allocate }, /* allocate */
4849: { &vop_update_desc, hfs_update }, /* update */
4850: { &vop_searchfs_desc,hfs_search }, /* search fs */
4851: { &vop_bwrite_desc, vn_bwrite }, /* bwrite */
4852: { &vop_pagein_desc, hfs_pagein }, /* pagein */
4853: { &vop_pageout_desc, hfs_pageout }, /* pageout */
4854: { &vop_copyfile_desc, err_copyfile }, /* copyfile */
4855: { NULL, NULL }
4856: };
4857:
4858: struct vnodeopv_desc hfs_vnodeop_opv_desc =
4859: { &hfs_vnodeop_p, hfs_vnodeop_entries };
4860:
4861: int (**hfs_specop_p)();
4862: struct vnodeopv_entry_desc hfs_specop_entries[] = {
4863: { &vop_default_desc, vn_default_error },
4864: { &vop_lookup_desc, spec_lookup }, /* lookup */
4865: { &vop_create_desc, spec_create }, /* create */
4866: { &vop_mknod_desc, spec_mknod }, /* mknod */
4867: { &vop_open_desc, spec_open }, /* open */
4868: { &vop_close_desc, hfsspec_close }, /* close */
4869: { &vop_access_desc, hfs_access }, /* access */
4870: { &vop_getattr_desc, hfs_getattr }, /* getattr */
4871: { &vop_setattr_desc, hfs_setattr }, /* setattr */
4872: { &vop_read_desc, hfsspec_read }, /* read */
4873: { &vop_write_desc, hfsspec_write }, /* write */
4874: { &vop_lease_desc, spec_lease_check }, /* lease */
4875: { &vop_ioctl_desc, spec_ioctl }, /* ioctl */
4876: { &vop_select_desc, spec_select }, /* select */
4877: { &vop_revoke_desc, spec_revoke }, /* revoke */
4878: { &vop_mmap_desc, spec_mmap }, /* mmap */
4879: { &vop_fsync_desc, hfs_fsync }, /* fsync */
4880: { &vop_seek_desc, spec_seek }, /* seek */
4881: { &vop_remove_desc, spec_remove }, /* remove */
4882: { &vop_link_desc, spec_link }, /* link */
4883: { &vop_rename_desc, spec_rename }, /* rename */
4884: { &vop_mkdir_desc, spec_mkdir }, /* mkdir */
4885: { &vop_rmdir_desc, spec_rmdir }, /* rmdir */
4886: { &vop_symlink_desc, spec_symlink }, /* symlink */
4887: { &vop_readdir_desc, spec_readdir }, /* readdir */
4888: { &vop_readlink_desc, spec_readlink }, /* readlink */
4889: { &vop_abortop_desc, spec_abortop }, /* abortop */
4890: { &vop_inactive_desc, hfs_inactive }, /* inactive */
4891: { &vop_reclaim_desc, hfs_reclaim }, /* reclaim */
4892: { &vop_lock_desc, hfs_lock }, /* lock */
4893: { &vop_unlock_desc, hfs_unlock }, /* unlock */
4894: { &vop_bmap_desc, spec_bmap }, /* bmap */
4895: { &vop_strategy_desc, spec_strategy }, /* strategy */
4896: { &vop_print_desc, hfs_print }, /* print */
4897: { &vop_islocked_desc, hfs_islocked }, /* islocked */
4898: { &vop_pathconf_desc, spec_pathconf }, /* pathconf */
4899: { &vop_advlock_desc, spec_advlock }, /* advlock */
4900: { &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */
4901: { &vop_valloc_desc, spec_valloc }, /* valloc */
4902: { &vop_reallocblks_desc, spec_reallocblks }, /* reallocblks */
4903: { &vop_vfree_desc, err_vfree }, /* vfree */
4904: { &vop_truncate_desc, spec_truncate }, /* truncate */
4905: { &vop_update_desc, hfs_update }, /* update */
4906: { &vop_bwrite_desc, vn_bwrite },
4907: #ifdef NeXT
4908: { &vop_devblocksize_desc, spec_devblocksize }, /* devblocksize */
4909: #endif /* NeXT */
4910: { &vop_pagein_desc, hfs_pagein }, /* Pagein */
4911: { &vop_pageout_desc, hfs_pageout }, /* Pageout */
4912: { &vop_copyfile_desc, err_copyfile }, /* copyfile */
4913: { (struct vnodeop_desc*)NULL, (int(*)())NULL }
4914: };
4915: struct vnodeopv_desc hfs_specop_opv_desc =
4916: { &hfs_specop_p, hfs_specop_entries };
4917:
4918: #if FIFO
4919: int (**hfs_fifoop_p)();
4920: struct vnodeopv_entry_desc hfs_fifoop_entries[] = {
4921: { &vop_default_desc, vn_default_error },
4922: { &vop_lookup_desc, fifo_lookup }, /* lookup */
4923: { &vop_create_desc, fifo_create }, /* create */
4924: { &vop_mknod_desc, fifo_mknod }, /* mknod */
4925: { &vop_open_desc, fifo_open }, /* open */
4926: { &vop_close_desc, hfsfifo_close }, /* close */
4927: { &vop_access_desc, hfs_access }, /* access */
4928: { &vop_getattr_desc, hfs_getattr }, /* getattr */
4929: { &vop_setattr_desc, hfs_setattr }, /* setattr */
4930: { &vop_read_desc, hfsfifo_read }, /* read */
4931: { &vop_write_desc, hfsfifo_write }, /* write */
4932: { &vop_lease_desc, fifo_lease_check }, /* lease */
4933: { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */
4934: { &vop_select_desc, fifo_select }, /* select */
4935: { &vop_revoke_desc, fifo_revoke }, /* revoke */
4936: { &vop_mmap_desc, fifo_mmap }, /* mmap */
4937: { &vop_fsync_desc, hfs_fsync }, /* fsync */
4938: { &vop_seek_desc, fifo_seek }, /* seek */
4939: { &vop_remove_desc, fifo_remove }, /* remove */
4940: { &vop_link_desc, fifo_link }, /* link */
4941: { &vop_rename_desc, fifo_rename }, /* rename */
4942: { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */
4943: { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */
4944: { &vop_symlink_desc, fifo_symlink }, /* symlink */
4945: { &vop_readdir_desc, fifo_readdir }, /* readdir */
4946: { &vop_readlink_desc, fifo_readlink }, /* readlink */
4947: { &vop_abortop_desc, fifo_abortop }, /* abortop */
4948: { &vop_inactive_desc, hfs_inactive }, /* inactive */
4949: { &vop_reclaim_desc, hfs_reclaim }, /* reclaim */
4950: { &vop_lock_desc, hfs_lock }, /* lock */
4951: { &vop_unlock_desc, hfs_unlock }, /* unlock */
4952: { &vop_bmap_desc, fifo_bmap }, /* bmap */
4953: { &vop_strategy_desc, fifo_strategy }, /* strategy */
4954: { &vop_print_desc, hfs_print }, /* print */
4955: { &vop_islocked_desc, hfs_islocked }, /* islocked */
4956: { &vop_pathconf_desc, fifo_pathconf }, /* pathconf */
4957: { &vop_advlock_desc, fifo_advlock }, /* advlock */
4958: { &vop_blkatoff_desc, fifo_blkatoff }, /* blkatoff */
4959: { &vop_valloc_desc, fifo_valloc }, /* valloc */
4960: { &vop_reallocblks_desc, fifo_reallocblks }, /* reallocblks */
4961: { &vop_vfree_desc, err_vfree }, /* vfree */
4962: { &vop_truncate_desc, fifo_truncate }, /* truncate */
4963: { &vop_update_desc, hfs_update }, /* update */
4964: { &vop_bwrite_desc, vn_bwrite },
4965: { &vop_pagein_desc, hfs_pagein }, /* Pagein */
4966: { &vop_pageout_desc, hfs_pageout }, /* Pageout */
4967: { &vop_copyfile_desc, err_copyfile }, /* copyfile */
4968: { (struct vnodeop_desc*)NULL, (int(*)())NULL }
4969: };
4970: struct vnodeopv_desc hfs_fifoop_opv_desc =
4971: { &hfs_fifoop_p, hfs_fifoop_entries };
4972: #endif /* FIFO */
4973:
4974:
4975:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.