]> git.saurik.com Git - apple/xnu.git/blob - bsd/hfs/hfs_search.c
b73ec833904d5ef642dd759d013f1dca295c4508
[apple/xnu.git] / bsd / hfs / hfs_search.c
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. */
72 struct directoryInfoSpec
73 {
74 u_int32_t numFiles;
75 };
76
77 struct fileInfoSpec
78 {
79 off_t dataLogicalLength;
80 off_t dataPhysicalLength;
81 off_t resourceLogicalLength;
82 off_t resourcePhysicalLength;
83 };
84
85 struct 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 };
104 typedef struct searchinfospec searchinfospec_t;
105
106 static void ResolveHardlink(struct hfsmount *hfsmp, HFSPlusCatalogFile *recp);
107
108
109 static int UnpackSearchAttributeBlock(struct hfsmount *hfsmp, struct attrlist *alist,
110 searchinfospec_t *searchInfo, void *attributeBuffer, int firstblock);
111
112 static 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
120 static int CheckAccess(ExtendedVCB *vcb, u_long searchBits, CatalogKey *key, struct vfs_context *ctx);
121
122 static 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
127 static Boolean CompareRange(u_long val, u_long low, u_long high);
128 static Boolean CompareWideRange(u_int64_t val, u_int64_t low, u_int64_t high);
129
130 static Boolean CompareRange( u_long val, u_long low, u_long high )
131 {
132 return( (val >= low) && (val <= high) );
133 }
134
135 static 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 #
151 vnop_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
160 int
161 hfs_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
426 ExitThisRoutine:
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
438 static void
439 ResolveHardlink(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
480 static Boolean
481 CompareMasked(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
500 static Boolean
501 ComparePartialUnicodeName (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
516 static Boolean
517 ComparePartialPascalName ( 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
545 static int
546 CheckAccess(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
634 ExitThisRoutine:
635 if ( vp != NULL ) {
636 hfs_unlock(VTOC(vp));
637 vnode_put(vp);
638 }
639 return ( myResult );
640
641 }
642
643 static int
644 CheckCriteria( 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
1002 TestDone:
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 */
1017 static int
1018 InsertMatch(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 );
1084 exit:
1085 cat_releasedesc(&c_desc);
1086
1087 return( err );
1088 }
1089
1090
1091 static int
1092 UnpackSearchAttributeBlock( 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 */