Copy msimg32
[reactos.git] / reactos / drivers / fs / vfat / fcb.c
1 /* $Id$
2 *
3 *
4 * FILE: drivers/fs/vfat/fcb.c
5 * PURPOSE: Routines to manipulate FCBs.
6 * COPYRIGHT: See COPYING in the top level directory
7 * PROJECT: ReactOS kernel
8 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
9 * Rex Jolliff (rex@lvcablemodem.com)
10 * Hartmut Birr
11 * Herve Poussineau (reactos@poussine.freesurf.fr)
12 */
13
14 /* ------------------------------------------------------- INCLUDES */
15
16 #include <ddk/ntddk.h>
17 #include <ntos/kefuncs.h>
18 #include <wchar.h>
19 #include <limits.h>
20 #include <rosrtl/string.h>
21
22 #define NDEBUG
23 #include <debug.h>
24
25 #include "vfat.h"
26
27 /* -------------------------------------------------------- DEFINES */
28
29 #define TAG(A, B, C, D) (ULONG)(((A)<<0) + ((B)<<8) + ((C)<<16) + ((D)<<24))
30 #define TAG_FCB TAG('V', 'F', 'C', 'B')
31
32 #define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
33
34 /* -------------------------------------------------------- PUBLICS */
35
36 ULONG vfatNameHash(ULONG hash, PUNICODE_STRING NameU)
37 {
38 PWCHAR last;
39 PWCHAR curr;
40 register WCHAR c;
41
42 ASSERT(NameU->Buffer[0] != L'.');
43 curr = NameU->Buffer;
44 last = NameU->Buffer + NameU->Length / sizeof(WCHAR);
45
46 while(curr < last)
47 {
48 c = towlower(*curr++);
49 hash = (hash + (c << 4) + (c >> 4)) * 11;
50 }
51 return hash;
52 }
53
54 VOID
55 vfatSplitPathName(PUNICODE_STRING PathNameU, PUNICODE_STRING DirNameU, PUNICODE_STRING FileNameU)
56 {
57 PWCHAR pName;
58 ULONG Length = 0;
59 pName = PathNameU->Buffer + PathNameU->Length / sizeof(WCHAR) - 1;
60 while (*pName != L'\\' && pName >= PathNameU->Buffer)
61 {
62 pName--;
63 Length++;
64 }
65 ASSERT(*pName == L'\\' || pName < PathNameU->Buffer);
66 if (FileNameU)
67 {
68 FileNameU->Buffer = pName + 1;
69 FileNameU->Length = FileNameU->MaximumLength = Length * sizeof(WCHAR);
70 }
71 if (DirNameU)
72 {
73 DirNameU->Buffer = PathNameU->Buffer;
74 DirNameU->Length = (pName + 1 - PathNameU->Buffer) * sizeof(WCHAR);
75 DirNameU->MaximumLength = DirNameU->Length;
76 }
77 }
78
79 VOID
80 vfatInitFcb(PVFATFCB Fcb, PUNICODE_STRING NameU)
81 {
82 Fcb->PathNameU.Length = 0;
83 Fcb->PathNameU.Buffer = Fcb->PathNameBuffer;
84 Fcb->PathNameU.MaximumLength = sizeof(Fcb->PathNameBuffer);
85 Fcb->ShortNameU.Length = 0;
86 Fcb->ShortNameU.Buffer = Fcb->ShortNameBuffer;
87 Fcb->ShortNameU.MaximumLength = sizeof(Fcb->ShortNameBuffer);
88 Fcb->DirNameU.Buffer = Fcb->PathNameU.Buffer;
89 if (NameU && NameU->Length)
90 {
91 RtlCopyUnicodeString(&Fcb->PathNameU, NameU);
92 vfatSplitPathName(&Fcb->PathNameU, &Fcb->DirNameU, &Fcb->LongNameU);
93 }
94 else
95 {
96 Fcb->DirNameU.Buffer = Fcb->LongNameU.Buffer = NULL;
97 Fcb->DirNameU.MaximumLength = Fcb->DirNameU.Length = 0;
98 Fcb->LongNameU.MaximumLength = Fcb->LongNameU.Length = 0;
99 }
100 RtlZeroMemory(&Fcb->FCBShareAccess, sizeof(SHARE_ACCESS));
101 Fcb->OpenHandleCount = 0;
102 }
103
104 PVFATFCB
105 vfatNewFCB(PDEVICE_EXTENSION pVCB, PUNICODE_STRING pFileNameU)
106 {
107 PVFATFCB rcFCB;
108
109 DPRINT("'%wZ'\n", pFileNameU);
110
111 rcFCB = ExAllocateFromNPagedLookasideList(&VfatGlobalData->FcbLookasideList);
112 if (rcFCB == NULL)
113 {
114 return NULL;
115 }
116 RtlZeroMemory(rcFCB, sizeof(VFATFCB));
117 vfatInitFcb(rcFCB, pFileNameU);
118 if (pVCB->Flags & VCB_IS_FATX)
119 {
120 rcFCB->Flags |= FCB_IS_FATX_ENTRY;
121 rcFCB->Attributes = &rcFCB->entry.FatX.Attrib;
122 }
123 else
124 rcFCB->Attributes = &rcFCB->entry.Fat.Attrib;
125 rcFCB->Hash.Hash = vfatNameHash(0, &rcFCB->PathNameU);
126 rcFCB->Hash.self = rcFCB;
127 rcFCB->ShortHash.self = rcFCB;
128 ExInitializeResourceLite(&rcFCB->PagingIoResource);
129 ExInitializeResourceLite(&rcFCB->MainResource);
130 FsRtlInitializeFileLock(&rcFCB->FileLock, NULL, NULL);
131 ExInitializeFastMutex(&rcFCB->LastMutex);
132 return rcFCB;
133 }
134
135 VOID
136 vfatDestroyCCB(PVFATCCB pCcb)
137 {
138 if (pCcb->SearchPattern.Buffer)
139 {
140 ExFreePool(pCcb->SearchPattern.Buffer);
141 }
142 ExFreeToNPagedLookasideList(&VfatGlobalData->CcbLookasideList, pCcb);
143 }
144
145 VOID
146 vfatDestroyFCB(PVFATFCB pFCB)
147 {
148 FsRtlUninitializeFileLock(&pFCB->FileLock);
149 ExDeleteResourceLite(&pFCB->PagingIoResource);
150 ExDeleteResourceLite(&pFCB->MainResource);
151 ExFreeToNPagedLookasideList(&VfatGlobalData->FcbLookasideList, pFCB);
152 }
153
154 BOOL
155 vfatFCBIsDirectory(PVFATFCB FCB)
156 {
157 return *FCB->Attributes & FILE_ATTRIBUTE_DIRECTORY;
158 }
159
160 BOOL
161 vfatFCBIsRoot(PVFATFCB FCB)
162 {
163 return FCB->PathNameU.Length == sizeof(WCHAR) && FCB->PathNameU.Buffer[0] == L'\\' ? TRUE : FALSE;
164 }
165
166 VOID
167 vfatReleaseFCB(PDEVICE_EXTENSION pVCB, PVFATFCB pFCB)
168 {
169 HASHENTRY* entry;
170 ULONG Index;
171 ULONG ShortIndex;
172 PVFATFCB tmpFcb;
173
174 DPRINT ("releasing FCB at %x: %wZ, refCount:%d\n",
175 pFCB,
176 &pFCB->PathNameU,
177 pFCB->RefCount);
178
179 while (pFCB)
180 {
181 Index = pFCB->Hash.Hash % FCB_HASH_TABLE_SIZE;
182 ShortIndex = pFCB->ShortHash.Hash % FCB_HASH_TABLE_SIZE;
183 pFCB->RefCount--;
184 if (pFCB->RefCount <= 0 && (!vfatFCBIsDirectory (pFCB) || pFCB->Flags & FCB_DELETE_PENDING))
185 {
186 tmpFcb = pFCB->parentFcb;
187 RemoveEntryList (&pFCB->FcbListEntry);
188 if (pFCB->Hash.Hash != pFCB->ShortHash.Hash)
189 {
190 entry = pVCB->FcbHashTable[ShortIndex];
191 if (entry->self == pFCB)
192 {
193 pVCB->FcbHashTable[ShortIndex] = entry->next;
194 }
195 else
196 {
197 while (entry->next->self != pFCB)
198 {
199 entry = entry->next;
200 }
201 entry->next = pFCB->ShortHash.next;
202 }
203 }
204 entry = pVCB->FcbHashTable[Index];
205 if (entry->self == pFCB)
206 {
207 pVCB->FcbHashTable[Index] = entry->next;
208 }
209 else
210 {
211 while (entry->next->self != pFCB)
212 {
213 entry = entry->next;
214 }
215 entry->next = pFCB->Hash.next;
216 }
217 if (vfatFCBIsDirectory(pFCB))
218 {
219 /* Uninitialize file cache if initialized for this file object. */
220 if (pFCB->FileObject->SectionObjectPointer->SharedCacheMap)
221 {
222 CcRosReleaseFileCache(pFCB->FileObject);
223 }
224 vfatDestroyCCB(pFCB->FileObject->FsContext2);
225 pFCB->FileObject->FsContext2 = NULL;
226 pFCB->FileObject->FsContext = NULL;
227 ObDereferenceObject(pFCB->FileObject);
228 }
229 vfatDestroyFCB (pFCB);
230 }
231 else
232 {
233 tmpFcb = NULL;
234 }
235 pFCB = tmpFcb;
236 }
237 }
238
239 VOID
240 vfatAddFCBToTable(PDEVICE_EXTENSION pVCB, PVFATFCB pFCB)
241 {
242 ULONG Index;
243 ULONG ShortIndex;
244
245 Index = pFCB->Hash.Hash % FCB_HASH_TABLE_SIZE;
246 ShortIndex = pFCB->ShortHash.Hash % FCB_HASH_TABLE_SIZE;
247
248 InsertTailList (&pVCB->FcbListHead, &pFCB->FcbListEntry);
249
250 pFCB->Hash.next = pVCB->FcbHashTable[Index];
251 pVCB->FcbHashTable[Index] = &pFCB->Hash;
252 if (pFCB->Hash.Hash != pFCB->ShortHash.Hash)
253 {
254 pFCB->ShortHash.next = pVCB->FcbHashTable[ShortIndex];
255 pVCB->FcbHashTable[ShortIndex] = &pFCB->ShortHash;
256 }
257 if (pFCB->parentFcb)
258 {
259 pFCB->parentFcb->RefCount++;
260 }
261 }
262
263 PVFATFCB
264 vfatGrabFCBFromTable(PDEVICE_EXTENSION pVCB, PUNICODE_STRING PathNameU)
265 {
266 PVFATFCB rcFCB;
267 ULONG Hash;
268 UNICODE_STRING DirNameU;
269 UNICODE_STRING FileNameU;
270 PUNICODE_STRING FcbNameU;
271
272 HASHENTRY* entry;
273
274 DPRINT("'%wZ'\n", PathNameU);
275
276 Hash = vfatNameHash(0, PathNameU);
277
278 entry = pVCB->FcbHashTable[Hash % FCB_HASH_TABLE_SIZE];
279 if (entry)
280 {
281 vfatSplitPathName(PathNameU, &DirNameU, &FileNameU);
282 }
283
284 while (entry)
285 {
286 if (entry->Hash == Hash)
287 {
288 rcFCB = entry->self;
289 DPRINT("'%wZ' '%wZ'\n", &DirNameU, &rcFCB->DirNameU);
290 if (RtlEqualUnicodeString(&DirNameU, &rcFCB->DirNameU, TRUE))
291 {
292 if (rcFCB->Hash.Hash == Hash)
293 {
294 FcbNameU = &rcFCB->LongNameU;
295 }
296 else
297 {
298 FcbNameU = &rcFCB->ShortNameU;
299 }
300 /* compare the file name */
301 DPRINT("'%wZ' '%wZ'\n", &FileNameU, FcbNameU);
302 if (RtlEqualUnicodeString(&FileNameU, FcbNameU, TRUE))
303 {
304 rcFCB->RefCount++;
305 CHECKPOINT;
306 return rcFCB;
307 }
308 }
309 }
310 entry = entry->next;
311 }
312 CHECKPOINT;
313 return NULL;
314 }
315
316 NTSTATUS
317 vfatFCBInitializeCacheFromVolume (PVCB vcb, PVFATFCB fcb)
318 {
319 NTSTATUS status;
320 PFILE_OBJECT fileObject;
321 ULONG fileCacheQuantum;
322 PVFATCCB newCCB;
323
324 fileObject = IoCreateStreamFileObject (NULL, vcb->StorageDevice);
325
326 newCCB = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList);
327 if (newCCB == NULL)
328 {
329 return STATUS_INSUFFICIENT_RESOURCES;
330 }
331 RtlZeroMemory(newCCB, sizeof (VFATCCB));
332
333 fileObject->Flags |= FO_FCB_IS_VALID | FO_DIRECT_CACHE_PAGING_READ;
334 fileObject->SectionObjectPointer = &fcb->SectionObjectPointers;
335 fileObject->FsContext = fcb;
336 fileObject->FsContext2 = newCCB;
337 fcb->FileObject = fileObject;
338
339
340 fileCacheQuantum = (vcb->FatInfo.BytesPerCluster >= PAGE_SIZE) ?
341 vcb->FatInfo.BytesPerCluster : PAGE_SIZE;
342
343 status = CcRosInitializeFileCache (fileObject,
344 fileCacheQuantum);
345 if (!NT_SUCCESS (status))
346 {
347 DbgPrint ("CcRosInitializeFileCache failed\n");
348 KEBUGCHECK (0);
349 }
350
351 fcb->Flags |= FCB_CACHE_INITIALIZED;
352
353 return status;
354 }
355
356 PVFATFCB
357 vfatMakeRootFCB(PDEVICE_EXTENSION pVCB)
358 {
359 PVFATFCB FCB;
360 ULONG FirstCluster, CurrentCluster, Size = 0;
361 NTSTATUS Status = STATUS_SUCCESS;
362 UNICODE_STRING NameU;
363
364 RtlRosInitUnicodeStringFromLiteral(&NameU, L"\\");
365
366 FCB = vfatNewFCB(pVCB, &NameU);
367 if (FCB->Flags & FCB_IS_FATX_ENTRY)
368 {
369 memset(FCB->entry.FatX.Filename, ' ', 42);
370 FCB->entry.FatX.FileSize = pVCB->FatInfo.rootDirectorySectors * pVCB->FatInfo.BytesPerSector;
371 FCB->entry.FatX.Attrib = FILE_ATTRIBUTE_DIRECTORY;
372 FCB->entry.FatX.FirstCluster = 1;
373 Size = pVCB->FatInfo.rootDirectorySectors * pVCB->FatInfo.BytesPerSector;
374 }
375 else
376 {
377 memset(FCB->entry.Fat.Filename, ' ', 11);
378 FCB->entry.Fat.FileSize = pVCB->FatInfo.rootDirectorySectors * pVCB->FatInfo.BytesPerSector;
379 FCB->entry.Fat.Attrib = FILE_ATTRIBUTE_DIRECTORY;
380 if (pVCB->FatInfo.FatType == FAT32)
381 {
382 CurrentCluster = FirstCluster = pVCB->FatInfo.RootCluster;
383 FCB->entry.Fat.FirstCluster = (unsigned short)(FirstCluster & 0xffff);
384 FCB->entry.Fat.FirstClusterHigh = (unsigned short)(FirstCluster >> 16);
385
386 while (CurrentCluster != 0xffffffff && NT_SUCCESS(Status))
387 {
388 Size += pVCB->FatInfo.BytesPerCluster;
389 Status = NextCluster (pVCB, FirstCluster, &CurrentCluster, FALSE);
390 }
391 }
392 else
393 {
394 FCB->entry.Fat.FirstCluster = 1;
395 Size = pVCB->FatInfo.rootDirectorySectors * pVCB->FatInfo.BytesPerSector;
396 }
397 }
398 FCB->ShortHash.Hash = FCB->Hash.Hash;
399 FCB->RefCount = 2;
400 FCB->dirIndex = 0;
401 FCB->RFCB.FileSize.QuadPart = Size;
402 FCB->RFCB.ValidDataLength.QuadPart = Size;
403 FCB->RFCB.AllocationSize.QuadPart = Size;
404
405 vfatFCBInitializeCacheFromVolume(pVCB, FCB);
406 vfatAddFCBToTable(pVCB, FCB);
407
408 return(FCB);
409 }
410
411 PVFATFCB
412 vfatOpenRootFCB(PDEVICE_EXTENSION pVCB)
413 {
414 PVFATFCB FCB;
415 UNICODE_STRING NameU;
416
417 RtlRosInitUnicodeStringFromLiteral(&NameU, L"\\");
418
419 FCB = vfatGrabFCBFromTable (pVCB, &NameU);
420 if (FCB == NULL)
421 {
422 FCB = vfatMakeRootFCB (pVCB);
423 }
424
425 return FCB;
426 }
427
428 NTSTATUS
429 vfatMakeFCBFromDirEntry(PVCB vcb,
430 PVFATFCB directoryFCB,
431 PVFAT_DIRENTRY_CONTEXT DirContext,
432 PVFATFCB* fileFCB)
433 {
434 PVFATFCB rcFCB;
435 WCHAR pathName [MAX_PATH];
436 ULONG Size;
437 ULONG hash;
438
439 UNICODE_STRING NameU;
440
441 if (directoryFCB->PathNameU.Length + 2 * sizeof(WCHAR) +
442 + DirContext->LongNameU.Length > MAX_PATH * sizeof(WCHAR))
443 {
444 return STATUS_OBJECT_NAME_INVALID;
445 }
446 NameU.Buffer = pathName;
447 NameU.Length = 0;
448 NameU.MaximumLength = sizeof(pathName);
449
450 RtlCopyUnicodeString(&NameU, &directoryFCB->PathNameU);
451 if (!vfatFCBIsRoot (directoryFCB))
452 {
453 RtlAppendUnicodeToString(&NameU, L"\\");
454 }
455 hash = vfatNameHash(0, &NameU);
456 if (DirContext->LongNameU.Length > 0)
457 {
458 RtlAppendUnicodeStringToString(&NameU, &DirContext->LongNameU);
459 }
460 else
461 {
462 RtlAppendUnicodeStringToString(&NameU, &DirContext->ShortNameU);
463 }
464 NameU.Buffer[NameU.Length / sizeof(WCHAR)] = 0;
465
466 rcFCB = vfatNewFCB (vcb, &NameU);
467 RtlCopyMemory (&rcFCB->entry, &DirContext->DirEntry, sizeof (DIR_ENTRY));
468 RtlCopyUnicodeString(&rcFCB->ShortNameU, &DirContext->ShortNameU);
469 if (vcb->Flags & VCB_IS_FATX)
470 {
471 rcFCB->ShortHash.Hash = rcFCB->Hash.Hash;
472 }
473 else
474 {
475 rcFCB->ShortHash.Hash = vfatNameHash(hash, &rcFCB->ShortNameU);
476 }
477
478 if (vfatFCBIsDirectory(rcFCB))
479 {
480 ULONG FirstCluster, CurrentCluster;
481 NTSTATUS Status;
482 Size = 0;
483 FirstCluster = vfatDirEntryGetFirstCluster (vcb, &rcFCB->entry);
484 if (FirstCluster == 1)
485 {
486 Size = vcb->FatInfo.rootDirectorySectors * vcb->FatInfo.BytesPerSector;
487 }
488 else if (FirstCluster != 0)
489 {
490 CurrentCluster = FirstCluster;
491 while (CurrentCluster != 0xffffffff)
492 {
493 Size += vcb->FatInfo.BytesPerCluster;
494 Status = NextCluster (vcb, FirstCluster, &CurrentCluster, FALSE);
495 }
496 }
497 }
498 else if (rcFCB->Flags & FCB_IS_FATX_ENTRY)
499 {
500 Size = rcFCB->entry.FatX.FileSize;
501 }
502 else
503 {
504 Size = rcFCB->entry.Fat.FileSize;
505 }
506 rcFCB->dirIndex = DirContext->DirIndex;
507 rcFCB->startIndex = DirContext->StartIndex;
508 rcFCB->RFCB.FileSize.QuadPart = Size;
509 rcFCB->RFCB.ValidDataLength.QuadPart = Size;
510 rcFCB->RFCB.AllocationSize.QuadPart = ROUND_UP(Size, vcb->FatInfo.BytesPerCluster);
511 rcFCB->RefCount++;
512 if (vfatFCBIsDirectory(rcFCB))
513 {
514 vfatFCBInitializeCacheFromVolume(vcb, rcFCB);
515 }
516 rcFCB->parentFcb = directoryFCB;
517 vfatAddFCBToTable (vcb, rcFCB);
518 *fileFCB = rcFCB;
519
520 return STATUS_SUCCESS;
521 }
522
523 NTSTATUS
524 vfatAttachFCBToFileObject (PDEVICE_EXTENSION vcb,
525 PVFATFCB fcb,
526 PFILE_OBJECT fileObject)
527 {
528 PVFATCCB newCCB;
529
530 newCCB = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList);
531 if (newCCB == NULL)
532 {
533 CHECKPOINT;
534 return STATUS_INSUFFICIENT_RESOURCES;
535 }
536 RtlZeroMemory (newCCB, sizeof (VFATCCB));
537
538 fileObject->Flags = fileObject->Flags | FO_FCB_IS_VALID |
539 FO_DIRECT_CACHE_PAGING_READ;
540 fileObject->SectionObjectPointer = &fcb->SectionObjectPointers;
541 fileObject->FsContext = fcb;
542 fileObject->FsContext2 = newCCB;
543 DPRINT ("file open: fcb:%x PathName:%wZ file size: %d\n", fcb, &fcb->PathNameU, fcb->entry.FileSize);
544
545 return STATUS_SUCCESS;
546 }
547
548 NTSTATUS
549 vfatDirFindFile (PDEVICE_EXTENSION pDeviceExt,
550 PVFATFCB pDirectoryFCB,
551 PUNICODE_STRING FileToFindU,
552 PVFATFCB * pFoundFCB)
553 {
554 NTSTATUS status;
555 PVOID Context = NULL;
556 PVOID Page = NULL;
557 BOOLEAN First = TRUE;
558 VFAT_DIRENTRY_CONTEXT DirContext;
559 WCHAR LongNameBuffer[MAX_PATH];
560 WCHAR ShortNameBuffer[13];
561 BOOLEAN FoundLong = FALSE;
562 BOOLEAN FoundShort = FALSE;
563
564 ASSERT(pDeviceExt);
565 ASSERT(pDirectoryFCB);
566 ASSERT(FileToFindU);
567
568 DPRINT ("vfatDirFindFile(VCB:%08x, dirFCB:%08x, File:%wZ)\n",
569 pDeviceExt,
570 pDirectoryFCB,
571 FileToFindU);
572 DPRINT ("Dir Path:%wZ\n", &pDirectoryFCB->PathNameU);
573
574 DirContext.DirIndex = 0;
575 DirContext.LongNameU.Buffer = LongNameBuffer;
576 DirContext.LongNameU.Length = 0;
577 DirContext.LongNameU.MaximumLength = sizeof(LongNameBuffer);
578 DirContext.ShortNameU.Buffer = ShortNameBuffer;
579 DirContext.ShortNameU.Length = 0;
580 DirContext.ShortNameU.MaximumLength = sizeof(ShortNameBuffer);
581
582 while (TRUE)
583 {
584 status = pDeviceExt->GetNextDirEntry(&Context,
585 &Page,
586 pDirectoryFCB,
587 &DirContext,
588 First);
589 First = FALSE;
590 if (status == STATUS_NO_MORE_ENTRIES)
591 {
592 return STATUS_OBJECT_NAME_NOT_FOUND;
593 }
594 if (!NT_SUCCESS(status))
595 {
596 return status;
597 }
598
599 DPRINT (" Index:%d longName:%wZ\n",
600 DirContext.DirIndex,
601 &DirContext.LongNameU);
602 DirContext.LongNameU.Buffer[DirContext.LongNameU.Length / sizeof(WCHAR)] = 0;
603 DirContext.ShortNameU.Buffer[DirContext.ShortNameU.Length / sizeof(WCHAR)] = 0;
604 if (!ENTRY_VOLUME(pDeviceExt, &DirContext.DirEntry))
605 {
606 FoundLong = RtlEqualUnicodeString(FileToFindU, &DirContext.LongNameU, TRUE);
607 if (FoundLong == FALSE)
608 {
609 FoundShort = RtlEqualUnicodeString(FileToFindU, &DirContext.ShortNameU, TRUE);
610 }
611 if (FoundLong || FoundShort)
612 {
613 status = vfatMakeFCBFromDirEntry (pDeviceExt,
614 pDirectoryFCB,
615 &DirContext,
616 pFoundFCB);
617 CcUnpinData(Context);
618 return status;
619 }
620 }
621 DirContext.DirIndex++;
622 }
623
624 return STATUS_OBJECT_NAME_NOT_FOUND;
625 }
626
627 NTSTATUS
628 vfatGetFCBForFile (PDEVICE_EXTENSION pVCB,
629 PVFATFCB *pParentFCB,
630 PVFATFCB *pFCB,
631 PUNICODE_STRING pFileNameU)
632 {
633 NTSTATUS status;
634 PVFATFCB FCB = NULL;
635 PVFATFCB parentFCB;
636 UNICODE_STRING NameU;
637 UNICODE_STRING RootNameU;
638 PWCHAR curr, prev, last;
639 ULONG Length;
640
641 DPRINT ("vfatGetFCBForFile (%x,%x,%x,%wZ)\n",
642 pVCB,
643 pParentFCB,
644 pFCB,
645 pFileNameU);
646
647 parentFCB = *pParentFCB;
648
649 if (parentFCB == NULL)
650 {
651 RtlRosInitUnicodeStringFromLiteral(&RootNameU, L"\\");
652
653 // Trivial case, open of the root directory on volume
654 if (RtlEqualUnicodeString(pFileNameU, &RootNameU, FALSE))
655 {
656 DPRINT ("returning root FCB\n");
657
658 FCB = vfatOpenRootFCB (pVCB);
659 *pFCB = FCB;
660 *pParentFCB = NULL;
661
662 return (FCB != NULL) ? STATUS_SUCCESS : STATUS_OBJECT_PATH_NOT_FOUND;
663 }
664
665 /* Check for an existing FCB */
666 FCB = vfatGrabFCBFromTable (pVCB, pFileNameU);
667 if (FCB)
668 {
669 *pFCB = FCB;
670 *pParentFCB = FCB->parentFcb;
671 (*pParentFCB)->RefCount++;
672 return STATUS_SUCCESS;
673 }
674
675 last = curr = pFileNameU->Buffer + pFileNameU->Length / sizeof(WCHAR) - 1;
676 while (*curr != L'\\' && curr > pFileNameU->Buffer)
677 {
678 curr--;
679 }
680
681 if (curr > pFileNameU->Buffer)
682 {
683 NameU.Buffer = pFileNameU->Buffer;
684 NameU.MaximumLength = NameU.Length = (curr - pFileNameU->Buffer) * sizeof(WCHAR);
685 FCB = vfatGrabFCBFromTable(pVCB, &NameU);
686 if (FCB)
687 {
688 Length = (curr - pFileNameU->Buffer) * sizeof(WCHAR);
689 if (Length != FCB->PathNameU.Length)
690 {
691 if (pFileNameU->Length + FCB->PathNameU.Length - Length > pFileNameU->MaximumLength)
692 {
693 vfatReleaseFCB (pVCB, FCB);
694 return STATUS_OBJECT_NAME_INVALID;
695 }
696 memmove(pFileNameU->Buffer + FCB->PathNameU.Length / sizeof(WCHAR),
697 curr, pFileNameU->Length - Length);
698 pFileNameU->Length += FCB->PathNameU.Length - Length;
699 curr = pFileNameU->Buffer + FCB->PathNameU.Length / sizeof(WCHAR);
700 last = pFileNameU->Buffer + pFileNameU->Length / sizeof(WCHAR) - 1;
701 }
702 RtlCopyMemory(pFileNameU->Buffer, FCB->PathNameU.Buffer, FCB->PathNameU.Length);
703 }
704 }
705 else
706 {
707 FCB = NULL;
708 }
709
710 if (FCB == NULL)
711 {
712 FCB = vfatOpenRootFCB(pVCB);
713 curr = pFileNameU->Buffer;
714 }
715
716 parentFCB = NULL;
717 prev = curr;
718 }
719 else
720 {
721 FCB = parentFCB;
722 parentFCB = NULL;
723 prev = curr = pFileNameU->Buffer - 1;
724 last = pFileNameU->Buffer + pFileNameU->Length / sizeof(WCHAR) - 1;
725 }
726
727 while (curr <= last)
728 {
729 if (parentFCB)
730 {
731 vfatReleaseFCB (pVCB, parentFCB);
732 parentFCB = 0;
733 }
734 // fail if element in FCB is not a directory
735 if (!vfatFCBIsDirectory (FCB))
736 {
737 DPRINT ("Element in requested path is not a directory\n");
738
739 vfatReleaseFCB (pVCB, FCB);
740 FCB = NULL;
741 *pParentFCB = NULL;
742 *pFCB = NULL;
743
744 return STATUS_OBJECT_PATH_NOT_FOUND;
745 }
746 parentFCB = FCB;
747 if (prev < curr)
748 {
749 Length = (curr - prev) * sizeof(WCHAR);
750 if (Length != parentFCB->LongNameU.Length)
751 {
752 if (pFileNameU->Length + parentFCB->LongNameU.Length - Length > pFileNameU->MaximumLength)
753 {
754 vfatReleaseFCB (pVCB, parentFCB);
755 return STATUS_OBJECT_NAME_INVALID;
756 }
757 memmove(prev + parentFCB->LongNameU.Length / sizeof(WCHAR), curr,
758 pFileNameU->Length - (curr - pFileNameU->Buffer) * sizeof(WCHAR));
759 pFileNameU->Length += parentFCB->LongNameU.Length - Length;
760 curr = prev + parentFCB->LongNameU.Length / sizeof(WCHAR);
761 last = pFileNameU->Buffer + pFileNameU->Length / sizeof(WCHAR) - 1;
762 }
763 RtlCopyMemory(prev, parentFCB->LongNameU.Buffer, parentFCB->LongNameU.Length);
764 }
765 curr++;
766 prev = curr;
767 while (*curr != L'\\' && curr <= last)
768 {
769 curr++;
770 }
771 NameU.Buffer = pFileNameU->Buffer;
772 NameU.Length = (curr - NameU.Buffer) * sizeof(WCHAR);
773 NameU.MaximumLength = pFileNameU->MaximumLength;
774 DPRINT("%wZ\n", &NameU);
775 FCB = vfatGrabFCBFromTable(pVCB, &NameU);
776 if (FCB == NULL)
777 {
778 NameU.Buffer = prev;
779 NameU.MaximumLength = NameU.Length = (curr - prev) * sizeof(WCHAR);
780 status = vfatDirFindFile(pVCB, parentFCB, &NameU, &FCB);
781 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
782 {
783 *pFCB = NULL;
784 if (curr > last)
785 {
786 *pParentFCB = parentFCB;
787 return STATUS_OBJECT_NAME_NOT_FOUND;
788 }
789 else
790 {
791 vfatReleaseFCB (pVCB, parentFCB);
792 *pParentFCB = NULL;
793 return STATUS_OBJECT_PATH_NOT_FOUND;
794 }
795 }
796 else if (!NT_SUCCESS (status))
797 {
798 vfatReleaseFCB (pVCB, parentFCB);
799 *pParentFCB = NULL;
800 *pFCB = NULL;
801
802 return status;
803 }
804 }
805 }
806
807 *pParentFCB = parentFCB;
808 *pFCB = FCB;
809
810 return STATUS_SUCCESS;
811 }
812