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