2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 File: CatalogIterators.c
25 Contains: Catalog Iterator Implementation
29 Copyright: © 1997-1998 by Apple Computer, Inc., all rights reserved.
35 Other Contact: Mark Day
37 Technology: Mac OS File System
44 Change History (most recent first):
45 <MacOSX> 4/23/98 djb Re-enable InvalidateCatalogCache (was commented out).
46 <MacOSX> 4/6/98 djb Add locking for cache globals (list) and iterators.
47 <MacOSX> 4/2/98 djb Define gCatalogCacheGlobals here instead of FSVars.
48 <MacOSX> 3/31/98 djb Sync up with final HFSVolumes.h header file.
50 <CS3> 11/13/97 djb Radar #1683572 - Fix for indexed GetFileInfo.
51 <CS2> 10/17/97 msd Bug 1683506. Add support for long Unicode names in
52 CatalogIterators. Added a single global buffer for long Unicode
53 names; it is used by at most one CatalogIterator at a time.
54 <CS1> 10/1/97 djb first checked in
58 #include "../../hfs_macos_defs.h"
59 #include "../../hfs.h"
60 #include "../../hfs_dbg.h"
61 #include "../../hfs_format.h"
63 #include "../headers/FileMgrInternal.h"
64 #include "../headers/BTreesInternal.h"
65 #include "../headers/CatalogPrivate.h"
66 #include "../headers/HFSInstrumentation.h"
69 #include <sys/param.h>
70 #include <sys/systm.h>
71 #include <libkern/libkern.h>
74 static void InsertCatalogIteratorAsMRU( CatalogCacheGlobals
*cacheGlobals
, CatalogIterator
*iterator
);
76 static void InsertCatalogIteratorAsLRU( CatalogCacheGlobals
*cacheGlobals
, CatalogIterator
*iterator
);
78 static void PrepareForLongName( CatalogIterator
*iterator
);
81 #if TARGET_API_MACOS_X
82 CatalogCacheGlobals
*gCatalogCacheGlobals
;
84 #define GetCatalogCacheGlobals() (gCatalogCacheGlobals)
86 #define CATALOG_ITER_LIST_LOCK(g) simple_lock(&(g)->simplelock)
88 #define CATALOG_ITER_LIST_UNLOCK(g) simple_unlock(&(g)->simplelock)
90 #define CI_LOCK(i) lockmgr(&(i)->iterator_lock, LK_EXCLUSIVE, (simple_lock_t) 0, current_proc())
92 #define CI_UNLOCK(i) lockmgr(&(i)->iterator_lock, LK_RELEASE, (simple_lock_t) 0, current_proc())
94 #define CI_SLEEPLESS_LOCK(i) lockmgr(&(i)->iterator_lock, LK_EXCLUSIVE | LK_NOWAIT, (simple_lock_t) 0, current_proc())
96 #define CI_LOCK_FROM_LIST(g,i) lockmgr(&(i)->iterator_lock, LK_EXCLUSIVE | LK_INTERLOCK, &(g)->simplelock, current_proc())
98 #else /* TARGET_API_MACOS_X */
100 #define GetCatalogCacheGlobals() ((CatalogCacheGlobals*) ((FSVarsRec*) LMGetFSMVars()->gCatalogCacheGlobals))
102 #define CATALOG_ITER_LIST_LOCK(g)
104 #define CATALOG_ITER_LIST_UNLOCK(g)
108 #define CI_UNLOCK(i) 0
110 #define CI_SLEEPLESS_LOCK(i) 0
112 #define CI_LOCK_FROM_LIST(g,i) 0
117 //_______________________________________________________________________________
118 // Routine: InitCatalogCache
120 // Function: Allocates cache, and initializes all the cache structures.
122 //_______________________________________________________________________________
124 InitCatalogCache(void)
126 CatalogCacheGlobals
* cacheGlobals
;
127 CatalogIterator
* iterator
;
134 cacheSize
= sizeof(CatalogCacheGlobals
) + ( kCatalogIteratorCount
* sizeof(CatalogIterator
) );
135 cacheGlobals
= (CatalogCacheGlobals
*) NewPtrSysClear( cacheSize
);
141 cacheGlobals
->iteratorCount
= kCatalogIteratorCount
;
143 lastIterator
= kCatalogIteratorCount
- 1; // last iterator number, since they start at 0
145 // Initialize the MRU order for the cache
146 cacheGlobals
->mru
= (CatalogIterator
*) ( (Ptr
)cacheGlobals
+ sizeof(CatalogCacheGlobals
) );
148 // Initialize the LRU order for the cache
149 cacheGlobals
->lru
= (CatalogIterator
*) ( (Ptr
)(cacheGlobals
->mru
) + (lastIterator
* sizeof(CatalogIterator
)) );
152 // Traverse iterators, setting initial mru, lru, and default values
153 for ( i
= 0, iterator
= cacheGlobals
->mru
; i
< kCatalogIteratorCount
; i
++, iterator
= iterator
->nextMRU
)
155 if ( i
== lastIterator
)
156 iterator
->nextMRU
= nil
; // terminate the list
158 iterator
->nextMRU
= (CatalogIterator
*) ( (Ptr
)iterator
+ sizeof(CatalogIterator
) );
161 iterator
->nextLRU
= nil
; // terminate the list
163 iterator
->nextLRU
= (CatalogIterator
*) ( (Ptr
)iterator
- sizeof(CatalogIterator
) );
165 #if TARGET_API_MACOS_X
166 lockinit(&iterator
->iterator_lock
, PINOD
, "hfs_catalog_iterator", 0, 0);
170 #if TARGET_API_MAC_OS8
171 (FSVarsRec
*) LMGetFSMVars()->gCatalogCacheGlobals
= (Ptr
) cacheGlobals
;
174 #if TARGET_API_MACOS_X
175 gCatalogCacheGlobals
= cacheGlobals
;
176 simple_lock_init(&cacheGlobals
->simplelock
);
183 //_______________________________________________________________________________
184 // Routine: InvalidateCatalogCache
186 // Function: Trash any interators matching volume parameter
188 //_______________________________________________________________________________
189 void PrintCatalogIterator( void );
192 InvalidateCatalogCache( ExtendedVCB
*volume
)
194 TrashCatalogIterator( volume
, 0 );
198 //_______________________________________________________________________________
199 // Routine: PrintCatalogIterator
201 // Function: Prints all interators
203 //_______________________________________________________________________________
206 PrintCatalogIterator( void )
208 CatalogIterator
*iterator
;
209 CatalogCacheGlobals
*cacheGlobals
= GetCatalogCacheGlobals();
212 PRINTIT("CatalogCacheGlobals @ 0x%08lX are:\n", (unsigned long)cacheGlobals
);
213 PRINTIT("\titeratorCount: %ld \n", cacheGlobals
->iteratorCount
);
214 PRINTIT("\tmru: 0x%08lX \n", (unsigned long)cacheGlobals
->mru
);
215 PRINTIT("\tlru: 0x%08lX \n", (unsigned long)cacheGlobals
->lru
);
217 for ( iterator
= cacheGlobals
->mru
, i
=0 ; iterator
!= nil
&& i
<32 ; iterator
= iterator
->nextMRU
, i
++)
220 PRINTIT(" i: 0x%08lX", (unsigned long)iterator
);
221 PRINTIT(" M: 0x%08lX", (unsigned long)iterator
->nextMRU
);
222 PRINTIT(" L: 0x%08lX", (unsigned long)iterator
->nextLRU
);
228 //_______________________________________________________________________________
229 // Routine: TrashCatalogIterator
231 // Function: Trash any interators matching volume and folder parameters
233 //_______________________________________________________________________________
235 TrashCatalogIterator( const ExtendedVCB
*volume
, HFSCatalogNodeID folderID
)
237 CatalogIterator
*iterator
;
238 CatalogCacheGlobals
*cacheGlobals
= GetCatalogCacheGlobals();
240 CATALOG_ITER_LIST_LOCK(cacheGlobals
);
242 for ( iterator
= cacheGlobals
->mru
; iterator
!= nil
; iterator
= iterator
->nextMRU
)
246 // first match the volume
247 if ( iterator
->volume
!= volume
)
250 // now match the folder (or all folders if 0)
251 if ( (folderID
== 0) || (folderID
== iterator
->folderID
) )
253 CatalogIterator
*next
;
255 iterator
->volume
= 0; // trash it
256 iterator
->folderID
= 0;
258 next
= iterator
->nextMRU
; // remember the next iterator
260 // if iterator is not already last then make it last
263 InsertCatalogIteratorAsLRU( cacheGlobals
, iterator
);
265 // iterator->nextMRU will always be zero (since we moved it to the end)
266 // so set up the next iterator manually (we know its not nil)
268 goto top
; // process the next iterator
273 CATALOG_ITER_LIST_UNLOCK(cacheGlobals
);
277 //_______________________________________________________________________________
278 // Routine: AgeCatalogIterator
280 // Function: Move iterator to the end of the list...
282 //_______________________________________________________________________________
284 AgeCatalogIterator ( CatalogIterator
*catalogIterator
)
286 CatalogCacheGlobals
* cacheGlobals
= GetCatalogCacheGlobals();
288 CATALOG_ITER_LIST_LOCK(cacheGlobals
);
290 //PRINTIT(" AgeCatalogIterator: v=%d, d=%ld, i=%d\n", catalogIterator->volRefNum, catalogIterator->folderID, catalogIterator->currentIndex);
292 InsertCatalogIteratorAsLRU( cacheGlobals
, catalogIterator
);
294 CATALOG_ITER_LIST_UNLOCK(cacheGlobals
);
298 //_______________________________________________________________________________
299 // Routine: GetCatalogIterator
301 // Function: Release interest in Catalog iterator
303 //_______________________________________________________________________________
305 ReleaseCatalogIterator( CatalogIterator
* catalogIterator
)
307 #if TARGET_API_MACOS_X
308 //PRINTIT(" ReleaseCatalogIterator: v=%d, d=%ld, i=%d\n", catalogIterator->volRefNum, catalogIterator->folderID, catalogIterator->currentIndex);
309 return CI_UNLOCK(catalogIterator
);
316 //_______________________________________________________________________________
317 // Routine: GetCatalogIterator
319 // Function: Returns an iterator associated with the volume, folderID, index,
320 // and iterationType (kIterateFilesOnly or kIterateAll).
321 // Searches the cache in MRU order.
322 // Inserts the resulting iterator at the head of mru automatically
324 // Note: The returned iterator is locked and ReleaseCatalogIterator must
325 // be called to unlock it.
327 //_______________________________________________________________________________
329 oGetCatalogIterator( const ExtendedVCB
*volume
, HFSCatalogNodeID folderID
, UInt16 index
)
331 CatalogCacheGlobals
* cacheGlobals
= GetCatalogCacheGlobals();
332 CatalogIterator
* iterator
;
333 CatalogIterator
* bestIterator
;
335 Boolean newIterator
= false;
338 LogStartTime(kGetCatalogIterator
);
340 bestDelta
= 0xFFFF; // assume the best thing is to start from scratch
343 CATALOG_ITER_LIST_LOCK(cacheGlobals
);
345 for ( iterator
= cacheGlobals
->mru
; iterator
!= nil
; iterator
= iterator
->nextMRU
)
348 UInt16 iteratorIndex
;
350 // first make sure volume, folder id and type matches
351 if ( (iterator
->volume
!= volume
) ||
352 (iterator
->folderID
!= folderID
) ||
353 (iterator
->currentIndex
== 0xFFFFFFFF))
358 if ( CI_SLEEPLESS_LOCK(iterator
) == EBUSY
) /* ignore busy iterators */
360 //PRINTIT(" GetCatalogIterator: busy v=%d, d=%ld, i=%d\n", volume, folderID, iterator->currentIndex);
364 iteratorIndex
= iterator
->currentIndex
;
366 // we matched volume, folder id and type, now check the index
367 if ( iteratorIndex
== index
)
370 bestIterator
= iterator
; // we scored! - so get out of this loop
371 break; // break with iterator locked
374 // calculate how far this iterator is from the requested index
375 if ( index
> iteratorIndex
)
376 delta
= index
- iteratorIndex
;
378 delta
= iteratorIndex
- index
;
381 // remember the best iterator so far (there could be more than one)
382 if ( delta
< bestDelta
)
384 bestDelta
= delta
; // we found a better one!
385 bestIterator
= iterator
; // so remember it
386 if ( delta
== 1 ) // just one away is good enough!
387 break; // break with iterator locked
390 (void) CI_UNLOCK(iterator
); // unlock iterator before moving to the next one
395 // check if we didn't get one or if the one we got is too far away...
396 if ( (bestIterator
== nil
) || (index
< bestDelta
) )
398 bestIterator
= cacheGlobals
->lru
; // start over with a new iterator
400 //PRINTIT(" GetCatalogIterator: recycle v=%d, d=%ld, i=%d\n", bestIterator->volRefNum, bestIterator->folderID, bestIterator->currentIndex);
401 (void) CI_LOCK_FROM_LIST(cacheGlobals
, bestIterator
); // XXX we should not eat the error!
403 CATALOG_ITER_LIST_LOCK(cacheGlobals
); // grab the lock again for MRU Insert below...
405 bestIterator
->volume
= volume
; // update the iterator's volume
406 bestIterator
->folderID
= folderID
; // ... and folderID
407 bestIterator
->currentIndex
= 0; // ... and offspring index marker
409 bestIterator
->btreeNodeHint
= 0;
410 bestIterator
->btreeIndexHint
= 0;
411 bestIterator
->parentID
= folderID
; // set key to folderID + empty name
412 bestIterator
->folderName
.unicodeName
.length
= 0; // clear pascal/unicode name
414 if ( volume
->vcbSigWord
== kHFSPlusSigWord
)
415 bestIterator
->nameType
= kShortUnicodeName
;
417 bestIterator
->nameType
= kShortPascalName
;
422 //PRINTIT(" GetCatalogIterator: found v=%d, d=%ld, i=%d\n", bestIterator->volRefNum, bestIterator->folderID, bestIterator->currentIndex);
425 // put this iterator at the front of the list
426 InsertCatalogIteratorAsMRU( cacheGlobals
, bestIterator
);
428 CATALOG_ITER_LIST_UNLOCK(cacheGlobals
);
430 LogEndTime(kGetCatalogIterator
, newIterator
);
432 return bestIterator
; // return our best shot
434 } // end oGetCatalogIterator
438 GetCatalogIterator(ExtendedVCB
*volume
, HFSCatalogNodeID folderID
, UInt32 offset
)
440 CatalogCacheGlobals
*cacheGlobals
= GetCatalogCacheGlobals();
441 CatalogIterator
*iterator
;
442 CatalogIterator
*bestIterator
;
446 CATALOG_ITER_LIST_LOCK(cacheGlobals
);
448 for (iterator
= cacheGlobals
->mru
; iterator
!= nil
; iterator
= iterator
->nextMRU
) {
450 /* first make sure volume and folder id match */
451 if ((iterator
->volume
!= volume
) || (iterator
->folderID
!= folderID
)) {
455 /* ignore busy iterators */
456 if ( CI_SLEEPLESS_LOCK(iterator
) == EBUSY
) {
457 //PRINTIT(" GetCatalogIterator: busy v=%d, d=%ld, i=%d\n", volume, folderID, iterator->currentIndex);
461 /* we matched volume, folder id, now check the offset */
462 if ( iterator
->currentOffset
== offset
|| iterator
->nextOffset
== offset
) {
463 bestIterator
= iterator
; // we scored! - so get out of this loop
464 break; // break with iterator locked
467 (void) CI_UNLOCK(iterator
); // unlock iterator before moving to the next one
470 // check if we didn't get one or if the one we got is too far away...
471 if (bestIterator
== NULL
)
473 bestIterator
= cacheGlobals
->lru
; // start over with a new iterator
475 //PRINTIT(" GetCatalogIterator: recycle v=%d, d=%ld, i=%d\n", bestIterator->volume, bestIterator->folderID, bestIterator->currentIndex);
476 (void) CI_LOCK_FROM_LIST(cacheGlobals
, bestIterator
); // XXX we should not eat the error!
478 CATALOG_ITER_LIST_LOCK(cacheGlobals
); // grab the lock again for MRU Insert below...
480 bestIterator
->volume
= volume
; // update the iterator's volume
481 bestIterator
->folderID
= folderID
; // ... and folderID
482 bestIterator
->currentIndex
= 0xFFFFFFFF; // ... and offspring index marker
483 bestIterator
->currentOffset
= 0xFFFFFFFF;
484 bestIterator
->nextOffset
= 0xFFFFFFFF;
486 bestIterator
->btreeNodeHint
= 0;
487 bestIterator
->btreeIndexHint
= 0;
488 bestIterator
->parentID
= folderID
; // set key to folderID + empty name
489 bestIterator
->folderName
.unicodeName
.length
= 0; // clear pascal/unicode name
491 if ( volume
->vcbSigWord
== kHFSPlusSigWord
)
492 bestIterator
->nameType
= kShortUnicodeName
;
494 bestIterator
->nameType
= kShortPascalName
;
497 //PRINTIT(" GetCatalogIterator: found v=%d, d=%ld, i=%d\n", bestIterator->volume, bestIterator->folderID, bestIterator->currentIndex);
500 // put this iterator at the front of the list
501 InsertCatalogIteratorAsMRU( cacheGlobals
, bestIterator
);
503 CATALOG_ITER_LIST_UNLOCK(cacheGlobals
);
505 return bestIterator
; // return our best shot
507 } /* GetCatalogIterator */
510 //_______________________________________________________________________________
511 // Routine: UpdateBtreeIterator
513 // Function: Fills in a BTreeIterator from a CatalogIterator
515 // Assumes: catalogIterator->nameType is correctly initialized!
516 // catalogIterator is locked (MacOS X)
517 //_______________________________________________________________________________
519 UpdateBtreeIterator(const CatalogIterator
*catalogIterator
, BTreeIterator
*btreeIterator
)
521 CatalogName
* nodeName
;
525 btreeIterator
->hint
.writeCount
= 0;
526 btreeIterator
->hint
.nodeNum
= catalogIterator
->btreeNodeHint
;
527 btreeIterator
->hint
.index
= catalogIterator
->btreeIndexHint
;
529 switch (catalogIterator
->nameType
)
531 case kShortPascalName
:
532 if ( catalogIterator
->folderName
.pascalName
[0] > 0 )
533 nodeName
= (CatalogName
*) catalogIterator
->folderName
.pascalName
;
540 case kShortUnicodeName
:
541 if ( catalogIterator
->folderName
.unicodeName
.length
> 0 )
542 nodeName
= (CatalogName
*) &catalogIterator
->folderName
.unicodeName
;
549 case kLongUnicodeName
:
550 if ( catalogIterator
->folderName
.longNamePtr
->length
> 0 )
551 nodeName
= (CatalogName
*) catalogIterator
->folderName
.longNamePtr
;
562 BuildCatalogKey(catalogIterator
->parentID
, nodeName
, isHFSPlus
, (CatalogKey
*) &btreeIterator
->key
);
566 //_______________________________________________________________________________
567 // Routine: UpdateCatalogIterator
569 // Function: Updates a CatalogIterator from a BTreeIterator
571 // Assumes: catalogIterator->nameType is correctly initialized!
572 // catalogIterator is locked (MacOS X)
573 //_______________________________________________________________________________
575 UpdateCatalogIterator (const BTreeIterator
*btreeIterator
, CatalogIterator
*catalogIterator
)
580 CatalogKey
* catalogKey
;
583 catalogIterator
->btreeNodeHint
= btreeIterator
->hint
.nodeNum
;
584 catalogIterator
->btreeIndexHint
= btreeIterator
->hint
.index
;
586 catalogKey
= (CatalogKey
*) &btreeIterator
->key
;
588 switch (catalogIterator
->nameType
)
590 case kShortPascalName
:
591 catalogIterator
->parentID
= catalogKey
->hfs
.parentID
;
593 dstName
= catalogIterator
->folderName
.pascalName
;
594 srcName
= catalogKey
->hfs
.nodeName
;
595 nameSize
= catalogKey
->hfs
.nodeName
[0] + sizeof(UInt8
);
598 case kShortUnicodeName
:
599 catalogIterator
->parentID
= catalogKey
->hfsPlus
.parentID
;
601 dstName
= &catalogIterator
->folderName
.unicodeName
;
602 srcName
= &catalogKey
->hfsPlus
.nodeName
;
603 nameSize
= (catalogKey
->hfsPlus
.nodeName
.length
+ 1) * sizeof(UInt16
);
605 // See if we need to make this iterator use long names
606 if ( nameSize
> sizeof(catalogIterator
->folderName
.unicodeName
) )
608 PrepareForLongName(catalogIterator
); // Find a long name buffer to use
609 dstName
= catalogIterator
->folderName
.longNamePtr
;
613 case kLongUnicodeName
:
614 catalogIterator
->parentID
= catalogKey
->hfsPlus
.parentID
;
616 dstName
= catalogIterator
->folderName
.longNamePtr
;
617 srcName
= &catalogKey
->hfsPlus
.nodeName
;
618 nameSize
= (catalogKey
->hfsPlus
.nodeName
.length
+ 1) * sizeof(UInt16
);
625 if (catalogIterator
->parentID
!= catalogIterator
->folderID
)
626 catalogIterator
->nextOffset
= 0xFFFFFFFF;
628 BlockMoveData(srcName
, dstName
, nameSize
);
630 } // end UpdateCatalogIterator
633 //_______________________________________________________________________________
634 // Routine: InsertCatalogIteratorAsMRU
636 // Function: Moves catalog iterator to head of mru order in double linked list
638 // Assumes list simple lock is held
639 //_______________________________________________________________________________
641 InsertCatalogIteratorAsMRU ( CatalogCacheGlobals
*cacheGlobals
, CatalogIterator
*iterator
)
643 CatalogIterator
*swapIterator
;
645 if ( cacheGlobals
->mru
!= iterator
) // if it's not already the mru iterator
647 swapIterator
= cacheGlobals
->mru
; // put it in the front of the double queue
648 cacheGlobals
->mru
= iterator
;
649 iterator
->nextLRU
->nextMRU
= iterator
->nextMRU
;
650 if ( iterator
->nextMRU
!= nil
)
651 iterator
->nextMRU
->nextLRU
= iterator
->nextLRU
;
653 cacheGlobals
->lru
= iterator
->nextLRU
;
654 iterator
->nextMRU
= swapIterator
;
655 iterator
->nextLRU
= nil
;
656 swapIterator
->nextLRU
= iterator
;
661 //________________________________________________________________________________
662 // Routine: InsertCatalogIteratorAsLRU
664 // Function: Moves catalog iterator to head of lru order in double linked list
666 // Assumes list simple lock is held
667 //_______________________________________________________________________________
669 InsertCatalogIteratorAsLRU ( CatalogCacheGlobals
*cacheGlobals
, CatalogIterator
*iterator
)
671 CatalogIterator
*swapIterator
;
673 if ( cacheGlobals
->lru
!= iterator
)
675 swapIterator
= cacheGlobals
->lru
;
676 cacheGlobals
->lru
= iterator
;
677 iterator
->nextMRU
->nextLRU
= iterator
->nextLRU
;
678 if ( iterator
->nextLRU
!= nil
)
679 iterator
->nextLRU
->nextMRU
= iterator
->nextMRU
;
681 cacheGlobals
->mru
= iterator
->nextMRU
;
682 iterator
->nextLRU
= swapIterator
;
683 iterator
->nextMRU
= nil
;
684 swapIterator
->nextMRU
= iterator
;
690 //_______________________________________________________________________________
691 // Routine: PrepareForLongName
693 // Function: Takes a CatalogIterator whose nameType is kShortUnicodeName, and
694 // changes the nameType to kLongUnicodeName.
696 // Since long Unicode names aren't stored in the CatalogIterator itself, we have
697 // to point to an HFSUniStr255 for storage. In the current implementation, we have
698 // just one such global buffer in the cache globals. We'll set the iterator to
699 // point to the global buffer and invalidate the iterator that was using it
700 // (i.e. the iterator whose nameType is kLongUnicodeName).
702 // Eventually, we might want to have a list of long name buffers which we recycle
703 // using an LRU algorithm. Or perhaps, some other way....
705 // Assumes: catalogIterator is locked (MacOS X)
706 //_______________________________________________________________________________
708 PrepareForLongName ( CatalogIterator
*iterator
)
710 CatalogCacheGlobals
*cacheGlobals
= GetCatalogCacheGlobals();
711 CatalogIterator
*iter
;
713 if (DEBUG_BUILD
&& iterator
->nameType
!= kShortUnicodeName
)
714 DebugStr("\p PrepareForLongName: nameType is wrong!");
717 // Walk through all the iterators. The first iterator whose nameType
718 // is kLongUnicodeName is invalidated (because it is using the global
719 // long name buffer).
722 CATALOG_ITER_LIST_LOCK(cacheGlobals
);
724 for ( iter
= cacheGlobals
->mru
; iter
!= nil
; iter
= iter
->nextMRU
)
726 if (iter
->nameType
== kLongUnicodeName
)
728 // if iterator is not already last then make it last
729 if ( iter
->nextMRU
!= nil
)
730 InsertCatalogIteratorAsLRU( cacheGlobals
, iter
);
732 (void) CI_LOCK_FROM_LIST(cacheGlobals
,iter
);
733 iter
->volume
= 0; // trash it
735 (void) CI_UNLOCK(iter
);
737 #if TARGET_API_MACOS_X
744 * if iter is nil then none of the iterators was using the LongUnicodeName buffer
747 CATALOG_ITER_LIST_UNLOCK(cacheGlobals
);
750 // Change the nameType of this iterator and point to the global
751 // long name buffer. Note - this iterator is already locked
753 iterator
->nameType
= kLongUnicodeName
;
754 iterator
->folderName
.longNamePtr
= &cacheGlobals
->longName
;