]> git.saurik.com Git - apple/xnu.git/blob - bsd/hfs/hfscommon/Catalog/CatalogIterators.c
xnu-344.21.73.tar.gz
[apple/xnu.git] / bsd / hfs / hfscommon / Catalog / CatalogIterators.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 File: CatalogIterators.c
27
28 Contains: Catalog Iterator Implementation
29
30 Version: HFS Plus 1.0
31
32 Copyright: © 1997-1998 by Apple Computer, Inc., all rights reserved.
33
34 File Ownership:
35
36 DRI: Don Brady
37
38 Other Contact: Mark Day
39
40 Technology: Mac OS File System
41
42 Writers:
43
44 (msd) Mark Day
45 (djb) Don Brady
46
47 Change History (most recent first):
48 <MacOSX> 4/23/98 djb Re-enable InvalidateCatalogCache (was commented out).
49 <MacOSX> 4/6/98 djb Add locking for cache globals (list) and iterators.
50 <MacOSX> 4/2/98 djb Define gCatalogCacheGlobals here instead of FSVars.
51 <MacOSX> 3/31/98 djb Sync up with final HFSVolumes.h header file.
52
53 <CS3> 11/13/97 djb Radar #1683572 - Fix for indexed GetFileInfo.
54 <CS2> 10/17/97 msd Bug 1683506. Add support for long Unicode names in
55 CatalogIterators. Added a single global buffer for long Unicode
56 names; it is used by at most one CatalogIterator at a time.
57 <CS1> 10/1/97 djb first checked in
58 */
59
60
61 #include "../../hfs_macos_defs.h"
62 #include "../../hfs.h"
63 #include "../../hfs_dbg.h"
64 #include "../../hfs_format.h"
65
66 #include "../headers/FileMgrInternal.h"
67 #include "../headers/BTreesInternal.h"
68 #include "../headers/CatalogPrivate.h"
69
70
71 #include <sys/param.h>
72 #include <sys/systm.h>
73 #include <libkern/libkern.h>
74 #include <sys/lock.h>
75
76 static void InsertCatalogIteratorAsMRU( CatalogCacheGlobals *cacheGlobals, CatalogIterator *iterator );
77
78 static void InsertCatalogIteratorAsLRU( CatalogCacheGlobals *cacheGlobals, CatalogIterator *iterator );
79
80 static void PrepareForLongName( CatalogIterator *iterator );
81
82
83 #if TARGET_API_MACOS_X
84 CatalogCacheGlobals *gCatalogCacheGlobals;
85
86 #define GetCatalogCacheGlobals() (gCatalogCacheGlobals)
87
88 #define CATALOG_ITER_LIST_LOCK(g) simple_lock(&(g)->simplelock)
89
90 #define CATALOG_ITER_LIST_UNLOCK(g) simple_unlock(&(g)->simplelock)
91
92 #define CI_LOCK(i) lockmgr(&(i)->iterator_lock, LK_EXCLUSIVE, (simple_lock_t) 0, current_proc())
93
94 #define CI_UNLOCK(i) lockmgr(&(i)->iterator_lock, LK_RELEASE, (simple_lock_t) 0, current_proc())
95
96 #define CI_SLEEPLESS_LOCK(i) lockmgr(&(i)->iterator_lock, LK_EXCLUSIVE | LK_NOWAIT, (simple_lock_t) 0, current_proc())
97
98 #define CI_LOCK_FROM_LIST(g,i) lockmgr(&(i)->iterator_lock, LK_EXCLUSIVE | LK_INTERLOCK, &(g)->simplelock, current_proc())
99
100 #else /* TARGET_API_MACOS_X */
101
102 #define GetCatalogCacheGlobals() ((CatalogCacheGlobals*) ((FSVarsRec*) LMGetFSMVars()->gCatalogCacheGlobals))
103
104 #define CATALOG_ITER_LIST_LOCK(g)
105
106 #define CATALOG_ITER_LIST_UNLOCK(g)
107
108 #define CI_LOCK(i) 0
109
110 #define CI_UNLOCK(i) 0
111
112 #define CI_SLEEPLESS_LOCK(i) 0
113
114 #define CI_LOCK_FROM_LIST(g,i) 0
115
116 #endif
117
118
119 //_______________________________________________________________________________
120 // Routine: InitCatalogCache
121 //
122 // Function: Allocates cache, and initializes all the cache structures.
123 //
124 //_______________________________________________________________________________
125 OSErr
126 InitCatalogCache(void)
127 {
128 CatalogCacheGlobals * cacheGlobals;
129 CatalogIterator * iterator;
130 UInt32 cacheSize;
131 UInt16 i;
132 UInt16 lastIterator;
133 OSErr err;
134
135
136 cacheSize = sizeof(CatalogCacheGlobals) + ( kCatalogIteratorCount * sizeof(CatalogIterator) );
137 cacheGlobals = (CatalogCacheGlobals *) NewPtrSysClear( cacheSize );
138
139 cacheGlobals->iteratorCount = kCatalogIteratorCount;
140
141 lastIterator = kCatalogIteratorCount - 1; // last iterator number, since they start at 0
142
143 // Initialize the MRU order for the cache
144 cacheGlobals->mru = (CatalogIterator *) ( (Ptr)cacheGlobals + sizeof(CatalogCacheGlobals) );
145
146 // Initialize the LRU order for the cache
147 cacheGlobals->lru = (CatalogIterator *) ( (Ptr)(cacheGlobals->mru) + (lastIterator * sizeof(CatalogIterator)) );
148
149
150 // Traverse iterators, setting initial mru, lru, and default values
151 for ( i = 0, iterator = cacheGlobals->mru; i < kCatalogIteratorCount ; i++, iterator = iterator->nextMRU )
152 {
153 if ( i == lastIterator )
154 iterator->nextMRU = nil; // terminate the list
155 else
156 iterator->nextMRU = (CatalogIterator *) ( (Ptr)iterator + sizeof(CatalogIterator) );
157
158 if ( i == 0 )
159 iterator->nextLRU = nil; // terminate the list
160 else
161 iterator->nextLRU = (CatalogIterator *) ( (Ptr)iterator - sizeof(CatalogIterator) );
162
163 #if TARGET_API_MACOS_X
164 lockinit(&iterator->iterator_lock, PINOD, "hfs_catalog_iterator", 0, 0);
165 #endif
166 }
167
168 #if TARGET_API_MAC_OS8
169 (FSVarsRec*) LMGetFSMVars()->gCatalogCacheGlobals = (Ptr) cacheGlobals;
170 #endif
171
172 #if TARGET_API_MACOS_X
173 gCatalogCacheGlobals = cacheGlobals;
174 simple_lock_init(&cacheGlobals->simplelock);
175 #endif
176
177 return noErr;
178 }
179
180
181 //_______________________________________________________________________________
182 // Routine: InvalidateCatalogCache
183 //
184 // Function: Trash any interators matching volume parameter
185 //
186 //_______________________________________________________________________________
187 void PrintCatalogIterator( void );
188
189 void
190 InvalidateCatalogCache( ExtendedVCB *volume )
191 {
192 TrashCatalogIterator( volume, 0 );
193 }
194
195
196 //_______________________________________________________________________________
197 // Routine: PrintCatalogIterator
198 //
199 // Function: Prints all interators
200 //
201 //_______________________________________________________________________________
202 #if HFS_DIAGNOSTIC
203 void
204 PrintCatalogIterator( void )
205 {
206 CatalogIterator *iterator;
207 CatalogCacheGlobals *cacheGlobals = GetCatalogCacheGlobals();
208 int i;
209
210 PRINTIT("CatalogCacheGlobals @ 0x%08lX are:\n", (unsigned long)cacheGlobals);
211 PRINTIT("\titeratorCount: %ld \n", cacheGlobals->iteratorCount);
212 PRINTIT("\tmru: 0x%08lX \n", (unsigned long)cacheGlobals->mru);
213 PRINTIT("\tlru: 0x%08lX \n", (unsigned long)cacheGlobals->lru);
214
215 for ( iterator = cacheGlobals->mru, i=0 ; iterator != nil && i<32 ; iterator = iterator->nextMRU, i++)
216 {
217 PRINTIT("%d: ", i);
218 PRINTIT(" i: 0x%08lX", (unsigned long)iterator);
219 PRINTIT(" M: 0x%08lX", (unsigned long)iterator->nextMRU);
220 PRINTIT(" L: 0x%08lX", (unsigned long)iterator->nextLRU);
221 PRINTIT("\n");
222 }
223 }
224 #endif
225
226 //_______________________________________________________________________________
227 // Routine: TrashCatalogIterator
228 //
229 // Function: Trash any interators matching volume and folder parameters
230 //
231 //_______________________________________________________________________________
232 void
233 TrashCatalogIterator( const ExtendedVCB *volume, HFSCatalogNodeID folderID )
234 {
235 CatalogIterator *iterator;
236 CatalogCacheGlobals *cacheGlobals = GetCatalogCacheGlobals();
237
238 CATALOG_ITER_LIST_LOCK(cacheGlobals);
239
240 for ( iterator = cacheGlobals->mru ; iterator != nil ; iterator = iterator->nextMRU )
241 {
242 top:
243
244 // first match the volume
245 if ( iterator->volume != volume )
246 continue;
247
248 // now match the folder (or all folders if 0)
249 if ( (folderID == 0) || (folderID == iterator->folderID) )
250 {
251 CatalogIterator *next;
252
253 iterator->volume = 0; // trash it
254 iterator->folderID = 0;
255
256 next = iterator->nextMRU; // remember the next iterator
257
258 // if iterator is not already last then make it last
259 if ( next != nil )
260 {
261 InsertCatalogIteratorAsLRU( cacheGlobals, iterator );
262
263 // iterator->nextMRU will always be zero (since we moved it to the end)
264 // so set up the next iterator manually (we know its not nil)
265 iterator = next;
266 goto top; // process the next iterator
267 }
268 }
269 }
270
271 CATALOG_ITER_LIST_UNLOCK(cacheGlobals);
272 }
273
274
275 //_______________________________________________________________________________
276 // Routine: AgeCatalogIterator
277 //
278 // Function: Move iterator to the end of the list...
279 //
280 //_______________________________________________________________________________
281 void
282 AgeCatalogIterator ( CatalogIterator *catalogIterator )
283 {
284 CatalogCacheGlobals * cacheGlobals = GetCatalogCacheGlobals();
285
286 CATALOG_ITER_LIST_LOCK(cacheGlobals);
287
288 //PRINTIT(" AgeCatalogIterator: v=%d, d=%ld, i=%d\n", catalogIterator->volRefNum, catalogIterator->folderID, catalogIterator->currentIndex);
289
290 InsertCatalogIteratorAsLRU( cacheGlobals, catalogIterator );
291
292 CATALOG_ITER_LIST_UNLOCK(cacheGlobals);
293 }
294
295
296 //_______________________________________________________________________________
297 // Routine: GetCatalogIterator
298 //
299 // Function: Release interest in Catalog iterator
300 //
301 //_______________________________________________________________________________
302 OSErr
303 ReleaseCatalogIterator( CatalogIterator* catalogIterator)
304 {
305 #if TARGET_API_MACOS_X
306 //PRINTIT(" ReleaseCatalogIterator: v=%d, d=%ld, i=%d\n", catalogIterator->volRefNum, catalogIterator->folderID, catalogIterator->currentIndex);
307 return CI_UNLOCK(catalogIterator);
308 #else
309 return noErr;
310 #endif
311 }
312
313
314 //_______________________________________________________________________________
315 // Routine: GetCatalogIterator
316 //
317 // Function: Returns an iterator associated with the volume, folderID, index,
318 // and iterationType (kIterateFilesOnly or kIterateAll).
319 // Searches the cache in MRU order.
320 // Inserts the resulting iterator at the head of mru automatically
321 //
322 // Note: The returned iterator is locked and ReleaseCatalogIterator must
323 // be called to unlock it.
324 //
325 //_______________________________________________________________________________
326
327 CatalogIterator*
328 GetCatalogIterator(ExtendedVCB *volume, HFSCatalogNodeID folderID, UInt32 offset)
329 {
330 CatalogCacheGlobals *cacheGlobals = GetCatalogCacheGlobals();
331 CatalogIterator *iterator;
332 CatalogIterator *bestIterator;
333
334 bestIterator = NULL;
335
336 CATALOG_ITER_LIST_LOCK(cacheGlobals);
337
338 for (iterator = cacheGlobals->mru ; iterator != nil ; iterator = iterator->nextMRU) {
339
340 /* first make sure volume and folder id match */
341 if ((iterator->volume != volume) || (iterator->folderID != folderID)) {
342 continue;
343 }
344
345 /* ignore busy iterators */
346 if ( CI_SLEEPLESS_LOCK(iterator) == EBUSY ) {
347 //PRINTIT(" GetCatalogIterator: busy v=%d, d=%ld, i=%d\n", volume, folderID, iterator->currentIndex);
348 continue;
349 }
350
351 /* we matched volume, folder id, now check the offset */
352 if ( iterator->currentOffset == offset || iterator->nextOffset == offset) {
353 bestIterator = iterator; // we scored! - so get out of this loop
354 break; // break with iterator locked
355 }
356
357 (void) CI_UNLOCK(iterator); // unlock iterator before moving to the next one
358 }
359
360 // check if we didn't get one or if the one we got is too far away...
361 if (bestIterator == NULL)
362 {
363 bestIterator = cacheGlobals->lru; // start over with a new iterator
364
365 //PRINTIT(" GetCatalogIterator: recycle v=%d, d=%ld, i=%d\n", bestIterator->volume, bestIterator->folderID, bestIterator->currentIndex);
366 (void) CI_LOCK_FROM_LIST(cacheGlobals, bestIterator); // XXX we should not eat the error!
367
368 CATALOG_ITER_LIST_LOCK(cacheGlobals); // grab the lock again for MRU Insert below...
369
370 bestIterator->volume = volume; // update the iterator's volume
371 bestIterator->folderID = folderID; // ... and folderID
372 bestIterator->currentIndex = 0xFFFFFFFF; // ... and offspring index marker
373 bestIterator->currentOffset = 0xFFFFFFFF;
374 bestIterator->nextOffset = 0xFFFFFFFF;
375
376 bestIterator->btreeNodeHint = 0;
377 bestIterator->btreeIndexHint = 0;
378 bestIterator->parentID = folderID; // set key to folderID + empty name
379 bestIterator->folderName.unicodeName.length = 0; // clear pascal/unicode name
380
381 if ( volume->vcbSigWord == kHFSPlusSigWord )
382 bestIterator->nameType = kShortUnicodeName;
383 else
384 bestIterator->nameType = kShortPascalName;
385 }
386 else {
387 //PRINTIT(" GetCatalogIterator: found v=%d, d=%ld, i=%d\n", bestIterator->volume, bestIterator->folderID, bestIterator->currentIndex);
388 }
389
390 // put this iterator at the front of the list
391 InsertCatalogIteratorAsMRU( cacheGlobals, bestIterator );
392
393 CATALOG_ITER_LIST_UNLOCK(cacheGlobals);
394
395 return bestIterator; // return our best shot
396
397 } /* GetCatalogIterator */
398
399
400 //_______________________________________________________________________________
401 // Routine: UpdateBtreeIterator
402 //
403 // Function: Fills in a BTreeIterator from a CatalogIterator
404 //
405 // Assumes: catalogIterator->nameType is correctly initialized!
406 // catalogIterator is locked (MacOS X)
407 //_______________________________________________________________________________
408 void
409 UpdateBtreeIterator(const CatalogIterator *catalogIterator, BTreeIterator *btreeIterator)
410 {
411 CatalogName * nodeName;
412 Boolean isHFSPlus;
413
414
415 btreeIterator->hint.writeCount = 0;
416 btreeIterator->hint.nodeNum = catalogIterator->btreeNodeHint;
417 btreeIterator->hint.index = catalogIterator->btreeIndexHint;
418
419 switch (catalogIterator->nameType)
420 {
421 case kShortPascalName:
422 if ( catalogIterator->folderName.pascalName[0] > 0 )
423 nodeName = (CatalogName *) catalogIterator->folderName.pascalName;
424 else
425 nodeName = NULL;
426
427 isHFSPlus = false;
428 break;
429
430 case kShortUnicodeName:
431 if ( catalogIterator->folderName.unicodeName.length > 0 )
432 nodeName = (CatalogName *) &catalogIterator->folderName.unicodeName;
433 else
434 nodeName = NULL;
435
436 isHFSPlus = true;
437 break;
438
439 case kLongUnicodeName:
440 if ( catalogIterator->folderName.longNamePtr->length > 0 )
441 nodeName = (CatalogName *) catalogIterator->folderName.longNamePtr;
442 else
443 nodeName = NULL;
444
445 isHFSPlus = true;
446 break;
447
448 default:
449 return;
450 }
451
452 BuildCatalogKey(catalogIterator->parentID, nodeName, isHFSPlus, (CatalogKey*) &btreeIterator->key);
453 }
454
455
456 //_______________________________________________________________________________
457 // Routine: UpdateCatalogIterator
458 //
459 // Function: Updates a CatalogIterator from a BTreeIterator
460 //
461 // Assumes: catalogIterator->nameType is correctly initialized!
462 // catalogIterator is locked (MacOS X)
463 //_______________________________________________________________________________
464 void
465 UpdateCatalogIterator (const BTreeIterator *btreeIterator, CatalogIterator *catalogIterator)
466 {
467 void * srcName;
468 void * dstName;
469 UInt16 nameSize;
470 CatalogKey * catalogKey;
471
472
473 catalogIterator->btreeNodeHint = btreeIterator->hint.nodeNum;
474 catalogIterator->btreeIndexHint = btreeIterator->hint.index;
475
476 catalogKey = (CatalogKey*) &btreeIterator->key;
477
478 switch (catalogIterator->nameType)
479 {
480 case kShortPascalName:
481 catalogIterator->parentID = catalogKey->hfs.parentID;
482
483 dstName = catalogIterator->folderName.pascalName;
484 srcName = catalogKey->hfs.nodeName;
485 nameSize = catalogKey->hfs.nodeName[0] + sizeof(UInt8);
486 break;
487
488 case kShortUnicodeName:
489 catalogIterator->parentID = catalogKey->hfsPlus.parentID;
490
491 dstName = &catalogIterator->folderName.unicodeName;
492 srcName = &catalogKey->hfsPlus.nodeName;
493 nameSize = (catalogKey->hfsPlus.nodeName.length + 1) * sizeof(UInt16);
494
495 // See if we need to make this iterator use long names
496 if ( nameSize > sizeof(catalogIterator->folderName.unicodeName) )
497 {
498 PrepareForLongName(catalogIterator); // Find a long name buffer to use
499 dstName = catalogIterator->folderName.longNamePtr;
500 }
501 break;
502
503 case kLongUnicodeName:
504 catalogIterator->parentID = catalogKey->hfsPlus.parentID;
505
506 dstName = catalogIterator->folderName.longNamePtr;
507 srcName = &catalogKey->hfsPlus.nodeName;
508 nameSize = (catalogKey->hfsPlus.nodeName.length + 1) * sizeof(UInt16);
509 break;
510
511 default:
512 return;
513 }
514
515 if (catalogIterator->parentID != catalogIterator->folderID)
516 catalogIterator->nextOffset = 0xFFFFFFFF;
517
518 BlockMoveData(srcName, dstName, nameSize);
519
520 } // end UpdateCatalogIterator
521
522
523 //_______________________________________________________________________________
524 // Routine: InsertCatalogIteratorAsMRU
525 //
526 // Function: Moves catalog iterator to head of mru order in double linked list
527 //
528 // Assumes list simple lock is held
529 //_______________________________________________________________________________
530 static void
531 InsertCatalogIteratorAsMRU ( CatalogCacheGlobals *cacheGlobals, CatalogIterator *iterator )
532 {
533 CatalogIterator *swapIterator;
534
535 if ( cacheGlobals->mru != iterator ) // if it's not already the mru iterator
536 {
537 swapIterator = cacheGlobals->mru; // put it in the front of the double queue
538 cacheGlobals->mru = iterator;
539 iterator->nextLRU->nextMRU = iterator->nextMRU;
540 if ( iterator->nextMRU != nil )
541 iterator->nextMRU->nextLRU = iterator->nextLRU;
542 else
543 cacheGlobals->lru= iterator->nextLRU;
544 iterator->nextMRU = swapIterator;
545 iterator->nextLRU = nil;
546 swapIterator->nextLRU = iterator;
547 }
548 }
549
550
551 //________________________________________________________________________________
552 // Routine: InsertCatalogIteratorAsLRU
553 //
554 // Function: Moves catalog iterator to head of lru order in double linked list
555 //
556 // Assumes list simple lock is held
557 //_______________________________________________________________________________
558 static void
559 InsertCatalogIteratorAsLRU ( CatalogCacheGlobals *cacheGlobals, CatalogIterator *iterator )
560 {
561 CatalogIterator *swapIterator;
562
563 if ( cacheGlobals->lru != iterator )
564 {
565 swapIterator = cacheGlobals->lru;
566 cacheGlobals->lru = iterator;
567 iterator->nextMRU->nextLRU = iterator->nextLRU;
568 if ( iterator->nextLRU != nil )
569 iterator->nextLRU->nextMRU = iterator->nextMRU;
570 else
571 cacheGlobals->mru= iterator->nextMRU;
572 iterator->nextLRU = swapIterator;
573 iterator->nextMRU = nil;
574 swapIterator->nextMRU = iterator;
575 }
576 }
577
578
579
580 //_______________________________________________________________________________
581 // Routine: PrepareForLongName
582 //
583 // Function: Takes a CatalogIterator whose nameType is kShortUnicodeName, and
584 // changes the nameType to kLongUnicodeName.
585 //
586 // Since long Unicode names aren't stored in the CatalogIterator itself, we have
587 // to point to an HFSUniStr255 for storage. In the current implementation, we have
588 // just one such global buffer in the cache globals. We'll set the iterator to
589 // point to the global buffer and invalidate the iterator that was using it
590 // (i.e. the iterator whose nameType is kLongUnicodeName).
591 //
592 // Eventually, we might want to have a list of long name buffers which we recycle
593 // using an LRU algorithm. Or perhaps, some other way....
594 //
595 // Assumes: catalogIterator is locked (MacOS X)
596 //_______________________________________________________________________________
597 static void
598 PrepareForLongName ( CatalogIterator *iterator )
599 {
600 CatalogCacheGlobals *cacheGlobals = GetCatalogCacheGlobals();
601 CatalogIterator *iter;
602
603 if (DEBUG_BUILD && iterator->nameType != kShortUnicodeName)
604 DebugStr("\p PrepareForLongName: nameType is wrong!");
605
606 //
607 // Walk through all the iterators. The first iterator whose nameType
608 // is kLongUnicodeName is invalidated (because it is using the global
609 // long name buffer).
610 //
611
612 CATALOG_ITER_LIST_LOCK(cacheGlobals);
613
614 for ( iter = cacheGlobals->mru ; iter != nil ; iter = iter->nextMRU )
615 {
616 if (iter->nameType == kLongUnicodeName)
617 {
618 // if iterator is not already last then make it last
619 if ( iter->nextMRU != nil )
620 InsertCatalogIteratorAsLRU( cacheGlobals, iter );
621
622 (void) CI_LOCK_FROM_LIST(cacheGlobals,iter);
623 iter->volume = 0; // trash it
624 iter->folderID = 0;
625 (void) CI_UNLOCK(iter);
626
627 #if TARGET_API_MACOS_X
628 break;
629 #endif
630 }
631 }
632
633 /*
634 * if iter is nil then none of the iterators was using the LongUnicodeName buffer
635 */
636 if (iter == nil)
637 CATALOG_ITER_LIST_UNLOCK(cacheGlobals);
638
639 //
640 // Change the nameType of this iterator and point to the global
641 // long name buffer. Note - this iterator is already locked
642 //
643 iterator->nameType = kLongUnicodeName;
644 iterator->folderName.longNamePtr = &cacheGlobals->longName;
645 }
646