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