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