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