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