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