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