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