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