2 * Copyright (c) 2000-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@
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"
50 #include "hfscommon/headers/BTreesPrivate.h"
51 #include "hfscommon/headers/BTreeScanner.h"
54 static int UnpackSearchAttributeBlock(struct vnode
*vp
, struct attrlist
*alist
, searchinfospec_t
*searchInfo
, void *attributeBuffer
);
56 Boolean
CheckCriteria(ExtendedVCB
*vcb
,
57 u_long searchBits
, struct attrlist
*attrList
,
58 CatalogNodeData
*cnp
, CatalogKey
*key
,
59 searchinfospec_t
*searchInfo1
, searchinfospec_t
*searchInfo2
);
61 static int CheckAccess(CatalogNodeData
*cnp
, CatalogKey
*key
, struct proc
*p
);
63 static int InsertMatch(struct vnode
*vp
, struct uio
*a_uio
, CatalogNodeData
*cnp
,
64 CatalogKey
*key
, struct attrlist
*returnAttrList
,
65 void *attributesBuffer
, void *variableBuffer
,
66 u_long bufferSize
, u_long
* nummatches
);
68 static Boolean
CompareRange(u_long val
, u_long low
, u_long high
);
69 static Boolean
CompareWideRange(u_int64_t val
, u_int64_t low
, u_int64_t high
);
71 static Boolean
CompareRange( u_long val
, u_long low
, u_long high
)
73 return( (val
>= low
) && (val
<= high
) );
76 static Boolean
CompareWideRange( u_int64_t val
, u_int64_t low
, u_int64_t high
)
78 return( (val
>= low
) && (val
<= high
) );
80 //#define CompareRange(val, low, high) ((val >= low) && (val <= high))
84 /************************************************************************/
85 /* Entry for searchfs() */
86 /************************************************************************/
88 #define errSearchBufferFull 101 /* Internal search errors */
97 IN struct ucred *cred;
104 struct vop_searchfs_args
*ap
; /*
105 struct vnodeop_desc *a_desc;
107 void *a_searchparams1;
108 void *a_searchparams2;
109 struct attrlist *a_searchattrs;
111 struct timeval *a_timelimit;
112 struct attrlist *a_returnattrs;
113 u_long *a_nummatches;
117 struct searchstate *a_searchstate;
121 searchinfospec_t searchInfo1
;
122 searchinfospec_t searchInfo2
;
123 void *attributesBuffer
;
124 void *variableBuffer
;
127 u_long fixedBlockSize
;
128 u_long eachReturnBufferSize
;
129 struct proc
*p
= current_proc();
130 CatalogNodeData myCNodeData
;
131 CatalogNodeData
* myCNodeDataPtr
;
132 CatalogKey
* myCurrentKeyPtr
;
133 CatalogRecord
* myCurrentDataPtr
;
134 CatPosition
* myCatPositionPtr
;
135 BTScanState myBTScanState
;
136 Boolean timerExpired
= false;
137 u_long lastNodeNum
= 0XFFFFFFFF;
138 ExtendedVCB
*vcb
= VTOVCB(ap
->a_vp
);
142 /* XXX Parameter check a_searchattrs? */
144 *(ap
->a_nummatches
) = 0;
146 if ( ap
->a_options
& ~SRCHFS_VALIDOPTIONSMASK
)
149 if (ap
->a_uio
->uio_resid
<= 0)
152 isHFSPlus
= (vcb
->vcbSigWord
== kHFSPlusSigWord
);
154 /* UnPack the search boundries, searchInfo1, searchInfo2 */
155 err
= UnpackSearchAttributeBlock( ap
->a_vp
, ap
->a_searchattrs
, &searchInfo1
, ap
->a_searchparams1
);
157 err
= UnpackSearchAttributeBlock( ap
->a_vp
, ap
->a_searchattrs
, &searchInfo2
, ap
->a_searchparams2
);
160 fixedBlockSize
= sizeof(u_long
) + AttributeBlockSize( ap
->a_returnattrs
); /* u_long for length longword */
161 eachReturnBufferSize
= fixedBlockSize
;
163 if ( ap
->a_returnattrs
->commonattr
& ATTR_CMN_NAME
) /* XXX should be more robust! */
164 eachReturnBufferSize
+= kHFSPlusMaxFileNameBytes
+ 1;
166 MALLOC( attributesBuffer
, void *, eachReturnBufferSize
, M_TEMP
, M_WAITOK
);
167 variableBuffer
= (void*)((char*) attributesBuffer
+ fixedBlockSize
);
169 /* Lock catalog b-tree */
170 err
= hfs_metafilelocking( VTOHFS(ap
->a_vp
), kHFSCatalogFileID
, LK_SHARED
, p
);
171 if ( err
!= E_NONE
) {
172 goto ExitThisRoutine
;
175 catalogFCB
= VTOFCB( vcb
->catalogRefNum
);
176 myCurrentKeyPtr
= NULL
;
177 myCurrentDataPtr
= NULL
;
178 myCatPositionPtr
= (CatPosition
*)ap
->a_searchstate
;
180 if (ap
->a_options
& SRCHFS_START
) {
181 /* Starting a new search. */
182 ap
->a_options
&= ~SRCHFS_START
;
183 bzero( (caddr_t
)myCatPositionPtr
, sizeof( *myCatPositionPtr
) );
184 err
= BTScanInitialize(catalogFCB
, 0, 0, 0, kCatSearchBufferSize
, &myBTScanState
);
186 /* Resuming a search. */
187 err
= BTScanInitialize(catalogFCB
, myCatPositionPtr
->nextNode
,
188 myCatPositionPtr
->nextRecord
,
189 myCatPositionPtr
->recordsFound
,
190 kCatSearchBufferSize
,
193 /* Make sure Catalog hasn't changed. */
195 && myCatPositionPtr
->writeCount
!= myBTScanState
.btcb
->writeCount
) {
196 myCatPositionPtr
->writeCount
= myBTScanState
.btcb
->writeCount
;
197 err
= EBUSY
; /* catChangedErr */
202 /* Unlock catalog b-tree */
203 (void) hfs_metafilelocking(VTOHFS(ap
->a_vp
), kHFSCatalogFileID
, LK_RELEASE
, p
);
205 goto ExitThisRoutine
;
208 * Check all the catalog btree records...
209 * return the attributes for matching items
212 struct timeval myCurrentTime
;
213 struct timeval myElapsedTime
;
215 err
= BTScanNextRecord(&myBTScanState
, timerExpired
,
216 (void **)&myCurrentKeyPtr
, (void **)&myCurrentDataPtr
,
222 // HFSPlus vols have CatalogRecords that map exactly to CatalogNodeData so there is no need
224 myCNodeDataPtr
= (CatalogNodeData
*) myCurrentDataPtr
;
226 CopyCatalogNodeData( vcb
, myCurrentDataPtr
, &myCNodeData
);
227 myCNodeDataPtr
= &myCNodeData
;
230 if (CheckCriteria(vcb
, ap
->a_options
, ap
->a_searchattrs
, myCNodeDataPtr
,
231 myCurrentKeyPtr
, &searchInfo1
, &searchInfo2
) &&
232 CheckAccess(myCNodeDataPtr
, myCurrentKeyPtr
, ap
->a_uio
->uio_procp
)) {
234 err
= InsertMatch(ap
->a_vp
, ap
->a_uio
, myCNodeDataPtr
,
235 myCurrentKeyPtr
, ap
->a_returnattrs
,
236 attributesBuffer
, variableBuffer
,
237 eachReturnBufferSize
, ap
->a_nummatches
);
240 * The last match didn't fit so come back
241 * to this record on the next trip.
243 --myBTScanState
.recordsFound
;
244 --myBTScanState
.recordNum
;
247 if (*(ap
->a_nummatches
) >= ap
->a_maxmatches
)
252 * Check our elapsed time and bail if we've hit the max.
253 * The idea here is to throttle the amount of time we
254 * spend in the kernel.
256 myCurrentTime
= time
;
257 timersub(&myCurrentTime
, &myBTScanState
.startTime
, &myElapsedTime
);
258 /* Note: assumes kMaxMicroSecsInKernel is less than 1,000,000 */
259 if (myElapsedTime
.tv_sec
> 0
260 || myElapsedTime
.tv_usec
>= kMaxMicroSecsInKernel
) {
265 /* Update catalog position */
266 myCatPositionPtr
->writeCount
= myBTScanState
.btcb
->writeCount
;
268 BTScanTerminate(&myBTScanState
, &myCatPositionPtr
->nextNode
,
269 &myCatPositionPtr
->nextRecord
,
270 &myCatPositionPtr
->recordsFound
);
272 if ( err
== E_NONE
) {
273 err
= EAGAIN
; /* signal to the user to call searchfs again */
274 } else if ( err
== errSearchBufferFull
) {
275 if ( *(ap
->a_nummatches
) > 0 )
279 } else if ( err
== btNotFound
) {
280 err
= E_NONE
; /* the entire disk has been searched */
281 } else if ( err
== fsBTTimeOutErr
) {
286 FREE( attributesBuffer
, M_TEMP
);
288 return (MacToVFSError(err
));
293 CompareMasked(const UInt32
*thisValue
, const UInt32
*compareData
,
294 const UInt32
*compareMask
, UInt32 count
)
299 matched
= true; /* Assume it will all match */
301 for (i
=0; i
<count
; i
++) {
302 if (((*thisValue
++ ^ *compareData
++) & *compareMask
++) != 0) {
313 ComparePartialUnicodeName (register ConstUniCharArrayPtr str
, register ItemCount s_len
,
314 register ConstUniCharArrayPtr find
, register ItemCount f_len
)
316 if (f_len
== 0 || s_len
== 0)
322 } while (FastUnicodeCompare(str
++, f_len
, find
, f_len
) != 0);
329 ComparePartialPascalName ( register ConstStr31Param str
, register ConstStr31Param find
)
331 register u_char s_len
= str
[0];
332 register u_char f_len
= find
[0];
333 register u_char
*tsp
;
336 if (f_len
== 0 || s_len
== 0)
339 bcopy(str
, tmpstr
, s_len
+ 1);
342 while (s_len
-- >= f_len
) {
345 if (FastRelString(tsp
++, find
) == 0)
354 * Check to see if caller has access rights to this item
357 CheckAccess(CatalogNodeData
*cnp
, CatalogKey
*key
, struct proc
*p
)
363 CheckCriteria( ExtendedVCB
*vcb
, u_long searchBits
,
364 struct attrlist
*attrList
, CatalogNodeData
*cnp
, CatalogKey
*key
,
365 searchinfospec_t
*searchInfo1
, searchinfospec_t
*searchInfo2
)
367 Boolean matched
, atleastone
;
369 attrgroup_t searchAttributes
;
371 isHFSPlus
= (vcb
->vcbSigWord
== kHFSPlusSigWord
);
373 switch (cnp
->cnd_type
) {
374 case kCatalogFolderNode
:
375 if ( (searchBits
& SRCHFS_MATCHDIRS
) == 0 ) { /* If we are NOT searching folders */
381 case kCatalogFileNode
:
382 if ( (searchBits
& SRCHFS_MATCHFILES
) == 0 ) { /* If we are NOT searching files */
388 default: /* Never match a thread record or any other type. */
389 return( false ); /* Not a file or folder record, so can't search it */
392 matched
= true; /* Assume we got a match */
393 atleastone
= false; /* Dont insert unless we match at least one criteria */
395 /* First, attempt to match the name -- either partial or complete */
396 if ( attrList
->commonattr
& ATTR_CMN_NAME
) {
398 /* Check for partial/full HFS Plus name match */
400 if ( searchBits
& SRCHFS_MATCHPARTIALNAMES
) {
401 matched
= ComparePartialUnicodeName(key
->hfsPlus
.nodeName
.unicode
,
402 key
->hfsPlus
.nodeName
.length
,
403 (UniChar
*)searchInfo1
->name
,
404 searchInfo1
->nameLength
);
405 } else /* full HFS Plus name match */ {
406 matched
= (FastUnicodeCompare(key
->hfsPlus
.nodeName
.unicode
,
407 key
->hfsPlus
.nodeName
.length
,
408 (UniChar
*)searchInfo1
->name
,
409 searchInfo1
->nameLength
) == 0);
412 /* Check for partial/full HFS name match */
414 if ( searchBits
& SRCHFS_MATCHPARTIALNAMES
)
415 matched
= ComparePartialPascalName(key
->hfs
.nodeName
, (u_char
*)searchInfo1
->name
);
416 else /* full HFS name match */
417 matched
= (FastRelString(key
->hfs
.nodeName
, (u_char
*)searchInfo1
->name
) == 0);
420 if ( matched
== false || (searchBits
& ~SRCHFS_MATCHPARTIALNAMES
) == 0 )
421 goto TestDone
; /* no match, or nothing more to compare */
426 /* Now that we have a record worth searching, see if it matches the search attributes */
427 if (cnp
->cnd_type
== kCatalogFileNode
) {
428 if ((attrList
->fileattr
& ~ATTR_FILE_VALIDMASK
) != 0) { /* attr we do know about */
432 else if ((attrList
->fileattr
& ATTR_FILE_VALIDMASK
) != 0) {
433 searchAttributes
= attrList
->fileattr
;
435 /* File logical length (data fork) */
436 if ( searchAttributes
& ATTR_FILE_DATALENGTH
) {
437 matched
= CompareWideRange(
438 cnp
->cnd_datafork
.logicalSize
,
439 searchInfo1
->f
.dataLogicalLength
,
440 searchInfo2
->f
.dataLogicalLength
);
441 if (matched
== false) goto TestDone
;
445 /* File physical length (data fork) */
446 if ( searchAttributes
& ATTR_FILE_DATAALLOCSIZE
) {
447 matched
= CompareWideRange(
448 cnp
->cnd_datafork
.totalBlocks
* vcb
->blockSize
,
449 searchInfo1
->f
.dataPhysicalLength
,
450 searchInfo2
->f
.dataPhysicalLength
);
451 if (matched
== false) goto TestDone
;
455 /* File logical length (resource fork) */
456 if ( searchAttributes
& ATTR_FILE_RSRCLENGTH
) {
457 matched
= CompareWideRange(
458 cnp
->cnd_rsrcfork
.logicalSize
,
459 searchInfo1
->f
.resourceLogicalLength
,
460 searchInfo2
->f
.resourceLogicalLength
);
461 if (matched
== false) goto TestDone
;
465 /* File physical length (resource fork) */
466 if ( searchAttributes
& ATTR_FILE_RSRCALLOCSIZE
) {
467 matched
= CompareWideRange(
468 cnp
->cnd_rsrcfork
.totalBlocks
* vcb
->blockSize
,
469 searchInfo1
->f
.resourcePhysicalLength
,
470 searchInfo2
->f
.resourcePhysicalLength
);
471 if (matched
== false) goto TestDone
;
476 atleastone
= true; /* to match SRCHFS_MATCHDIRS */
480 * Check the directory attributes
482 else if (cnp
->cnd_type
== kCatalogFolderNode
) {
483 if ((attrList
->dirattr
& ~ATTR_DIR_VALIDMASK
) != 0) { /* attr we do know about */
487 else if ((attrList
->dirattr
& ATTR_DIR_VALIDMASK
) != 0) {
488 searchAttributes
= attrList
->dirattr
;
490 /* Directory valence */
491 if ( searchAttributes
& ATTR_DIR_ENTRYCOUNT
) {
492 matched
= CompareRange(cnp
->cnd_valence
, searchInfo1
->d
.numFiles
, searchInfo2
->d
.numFiles
);
493 if (matched
== false) goto TestDone
;
498 atleastone
= true; /* to match SRCHFS_MATCHDIRS */
503 * Check the common attributes
505 searchAttributes
= attrList
->commonattr
;
506 if ( (searchAttributes
& ATTR_CMN_VALIDMASK
) != 0 ) {
509 if ( searchAttributes
& ATTR_CMN_OBJID
) {
510 matched
= CompareRange( cnp
->cnd_nodeID
, searchInfo1
->nodeID
, searchInfo2
->nodeID
);
511 if (matched
== false) goto TestDone
;
516 if ( searchAttributes
& ATTR_CMN_PAROBJID
) {
517 HFSCatalogNodeID parentID
;
520 parentID
= key
->hfsPlus
.parentID
;
522 parentID
= key
->hfs
.parentID
;
524 matched
= CompareRange( parentID
, searchInfo1
->parentDirID
, searchInfo2
->parentDirID
);
525 if (matched
== false) goto TestDone
;
529 /* Finder Info & Extended Finder Info where extFinderInfo is last 32 bytes */
530 if ( searchAttributes
& ATTR_CMN_FNDRINFO
) {
532 thisValue
= (UInt32
*) &cnp
->cnd_finderInfo
;
535 * Note: ioFlFndrInfo and ioDrUsrWds have the same offset in search info, so
536 * no need to test the object type here.
538 matched
= CompareMasked( thisValue
, (UInt32
*) &searchInfo1
->finderInfo
,
539 (UInt32
*) &searchInfo2
->finderInfo
, 8 ); /* 8 * UInt32 */
540 if (matched
== false) goto TestDone
;
545 if ( searchAttributes
& ATTR_CMN_CRTIME
) {
546 matched
= CompareRange(to_bsd_time(cnp
->cnd_createDate
),
547 searchInfo1
->creationDate
.tv_sec
, searchInfo2
->creationDate
.tv_sec
);
548 if (matched
== false) goto TestDone
;
553 if ( searchAttributes
& ATTR_CMN_MODTIME
) {
554 matched
= CompareRange(to_bsd_time(cnp
->cnd_contentModDate
),
555 searchInfo1
->modificationDate
.tv_sec
, searchInfo2
->modificationDate
.tv_sec
);
556 if (matched
== false) goto TestDone
;
561 if ( searchAttributes
& ATTR_CMN_CHGTIME
) {
562 matched
= CompareRange(to_bsd_time(cnp
->cnd_attributeModDate
),
563 searchInfo1
->changeDate
.tv_sec
, searchInfo2
->changeDate
.tv_sec
);
564 if (matched
== false) goto TestDone
;
569 if ( searchAttributes
& ATTR_CMN_BKUPTIME
) {
570 matched
= CompareRange(to_bsd_time(cnp
->cnd_backupDate
),
571 searchInfo1
->lastBackupDate
.tv_sec
, searchInfo2
->lastBackupDate
.tv_sec
);
572 if (matched
== false) goto TestDone
;
577 if ( searchAttributes
& ATTR_CMN_OWNERID
) {
578 matched
= CompareRange( cnp
->cnd_ownerID
, searchInfo1
->uid
, searchInfo2
->uid
);
579 if (matched
== false) goto TestDone
;
584 if ( searchAttributes
& ATTR_CMN_GRPID
) {
585 matched
= CompareRange( cnp
->cnd_groupID
, searchInfo1
->gid
, searchInfo2
->gid
);
586 if (matched
== false) goto TestDone
;
591 if ( searchAttributes
& ATTR_CMN_ACCESSMASK
) {
592 matched
= CompareRange( (u_long
)cnp
->cnd_mode
,
593 (u_long
)searchInfo1
->mask
, (u_long
)searchInfo2
->mask
);
594 if (matched
== false) goto TestDone
;
600 /* If we got here w/o matching any, then set to false */
606 * Finally, determine whether we need to negate the sense of the match
607 * (i.e. find all objects that DON'T match).
609 if ( searchBits
& SRCHFS_NEGATEPARAMS
)
617 * Adds another record to the packed array for output
620 InsertMatch( struct vnode
*root_vp
, struct uio
*a_uio
, CatalogNodeData
*cnp
,
621 CatalogKey
*key
, struct attrlist
*returnAttrList
, void *attributesBuffer
,
622 void *variableBuffer
, u_long bufferSize
, u_long
* nummatches
)
625 void *rovingAttributesBuffer
;
626 void *rovingVariableBuffer
;
627 struct hfsCatalogInfo catalogInfo
;
628 u_long packedBufferSize
;
629 ExtendedVCB
*vcb
= VTOVCB(root_vp
);
630 Boolean isHFSPlus
= vcb
->vcbSigWord
== kHFSPlusSigWord
;
631 u_long privateDir
= VTOHFS(root_vp
)->hfs_private_metadata_dir
;
633 rovingAttributesBuffer
= (char*)attributesBuffer
+ sizeof(u_long
); /* Reserve space for length field */
634 rovingVariableBuffer
= variableBuffer
;
636 INIT_CATALOGDATA(&catalogInfo
.nodeData
, 0);
637 catalogInfo
.nodeData
.cnd_iNodeNumCopy
= 0;
639 /* The packing call below expects a struct hfsCatalogInfo */
640 bcopy(cnp
, &catalogInfo
.nodeData
, (cnp
->cnd_type
== kCatalogFileNode
) ?
641 sizeof(HFSPlusCatalogFile
) : sizeof(HFSPlusCatalogFolder
));
643 catalogInfo
.nodeData
.cnm_parID
= isHFSPlus
? key
->hfsPlus
.parentID
: key
->hfs
.parentID
;
645 /* hide open files that have been deleted */
646 if ((privateDir
!= 0) && (catalogInfo
.nodeData
.cnm_parID
== privateDir
))
649 /* hide our private meta data directory */
650 if ((privateDir
!= 0) && (catalogInfo
.nodeData
.cnd_nodeID
== privateDir
))
653 if ( returnAttrList
->commonattr
& ATTR_CMN_NAME
) {
656 catalogInfo
.nodeData
.cnm_nameptr
= catalogInfo
.nodeData
.cnm_namespace
;
658 /* Return result in UTF-8 */
660 err
= utf8_encodestr(key
->hfsPlus
.nodeName
.unicode
,
661 key
->hfsPlus
.nodeName
.length
* sizeof(UniChar
),
662 catalogInfo
.nodeData
.cnm_namespace
,
664 MAXHFSVNODELEN
+ 1, ':', 0);
665 if (err
== ENAMETOOLONG
) {
666 utf8len
= utf8_encodelen(key
->hfsPlus
.nodeName
.unicode
,
667 key
->hfsPlus
.nodeName
.length
* sizeof(UniChar
), ':', 0);
668 MALLOC(catalogInfo
.nodeData
.cnm_nameptr
, char *, utf8len
+1, M_TEMP
, M_WAITOK
);
669 catalogInfo
.nodeData
.cnm_flags
|= kCatNameIsAllocated
;
670 err
= utf8_encodestr(key
->hfsPlus
.nodeName
.unicode
,
671 key
->hfsPlus
.nodeName
.length
* sizeof(UniChar
),
672 catalogInfo
.nodeData
.cnm_nameptr
,
674 utf8len
+ 1, ':', 0);
677 err
= hfs_to_utf8(vcb
,
680 (ByteCount
*) &utf8len
,
681 catalogInfo
.nodeData
.cnm_namespace
);
682 if (err
== ENAMETOOLONG
) {
683 MALLOC(catalogInfo
.nodeData
.cnm_nameptr
, char *, utf8len
+1, M_TEMP
, M_WAITOK
);
684 catalogInfo
.nodeData
.cnm_flags
|= kCatNameIsAllocated
;
685 err
= hfs_to_utf8(vcb
,
688 (ByteCount
*) &utf8len
,
689 catalogInfo
.nodeData
.cnm_nameptr
);
692 * When an HFS name cannot be encoded with the current
693 * volume encoding we use MacRoman as a fallback.
695 err
= mac_roman_to_utf8(key
->hfs
.nodeName
, MAXHFSVNODELEN
+ 1,
696 (ByteCount
*) &utf8len
,
697 catalogInfo
.nodeData
.cnm_namespace
);
700 catalogInfo
.nodeData
.cnm_length
= utf8len
;
701 if (err
&& (catalogInfo
.nodeData
.cnm_flags
& kCatNameIsAllocated
))
703 DisposePtr(catalogInfo
.nodeData
.cnm_nameptr
);
704 catalogInfo
.nodeData
.cnm_flags
&= ~kCatNameIsAllocated
;
705 catalogInfo
.nodeData
.cnm_nameptr
= catalogInfo
.nodeData
.cnm_namespace
;
706 catalogInfo
.nodeData
.cnm_namespace
[0] = 0;
710 PackCatalogInfoAttributeBlock( returnAttrList
,root_vp
, &catalogInfo
, &rovingAttributesBuffer
, &rovingVariableBuffer
);
712 CLEAN_CATALOGDATA(&catalogInfo
.nodeData
);
714 packedBufferSize
= (char*)rovingVariableBuffer
- (char*)attributesBuffer
;
716 if ( packedBufferSize
> a_uio
->uio_resid
)
717 return( errSearchBufferFull
);
721 *((u_long
*)attributesBuffer
) = packedBufferSize
; /* Store length of fixed + var block */
723 err
= uiomove( (caddr_t
)attributesBuffer
, packedBufferSize
, a_uio
); /* XXX should be packedBufferSize */
730 UnpackSearchAttributeBlock( struct vnode
*vp
, struct attrlist
*alist
, searchinfospec_t
*searchInfo
, void *attributeBuffer
)
735 DBG_ASSERT(searchInfo
!= NULL
);
737 bufferSize
= *((u_long
*)attributeBuffer
);
739 return (EINVAL
); /* XXX -DJB is a buffer size of zero ever valid for searchfs? */
741 ++((u_long
*)attributeBuffer
); /* advance past the size */
744 * UnPack common attributes
746 a
= alist
->commonattr
;
748 if ( a
& ATTR_CMN_NAME
) {
749 char *s
= (char*) attributeBuffer
+ ((attrreference_t
*) attributeBuffer
)->attr_dataoffset
;
750 size_t len
= ((attrreference_t
*) attributeBuffer
)->attr_length
;
752 if (len
> sizeof(searchInfo
->name
))
755 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
757 /* Convert name to Unicode to match HFS Plus B-Tree names */
760 if (utf8_decodestr(s
, len
-1, (UniChar
*)searchInfo
->name
, &ucslen
,
761 sizeof(searchInfo
->name
), ':', UTF_DECOMPOSED
))
764 searchInfo
->nameLength
= ucslen
/ sizeof(UniChar
);
766 searchInfo
->nameLength
= 0;
768 ++((attrreference_t
*)attributeBuffer
);
771 /* Convert name to pascal string to match HFS B-Tree names */
774 if (utf8_to_hfs(VTOVCB(vp
), len
-1, s
, (u_char
*)searchInfo
->name
) != 0)
777 searchInfo
->nameLength
= searchInfo
->name
[0];
779 searchInfo
->name
[0] = searchInfo
->nameLength
= 0;
781 ++((attrreference_t
*)attributeBuffer
);
784 if ( a
& ATTR_CMN_OBJID
) {
785 searchInfo
->nodeID
= ((fsobj_id_t
*) attributeBuffer
)->fid_objno
; /* ignore fid_generation */
786 ++((fsobj_id_t
*)attributeBuffer
);
788 if ( a
& ATTR_CMN_PAROBJID
) {
789 searchInfo
->parentDirID
= ((fsobj_id_t
*) attributeBuffer
)->fid_objno
; /* ignore fid_generation */
790 ++((fsobj_id_t
*)attributeBuffer
);
792 if ( a
& ATTR_CMN_CRTIME
) {
793 searchInfo
->creationDate
= *((struct timespec
*)attributeBuffer
);
794 ++((struct timespec
*)attributeBuffer
);
796 if ( a
& ATTR_CMN_MODTIME
) {
797 searchInfo
->modificationDate
= *((struct timespec
*)attributeBuffer
);
798 ++((struct timespec
*)attributeBuffer
);
800 if ( a
& ATTR_CMN_CHGTIME
) {
801 searchInfo
->changeDate
= *((struct timespec
*)attributeBuffer
);
802 ++((struct timespec
*)attributeBuffer
);
804 if ( a
& ATTR_CMN_BKUPTIME
) {
805 searchInfo
->lastBackupDate
= *((struct timespec
*)attributeBuffer
);
806 ++((struct timespec
*)attributeBuffer
);
808 if ( a
& ATTR_CMN_FNDRINFO
) {
809 bcopy( attributeBuffer
, searchInfo
->finderInfo
, sizeof(u_long
) * 8 );
810 (u_long
*)attributeBuffer
+= 8;
812 if ( a
& ATTR_CMN_BKUPTIME
) {
813 searchInfo
->lastBackupDate
= *((struct timespec
*)attributeBuffer
);
814 ++((struct timespec
*)attributeBuffer
);
816 if ( a
& ATTR_CMN_OWNERID
) {
817 searchInfo
->uid
= *((uid_t
*)attributeBuffer
);
818 ++((uid_t
*)attributeBuffer
);
820 if ( a
& ATTR_CMN_GRPID
) {
821 searchInfo
->gid
= *((gid_t
*)attributeBuffer
);
822 ++((gid_t
*)attributeBuffer
);
824 if ( a
& ATTR_CMN_ACCESSMASK
) {
825 searchInfo
->mask
= *((mode_t
*)attributeBuffer
);
826 ++((mode_t
*)attributeBuffer
);
832 if ( a
& ATTR_DIR_ENTRYCOUNT
) {
833 searchInfo
->d
.numFiles
= *((u_long
*)attributeBuffer
);
834 ++((u_long
*)attributeBuffer
);
840 if ( a
& ATTR_FILE_DATALENGTH
) {
841 searchInfo
->f
.dataLogicalLength
= *((off_t
*)attributeBuffer
);
842 ++((off_t
*)attributeBuffer
);
844 if ( a
& ATTR_FILE_DATAALLOCSIZE
) {
845 searchInfo
->f
.dataPhysicalLength
= *((off_t
*)attributeBuffer
);
846 ++((off_t
*)attributeBuffer
);
848 if ( a
& ATTR_FILE_RSRCLENGTH
) {
849 searchInfo
->f
.resourceLogicalLength
= *((off_t
*)attributeBuffer
);
850 ++((off_t
*)attributeBuffer
);
852 if ( a
& ATTR_FILE_RSRCALLOCSIZE
) {
853 searchInfo
->f
.resourcePhysicalLength
= *((off_t
*)attributeBuffer
);
854 ++((off_t
*)attributeBuffer
);