ba62929349f37f42fe41ed39ce7d67ab38790d9c
[reactos.git] / reactos / drivers / filesystems / fastfat_new / fcb.c
1 /*
2 * PROJECT: ReactOS FAT file system driver
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/filesystems/fastfat/fcb.c
5 * PURPOSE: FCB manipulation routines.
6 * PROGRAMMERS: Alexey Vlasov
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #define NDEBUG
12 #include "fastfat.h"
13
14 /* FUNCTIONS ****************************************************************/
15
16 /**
17 * Locates FCB by the supplied name in the cache trie of fcbs.
18 *
19 * @param ParentFcb
20 * Supplies a pointer to the parent FCB
21 *
22 * @param Name
23 * Supplied a name of the FCB to be located in cache.
24 *
25 * @return
26 * Pointer to the found FCB or NULL.
27 */
28 PFCB
29 FatLookupFcbByName(
30 IN PFCB ParentFcb,
31 IN PUNICODE_STRING Name)
32 {
33 PFCB_NAME_LINK Node;
34 PRTL_SPLAY_LINKS Links;
35
36 /* Get sub-trie root node from the parent FCB */
37 Links = ParentFcb->Dcb.SplayLinks;
38 while (Links != NULL)
39 {
40 LONG Comparison;
41
42 Node = CONTAINING_RECORD(Links, FCB_NAME_LINK, Links);
43
44 /*
45 * Compare the name stored in the node
46 * and determine the direction to walk.
47 */
48 Comparison = RtlCompareUnicodeString(&Node->String, Name, TRUE);
49 if (Comparison > 0) {
50 /* Left child */
51 Links = RtlLeftChild(&Node->Links);
52 }
53 else if (Comparison < 0)
54 {
55 /* Right child */
56 Links = RtlRightChild(&Node->Links);
57 }
58 else
59 {
60 /* Strings are equal, we have found the node! */
61 break;
62 }
63 }
64
65 /* The case when nothing was found. */
66 if (Links == NULL)
67 return NULL;
68
69 /* Cast node to the FCB structure. */
70 return CONTAINING_RECORD(Links, FCB, FileName[Node->Type]);
71 }
72
73 /**
74 * Inserts FCB into FCBs cache trie.
75 *
76 * @param ParentFcb
77 * Supplies a pointer to the parent FCB
78 *
79 * @param Fcb
80 * Supplied a pointer to the being inserted FCB.
81 *
82 * @return
83 * TRUE if the FCB was successfully inserted,
84 * FASLE in the case of name collision.
85 */
86 BOOLEAN
87 FatLinkFcbNames(
88 IN PFCB ParentFcb,
89 IN PFCB Fcb)
90 {
91 PFCB_NAME_LINK Name;
92 PRTL_SPLAY_LINKS Links;
93
94 /* None of the parameters can be NULL */
95 ASSERT(ParentFcb != NULL && Fcb != NULL);
96
97 /* Get root links of the parent FCB. */
98 Links = ParentFcb->Dcb.SplayLinks;
99
100 /*
101 * Get first file name
102 * (short name for FAT because it's always there.
103 */
104 Name = Fcb->FileName;
105
106 /*
107 * Check if ParentDcb links are initialized,
108 * at least one child FCB is cached.
109 */
110 if (Links == NULL)
111 {
112 ParentFcb->Dcb.SplayLinks = Links = &Name->Links;
113 RtlInitializeSplayLinks(Links);
114
115 /* Check if we have more names to cache. */
116 if ((++Name)->String.Length == 0)
117 return TRUE;
118 }
119 /* Lookup for the insertion point in the trie. */
120 do
121 {
122 LONG Comparison;
123 PFCB_NAME_LINK Node;
124 PRTL_SPLAY_LINKS PrevLinks;
125
126 PrevLinks = Links;
127 Node = CONTAINING_RECORD(Links, FCB_NAME_LINK, Links);
128 Comparison = RtlCompareUnicodeString(&Node->String, &Name->String, TRUE);
129 if (Comparison > 0) {
130 Links = RtlLeftChild(&Node->Links);
131 if (Links == NULL)
132 {
133 RtlInsertAsLeftChild(PrevLinks, &Name->Links);
134 break;
135 }
136 }
137 else if (Comparison < 0)
138 {
139 Links = RtlRightChild(&Node->Links);
140 if (Links == NULL)
141 {
142 RtlInsertAsRightChild(PrevLinks, &Name->Links);
143 break;
144 }
145 }
146 else
147 {
148 return FALSE;
149 }
150
151 /* Possibly switch to the second (lfn) name and cache that. */
152 } while (Name == Fcb->FileName && (++Name)->String.Length > 0);
153 return TRUE;
154 }
155
156 /**
157 * Unlinks FCB from the FCBs cache trie.
158 *
159 * @param ParentFcb
160 * Supplies a pointer to the parent FCB
161 *
162 * @param Fcb
163 * Supplied a pointer to the being unlinked FCB.
164 *
165 * @return
166 * VOID
167 */
168 VOID
169 FatUnlinkFcbNames(
170 IN PFCB ParentFcb,
171 IN PFCB Fcb)
172 {
173 /* See if there is an lfn and unlink that. */
174 if (Fcb->FileName[FcbLongName].String.Length > 0)
175 ParentFcb->Dcb.SplayLinks =
176 RtlDelete(&Fcb->FileName[FcbLongName].Links);
177
178 /* See if there is a short name and unlink that. */
179 if (Fcb->FileName[FcbShortName].String.Length > 0)
180 ParentFcb->Dcb.SplayLinks =
181 RtlDelete(&Fcb->FileName[FcbShortName].Links);
182 }
183
184 NTSTATUS
185 FatCreateFcb(
186 OUT PFCB* CreatedFcb,
187 IN PFAT_IRP_CONTEXT IrpContext,
188 IN PFCB ParentFcb,
189 IN PDIR_ENTRY Dirent,
190 IN PUNICODE_STRING FileName,
191 IN PUNICODE_STRING LongFileName OPTIONAL)
192 {
193 NTSTATUS Status;
194 PFCB Fcb;
195
196 /* Allocate FCB structure. */
197 Fcb = (PFCB) ExAllocateFromNPagedLookasideList(&FatGlobalData.NonPagedFcbList);
198 if (Fcb == NULL)
199 return STATUS_INSUFFICIENT_RESOURCES;
200 RtlZeroMemory(Fcb, sizeof(FCB));
201
202 /* Setup FCB Advanced Header. */
203 Fcb->Header.NodeTypeCode = FAT_NTC_FCB;
204 Fcb->Header.NodeByteSize = sizeof(*Fcb);
205 ExInitializeResourceLite(&Fcb->Resource);
206 Fcb->Header.Resource = &Fcb->Resource;
207 ExInitializeResourceLite(&Fcb->PagingIoResource);
208 Fcb->Header.PagingIoResource = &Fcb->PagingIoResource;
209 ExInitializeFastMutex(&Fcb->HeaderMutex);
210 FsRtlSetupAdvancedHeader(&Fcb->Header, &Fcb->HeaderMutex);
211 Fcb->Header.FileSize.QuadPart = Dirent->FileSize;
212 Fcb->Header.ValidDataLength.QuadPart = Dirent->FileSize;
213 Fcb->Header.IsFastIoPossible = FastIoIsNotPossible;
214
215 /* Setup main fields. */
216 FsRtlInitializeFileLock(&Fcb->Lock, NULL, NULL);
217 FsRtlInitializeLargeMcb(&Fcb->Mcb, PagedPool);
218 Fcb->Vcb = IrpContext->Vcb;
219 Fcb->ParentFcb = ParentFcb;
220 Fcb->FirstCluster = Dirent->FirstCluster
221 | (Dirent->FirstClusterOfFileHi << 0x10);
222
223 /* Setup basic info. */
224 Fcb->BasicInfo.FileAttributes = Dirent->Attributes;
225 FatQueryFileTimes(&Fcb->BasicInfo.CreationTime, Dirent);
226
227 /* Setup short name since always present in FAT. */
228 Fcb->FileName[FcbShortName].Type = FcbShortName;
229 Fcb->FileName[FcbShortName].String.Buffer = Fcb->ShortNameBuffer;
230 Fcb->FileName[FcbShortName].String.MaximumLength = 0x0c;
231 Fcb->FileName[FcbShortName].String.Length = FileName->Length;
232 RtlCopyMemory(Fcb->ShortNameBuffer, FileName->Buffer, FileName->Length);
233
234 /* Just swap optional lfn. */
235 if (ARGUMENT_PRESENT(LongFileName) && LongFileName->Length > 0)
236 {
237 Fcb->FileName[FcbLongName].Type = FcbLongName;
238 Fcb->FileName[FcbLongName].String = *LongFileName;
239 RtlZeroMemory(LongFileName, sizeof(UNICODE_STRING));
240 }
241
242 /* Put FCB into cache trie. */
243 if (!FatLinkFcbNames(ParentFcb, Fcb))
244 {
245 Status = STATUS_OBJECT_NAME_COLLISION;
246 goto FsdFatCreateFcbCleanup;
247 }
248 *CreatedFcb = Fcb;
249
250 /* We are done! */
251 return STATUS_SUCCESS;
252
253 FsdFatCreateFcbCleanup:
254 if (ARGUMENT_PRESENT(LongFileName) &&
255 Fcb->FileName[FcbLongName].String.Buffer != NULL)
256 {
257 /* Swap lfn back to the input parameter */
258 *LongFileName = Fcb->FileName[FcbLongName].String;
259 }
260 ExFreeToNPagedLookasideList(&FatGlobalData.NonPagedFcbList, Fcb);
261 return Status;
262 }
263
264 NTSTATUS
265 FatOpenFcb(
266 OUT PFCB* Fcb,
267 IN PFAT_IRP_CONTEXT IrpContext,
268 IN PFCB ParentFcb,
269 IN PUNICODE_STRING FileName)
270 {
271 FAT_FIND_DIRENT_CONTEXT Context;
272 UNICODE_STRING LongFileName;
273 PDIR_ENTRY Dirent;
274 NTSTATUS Status;
275
276 // TODO: _SEH_TRY {
277 if (ParentFcb->Dcb.StreamFileObject == NULL)
278 {
279 PFILE_OBJECT FileObject;
280 PVPB Vpb;
281
282 Vpb = IrpContext->Vcb->Vpb;
283
284 /* Create stream file object */
285 FileObject = IoCreateStreamFileObject(NULL, Vpb->RealDevice);
286 FileObject->Vpb = Vpb;
287 FileObject->SectionObjectPointer = &ParentFcb->SectionObjectPointers;
288 FileObject->FsContext = ParentFcb;
289 FileObject->FsContext2 = NULL;
290
291 /* Store it in parent fcb */
292 ParentFcb->Dcb.StreamFileObject = FileObject;
293
294 }
295
296 /* Check if cache is initialized. */
297 if (ParentFcb->Dcb.StreamFileObject->PrivateCacheMap == NULL )
298 {
299 CcInitializeCacheMap(ParentFcb->Dcb.StreamFileObject,
300 (PCC_FILE_SIZES) &ParentFcb->Header.AllocationSize,
301 TRUE,
302 &FatGlobalData.CacheMgrNoopCallbacks,
303 ParentFcb);
304 }
305
306 /* Page context */
307 Context.Page.FileObject = ParentFcb->Dcb.StreamFileObject;
308 Context.Page.EndOfData = ParentFcb->Header.FileSize;
309 Context.Page.Offset.QuadPart = -1LL;
310 Context.Page.Bcb = NULL;
311 Context.Page.CanWait = BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT);
312 Context.Page.EndOfData = ParentFcb->Header.FileSize;
313
314 /* Search context */
315 Context.ShortName.Length = 0;
316 Context.ShortName.Buffer = Context.ShortNameBuffer;
317 Context.ShortName.MaximumLength = sizeof(Context.ShortNameBuffer);
318 Context.FileName = FileName;
319 Context.Valid8dot3Name = RtlIsNameLegalDOS8Dot3(FileName, NULL, NULL);
320
321 /* Locate the dirent */
322 FatFindDirent(&Context, &Dirent, &LongFileName);
323
324 Status = FatCreateFcb(Fcb, IrpContext, ParentFcb, Dirent,
325 &Context.ShortName, &LongFileName);
326 return Status;
327 }
328 /* EOF */