]> git.saurik.com Git - apple/xnu.git/blob - bsd/hfs/hfs_search.c
xnu-201.19.3.tar.gz
[apple/xnu.git] / bsd / hfs / hfs_search.c
1 /*
2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /* @(#)hfs_search.c
23 *
24 * (c) 1997-2000 Apple Computer, Inc. All Rights Reserved
25 *
26 *
27 * MODIFICATION HISTORY:
28 * 04-May-1999 Don Brady Split off from hfs_vnodeops.c.
29 */
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
34 #include <sys/file.h>
35 #include <sys/buf.h>
36 #include <sys/proc.h>
37 #include <sys/conf.h>
38 #include <mach/machine/vm_types.h>
39 #include <sys/vnode.h>
40 #include <sys/malloc.h>
41 #include <sys/signalvar.h>
42 #include <sys/attr.h>
43 #include <sys/utfconv.h>
44
45 #include "hfs.h"
46 #include "hfs_dbg.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"
52
53
54 static int UnpackSearchAttributeBlock(struct vnode *vp, struct attrlist *alist, searchinfospec_t *searchInfo, void *attributeBuffer);
55
56 Boolean CheckCriteria(ExtendedVCB *vcb,
57 u_long searchBits, struct attrlist *attrList,
58 CatalogNodeData *cnp, CatalogKey *key,
59 searchinfospec_t *searchInfo1, searchinfospec_t *searchInfo2);
60
61 static int CheckAccess(CatalogNodeData *cnp, CatalogKey *key, struct proc *p);
62
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 );
67
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);
70
71 static Boolean CompareRange( u_long val, u_long low, u_long high )
72 {
73 return( (val >= low) && (val <= high) );
74 }
75
76 static Boolean CompareWideRange( u_int64_t val, u_int64_t low, u_int64_t high )
77 {
78 return( (val >= low) && (val <= high) );
79 }
80 //#define CompareRange(val, low, high) ((val >= low) && (val <= high))
81
82
83
84 /************************************************************************/
85 /* Entry for searchfs() */
86 /************************************************************************/
87
88 #define errSearchBufferFull 101 /* Internal search errors */
89 /*
90 #
91 #% searchfs vp L L L
92 #
93 vop_searchfs {
94 IN struct vnode *vp;
95 IN off_t length;
96 IN int flags;
97 IN struct ucred *cred;
98 IN struct proc *p;
99 };
100 */
101
102 int
103 hfs_search( ap )
104 struct vop_searchfs_args *ap; /*
105 struct vnodeop_desc *a_desc;
106 struct vnode *a_vp;
107 void *a_searchparams1;
108 void *a_searchparams2;
109 struct attrlist *a_searchattrs;
110 u_long a_maxmatches;
111 struct timeval *a_timelimit;
112 struct attrlist *a_returnattrs;
113 u_long *a_nummatches;
114 u_long a_scriptcode;
115 u_long a_options;
116 struct uio *a_uio;
117 struct searchstate *a_searchstate;
118 */
119 {
120 FCB* catalogFCB;
121 searchinfospec_t searchInfo1;
122 searchinfospec_t searchInfo2;
123 void *attributesBuffer;
124 void *variableBuffer;
125 short recordSize;
126 short operation;
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);
139 int err = E_NONE;
140 int isHFSPlus;
141
142 /* XXX Parameter check a_searchattrs? */
143
144 *(ap->a_nummatches) = 0;
145
146 if ( ap->a_options & ~SRCHFS_VALIDOPTIONSMASK )
147 return( EINVAL );
148
149 if (ap->a_uio->uio_resid <= 0)
150 return (EINVAL);
151
152 isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord);
153
154 /* UnPack the search boundries, searchInfo1, searchInfo2 */
155 err = UnpackSearchAttributeBlock( ap->a_vp, ap->a_searchattrs, &searchInfo1, ap->a_searchparams1 );
156 if (err) return err;
157 err = UnpackSearchAttributeBlock( ap->a_vp, ap->a_searchattrs, &searchInfo2, ap->a_searchparams2 );
158 if (err) return err;
159
160 fixedBlockSize = sizeof(u_long) + AttributeBlockSize( ap->a_returnattrs ); /* u_long for length longword */
161 eachReturnBufferSize = fixedBlockSize;
162
163 if ( ap->a_returnattrs->commonattr & ATTR_CMN_NAME ) /* XXX should be more robust! */
164 eachReturnBufferSize += kHFSPlusMaxFileNameBytes + 1;
165
166 MALLOC( attributesBuffer, void *, eachReturnBufferSize, M_TEMP, M_WAITOK );
167 variableBuffer = (void*)((char*) attributesBuffer + fixedBlockSize);
168
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;
173 };
174
175 catalogFCB = VTOFCB( vcb->catalogRefNum );
176 myCurrentKeyPtr = NULL;
177 myCurrentDataPtr = NULL;
178 myCatPositionPtr = (CatPosition *)ap->a_searchstate;
179
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);
185 } else {
186 /* Resuming a search. */
187 err = BTScanInitialize(catalogFCB, myCatPositionPtr->nextNode,
188 myCatPositionPtr->nextRecord,
189 myCatPositionPtr->recordsFound,
190 kCatSearchBufferSize,
191 &myBTScanState);
192 #if 0
193 /* Make sure Catalog hasn't changed. */
194 if (err == 0
195 && myCatPositionPtr->writeCount != myBTScanState.btcb->writeCount) {
196 myCatPositionPtr->writeCount = myBTScanState.btcb->writeCount;
197 err = EBUSY; /* catChangedErr */
198 }
199 #endif
200 }
201
202 /* Unlock catalog b-tree */
203 (void) hfs_metafilelocking(VTOHFS(ap->a_vp), kHFSCatalogFileID, LK_RELEASE, p);
204 if (err)
205 goto ExitThisRoutine;
206
207 /*
208 * Check all the catalog btree records...
209 * return the attributes for matching items
210 */
211 for (;;) {
212 struct timeval myCurrentTime;
213 struct timeval myElapsedTime;
214
215 err = BTScanNextRecord(&myBTScanState, timerExpired,
216 (void **)&myCurrentKeyPtr, (void **)&myCurrentDataPtr,
217 NULL);
218 if (err)
219 break;
220
221 if ( isHFSPlus ) {
222 // HFSPlus vols have CatalogRecords that map exactly to CatalogNodeData so there is no need
223 // to copy.
224 myCNodeDataPtr = (CatalogNodeData *) myCurrentDataPtr;
225 } else {
226 CopyCatalogNodeData( vcb, myCurrentDataPtr, &myCNodeData );
227 myCNodeDataPtr = &myCNodeData;
228 }
229
230 if (CheckCriteria(vcb, ap->a_options, ap->a_searchattrs, myCNodeDataPtr,
231 myCurrentKeyPtr, &searchInfo1, &searchInfo2) &&
232 CheckAccess(myCNodeDataPtr, myCurrentKeyPtr, ap->a_uio->uio_procp)) {
233
234 err = InsertMatch(ap->a_vp, ap->a_uio, myCNodeDataPtr,
235 myCurrentKeyPtr, ap->a_returnattrs,
236 attributesBuffer, variableBuffer,
237 eachReturnBufferSize, ap->a_nummatches);
238 if (err) {
239 /*
240 * The last match didn't fit so come back
241 * to this record on the next trip.
242 */
243 --myBTScanState.recordsFound;
244 --myBTScanState.recordNum;
245 break;
246 }
247 if (*(ap->a_nummatches) >= ap->a_maxmatches)
248 break;
249 }
250
251 /*
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.
255 */
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) {
261 timerExpired = true;
262 }
263 }
264
265 /* Update catalog position */
266 myCatPositionPtr->writeCount = myBTScanState.btcb->writeCount;
267
268 BTScanTerminate(&myBTScanState, &myCatPositionPtr->nextNode,
269 &myCatPositionPtr->nextRecord,
270 &myCatPositionPtr->recordsFound);
271
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 )
276 err = EAGAIN;
277 else
278 err = ENOBUFS;
279 } else if ( err == btNotFound ) {
280 err = E_NONE; /* the entire disk has been searched */
281 } else if ( err == fsBTTimeOutErr ) {
282 err = EAGAIN;
283 }
284
285 ExitThisRoutine:
286 FREE( attributesBuffer, M_TEMP );
287
288 return (MacToVFSError(err));
289 }
290
291
292 static Boolean
293 CompareMasked(const UInt32 *thisValue, const UInt32 *compareData,
294 const UInt32 *compareMask, UInt32 count)
295 {
296 Boolean matched;
297 UInt32 i;
298
299 matched = true; /* Assume it will all match */
300
301 for (i=0; i<count; i++) {
302 if (((*thisValue++ ^ *compareData++) & *compareMask++) != 0) {
303 matched = false;
304 break;
305 }
306 }
307
308 return matched;
309 }
310
311
312 static Boolean
313 ComparePartialUnicodeName (register ConstUniCharArrayPtr str, register ItemCount s_len,
314 register ConstUniCharArrayPtr find, register ItemCount f_len )
315 {
316 if (f_len == 0 || s_len == 0)
317 return FALSE;
318
319 do {
320 if (s_len-- < f_len)
321 return FALSE;
322 } while (FastUnicodeCompare(str++, f_len, find, f_len) != 0);
323
324 return TRUE;
325 }
326
327
328 static Boolean
329 ComparePartialPascalName ( register ConstStr31Param str, register ConstStr31Param find )
330 {
331 register u_char s_len = str[0];
332 register u_char f_len = find[0];
333 register u_char *tsp;
334 Str31 tmpstr;
335
336 if (f_len == 0 || s_len == 0)
337 return FALSE;
338
339 bcopy(str, tmpstr, s_len + 1);
340 tsp = &tmpstr[0];
341
342 while (s_len-- >= f_len) {
343 *tsp = f_len;
344
345 if (FastRelString(tsp++, find) == 0)
346 return TRUE;
347 }
348
349 return FALSE;
350 }
351
352
353 /*
354 * Check to see if caller has access rights to this item
355 */
356 static int
357 CheckAccess(CatalogNodeData *cnp, CatalogKey *key, struct proc *p)
358 {
359 return (1);
360 }
361
362 Boolean
363 CheckCriteria( ExtendedVCB *vcb, u_long searchBits,
364 struct attrlist *attrList, CatalogNodeData *cnp, CatalogKey *key,
365 searchinfospec_t *searchInfo1, searchinfospec_t *searchInfo2 )
366 {
367 Boolean matched, atleastone;
368 Boolean isHFSPlus;
369 attrgroup_t searchAttributes;
370
371 isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord);
372
373 switch (cnp->cnd_type) {
374 case kCatalogFolderNode:
375 if ( (searchBits & SRCHFS_MATCHDIRS) == 0 ) { /* If we are NOT searching folders */
376 matched = false;
377 goto TestDone;
378 }
379 break;
380
381 case kCatalogFileNode:
382 if ( (searchBits & SRCHFS_MATCHFILES) == 0 ) { /* If we are NOT searching files */
383 matched = false;
384 goto TestDone;
385 }
386 break;
387
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 */
390 }
391
392 matched = true; /* Assume we got a match */
393 atleastone = false; /* Dont insert unless we match at least one criteria */
394
395 /* First, attempt to match the name -- either partial or complete */
396 if ( attrList->commonattr & ATTR_CMN_NAME ) {
397 if (isHFSPlus) {
398 /* Check for partial/full HFS Plus name match */
399
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);
410 }
411 } else {
412 /* Check for partial/full HFS name match */
413
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);
418 }
419
420 if ( matched == false || (searchBits & ~SRCHFS_MATCHPARTIALNAMES) == 0 )
421 goto TestDone; /* no match, or nothing more to compare */
422
423 atleastone = true;
424 }
425
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 */
429 matched = false;
430 goto TestDone;
431 }
432 else if ((attrList->fileattr & ATTR_FILE_VALIDMASK) != 0) {
433 searchAttributes = attrList->fileattr;
434
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;
442 atleastone = true;
443 }
444
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;
452 atleastone = true;
453 }
454
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;
462 atleastone = true;
463 }
464
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;
472 atleastone = true;
473 }
474 }
475 else {
476 atleastone = true; /* to match SRCHFS_MATCHDIRS */
477 }
478 }
479 /*
480 * Check the directory attributes
481 */
482 else if (cnp->cnd_type == kCatalogFolderNode) {
483 if ((attrList->dirattr & ~ATTR_DIR_VALIDMASK) != 0) { /* attr we do know about */
484 matched = false;
485 goto TestDone;
486 }
487 else if ((attrList->dirattr & ATTR_DIR_VALIDMASK) != 0) {
488 searchAttributes = attrList->dirattr;
489
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;
494 atleastone = true;
495 }
496 }
497 else {
498 atleastone = true; /* to match SRCHFS_MATCHDIRS */
499 }
500 }
501
502 /*
503 * Check the common attributes
504 */
505 searchAttributes = attrList->commonattr;
506 if ( (searchAttributes & ATTR_CMN_VALIDMASK) != 0 ) {
507
508 /* node ID */
509 if ( searchAttributes & ATTR_CMN_OBJID ) {
510 matched = CompareRange( cnp->cnd_nodeID, searchInfo1->nodeID, searchInfo2->nodeID );
511 if (matched == false) goto TestDone;
512 atleastone = true;
513 }
514
515 /* Parent ID */
516 if ( searchAttributes & ATTR_CMN_PAROBJID ) {
517 HFSCatalogNodeID parentID;
518
519 if (isHFSPlus)
520 parentID = key->hfsPlus.parentID;
521 else
522 parentID = key->hfs.parentID;
523
524 matched = CompareRange( parentID, searchInfo1->parentDirID, searchInfo2->parentDirID );
525 if (matched == false) goto TestDone;
526 atleastone = true;
527 }
528
529 /* Finder Info & Extended Finder Info where extFinderInfo is last 32 bytes */
530 if ( searchAttributes & ATTR_CMN_FNDRINFO ) {
531 UInt32 *thisValue;
532 thisValue = (UInt32 *) &cnp->cnd_finderInfo;
533
534 /*
535 * Note: ioFlFndrInfo and ioDrUsrWds have the same offset in search info, so
536 * no need to test the object type here.
537 */
538 matched = CompareMasked( thisValue, (UInt32 *) &searchInfo1->finderInfo,
539 (UInt32 *) &searchInfo2->finderInfo, 8 ); /* 8 * UInt32 */
540 if (matched == false) goto TestDone;
541 atleastone = true;
542 }
543
544 /* Create date */
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;
549 atleastone = true;
550 }
551
552 /* Mod date */
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;
557 atleastone = true;
558 }
559
560 /* Change Time */
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;
565 atleastone = true;
566 }
567
568 /* Backup date */
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;
573 atleastone = true;
574 }
575
576 /* User ID */
577 if ( searchAttributes & ATTR_CMN_OWNERID ) {
578 matched = CompareRange( cnp->cnd_ownerID, searchInfo1->uid, searchInfo2->uid );
579 if (matched == false) goto TestDone;
580 atleastone = true;
581 }
582
583 /* Group ID */
584 if ( searchAttributes & ATTR_CMN_GRPID ) {
585 matched = CompareRange( cnp->cnd_groupID, searchInfo1->gid, searchInfo2->gid );
586 if (matched == false) goto TestDone;
587 atleastone = true;
588 }
589
590 /* mode */
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;
595 atleastone = true;
596 }
597
598 }
599
600 /* If we got here w/o matching any, then set to false */
601 if (! atleastone)
602 matched = false;
603
604 TestDone:
605 /*
606 * Finally, determine whether we need to negate the sense of the match
607 * (i.e. find all objects that DON'T match).
608 */
609 if ( searchBits & SRCHFS_NEGATEPARAMS )
610 matched = !matched;
611
612 return( matched );
613 }
614
615
616 /*
617 * Adds another record to the packed array for output
618 */
619 static int
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 )
623 {
624 int err;
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;
632
633 rovingAttributesBuffer = (char*)attributesBuffer + sizeof(u_long); /* Reserve space for length field */
634 rovingVariableBuffer = variableBuffer;
635
636 INIT_CATALOGDATA(&catalogInfo.nodeData, 0);
637 catalogInfo.nodeData.cnd_iNodeNumCopy = 0;
638
639 /* The packing call below expects a struct hfsCatalogInfo */
640 bcopy(cnp, &catalogInfo.nodeData, (cnp->cnd_type == kCatalogFileNode) ?
641 sizeof(HFSPlusCatalogFile) : sizeof(HFSPlusCatalogFolder));
642
643 catalogInfo.nodeData.cnm_parID = isHFSPlus ? key->hfsPlus.parentID : key->hfs.parentID;
644
645 /* hide open files that have been deleted */
646 if ((privateDir != 0) && (catalogInfo.nodeData.cnm_parID == privateDir))
647 return (0);
648
649 /* hide our private meta data directory */
650 if ((privateDir != 0) && (catalogInfo.nodeData.cnd_nodeID == privateDir))
651 return (0);
652
653 if ( returnAttrList->commonattr & ATTR_CMN_NAME ) {
654 size_t utf8len = 0;
655
656 catalogInfo.nodeData.cnm_nameptr = catalogInfo.nodeData.cnm_namespace;
657
658 /* Return result in UTF-8 */
659 if ( isHFSPlus ) {
660 err = utf8_encodestr(key->hfsPlus.nodeName.unicode,
661 key->hfsPlus.nodeName.length * sizeof(UniChar),
662 catalogInfo.nodeData.cnm_namespace,
663 &utf8len,
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,
673 &utf8len,
674 utf8len + 1, ':', 0);
675 }
676 } else {
677 err = hfs_to_utf8(vcb,
678 key->hfs.nodeName,
679 MAXHFSVNODELEN + 1,
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,
686 key->hfs.nodeName,
687 utf8len + 1,
688 (ByteCount*) &utf8len,
689 catalogInfo.nodeData.cnm_nameptr);
690 } else if (err) {
691 /*
692 * When an HFS name cannot be encoded with the current
693 * volume encoding we use MacRoman as a fallback.
694 */
695 err = mac_roman_to_utf8(key->hfs.nodeName, MAXHFSVNODELEN + 1,
696 (ByteCount*) &utf8len,
697 catalogInfo.nodeData.cnm_namespace);
698 }
699 }
700 catalogInfo.nodeData.cnm_length = utf8len;
701 if (err && (catalogInfo.nodeData.cnm_flags & kCatNameIsAllocated))
702 {
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;
707 }
708 }
709
710 PackCatalogInfoAttributeBlock( returnAttrList,root_vp, &catalogInfo, &rovingAttributesBuffer, &rovingVariableBuffer );
711
712 CLEAN_CATALOGDATA(&catalogInfo.nodeData);
713
714 packedBufferSize = (char*)rovingVariableBuffer - (char*)attributesBuffer;
715
716 if ( packedBufferSize > a_uio->uio_resid )
717 return( errSearchBufferFull );
718
719 (* nummatches)++;
720
721 *((u_long *)attributesBuffer) = packedBufferSize; /* Store length of fixed + var block */
722
723 err = uiomove( (caddr_t)attributesBuffer, packedBufferSize, a_uio ); /* XXX should be packedBufferSize */
724
725 return( err );
726 }
727
728
729 static int
730 UnpackSearchAttributeBlock( struct vnode *vp, struct attrlist *alist, searchinfospec_t *searchInfo, void *attributeBuffer )
731 {
732 attrgroup_t a;
733 u_long bufferSize;
734
735 DBG_ASSERT(searchInfo != NULL);
736
737 bufferSize = *((u_long *)attributeBuffer);
738 if (bufferSize == 0)
739 return (EINVAL); /* XXX -DJB is a buffer size of zero ever valid for searchfs? */
740
741 ++((u_long *)attributeBuffer); /* advance past the size */
742
743 /*
744 * UnPack common attributes
745 */
746 a = alist->commonattr;
747 if ( a != 0 ) {
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;
751
752 if (len > sizeof(searchInfo->name))
753 return (EINVAL);
754
755 if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) {
756 size_t ucslen;
757 /* Convert name to Unicode to match HFS Plus B-Tree names */
758
759 if (len > 0) {
760 if (utf8_decodestr(s, len-1, (UniChar*)searchInfo->name, &ucslen,
761 sizeof(searchInfo->name), ':', UTF_DECOMPOSED))
762 return (EINVAL);
763
764 searchInfo->nameLength = ucslen / sizeof(UniChar);
765 } else {
766 searchInfo->nameLength = 0;
767 }
768 ++((attrreference_t *)attributeBuffer);
769
770 } else {
771 /* Convert name to pascal string to match HFS B-Tree names */
772
773 if (len > 0) {
774 if (utf8_to_hfs(VTOVCB(vp), len-1, s, (u_char*)searchInfo->name) != 0)
775 return (EINVAL);
776
777 searchInfo->nameLength = searchInfo->name[0];
778 } else {
779 searchInfo->name[0] = searchInfo->nameLength = 0;
780 }
781 ++((attrreference_t *)attributeBuffer);
782 }
783 }
784 if ( a & ATTR_CMN_OBJID ) {
785 searchInfo->nodeID = ((fsobj_id_t *) attributeBuffer)->fid_objno; /* ignore fid_generation */
786 ++((fsobj_id_t *)attributeBuffer);
787 }
788 if ( a & ATTR_CMN_PAROBJID ) {
789 searchInfo->parentDirID = ((fsobj_id_t *) attributeBuffer)->fid_objno; /* ignore fid_generation */
790 ++((fsobj_id_t *)attributeBuffer);
791 }
792 if ( a & ATTR_CMN_CRTIME ) {
793 searchInfo->creationDate = *((struct timespec *)attributeBuffer);
794 ++((struct timespec *)attributeBuffer);
795 }
796 if ( a & ATTR_CMN_MODTIME ) {
797 searchInfo->modificationDate = *((struct timespec *)attributeBuffer);
798 ++((struct timespec *)attributeBuffer);
799 }
800 if ( a & ATTR_CMN_CHGTIME ) {
801 searchInfo->changeDate = *((struct timespec *)attributeBuffer);
802 ++((struct timespec *)attributeBuffer);
803 }
804 if ( a & ATTR_CMN_BKUPTIME ) {
805 searchInfo->lastBackupDate = *((struct timespec *)attributeBuffer);
806 ++((struct timespec *)attributeBuffer);
807 }
808 if ( a & ATTR_CMN_FNDRINFO ) {
809 bcopy( attributeBuffer, searchInfo->finderInfo, sizeof(u_long) * 8 );
810 (u_long *)attributeBuffer += 8;
811 }
812 if ( a & ATTR_CMN_BKUPTIME ) {
813 searchInfo->lastBackupDate = *((struct timespec *)attributeBuffer);
814 ++((struct timespec *)attributeBuffer);
815 }
816 if ( a & ATTR_CMN_OWNERID ) {
817 searchInfo->uid = *((uid_t *)attributeBuffer);
818 ++((uid_t *)attributeBuffer);
819 }
820 if ( a & ATTR_CMN_GRPID ) {
821 searchInfo->gid = *((gid_t *)attributeBuffer);
822 ++((gid_t *)attributeBuffer);
823 }
824 if ( a & ATTR_CMN_ACCESSMASK ) {
825 searchInfo->mask = *((mode_t *)attributeBuffer);
826 ++((mode_t *)attributeBuffer);
827 }
828 }
829
830 a = alist->dirattr;
831 if ( a != 0 ) {
832 if ( a & ATTR_DIR_ENTRYCOUNT ) {
833 searchInfo->d.numFiles = *((u_long *)attributeBuffer);
834 ++((u_long *)attributeBuffer);
835 }
836 }
837
838 a = alist->fileattr;
839 if ( a != 0 ) {
840 if ( a & ATTR_FILE_DATALENGTH ) {
841 searchInfo->f.dataLogicalLength = *((off_t *)attributeBuffer);
842 ++((off_t *)attributeBuffer);
843 }
844 if ( a & ATTR_FILE_DATAALLOCSIZE ) {
845 searchInfo->f.dataPhysicalLength = *((off_t *)attributeBuffer);
846 ++((off_t *)attributeBuffer);
847 }
848 if ( a & ATTR_FILE_RSRCLENGTH ) {
849 searchInfo->f.resourceLogicalLength = *((off_t *)attributeBuffer);
850 ++((off_t *)attributeBuffer);
851 }
852 if ( a & ATTR_FILE_RSRCALLOCSIZE ) {
853 searchInfo->f.resourcePhysicalLength = *((off_t *)attributeBuffer);
854 ++((off_t *)attributeBuffer);
855 }
856 }
857
858 return (0);
859 }
860
861