]> git.saurik.com Git - apple/xnu.git/blob - bsd/hfs/hfs_search.c
xnu-1486.2.11.tar.gz
[apple/xnu.git] / bsd / hfs / hfs_search.c
1 /*
2 * Copyright (c) 1997-2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 *
28 * @(#)hfs_search.c
29 */
30 /*
31 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
32 * support for mandatory and extensible security protections. This notice
33 * is included in support of clause 2.2 (b) of the Apple Public License,
34 * Version 2.0.
35 */
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/file.h>
41 #include <sys/proc.h>
42 #include <sys/conf.h>
43 #include <mach/machine/vm_types.h>
44 #include <sys/vnode.h>
45 #include <sys/malloc.h>
46 #include <sys/signalvar.h>
47 #include <sys/attr.h>
48 #include <sys/utfconv.h>
49 #include <sys/kauth.h>
50 #include <sys/vnode_internal.h>
51
52 #if CONFIG_MACF
53 #include <security/mac_framework.h>
54 #endif
55
56 #include "hfs.h"
57 #include "hfs_dbg.h"
58 #include "hfs_catalog.h"
59 #include "hfs_attrlist.h"
60 #include "hfs_endian.h"
61
62 #include "hfscommon/headers/FileMgrInternal.h"
63 #include "hfscommon/headers/HFSUnicodeWrappers.h"
64 #include "hfscommon/headers/BTreesPrivate.h"
65 #include "hfscommon/headers/BTreeScanner.h"
66 #include "hfscommon/headers/CatalogPrivate.h"
67
68 /* Search criterea. */
69 struct directoryInfoSpec
70 {
71 u_int32_t numFiles;
72 };
73
74 struct fileInfoSpec
75 {
76 off_t dataLogicalLength;
77 off_t dataPhysicalLength;
78 off_t resourceLogicalLength;
79 off_t resourcePhysicalLength;
80 };
81
82 struct searchinfospec
83 {
84 u_char name[kHFSPlusMaxFileNameBytes];
85 u_int32_t nameLength;
86 char attributes; // see IM:Files 2-100
87 u_int32_t nodeID;
88 u_int32_t parentDirID;
89 struct timespec creationDate;
90 struct timespec modificationDate;
91 struct timespec changeDate;
92 struct timespec accessDate;
93 struct timespec lastBackupDate;
94 u_int8_t finderInfo[32];
95 uid_t uid;
96 gid_t gid;
97 mode_t mask;
98 struct fileInfoSpec f;
99 struct directoryInfoSpec d;
100 };
101 typedef struct searchinfospec searchinfospec_t;
102
103 static void ResolveHardlink(struct hfsmount *hfsmp, HFSPlusCatalogFile *recp);
104
105
106 static int UnpackSearchAttributeBlock(struct hfsmount *hfsmp, struct attrlist *alist,
107 searchinfospec_t *searchInfo, void *attributeBuffer, int firstblock);
108
109 static int CheckCriteria( ExtendedVCB *vcb,
110 u_long searchBits,
111 struct attrlist *attrList,
112 CatalogRecord *rec,
113 CatalogKey *key,
114 searchinfospec_t *searchInfo1,
115 searchinfospec_t *searchInfo2 );
116
117 static int CheckAccess(ExtendedVCB *vcb, u_long searchBits, CatalogKey *key, struct vfs_context *ctx);
118
119 static int InsertMatch(struct hfsmount *hfsmp, uio_t a_uio, CatalogRecord *rec,
120 CatalogKey *key, struct attrlist *returnAttrList,
121 void *attributesBuffer, void *variableBuffer,
122 uint32_t * nummatches );
123
124 static Boolean CompareRange(u_long val, u_long low, u_long high);
125 static Boolean CompareWideRange(u_int64_t val, u_int64_t low, u_int64_t high);
126
127 static Boolean CompareRange( u_long val, u_long low, u_long high )
128 {
129 return( (val >= low) && (val <= high) );
130 }
131
132 static Boolean CompareWideRange( u_int64_t val, u_int64_t low, u_int64_t high )
133 {
134 return( (val >= low) && (val <= high) );
135 }
136 //#define CompareRange(val, low, high) ((val >= low) && (val <= high))
137
138
139 /************************************************************************/
140 /* Entry for searchfs() */
141 /************************************************************************/
142
143 #define errSearchBufferFull 101 /* Internal search errors */
144 /*
145 #
146 #% searchfs vp L L L
147 #
148 vnop_searchfs {
149 IN struct vnode *vp;
150 IN off_t length;
151 IN int flags;
152 IN kauth_cred_t cred;
153 IN struct proc *p;
154 };
155 */
156
157 __private_extern__
158 int
159 hfs_vnop_search(ap)
160 struct vnop_searchfs_args *ap; /*
161 struct vnodeop_desc *a_desc;
162 struct vnode *a_vp;
163 void *a_searchparams1;
164 void *a_searchparams2;
165 struct attrlist *a_searchattrs;
166 u_long a_maxmatches;
167 struct timeval *a_timelimit;
168 struct attrlist *a_returnattrs;
169 u_long *a_nummatches;
170 u_long a_scriptcode;
171 u_long a_options;
172 struct uio *a_uio;
173 struct searchstate *a_searchstate;
174 vfs_context_t a_context;
175 */
176 {
177 ExtendedVCB *vcb = VTOVCB(ap->a_vp);
178 struct hfsmount *hfsmp;
179 FCB * catalogFCB;
180 searchinfospec_t searchInfo1;
181 searchinfospec_t searchInfo2;
182 void *attributesBuffer = NULL;
183 void *variableBuffer;
184 u_int32_t fixedBlockSize;
185 u_int32_t eachReturnBufferSize;
186 struct proc *p = current_proc();
187 int err = E_NONE;
188 int isHFSPlus;
189 int timerExpired = false;
190 CatalogKey * myCurrentKeyPtr;
191 CatalogRecord * myCurrentDataPtr;
192 CatPosition * myCatPositionPtr;
193 BTScanState myBTScanState;
194 user_addr_t user_start = 0;
195 user_size_t user_len = 0;
196 int32_t searchTime;
197 int lockflags;
198
199 /* XXX Parameter check a_searchattrs? */
200
201 *(ap->a_nummatches) = 0;
202
203 if (ap->a_options & ~SRCHFS_VALIDOPTIONSMASK)
204 return (EINVAL);
205
206 /*
207 * Reject requests for unsupported attributes.
208 */
209 if ((ap->a_returnattrs->commonattr & ~HFS_ATTR_CMN_VALID) ||
210 (ap->a_returnattrs->volattr != 0) ||
211 (ap->a_returnattrs->dirattr & ~HFS_ATTR_DIR_VALID) ||
212 (ap->a_returnattrs->fileattr & ~HFS_ATTR_FILE_VALID) ||
213 (ap->a_returnattrs->forkattr != 0)) {
214 return (EINVAL);
215 }
216
217 /* SRCHFS_SKIPLINKS requires root access.
218 * This option cannot be used with either
219 * the ATTR_CMN_NAME or ATTR_CMN_PAROBJID
220 * attributes.
221 */
222 if (ap->a_options & SRCHFS_SKIPLINKS) {
223 attrgroup_t attrs;
224
225 attrs = ap->a_searchattrs->commonattr | ap->a_returnattrs->commonattr;
226 if (attrs & (ATTR_CMN_NAME | ATTR_CMN_PAROBJID))
227 return (EINVAL);
228 if ((err = vfs_context_suser(ap->a_context)))
229 return (err);
230 }
231
232 // If both 32-bit and 64-bit parent ids or file ids are given
233 // then return an error.
234
235 attrgroup_t test_attrs=ap->a_searchattrs->commonattr;
236
237 if (((test_attrs & ATTR_CMN_OBJID) && (test_attrs & ATTR_CMN_FILEID)) ||
238 ((test_attrs & ATTR_CMN_PARENTID) && (test_attrs & ATTR_CMN_PAROBJID)))
239 return (EINVAL);
240
241
242 if (uio_resid(ap->a_uio) <= 0)
243 return (EINVAL);
244
245 isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord);
246 hfsmp = VTOHFS(ap->a_vp);
247
248 searchTime = kMaxMicroSecsInKernel;
249 if (ap->a_timelimit->tv_sec == 0 &&
250 ap->a_timelimit->tv_usec > 0 &&
251 ap->a_timelimit->tv_usec < kMaxMicroSecsInKernel) {
252 searchTime = ap->a_timelimit->tv_usec;
253 }
254
255 /* UnPack the search boundries, searchInfo1, searchInfo2 */
256 err = UnpackSearchAttributeBlock(hfsmp, ap->a_searchattrs,
257 &searchInfo1, ap->a_searchparams1, 1);
258 if (err) return err;
259 err = UnpackSearchAttributeBlock(hfsmp, ap->a_searchattrs,
260 &searchInfo2, ap->a_searchparams2, 0);
261 if (err) return err;
262
263 //shadow search bits if 64-bit file/parent ids are used
264 if (ap->a_searchattrs->commonattr & ATTR_CMN_FILEID)
265 ap->a_searchattrs->commonattr |= ATTR_CMN_OBJID;
266 if (ap->a_searchattrs->commonattr & ATTR_CMN_PARENTID)
267 ap->a_searchattrs->commonattr |= ATTR_CMN_PAROBJID;
268
269 fixedBlockSize = sizeof(u_int32_t) + hfs_attrblksize(ap->a_returnattrs); /* u_int32_t for length word */
270
271 eachReturnBufferSize = fixedBlockSize;
272
273 if ( ap->a_returnattrs->commonattr & ATTR_CMN_NAME ) /* XXX should be more robust! */
274 eachReturnBufferSize += kHFSPlusMaxFileNameBytes + 1;
275
276 MALLOC( attributesBuffer, void *, eachReturnBufferSize, M_TEMP, M_WAITOK );
277 if (attributesBuffer == NULL) {
278 err = ENOMEM;
279 goto ExitThisRoutine;
280 }
281 variableBuffer = (void*)((char*) attributesBuffer + fixedBlockSize);
282
283 // XXXdbg - have to lock the user's buffer so we don't fault
284 // while holding the shared catalog file lock. see the comment
285 // in hfs_readdir() for more details.
286 //
287 if (hfsmp->jnl && uio_isuserspace(ap->a_uio)) {
288 user_start = uio_curriovbase(ap->a_uio);
289 user_len = uio_curriovlen(ap->a_uio);
290
291 if ((err = vslock(user_start, user_len)) != 0) {
292 user_start = 0;
293 goto ExitThisRoutine;
294 }
295 }
296
297 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
298
299 catalogFCB = GetFileControlBlock(vcb->catalogRefNum);
300 myCurrentKeyPtr = NULL;
301 myCurrentDataPtr = NULL;
302 myCatPositionPtr = (CatPosition *)ap->a_searchstate;
303
304 if (ap->a_options & SRCHFS_START) {
305 /* Starting a new search. */
306 /* Make sure the on-disk Catalog file is current */
307 (void) hfs_fsync(vcb->catalogRefNum, MNT_WAIT, 0, p);
308 if (hfsmp->jnl) {
309 hfs_systemfile_unlock(hfsmp, lockflags);
310 hfs_journal_flush(hfsmp);
311 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
312 }
313
314 ap->a_options &= ~SRCHFS_START;
315 bzero((caddr_t)myCatPositionPtr, sizeof(*myCatPositionPtr));
316 err = BTScanInitialize(catalogFCB, 0, 0, 0, kCatSearchBufferSize, &myBTScanState);
317 if (err) {
318 goto ExitThisRoutine;
319 }
320 } else {
321 /* Resuming a search. */
322 err = BTScanInitialize(catalogFCB, myCatPositionPtr->nextNode,
323 myCatPositionPtr->nextRecord,
324 myCatPositionPtr->recordsFound,
325 kCatSearchBufferSize,
326 &myBTScanState);
327 /* Make sure Catalog hasn't changed. */
328 if (err == 0
329 && myCatPositionPtr->writeCount != myBTScanState.btcb->writeCount) {
330 myCatPositionPtr->writeCount = myBTScanState.btcb->writeCount;
331 err = EBUSY; /* catChangedErr */
332 }
333 }
334 hfs_systemfile_unlock(hfsmp, lockflags);
335
336 if (err)
337 goto ExitThisRoutine;
338
339 /*
340 * Check all the catalog btree records...
341 * return the attributes for matching items
342 */
343 for (;;) {
344 struct timeval myCurrentTime;
345 struct timeval myElapsedTime;
346
347 err = BTScanNextRecord(&myBTScanState, timerExpired,
348 (void **)&myCurrentKeyPtr, (void **)&myCurrentDataPtr,
349 NULL);
350 if (err)
351 break;
352
353 /* Resolve any hardlinks */
354 if (isHFSPlus && (ap->a_options & SRCHFS_SKIPLINKS) == 0) {
355 ResolveHardlink(vcb, (HFSPlusCatalogFile *)myCurrentDataPtr);
356 }
357 if (CheckCriteria( vcb, ap->a_options, ap->a_searchattrs, myCurrentDataPtr,
358 myCurrentKeyPtr, &searchInfo1, &searchInfo2 )
359 && CheckAccess(vcb, ap->a_options, myCurrentKeyPtr, ap->a_context)) {
360 err = InsertMatch(hfsmp, ap->a_uio, myCurrentDataPtr,
361 myCurrentKeyPtr, ap->a_returnattrs,
362 attributesBuffer, variableBuffer, ap->a_nummatches);
363 if (err) {
364 /*
365 * The last match didn't fit so come back
366 * to this record on the next trip.
367 */
368 --myBTScanState.recordsFound;
369 --myBTScanState.recordNum;
370 break;
371 }
372
373 if (*(ap->a_nummatches) >= ap->a_maxmatches)
374 break;
375 }
376
377 /*
378 * Check our elapsed time and bail if we've hit the max.
379 * The idea here is to throttle the amount of time we
380 * spend in the kernel.
381 */
382 microuptime(&myCurrentTime);
383 timersub(&myCurrentTime, &myBTScanState.startTime, &myElapsedTime);
384 /* Note: assumes kMaxMicroSecsInKernel is less than 1,000,000 */
385 if (myElapsedTime.tv_sec > 0
386 || myElapsedTime.tv_usec >= searchTime) {
387 timerExpired = true;
388 }
389 }
390
391 /* Update catalog position */
392 myCatPositionPtr->writeCount = myBTScanState.btcb->writeCount;
393
394 BTScanTerminate(&myBTScanState, &myCatPositionPtr->nextNode,
395 &myCatPositionPtr->nextRecord,
396 &myCatPositionPtr->recordsFound);
397
398 if ( err == E_NONE ) {
399 err = EAGAIN; /* signal to the user to call searchfs again */
400 } else if ( err == errSearchBufferFull ) {
401 if ( *(ap->a_nummatches) > 0 )
402 err = EAGAIN;
403 else
404 err = ENOBUFS;
405 } else if ( err == btNotFound ) {
406 err = E_NONE; /* the entire disk has been searched */
407 } else if ( err == fsBTTimeOutErr ) {
408 err = EAGAIN;
409 }
410
411 ExitThisRoutine:
412 if (attributesBuffer)
413 FREE(attributesBuffer, M_TEMP);
414
415 if (hfsmp->jnl && user_start) {
416 vsunlock(user_start, user_len, TRUE);
417 }
418
419 return (MacToVFSError(err));
420 }
421
422
423 static void
424 ResolveHardlink(struct hfsmount *hfsmp, HFSPlusCatalogFile *recp)
425 {
426 u_int32_t type, creator;
427 int isdirlink = 0;
428 int isfilelink = 0;
429 time_t filecreatedate;
430
431 if (recp->recordType != kHFSPlusFileRecord) {
432 return;
433 }
434 type = SWAP_BE32(recp->userInfo.fdType);
435 creator = SWAP_BE32(recp->userInfo.fdCreator);
436 filecreatedate = to_bsd_time(recp->createDate);
437
438 if ((type == kHardLinkFileType && creator == kHFSPlusCreator) &&
439 (filecreatedate == (time_t)hfsmp->vcbCrDate ||
440 filecreatedate == (time_t)hfsmp->hfs_metadata_createdate)) {
441 isfilelink = 1;
442 } else if ((type == kHFSAliasType && creator == kHFSAliasCreator) &&
443 (recp->flags & kHFSHasLinkChainMask) &&
444 (filecreatedate == (time_t)hfsmp->vcbCrDate ||
445 filecreatedate == (time_t)hfsmp->hfs_metadata_createdate)) {
446 isdirlink = 1;
447 }
448
449 if (isfilelink || isdirlink) {
450 cnid_t saved_cnid;
451 int lockflags;
452
453 /* Export link's cnid (a unique value) instead of inode's cnid */
454 saved_cnid = recp->fileID;
455 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
456
457 (void) cat_resolvelink(hfsmp, recp->hl_linkReference, isdirlink, recp);
458
459 recp->fileID = saved_cnid;
460 hfs_systemfile_unlock(hfsmp, lockflags);
461 }
462 }
463
464
465 static Boolean
466 CompareMasked(const u_int32_t *thisValue, const u_int32_t *compareData,
467 const u_int32_t *compareMask, u_int32_t count)
468 {
469 Boolean matched;
470 u_int32_t i;
471
472 matched = true; /* Assume it will all match */
473
474 for (i=0; i<count; i++) {
475 if (((*thisValue++ ^ *compareData++) & *compareMask++) != 0) {
476 matched = false;
477 break;
478 }
479 }
480
481 return matched;
482 }
483
484
485 static Boolean
486 ComparePartialUnicodeName (register ConstUniCharArrayPtr str, register ItemCount s_len,
487 register ConstUniCharArrayPtr find, register ItemCount f_len )
488 {
489 if (f_len == 0 || s_len == 0)
490 return FALSE;
491
492 do {
493 if (s_len-- < f_len)
494 return FALSE;
495 } while (FastUnicodeCompare(str++, f_len, find, f_len) != 0);
496
497 return TRUE;
498 }
499
500
501 static Boolean
502 ComparePartialPascalName ( register ConstStr31Param str, register ConstStr31Param find )
503 {
504 register u_char s_len = str[0];
505 register u_char f_len = find[0];
506 register u_char *tsp;
507 Str31 tmpstr;
508
509 if (f_len == 0 || s_len == 0)
510 return FALSE;
511
512 bcopy(str, tmpstr, s_len + 1);
513 tsp = &tmpstr[0];
514
515 while (s_len-- >= f_len) {
516 *tsp = f_len;
517
518 if (FastRelString(tsp++, find) == 0)
519 return TRUE;
520 }
521
522 return FALSE;
523 }
524
525
526 /*
527 * Check to see if caller has access rights to this item
528 */
529
530 static int
531 CheckAccess(ExtendedVCB *theVCBPtr, u_long searchBits, CatalogKey *theKeyPtr, struct vfs_context *ctx)
532 {
533 Boolean isHFSPlus;
534 int myErr;
535 int myResult;
536 HFSCatalogNodeID myNodeID;
537 hfsmount_t * hfsmp;
538 struct FndrDirInfo *finfop;
539 struct vnode * vp = NULL;
540
541 myResult = 0; /* default to "no access" */
542
543 if (!vfs_context_suser(ctx)) {
544 myResult = 1; /* allow access */
545 goto ExitThisRoutine; /* root always has access */
546 }
547
548 hfsmp = VCBTOHFS( theVCBPtr );
549 isHFSPlus = ( theVCBPtr->vcbSigWord == kHFSPlusSigWord );
550 if ( isHFSPlus )
551 myNodeID = theKeyPtr->hfsPlus.parentID;
552 else
553 myNodeID = theKeyPtr->hfs.parentID;
554
555 while ( myNodeID >= kRootDirID ) {
556 cnode_t * cp;
557
558 /* now go get catalog data for this directory */
559 myErr = hfs_vget(hfsmp, myNodeID, &vp, 0);
560 if ( myErr ) {
561 goto ExitThisRoutine; /* no access */
562 }
563
564 cp = VTOC(vp);
565 finfop = (struct FndrDirInfo *)&cp->c_attr.ca_finderinfo[0];
566
567 if ( searchBits & SRCHFS_SKIPPACKAGES ) {
568 if ( (SWAP_BE16(finfop->frFlags) & kHasBundle)
569 || (cp->c_desc.cd_nameptr != NULL
570 && is_package_name((const char *)cp->c_desc.cd_nameptr, cp->c_desc.cd_namelen)) ) {
571 myResult = 0;
572 goto ExitThisRoutine;
573 }
574 }
575
576 if ( searchBits & SRCHFS_SKIPINAPPROPRIATE ) {
577 if ( cp->c_parentcnid == kRootDirID && cp->c_desc.cd_nameptr != NULL &&
578 vn_searchfs_inappropriate_name((const char *)cp->c_desc.cd_nameptr, cp->c_desc.cd_namelen) ) {
579 myResult = 0;
580 goto ExitThisRoutine;
581 }
582 }
583
584 if ( (searchBits & SRCHFS_SKIPINVISIBLE) &&
585 (SWAP_BE16(finfop->frFlags) & kIsInvisible) ) {
586 myResult = 0;
587 goto ExitThisRoutine;
588 }
589
590 myNodeID = cp->c_parentcnid; /* move up the hierarchy */
591 hfs_unlock(VTOC(vp));
592
593 #if CONFIG_MACF
594 if (vp->v_type == VDIR) {
595 myErr = mac_vnode_check_readdir(ctx, vp);
596 } else {
597 myErr = mac_vnode_check_stat(ctx, NOCRED, vp);
598 }
599 if (myErr) {
600 vnode_put(vp);
601 vp = NULL;
602 goto ExitThisRoutine;
603 }
604 #endif /* MAC */
605
606 if (vp->v_type == VDIR) {
607 myErr = vnode_authorize(vp, NULL, (KAUTH_VNODE_SEARCH | KAUTH_VNODE_LIST_DIRECTORY), ctx);
608 } else {
609 myErr = vnode_authorize(vp, NULL, (KAUTH_VNODE_SEARCH), ctx);
610 }
611 vnode_put(vp);
612 vp = NULL;
613 if ( myErr ) {
614 goto ExitThisRoutine; /* no access */
615 }
616 }
617 myResult = 1; /* allow access */
618
619 ExitThisRoutine:
620 if ( vp != NULL ) {
621 hfs_unlock(VTOC(vp));
622 vnode_put(vp);
623 }
624 return ( myResult );
625
626 }
627
628 static int
629 CheckCriteria( ExtendedVCB *vcb,
630 u_long searchBits,
631 struct attrlist *attrList,
632 CatalogRecord *rec,
633 CatalogKey *key,
634 searchinfospec_t *searchInfo1,
635 searchinfospec_t *searchInfo2 )
636 {
637 Boolean matched, atleastone;
638 Boolean isHFSPlus;
639 attrgroup_t searchAttributes;
640 struct cat_attr c_attr;
641 struct cat_fork datafork;
642 struct cat_fork rsrcfork;
643
644 bzero(&c_attr, sizeof(c_attr));
645 isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord);
646
647 switch (rec->recordType) {
648 case kHFSFolderRecord:
649 case kHFSPlusFolderRecord:
650 if ( (searchBits & SRCHFS_MATCHDIRS) == 0 ) { /* If we are NOT searching folders */
651 matched = false;
652 goto TestDone;
653 }
654 break;
655
656 case kHFSFileRecord:
657 if ( (searchBits & SRCHFS_MATCHFILES) == 0 ) { /* If we are NOT searching files */
658 matched = false;
659 goto TestDone;
660 }
661 break;
662
663 case kHFSPlusFileRecord:
664 /* Check if hardlink links should be skipped. */
665 if (searchBits & SRCHFS_SKIPLINKS) {
666 cnid_t parid = key->hfsPlus.parentID;
667 HFSPlusCatalogFile *filep = (HFSPlusCatalogFile *)rec;
668
669 if ((SWAP_BE32(filep->userInfo.fdType) == kHardLinkFileType) &&
670 (SWAP_BE32(filep->userInfo.fdCreator) == kHFSPlusCreator)) {
671 return (false); /* skip over file link records */
672 } else if ((parid == vcb->hfs_private_desc[FILE_HARDLINKS].cd_cnid) &&
673 (filep->bsdInfo.special.linkCount == 0)) {
674 return (false); /* skip over unlinked files */
675 } else if ((SWAP_BE32(filep->userInfo.fdType) == kHFSAliasType) &&
676 (SWAP_BE32(filep->userInfo.fdCreator) == kHFSAliasCreator) &&
677 (filep->flags & kHFSHasLinkChainMask)) {
678 return (false); /* skip over dir link records */
679 }
680 } else if (key->hfsPlus.parentID == vcb->hfs_private_desc[FILE_HARDLINKS].cd_cnid) {
681 return (false); /* skip over private files */
682 } else if (key->hfsPlus.parentID == vcb->hfs_private_desc[DIR_HARDLINKS].cd_cnid) {
683 return (false); /* skip over private files */
684 }
685
686 if ( (searchBits & SRCHFS_MATCHFILES) == 0 ) { /* If we are NOT searching files */
687 matched = false;
688 goto TestDone;
689 }
690 break;
691
692 default: /* Never match a thread record or any other type. */
693 return( false ); /* Not a file or folder record, so can't search it */
694 }
695
696 matched = true; /* Assume we got a match */
697 atleastone = false; /* Dont insert unless we match at least one criteria */
698
699 /* First, attempt to match the name -- either partial or complete */
700 if ( attrList->commonattr & ATTR_CMN_NAME ) {
701 if (isHFSPlus) {
702 /* Check for partial/full HFS Plus name match */
703
704 if ( searchBits & SRCHFS_MATCHPARTIALNAMES ) {
705 matched = ComparePartialUnicodeName(key->hfsPlus.nodeName.unicode,
706 key->hfsPlus.nodeName.length,
707 (UniChar*)searchInfo1->name,
708 searchInfo1->nameLength );
709 } else /* full HFS Plus name match */ {
710 matched = (FastUnicodeCompare(key->hfsPlus.nodeName.unicode,
711 key->hfsPlus.nodeName.length,
712 (UniChar*)searchInfo1->name,
713 searchInfo1->nameLength ) == 0);
714 }
715 } else {
716 /* Check for partial/full HFS name match */
717
718 if ( searchBits & SRCHFS_MATCHPARTIALNAMES )
719 matched = ComparePartialPascalName(key->hfs.nodeName, (u_char*)searchInfo1->name);
720 else /* full HFS name match */
721 matched = (FastRelString(key->hfs.nodeName, (u_char*)searchInfo1->name) == 0);
722 }
723
724 if ( matched == false || (searchBits & ~SRCHFS_MATCHPARTIALNAMES) == 0 )
725 goto TestDone; /* no match, or nothing more to compare */
726
727 atleastone = true;
728 }
729
730 /* Convert catalog record into cat_attr format. */
731 cat_convertattr(VCBTOHFS(vcb), rec, &c_attr, &datafork, &rsrcfork);
732
733 if (searchBits & SRCHFS_SKIPINVISIBLE) {
734 int flags;
735
736 switch (rec->recordType) {
737 case kHFSFolderRecord:
738 case kHFSPlusFolderRecord: {
739 struct FndrDirInfo *finder_info;
740
741 finder_info = (struct FndrDirInfo *)&c_attr.ca_finderinfo[0];
742 flags = SWAP_BE16(finder_info->frFlags);
743 break;
744 }
745
746 case kHFSFileRecord:
747 case kHFSPlusFileRecord: {
748 struct FndrFileInfo *finder_info;
749
750 finder_info = (struct FndrFileInfo *)&c_attr.ca_finderinfo[0];
751 flags = SWAP_BE16(finder_info->fdFlags);
752 break;
753 }
754
755 default: {
756 flags = kIsInvisible;
757 break;
758 }
759 }
760
761 if (flags & kIsInvisible) {
762 matched = false;
763 goto TestDone;
764 }
765 }
766
767
768
769 /* Now that we have a record worth searching, see if it matches the search attributes */
770 if (rec->recordType == kHFSFileRecord ||
771 rec->recordType == kHFSPlusFileRecord) {
772 if ((attrList->fileattr & ~ATTR_FILE_VALIDMASK) != 0) { /* attr we do know about */
773 matched = false;
774 goto TestDone;
775 }
776 else if ((attrList->fileattr & ATTR_FILE_VALIDMASK) != 0) {
777 searchAttributes = attrList->fileattr;
778
779 #if HFS_COMPRESSION
780 if ( c_attr.ca_flags & UF_COMPRESSED ) {
781 /* for compressed files, set the data length to the uncompressed data size */
782 if (( searchAttributes & ATTR_FILE_DATALENGTH ) ||
783 ( searchAttributes & ATTR_FILE_DATAALLOCSIZE ) ) {
784 if ( 0 == hfs_uncompressed_size_of_compressed_file(vcb, NULL, c_attr.ca_fileid, &datafork.cf_size, 1) ) { /* 1 == don't take the cnode lock */
785 datafork.cf_blocks = rsrcfork.cf_blocks;
786 }
787 }
788 /* treat compressed files as if their resource fork is empty */
789 if (( searchAttributes & ATTR_FILE_RSRCLENGTH ) ||
790 ( searchAttributes & ATTR_FILE_RSRCALLOCSIZE ) ) {
791 rsrcfork.cf_size = 0;
792 rsrcfork.cf_blocks = 0;
793 }
794 }
795 #endif /* HFS_COMPRESSION */
796
797 /* File logical length (data fork) */
798 if ( searchAttributes & ATTR_FILE_DATALENGTH ) {
799 matched = CompareWideRange(
800 datafork.cf_size,
801 searchInfo1->f.dataLogicalLength,
802 searchInfo2->f.dataLogicalLength);
803 if (matched == false) goto TestDone;
804 atleastone = true;
805 }
806
807 /* File physical length (data fork) */
808 if ( searchAttributes & ATTR_FILE_DATAALLOCSIZE ) {
809 matched = CompareWideRange(
810 (u_int64_t)datafork.cf_blocks * (u_int64_t)vcb->blockSize,
811 searchInfo1->f.dataPhysicalLength,
812 searchInfo2->f.dataPhysicalLength);
813 if (matched == false) goto TestDone;
814 atleastone = true;
815 }
816
817 /* File logical length (resource fork) */
818 if ( searchAttributes & ATTR_FILE_RSRCLENGTH ) {
819 matched = CompareWideRange(
820 rsrcfork.cf_size,
821 searchInfo1->f.resourceLogicalLength,
822 searchInfo2->f.resourceLogicalLength);
823 if (matched == false) goto TestDone;
824 atleastone = true;
825 }
826
827 /* File physical length (resource fork) */
828 if ( searchAttributes & ATTR_FILE_RSRCALLOCSIZE ) {
829 matched = CompareWideRange(
830 (u_int64_t)rsrcfork.cf_blocks * (u_int64_t)vcb->blockSize,
831 searchInfo1->f.resourcePhysicalLength,
832 searchInfo2->f.resourcePhysicalLength);
833 if (matched == false) goto TestDone;
834 atleastone = true;
835 }
836 }
837 else {
838 atleastone = true; /* to match SRCHFS_MATCHFILES */
839 }
840 }
841 /*
842 * Check the directory attributes
843 */
844 else if (rec->recordType == kHFSFolderRecord ||
845 rec->recordType == kHFSPlusFolderRecord) {
846 if ((attrList->dirattr & ~ATTR_DIR_VALIDMASK) != 0) { /* attr we do know about */
847 matched = false;
848 goto TestDone;
849 }
850 else if ((attrList->dirattr & ATTR_DIR_VALIDMASK) != 0) {
851 searchAttributes = attrList->dirattr;
852
853 /* Directory valence */
854 if ( searchAttributes & ATTR_DIR_ENTRYCOUNT ) {
855 matched = CompareRange(c_attr.ca_entries,
856 searchInfo1->d.numFiles,
857 searchInfo2->d.numFiles );
858 if (matched == false) goto TestDone;
859 atleastone = true;
860 }
861 }
862 else {
863 atleastone = true; /* to match SRCHFS_MATCHDIRS */
864 }
865 }
866
867 /*
868 * Check the common attributes
869 */
870 searchAttributes = attrList->commonattr;
871 if ( (searchAttributes & ATTR_CMN_VALIDMASK) != 0 ) {
872 /* node ID */
873 if ( searchAttributes & ATTR_CMN_OBJID ) {
874 matched = CompareRange(c_attr.ca_fileid,
875 searchInfo1->nodeID,
876 searchInfo2->nodeID );
877 if (matched == false) goto TestDone;
878 atleastone = true;
879 }
880
881 /* Parent ID */
882 if ( searchAttributes & ATTR_CMN_PAROBJID ) {
883 HFSCatalogNodeID parentID;
884
885 if (isHFSPlus)
886 parentID = key->hfsPlus.parentID;
887 else
888 parentID = key->hfs.parentID;
889
890 matched = CompareRange(parentID, searchInfo1->parentDirID,
891 searchInfo2->parentDirID );
892 if (matched == false) goto TestDone;
893 atleastone = true;
894 }
895
896 /* Finder Info & Extended Finder Info where extFinderInfo is last 32 bytes */
897 if ( searchAttributes & ATTR_CMN_FNDRINFO ) {
898 u_int32_t *thisValue;
899 thisValue = (u_int32_t *) &c_attr.ca_finderinfo;
900
901 /*
902 * Note: ioFlFndrInfo and ioDrUsrWds have the same offset in search info, so
903 * no need to test the object type here.
904 */
905 matched = CompareMasked(thisValue,
906 (u_int32_t *)&searchInfo1->finderInfo,
907 (u_int32_t *) &searchInfo2->finderInfo, 8);
908 if (matched == false) goto TestDone;
909 atleastone = true;
910 }
911
912 /* Create date */
913 if ( searchAttributes & ATTR_CMN_CRTIME ) {
914 matched = CompareRange(c_attr.ca_itime,
915 searchInfo1->creationDate.tv_sec,
916 searchInfo2->creationDate.tv_sec);
917 if (matched == false) goto TestDone;
918 atleastone = true;
919 }
920
921 /* Mod date */
922 if ( searchAttributes & ATTR_CMN_MODTIME ) {
923 matched = CompareRange(c_attr.ca_mtime,
924 searchInfo1->modificationDate.tv_sec,
925 searchInfo2->modificationDate.tv_sec);
926 if (matched == false) goto TestDone;
927 atleastone = true;
928 }
929
930 /* Change Time */
931 if ( searchAttributes & ATTR_CMN_CHGTIME ) {
932 matched = CompareRange(c_attr.ca_ctime,
933 searchInfo1->changeDate.tv_sec,
934 searchInfo2->changeDate.tv_sec);
935 if (matched == false) goto TestDone;
936 atleastone = true;
937 }
938
939 /* Access date */
940 if ( searchAttributes & ATTR_CMN_ACCTIME ) {
941 matched = CompareRange(c_attr.ca_atime,
942 searchInfo1->accessDate.tv_sec,
943 searchInfo2->accessDate.tv_sec);
944 if (matched == false) goto TestDone;
945 atleastone = true;
946 }
947
948 /* Backup date */
949 if ( searchAttributes & ATTR_CMN_BKUPTIME ) {
950 matched = CompareRange(c_attr.ca_btime,
951 searchInfo1->lastBackupDate.tv_sec,
952 searchInfo2->lastBackupDate.tv_sec);
953 if (matched == false) goto TestDone;
954 atleastone = true;
955 }
956
957 /* User ID */
958 if ( searchAttributes & ATTR_CMN_OWNERID ) {
959 matched = CompareRange(c_attr.ca_uid,
960 searchInfo1->uid, searchInfo2->uid);
961 if (matched == false) goto TestDone;
962 atleastone = true;
963 }
964
965 /* Group ID */
966 if ( searchAttributes & ATTR_CMN_GRPID ) {
967 matched = CompareRange(c_attr.ca_gid,
968 searchInfo1->gid, searchInfo2->gid);
969 if (matched == false) goto TestDone;
970 atleastone = true;
971 }
972
973 /* mode */
974 if ( searchAttributes & ATTR_CMN_ACCESSMASK ) {
975 matched = CompareRange((u_int32_t)c_attr.ca_mode,
976 (u_int32_t)searchInfo1->mask,
977 (u_int32_t)searchInfo2->mask);
978 if (matched == false) goto TestDone;
979 atleastone = true;
980 }
981 }
982
983 /* If we got here w/o matching any, then set to false */
984 if (! atleastone)
985 matched = false;
986
987 TestDone:
988 /*
989 * Finally, determine whether we need to negate the sense of the match
990 * (i.e. find all objects that DON'T match).
991 */
992 if ( searchBits & SRCHFS_NEGATEPARAMS )
993 matched = !matched;
994
995 return( matched );
996 }
997
998
999 /*
1000 * Adds another record to the packed array for output
1001 */
1002 static int
1003 InsertMatch(struct hfsmount *hfsmp, uio_t a_uio, CatalogRecord *rec,
1004 CatalogKey *key, struct attrlist *returnAttrList,
1005 void *attributesBuffer, void *variableBuffer, uint32_t * nummatches)
1006 {
1007 int err;
1008 void *rovingAttributesBuffer;
1009 void *rovingVariableBuffer;
1010 long packedBufferSize;
1011 struct attrblock attrblk;
1012 struct cat_desc c_desc;
1013 struct cat_attr c_attr;
1014 struct cat_fork datafork;
1015 struct cat_fork rsrcfork;
1016
1017 bzero(&c_desc, sizeof(c_desc));
1018 bzero(&c_attr, sizeof(c_attr));
1019 rovingAttributesBuffer = (char*)attributesBuffer + sizeof(u_int32_t); /* Reserve space for length field */
1020 rovingVariableBuffer = variableBuffer;
1021
1022 /* Convert catalog record into cat_attr format. */
1023 cat_convertattr(hfsmp, rec, &c_attr, &datafork, &rsrcfork);
1024
1025 /* Hide our private meta data directories */
1026 if (c_attr.ca_fileid == hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid ||
1027 c_attr.ca_fileid == hfsmp->hfs_private_desc[DIR_HARDLINKS].cd_cnid) {
1028 err = 0;
1029 goto exit;
1030 }
1031
1032 /* Hide the private journal files */
1033 if (hfsmp->jnl &&
1034 ((c_attr.ca_fileid == hfsmp->hfs_jnlfileid) ||
1035 (c_attr.ca_fileid == hfsmp->hfs_jnlinfoblkid))) {
1036 err = 0;
1037 goto exit;
1038 }
1039
1040 if (returnAttrList->commonattr & ATTR_CMN_NAME) {
1041 cat_convertkey(hfsmp, key, rec, &c_desc);
1042 } else {
1043 c_desc.cd_cnid = c_attr.ca_fileid;
1044 if (hfsmp->hfs_flags & HFS_STANDARD)
1045 c_desc.cd_parentcnid = key->hfs.parentID;
1046 else
1047 c_desc.cd_parentcnid = key->hfsPlus.parentID;
1048 }
1049
1050 attrblk.ab_attrlist = returnAttrList;
1051 attrblk.ab_attrbufpp = &rovingAttributesBuffer;
1052 attrblk.ab_varbufpp = &rovingVariableBuffer;
1053 attrblk.ab_flags = 0;
1054 attrblk.ab_blocksize = 0;
1055 attrblk.ab_context = vfs_context_current();
1056
1057 hfs_packattrblk(&attrblk, hfsmp, NULL, &c_desc, &c_attr, &datafork, &rsrcfork, vfs_context_current());
1058
1059 packedBufferSize = (char*)rovingVariableBuffer - (char*)attributesBuffer;
1060
1061 if ( packedBufferSize > uio_resid(a_uio) )
1062 return( errSearchBufferFull );
1063
1064 (* nummatches)++;
1065
1066 *((u_int32_t *)attributesBuffer) = packedBufferSize; /* Store length of fixed + var block */
1067
1068 err = uiomove( (caddr_t)attributesBuffer, packedBufferSize, a_uio ); /* XXX should be packedBufferSize */
1069 exit:
1070 cat_releasedesc(&c_desc);
1071
1072 return( err );
1073 }
1074
1075
1076 static int
1077 UnpackSearchAttributeBlock( struct hfsmount *hfsmp, struct attrlist *alist,
1078 searchinfospec_t *searchInfo, void *attributeBuffer, int firstblock)
1079 {
1080 attrgroup_t a;
1081 u_int32_t bufferSize;
1082 boolean_t is_64_bit;
1083
1084 DBG_ASSERT(searchInfo != NULL);
1085
1086 is_64_bit = proc_is64bit(current_proc());
1087
1088 bufferSize = *((u_int32_t *)attributeBuffer);
1089 if (bufferSize == 0)
1090 return (EINVAL); /* XXX -DJB is a buffer size of zero ever valid for searchfs? */
1091
1092 attributeBuffer = (u_int32_t *)attributeBuffer + 1; /* advance past the size */
1093
1094 /*
1095 * UnPack common attributes
1096 */
1097 a = alist->commonattr;
1098 if ( a != 0 ) {
1099 if ( a & ATTR_CMN_NAME ) {
1100 if (firstblock) {
1101 /* Only use the attrreference_t for the first searchparams */
1102 char *s;
1103 u_int32_t len;
1104
1105 s = (char*) attributeBuffer + ((attrreference_t *) attributeBuffer)->attr_dataoffset;
1106 len = ((attrreference_t *) attributeBuffer)->attr_length;
1107
1108 if (len > sizeof(searchInfo->name))
1109 return (EINVAL);
1110
1111 if (hfsmp->hfs_flags & HFS_STANDARD) {
1112 /* Convert name to pascal string to match HFS B-Tree names */
1113
1114 if (len > 0) {
1115 if (utf8_to_hfs(HFSTOVCB(hfsmp), len-1, (u_char *)s, (u_char*)searchInfo->name) != 0)
1116 return (EINVAL);
1117
1118 searchInfo->nameLength = searchInfo->name[0];
1119 } else {
1120 searchInfo->name[0] = searchInfo->nameLength = 0;
1121 }
1122 } else {
1123 size_t ucslen;
1124 /* Convert name to Unicode to match HFS Plus B-Tree names */
1125
1126 if (len > 0) {
1127 if (utf8_decodestr((u_int8_t *)s, len-1, (UniChar*)searchInfo->name, &ucslen,
1128 sizeof(searchInfo->name), ':', UTF_DECOMPOSED | UTF_ESCAPE_ILLEGAL))
1129 return (EINVAL);
1130
1131 searchInfo->nameLength = ucslen / sizeof(UniChar);
1132 } else {
1133 searchInfo->nameLength = 0;
1134 }
1135 }
1136 }
1137 attributeBuffer = (attrreference_t*) attributeBuffer +1;
1138 }
1139 if ( a & ATTR_CMN_OBJID ) {
1140 searchInfo->nodeID = ((fsobj_id_t *) attributeBuffer)->fid_objno; /* ignore fid_generation */
1141 attributeBuffer = (fsobj_id_t *)attributeBuffer + 1;
1142 }
1143 if ( a & ATTR_CMN_PAROBJID ) {
1144 searchInfo->parentDirID = ((fsobj_id_t *) attributeBuffer)->fid_objno; /* ignore fid_generation */
1145 attributeBuffer = (fsobj_id_t *)attributeBuffer + 1;
1146 }
1147
1148 if ( a & ATTR_CMN_CRTIME ) {
1149 if (is_64_bit) {
1150 struct user64_timespec tmp;
1151 tmp = *((struct user64_timespec *)attributeBuffer);
1152 searchInfo->creationDate.tv_sec = (time_t)tmp.tv_sec;
1153 searchInfo->creationDate.tv_nsec = tmp.tv_nsec;
1154 attributeBuffer = (struct user64_timespec *)attributeBuffer + 1;
1155 }
1156 else {
1157 struct user32_timespec tmp;
1158 tmp = *((struct user32_timespec *)attributeBuffer);
1159 searchInfo->creationDate.tv_sec = (time_t)tmp.tv_sec;
1160 searchInfo->creationDate.tv_nsec = tmp.tv_nsec;
1161 attributeBuffer = (struct user32_timespec *)attributeBuffer + 1;
1162 }
1163 }
1164 if ( a & ATTR_CMN_MODTIME ) {
1165 if (is_64_bit) {
1166 struct user64_timespec tmp;
1167 tmp = *((struct user64_timespec *)attributeBuffer);
1168 searchInfo->modificationDate.tv_sec = (time_t)tmp.tv_sec;
1169 searchInfo->modificationDate.tv_nsec = tmp.tv_nsec;
1170 attributeBuffer = (struct user64_timespec *)attributeBuffer + 1;
1171 }
1172 else {
1173 struct user32_timespec tmp;
1174 tmp = *((struct user32_timespec *)attributeBuffer);
1175 searchInfo->modificationDate.tv_sec = (time_t)tmp.tv_sec;
1176 searchInfo->modificationDate.tv_nsec = tmp.tv_nsec;
1177 attributeBuffer = (struct user32_timespec *)attributeBuffer + 1;
1178 }
1179 }
1180 if ( a & ATTR_CMN_CHGTIME ) {
1181 if (is_64_bit) {
1182 struct user64_timespec tmp;
1183 tmp = *((struct user64_timespec *)attributeBuffer);
1184 searchInfo->changeDate.tv_sec = (time_t)tmp.tv_sec;
1185 searchInfo->changeDate.tv_nsec = tmp.tv_nsec;
1186 attributeBuffer = (struct user64_timespec *)attributeBuffer + 1;
1187 }
1188 else {
1189 struct user32_timespec tmp;
1190 tmp = *((struct user32_timespec *)attributeBuffer);
1191 searchInfo->changeDate.tv_sec = (time_t)tmp.tv_sec;
1192 searchInfo->changeDate.tv_nsec = tmp.tv_nsec;
1193 attributeBuffer = (struct user32_timespec *)attributeBuffer + 1;
1194 }
1195 }
1196 if ( a & ATTR_CMN_ACCTIME ) {
1197 if (is_64_bit) {
1198 struct user64_timespec tmp;
1199 tmp = *((struct user64_timespec *)attributeBuffer);
1200 searchInfo->accessDate.tv_sec = (time_t)tmp.tv_sec;
1201 searchInfo->accessDate.tv_nsec = tmp.tv_nsec;
1202 attributeBuffer = (struct user64_timespec *)attributeBuffer + 1;
1203 }
1204 else {
1205 struct user32_timespec tmp;
1206 tmp = *((struct user32_timespec *)attributeBuffer);
1207 searchInfo->accessDate.tv_sec = (time_t)tmp.tv_sec;
1208 searchInfo->accessDate.tv_nsec = tmp.tv_nsec;
1209 attributeBuffer = (struct user32_timespec *)attributeBuffer + 1;
1210 }
1211 }
1212 if ( a & ATTR_CMN_BKUPTIME ) {
1213 if (is_64_bit) {
1214 struct user64_timespec tmp;
1215 tmp = *((struct user64_timespec *)attributeBuffer);
1216 searchInfo->lastBackupDate.tv_sec = (time_t)tmp.tv_sec;
1217 searchInfo->lastBackupDate.tv_nsec = tmp.tv_nsec;
1218 attributeBuffer = (struct user64_timespec *)attributeBuffer + 1;
1219 }
1220 else {
1221 struct user32_timespec tmp;
1222 tmp = *((struct user32_timespec *)attributeBuffer);
1223 searchInfo->lastBackupDate.tv_sec = (time_t)tmp.tv_sec;
1224 searchInfo->lastBackupDate.tv_nsec = tmp.tv_nsec;
1225 attributeBuffer = (struct user32_timespec *)attributeBuffer + 1;
1226 }
1227 }
1228 if ( a & ATTR_CMN_FNDRINFO ) {
1229 bcopy( attributeBuffer, searchInfo->finderInfo, sizeof(searchInfo->finderInfo) );
1230 attributeBuffer = (u_int8_t *)attributeBuffer + 32;
1231 }
1232 if ( a & ATTR_CMN_OWNERID ) {
1233 searchInfo->uid = *((uid_t *)attributeBuffer);
1234 attributeBuffer = (uid_t *)attributeBuffer + 1;
1235 }
1236 if ( a & ATTR_CMN_GRPID ) {
1237 searchInfo->gid = *((gid_t *)attributeBuffer);
1238 attributeBuffer = (gid_t *)attributeBuffer + 1;
1239 }
1240 if ( a & ATTR_CMN_ACCESSMASK ) {
1241 searchInfo->mask = *((mode_t *)attributeBuffer);
1242 attributeBuffer = (mode_t *)attributeBuffer + 1;
1243 }
1244 if ( a & ATTR_CMN_FILEID ) {
1245 searchInfo->nodeID = (u_int32_t)*((u_int64_t *) attributeBuffer);
1246 attributeBuffer = (u_int64_t *)attributeBuffer + 1;
1247 }
1248 if ( a & ATTR_CMN_PARENTID ) {
1249 searchInfo->parentDirID = (u_int32_t)*((u_int64_t *) attributeBuffer);
1250 attributeBuffer = (u_int64_t *)attributeBuffer + 1;
1251 }
1252 }
1253
1254 a = alist->dirattr;
1255 if ( a != 0 ) {
1256 if ( a & ATTR_DIR_ENTRYCOUNT ) {
1257 searchInfo->d.numFiles = *((u_int32_t *)attributeBuffer);
1258 attributeBuffer = (u_int32_t *)attributeBuffer + 1;
1259 }
1260 }
1261
1262 a = alist->fileattr;
1263 if ( a != 0 ) {
1264 if ( a & ATTR_FILE_DATALENGTH ) {
1265 searchInfo->f.dataLogicalLength = *((off_t *)attributeBuffer);
1266 attributeBuffer = (off_t *)attributeBuffer + 1;
1267 }
1268 if ( a & ATTR_FILE_DATAALLOCSIZE ) {
1269 searchInfo->f.dataPhysicalLength = *((off_t *)attributeBuffer);
1270 attributeBuffer = (off_t *)attributeBuffer + 1;
1271 }
1272 if ( a & ATTR_FILE_RSRCLENGTH ) {
1273 searchInfo->f.resourceLogicalLength = *((off_t *)attributeBuffer);
1274 attributeBuffer = (off_t *)attributeBuffer + 1;
1275 }
1276 if ( a & ATTR_FILE_RSRCALLOCSIZE ) {
1277 searchInfo->f.resourcePhysicalLength = *((off_t *)attributeBuffer);
1278 attributeBuffer = (off_t *)attributeBuffer + 1;
1279 }
1280 }
1281
1282 return (0);
1283 }
1284