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 1268