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