|
|
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.