2 * Copyright (c) 1997-2002 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@
25 #include <sys/param.h>
26 #include <sys/systm.h>
27 #include <sys/kernel.h>
32 #include <mach/machine/vm_types.h>
33 #include <sys/vnode.h>
34 #include <sys/malloc.h>
35 #include <sys/signalvar.h>
37 #include <sys/utfconv.h>
41 #include "hfs_catalog.h"
42 #include "hfs_attrlist.h"
43 #include "hfs_endian.h"
45 #include "hfscommon/headers/FileMgrInternal.h"
46 #include "hfscommon/headers/CatalogPrivate.h"
47 #include "hfscommon/headers/HFSUnicodeWrappers.h"
48 #include "hfscommon/headers/BTreesPrivate.h"
49 #include "hfscommon/headers/BTreeScanner.h"
52 /* Search criterea. */
53 struct directoryInfoSpec
60 off_t dataLogicalLength
;
61 off_t dataPhysicalLength
;
62 off_t resourceLogicalLength
;
63 off_t resourcePhysicalLength
;
68 u_char name
[kHFSPlusMaxFileNameBytes
];
70 char attributes
; // see IM:Files 2-100
73 struct timespec creationDate
;
74 struct timespec modificationDate
;
75 struct timespec changeDate
;
76 struct timespec accessDate
;
77 struct timespec lastBackupDate
;
82 struct fileInfoSpec f
;
83 struct directoryInfoSpec d
;
85 typedef struct searchinfospec searchinfospec_t
;
87 static void ResolveHardlink(ExtendedVCB
*vcb
, HFSPlusCatalogFile
*recp
);
90 static int UnpackSearchAttributeBlock(struct vnode
*vp
, struct attrlist
*alist
,
91 searchinfospec_t
*searchInfo
, void *attributeBuffer
);
93 static int CheckCriteria( ExtendedVCB
*vcb
,
95 struct attrlist
*attrList
,
98 searchinfospec_t
*searchInfo1
,
99 searchinfospec_t
*searchInfo2
,
100 Boolean lookForDup
);
102 static int CheckAccess(ExtendedVCB
*vcb
, CatalogKey
*key
, struct proc
*p
);
104 static int InsertMatch(struct vnode
*vp
, struct uio
*a_uio
, CatalogRecord
*rec
,
105 CatalogKey
*key
, struct attrlist
*returnAttrList
,
106 void *attributesBuffer
, void *variableBuffer
,
107 u_long bufferSize
, u_long
* nummatches
);
109 static Boolean
CompareRange(u_long val
, u_long low
, u_long high
);
110 static Boolean
CompareWideRange(u_int64_t val
, u_int64_t low
, u_int64_t high
);
112 static Boolean
CompareRange( u_long val
, u_long low
, u_long high
)
114 return( (val
>= low
) && (val
<= high
) );
117 static Boolean
CompareWideRange( u_int64_t val
, u_int64_t low
, u_int64_t high
)
119 return( (val
>= low
) && (val
<= high
) );
121 //#define CompareRange(val, low, high) ((val >= low) && (val <= high))
123 #if 1 // Installer workaround (2940423)
124 static Boolean
IsTargetName( searchinfospec_t
* searchInfoPtr
, Boolean isHFSPlus
);
125 #endif // Installer workaround
127 extern int cat_convertkey(
128 struct hfsmount
*hfsmp
,
130 CatalogRecord
* recp
,
131 struct cat_desc
*descp
);
133 extern void cat_convertattr(
134 struct hfsmount
*hfsmp
,
135 CatalogRecord
* recp
,
136 struct cat_attr
*attrp
,
137 struct cat_fork
*datafp
,
138 struct cat_fork
*rsrcfp
);
140 extern int resolvelink(struct hfsmount
*hfsmp
, u_long linkref
,
141 struct HFSPlusCatalogFile
*recp
);
143 /************************************************************************/
144 /* Entry for searchfs() */
145 /************************************************************************/
147 #define errSearchBufferFull 101 /* Internal search errors */
156 IN struct ucred *cred;
163 struct vop_searchfs_args
*ap
; /*
164 struct vnodeop_desc *a_desc;
166 void *a_searchparams1;
167 void *a_searchparams2;
168 struct attrlist *a_searchattrs;
170 struct timeval *a_timelimit;
171 struct attrlist *a_returnattrs;
172 u_long *a_nummatches;
176 struct searchstate *a_searchstate;
179 ExtendedVCB
*vcb
= VTOVCB(ap
->a_vp
);
181 searchinfospec_t searchInfo1
;
182 searchinfospec_t searchInfo2
;
183 void *attributesBuffer
;
184 void *variableBuffer
;
185 u_long fixedBlockSize
;
186 u_long eachReturnBufferSize
;
187 struct proc
*p
= current_proc();
190 int timerExpired
= false;
191 int doQuickExit
= false;
192 CatalogKey
* myCurrentKeyPtr
;
193 CatalogRecord
* myCurrentDataPtr
;
194 CatPosition
* myCatPositionPtr
;
195 BTScanState myBTScanState
;
197 /* XXX Parameter check a_searchattrs? */
199 *(ap
->a_nummatches
) = 0;
201 if (ap
->a_options
& ~SRCHFS_VALIDOPTIONSMASK
)
204 if (ap
->a_uio
->uio_resid
<= 0)
207 isHFSPlus
= (vcb
->vcbSigWord
== kHFSPlusSigWord
);
209 /* UnPack the search boundries, searchInfo1, searchInfo2 */
210 err
= UnpackSearchAttributeBlock(ap
->a_vp
, ap
->a_searchattrs
,
211 &searchInfo1
, ap
->a_searchparams1
);
213 err
= UnpackSearchAttributeBlock(ap
->a_vp
, ap
->a_searchattrs
,
214 &searchInfo2
, ap
->a_searchparams2
);
217 fixedBlockSize
= sizeof(u_long
) + hfs_attrblksize(ap
->a_returnattrs
); /* u_long for length longword */
218 eachReturnBufferSize
= fixedBlockSize
;
220 if ( ap
->a_returnattrs
->commonattr
& ATTR_CMN_NAME
) /* XXX should be more robust! */
221 eachReturnBufferSize
+= kHFSPlusMaxFileNameBytes
+ 1;
223 MALLOC( attributesBuffer
, void *, eachReturnBufferSize
, M_TEMP
, M_WAITOK
);
224 variableBuffer
= (void*)((char*) attributesBuffer
+ fixedBlockSize
);
226 /* Lock catalog b-tree */
227 err
= hfs_metafilelocking(VTOHFS(ap
->a_vp
), kHFSCatalogFileID
, LK_SHARED
, p
);
229 goto ExitThisRoutine
;
231 catalogFCB
= GetFileControlBlock(vcb
->catalogRefNum
);
232 myCurrentKeyPtr
= NULL
;
233 myCurrentDataPtr
= NULL
;
234 myCatPositionPtr
= (CatPosition
*)ap
->a_searchstate
;
236 if (ap
->a_options
& SRCHFS_START
) {
237 /* Starting a new search. */
238 /* Make sure the on-disk Catalog file is current */
239 (void) VOP_FSYNC(vcb
->catalogRefNum
, NOCRED
, MNT_WAIT
, p
);
240 ap
->a_options
&= ~SRCHFS_START
;
241 bzero( (caddr_t
)myCatPositionPtr
, sizeof( *myCatPositionPtr
) );
242 err
= BTScanInitialize(catalogFCB
, 0, 0, 0, kCatSearchBufferSize
, &myBTScanState
);
244 #if 1 // Installer workaround (2940423)
245 // hack to get around installer problems when the installer expects search results
246 // to be in key order. At this point the problem appears to be limited to
247 // searches for "Library". The idea here is to go get the "Library" at root
248 // and return it first to the caller then continue the search as normal with
249 // the exception of taking care not to return a duplicate hit (see CheckCriteria)
250 if ( err
== E_NONE
&&
251 (ap
->a_searchattrs
->commonattr
& ATTR_CMN_NAME
) != 0 &&
252 IsTargetName( &searchInfo1
, isHFSPlus
) )
255 BTreeIterator iterator
;
256 FSBufferDescriptor btrec
;
261 bzero( (caddr_t
)&iterator
, sizeof( iterator
) );
262 keyp
= (CatalogKey
*) &iterator
.key
;
263 (void) BuildCatalogKeyUTF8(vcb
, kRootDirID
, "Library", kUndefinedStrLen
, keyp
, NULL
);
265 btrec
.bufferAddress
= &rec
;
267 btrec
.itemSize
= sizeof( rec
);
269 result
= BTSearchRecord( catalogFCB
, &iterator
, &btrec
, &reclen
, &iterator
);
270 if ( result
== E_NONE
) {
271 if (CheckCriteria(vcb
, ap
->a_options
, ap
->a_searchattrs
, &rec
,
272 keyp
, &searchInfo1
, &searchInfo2
, false) &&
273 CheckAccess(vcb
, keyp
, ap
->a_uio
->uio_procp
)) {
275 result
= InsertMatch(ap
->a_vp
, ap
->a_uio
, &rec
,
276 keyp
, ap
->a_returnattrs
,
277 attributesBuffer
, variableBuffer
,
278 eachReturnBufferSize
, ap
->a_nummatches
);
279 if (result
== E_NONE
&& *(ap
->a_nummatches
) >= ap
->a_maxmatches
)
284 #endif // Installer workaround
286 /* Resuming a search. */
287 err
= BTScanInitialize(catalogFCB
, myCatPositionPtr
->nextNode
,
288 myCatPositionPtr
->nextRecord
,
289 myCatPositionPtr
->recordsFound
,
290 kCatSearchBufferSize
,
292 /* Make sure Catalog hasn't changed. */
294 && myCatPositionPtr
->writeCount
!= myBTScanState
.btcb
->writeCount
) {
295 myCatPositionPtr
->writeCount
= myBTScanState
.btcb
->writeCount
;
296 err
= EBUSY
; /* catChangedErr */
300 /* Unlock catalog b-tree */
301 (void) hfs_metafilelocking(VTOHFS(ap
->a_vp
), kHFSCatalogFileID
, LK_RELEASE
, p
);
303 goto ExitThisRoutine
;
304 #if 1 // Installer workaround (2940423)
307 #endif // Installer workaround
310 * Check all the catalog btree records...
311 * return the attributes for matching items
314 struct timeval myCurrentTime
;
315 struct timeval myElapsedTime
;
317 err
= BTScanNextRecord(&myBTScanState
, timerExpired
,
318 (void **)&myCurrentKeyPtr
, (void **)&myCurrentDataPtr
,
323 /* Resolve any hardlinks */
325 ResolveHardlink(vcb
, (HFSPlusCatalogFile
*) myCurrentDataPtr
);
327 if (CheckCriteria( vcb
, ap
->a_options
, ap
->a_searchattrs
, myCurrentDataPtr
,
328 myCurrentKeyPtr
, &searchInfo1
, &searchInfo2
, true )
329 && CheckAccess(vcb
, myCurrentKeyPtr
, ap
->a_uio
->uio_procp
)) {
330 err
= InsertMatch(ap
->a_vp
, ap
->a_uio
, myCurrentDataPtr
,
331 myCurrentKeyPtr
, ap
->a_returnattrs
,
332 attributesBuffer
, variableBuffer
,
333 eachReturnBufferSize
, ap
->a_nummatches
);
336 * The last match didn't fit so come back
337 * to this record on the next trip.
339 --myBTScanState
.recordsFound
;
340 --myBTScanState
.recordNum
;
344 if (*(ap
->a_nummatches
) >= ap
->a_maxmatches
)
349 * Check our elapsed time and bail if we've hit the max.
350 * The idea here is to throttle the amount of time we
351 * spend in the kernel.
353 myCurrentTime
= time
;
354 timersub(&myCurrentTime
, &myBTScanState
.startTime
, &myElapsedTime
);
355 /* Note: assumes kMaxMicroSecsInKernel is less than 1,000,000 */
356 if (myElapsedTime
.tv_sec
> 0
357 || myElapsedTime
.tv_usec
>= kMaxMicroSecsInKernel
) {
363 /* Update catalog position */
364 myCatPositionPtr
->writeCount
= myBTScanState
.btcb
->writeCount
;
366 BTScanTerminate(&myBTScanState
, &myCatPositionPtr
->nextNode
,
367 &myCatPositionPtr
->nextRecord
,
368 &myCatPositionPtr
->recordsFound
);
370 if ( err
== E_NONE
) {
371 err
= EAGAIN
; /* signal to the user to call searchfs again */
372 } else if ( err
== errSearchBufferFull
) {
373 if ( *(ap
->a_nummatches
) > 0 )
377 } else if ( err
== btNotFound
) {
378 err
= E_NONE
; /* the entire disk has been searched */
379 } else if ( err
== fsBTTimeOutErr
) {
384 FREE( attributesBuffer
, M_TEMP
);
386 return (MacToVFSError(err
));
391 ResolveHardlink(ExtendedVCB
*vcb
, HFSPlusCatalogFile
*recp
)
393 if ((recp
->recordType
== kHFSPlusFileRecord
)
394 && (SWAP_BE32(recp
->userInfo
.fdType
) == kHardLinkFileType
)
395 && (SWAP_BE32(recp
->userInfo
.fdCreator
) == kHFSPlusCreator
)
396 && ((to_bsd_time(recp
->createDate
) == vcb
->vcbCrDate
) ||
397 (to_bsd_time(recp
->createDate
) == VCBTOHFS(vcb
)->hfs_metadata_createdate
))) {
398 (void) resolvelink(VCBTOHFS(vcb
), recp
->bsdInfo
.special
.iNodeNum
, recp
);
404 CompareMasked(const UInt32
*thisValue
, const UInt32
*compareData
,
405 const UInt32
*compareMask
, UInt32 count
)
410 matched
= true; /* Assume it will all match */
412 for (i
=0; i
<count
; i
++) {
413 if (((*thisValue
++ ^ *compareData
++) & *compareMask
++) != 0) {
424 ComparePartialUnicodeName (register ConstUniCharArrayPtr str
, register ItemCount s_len
,
425 register ConstUniCharArrayPtr find
, register ItemCount f_len
)
427 if (f_len
== 0 || s_len
== 0)
433 } while (FastUnicodeCompare(str
++, f_len
, find
, f_len
) != 0);
440 ComparePartialPascalName ( register ConstStr31Param str
, register ConstStr31Param find
)
442 register u_char s_len
= str
[0];
443 register u_char f_len
= find
[0];
444 register u_char
*tsp
;
447 if (f_len
== 0 || s_len
== 0)
450 bcopy(str
, tmpstr
, s_len
+ 1);
453 while (s_len
-- >= f_len
) {
456 if (FastRelString(tsp
++, find
) == 0)
465 * Check to see if caller has access rights to this item
469 CheckAccess(ExtendedVCB
*theVCBPtr
, CatalogKey
*theKeyPtr
, struct proc
*theProcPtr
)
474 HFSCatalogNodeID myNodeID
;
475 unsigned long myPerms
;
476 hfsmount_t
* my_hfsmountPtr
;
477 struct cat_desc my_cat_desc
;
478 struct cat_attr my_cat_attr
;
480 myResult
= 0; /* default to "no access" */
481 my_cat_desc
.cd_nameptr
= NULL
;
482 my_cat_desc
.cd_namelen
= 0;
484 if ( theProcPtr
->p_ucred
->cr_uid
== 0 ) {
485 myResult
= 1; /* allow access */
486 goto ExitThisRoutine
; /* root always has access */
489 my_hfsmountPtr
= VCBTOHFS( theVCBPtr
);
490 isHFSPlus
= ( theVCBPtr
->vcbSigWord
== kHFSPlusSigWord
);
492 myNodeID
= theKeyPtr
->hfsPlus
.parentID
;
494 myNodeID
= theKeyPtr
->hfs
.parentID
;
496 while ( myNodeID
>= kRootDirID
) {
497 /* now go get catalog data for this directory */
498 myErr
= hfs_metafilelocking( my_hfsmountPtr
, kHFSCatalogFileID
, LK_SHARED
, theProcPtr
);
500 goto ExitThisRoutine
; /* no access */
502 myErr
= cat_idlookup( my_hfsmountPtr
, myNodeID
, &my_cat_desc
, &my_cat_attr
, NULL
);
503 (void) hfs_metafilelocking( my_hfsmountPtr
, kHFSCatalogFileID
, LK_RELEASE
, theProcPtr
);
505 goto ExitThisRoutine
; /* no access */
507 myNodeID
= my_cat_desc
.cd_parentcnid
; /* move up the hierarchy */
508 myPerms
= DerivePermissionSummary(my_cat_attr
.ca_uid
, my_cat_attr
.ca_gid
,
509 my_cat_attr
.ca_mode
, my_hfsmountPtr
->hfs_mp
,
510 theProcPtr
->p_ucred
, theProcPtr
);
511 cat_releasedesc( &my_cat_desc
);
513 if ( (myPerms
& X_OK
) == 0 )
514 goto ExitThisRoutine
; /* no access */
517 myResult
= 1; /* allow access */
520 cat_releasedesc( &my_cat_desc
);
526 CheckCriteria( ExtendedVCB
*vcb
,
528 struct attrlist
*attrList
,
531 searchinfospec_t
*searchInfo1
,
532 searchinfospec_t
*searchInfo2
,
535 Boolean matched
, atleastone
;
537 attrgroup_t searchAttributes
;
538 struct cat_attr c_attr
= {0};
539 struct cat_fork datafork
;
540 struct cat_fork rsrcfork
;
542 isHFSPlus
= (vcb
->vcbSigWord
== kHFSPlusSigWord
);
544 switch (rec
->recordType
) {
545 case kHFSFolderRecord
:
546 case kHFSPlusFolderRecord
:
547 if ( (searchBits
& SRCHFS_MATCHDIRS
) == 0 ) { /* If we are NOT searching folders */
554 case kHFSPlusFileRecord
:
555 if ( (searchBits
& SRCHFS_MATCHFILES
) == 0 ) { /* If we are NOT searching files */
561 default: /* Never match a thread record or any other type. */
562 return( false ); /* Not a file or folder record, so can't search it */
565 matched
= true; /* Assume we got a match */
566 atleastone
= false; /* Dont insert unless we match at least one criteria */
568 /* First, attempt to match the name -- either partial or complete */
569 if ( attrList
->commonattr
& ATTR_CMN_NAME
) {
571 /* Check for partial/full HFS Plus name match */
573 if ( searchBits
& SRCHFS_MATCHPARTIALNAMES
) {
574 matched
= ComparePartialUnicodeName(key
->hfsPlus
.nodeName
.unicode
,
575 key
->hfsPlus
.nodeName
.length
,
576 (UniChar
*)searchInfo1
->name
,
577 searchInfo1
->nameLength
);
578 } else /* full HFS Plus name match */ {
579 matched
= (FastUnicodeCompare(key
->hfsPlus
.nodeName
.unicode
,
580 key
->hfsPlus
.nodeName
.length
,
581 (UniChar
*)searchInfo1
->name
,
582 searchInfo1
->nameLength
) == 0);
585 /* Check for partial/full HFS name match */
587 if ( searchBits
& SRCHFS_MATCHPARTIALNAMES
)
588 matched
= ComparePartialPascalName(key
->hfs
.nodeName
, (u_char
*)searchInfo1
->name
);
589 else /* full HFS name match */
590 matched
= (FastRelString(key
->hfs
.nodeName
, (u_char
*)searchInfo1
->name
) == 0);
593 #if 1 // Installer workaround (2940423)
595 HFSCatalogNodeID parentID
;
597 parentID
= key
->hfsPlus
.parentID
;
599 parentID
= key
->hfs
.parentID
;
601 if ( matched
&& parentID
== kRootDirID
&&
602 IsTargetName( searchInfo1
, isHFSPlus
) )
605 #endif // Installer workaround
607 if ( matched
== false || (searchBits
& ~SRCHFS_MATCHPARTIALNAMES
) == 0 )
608 goto TestDone
; /* no match, or nothing more to compare */
613 /* Convert catalog record into cat_attr format. */
614 cat_convertattr(VCBTOHFS(vcb
), rec
, &c_attr
, &datafork
, &rsrcfork
);
616 /* Now that we have a record worth searching, see if it matches the search attributes */
617 if (rec
->recordType
== kHFSFileRecord
||
618 rec
->recordType
== kHFSPlusFileRecord
) {
619 if ((attrList
->fileattr
& ~ATTR_FILE_VALIDMASK
) != 0) { /* attr we do know about */
623 else if ((attrList
->fileattr
& ATTR_FILE_VALIDMASK
) != 0) {
624 searchAttributes
= attrList
->fileattr
;
626 /* File logical length (data fork) */
627 if ( searchAttributes
& ATTR_FILE_DATALENGTH
) {
628 matched
= CompareWideRange(
630 searchInfo1
->f
.dataLogicalLength
,
631 searchInfo2
->f
.dataLogicalLength
);
632 if (matched
== false) goto TestDone
;
636 /* File physical length (data fork) */
637 if ( searchAttributes
& ATTR_FILE_DATAALLOCSIZE
) {
638 matched
= CompareWideRange(
639 (u_int64_t
)datafork
.cf_blocks
* (u_int64_t
)vcb
->blockSize
,
640 searchInfo1
->f
.dataPhysicalLength
,
641 searchInfo2
->f
.dataPhysicalLength
);
642 if (matched
== false) goto TestDone
;
646 /* File logical length (resource fork) */
647 if ( searchAttributes
& ATTR_FILE_RSRCLENGTH
) {
648 matched
= CompareWideRange(
650 searchInfo1
->f
.resourceLogicalLength
,
651 searchInfo2
->f
.resourceLogicalLength
);
652 if (matched
== false) goto TestDone
;
656 /* File physical length (resource fork) */
657 if ( searchAttributes
& ATTR_FILE_RSRCALLOCSIZE
) {
658 matched
= CompareWideRange(
659 (u_int64_t
)rsrcfork
.cf_blocks
* (u_int64_t
)vcb
->blockSize
,
660 searchInfo1
->f
.resourcePhysicalLength
,
661 searchInfo2
->f
.resourcePhysicalLength
);
662 if (matched
== false) goto TestDone
;
667 atleastone
= true; /* to match SRCHFS_MATCHFILES */
671 * Check the directory attributes
673 else if (rec
->recordType
== kHFSFolderRecord
||
674 rec
->recordType
== kHFSPlusFolderRecord
) {
675 if ((attrList
->dirattr
& ~ATTR_DIR_VALIDMASK
) != 0) { /* attr we do know about */
679 else if ((attrList
->dirattr
& ATTR_DIR_VALIDMASK
) != 0) {
680 searchAttributes
= attrList
->dirattr
;
682 /* Directory valence */
683 if ( searchAttributes
& ATTR_DIR_ENTRYCOUNT
) {
684 matched
= CompareRange(c_attr
.ca_entries
,
685 searchInfo1
->d
.numFiles
,
686 searchInfo2
->d
.numFiles
);
687 if (matched
== false) goto TestDone
;
692 atleastone
= true; /* to match SRCHFS_MATCHDIRS */
697 * Check the common attributes
699 searchAttributes
= attrList
->commonattr
;
700 if ( (searchAttributes
& ATTR_CMN_VALIDMASK
) != 0 ) {
702 if ( searchAttributes
& ATTR_CMN_OBJID
) {
703 matched
= CompareRange(c_attr
.ca_fileid
,
705 searchInfo2
->nodeID
);
706 if (matched
== false) goto TestDone
;
711 if ( searchAttributes
& ATTR_CMN_PAROBJID
) {
712 HFSCatalogNodeID parentID
;
715 parentID
= key
->hfsPlus
.parentID
;
717 parentID
= key
->hfs
.parentID
;
719 matched
= CompareRange(parentID
, searchInfo1
->parentDirID
,
720 searchInfo2
->parentDirID
);
721 if (matched
== false) goto TestDone
;
725 /* Finder Info & Extended Finder Info where extFinderInfo is last 32 bytes */
726 if ( searchAttributes
& ATTR_CMN_FNDRINFO
) {
728 thisValue
= (UInt32
*) &c_attr
.ca_finderinfo
;
731 * Note: ioFlFndrInfo and ioDrUsrWds have the same offset in search info, so
732 * no need to test the object type here.
734 matched
= CompareMasked(thisValue
,
735 (UInt32
*)&searchInfo1
->finderInfo
,
736 (UInt32
*) &searchInfo2
->finderInfo
, 8);
737 if (matched
== false) goto TestDone
;
742 if ( searchAttributes
& ATTR_CMN_CRTIME
) {
743 matched
= CompareRange(c_attr
.ca_itime
,
744 searchInfo1
->creationDate
.tv_sec
,
745 searchInfo2
->creationDate
.tv_sec
);
746 if (matched
== false) goto TestDone
;
751 if ( searchAttributes
& ATTR_CMN_MODTIME
) {
752 matched
= CompareRange(c_attr
.ca_mtime
,
753 searchInfo1
->modificationDate
.tv_sec
,
754 searchInfo2
->modificationDate
.tv_sec
);
755 if (matched
== false) goto TestDone
;
760 if ( searchAttributes
& ATTR_CMN_CHGTIME
) {
761 matched
= CompareRange(c_attr
.ca_ctime
,
762 searchInfo1
->changeDate
.tv_sec
,
763 searchInfo2
->changeDate
.tv_sec
);
764 if (matched
== false) goto TestDone
;
769 if ( searchAttributes
& ATTR_CMN_ACCTIME
) {
770 matched
= CompareRange(c_attr
.ca_atime
,
771 searchInfo1
->accessDate
.tv_sec
,
772 searchInfo2
->accessDate
.tv_sec
);
773 if (matched
== false) goto TestDone
;
778 if ( searchAttributes
& ATTR_CMN_BKUPTIME
) {
779 matched
= CompareRange(c_attr
.ca_btime
,
780 searchInfo1
->lastBackupDate
.tv_sec
,
781 searchInfo2
->lastBackupDate
.tv_sec
);
782 if (matched
== false) goto TestDone
;
787 if ( searchAttributes
& ATTR_CMN_OWNERID
) {
788 matched
= CompareRange(c_attr
.ca_uid
,
789 searchInfo1
->uid
, searchInfo2
->uid
);
790 if (matched
== false) goto TestDone
;
795 if ( searchAttributes
& ATTR_CMN_GRPID
) {
796 matched
= CompareRange(c_attr
.ca_gid
,
797 searchInfo1
->gid
, searchInfo2
->gid
);
798 if (matched
== false) goto TestDone
;
803 if ( searchAttributes
& ATTR_CMN_ACCESSMASK
) {
804 matched
= CompareRange((u_long
)c_attr
.ca_mode
,
805 (u_long
)searchInfo1
->mask
,
806 (u_long
)searchInfo2
->mask
);
807 if (matched
== false) goto TestDone
;
812 /* If we got here w/o matching any, then set to false */
818 * Finally, determine whether we need to negate the sense of the match
819 * (i.e. find all objects that DON'T match).
821 if ( searchBits
& SRCHFS_NEGATEPARAMS
)
829 * Adds another record to the packed array for output
832 InsertMatch( struct vnode
*root_vp
, struct uio
*a_uio
, CatalogRecord
*rec
,
833 CatalogKey
*key
, struct attrlist
*returnAttrList
, void *attributesBuffer
,
834 void *variableBuffer
, u_long bufferSize
, u_long
* nummatches
)
837 void *rovingAttributesBuffer
;
838 void *rovingVariableBuffer
;
839 u_long packedBufferSize
;
840 ExtendedVCB
*vcb
= VTOVCB(root_vp
);
841 Boolean isHFSPlus
= vcb
->vcbSigWord
== kHFSPlusSigWord
;
842 u_long privateDir
= VTOHFS(root_vp
)->hfs_private_metadata_dir
;
843 struct attrblock attrblk
;
844 struct cat_desc c_desc
= {0};
845 struct cat_attr c_attr
= {0};
846 struct cat_fork datafork
;
847 struct cat_fork rsrcfork
;
849 rovingAttributesBuffer
= (char*)attributesBuffer
+ sizeof(u_long
); /* Reserve space for length field */
850 rovingVariableBuffer
= variableBuffer
;
852 /* Convert catalog record into cat_attr format. */
853 cat_convertattr(VTOHFS(root_vp
), rec
, &c_attr
, &datafork
, &rsrcfork
);
855 /* hide our private meta data directory */
856 if ((privateDir
!= 0) && (c_attr
.ca_fileid
== privateDir
)) {
861 if (returnAttrList
->commonattr
& ATTR_CMN_NAME
) {
862 cat_convertkey(VTOHFS(root_vp
), key
, rec
, &c_desc
);
864 c_desc
.cd_cnid
= c_attr
.ca_fileid
;
866 c_desc
.cd_parentcnid
= key
->hfsPlus
.parentID
;
868 c_desc
.cd_parentcnid
= key
->hfs
.parentID
;
871 /* hide open files that have been deleted */
872 if ((privateDir
!= 0) && (c_desc
.cd_parentcnid
== privateDir
)) {
877 attrblk
.ab_attrlist
= returnAttrList
;
878 attrblk
.ab_attrbufpp
= &rovingAttributesBuffer
;
879 attrblk
.ab_varbufpp
= &rovingVariableBuffer
;
880 attrblk
.ab_flags
= 0;
881 attrblk
.ab_blocksize
= 0;
883 hfs_packattrblk(&attrblk
, VTOHFS(root_vp
), NULL
, &c_desc
, &c_attr
, &datafork
, &rsrcfork
);
885 packedBufferSize
= (char*)rovingVariableBuffer
- (char*)attributesBuffer
;
887 if ( packedBufferSize
> a_uio
->uio_resid
)
888 return( errSearchBufferFull
);
892 *((u_long
*)attributesBuffer
) = packedBufferSize
; /* Store length of fixed + var block */
894 err
= uiomove( (caddr_t
)attributesBuffer
, packedBufferSize
, a_uio
); /* XXX should be packedBufferSize */
896 cat_releasedesc(&c_desc
);
903 UnpackSearchAttributeBlock( struct vnode
*vp
, struct attrlist
*alist
, searchinfospec_t
*searchInfo
, void *attributeBuffer
)
908 DBG_ASSERT(searchInfo
!= NULL
);
910 bufferSize
= *((u_long
*)attributeBuffer
);
912 return (EINVAL
); /* XXX -DJB is a buffer size of zero ever valid for searchfs? */
914 ++((u_long
*)attributeBuffer
); /* advance past the size */
917 * UnPack common attributes
919 a
= alist
->commonattr
;
921 if ( a
& ATTR_CMN_NAME
) {
922 char *s
= (char*) attributeBuffer
+ ((attrreference_t
*) attributeBuffer
)->attr_dataoffset
;
923 size_t len
= ((attrreference_t
*) attributeBuffer
)->attr_length
;
925 if (len
> sizeof(searchInfo
->name
))
928 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
930 /* Convert name to Unicode to match HFS Plus B-Tree names */
933 if (utf8_decodestr(s
, len
-1, (UniChar
*)searchInfo
->name
, &ucslen
,
934 sizeof(searchInfo
->name
), ':', UTF_DECOMPOSED
))
937 searchInfo
->nameLength
= ucslen
/ sizeof(UniChar
);
939 searchInfo
->nameLength
= 0;
941 ++((attrreference_t
*)attributeBuffer
);
944 /* Convert name to pascal string to match HFS B-Tree names */
947 if (utf8_to_hfs(VTOVCB(vp
), len
-1, s
, (u_char
*)searchInfo
->name
) != 0)
950 searchInfo
->nameLength
= searchInfo
->name
[0];
952 searchInfo
->name
[0] = searchInfo
->nameLength
= 0;
954 ++((attrreference_t
*)attributeBuffer
);
957 if ( a
& ATTR_CMN_OBJID
) {
958 searchInfo
->nodeID
= ((fsobj_id_t
*) attributeBuffer
)->fid_objno
; /* ignore fid_generation */
959 ++((fsobj_id_t
*)attributeBuffer
);
961 if ( a
& ATTR_CMN_PAROBJID
) {
962 searchInfo
->parentDirID
= ((fsobj_id_t
*) attributeBuffer
)->fid_objno
; /* ignore fid_generation */
963 ++((fsobj_id_t
*)attributeBuffer
);
965 if ( a
& ATTR_CMN_CRTIME
) {
966 searchInfo
->creationDate
= *((struct timespec
*)attributeBuffer
);
967 ++((struct timespec
*)attributeBuffer
);
969 if ( a
& ATTR_CMN_MODTIME
) {
970 searchInfo
->modificationDate
= *((struct timespec
*)attributeBuffer
);
971 ++((struct timespec
*)attributeBuffer
);
973 if ( a
& ATTR_CMN_CHGTIME
) {
974 searchInfo
->changeDate
= *((struct timespec
*)attributeBuffer
);
975 ++((struct timespec
*)attributeBuffer
);
977 if ( a
& ATTR_CMN_ACCTIME
) {
978 searchInfo
->accessDate
= *((struct timespec
*)attributeBuffer
);
979 ++((struct timespec
*)attributeBuffer
);
981 if ( a
& ATTR_CMN_BKUPTIME
) {
982 searchInfo
->lastBackupDate
= *((struct timespec
*)attributeBuffer
);
983 ++((struct timespec
*)attributeBuffer
);
985 if ( a
& ATTR_CMN_FNDRINFO
) {
986 bcopy( attributeBuffer
, searchInfo
->finderInfo
, sizeof(u_long
) * 8 );
987 (u_long
*)attributeBuffer
+= 8;
989 if ( a
& ATTR_CMN_BKUPTIME
) {
990 searchInfo
->lastBackupDate
= *((struct timespec
*)attributeBuffer
);
991 ++((struct timespec
*)attributeBuffer
);
993 if ( a
& ATTR_CMN_OWNERID
) {
994 searchInfo
->uid
= *((uid_t
*)attributeBuffer
);
995 ++((uid_t
*)attributeBuffer
);
997 if ( a
& ATTR_CMN_GRPID
) {
998 searchInfo
->gid
= *((gid_t
*)attributeBuffer
);
999 ++((gid_t
*)attributeBuffer
);
1001 if ( a
& ATTR_CMN_ACCESSMASK
) {
1002 searchInfo
->mask
= *((mode_t
*)attributeBuffer
);
1003 ++((mode_t
*)attributeBuffer
);
1009 if ( a
& ATTR_DIR_ENTRYCOUNT
) {
1010 searchInfo
->d
.numFiles
= *((u_long
*)attributeBuffer
);
1011 ++((u_long
*)attributeBuffer
);
1015 a
= alist
->fileattr
;
1017 if ( a
& ATTR_FILE_DATALENGTH
) {
1018 searchInfo
->f
.dataLogicalLength
= *((off_t
*)attributeBuffer
);
1019 ++((off_t
*)attributeBuffer
);
1021 if ( a
& ATTR_FILE_DATAALLOCSIZE
) {
1022 searchInfo
->f
.dataPhysicalLength
= *((off_t
*)attributeBuffer
);
1023 ++((off_t
*)attributeBuffer
);
1025 if ( a
& ATTR_FILE_RSRCLENGTH
) {
1026 searchInfo
->f
.resourceLogicalLength
= *((off_t
*)attributeBuffer
);
1027 ++((off_t
*)attributeBuffer
);
1029 if ( a
& ATTR_FILE_RSRCALLOCSIZE
) {
1030 searchInfo
->f
.resourcePhysicalLength
= *((off_t
*)attributeBuffer
);
1031 ++((off_t
*)attributeBuffer
);
1039 #if 1 // Installer workaround (2940423)
1040 /* this routine was added as part of the work around where some installers would fail */
1041 /* because they incorrectly assumed search results were in some kind of order. */
1042 /* This routine is used to indentify the problematic target. At this point we */
1043 /* only know of one. This routine could be modified for more (I hope not). */
1044 static Boolean
IsTargetName( searchinfospec_t
* searchInfoPtr
, Boolean isHFSPlus
)
1046 if ( searchInfoPtr
->name
== NULL
)
1050 HFSUniStr255 myName
= {
1051 7, /* number of unicode characters */
1053 'L','i','b','r','a','r','y'
1056 if ( FastUnicodeCompare( myName
.unicode
, myName
.length
,
1057 (UniChar
*)searchInfoPtr
->name
,
1058 searchInfoPtr
->nameLength
) == 0 ) {
1063 u_char myName
[32] = {
1064 0x07,'L','i','b','r','a','r','y'
1066 if ( FastRelString(myName
, (u_char
*)searchInfoPtr
->name
) == 0 ) {
1072 } /* IsTargetName */
1073 #endif // Installer workaround