2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
24 * (c) 1997-2000 Apple Computer, Inc. All Rights Reserved
27 * MODIFICATION HISTORY:
28 * 04-May-1999 Don Brady Split off from hfs_vnodeops.c.
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
38 #include <mach/machine/vm_types.h>
39 #include <sys/vnode.h>
40 #include <sys/malloc.h>
41 #include <sys/signalvar.h>
43 #include <sys/utfconv.h>
47 #include "hfscommon/headers/FileMgrInternal.h"
48 #include "hfscommon/headers/CatalogPrivate.h"
49 #include "hfscommon/headers/HFSUnicodeWrappers.h"
52 /* Private description used in hfs_search */
54 * ============ W A R N I N G ! ============
55 * DO NOT INCREASE THE SIZE OF THIS STRUCT!
56 * It must match the size of the opaque
57 * searchstate struct (in sys/attr.h).
61 BTreeIterator btreeIterator
;
63 typedef struct SearchState SearchState
;
66 static int UnpackSearchAttributeBlock(struct vnode
*vp
, struct attrlist
*alist
, searchinfospec_t
*searchInfo
, void *attributeBuffer
);
68 Boolean
CheckCriteria(ExtendedVCB
*vcb
, const SearchState
*searchState
,
69 u_long searchBits
, struct attrlist
*attrList
,
70 CatalogNodeData
*cnp
, CatalogKey
*key
,
71 searchinfospec_t
*searchInfo1
, searchinfospec_t
*searchInfo2
);
73 static int CheckAccess(CatalogNodeData
*cnp
, CatalogKey
*key
, struct proc
*p
);
75 static int InsertMatch(struct vnode
*vp
, struct uio
*a_uio
, CatalogNodeData
*cnp
,
76 CatalogKey
*key
, struct attrlist
*returnAttrList
,
77 void *attributesBuffer
, void *variableBuffer
,
78 u_long bufferSize
, u_long
* nummatches
);
80 static Boolean
CompareRange(u_long val
, u_long low
, u_long high
);
81 static Boolean
CompareWideRange(u_int64_t val
, u_int64_t low
, u_int64_t high
);
83 static Boolean
CompareRange( u_long val
, u_long low
, u_long high
)
85 return( (val
>= low
) && (val
<= high
) );
88 static Boolean
CompareWideRange( u_int64_t val
, u_int64_t low
, u_int64_t high
)
90 return( (val
>= low
) && (val
<= high
) );
92 //#define CompareRange(val, low, high) ((val >= low) && (val <= high))
96 /************************************************************************/
97 /* Entry for searchfs() */
98 /************************************************************************/
100 #define errSearchBufferFull 101 /* Internal search errors */
109 IN struct ucred *cred;
116 struct vop_searchfs_args
*ap
; /*
117 struct vnodeop_desc *a_desc;
119 void *a_searchparams1;
120 void *a_searchparams2;
121 struct attrlist *a_searchattrs;
123 struct timeval *a_timelimit;
124 struct attrlist *a_returnattrs;
125 u_long *a_nummatches;
129 struct searchstate *a_searchstate;
132 CatalogNodeData cnode
;
134 FSBufferDescriptor btRecord
;
136 SearchState
*searchState
;
137 searchinfospec_t searchInfo1
;
138 searchinfospec_t searchInfo2
;
139 void *attributesBuffer
;
140 void *variableBuffer
;
143 u_long fixedBlockSize
;
144 u_long eachReturnBufferSize
;
145 struct proc
*p
= current_proc();
146 u_long nodesToCheck
= 30; /* After we search 30 nodes we must give up time */
147 u_long lastNodeNum
= 0XFFFFFFFF;
148 ExtendedVCB
*vcb
= VTOVCB(ap
->a_vp
);
152 /* XXX Parameter check a_searchattrs? */
154 *(ap
->a_nummatches
) = 0;
156 if ( ap
->a_options
& ~SRCHFS_VALIDOPTIONSMASK
)
159 if (ap
->a_uio
->uio_resid
<= 0)
162 isHFSPlus
= (vcb
->vcbSigWord
== kHFSPlusSigWord
);
163 searchState
= (SearchState
*)ap
->a_searchstate
;
166 * Check if this is the first time we are being called.
167 * If it is, allocate SearchState and we'll move it to the users space on exit
169 if ( ap
->a_options
& SRCHFS_START
) {
170 bzero( (caddr_t
)searchState
, sizeof(SearchState
) );
171 operation
= kBTreeFirstRecord
;
172 ap
->a_options
&= ~SRCHFS_START
;
174 operation
= kBTreeCurrentRecord
;
177 /* UnPack the search boundries, searchInfo1, searchInfo2 */
178 err
= UnpackSearchAttributeBlock( ap
->a_vp
, ap
->a_searchattrs
, &searchInfo1
, ap
->a_searchparams1
);
180 err
= UnpackSearchAttributeBlock( ap
->a_vp
, ap
->a_searchattrs
, &searchInfo2
, ap
->a_searchparams2
);
183 btRecord
.itemCount
= 1;
185 btRecord
.itemSize
= sizeof(cnode
);
186 btRecord
.bufferAddress
= &cnode
;
188 btRecord
.itemSize
= sizeof(HFSCatalogFile
);
189 btRecord
.bufferAddress
= &cnode
.cnd_extra
;
191 catalogFCB
= VTOFCB( vcb
->catalogRefNum
);
192 key
= (BTreeKey
*) &(searchState
->btreeIterator
.key
);
193 fixedBlockSize
= sizeof(u_long
) + AttributeBlockSize( ap
->a_returnattrs
); /* u_long for length longword */
194 eachReturnBufferSize
= fixedBlockSize
;
196 if ( ap
->a_returnattrs
->commonattr
& ATTR_CMN_NAME
) /* XXX should be more robust! */
197 eachReturnBufferSize
+= kHFSPlusMaxFileNameBytes
+ 1;
199 MALLOC( attributesBuffer
, void *, eachReturnBufferSize
, M_TEMP
, M_WAITOK
);
200 variableBuffer
= (void*)((char*) attributesBuffer
+ fixedBlockSize
);
202 /* Lock catalog b-tree */
203 err
= hfs_metafilelocking( VTOHFS(ap
->a_vp
), kHFSCatalogFileID
, LK_SHARED
, p
);
204 if ( err
!= E_NONE
) {
205 goto ExitThisRoutine
;
209 * Iterate over all the catalog btree records
212 err
= BTIterateRecord( catalogFCB
, operation
, &(searchState
->btreeIterator
), &btRecord
, &recordSize
);
214 while( err
== E_NONE
) {
216 CopyCatalogNodeData(vcb
, (CatalogRecord
*)&cnode
.cnd_extra
, &cnode
);
218 if ( CheckCriteria( vcb
, searchState
, ap
->a_options
, ap
->a_searchattrs
, &cnode
,
219 (CatalogKey
*)key
, &searchInfo1
, &searchInfo2
) &&
220 CheckAccess(&cnode
, (CatalogKey
*)key
, ap
->a_uio
->uio_procp
)) {
221 err
= InsertMatch(ap
->a_vp
, ap
->a_uio
, &cnode
, (CatalogKey
*)key
,
222 ap
->a_returnattrs
, attributesBuffer
, variableBuffer
,
223 eachReturnBufferSize
, ap
->a_nummatches
);
228 err
= BTIterateRecord( catalogFCB
, kBTreeNextRecord
, &(searchState
->btreeIterator
), &btRecord
, &recordSize
);
230 if ( *(ap
->a_nummatches
) >= ap
->a_maxmatches
)
233 if ( searchState
->btreeIterator
.hint
.nodeNum
!= lastNodeNum
) {
234 lastNodeNum
= searchState
->btreeIterator
.hint
.nodeNum
;
235 if ( --nodesToCheck
== 0 )
236 break; /* We must leave the kernel to give up time */
240 /* Unlock catalog b-tree */
241 (void) hfs_metafilelocking( VTOHFS(ap
->a_vp
), kHFSCatalogFileID
, LK_RELEASE
, p
);
244 if ( err
== E_NONE
) {
245 err
= EAGAIN
; /* signal to the user to call searchfs again */
246 } else if ( err
== errSearchBufferFull
) {
247 if ( *(ap
->a_nummatches
) > 0 )
251 } else if ( err
== btNotFound
) {
252 err
= E_NONE
; /* the entire disk has been searched */
256 FREE( attributesBuffer
, M_TEMP
);
263 CompareMasked(const UInt32
*thisValue
, const UInt32
*compareData
,
264 const UInt32
*compareMask
, UInt32 count
)
269 matched
= true; /* Assume it will all match */
271 for (i
=0; i
<count
; i
++) {
272 if (((*thisValue
++ ^ *compareData
++) & *compareMask
++) != 0) {
283 ComparePartialUnicodeName (register ConstUniCharArrayPtr str
, register ItemCount s_len
,
284 register ConstUniCharArrayPtr find
, register ItemCount f_len
)
286 if (f_len
== 0 || s_len
== 0)
292 } while (FastUnicodeCompare(str
++, f_len
, find
, f_len
) != 0);
299 ComparePartialPascalName ( register ConstStr31Param str
, register ConstStr31Param find
)
301 register u_char s_len
= str
[0];
302 register u_char f_len
= find
[0];
303 register u_char
*tsp
;
306 if (f_len
== 0 || s_len
== 0)
309 bcopy(str
, tmpstr
, s_len
+ 1);
312 while (s_len
-- >= f_len
) {
315 if (FastRelString(tsp
++, find
) == 0)
324 * Check to see if caller has access rights to this item
327 CheckAccess(CatalogNodeData
*cnp
, CatalogKey
*key
, struct proc
*p
)
333 CheckCriteria( ExtendedVCB
*vcb
, const SearchState
*searchState
, u_long searchBits
,
334 struct attrlist
*attrList
, CatalogNodeData
*cnp
, CatalogKey
*key
,
335 searchinfospec_t
*searchInfo1
, searchinfospec_t
*searchInfo2
)
337 Boolean matched
, atleastone
;
339 attrgroup_t searchAttributes
;
341 isHFSPlus
= (vcb
->vcbSigWord
== kHFSPlusSigWord
);
343 switch (cnp
->cnd_type
) {
344 case kCatalogFolderNode
:
345 if ( (searchBits
& SRCHFS_MATCHDIRS
) == 0 ) { /* If we are NOT searching folders */
351 case kCatalogFileNode
:
352 if ( (searchBits
& SRCHFS_MATCHFILES
) == 0 ) { /* If we are NOT searching files */
358 default: /* Never match a thread record or any other type. */
359 return( false ); /* Not a file or folder record, so can't search it */
362 matched
= true; /* Assume we got a match */
363 atleastone
= false; /* Dont insert unless we match at least one criteria */
365 /* First, attempt to match the name -- either partial or complete */
366 if ( attrList
->commonattr
& ATTR_CMN_NAME
) {
368 /* Check for partial/full HFS Plus name match */
370 if ( searchBits
& SRCHFS_MATCHPARTIALNAMES
) {
371 matched
= ComparePartialUnicodeName(key
->hfsPlus
.nodeName
.unicode
,
372 key
->hfsPlus
.nodeName
.length
,
373 (UniChar
*)searchInfo1
->name
,
374 searchInfo1
->nameLength
);
375 } else /* full HFS Plus name match */ {
376 matched
= (FastUnicodeCompare(key
->hfsPlus
.nodeName
.unicode
,
377 key
->hfsPlus
.nodeName
.length
,
378 (UniChar
*)searchInfo1
->name
,
379 searchInfo1
->nameLength
) == 0);
382 /* Check for partial/full HFS name match */
384 if ( searchBits
& SRCHFS_MATCHPARTIALNAMES
)
385 matched
= ComparePartialPascalName(key
->hfs
.nodeName
, (u_char
*)searchInfo1
->name
);
386 else /* full HFS name match */
387 matched
= (FastRelString(key
->hfs
.nodeName
, (u_char
*)searchInfo1
->name
) == 0);
390 if ( matched
== false || (searchBits
& ~SRCHFS_MATCHPARTIALNAMES
) == 0 )
391 goto TestDone
; /* no match, or nothing more to compare */
396 /* Now that we have a record worth searching, see if it matches the search attributes */
397 if (cnp
->cnd_type
== kCatalogFileNode
) {
398 if ((attrList
->dirattr
& ~ATTR_FILE_VALIDMASK
) != 0) { /* attr we do know about */
402 else if ((attrList
->dirattr
& ATTR_FILE_VALIDMASK
) != 0) {
403 searchAttributes
= attrList
->fileattr
;
405 /* File logical length (data fork) */
406 if ( searchAttributes
& ATTR_FILE_DATALENGTH
) {
407 matched
= CompareWideRange(
408 cnp
->cnd_datafork
.logicalSize
,
409 searchInfo1
->f
.dataLogicalLength
,
410 searchInfo2
->f
.dataLogicalLength
);
411 if (matched
== false) goto TestDone
;
415 /* File physical length (data fork) */
416 if ( searchAttributes
& ATTR_FILE_DATAALLOCSIZE
) {
417 matched
= CompareWideRange(
418 cnp
->cnd_datafork
.totalBlocks
* vcb
->blockSize
,
419 searchInfo1
->f
.dataPhysicalLength
,
420 searchInfo2
->f
.dataPhysicalLength
);
421 if (matched
== false) goto TestDone
;
425 /* File logical length (resource fork) */
426 if ( searchAttributes
& ATTR_FILE_RSRCLENGTH
) {
427 matched
= CompareWideRange(
428 cnp
->cnd_rsrcfork
.logicalSize
,
429 searchInfo1
->f
.resourceLogicalLength
,
430 searchInfo2
->f
.resourceLogicalLength
);
431 if (matched
== false) goto TestDone
;
435 /* File physical length (resource fork) */
436 if ( searchAttributes
& ATTR_FILE_RSRCALLOCSIZE
) {
437 matched
= CompareWideRange(
438 cnp
->cnd_rsrcfork
.totalBlocks
* vcb
->blockSize
,
439 searchInfo1
->f
.resourcePhysicalLength
,
440 searchInfo2
->f
.resourcePhysicalLength
);
441 if (matched
== false) goto TestDone
;
446 atleastone
= true; /* to match SRCHFS_MATCHDIRS */
450 * Check the directory attributes
452 else if (cnp
->cnd_type
== kCatalogFolderNode
) {
453 if ((attrList
->dirattr
& ~ATTR_DIR_VALIDMASK
) != 0) { /* attr we do know about */
457 else if ((attrList
->dirattr
& ATTR_DIR_VALIDMASK
) != 0) {
458 searchAttributes
= attrList
->dirattr
;
460 /* Directory valence */
461 if ( searchAttributes
& ATTR_DIR_ENTRYCOUNT
) {
462 matched
= CompareRange(cnp
->cnd_valence
, searchInfo1
->d
.numFiles
, searchInfo2
->d
.numFiles
);
463 if (matched
== false) goto TestDone
;
468 atleastone
= true; /* to match SRCHFS_MATCHDIRS */
473 * Check the common attributes
475 searchAttributes
= attrList
->commonattr
;
476 if ( (searchAttributes
& ATTR_CMN_VALIDMASK
) != 0 ) {
479 if ( searchAttributes
& ATTR_CMN_OBJID
) {
480 matched
= CompareRange( cnp
->cnd_nodeID
, searchInfo1
->nodeID
, searchInfo2
->nodeID
);
481 if (matched
== false) goto TestDone
;
486 if ( searchAttributes
& ATTR_CMN_PAROBJID
) {
487 HFSCatalogNodeID parentID
;
490 parentID
= key
->hfsPlus
.parentID
;
492 parentID
= key
->hfs
.parentID
;
494 matched
= CompareRange( parentID
, searchInfo1
->parentDirID
, searchInfo2
->parentDirID
);
495 if (matched
== false) goto TestDone
;
499 /* Finder Info & Extended Finder Info where extFinderInfo is last 32 bytes */
500 if ( searchAttributes
& ATTR_CMN_FNDRINFO
) {
502 thisValue
= (UInt32
*) &cnp
->cnd_finderInfo
;
505 * Note: ioFlFndrInfo and ioDrUsrWds have the same offset in search info, so
506 * no need to test the object type here.
508 matched
= CompareMasked( thisValue
, (UInt32
*) &searchInfo1
->finderInfo
,
509 (UInt32
*) &searchInfo2
->finderInfo
, 8 ); /* 8 * UInt32 */
510 if (matched
== false) goto TestDone
;
515 if ( searchAttributes
& ATTR_CMN_CRTIME
) {
516 matched
= CompareRange(to_bsd_time(cnp
->cnd_createDate
),
517 searchInfo1
->creationDate
.tv_sec
, searchInfo2
->creationDate
.tv_sec
);
518 if (matched
== false) goto TestDone
;
523 if ( searchAttributes
& ATTR_CMN_MODTIME
) {
524 matched
= CompareRange(to_bsd_time(cnp
->cnd_contentModDate
),
525 searchInfo1
->modificationDate
.tv_sec
, searchInfo2
->modificationDate
.tv_sec
);
526 if (matched
== false) goto TestDone
;
531 if ( searchAttributes
& ATTR_CMN_CHGTIME
) {
532 matched
= CompareRange(to_bsd_time(cnp
->cnd_attributeModDate
),
533 searchInfo1
->changeDate
.tv_sec
, searchInfo2
->changeDate
.tv_sec
);
534 if (matched
== false) goto TestDone
;
539 if ( searchAttributes
& ATTR_CMN_BKUPTIME
) {
540 matched
= CompareRange(to_bsd_time(cnp
->cnd_backupDate
),
541 searchInfo1
->lastBackupDate
.tv_sec
, searchInfo2
->lastBackupDate
.tv_sec
);
542 if (matched
== false) goto TestDone
;
547 if ( searchAttributes
& ATTR_CMN_OWNERID
) {
548 matched
= CompareRange( cnp
->cnd_ownerID
, searchInfo1
->uid
, searchInfo2
->uid
);
549 if (matched
== false) goto TestDone
;
554 if ( searchAttributes
& ATTR_CMN_GRPID
) {
555 matched
= CompareRange( cnp
->cnd_groupID
, searchInfo1
->gid
, searchInfo2
->gid
);
556 if (matched
== false) goto TestDone
;
561 if ( searchAttributes
& ATTR_CMN_ACCESSMASK
) {
562 matched
= CompareRange( (u_long
)cnp
->cnd_mode
,
563 (u_long
)searchInfo1
->mask
, (u_long
)searchInfo2
->mask
);
564 if (matched
== false) goto TestDone
;
570 /* If we got here w/o matching any, then set to false */
576 * Finally, determine whether we need to negate the sense of the match
577 * (i.e. find all objects that DON'T match).
579 if ( searchBits
& SRCHFS_NEGATEPARAMS
)
587 * Adds another record to the packed array for output
590 InsertMatch( struct vnode
*root_vp
, struct uio
*a_uio
, CatalogNodeData
*cnp
,
591 CatalogKey
*key
, struct attrlist
*returnAttrList
, void *attributesBuffer
,
592 void *variableBuffer
, u_long bufferSize
, u_long
* nummatches
)
595 void *rovingAttributesBuffer
;
596 void *rovingVariableBuffer
;
597 struct hfsCatalogInfo catalogInfo
;
598 u_long packedBufferSize
;
599 ExtendedVCB
*vcb
= VTOVCB(root_vp
);
600 Boolean isHFSPlus
= vcb
->vcbSigWord
== kHFSPlusSigWord
;
601 u_long privateDir
= VTOHFS(root_vp
)->hfs_private_metadata_dir
;
603 rovingAttributesBuffer
= (char*)attributesBuffer
+ sizeof(u_long
); /* Reserve space for length field */
604 rovingVariableBuffer
= variableBuffer
;
606 INIT_CATALOGDATA(&catalogInfo
.nodeData
, 0);
607 catalogInfo
.nodeData
.cnd_iNodeNumCopy
= 0;
609 /* The packing call below expects a struct hfsCatalogInfo */
610 bcopy(cnp
, &catalogInfo
.nodeData
, (cnp
->cnd_type
== kCatalogFileNode
) ?
611 sizeof(HFSPlusCatalogFile
) : sizeof(HFSPlusCatalogFolder
));
613 catalogInfo
.nodeData
.cnm_parID
= isHFSPlus
? key
->hfsPlus
.parentID
: key
->hfs
.parentID
;
615 /* hide open files that have been deleted */
616 if ((privateDir
!= 0) && (catalogInfo
.nodeData
.cnm_parID
== privateDir
))
619 /* hide our private meta data directory */
620 if ((privateDir
!= 0) && (catalogInfo
.nodeData
.cnd_nodeID
== privateDir
))
623 if ( returnAttrList
->commonattr
& ATTR_CMN_NAME
) {
626 catalogInfo
.nodeData
.cnm_nameptr
= catalogInfo
.nodeData
.cnm_namespace
;
628 /* Return result in UTF-8 */
630 err
= utf8_encodestr(key
->hfsPlus
.nodeName
.unicode
,
631 key
->hfsPlus
.nodeName
.length
* sizeof(UniChar
),
632 catalogInfo
.nodeData
.cnm_namespace
,
634 MAXHFSVNODELEN
+ 1, ':', 0);
635 if (err
== ENAMETOOLONG
) {
636 utf8len
= utf8_encodelen(key
->hfsPlus
.nodeName
.unicode
,
637 key
->hfsPlus
.nodeName
.length
* sizeof(UniChar
), ':', 0);
638 MALLOC(catalogInfo
.nodeData
.cnm_nameptr
, char *, utf8len
+1, M_TEMP
, M_WAITOK
);
639 catalogInfo
.nodeData
.cnm_flags
|= kCatNameIsAllocated
;
640 err
= utf8_encodestr(key
->hfsPlus
.nodeName
.unicode
,
641 key
->hfsPlus
.nodeName
.length
* sizeof(UniChar
),
642 catalogInfo
.nodeData
.cnm_nameptr
,
644 utf8len
+ 1, ':', 0);
647 err
= hfs_to_utf8(vcb
,
650 (ByteCount
*) &utf8len
,
651 catalogInfo
.nodeData
.cnm_namespace
);
652 if (err
== ENAMETOOLONG
) {
653 MALLOC(catalogInfo
.nodeData
.cnm_nameptr
, char *, utf8len
+1, M_TEMP
, M_WAITOK
);
654 catalogInfo
.nodeData
.cnm_flags
|= kCatNameIsAllocated
;
655 err
= hfs_to_utf8(vcb
,
658 (ByteCount
*) &utf8len
,
659 catalogInfo
.nodeData
.cnm_nameptr
);
662 * When an HFS name cannot be encoded with the current
663 * volume encoding we use MacRoman as a fallback.
665 err
= mac_roman_to_utf8(key
->hfs
.nodeName
, MAXHFSVNODELEN
+ 1,
666 (ByteCount
*) &utf8len
,
667 catalogInfo
.nodeData
.cnm_namespace
);
670 catalogInfo
.nodeData
.cnm_length
= utf8len
;
671 if (err
&& (catalogInfo
.nodeData
.cnm_flags
& kCatNameIsAllocated
))
673 DisposePtr(catalogInfo
.nodeData
.cnm_nameptr
);
674 catalogInfo
.nodeData
.cnm_flags
&= ~kCatNameIsAllocated
;
675 catalogInfo
.nodeData
.cnm_nameptr
= catalogInfo
.nodeData
.cnm_namespace
;
676 catalogInfo
.nodeData
.cnm_namespace
[0] = 0;
680 PackCatalogInfoAttributeBlock( returnAttrList
,root_vp
, &catalogInfo
, &rovingAttributesBuffer
, &rovingVariableBuffer
);
682 CLEAN_CATALOGDATA(&catalogInfo
.nodeData
);
684 packedBufferSize
= (char*)rovingVariableBuffer
- (char*)attributesBuffer
;
686 if ( packedBufferSize
> a_uio
->uio_resid
)
687 return( errSearchBufferFull
);
691 *((u_long
*)attributesBuffer
) = packedBufferSize
; /* Store length of fixed + var block */
693 err
= uiomove( (caddr_t
)attributesBuffer
, packedBufferSize
, a_uio
); /* XXX should be packedBufferSize */
700 UnpackSearchAttributeBlock( struct vnode
*vp
, struct attrlist
*alist
, searchinfospec_t
*searchInfo
, void *attributeBuffer
)
705 DBG_ASSERT(searchInfo
!= NULL
);
707 bufferSize
= *((u_long
*)attributeBuffer
);
709 return (EINVAL
); /* XXX -DJB is a buffer size of zero ever valid for searchfs? */
711 ++((u_long
*)attributeBuffer
); /* advance past the size */
714 * UnPack common attributes
716 a
= alist
->commonattr
;
718 if ( a
& ATTR_CMN_NAME
) {
719 char *s
= (char*) attributeBuffer
+ ((attrreference_t
*) attributeBuffer
)->attr_dataoffset
;
720 size_t len
= ((attrreference_t
*) attributeBuffer
)->attr_length
;
722 if (len
> sizeof(searchInfo
->name
))
725 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
727 /* Convert name to Unicode to match HFS Plus B-Tree names */
730 if (utf8_decodestr(s
, len
-1, (UniChar
*)searchInfo
->name
, &ucslen
,
731 sizeof(searchInfo
->name
), ':', UTF_DECOMPOSED
))
734 searchInfo
->nameLength
= ucslen
/ sizeof(UniChar
);
736 searchInfo
->nameLength
= 0;
738 ++((attrreference_t
*)attributeBuffer
);
741 /* Convert name to pascal string to match HFS B-Tree names */
744 if (utf8_to_hfs(VTOVCB(vp
), len
-1, s
, (u_char
*)searchInfo
->name
) != 0)
747 searchInfo
->nameLength
= searchInfo
->name
[0];
749 searchInfo
->name
[0] = searchInfo
->nameLength
= 0;
751 ++((attrreference_t
*)attributeBuffer
);
754 if ( a
& ATTR_CMN_OBJID
) {
755 searchInfo
->nodeID
= ((fsobj_id_t
*) attributeBuffer
)->fid_objno
; /* ignore fid_generation */
756 ++((fsobj_id_t
*)attributeBuffer
);
758 if ( a
& ATTR_CMN_PAROBJID
) {
759 searchInfo
->parentDirID
= ((fsobj_id_t
*) attributeBuffer
)->fid_objno
; /* ignore fid_generation */
760 ++((fsobj_id_t
*)attributeBuffer
);
762 if ( a
& ATTR_CMN_CRTIME
) {
763 searchInfo
->creationDate
= *((struct timespec
*)attributeBuffer
);
764 ++((struct timespec
*)attributeBuffer
);
766 if ( a
& ATTR_CMN_MODTIME
) {
767 searchInfo
->modificationDate
= *((struct timespec
*)attributeBuffer
);
768 ++((struct timespec
*)attributeBuffer
);
770 if ( a
& ATTR_CMN_CHGTIME
) {
771 searchInfo
->changeDate
= *((struct timespec
*)attributeBuffer
);
772 ++((struct timespec
*)attributeBuffer
);
774 if ( a
& ATTR_CMN_BKUPTIME
) {
775 searchInfo
->lastBackupDate
= *((struct timespec
*)attributeBuffer
);
776 ++((struct timespec
*)attributeBuffer
);
778 if ( a
& ATTR_CMN_FNDRINFO
) {
779 bcopy( attributeBuffer
, searchInfo
->finderInfo
, sizeof(u_long
) * 8 );
780 (u_long
*)attributeBuffer
+= 8;
782 if ( a
& ATTR_CMN_BKUPTIME
) {
783 searchInfo
->lastBackupDate
= *((struct timespec
*)attributeBuffer
);
784 ++((struct timespec
*)attributeBuffer
);
786 if ( a
& ATTR_CMN_OWNERID
) {
787 searchInfo
->uid
= *((uid_t
*)attributeBuffer
);
788 ++((uid_t
*)attributeBuffer
);
790 if ( a
& ATTR_CMN_GRPID
) {
791 searchInfo
->gid
= *((gid_t
*)attributeBuffer
);
792 ++((gid_t
*)attributeBuffer
);
794 if ( a
& ATTR_CMN_ACCESSMASK
) {
795 searchInfo
->mask
= *((mode_t
*)attributeBuffer
);
796 ++((mode_t
*)attributeBuffer
);
802 if ( a
& ATTR_DIR_ENTRYCOUNT
) {
803 searchInfo
->d
.numFiles
= *((u_long
*)attributeBuffer
);
804 ++((u_long
*)attributeBuffer
);
810 if ( a
& ATTR_FILE_DATALENGTH
) {
811 searchInfo
->f
.dataLogicalLength
= *((off_t
*)attributeBuffer
);
812 ++((off_t
*)attributeBuffer
);
814 if ( a
& ATTR_FILE_DATAALLOCSIZE
) {
815 searchInfo
->f
.dataPhysicalLength
= *((off_t
*)attributeBuffer
);
816 ++((off_t
*)attributeBuffer
);
818 if ( a
& ATTR_FILE_RSRCLENGTH
) {
819 searchInfo
->f
.resourceLogicalLength
= *((off_t
*)attributeBuffer
);
820 ++((off_t
*)attributeBuffer
);
822 if ( a
& ATTR_FILE_RSRCALLOCSIZE
) {
823 searchInfo
->f
.resourcePhysicalLength
= *((off_t
*)attributeBuffer
);
824 ++((off_t
*)attributeBuffer
);