1 /** @file
2   Functions for directory cache operation.
3 
4 Copyright (c) 2005, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials are licensed and made available
6 under the terms and conditions of the BSD License which accompanies this
7 distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9 
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 
14 **/
15 
16 #include "Fat.h"
17 
18 /**
19 
20   Free the directory structure and release the memory.
21 
22   @param  ODir                  - The directory to be freed.
23 
24 **/
25 STATIC
26 VOID
FatFreeODir(IN FAT_ODIR * ODir)27 FatFreeODir (
28   IN FAT_ODIR    *ODir
29   )
30 {
31   FAT_DIRENT  *DirEnt;
32 
33   //
34   // Release Directory Entry Nodes
35   //
36   while (!IsListEmpty (&ODir->ChildList)) {
37     DirEnt = DIRENT_FROM_LINK (ODir->ChildList.ForwardLink);
38     RemoveEntryList (&DirEnt->Link);
39     //
40     // Make sure the OFile has been closed
41     //
42     ASSERT (DirEnt->OFile == NULL);
43     FatFreeDirEnt (DirEnt);
44   }
45 
46   FreePool (ODir);
47 }
48 
49 /**
50 
51   Allocate the directory structure.
52 
53   @param  OFile                   - The corresponding OFile.
54 
55 **/
56 STATIC
57 FAT_ODIR *
FatAllocateODir(IN FAT_OFILE * OFile)58 FatAllocateODir (
59   IN FAT_OFILE   *OFile
60   )
61 {
62   FAT_ODIR  *ODir;
63 
64   ODir = AllocateZeroPool (sizeof (FAT_ODIR));
65   if (ODir != NULL) {
66     //
67     // Initialize the directory entry list
68     //
69     ODir->Signature = FAT_ODIR_SIGNATURE;
70     InitializeListHead (&ODir->ChildList);
71     ODir->CurrentCursor = &ODir->ChildList;
72   }
73 
74   return ODir;
75 }
76 
77 /**
78 
79   Discard the directory structure when an OFile will be freed.
80   Volume will cache this directory if the OFile does not represent a deleted file.
81 
82   @param  OFile                 - The OFile whose directory structure is to be discarded.
83 
84 **/
85 VOID
FatDiscardODir(IN FAT_OFILE * OFile)86 FatDiscardODir (
87   IN FAT_OFILE    *OFile
88   )
89 {
90   FAT_ODIR    *ODir;
91   FAT_VOLUME  *Volume;
92 
93   Volume  = OFile->Volume;
94   ODir    = OFile->ODir;
95   if (!OFile->DirEnt->Invalid) {
96     //
97     // If OFile does not represent a deleted file, then we will cache the directory
98     // We use OFile's first cluster as the directory's tag
99     //
100     ODir->DirCacheTag = OFile->FileCluster;
101     InsertHeadList (&Volume->DirCacheList, &ODir->DirCacheLink);
102     if (Volume->DirCacheCount == FAT_MAX_DIR_CACHE_COUNT) {
103       //
104       // Replace the least recent used directory
105       //
106       ODir = ODIR_FROM_DIRCACHELINK (Volume->DirCacheList.BackLink);
107       RemoveEntryList (&ODir->DirCacheLink);
108     } else {
109       //
110       // No need to find a replace
111       //
112       Volume->DirCacheCount++;
113       ODir = NULL;
114     }
115   }
116   //
117   // Release ODir Structure
118   //
119   if (ODir != NULL) {
120     FatFreeODir (ODir);
121   }
122 }
123 
124 /**
125 
126 
127   Request the directory structure when an OFile is newly generated.
128   If the directory structure is cached by volume, then just return this directory;
129   Otherwise, allocate a new one for OFile.
130 
131   @param  OFile                 - The OFile which requests directory structure.
132 
133 **/
134 VOID
FatRequestODir(IN FAT_OFILE * OFile)135 FatRequestODir (
136   IN FAT_OFILE    *OFile
137   )
138 {
139   UINTN           DirCacheTag;
140   FAT_VOLUME      *Volume;
141   FAT_ODIR        *ODir;
142   FAT_ODIR        *CurrentODir;
143   LIST_ENTRY      *CurrentODirLink;
144 
145   Volume      = OFile->Volume;
146   ODir        = NULL;
147   DirCacheTag = OFile->FileCluster;
148   for (CurrentODirLink  = Volume->DirCacheList.ForwardLink;
149        CurrentODirLink != &Volume->DirCacheList;
150        CurrentODirLink  = CurrentODirLink->ForwardLink
151       ) {
152     CurrentODir = ODIR_FROM_DIRCACHELINK (CurrentODirLink);
153     if (CurrentODir->DirCacheTag == DirCacheTag) {
154       RemoveEntryList (&CurrentODir->DirCacheLink);
155       Volume->DirCacheCount--;
156       ODir = CurrentODir;
157       break;
158     }
159   }
160 
161   if (ODir == NULL) {
162     //
163     // This directory is not cached, then allocate a new one
164     //
165     ODir = FatAllocateODir (OFile);
166   }
167 
168   OFile->ODir = ODir;
169 }
170 
171 /**
172 
173   Clean up all the cached directory structures when the volume is going to be abandoned.
174 
175   @param  Volume                - FAT file system volume.
176 
177 **/
178 VOID
FatCleanupODirCache(IN FAT_VOLUME * Volume)179 FatCleanupODirCache (
180   IN FAT_VOLUME         *Volume
181   )
182 {
183   FAT_ODIR  *ODir;
184   while (Volume->DirCacheCount > 0) {
185     ODir = ODIR_FROM_DIRCACHELINK (Volume->DirCacheList.BackLink);
186     RemoveEntryList (&ODir->DirCacheLink);
187     FatFreeODir (ODir);
188     Volume->DirCacheCount--;
189   }
190 }
191