|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* @(#)hfs_search.c ! 23: * ! 24: * (c) 1997-2000 Apple Computer, Inc. All Rights Reserved ! 25: * ! 26: * ! 27: * MODIFICATION HISTORY: ! 28: * 04-May-1999 Don Brady Split off from hfs_vnodeops.c. ! 29: */ ! 30: ! 31: #include <sys/param.h> ! 32: #include <sys/systm.h> ! 33: #include <sys/kernel.h> ! 34: #include <sys/file.h> ! 35: #include <sys/buf.h> ! 36: #include <sys/proc.h> ! 37: #include <sys/conf.h> ! 38: #include <mach/machine/vm_types.h> ! 39: #include <sys/vnode.h> ! 40: #include <sys/malloc.h> ! 41: #include <sys/signalvar.h> ! 42: #include <sys/attr.h> ! 43: ! 44: #include "hfs.h" ! 45: #include "hfs_dbg.h" ! 46: #include "hfscommon/headers/FileMgrInternal.h" ! 47: #include "hfscommon/headers/CatalogPrivate.h" ! 48: #include "hfscommon/headers/HFSUnicodeWrappers.h" ! 49: ! 50: ! 51: /* Private description used in hfs_search */ ! 52: struct SearchState { ! 53: long searchBits; ! 54: BTreeIterator btreeIterator; ! 55: short vRefNum; /* Volume reference of volume being searched */ ! 56: char isHFSPlus; /* True if volume is HFS */ ! 57: char pad1[3]; /* long align the structure */ ! 58: }; ! 59: typedef struct SearchState SearchState; ! 60: ! 61: ! 62: static int UnpackSearchAttributeBlock(struct vnode *vp, struct attrlist *alist, searchinfospec_t *searchInfo, void *attributeBuffer); ! 63: ! 64: Boolean CheckCriteria( ExtendedVCB *vcb, const SearchState *searchState, u_long searchBits, struct attrlist *attrList, CatalogRecord *catalogRecord, CatalogKey *key, searchinfospec_t *searchInfo1, searchinfospec_t *searchInfo2 ); ! 65: ! 66: static int InsertMatch( struct vnode *vp, struct uio *a_uio, CatalogRecord *catalogRecord, CatalogKey *key, struct attrlist *returnAttrList, void *attributesBuffer, void *variableBuffer, u_long bufferSize, u_long * nummatches ); ! 67: ! 68: static Boolean CompareRange(u_long val, u_long low, u_long high); ! 69: static Boolean CompareWideRange(u_int64_t val, u_int64_t low, u_int64_t high); ! 70: ! 71: static Boolean CompareRange( u_long val, u_long low, u_long high ) ! 72: { ! 73: return( (val >= low) && (val <= high) ); ! 74: } ! 75: ! 76: static Boolean CompareWideRange( u_int64_t val, u_int64_t low, u_int64_t high ) ! 77: { ! 78: return( (val >= low) && (val <= high) ); ! 79: } ! 80: //#define CompareRange(val, low, high) ((val >= low) && (val <= high)) ! 81: ! 82: ! 83: ! 84: /************************************************************************/ ! 85: /* Entry for searchfs() */ ! 86: /************************************************************************/ ! 87: ! 88: #define errSearchBufferFull 101 /* Internal search errors */ ! 89: /* ! 90: # ! 91: #% searchfs vp L L L ! 92: # ! 93: vop_searchfs { ! 94: IN struct vnode *vp; ! 95: IN off_t length; ! 96: IN int flags; ! 97: IN struct ucred *cred; ! 98: IN struct proc *p; ! 99: }; ! 100: */ ! 101: ! 102: int ! 103: hfs_search( ap ) ! 104: struct vop_searchfs_args *ap; /* ! 105: struct vnodeop_desc *a_desc; ! 106: struct vnode *a_vp; ! 107: void *a_searchparams1; ! 108: void *a_searchparams2; ! 109: struct attrlist *a_searchattrs; ! 110: u_long a_maxmatches; ! 111: struct timeval *a_timelimit; ! 112: struct attrlist *a_returnattrs; ! 113: u_long *a_nummatches; ! 114: u_long a_scriptcode; ! 115: u_long a_options; ! 116: struct uio *a_uio; ! 117: struct searchstate *a_searchstate; ! 118: */ ! 119: { ! 120: CatalogRecord catalogRecord; ! 121: BTreeKey *key; ! 122: FSBufferDescriptor btRecord; ! 123: FCB* catalogFCB; ! 124: SearchState *searchState; ! 125: searchinfospec_t searchInfo1; ! 126: searchinfospec_t searchInfo2; ! 127: void *attributesBuffer; ! 128: void *variableBuffer; ! 129: short recordSize; ! 130: short operation; ! 131: u_long fixedBlockSize; ! 132: u_long eachReturnBufferSize; ! 133: struct proc *p = current_proc(); ! 134: u_long nodesToCheck = 30; /* After we search 30 nodes we must give up time */ ! 135: u_long lastNodeNum = 0XFFFFFFFF; ! 136: ExtendedVCB *vcb = VTOVCB(ap->a_vp); ! 137: int err = E_NONE; ! 138: ! 139: /* XXX Parameter check a_searchattrs? */ ! 140: ! 141: *(ap->a_nummatches) = 0; ! 142: ! 143: if ( ap->a_options & ~SRCHFS_VALIDOPTIONSMASK ) ! 144: return( EINVAL ); ! 145: ! 146: if (ap->a_uio->uio_resid <= 0) ! 147: return (EINVAL); ! 148: ! 149: searchState = (SearchState *)ap->a_searchstate; ! 150: ! 151: /* ! 152: * Check if this is the first time we are being called. ! 153: * If it is, allocate SearchState and we'll move it to the users space on exit ! 154: */ ! 155: if ( ap->a_options & SRCHFS_START ) { ! 156: bzero( (caddr_t)searchState, sizeof(SearchState) ); ! 157: searchState->isHFSPlus = ( vcb->vcbSigWord == kHFSPlusSigWord ); ! 158: operation = kBTreeFirstRecord; ! 159: ap->a_options &= ~SRCHFS_START; ! 160: } else { ! 161: operation = kBTreeCurrentRecord; ! 162: } ! 163: ! 164: /* UnPack the search boundries, searchInfo1, searchInfo2 */ ! 165: err = UnpackSearchAttributeBlock( ap->a_vp, ap->a_searchattrs, &searchInfo1, ap->a_searchparams1 ); ! 166: if (err) return err; ! 167: err = UnpackSearchAttributeBlock( ap->a_vp, ap->a_searchattrs, &searchInfo2, ap->a_searchparams2 ); ! 168: if (err) return err; ! 169: ! 170: btRecord.itemCount = 1; ! 171: btRecord.itemSize = sizeof( catalogRecord ); ! 172: btRecord.bufferAddress = &catalogRecord; ! 173: catalogFCB = VTOFCB( vcb->catalogRefNum ); ! 174: key = (BTreeKey*) &(searchState->btreeIterator.key); ! 175: fixedBlockSize = sizeof(u_long) + AttributeBlockSize( ap->a_returnattrs ); /* u_long for length longword */ ! 176: eachReturnBufferSize = fixedBlockSize; ! 177: ! 178: if ( ap->a_returnattrs->commonattr & ATTR_CMN_NAME ) /* XXX should be more robust! */ ! 179: eachReturnBufferSize += NAME_MAX + 1; ! 180: ! 181: MALLOC( attributesBuffer, void *, eachReturnBufferSize, M_TEMP, M_WAITOK ); ! 182: variableBuffer = (void*)((char*) attributesBuffer + fixedBlockSize); ! 183: ! 184: /* Lock catalog b-tree */ ! 185: err = hfs_metafilelocking( VTOHFS(ap->a_vp), kHFSCatalogFileID, LK_SHARED, p ); ! 186: if ( err != E_NONE ) { ! 187: goto ExitThisRoutine; ! 188: }; ! 189: ! 190: /* ! 191: * Iterate over all the catalog btree records ! 192: */ ! 193: ! 194: err = BTIterateRecord( catalogFCB, operation, &(searchState->btreeIterator), &btRecord, &recordSize ); ! 195: ! 196: while( err == E_NONE ) { ! 197: if ( CheckCriteria( vcb, searchState, ap->a_options, ap->a_searchattrs, &catalogRecord, ! 198: (CatalogKey *)key, &searchInfo1, &searchInfo2 ) == true ) { ! 199: err = InsertMatch(ap->a_vp, ap->a_uio, &catalogRecord, (CatalogKey *)key, ! 200: ap->a_returnattrs, attributesBuffer, variableBuffer, ! 201: eachReturnBufferSize, ap->a_nummatches); ! 202: if ( err != E_NONE ) ! 203: break; ! 204: } ! 205: ! 206: err = BTIterateRecord( catalogFCB, kBTreeNextRecord, &(searchState->btreeIterator), &btRecord, &recordSize ); ! 207: ! 208: if ( *(ap->a_nummatches) >= ap->a_maxmatches ) ! 209: break; ! 210: ! 211: if ( searchState->btreeIterator.hint.nodeNum != lastNodeNum ) { ! 212: lastNodeNum = searchState->btreeIterator.hint.nodeNum; ! 213: if ( --nodesToCheck == 0 ) ! 214: break; /* We must leave the kernel to give up time */ ! 215: } ! 216: } ! 217: ! 218: /* Unlock catalog b-tree */ ! 219: (void) hfs_metafilelocking( VTOHFS(ap->a_vp), kHFSCatalogFileID, LK_RELEASE, p ); ! 220: ! 221: ! 222: if ( err == E_NONE ) { ! 223: err = EAGAIN; /* signal to the user to call searchfs again */ ! 224: } else if ( err == errSearchBufferFull ) { ! 225: if ( *(ap->a_nummatches) > 0 ) ! 226: err = EAGAIN; ! 227: else ! 228: err = ENOBUFS; ! 229: } else if ( err == btNotFound ) { ! 230: err = E_NONE; /* the entire disk has been searched */ ! 231: } ! 232: ! 233: ExitThisRoutine: ! 234: FREE( attributesBuffer, M_TEMP ); ! 235: ! 236: return( err ); ! 237: } ! 238: ! 239: ! 240: static Boolean ! 241: CompareMasked(const UInt32 *thisValue, const UInt32 *compareData, ! 242: const UInt32 *compareMask, UInt32 count) ! 243: { ! 244: Boolean matched; ! 245: UInt32 i; ! 246: ! 247: matched = true; /* Assume it will all match */ ! 248: ! 249: for (i=0; i<count; i++) { ! 250: if (((*thisValue++ ^ *compareData++) & *compareMask++) != 0) { ! 251: matched = false; ! 252: break; ! 253: } ! 254: } ! 255: ! 256: return matched; ! 257: } ! 258: ! 259: ! 260: static Boolean ! 261: ComparePartialUnicodeName (register ConstUniCharArrayPtr str, register ItemCount s_len, ! 262: register ConstUniCharArrayPtr find, register ItemCount f_len ) ! 263: { ! 264: if (f_len == 0 || s_len == 0) ! 265: return FALSE; ! 266: ! 267: do { ! 268: if (s_len-- < f_len) ! 269: return FALSE; ! 270: } while (FastUnicodeCompare(str++, f_len, find, f_len) != 0); ! 271: ! 272: return TRUE; ! 273: } ! 274: ! 275: ! 276: static Boolean ! 277: ComparePartialPascalName ( register ConstStr31Param str, register ConstStr31Param find ) ! 278: { ! 279: register u_char s_len = str[0]; ! 280: register u_char f_len = find[0]; ! 281: register u_char *tsp; ! 282: Str31 tmpstr; ! 283: ! 284: if (f_len == 0 || s_len == 0) ! 285: return FALSE; ! 286: ! 287: bcopy(str, tmpstr, s_len + 1); ! 288: tsp = &tmpstr[0]; ! 289: ! 290: while (s_len-- >= f_len) { ! 291: *tsp = f_len; ! 292: ! 293: if (FastRelString(tsp++, find) == 0) ! 294: return TRUE; ! 295: } ! 296: ! 297: return FALSE; ! 298: } ! 299: ! 300: ! 301: Boolean ! 302: CheckCriteria( ExtendedVCB *vcb, const SearchState *searchState, u_long searchBits, ! 303: struct attrlist *attrList, CatalogRecord *catalogRecord, CatalogKey *key, ! 304: searchinfospec_t *searchInfo1, searchinfospec_t *searchInfo2 ) ! 305: { ! 306: Boolean matched; ! 307: CatalogNodeData catData; ! 308: attrgroup_t searchAttributes; ! 309: ! 310: switch ( catalogRecord->recordType ) { ! 311: case kHFSFolderRecord: ! 312: case kHFSPlusFolderRecord: ! 313: if ( (searchBits & SRCHFS_MATCHDIRS) == 0 ) { /* If we are NOT searching folders */ ! 314: matched = false; ! 315: goto TestDone; ! 316: } ! 317: break; ! 318: ! 319: case kHFSFileRecord: ! 320: case kHFSPlusFileRecord: ! 321: if ( (searchBits & SRCHFS_MATCHFILES) == 0 ) { /* If we are NOT searching files */ ! 322: matched = false; ! 323: goto TestDone; ! 324: } ! 325: break; ! 326: ! 327: default: /* Never match a thread record or any other type. */ ! 328: return( false ); /* Not a file or folder record, so can't search it */ ! 329: } ! 330: ! 331: /* Change the catalog record data into a single common form */ ! 332: matched = true; /* Assume we got a match */ ! 333: catData.cnd_type = 0; /* mark this record as not in use */ ! 334: CopyCatalogNodeData( vcb, catalogRecord, &catData ); ! 335: ! 336: /* First, attempt to match the name -- either partial or complete */ ! 337: if ( attrList->commonattr & ATTR_CMN_NAME ) { ! 338: if ( searchState->isHFSPlus ) { ! 339: /* Check for partial/full HFS Plus name match */ ! 340: ! 341: if ( searchBits & SRCHFS_MATCHPARTIALNAMES ) { ! 342: matched = ComparePartialUnicodeName(key->hfsPlus.nodeName.unicode, ! 343: key->hfsPlus.nodeName.length, ! 344: (UniChar*)searchInfo1->name, ! 345: searchInfo1->nameLength ); ! 346: } else /* full HFS Plus name match */ { ! 347: matched = (FastUnicodeCompare(key->hfsPlus.nodeName.unicode, ! 348: key->hfsPlus.nodeName.length, ! 349: (UniChar*)searchInfo1->name, ! 350: searchInfo1->nameLength ) == 0); ! 351: } ! 352: } else { ! 353: /* Check for partial/full HFS name match */ ! 354: ! 355: if ( searchBits & SRCHFS_MATCHPARTIALNAMES ) ! 356: matched = ComparePartialPascalName(key->hfs.nodeName, (u_char*)searchInfo1->name); ! 357: else /* full HFS name match */ ! 358: matched = (FastRelString(key->hfs.nodeName, (u_char*)searchInfo1->name) == 0); ! 359: } ! 360: ! 361: if ( matched == false || (searchBits & ~SRCHFS_MATCHPARTIALNAMES) == 0 ) ! 362: goto TestDone; /* no match, or nothing more to compare */ ! 363: } ! 364: ! 365: ! 366: /* Now that we have a record worth searching, see if it matches the search attributes */ ! 367: if ( (catData.cnd_type == kCatalogFileNode) && ((attrList->fileattr & ATTR_FILE_VALIDMASK) != 0) ) ! 368: { ! 369: searchAttributes = attrList->fileattr; ! 370: ! 371: /* File logical length (data fork) */ ! 372: if ( searchAttributes & ATTR_FILE_DATALENGTH ) { ! 373: matched = CompareWideRange( ! 374: catData.cnd_datafork.logicalSize, ! 375: searchInfo1->f.dataLogicalLength, ! 376: searchInfo2->f.dataLogicalLength); ! 377: if (matched == false) goto TestDone; ! 378: } ! 379: ! 380: /* File physical length (data fork) */ ! 381: if ( searchAttributes & ATTR_FILE_DATAALLOCSIZE ) { ! 382: matched = CompareWideRange( ! 383: catData.cnd_datafork.totalBlocks * vcb->blockSize, ! 384: searchInfo1->f.dataPhysicalLength, ! 385: searchInfo2->f.dataPhysicalLength); ! 386: if (matched == false) goto TestDone; ! 387: } ! 388: ! 389: /* File logical length (resource fork) */ ! 390: if ( searchAttributes & ATTR_FILE_RSRCLENGTH ) { ! 391: matched = CompareWideRange( ! 392: catData.cnd_rsrcfork.logicalSize, ! 393: searchInfo1->f.resourceLogicalLength, ! 394: searchInfo2->f.resourceLogicalLength); ! 395: if (matched == false) goto TestDone; ! 396: } ! 397: ! 398: /* File physical length (resource fork) */ ! 399: if ( searchAttributes & ATTR_FILE_RSRCALLOCSIZE ) { ! 400: matched = CompareWideRange( ! 401: catData.cnd_rsrcfork.totalBlocks * vcb->blockSize, ! 402: searchInfo1->f.resourcePhysicalLength, ! 403: searchInfo2->f.resourcePhysicalLength); ! 404: if (matched == false) goto TestDone; ! 405: } ! 406: ! 407: /* File logical length (resource + data fork) */ ! 408: if ( searchAttributes & ATTR_FILE_TOTALSIZE ) { ! 409: matched = CompareWideRange( ! 410: catData.cnd_rsrcfork.logicalSize + ! 411: catData.cnd_datafork.logicalSize, ! 412: searchInfo1->f.resourceLogicalLength + searchInfo1->f.dataLogicalLength, ! 413: searchInfo2->f.resourceLogicalLength + searchInfo2->f.dataLogicalLength); ! 414: if (matched == false) goto TestDone; ! 415: } ! 416: ! 417: /* File physical length (resource + data fork) */ ! 418: if ( searchAttributes & ATTR_FILE_TOTALSIZE ) { ! 419: matched = CompareWideRange( ! 420: (catData.cnd_rsrcfork.totalBlocks + ! 421: catData.cnd_datafork.totalBlocks) * vcb->blockSize, ! 422: searchInfo1->f.resourcePhysicalLength + searchInfo1->f.dataPhysicalLength, ! 423: searchInfo2->f.resourcePhysicalLength + searchInfo2->f.dataPhysicalLength ); ! 424: if (matched == false) goto TestDone; ! 425: } ! 426: } ! 427: /* ! 428: * Check the directory attributes ! 429: */ ! 430: else if ( (catData.cnd_type == kCatalogFolderNode) && ((attrList->dirattr & ATTR_DIR_VALIDMASK) != 0) ) ! 431: { ! 432: searchAttributes = attrList->dirattr; ! 433: ! 434: /* Directory valence */ ! 435: if ( searchAttributes & ATTR_DIR_ENTRYCOUNT ) { ! 436: matched = CompareRange(catData.cnd_valence, searchInfo1->d.numFiles, searchInfo2->d.numFiles ); ! 437: if (matched == false) goto TestDone; ! 438: } ! 439: } ! 440: ! 441: /* ! 442: * Check the common attributes ! 443: */ ! 444: searchAttributes = attrList->commonattr; ! 445: if ( (searchAttributes & ATTR_CMN_VALIDMASK) != 0 ) { ! 446: ! 447: /* Parent ID */ ! 448: if ( searchAttributes & ATTR_CMN_PAROBJID ) { ! 449: HFSCatalogNodeID parentID; ! 450: ! 451: if (searchState->isHFSPlus) ! 452: parentID = key->hfsPlus.parentID; ! 453: else ! 454: parentID = key->hfs.parentID; ! 455: ! 456: matched = CompareRange( parentID, searchInfo1->parentDirID, searchInfo2->parentDirID ); ! 457: if (matched == false) goto TestDone; ! 458: } ! 459: ! 460: /* Finder Info & Extended Finder Info where extFinderInfo is last 32 bytes */ ! 461: if ( searchAttributes & ATTR_CMN_FNDRINFO ) { ! 462: UInt32 *thisValue; ! 463: thisValue = (UInt32 *) &catData.cnd_finderInfo; ! 464: ! 465: /* ! 466: * Note: ioFlFndrInfo and ioDrUsrWds have the same offset in search info, so ! 467: * no need to test the object type here. ! 468: */ ! 469: matched = CompareMasked( thisValue, (UInt32 *) &searchInfo1->finderInfo, (UInt32 *) &searchInfo2->finderInfo, 8 ); /* 8 * UInt32 */ ! 470: if (matched == false) goto TestDone; ! 471: } ! 472: ! 473: /* Create date */ ! 474: if ( searchAttributes & ATTR_CMN_CRTIME ) { ! 475: matched = CompareRange(to_bsd_time(catData.cnd_createDate), ! 476: searchInfo1->creationDate.tv_sec, searchInfo2->creationDate.tv_sec ); ! 477: if (matched == false) goto TestDone; ! 478: } ! 479: ! 480: /* Mod date */ ! 481: if ( searchAttributes & ATTR_CMN_MODTIME ) { ! 482: matched = CompareRange(to_bsd_time(catData.cnd_contentModDate), ! 483: searchInfo1->modificationDate.tv_sec, searchInfo2->modificationDate.tv_sec ); ! 484: if (matched == false) goto TestDone; ! 485: } ! 486: ! 487: /* Backup date */ ! 488: if ( searchAttributes & ATTR_CMN_BKUPTIME ) { ! 489: matched = CompareRange(to_bsd_time(catData.cnd_backupDate), ! 490: searchInfo1->lastBackupDate.tv_sec, searchInfo2->lastBackupDate.tv_sec ); ! 491: if (matched == false) goto TestDone; ! 492: } ! 493: ! 494: } ! 495: ! 496: ! 497: TestDone: ! 498: /* ! 499: * Finally, determine whether we need to negate the sense of the match ! 500: * (i.e. find all objects that DON'T match). ! 501: */ ! 502: if ( searchBits & SRCHFS_NEGATEPARAMS ) ! 503: matched = !matched; ! 504: ! 505: return( matched ); ! 506: } ! 507: ! 508: ! 509: /* ! 510: * Adds another record to the packed array for output ! 511: */ ! 512: static int ! 513: InsertMatch( struct vnode *root_vp, struct uio *a_uio, CatalogRecord *catalogRecord, ! 514: CatalogKey *key, struct attrlist *returnAttrList, void *attributesBuffer, ! 515: void *variableBuffer, u_long bufferSize, u_long * nummatches ) ! 516: { ! 517: int err; ! 518: void *rovingAttributesBuffer; ! 519: void *rovingVariableBuffer; ! 520: struct hfsCatalogInfo catalogInfo; ! 521: u_long packedBufferSize; ! 522: ExtendedVCB *vcb = VTOVCB(root_vp); ! 523: Boolean isHFSPlus = vcb->vcbSigWord == kHFSPlusSigWord; ! 524: u_long privateDir = VTOHFS(root_vp)->hfs_private_metadata_dir; ! 525: ! 526: rovingAttributesBuffer = (char*)attributesBuffer + sizeof(u_long); /* Reserve space for length field */ ! 527: rovingVariableBuffer = variableBuffer; ! 528: ! 529: CopyCatalogNodeData( vcb, catalogRecord, &catalogInfo.nodeData ); ! 530: ! 531: catalogInfo.spec.parID = isHFSPlus ? key->hfsPlus.parentID : key->hfs.parentID; ! 532: ! 533: /* hide open files that have been deleted */ ! 534: if (catalogInfo.spec.parID == privateDir) ! 535: return (0); ! 536: ! 537: /* hide our private meta data directory */ ! 538: if (catalogInfo.nodeData.cnd_nodeID == privateDir) ! 539: return (0); ! 540: ! 541: if ( returnAttrList->commonattr & ATTR_CMN_NAME ) ! 542: { ! 543: ByteCount actualDstLen; ! 544: ! 545: /* Return result in UTF-8 */ ! 546: if ( isHFSPlus ) { ! 547: err = ConvertUnicodeToUTF8( key->hfsPlus.nodeName.length * sizeof(UniChar), ! 548: key->hfsPlus.nodeName.unicode, ! 549: sizeof(catalogInfo.spec.name), ! 550: &actualDstLen, ! 551: catalogInfo.spec.name); ! 552: } else { ! 553: err = hfs_to_utf8(vcb, key->hfs.nodeName, ! 554: sizeof(catalogInfo.spec.name), ! 555: &actualDstLen, catalogInfo.spec.name); ! 556: } ! 557: } ! 558: ! 559: PackCatalogInfoAttributeBlock( returnAttrList,root_vp, &catalogInfo, &rovingAttributesBuffer, &rovingVariableBuffer ); ! 560: ! 561: packedBufferSize = (char*)rovingVariableBuffer - (char*)attributesBuffer; ! 562: ! 563: if ( packedBufferSize > a_uio->uio_resid ) ! 564: return( errSearchBufferFull ); ! 565: ! 566: (* nummatches)++; ! 567: ! 568: *((u_long *)attributesBuffer) = packedBufferSize; /* Store length of fixed + var block */ ! 569: ! 570: err = uiomove( (caddr_t)attributesBuffer, packedBufferSize, a_uio ); /* XXX should be packedBufferSize */ ! 571: ! 572: return( err ); ! 573: } ! 574: ! 575: ! 576: static int ! 577: UnpackSearchAttributeBlock( struct vnode *vp, struct attrlist *alist, searchinfospec_t *searchInfo, void *attributeBuffer ) ! 578: { ! 579: attrgroup_t a; ! 580: u_long bufferSize; ! 581: ! 582: DBG_ASSERT(searchInfo != NULL); ! 583: ! 584: bufferSize = *((u_long *)attributeBuffer); ! 585: if (bufferSize == 0) ! 586: return (EINVAL); /* XXX -DJB is a buffer size of zero ever valid for searchfs? */ ! 587: ! 588: ++((u_long *)attributeBuffer); /* advance past the size */ ! 589: ! 590: /* ! 591: * UnPack common attributes ! 592: */ ! 593: a = alist->commonattr; ! 594: if ( a != 0 ) { ! 595: if ( a & ATTR_CMN_NAME ) { ! 596: char *s = (char*) attributeBuffer + ((attrreference_t *) attributeBuffer)->attr_dataoffset; ! 597: size_t len = ((attrreference_t *) attributeBuffer)->attr_length; ! 598: ! 599: if (len > sizeof(searchInfo->name)) ! 600: return (EINVAL); ! 601: ! 602: if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) { ! 603: ByteCount actualDstLen; ! 604: /* Convert name to Unicode to match HFS Plus B-Tree names */ ! 605: ! 606: if (len > 0) { ! 607: if (ConvertUTF8ToUnicode(len-1, s, sizeof(searchInfo->name), ! 608: &actualDstLen, (UniChar*)searchInfo->name) != 0) ! 609: return (EINVAL); ! 610: ! 611: ! 612: searchInfo->nameLength = actualDstLen / sizeof(UniChar); ! 613: } else { ! 614: searchInfo->nameLength = 0; ! 615: } ! 616: ++((attrreference_t *)attributeBuffer); ! 617: ! 618: } else { ! 619: /* Convert name to pascal string to match HFS B-Tree names */ ! 620: ! 621: if (len > 0) { ! 622: if (utf8_to_hfs(VTOVCB(vp), len-1, s, (u_char*)searchInfo->name) != 0) ! 623: return (EINVAL); ! 624: ! 625: searchInfo->nameLength = searchInfo->name[0]; ! 626: } else { ! 627: searchInfo->name[0] = searchInfo->nameLength = 0; ! 628: } ! 629: ++((attrreference_t *)attributeBuffer); ! 630: } ! 631: } ! 632: if ( a & ATTR_CMN_PAROBJID ) { ! 633: searchInfo->parentDirID = ((fsobj_id_t *) attributeBuffer)->fid_objno; /* ignore fid_generation */ ! 634: ++((fsobj_id_t *)attributeBuffer); ! 635: } ! 636: if ( a & ATTR_CMN_CRTIME ) { ! 637: searchInfo->creationDate = *((struct timespec *)attributeBuffer); ! 638: ++((struct timespec *)attributeBuffer); ! 639: } ! 640: if ( a & ATTR_CMN_MODTIME ) { ! 641: searchInfo->modificationDate = *((struct timespec *)attributeBuffer); ! 642: ++((struct timespec *)attributeBuffer); ! 643: } ! 644: if ( a & ATTR_CMN_BKUPTIME ) { ! 645: searchInfo->lastBackupDate = *((struct timespec *)attributeBuffer); ! 646: ++((struct timespec *)attributeBuffer); ! 647: } ! 648: if ( a & ATTR_CMN_FNDRINFO ) { ! 649: bcopy( attributeBuffer, searchInfo->finderInfo, sizeof(u_long) * 8 ); ! 650: attributeBuffer += (sizeof(u_long) * 8 ); ! 651: } ! 652: } ! 653: ! 654: a = alist->dirattr; ! 655: if ( a != 0 ) { ! 656: if ( a & ATTR_DIR_ENTRYCOUNT ) { ! 657: searchInfo->d.numFiles = *((u_long *)attributeBuffer); ! 658: ++((u_long *)attributeBuffer); ! 659: } ! 660: } ! 661: ! 662: a = alist->fileattr; ! 663: if ( a != 0 ) { ! 664: if ( a & ATTR_FILE_DATALENGTH ) { ! 665: searchInfo->f.dataLogicalLength = *((off_t *)attributeBuffer); ! 666: ++((off_t *)attributeBuffer); ! 667: } ! 668: if ( a & ATTR_FILE_DATAALLOCSIZE ) { ! 669: searchInfo->f.dataPhysicalLength = *((off_t *)attributeBuffer); ! 670: ++((off_t *)attributeBuffer); ! 671: } ! 672: if ( a & ATTR_FILE_RSRCLENGTH ) { ! 673: searchInfo->f.resourceLogicalLength = *((off_t *)attributeBuffer); ! 674: ++((off_t *)attributeBuffer); ! 675: } ! 676: if ( a & ATTR_FILE_RSRCALLOCSIZE ) { ! 677: searchInfo->f.resourcePhysicalLength = *((off_t *)attributeBuffer); ! 678: ++((off_t *)attributeBuffer); ! 679: } ! 680: } ! 681: ! 682: return (0); ! 683: } ! 684: ! 685:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.