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