]> git.saurik.com Git - apple/xnu.git/blob - bsd/hfs/hfscommon/Catalog/CatalogIterators.c
596b812bb1b141324c655484cfd31504b7e713fe
[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 * 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.
11 *
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
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 File: CatalogIterators.c
24
25 Contains: Catalog Iterator Implementation
26
27 Version: HFS Plus 1.0
28
29 Copyright: © 1997-1998 by Apple Computer, Inc., all rights reserved.
30
31 File Ownership:
32
33 DRI: Don Brady
34
35 Other Contact: Mark Day
36
37 Technology: Mac OS File System
38
39 Writers:
40
41 (msd) Mark Day
42 (djb) Don Brady
43
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.
49
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
55 */
56
57
58 #include "../../hfs_macos_defs.h"
59 #include "../../hfs.h"
60 #include "../../hfs_dbg.h"
61 #include "../../hfs_format.h"
62
63 #include "../headers/FileMgrInternal.h"
64 #include "../headers/BTreesInternal.h"
65 #include "../headers/CatalogPrivate.h"
66 #include "../headers/HFSInstrumentation.h"
67
68
69 #include <sys/param.h>
70 #include <sys/systm.h>
71 #include <libkern/libkern.h>
72 #include <sys/lock.h>
73
74 static void InsertCatalogIteratorAsMRU( CatalogCacheGlobals *cacheGlobals, CatalogIterator *iterator );
75
76 static void InsertCatalogIteratorAsLRU( CatalogCacheGlobals *cacheGlobals, CatalogIterator *iterator );
77
78 static void PrepareForLongName( CatalogIterator *iterator );
79
80
81 #if TARGET_API_MACOS_X
82 CatalogCacheGlobals *gCatalogCacheGlobals;
83
84 #define GetCatalogCacheGlobals() (gCatalogCacheGlobals)
85
86 #define CATALOG_ITER_LIST_LOCK(g) simple_lock(&(g)->simplelock)
87
88 #define CATALOG_ITER_LIST_UNLOCK(g) simple_unlock(&(g)->simplelock)
89
90 #define CI_LOCK(i) lockmgr(&(i)->iterator_lock, LK_EXCLUSIVE, (simple_lock_t) 0, current_proc())
91
92 #define CI_UNLOCK(i) lockmgr(&(i)->iterator_lock, LK_RELEASE, (simple_lock_t) 0, current_proc())
93
94 #define CI_SLEEPLESS_LOCK(i) lockmgr(&(i)->iterator_lock, LK_EXCLUSIVE | LK_NOWAIT, (simple_lock_t) 0, current_proc())
95
96 #define CI_LOCK_FROM_LIST(g,i) lockmgr(&(i)->iterator_lock, LK_EXCLUSIVE | LK_INTERLOCK, &(g)->simplelock, current_proc())
97
98 #else /* TARGET_API_MACOS_X */
99
100 #define GetCatalogCacheGlobals() ((CatalogCacheGlobals*) ((FSVarsRec*) LMGetFSMVars()->gCatalogCacheGlobals))
101
102 #define CATALOG_ITER_LIST_LOCK(g)
103
104 #define CATALOG_ITER_LIST_UNLOCK(g)
105
106 #define CI_LOCK(i) 0
107
108 #define CI_UNLOCK(i) 0
109
110 #define CI_SLEEPLESS_LOCK(i) 0
111
112 #define CI_LOCK_FROM_LIST(g,i) 0
113
114 #endif
115
116
117 //_______________________________________________________________________________
118 // Routine: InitCatalogCache
119 //
120 // Function: Allocates cache, and initializes all the cache structures.
121 //
122 //_______________________________________________________________________________
123 OSErr
124 InitCatalogCache(void)
125 {
126 CatalogCacheGlobals * cacheGlobals;
127 CatalogIterator * iterator;
128 UInt32 cacheSize;
129 UInt16 i;
130 UInt16 lastIterator;
131 OSErr err;
132
133
134 cacheSize = sizeof(CatalogCacheGlobals) + ( kCatalogIteratorCount * sizeof(CatalogIterator) );
135 cacheGlobals = (CatalogCacheGlobals *) NewPtrSysClear( cacheSize );
136
137 err = MemError();
138 if (err != noErr)
139 return err;
140
141 cacheGlobals->iteratorCount = kCatalogIteratorCount;
142
143 lastIterator = kCatalogIteratorCount - 1; // last iterator number, since they start at 0
144
145 // Initialize the MRU order for the cache
146 cacheGlobals->mru = (CatalogIterator *) ( (Ptr)cacheGlobals + sizeof(CatalogCacheGlobals) );
147
148 // Initialize the LRU order for the cache
149 cacheGlobals->lru = (CatalogIterator *) ( (Ptr)(cacheGlobals->mru) + (lastIterator * sizeof(CatalogIterator)) );
150
151
152 // Traverse iterators, setting initial mru, lru, and default values
153 for ( i = 0, iterator = cacheGlobals->mru; i < kCatalogIteratorCount ; i++, iterator = iterator->nextMRU )
154 {
155 if ( i == lastIterator )
156 iterator->nextMRU = nil; // terminate the list
157 else
158 iterator->nextMRU = (CatalogIterator *) ( (Ptr)iterator + sizeof(CatalogIterator) );
159
160 if ( i == 0 )
161 iterator->nextLRU = nil; // terminate the list
162 else
163 iterator->nextLRU = (CatalogIterator *) ( (Ptr)iterator - sizeof(CatalogIterator) );
164
165 #if TARGET_API_MACOS_X
166 lockinit(&iterator->iterator_lock, PINOD, "hfs_catalog_iterator", 0, 0);
167 #endif
168 }
169
170 #if TARGET_API_MAC_OS8
171 (FSVarsRec*) LMGetFSMVars()->gCatalogCacheGlobals = (Ptr) cacheGlobals;
172 #endif
173
174 #if TARGET_API_MACOS_X
175 gCatalogCacheGlobals = cacheGlobals;
176 simple_lock_init(&cacheGlobals->simplelock);
177 #endif
178
179 return noErr;
180 }
181
182
183 //_______________________________________________________________________________
184 // Routine: InvalidateCatalogCache
185 //
186 // Function: Trash any interators matching volume parameter
187 //
188 //_______________________________________________________________________________
189 void PrintCatalogIterator( void );
190
191 void
192 InvalidateCatalogCache( ExtendedVCB *volume )
193 {
194 TrashCatalogIterator( volume, 0 );
195 }
196
197
198 //_______________________________________________________________________________
199 // Routine: PrintCatalogIterator
200 //
201 // Function: Prints all interators
202 //
203 //_______________________________________________________________________________
204 #if HFS_DIAGNOSTIC
205 void
206 PrintCatalogIterator( void )
207 {
208 CatalogIterator *iterator;
209 CatalogCacheGlobals *cacheGlobals = GetCatalogCacheGlobals();
210 int i;
211
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);
216
217 for ( iterator = cacheGlobals->mru, i=0 ; iterator != nil && i<32 ; iterator = iterator->nextMRU, i++)
218 {
219 PRINTIT("%d: ", 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);
223 PRINTIT("\n");
224 }
225 }
226 #endif
227
228 //_______________________________________________________________________________
229 // Routine: TrashCatalogIterator
230 //
231 // Function: Trash any interators matching volume and folder parameters
232 //
233 //_______________________________________________________________________________
234 void
235 TrashCatalogIterator( const ExtendedVCB *volume, HFSCatalogNodeID folderID )
236 {
237 CatalogIterator *iterator;
238 CatalogCacheGlobals *cacheGlobals = GetCatalogCacheGlobals();
239
240 CATALOG_ITER_LIST_LOCK(cacheGlobals);
241
242 for ( iterator = cacheGlobals->mru ; iterator != nil ; iterator = iterator->nextMRU )
243 {
244 top:
245
246 // first match the volume
247 if ( iterator->volume != volume )
248 continue;
249
250 // now match the folder (or all folders if 0)
251 if ( (folderID == 0) || (folderID == iterator->folderID) )
252 {
253 CatalogIterator *next;
254
255 iterator->volume = 0; // trash it
256 iterator->folderID = 0;
257
258 next = iterator->nextMRU; // remember the next iterator
259
260 // if iterator is not already last then make it last
261 if ( next != nil )
262 {
263 InsertCatalogIteratorAsLRU( cacheGlobals, iterator );
264
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)
267 iterator = next;
268 goto top; // process the next iterator
269 }
270 }
271 }
272
273 CATALOG_ITER_LIST_UNLOCK(cacheGlobals);
274 }
275
276
277 //_______________________________________________________________________________
278 // Routine: AgeCatalogIterator
279 //
280 // Function: Move iterator to the end of the list...
281 //
282 //_______________________________________________________________________________
283 void
284 AgeCatalogIterator ( CatalogIterator *catalogIterator )
285 {
286 CatalogCacheGlobals * cacheGlobals = GetCatalogCacheGlobals();
287
288 CATALOG_ITER_LIST_LOCK(cacheGlobals);
289
290 //PRINTIT(" AgeCatalogIterator: v=%d, d=%ld, i=%d\n", catalogIterator->volRefNum, catalogIterator->folderID, catalogIterator->currentIndex);
291
292 InsertCatalogIteratorAsLRU( cacheGlobals, catalogIterator );
293
294 CATALOG_ITER_LIST_UNLOCK(cacheGlobals);
295 }
296
297
298 //_______________________________________________________________________________
299 // Routine: GetCatalogIterator
300 //
301 // Function: Release interest in Catalog iterator
302 //
303 //_______________________________________________________________________________
304 OSErr
305 ReleaseCatalogIterator( CatalogIterator* catalogIterator)
306 {
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);
310 #else
311 return noErr;
312 #endif
313 }
314
315
316 //_______________________________________________________________________________
317 // Routine: GetCatalogIterator
318 //
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
323 //
324 // Note: The returned iterator is locked and ReleaseCatalogIterator must
325 // be called to unlock it.
326 //
327 //_______________________________________________________________________________
328 CatalogIterator*
329 oGetCatalogIterator( const ExtendedVCB *volume, HFSCatalogNodeID folderID, UInt16 index)
330 {
331 CatalogCacheGlobals * cacheGlobals = GetCatalogCacheGlobals();
332 CatalogIterator * iterator;
333 CatalogIterator * bestIterator;
334 UInt16 bestDelta;
335 Boolean newIterator = false;
336
337
338 LogStartTime(kGetCatalogIterator);
339
340 bestDelta = 0xFFFF; // assume the best thing is to start from scratch
341 bestIterator = nil;
342
343 CATALOG_ITER_LIST_LOCK(cacheGlobals);
344
345 for ( iterator = cacheGlobals->mru ; iterator != nil ; iterator = iterator->nextMRU )
346 {
347 UInt16 delta;
348 UInt16 iteratorIndex;
349
350 // first make sure volume, folder id and type matches
351 if ( (iterator->volume != volume) ||
352 (iterator->folderID != folderID) ||
353 (iterator->currentIndex == 0xFFFFFFFF))
354 {
355 continue;
356 }
357
358 if ( CI_SLEEPLESS_LOCK(iterator) == EBUSY ) /* ignore busy iterators */
359 {
360 //PRINTIT(" GetCatalogIterator: busy v=%d, d=%ld, i=%d\n", volume, folderID, iterator->currentIndex);
361 continue;
362 }
363
364 iteratorIndex = iterator->currentIndex;
365
366 // we matched volume, folder id and type, now check the index
367 if ( iteratorIndex == index )
368 {
369 bestDelta = 0;
370 bestIterator = iterator; // we scored! - so get out of this loop
371 break; // break with iterator locked
372 }
373
374 // calculate how far this iterator is from the requested index
375 if ( index > iteratorIndex )
376 delta = index - iteratorIndex;
377 else
378 delta = iteratorIndex - index;
379
380
381 // remember the best iterator so far (there could be more than one)
382 if ( delta < bestDelta )
383 {
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
388 }
389
390 (void) CI_UNLOCK(iterator); // unlock iterator before moving to the next one
391
392 } // end for
393
394
395 // check if we didn't get one or if the one we got is too far away...
396 if ( (bestIterator == nil) || (index < bestDelta) )
397 {
398 bestIterator = cacheGlobals->lru; // start over with a new iterator
399
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!
402
403 CATALOG_ITER_LIST_LOCK(cacheGlobals); // grab the lock again for MRU Insert below...
404
405 bestIterator->volume = volume; // update the iterator's volume
406 bestIterator->folderID = folderID; // ... and folderID
407 bestIterator->currentIndex = 0; // ... and offspring index marker
408
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
413
414 if ( volume->vcbSigWord == kHFSPlusSigWord )
415 bestIterator->nameType = kShortUnicodeName;
416 else
417 bestIterator->nameType = kShortPascalName;
418
419 newIterator = true;
420 }
421 else {
422 //PRINTIT(" GetCatalogIterator: found v=%d, d=%ld, i=%d\n", bestIterator->volRefNum, bestIterator->folderID, bestIterator->currentIndex);
423 }
424
425 // put this iterator at the front of the list
426 InsertCatalogIteratorAsMRU( cacheGlobals, bestIterator );
427
428 CATALOG_ITER_LIST_UNLOCK(cacheGlobals);
429
430 LogEndTime(kGetCatalogIterator, newIterator);
431
432 return bestIterator; // return our best shot
433
434 } // end oGetCatalogIterator
435
436
437 CatalogIterator*
438 GetCatalogIterator(ExtendedVCB *volume, HFSCatalogNodeID folderID, UInt32 offset)
439 {
440 CatalogCacheGlobals *cacheGlobals = GetCatalogCacheGlobals();
441 CatalogIterator *iterator;
442 CatalogIterator *bestIterator;
443
444 bestIterator = NULL;
445
446 CATALOG_ITER_LIST_LOCK(cacheGlobals);
447
448 for (iterator = cacheGlobals->mru ; iterator != nil ; iterator = iterator->nextMRU) {
449
450 /* first make sure volume and folder id match */
451 if ((iterator->volume != volume) || (iterator->folderID != folderID)) {
452 continue;
453 }
454
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);
458 continue;
459 }
460
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
465 }
466
467 (void) CI_UNLOCK(iterator); // unlock iterator before moving to the next one
468 }
469
470 // check if we didn't get one or if the one we got is too far away...
471 if (bestIterator == NULL)
472 {
473 bestIterator = cacheGlobals->lru; // start over with a new iterator
474
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!
477
478 CATALOG_ITER_LIST_LOCK(cacheGlobals); // grab the lock again for MRU Insert below...
479
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;
485
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
490
491 if ( volume->vcbSigWord == kHFSPlusSigWord )
492 bestIterator->nameType = kShortUnicodeName;
493 else
494 bestIterator->nameType = kShortPascalName;
495 }
496 else {
497 //PRINTIT(" GetCatalogIterator: found v=%d, d=%ld, i=%d\n", bestIterator->volume, bestIterator->folderID, bestIterator->currentIndex);
498 }
499
500 // put this iterator at the front of the list
501 InsertCatalogIteratorAsMRU( cacheGlobals, bestIterator );
502
503 CATALOG_ITER_LIST_UNLOCK(cacheGlobals);
504
505 return bestIterator; // return our best shot
506
507 } /* GetCatalogIterator */
508
509
510 //_______________________________________________________________________________
511 // Routine: UpdateBtreeIterator
512 //
513 // Function: Fills in a BTreeIterator from a CatalogIterator
514 //
515 // Assumes: catalogIterator->nameType is correctly initialized!
516 // catalogIterator is locked (MacOS X)
517 //_______________________________________________________________________________
518 void
519 UpdateBtreeIterator(const CatalogIterator *catalogIterator, BTreeIterator *btreeIterator)
520 {
521 CatalogName * nodeName;
522 Boolean isHFSPlus;
523
524
525 btreeIterator->hint.writeCount = 0;
526 btreeIterator->hint.nodeNum = catalogIterator->btreeNodeHint;
527 btreeIterator->hint.index = catalogIterator->btreeIndexHint;
528
529 switch (catalogIterator->nameType)
530 {
531 case kShortPascalName:
532 if ( catalogIterator->folderName.pascalName[0] > 0 )
533 nodeName = (CatalogName *) catalogIterator->folderName.pascalName;
534 else
535 nodeName = NULL;
536
537 isHFSPlus = false;
538 break;
539
540 case kShortUnicodeName:
541 if ( catalogIterator->folderName.unicodeName.length > 0 )
542 nodeName = (CatalogName *) &catalogIterator->folderName.unicodeName;
543 else
544 nodeName = NULL;
545
546 isHFSPlus = true;
547 break;
548
549 case kLongUnicodeName:
550 if ( catalogIterator->folderName.longNamePtr->length > 0 )
551 nodeName = (CatalogName *) catalogIterator->folderName.longNamePtr;
552 else
553 nodeName = NULL;
554
555 isHFSPlus = true;
556 break;
557
558 default:
559 return;
560 }
561
562 BuildCatalogKey(catalogIterator->parentID, nodeName, isHFSPlus, (CatalogKey*) &btreeIterator->key);
563 }
564
565
566 //_______________________________________________________________________________
567 // Routine: UpdateCatalogIterator
568 //
569 // Function: Updates a CatalogIterator from a BTreeIterator
570 //
571 // Assumes: catalogIterator->nameType is correctly initialized!
572 // catalogIterator is locked (MacOS X)
573 //_______________________________________________________________________________
574 void
575 UpdateCatalogIterator (const BTreeIterator *btreeIterator, CatalogIterator *catalogIterator)
576 {
577 void * srcName;
578 void * dstName;
579 UInt16 nameSize;
580 CatalogKey * catalogKey;
581
582
583 catalogIterator->btreeNodeHint = btreeIterator->hint.nodeNum;
584 catalogIterator->btreeIndexHint = btreeIterator->hint.index;
585
586 catalogKey = (CatalogKey*) &btreeIterator->key;
587
588 switch (catalogIterator->nameType)
589 {
590 case kShortPascalName:
591 catalogIterator->parentID = catalogKey->hfs.parentID;
592
593 dstName = catalogIterator->folderName.pascalName;
594 srcName = catalogKey->hfs.nodeName;
595 nameSize = catalogKey->hfs.nodeName[0] + sizeof(UInt8);
596 break;
597
598 case kShortUnicodeName:
599 catalogIterator->parentID = catalogKey->hfsPlus.parentID;
600
601 dstName = &catalogIterator->folderName.unicodeName;
602 srcName = &catalogKey->hfsPlus.nodeName;
603 nameSize = (catalogKey->hfsPlus.nodeName.length + 1) * sizeof(UInt16);
604
605 // See if we need to make this iterator use long names
606 if ( nameSize > sizeof(catalogIterator->folderName.unicodeName) )
607 {
608 PrepareForLongName(catalogIterator); // Find a long name buffer to use
609 dstName = catalogIterator->folderName.longNamePtr;
610 }
611 break;
612
613 case kLongUnicodeName:
614 catalogIterator->parentID = catalogKey->hfsPlus.parentID;
615
616 dstName = catalogIterator->folderName.longNamePtr;
617 srcName = &catalogKey->hfsPlus.nodeName;
618 nameSize = (catalogKey->hfsPlus.nodeName.length + 1) * sizeof(UInt16);
619 break;
620
621 default:
622 return;
623 }
624
625 if (catalogIterator->parentID != catalogIterator->folderID)
626 catalogIterator->nextOffset = 0xFFFFFFFF;
627
628 BlockMoveData(srcName, dstName, nameSize);
629
630 } // end UpdateCatalogIterator
631
632
633 //_______________________________________________________________________________
634 // Routine: InsertCatalogIteratorAsMRU
635 //
636 // Function: Moves catalog iterator to head of mru order in double linked list
637 //
638 // Assumes list simple lock is held
639 //_______________________________________________________________________________
640 static void
641 InsertCatalogIteratorAsMRU ( CatalogCacheGlobals *cacheGlobals, CatalogIterator *iterator )
642 {
643 CatalogIterator *swapIterator;
644
645 if ( cacheGlobals->mru != iterator ) // if it's not already the mru iterator
646 {
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;
652 else
653 cacheGlobals->lru= iterator->nextLRU;
654 iterator->nextMRU = swapIterator;
655 iterator->nextLRU = nil;
656 swapIterator->nextLRU = iterator;
657 }
658 }
659
660
661 //________________________________________________________________________________
662 // Routine: InsertCatalogIteratorAsLRU
663 //
664 // Function: Moves catalog iterator to head of lru order in double linked list
665 //
666 // Assumes list simple lock is held
667 //_______________________________________________________________________________
668 static void
669 InsertCatalogIteratorAsLRU ( CatalogCacheGlobals *cacheGlobals, CatalogIterator *iterator )
670 {
671 CatalogIterator *swapIterator;
672
673 if ( cacheGlobals->lru != iterator )
674 {
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;
680 else
681 cacheGlobals->mru= iterator->nextMRU;
682 iterator->nextLRU = swapIterator;
683 iterator->nextMRU = nil;
684 swapIterator->nextMRU = iterator;
685 }
686 }
687
688
689
690 //_______________________________________________________________________________
691 // Routine: PrepareForLongName
692 //
693 // Function: Takes a CatalogIterator whose nameType is kShortUnicodeName, and
694 // changes the nameType to kLongUnicodeName.
695 //
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).
701 //
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....
704 //
705 // Assumes: catalogIterator is locked (MacOS X)
706 //_______________________________________________________________________________
707 static void
708 PrepareForLongName ( CatalogIterator *iterator )
709 {
710 CatalogCacheGlobals *cacheGlobals = GetCatalogCacheGlobals();
711 CatalogIterator *iter;
712
713 if (DEBUG_BUILD && iterator->nameType != kShortUnicodeName)
714 DebugStr("\p PrepareForLongName: nameType is wrong!");
715
716 //
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).
720 //
721
722 CATALOG_ITER_LIST_LOCK(cacheGlobals);
723
724 for ( iter = cacheGlobals->mru ; iter != nil ; iter = iter->nextMRU )
725 {
726 if (iter->nameType == kLongUnicodeName)
727 {
728 // if iterator is not already last then make it last
729 if ( iter->nextMRU != nil )
730 InsertCatalogIteratorAsLRU( cacheGlobals, iter );
731
732 (void) CI_LOCK_FROM_LIST(cacheGlobals,iter);
733 iter->volume = 0; // trash it
734 iter->folderID = 0;
735 (void) CI_UNLOCK(iter);
736
737 #if TARGET_API_MACOS_X
738 break;
739 #endif
740 }
741 }
742
743 /*
744 * if iter is nil then none of the iterators was using the LongUnicodeName buffer
745 */
746 if (iter == nil)
747 CATALOG_ITER_LIST_UNLOCK(cacheGlobals);
748
749 //
750 // Change the nameType of this iterator and point to the global
751 // long name buffer. Note - this iterator is already locked
752 //
753 iterator->nameType = kLongUnicodeName;
754 iterator->folderName.longNamePtr = &cacheGlobals->longName;
755 }
756