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