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