]> git.saurik.com Git - apple/xnu.git/blame_incremental - bsd/hfs/hfs_search.c
xnu-1228.5.18.tar.gz
[apple/xnu.git] / bsd / hfs / hfs_search.c
... / ...
CommitLineData
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. */
69struct directoryInfoSpec
70{
71 u_int32_t numFiles;
72};
73
74struct fileInfoSpec
75{
76 off_t dataLogicalLength;
77 off_t dataPhysicalLength;
78 off_t resourceLogicalLength;
79 off_t resourcePhysicalLength;
80};
81
82struct searchinfospec
83{
84 u_char name[kHFSPlusMaxFileNameBytes];
85 u_long nameLength;
86 char attributes; // see IM:Files 2-100
87 u_long nodeID;
88 u_long 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};
101typedef struct searchinfospec searchinfospec_t;
102
103static void ResolveHardlink(struct hfsmount *hfsmp, HFSPlusCatalogFile *recp);
104
105
106static int UnpackSearchAttributeBlock(struct hfsmount *hfsmp, struct attrlist *alist,
107 searchinfospec_t *searchInfo, void *attributeBuffer);
108
109static 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
117static int CheckAccess(ExtendedVCB *vcb, u_long searchBits, CatalogKey *key, struct vfs_context *ctx);
118
119static int InsertMatch(struct hfsmount *hfsmp, uio_t a_uio, CatalogRecord *rec,
120 CatalogKey *key, struct attrlist *returnAttrList,
121 void *attributesBuffer, void *variableBuffer,
122 u_long * nummatches );
123
124static Boolean CompareRange(u_long val, u_long low, u_long high);
125static Boolean CompareWideRange(u_int64_t val, u_int64_t low, u_int64_t high);
126
127static Boolean CompareRange( u_long val, u_long low, u_long high )
128{
129 return( (val >= low) && (val <= high) );
130}
131
132static 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#
148vnop_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__
158int
159hfs_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;
183 void *variableBuffer;
184 u_long fixedBlockSize;
185 u_long 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);
258 if (err) return err;
259 err = UnpackSearchAttributeBlock(hfsmp, ap->a_searchattrs,
260 &searchInfo2, ap->a_searchparams2);
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 variableBuffer = (void*)((char*) attributesBuffer + fixedBlockSize);
278
279 // XXXdbg - have to lock the user's buffer so we don't fault
280 // while holding the shared catalog file lock. see the comment
281 // in hfs_readdir() for more details.
282 //
283 if (hfsmp->jnl && uio_isuserspace(ap->a_uio)) {
284 user_start = uio_curriovbase(ap->a_uio);
285 user_len = uio_curriovlen(ap->a_uio);
286
287 if ((err = vslock(user_start, user_len)) != 0) {
288 user_start = 0;
289 goto ExitThisRoutine;
290 }
291 }
292
293 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
294
295 catalogFCB = GetFileControlBlock(vcb->catalogRefNum);
296 myCurrentKeyPtr = NULL;
297 myCurrentDataPtr = NULL;
298 myCatPositionPtr = (CatPosition *)ap->a_searchstate;
299
300 if (ap->a_options & SRCHFS_START) {
301 /* Starting a new search. */
302 /* Make sure the on-disk Catalog file is current */
303 (void) hfs_fsync(vcb->catalogRefNum, MNT_WAIT, 0, p);
304 if (hfsmp->jnl) {
305 hfs_systemfile_unlock(hfsmp, lockflags);
306 journal_flush(hfsmp->jnl);
307 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
308 }
309
310 ap->a_options &= ~SRCHFS_START;
311 bzero((caddr_t)myCatPositionPtr, sizeof(*myCatPositionPtr));
312 err = BTScanInitialize(catalogFCB, 0, 0, 0, kCatSearchBufferSize, &myBTScanState);
313 if (err) {
314 goto ExitThisRoutine;
315 }
316 } else {
317 /* Resuming a search. */
318 err = BTScanInitialize(catalogFCB, myCatPositionPtr->nextNode,
319 myCatPositionPtr->nextRecord,
320 myCatPositionPtr->recordsFound,
321 kCatSearchBufferSize,
322 &myBTScanState);
323 /* Make sure Catalog hasn't changed. */
324 if (err == 0
325 && myCatPositionPtr->writeCount != myBTScanState.btcb->writeCount) {
326 myCatPositionPtr->writeCount = myBTScanState.btcb->writeCount;
327 err = EBUSY; /* catChangedErr */
328 }
329 }
330 hfs_systemfile_unlock(hfsmp, lockflags);
331
332 if (err)
333 goto ExitThisRoutine;
334
335 /*
336 * Check all the catalog btree records...
337 * return the attributes for matching items
338 */
339 for (;;) {
340 struct timeval myCurrentTime;
341 struct timeval myElapsedTime;
342
343 err = BTScanNextRecord(&myBTScanState, timerExpired,
344 (void **)&myCurrentKeyPtr, (void **)&myCurrentDataPtr,
345 NULL);
346 if (err)
347 break;
348
349 /* Resolve any hardlinks */
350 if (isHFSPlus && (ap->a_options & SRCHFS_SKIPLINKS) == 0) {
351 ResolveHardlink(vcb, (HFSPlusCatalogFile *)myCurrentDataPtr);
352 }
353 if (CheckCriteria( vcb, ap->a_options, ap->a_searchattrs, myCurrentDataPtr,
354 myCurrentKeyPtr, &searchInfo1, &searchInfo2 )
355 && CheckAccess(vcb, ap->a_options, myCurrentKeyPtr, ap->a_context)) {
356 err = InsertMatch(hfsmp, ap->a_uio, myCurrentDataPtr,
357 myCurrentKeyPtr, ap->a_returnattrs,
358 attributesBuffer, variableBuffer, ap->a_nummatches);
359 if (err) {
360 /*
361 * The last match didn't fit so come back
362 * to this record on the next trip.
363 */
364 --myBTScanState.recordsFound;
365 --myBTScanState.recordNum;
366 break;
367 }
368
369 if (*(ap->a_nummatches) >= ap->a_maxmatches)
370 break;
371 }
372
373 /*
374 * Check our elapsed time and bail if we've hit the max.
375 * The idea here is to throttle the amount of time we
376 * spend in the kernel.
377 */
378 microuptime(&myCurrentTime);
379 timersub(&myCurrentTime, &myBTScanState.startTime, &myElapsedTime);
380 /* Note: assumes kMaxMicroSecsInKernel is less than 1,000,000 */
381 if (myElapsedTime.tv_sec > 0
382 || myElapsedTime.tv_usec >= searchTime) {
383 timerExpired = true;
384 }
385 }
386
387 /* Update catalog position */
388 myCatPositionPtr->writeCount = myBTScanState.btcb->writeCount;
389
390 BTScanTerminate(&myBTScanState, &myCatPositionPtr->nextNode,
391 &myCatPositionPtr->nextRecord,
392 &myCatPositionPtr->recordsFound);
393
394 if ( err == E_NONE ) {
395 err = EAGAIN; /* signal to the user to call searchfs again */
396 } else if ( err == errSearchBufferFull ) {
397 if ( *(ap->a_nummatches) > 0 )
398 err = EAGAIN;
399 else
400 err = ENOBUFS;
401 } else if ( err == btNotFound ) {
402 err = E_NONE; /* the entire disk has been searched */
403 } else if ( err == fsBTTimeOutErr ) {
404 err = EAGAIN;
405 }
406
407ExitThisRoutine:
408 FREE( attributesBuffer, M_TEMP );
409
410 if (hfsmp->jnl && user_start) {
411 vsunlock(user_start, user_len, TRUE);
412 }
413
414 return (MacToVFSError(err));
415}
416
417
418static void
419ResolveHardlink(struct hfsmount *hfsmp, HFSPlusCatalogFile *recp)
420{
421 u_int32_t type, creator;
422 int isdirlink = 0;
423 int isfilelink = 0;
424 time_t filecreatedate;
425
426 if (recp->recordType != kHFSPlusFileRecord) {
427 return;
428 }
429 type = SWAP_BE32(recp->userInfo.fdType);
430 creator = SWAP_BE32(recp->userInfo.fdCreator);
431 filecreatedate = to_bsd_time(recp->createDate);
432
433 if ((type == kHardLinkFileType && creator == kHFSPlusCreator) &&
434 (filecreatedate == (time_t)hfsmp->vcbCrDate ||
435 filecreatedate == (time_t)hfsmp->hfs_metadata_createdate)) {
436 isfilelink = 1;
437 } else if ((type == kHFSAliasType && creator == kHFSAliasCreator) &&
438 (recp->flags & kHFSHasLinkChainMask) &&
439 (filecreatedate == (time_t)hfsmp->vcbCrDate ||
440 filecreatedate == (time_t)hfsmp->hfs_metadata_createdate)) {
441 isdirlink = 1;
442 }
443
444 if (isfilelink || isdirlink) {
445 cnid_t saved_cnid;
446 int lockflags;
447
448 /* Export link's cnid (a unique value) instead of inode's cnid */
449 saved_cnid = recp->fileID;
450 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
451
452 (void) cat_resolvelink(hfsmp, recp->hl_linkReference, isdirlink, recp);
453
454 recp->fileID = saved_cnid;
455 hfs_systemfile_unlock(hfsmp, lockflags);
456 }
457}
458
459
460static Boolean
461CompareMasked(const u_int32_t *thisValue, const u_int32_t *compareData,
462 const u_int32_t *compareMask, u_int32_t count)
463{
464 Boolean matched;
465 u_int32_t i;
466
467 matched = true; /* Assume it will all match */
468
469 for (i=0; i<count; i++) {
470 if (((*thisValue++ ^ *compareData++) & *compareMask++) != 0) {
471 matched = false;
472 break;
473 }
474 }
475
476 return matched;
477}
478
479
480static Boolean
481ComparePartialUnicodeName (register ConstUniCharArrayPtr str, register ItemCount s_len,
482 register ConstUniCharArrayPtr find, register ItemCount f_len )
483{
484 if (f_len == 0 || s_len == 0)
485 return FALSE;
486
487 do {
488 if (s_len-- < f_len)
489 return FALSE;
490 } while (FastUnicodeCompare(str++, f_len, find, f_len) != 0);
491
492 return TRUE;
493}
494
495
496static Boolean
497ComparePartialPascalName ( register ConstStr31Param str, register ConstStr31Param find )
498{
499 register u_char s_len = str[0];
500 register u_char f_len = find[0];
501 register u_char *tsp;
502 Str31 tmpstr;
503
504 if (f_len == 0 || s_len == 0)
505 return FALSE;
506
507 bcopy(str, tmpstr, s_len + 1);
508 tsp = &tmpstr[0];
509
510 while (s_len-- >= f_len) {
511 *tsp = f_len;
512
513 if (FastRelString(tsp++, find) == 0)
514 return TRUE;
515 }
516
517 return FALSE;
518}
519
520
521//
522// Determine if a name is "inappropriate" where the definition
523// of "inappropriate" is up to higher level execs. Currently
524// that's limited to /System.
525//
526static int
527is_inappropriate_name(const char *name, int len)
528{
529 const char *bad_names[] = { "System" };
530 int bad_len[] = { 6 };
531 int i;
532
533 for(i=0; i < (int) (sizeof(bad_names) / sizeof(bad_names[0])); i++) {
534 if (len == bad_len[i] && strncmp(name, bad_names[i], strlen(bad_names[i]) + 1) == 0) {
535 return 1;
536 }
537 }
538
539 // if we get here, no name matched
540 return 0;
541}
542
543
544
545/*
546 * Check to see if caller has access rights to this item
547 */
548
549static int
550CheckAccess(ExtendedVCB *theVCBPtr, u_long searchBits, CatalogKey *theKeyPtr, struct vfs_context *ctx)
551{
552 Boolean isHFSPlus;
553 int myErr;
554 int myResult;
555 HFSCatalogNodeID myNodeID;
556 hfsmount_t * hfsmp;
557 struct FndrDirInfo *finfop;
558 struct vnode * vp = NULL;
559
560 myResult = 0; /* default to "no access" */
561
562 if (!vfs_context_suser(ctx)) {
563 myResult = 1; /* allow access */
564 goto ExitThisRoutine; /* root always has access */
565 }
566
567 hfsmp = VCBTOHFS( theVCBPtr );
568 isHFSPlus = ( theVCBPtr->vcbSigWord == kHFSPlusSigWord );
569 if ( isHFSPlus )
570 myNodeID = theKeyPtr->hfsPlus.parentID;
571 else
572 myNodeID = theKeyPtr->hfs.parentID;
573
574 while ( myNodeID >= kRootDirID ) {
575 cnode_t * cp;
576
577 /* now go get catalog data for this directory */
578 myErr = hfs_vget(hfsmp, myNodeID, &vp, 0);
579 if ( myErr ) {
580 goto ExitThisRoutine; /* no access */
581 }
582
583 cp = VTOC(vp);
584 finfop = (struct FndrDirInfo *)&cp->c_attr.ca_finderinfo[0];
585
586 if ( searchBits & SRCHFS_SKIPPACKAGES ) {
587 if ( (SWAP_BE16(finfop->frFlags) & kHasBundle)
588 || (cp->c_desc.cd_nameptr != NULL
589 && is_package_name((const char *)cp->c_desc.cd_nameptr, cp->c_desc.cd_namelen)) ) {
590 myResult = 0;
591 goto ExitThisRoutine;
592 }
593 }
594
595 if ( searchBits & SRCHFS_SKIPINAPPROPRIATE ) {
596 if ( cp->c_parentcnid == kRootDirID && cp->c_desc.cd_nameptr != NULL &&
597 is_inappropriate_name((const char *)cp->c_desc.cd_nameptr, cp->c_desc.cd_namelen) ) {
598 myResult = 0;
599 goto ExitThisRoutine;
600 }
601 }
602
603 if ( (searchBits & SRCHFS_SKIPINVISIBLE) &&
604 (SWAP_BE16(finfop->frFlags) & kIsInvisible) ) {
605 myResult = 0;
606 goto ExitThisRoutine;
607 }
608
609 myNodeID = cp->c_parentcnid; /* move up the hierarchy */
610 hfs_unlock(VTOC(vp));
611
612#if CONFIG_MACF
613 if (vp->v_type == VDIR) {
614 myErr = mac_vnode_check_readdir(ctx, vp);
615 } else {
616 myErr = mac_vnode_check_stat(ctx, NOCRED, vp);
617 }
618 if (myErr) {
619 vnode_put(vp);
620 vp = NULL;
621 goto ExitThisRoutine;
622 }
623#endif /* MAC */
624
625 if (vp->v_type == VDIR) {
626 myErr = vnode_authorize(vp, NULL, (KAUTH_VNODE_SEARCH | KAUTH_VNODE_LIST_DIRECTORY), ctx);
627 } else {
628 myErr = vnode_authorize(vp, NULL, (KAUTH_VNODE_SEARCH), ctx);
629 }
630 vnode_put(vp);
631 vp = NULL;
632 if ( myErr ) {
633 goto ExitThisRoutine; /* no access */
634 }
635 }
636 myResult = 1; /* allow access */
637
638ExitThisRoutine:
639 if ( vp != NULL ) {
640 hfs_unlock(VTOC(vp));
641 vnode_put(vp);
642 }
643 return ( myResult );
644
645}
646
647static int
648CheckCriteria( ExtendedVCB *vcb,
649 u_long searchBits,
650 struct attrlist *attrList,
651 CatalogRecord *rec,
652 CatalogKey *key,
653 searchinfospec_t *searchInfo1,
654 searchinfospec_t *searchInfo2 )
655{
656 Boolean matched, atleastone;
657 Boolean isHFSPlus;
658 attrgroup_t searchAttributes;
659 struct cat_attr c_attr;
660 struct cat_fork datafork;
661 struct cat_fork rsrcfork;
662
663 bzero(&c_attr, sizeof(c_attr));
664 isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord);
665
666 switch (rec->recordType) {
667 case kHFSFolderRecord:
668 case kHFSPlusFolderRecord:
669 if ( (searchBits & SRCHFS_MATCHDIRS) == 0 ) { /* If we are NOT searching folders */
670 matched = false;
671 goto TestDone;
672 }
673 break;
674
675 case kHFSFileRecord:
676 if ( (searchBits & SRCHFS_MATCHFILES) == 0 ) { /* If we are NOT searching files */
677 matched = false;
678 goto TestDone;
679 }
680 break;
681
682 case kHFSPlusFileRecord:
683 /* Check if hardlink links should be skipped. */
684 if (searchBits & SRCHFS_SKIPLINKS) {
685 cnid_t parid = key->hfsPlus.parentID;
686 HFSPlusCatalogFile *filep = (HFSPlusCatalogFile *)rec;
687
688 if ((SWAP_BE32(filep->userInfo.fdType) == kHardLinkFileType) &&
689 (SWAP_BE32(filep->userInfo.fdCreator) == kHFSPlusCreator)) {
690 return (false); /* skip over file link records */
691 } else if ((parid == vcb->hfs_private_desc[FILE_HARDLINKS].cd_cnid) &&
692 (filep->bsdInfo.special.linkCount == 0)) {
693 return (false); /* skip over unlinked files */
694 } else if ((SWAP_BE32(filep->userInfo.fdType) == kHFSAliasType) &&
695 (SWAP_BE32(filep->userInfo.fdCreator) == kHFSAliasCreator) &&
696 (filep->flags & kHFSHasLinkChainMask)) {
697 return (false); /* skip over dir link records */
698 }
699 } else if (key->hfsPlus.parentID == vcb->hfs_private_desc[FILE_HARDLINKS].cd_cnid) {
700 return (false); /* skip over private files */
701 } else if (key->hfsPlus.parentID == vcb->hfs_private_desc[DIR_HARDLINKS].cd_cnid) {
702 return (false); /* skip over private files */
703 }
704
705 if ( (searchBits & SRCHFS_MATCHFILES) == 0 ) { /* If we are NOT searching files */
706 matched = false;
707 goto TestDone;
708 }
709 break;
710
711 default: /* Never match a thread record or any other type. */
712 return( false ); /* Not a file or folder record, so can't search it */
713 }
714
715 matched = true; /* Assume we got a match */
716 atleastone = false; /* Dont insert unless we match at least one criteria */
717
718 /* First, attempt to match the name -- either partial or complete */
719 if ( attrList->commonattr & ATTR_CMN_NAME ) {
720 if (isHFSPlus) {
721 /* Check for partial/full HFS Plus name match */
722
723 if ( searchBits & SRCHFS_MATCHPARTIALNAMES ) {
724 matched = ComparePartialUnicodeName(key->hfsPlus.nodeName.unicode,
725 key->hfsPlus.nodeName.length,
726 (UniChar*)searchInfo1->name,
727 searchInfo1->nameLength );
728 } else /* full HFS Plus name match */ {
729 matched = (FastUnicodeCompare(key->hfsPlus.nodeName.unicode,
730 key->hfsPlus.nodeName.length,
731 (UniChar*)searchInfo1->name,
732 searchInfo1->nameLength ) == 0);
733 }
734 } else {
735 /* Check for partial/full HFS name match */
736
737 if ( searchBits & SRCHFS_MATCHPARTIALNAMES )
738 matched = ComparePartialPascalName(key->hfs.nodeName, (u_char*)searchInfo1->name);
739 else /* full HFS name match */
740 matched = (FastRelString(key->hfs.nodeName, (u_char*)searchInfo1->name) == 0);
741 }
742
743 if ( matched == false || (searchBits & ~SRCHFS_MATCHPARTIALNAMES) == 0 )
744 goto TestDone; /* no match, or nothing more to compare */
745
746 atleastone = true;
747 }
748
749 /* Convert catalog record into cat_attr format. */
750 cat_convertattr(VCBTOHFS(vcb), rec, &c_attr, &datafork, &rsrcfork);
751
752 if (searchBits & SRCHFS_SKIPINVISIBLE) {
753 int flags;
754
755 switch (rec->recordType) {
756 case kHFSFolderRecord:
757 case kHFSPlusFolderRecord: {
758 struct FndrDirInfo *finder_info;
759
760 finder_info = (struct FndrDirInfo *)&c_attr.ca_finderinfo[0];
761 flags = SWAP_BE16(finder_info->frFlags);
762 break;
763 }
764
765 case kHFSFileRecord:
766 case kHFSPlusFileRecord: {
767 struct FndrFileInfo *finder_info;
768
769 finder_info = (struct FndrFileInfo *)&c_attr.ca_finderinfo[0];
770 flags = SWAP_BE16(finder_info->fdFlags);
771 break;
772 }
773
774 default: {
775 flags = kIsInvisible;
776 break;
777 }
778 }
779
780 if (flags & kIsInvisible) {
781 matched = false;
782 goto TestDone;
783 }
784 }
785
786
787
788 /* Now that we have a record worth searching, see if it matches the search attributes */
789 if (rec->recordType == kHFSFileRecord ||
790 rec->recordType == kHFSPlusFileRecord) {
791 if ((attrList->fileattr & ~ATTR_FILE_VALIDMASK) != 0) { /* attr we do know about */
792 matched = false;
793 goto TestDone;
794 }
795 else if ((attrList->fileattr & ATTR_FILE_VALIDMASK) != 0) {
796 searchAttributes = attrList->fileattr;
797
798 /* File logical length (data fork) */
799 if ( searchAttributes & ATTR_FILE_DATALENGTH ) {
800 matched = CompareWideRange(
801 datafork.cf_size,
802 searchInfo1->f.dataLogicalLength,
803 searchInfo2->f.dataLogicalLength);
804 if (matched == false) goto TestDone;
805 atleastone = true;
806 }
807
808 /* File physical length (data fork) */
809 if ( searchAttributes & ATTR_FILE_DATAALLOCSIZE ) {
810 matched = CompareWideRange(
811 (u_int64_t)datafork.cf_blocks * (u_int64_t)vcb->blockSize,
812 searchInfo1->f.dataPhysicalLength,
813 searchInfo2->f.dataPhysicalLength);
814 if (matched == false) goto TestDone;
815 atleastone = true;
816 }
817
818 /* File logical length (resource fork) */
819 if ( searchAttributes & ATTR_FILE_RSRCLENGTH ) {
820 matched = CompareWideRange(
821 rsrcfork.cf_size,
822 searchInfo1->f.resourceLogicalLength,
823 searchInfo2->f.resourceLogicalLength);
824 if (matched == false) goto TestDone;
825 atleastone = true;
826 }
827
828 /* File physical length (resource fork) */
829 if ( searchAttributes & ATTR_FILE_RSRCALLOCSIZE ) {
830 matched = CompareWideRange(
831 (u_int64_t)rsrcfork.cf_blocks * (u_int64_t)vcb->blockSize,
832 searchInfo1->f.resourcePhysicalLength,
833 searchInfo2->f.resourcePhysicalLength);
834 if (matched == false) goto TestDone;
835 atleastone = true;
836 }
837 }
838 else {
839 atleastone = true; /* to match SRCHFS_MATCHFILES */
840 }
841 }
842 /*
843 * Check the directory attributes
844 */
845 else if (rec->recordType == kHFSFolderRecord ||
846 rec->recordType == kHFSPlusFolderRecord) {
847 if ((attrList->dirattr & ~ATTR_DIR_VALIDMASK) != 0) { /* attr we do know about */
848 matched = false;
849 goto TestDone;
850 }
851 else if ((attrList->dirattr & ATTR_DIR_VALIDMASK) != 0) {
852 searchAttributes = attrList->dirattr;
853
854 /* Directory valence */
855 if ( searchAttributes & ATTR_DIR_ENTRYCOUNT ) {
856 matched = CompareRange(c_attr.ca_entries,
857 searchInfo1->d.numFiles,
858 searchInfo2->d.numFiles );
859 if (matched == false) goto TestDone;
860 atleastone = true;
861 }
862 }
863 else {
864 atleastone = true; /* to match SRCHFS_MATCHDIRS */
865 }
866 }
867
868 /*
869 * Check the common attributes
870 */
871 searchAttributes = attrList->commonattr;
872 if ( (searchAttributes & ATTR_CMN_VALIDMASK) != 0 ) {
873 /* node ID */
874 if ( searchAttributes & ATTR_CMN_OBJID ) {
875 matched = CompareRange(c_attr.ca_fileid,
876 searchInfo1->nodeID,
877 searchInfo2->nodeID );
878 if (matched == false) goto TestDone;
879 atleastone = true;
880 }
881
882 /* Parent ID */
883 if ( searchAttributes & ATTR_CMN_PAROBJID ) {
884 HFSCatalogNodeID parentID;
885
886 if (isHFSPlus)
887 parentID = key->hfsPlus.parentID;
888 else
889 parentID = key->hfs.parentID;
890
891 matched = CompareRange(parentID, searchInfo1->parentDirID,
892 searchInfo2->parentDirID );
893 if (matched == false) goto TestDone;
894 atleastone = true;
895 }
896
897 /* Finder Info & Extended Finder Info where extFinderInfo is last 32 bytes */
898 if ( searchAttributes & ATTR_CMN_FNDRINFO ) {
899 u_int32_t *thisValue;
900 thisValue = (u_int32_t *) &c_attr.ca_finderinfo;
901
902 /*
903 * Note: ioFlFndrInfo and ioDrUsrWds have the same offset in search info, so
904 * no need to test the object type here.
905 */
906 matched = CompareMasked(thisValue,
907 (u_int32_t *)&searchInfo1->finderInfo,
908 (u_int32_t *) &searchInfo2->finderInfo, 8);
909 if (matched == false) goto TestDone;
910 atleastone = true;
911 }
912
913 /* Create date */
914 if ( searchAttributes & ATTR_CMN_CRTIME ) {
915 matched = CompareRange(c_attr.ca_itime,
916 searchInfo1->creationDate.tv_sec,
917 searchInfo2->creationDate.tv_sec);
918 if (matched == false) goto TestDone;
919 atleastone = true;
920 }
921
922 /* Mod date */
923 if ( searchAttributes & ATTR_CMN_MODTIME ) {
924 matched = CompareRange(c_attr.ca_mtime,
925 searchInfo1->modificationDate.tv_sec,
926 searchInfo2->modificationDate.tv_sec);
927 if (matched == false) goto TestDone;
928 atleastone = true;
929 }
930
931 /* Change Time */
932 if ( searchAttributes & ATTR_CMN_CHGTIME ) {
933 matched = CompareRange(c_attr.ca_ctime,
934 searchInfo1->changeDate.tv_sec,
935 searchInfo2->changeDate.tv_sec);
936 if (matched == false) goto TestDone;
937 atleastone = true;
938 }
939
940 /* Access date */
941 if ( searchAttributes & ATTR_CMN_ACCTIME ) {
942 matched = CompareRange(c_attr.ca_atime,
943 searchInfo1->accessDate.tv_sec,
944 searchInfo2->accessDate.tv_sec);
945 if (matched == false) goto TestDone;
946 atleastone = true;
947 }
948
949 /* Backup date */
950 if ( searchAttributes & ATTR_CMN_BKUPTIME ) {
951 matched = CompareRange(c_attr.ca_btime,
952 searchInfo1->lastBackupDate.tv_sec,
953 searchInfo2->lastBackupDate.tv_sec);
954 if (matched == false) goto TestDone;
955 atleastone = true;
956 }
957
958 /* User ID */
959 if ( searchAttributes & ATTR_CMN_OWNERID ) {
960 matched = CompareRange(c_attr.ca_uid,
961 searchInfo1->uid, searchInfo2->uid);
962 if (matched == false) goto TestDone;
963 atleastone = true;
964 }
965
966 /* Group ID */
967 if ( searchAttributes & ATTR_CMN_GRPID ) {
968 matched = CompareRange(c_attr.ca_gid,
969 searchInfo1->gid, searchInfo2->gid);
970 if (matched == false) goto TestDone;
971 atleastone = true;
972 }
973
974 /* mode */
975 if ( searchAttributes & ATTR_CMN_ACCESSMASK ) {
976 matched = CompareRange((u_int32_t)c_attr.ca_mode,
977 (u_int32_t)searchInfo1->mask,
978 (u_int32_t)searchInfo2->mask);
979 if (matched == false) goto TestDone;
980 atleastone = true;
981 }
982 }
983
984 /* If we got here w/o matching any, then set to false */
985 if (! atleastone)
986 matched = false;
987
988TestDone:
989 /*
990 * Finally, determine whether we need to negate the sense of the match
991 * (i.e. find all objects that DON'T match).
992 */
993 if ( searchBits & SRCHFS_NEGATEPARAMS )
994 matched = !matched;
995
996 return( matched );
997}
998
999
1000/*
1001 * Adds another record to the packed array for output
1002 */
1003static int
1004InsertMatch(struct hfsmount *hfsmp, uio_t a_uio, CatalogRecord *rec,
1005 CatalogKey *key, struct attrlist *returnAttrList,
1006 void *attributesBuffer, void *variableBuffer, u_long * nummatches)
1007{
1008 int err;
1009 void *rovingAttributesBuffer;
1010 void *rovingVariableBuffer;
1011 u_long packedBufferSize;
1012 struct attrblock attrblk;
1013 struct cat_desc c_desc;
1014 struct cat_attr c_attr;
1015 struct cat_fork datafork;
1016 struct cat_fork rsrcfork;
1017
1018 bzero(&c_desc, sizeof(c_desc));
1019 bzero(&c_attr, sizeof(c_attr));
1020 rovingAttributesBuffer = (char*)attributesBuffer + sizeof(u_long); /* Reserve space for length field */
1021 rovingVariableBuffer = variableBuffer;
1022
1023 /* Convert catalog record into cat_attr format. */
1024 cat_convertattr(hfsmp, rec, &c_attr, &datafork, &rsrcfork);
1025
1026 /* Hide our private meta data directories */
1027 if (c_attr.ca_fileid == hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid ||
1028 c_attr.ca_fileid == hfsmp->hfs_private_desc[DIR_HARDLINKS].cd_cnid) {
1029 err = 0;
1030 goto exit;
1031 }
1032
1033 /* Hide the private journal files */
1034 if (hfsmp->jnl &&
1035 ((c_attr.ca_fileid == hfsmp->hfs_jnlfileid) ||
1036 (c_attr.ca_fileid == hfsmp->hfs_jnlinfoblkid))) {
1037 err = 0;
1038 goto exit;
1039 }
1040
1041 if (returnAttrList->commonattr & ATTR_CMN_NAME) {
1042 cat_convertkey(hfsmp, key, rec, &c_desc);
1043 } else {
1044 c_desc.cd_cnid = c_attr.ca_fileid;
1045 if (hfsmp->hfs_flags & HFS_STANDARD)
1046 c_desc.cd_parentcnid = key->hfs.parentID;
1047 else
1048 c_desc.cd_parentcnid = key->hfsPlus.parentID;
1049 }
1050
1051 attrblk.ab_attrlist = returnAttrList;
1052 attrblk.ab_attrbufpp = &rovingAttributesBuffer;
1053 attrblk.ab_varbufpp = &rovingVariableBuffer;
1054 attrblk.ab_flags = 0;
1055 attrblk.ab_blocksize = 0;
1056 attrblk.ab_context = vfs_context_current();
1057
1058 hfs_packattrblk(&attrblk, hfsmp, NULL, &c_desc, &c_attr, &datafork, &rsrcfork, current_proc());
1059
1060 packedBufferSize = (char*)rovingVariableBuffer - (char*)attributesBuffer;
1061
1062 if ( packedBufferSize > uio_resid(a_uio) )
1063 return( errSearchBufferFull );
1064
1065 (* nummatches)++;
1066
1067 *((u_long *)attributesBuffer) = packedBufferSize; /* Store length of fixed + var block */
1068
1069 err = uiomove( (caddr_t)attributesBuffer, packedBufferSize, a_uio ); /* XXX should be packedBufferSize */
1070exit:
1071 cat_releasedesc(&c_desc);
1072
1073 return( err );
1074}
1075
1076
1077static int
1078UnpackSearchAttributeBlock( struct hfsmount *hfsmp, struct attrlist *alist, searchinfospec_t *searchInfo, void *attributeBuffer )
1079{
1080 attrgroup_t a;
1081 u_long 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 char *s;
1101 u_int32_t len;
1102
1103 s = (char*) attributeBuffer + ((attrreference_t *) attributeBuffer)->attr_dataoffset;
1104 len = ((attrreference_t *) attributeBuffer)->attr_length;
1105
1106 if (len > sizeof(searchInfo->name))
1107 return (EINVAL);
1108
1109 if (hfsmp->hfs_flags & HFS_STANDARD) {
1110 /* Convert name to pascal string to match HFS B-Tree names */
1111
1112 if (len > 0) {
1113 if (utf8_to_hfs(HFSTOVCB(hfsmp), len-1, (u_char *)s, (u_char*)searchInfo->name) != 0)
1114 return (EINVAL);
1115
1116 searchInfo->nameLength = searchInfo->name[0];
1117 } else {
1118 searchInfo->name[0] = searchInfo->nameLength = 0;
1119 }
1120 attributeBuffer = (attrreference_t *)attributeBuffer + 1;
1121 } else {
1122 size_t ucslen;
1123 /* Convert name to Unicode to match HFS Plus B-Tree names */
1124
1125 if (len > 0) {
1126 if (utf8_decodestr((u_int8_t *)s, len-1, (UniChar*)searchInfo->name, &ucslen,
1127 sizeof(searchInfo->name), ':', UTF_DECOMPOSED | UTF_ESCAPE_ILLEGAL))
1128 return (EINVAL);
1129
1130 searchInfo->nameLength = ucslen / sizeof(UniChar);
1131 } else {
1132 searchInfo->nameLength = 0;
1133 }
1134 attributeBuffer = (attrreference_t *)attributeBuffer + 1;
1135 }
1136 }
1137 if ( a & ATTR_CMN_OBJID ) {
1138 searchInfo->nodeID = ((fsobj_id_t *) attributeBuffer)->fid_objno; /* ignore fid_generation */
1139 attributeBuffer = (fsobj_id_t *)attributeBuffer + 1;
1140 }
1141 if ( a & ATTR_CMN_PAROBJID ) {
1142 searchInfo->parentDirID = ((fsobj_id_t *) attributeBuffer)->fid_objno; /* ignore fid_generation */
1143 attributeBuffer = (fsobj_id_t *)attributeBuffer + 1;
1144 }
1145
1146 if ( a & ATTR_CMN_CRTIME ) {
1147 if (is_64_bit) {
1148 struct user_timespec tmp;
1149 tmp = *((struct user_timespec *)attributeBuffer);
1150 searchInfo->creationDate.tv_sec = (time_t)tmp.tv_sec;
1151 searchInfo->creationDate.tv_nsec = tmp.tv_nsec;
1152 attributeBuffer = (struct user_timespec *)attributeBuffer + 1;
1153 }
1154 else {
1155 searchInfo->creationDate = *((struct timespec *)attributeBuffer);
1156 attributeBuffer = (struct timespec *)attributeBuffer + 1;
1157 }
1158 }
1159 if ( a & ATTR_CMN_MODTIME ) {
1160 if (is_64_bit) {
1161 struct user_timespec tmp;
1162 tmp = *((struct user_timespec *)attributeBuffer);
1163 searchInfo->modificationDate.tv_sec = (time_t)tmp.tv_sec;
1164 searchInfo->modificationDate.tv_nsec = tmp.tv_nsec;
1165 attributeBuffer = (struct user_timespec *)attributeBuffer + 1;
1166 }
1167 else {
1168 searchInfo->modificationDate = *((struct timespec *)attributeBuffer);
1169 attributeBuffer = (struct timespec *)attributeBuffer + 1;
1170 }
1171 }
1172 if ( a & ATTR_CMN_CHGTIME ) {
1173 if (is_64_bit) {
1174 struct user_timespec tmp;
1175 tmp = *((struct user_timespec *)attributeBuffer);
1176 searchInfo->changeDate.tv_sec = (time_t)tmp.tv_sec;
1177 searchInfo->changeDate.tv_nsec = tmp.tv_nsec;
1178 attributeBuffer = (struct user_timespec *)attributeBuffer + 1;
1179 }
1180 else {
1181 searchInfo->changeDate = *((struct timespec *)attributeBuffer);
1182 attributeBuffer = (struct timespec *)attributeBuffer + 1;
1183 }
1184 }
1185 if ( a & ATTR_CMN_ACCTIME ) {
1186 if (is_64_bit) {
1187 struct user_timespec tmp;
1188 tmp = *((struct user_timespec *)attributeBuffer);
1189 searchInfo->accessDate.tv_sec = (time_t)tmp.tv_sec;
1190 searchInfo->accessDate.tv_nsec = tmp.tv_nsec;
1191 attributeBuffer = (struct user_timespec *)attributeBuffer + 1;
1192 }
1193 else {
1194 searchInfo->accessDate = *((struct timespec *)attributeBuffer);
1195 attributeBuffer = (struct timespec *)attributeBuffer + 1;
1196 }
1197 }
1198 if ( a & ATTR_CMN_BKUPTIME ) {
1199 if (is_64_bit) {
1200 struct user_timespec tmp;
1201 tmp = *((struct user_timespec *)attributeBuffer);
1202 searchInfo->lastBackupDate.tv_sec = (time_t)tmp.tv_sec;
1203 searchInfo->lastBackupDate.tv_nsec = tmp.tv_nsec;
1204 attributeBuffer = (struct user_timespec *)attributeBuffer + 1;
1205 }
1206 else {
1207 searchInfo->lastBackupDate = *((struct timespec *)attributeBuffer);
1208 attributeBuffer = (struct timespec *)attributeBuffer + 1;
1209 }
1210 }
1211 if ( a & ATTR_CMN_FNDRINFO ) {
1212 bcopy( attributeBuffer, searchInfo->finderInfo, sizeof(searchInfo->finderInfo) );
1213 attributeBuffer = (u_int8_t *)attributeBuffer + 32;
1214 }
1215 if ( a & ATTR_CMN_OWNERID ) {
1216 searchInfo->uid = *((uid_t *)attributeBuffer);
1217 attributeBuffer = (uid_t *)attributeBuffer + 1;
1218 }
1219 if ( a & ATTR_CMN_GRPID ) {
1220 searchInfo->gid = *((gid_t *)attributeBuffer);
1221 attributeBuffer = (gid_t *)attributeBuffer + 1;
1222 }
1223 if ( a & ATTR_CMN_ACCESSMASK ) {
1224 searchInfo->mask = *((mode_t *)attributeBuffer);
1225 attributeBuffer = (mode_t *)attributeBuffer + 1;
1226 }
1227 if ( a & ATTR_CMN_FILEID ) {
1228 searchInfo->nodeID = (u_int32_t)*((u_int64_t *) attributeBuffer);
1229 attributeBuffer = (u_int64_t *)attributeBuffer + 1;
1230 }
1231 if ( a & ATTR_CMN_PARENTID ) {
1232 searchInfo->parentDirID = (u_int32_t)*((u_int64_t *) attributeBuffer);
1233 attributeBuffer = (u_int64_t *)attributeBuffer + 1;
1234 }
1235 }
1236
1237 a = alist->dirattr;
1238 if ( a != 0 ) {
1239 if ( a & ATTR_DIR_ENTRYCOUNT ) {
1240 searchInfo->d.numFiles = *((u_int32_t *)attributeBuffer);
1241 attributeBuffer = (u_int32_t *)attributeBuffer + 1;
1242 }
1243 }
1244
1245 a = alist->fileattr;
1246 if ( a != 0 ) {
1247 if ( a & ATTR_FILE_DATALENGTH ) {
1248 searchInfo->f.dataLogicalLength = *((off_t *)attributeBuffer);
1249 attributeBuffer = (off_t *)attributeBuffer + 1;
1250 }
1251 if ( a & ATTR_FILE_DATAALLOCSIZE ) {
1252 searchInfo->f.dataPhysicalLength = *((off_t *)attributeBuffer);
1253 attributeBuffer = (off_t *)attributeBuffer + 1;
1254 }
1255 if ( a & ATTR_FILE_RSRCLENGTH ) {
1256 searchInfo->f.resourceLogicalLength = *((off_t *)attributeBuffer);
1257 attributeBuffer = (off_t *)attributeBuffer + 1;
1258 }
1259 if ( a & ATTR_FILE_RSRCALLOCSIZE ) {
1260 searchInfo->f.resourcePhysicalLength = *((off_t *)attributeBuffer);
1261 attributeBuffer = (off_t *)attributeBuffer + 1;
1262 }
1263 }
1264
1265 return (0);
1266}
1267