branch update for HEAD-2003021201
[reactos.git] / drivers / fs / vfat / fcb.c
1 /* $Id$
2  *
3  *
4  * FILE:             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  */
11
12 /*  -------------------------------------------------------  INCLUDES  */
13
14 #include <ddk/ntddk.h>
15 #include <wchar.h>
16 #include <limits.h>
17
18 #define NDEBUG
19 #include <debug.h>
20
21 #include "vfat.h"
22
23 /*  --------------------------------------------------------  DEFINES  */
24
25 #define TAG(A, B, C, D) (ULONG)(((A)<<0) + ((B)<<8) + ((C)<<16) + ((D)<<24))
26 #define TAG_FCB TAG('V', 'F', 'C', 'B')
27
28 #define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
29
30 /*  --------------------------------------------------------  PUBLICS  */
31
32 ULONG vfatNameHash(ULONG hash, PWCHAR name)
33 {
34   WCHAR c;
35   while(c = *name++)
36   {
37     c = towlower(c);
38     hash = (hash + (c << 4) + (c >> 4)) * 11;
39   }
40   return hash;
41 }
42
43 PVFATFCB
44 vfatNewFCB(PWCHAR pFileName)
45 {
46   PVFATFCB  rcFCB;
47
48   rcFCB = ExAllocateFromNPagedLookasideList(&VfatGlobalData->FcbLookasideList);
49   memset (rcFCB, 0, sizeof (VFATFCB));
50   if (pFileName)
51   {
52     wcscpy (rcFCB->PathName, pFileName);
53     rcFCB->ObjectName = wcsrchr(rcFCB->PathName, L'\\');
54     if (rcFCB->ObjectName == NULL)
55     {
56       rcFCB->ObjectName = rcFCB->PathName;
57     }
58     rcFCB->Hash.Hash = vfatNameHash(0, rcFCB->PathName);
59     DPRINT("%08x (%03x) '%S'\n", rcFCB->Hash.Hash, rcFCB->Hash.Hash % FCB_HASH_TABLE_SIZE, pFileName);
60   }
61   rcFCB->Hash.self = rcFCB;
62   rcFCB->ShortHash.self = rcFCB;
63   ExInitializeResourceLite(&rcFCB->PagingIoResource);
64   ExInitializeResourceLite(&rcFCB->MainResource);
65   FsRtlInitializeFileLock(&rcFCB->FileLock, NULL, NULL); 
66   return  rcFCB;
67 }
68
69 VOID 
70 vfatDestroyCCB(PVFATCCB pCcb)
71 {
72   if (pCcb->DirectorySearchPattern)
73   {
74      ExFreePool(pCcb->DirectorySearchPattern);
75   }
76   ExFreeToNPagedLookasideList(&VfatGlobalData->CcbLookasideList, pCcb);
77 }
78
79 VOID
80 vfatDestroyFCB(PVFATFCB  pFCB)
81 {
82   FsRtlUninitializeFileLock(&pFCB->FileLock); 
83   ExDeleteResourceLite(&pFCB->PagingIoResource);
84   ExDeleteResourceLite(&pFCB->MainResource);
85   if ((pFCB->Flags & FCB_IS_PAGE_FILE) && pFCB->FatChainSize)
86         ExFreePool(pFCB->FatChain);
87   ExFreeToNPagedLookasideList(&VfatGlobalData->FcbLookasideList, pFCB);
88 }
89
90 BOOL
91 vfatFCBIsDirectory(PVFATFCB FCB)
92 {
93   return  FCB->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY;
94 }
95
96 BOOL
97 vfatFCBIsRoot(PVFATFCB FCB)
98 {
99     return  FCB->PathName[0] == L'\\' && FCB->PathName[1] == 0 ? TRUE : FALSE;
100 }
101
102 VOID
103 vfatReleaseFCB(PDEVICE_EXTENSION  pVCB,  PVFATFCB  pFCB)
104 {
105   KIRQL  oldIrql;
106   HASHENTRY* entry;
107   ULONG Index;
108   ULONG ShortIndex;
109   PVFATFCB tmpFcb;
110
111   DPRINT ("releasing FCB at %x: %S, refCount:%d\n",
112           pFCB,
113           pFCB->PathName,
114           pFCB->RefCount);
115
116   while (pFCB)
117   {
118      Index = pFCB->Hash.Hash % FCB_HASH_TABLE_SIZE;
119      ShortIndex = pFCB->ShortHash.Hash % FCB_HASH_TABLE_SIZE;
120      KeAcquireSpinLock (&pVCB->FcbListLock, &oldIrql);
121      pFCB->RefCount--;
122      if (pFCB->RefCount <= 0 && (!vfatFCBIsDirectory (pFCB) || pFCB->Flags & FCB_DELETE_PENDING))
123      {
124         tmpFcb = pFCB->parentFcb;
125         RemoveEntryList (&pFCB->FcbListEntry);  
126         if (pFCB->Hash.Hash != pFCB->ShortHash.Hash)
127         {
128            entry = pVCB->FcbHashTable[ShortIndex];
129            if (entry->self == pFCB)
130            {
131               pVCB->FcbHashTable[ShortIndex] = entry->next;
132            }
133            else
134            {
135               while (entry->next->self != pFCB)
136               {
137                  entry = entry->next;
138               }
139               entry->next = pFCB->ShortHash.next;
140            }
141         }
142         entry = pVCB->FcbHashTable[Index];
143         if (entry->self == pFCB)
144         {
145            pVCB->FcbHashTable[Index] = entry->next;
146         }
147         else
148         {
149            while (entry->next->self != pFCB)
150            {
151               entry = entry->next;
152            }
153            entry->next = pFCB->Hash.next;
154         }
155         KeReleaseSpinLock (&pVCB->FcbListLock, oldIrql);
156         if (vfatFCBIsDirectory(pFCB))
157         {
158            /* Uninitialize file cache if initialized for this file object. */
159            if (pFCB->RFCB.Bcb != NULL)
160            {
161               CcRosReleaseFileCache(pFCB->FileObject, pFCB->RFCB.Bcb);
162            }
163            vfatDestroyCCB(pFCB->FileObject->FsContext2);
164            pFCB->FileObject->FsContext2 = NULL;
165            ObDereferenceObject(pFCB->FileObject);
166         }
167         vfatDestroyFCB (pFCB);
168      }
169      else
170      {
171         KeReleaseSpinLock (&pVCB->FcbListLock, oldIrql);
172         tmpFcb = NULL;
173      }
174      pFCB = tmpFcb;
175   }
176 }
177
178 VOID
179 vfatAddFCBToTable(PDEVICE_EXTENSION  pVCB,  PVFATFCB  pFCB)
180 {
181   KIRQL  oldIrql;
182   ULONG Index;
183   ULONG ShortIndex;
184
185   Index = pFCB->Hash.Hash % FCB_HASH_TABLE_SIZE;
186   ShortIndex = pFCB->ShortHash.Hash % FCB_HASH_TABLE_SIZE;
187   KeAcquireSpinLock (&pVCB->FcbListLock, &oldIrql);
188   pFCB->pDevExt = pVCB;
189   InsertTailList (&pVCB->FcbListHead, &pFCB->FcbListEntry);
190    
191   pFCB->Hash.next = pVCB->FcbHashTable[Index];
192   pVCB->FcbHashTable[Index] = &pFCB->Hash;
193   if (pFCB->Hash.Hash != pFCB->ShortHash.Hash)
194   {
195      pFCB->ShortHash.next = pVCB->FcbHashTable[ShortIndex];
196      pVCB->FcbHashTable[ShortIndex] = &pFCB->ShortHash;
197   }
198   if (pFCB->parentFcb)
199   {
200      pFCB->parentFcb->RefCount++;
201   }
202   KeReleaseSpinLock (&pVCB->FcbListLock, oldIrql);
203 }
204
205 PVFATFCB
206 vfatGrabFCBFromTable(PDEVICE_EXTENSION  pVCB, PWSTR  pFileName)
207 {
208   KIRQL  oldIrql;
209   PVFATFCB  rcFCB;
210   PLIST_ENTRY  current_entry;
211   ULONG Hash;
212   PWCHAR ObjectName = NULL;
213   ULONG len;
214   ULONG index;
215   ULONG currentindex;
216   
217   HASHENTRY* entry; 
218
219   Hash = vfatNameHash(0, pFileName);
220
221   KeAcquireSpinLock (&pVCB->FcbListLock, &oldIrql);
222   entry = pVCB->FcbHashTable[Hash % FCB_HASH_TABLE_SIZE];
223
224   while (entry)
225   {
226      if (entry->Hash == Hash)
227      {
228         rcFCB = entry->self;
229         if (rcFCB->Hash.Hash == Hash)
230         {
231            /* compare the long name */
232            if (!_wcsicmp(pFileName, rcFCB->PathName))
233            {
234               rcFCB->RefCount++;
235               KeReleaseSpinLock (&pVCB->FcbListLock, oldIrql);
236               return rcFCB;
237            }
238         }
239         else
240         {
241            len = rcFCB->ObjectName - rcFCB->PathName + 1;
242            if (ObjectName == NULL)
243            {
244               ObjectName = wcsrchr(pFileName, L'\\');
245               if (ObjectName == NULL)
246               {
247                 ObjectName = pFileName;
248               }
249               else
250               {
251                 ObjectName++;
252               }
253            }
254
255            /* compare the short name and the directory */
256            if (!_wcsicmp(ObjectName, rcFCB->ShortName) && !_wcsnicmp(pFileName, rcFCB->PathName, len))
257            {
258               rcFCB->RefCount++;
259               KeReleaseSpinLock (&pVCB->FcbListLock, oldIrql);
260               return rcFCB;
261            }
262         }
263      }
264      entry = entry->next;
265   }
266   KeReleaseSpinLock (&pVCB->FcbListLock, oldIrql);
267
268   return  NULL;
269 }
270
271 NTSTATUS
272 vfatFCBInitializeCacheFromVolume (PVCB  vcb, PVFATFCB  fcb)
273 {
274   NTSTATUS  status;
275   PFILE_OBJECT  fileObject;
276   ULONG  fileCacheQuantum;
277   PVFATCCB  newCCB;
278
279   fileObject = IoCreateStreamFileObject (NULL, vcb->StorageDevice);
280
281   newCCB = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList);
282   if (newCCB == NULL)
283   {
284     return  STATUS_INSUFFICIENT_RESOURCES;
285   }
286   memset (newCCB, 0, sizeof (VFATCCB));
287
288   fileObject->Flags |= FO_FCB_IS_VALID | FO_DIRECT_CACHE_PAGING_READ;
289   fileObject->SectionObjectPointers = &fcb->SectionObjectPointers;
290   fileObject->FsContext = (PVOID) &fcb->RFCB;
291   fileObject->FsContext2 = newCCB;
292   newCCB->pFcb = fcb;
293   newCCB->PtrFileObject = fileObject;
294   fcb->FileObject = fileObject;
295   fcb->pDevExt = vcb;
296
297
298   fileCacheQuantum = (vcb->FatInfo.BytesPerCluster >= PAGE_SIZE) ?
299       vcb->FatInfo.BytesPerCluster : PAGE_SIZE;
300
301   status = CcRosInitializeFileCache (fileObject,
302                                      &fcb->RFCB.Bcb,
303                                      fileCacheQuantum);
304   if (!NT_SUCCESS (status))
305   {
306     DbgPrint ("CcRosInitializeFileCache failed\n");
307     KeBugCheck (0);
308   }
309
310   fcb->Flags |= FCB_CACHE_INITIALIZED;
311
312   return  status;
313 }
314
315 PVFATFCB
316 vfatMakeRootFCB(PDEVICE_EXTENSION  pVCB)
317 {
318   PVFATFCB  FCB;
319   ULONG FirstCluster, CurrentCluster, Size = 0;
320   NTSTATUS Status = STATUS_SUCCESS;
321
322   FCB = vfatNewFCB(L"\\");
323   memset(FCB->entry.Filename, ' ', 11);
324   FCB->ShortName[0] = L'\\';
325   FCB->ShortName[1] = 0;
326   FCB->ShortHash.Hash = FCB->Hash.Hash;
327   FCB->entry.FileSize = pVCB->FatInfo.rootDirectorySectors * pVCB->FatInfo.BytesPerSector;
328   FCB->entry.Attrib = FILE_ATTRIBUTE_DIRECTORY;
329   if (pVCB->FatInfo.FatType == FAT32)
330   {
331     CurrentCluster = FirstCluster = pVCB->FatInfo.RootCluster;
332     FCB->entry.FirstCluster = FirstCluster & 0xffff;
333     FCB->entry.FirstClusterHigh = FirstCluster >> 16;
334     CurrentCluster = FirstCluster;
335
336     while (CurrentCluster != 0xffffffff && NT_SUCCESS(Status))
337     {
338       Size += pVCB->FatInfo.BytesPerCluster;
339       Status = NextCluster (pVCB, NULL, FirstCluster, &CurrentCluster, FALSE);
340     }
341   }
342   else
343   {
344     FCB->entry.FirstCluster = 1;
345     Size = pVCB->FatInfo.rootDirectorySectors * pVCB->FatInfo.BytesPerSector;
346   }
347   FCB->RefCount = 2;
348   FCB->dirIndex = 0;
349   FCB->RFCB.FileSize.QuadPart = Size;
350   FCB->RFCB.ValidDataLength.QuadPart = Size;
351   FCB->RFCB.AllocationSize.QuadPart = Size;
352
353   vfatFCBInitializeCacheFromVolume(pVCB, FCB);
354   vfatAddFCBToTable(pVCB, FCB);
355
356   return(FCB);
357 }
358
359 PVFATFCB
360 vfatOpenRootFCB(PDEVICE_EXTENSION  pVCB)
361 {
362   PVFATFCB  FCB;
363
364   FCB = vfatGrabFCBFromTable (pVCB, L"\\");
365   if (FCB == NULL)
366   {
367     FCB = vfatMakeRootFCB (pVCB);
368   }
369
370   return  FCB;
371 }
372
373 NTSTATUS
374 vfatMakeFCBFromDirEntry(PVCB  vcb,
375                         PVFATFCB  directoryFCB,
376                         PWSTR  longName,
377                         PFAT_DIR_ENTRY  dirEntry,
378                         ULONG startIndex,
379                         ULONG dirIndex,
380                         PVFATFCB* fileFCB)
381 {
382   PVFATFCB  rcFCB;
383   WCHAR  pathName [MAX_PATH];
384   WCHAR  entryName [14];
385   ULONG Size;
386   ULONG hash;
387   
388   if (longName [0] != 0 && wcslen (directoryFCB->PathName) +
389         sizeof(WCHAR) + wcslen (longName) > MAX_PATH)
390   {
391     return  STATUS_OBJECT_NAME_INVALID;
392   }
393   wcscpy (pathName, directoryFCB->PathName);
394   if (!vfatFCBIsRoot (directoryFCB))
395   {
396     wcscat (pathName, L"\\");
397   }
398   hash = vfatNameHash(0, pathName);
399   vfatGetDirEntryName (dirEntry, entryName);
400   if (longName [0] != 0)
401   {
402     wcscat (pathName, longName);
403   }
404   else
405   {
406     wcscat (pathName, entryName);
407   }
408   rcFCB = vfatNewFCB (pathName);
409   memcpy (&rcFCB->entry, dirEntry, sizeof (FAT_DIR_ENTRY));
410   wcscpy(rcFCB->ShortName, entryName);
411   rcFCB->ShortHash.Hash = vfatNameHash(hash, entryName);
412   
413   if (vfatFCBIsDirectory(rcFCB))
414   {
415     ULONG FirstCluster, CurrentCluster;
416     NTSTATUS Status;
417     Size = 0;
418     FirstCluster = vfatDirEntryGetFirstCluster (vcb, &rcFCB->entry);
419     if (FirstCluster == 1)
420     {
421       Size = vcb->FatInfo.rootDirectorySectors * vcb->FatInfo.BytesPerSector;
422     }
423     else
424     {
425       CurrentCluster = FirstCluster;
426       while (CurrentCluster != 0xffffffff)
427       {
428          Size += vcb->FatInfo.BytesPerCluster;
429          Status = NextCluster (vcb, NULL, FirstCluster, &CurrentCluster, FALSE);
430       }
431     }
432   }
433   else
434   {
435     Size = rcFCB->entry.FileSize;
436   }
437   rcFCB->dirIndex = dirIndex;
438   rcFCB->startIndex = startIndex;
439   rcFCB->RFCB.FileSize.QuadPart = Size;
440   rcFCB->RFCB.ValidDataLength.QuadPart = Size;
441   rcFCB->RFCB.AllocationSize.QuadPart = ROUND_UP(Size, vcb->FatInfo.BytesPerCluster);
442   rcFCB->RefCount++;
443   if (vfatFCBIsDirectory(rcFCB))
444     {
445       vfatFCBInitializeCacheFromVolume(vcb, rcFCB);
446     }
447   rcFCB->parentFcb = directoryFCB;
448   vfatAddFCBToTable (vcb, rcFCB);
449   *fileFCB = rcFCB;
450
451   return  STATUS_SUCCESS;
452 }
453
454 NTSTATUS
455 vfatAttachFCBToFileObject (PDEVICE_EXTENSION  vcb,
456                            PVFATFCB  fcb,
457                            PFILE_OBJECT  fileObject)
458 {
459   NTSTATUS  status;
460   PVFATCCB  newCCB;
461
462   newCCB = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList);
463   if (newCCB == NULL)
464   {
465     return  STATUS_INSUFFICIENT_RESOURCES;
466   }
467   memset (newCCB, 0, sizeof (VFATCCB));
468
469   fileObject->Flags = fileObject->Flags | FO_FCB_IS_VALID |
470       FO_DIRECT_CACHE_PAGING_READ;
471   fileObject->SectionObjectPointers = &fcb->SectionObjectPointers;
472   fileObject->FsContext = (PVOID) &fcb->RFCB;
473   fileObject->FsContext2 = newCCB;
474   newCCB->pFcb = fcb;
475   newCCB->PtrFileObject = fileObject;
476   fcb->pDevExt = vcb;
477   DPRINT ("file open: fcb:%x file size: %d\n", fcb, fcb->entry.FileSize);
478
479   return  STATUS_SUCCESS;
480 }
481
482 NTSTATUS
483 vfatDirFindFile (PDEVICE_EXTENSION  pDeviceExt,
484                  PVFATFCB  pDirectoryFCB,
485                  PWSTR  pFileToFind,
486                  PVFATFCB * pFoundFCB)
487 {
488   ULONG  directoryIndex;
489   ULONG startIndex;
490   NTSTATUS  status;
491   WCHAR  defaultFileName [2];
492   WCHAR  currentLongName [256];
493   FAT_DIR_ENTRY  currentDirEntry;
494   WCHAR  currentEntryName [256];
495   PVOID Context = NULL;
496   PVOID Page;
497
498   assert (pDeviceExt);
499   assert (pDirectoryFCB);
500   assert (pFileToFind);
501
502   DPRINT ("vfatDirFindFile(VCB:%08x, dirFCB:%08x, File:%S)\n",
503           pDeviceExt,
504           pDirectoryFCB,
505           pFileToFind);
506   DPRINT ("Dir Path:%S\n", pDirectoryFCB->PathName);
507
508   //  default to '.' if no filename specified
509   if (wcslen (pFileToFind) == 0)
510   {
511     defaultFileName [0] = L'.';
512     defaultFileName [1] = 0;
513     pFileToFind = defaultFileName;
514   }
515
516   directoryIndex = 0;
517   while (TRUE)
518   {
519     status = vfatGetNextDirEntry(&Context,
520                                  &Page, 
521                                  pDirectoryFCB,
522                                  &directoryIndex,
523                                  currentLongName,
524                                  &currentDirEntry,
525                                  &startIndex);
526     if (status == STATUS_NO_MORE_ENTRIES)
527     {
528       return STATUS_OBJECT_NAME_NOT_FOUND;
529     }
530
531     DPRINT ("  Index:%d  longName:%S\n",
532             directoryIndex,
533             currentLongName);
534
535     if (!vfatIsDirEntryVolume(&currentDirEntry))
536     {
537       if (currentLongName [0] != L'\0' && wstrcmpjoki (currentLongName, pFileToFind))
538       {
539         DPRINT ("Match found, %S\n", currentLongName);
540         status = vfatMakeFCBFromDirEntry (pDeviceExt,
541                                           pDirectoryFCB,
542                                           currentLongName,
543                                           &currentDirEntry,
544                                           startIndex, 
545                                           directoryIndex,
546                                           pFoundFCB);
547         CcUnpinData(Context);
548         return  status;
549       }
550       else
551       {
552         vfatGetDirEntryName (&currentDirEntry, currentEntryName);
553         DPRINT ("  entryName:%S\n", currentEntryName);
554
555         if (wstrcmpjoki (currentEntryName, pFileToFind))
556         {
557           DPRINT ("Match found, %S\n", currentEntryName);
558           status = vfatMakeFCBFromDirEntry (pDeviceExt,
559                                             pDirectoryFCB,
560                                             currentLongName,
561                                             &currentDirEntry,
562                                             startIndex,
563                                             directoryIndex,
564                                             pFoundFCB);
565           CcUnpinData(Context);
566           return  status;
567         }
568       }
569     }
570     directoryIndex++;
571   }
572
573   return  STATUS_OBJECT_NAME_NOT_FOUND;
574 }
575
576 NTSTATUS
577 vfatGetFCBForFile (PDEVICE_EXTENSION  pVCB,
578                    PVFATFCB  *pParentFCB,
579                    PVFATFCB  *pFCB,
580                    const PWSTR  pFileName)
581 {
582   NTSTATUS  status;
583   WCHAR  pathName [MAX_PATH];
584   WCHAR  elementName [MAX_PATH];
585   PWCHAR  currentElement;
586   PVFATFCB  FCB;
587   PVFATFCB  parentFCB;
588
589   DPRINT ("vfatGetFCBForFile (%x,%x,%x,%S)\n",
590           pVCB,
591           pParentFCB,
592           pFCB,
593           pFileName);
594
595   //  Trivial case, open of the root directory on volume
596   if (pFileName [0] == L'\0' || wcscmp (pFileName, L"\\") == 0)
597   {
598     DPRINT ("returning root FCB\n");
599
600     FCB = vfatOpenRootFCB (pVCB);
601     *pFCB = FCB;
602     *pParentFCB = NULL;
603
604     return  (FCB != NULL) ? STATUS_SUCCESS : STATUS_OBJECT_PATH_NOT_FOUND;
605   }
606
607   currentElement = wcsrchr(pFileName, L'\\');
608   wcsncpy(pathName, pFileName, currentElement - pFileName);
609   pathName[currentElement - pFileName] = L'\0';
610   currentElement++;
611
612   FCB = vfatGrabFCBFromTable(pVCB, pathName);
613   if (FCB == NULL)
614   {
615      currentElement = pFileName + 1;
616      wcscpy (pathName, L"\\");
617      FCB = vfatOpenRootFCB (pVCB);
618   }
619   parentFCB = NULL;
620
621   //  Parse filename and check each path element for existance and access
622   while (vfatGetNextPathElement (currentElement) != 0)
623   {
624     //  Skip blank directory levels
625     if ((vfatGetNextPathElement (currentElement) - currentElement) == 0)
626     {
627       currentElement++;
628       continue;
629     }
630
631     DPRINT ("Parsing, currentElement:%S\n", currentElement);
632     DPRINT ("  parentFCB:%x FCB:%x\n", parentFCB, FCB);
633
634     //  descend to next directory level
635     if (parentFCB)
636     {
637       vfatReleaseFCB (pVCB, parentFCB);
638       parentFCB = 0;
639     }
640     //  fail if element in FCB is not a directory
641     if (!vfatFCBIsDirectory (FCB))
642     {
643       DPRINT ("Element in requested path is not a directory\n");
644
645       vfatReleaseFCB (pVCB, FCB);
646       FCB = 0;
647       *pParentFCB = NULL;
648       *pFCB = NULL;
649
650       return  STATUS_OBJECT_PATH_NOT_FOUND;
651     }
652     parentFCB = FCB;
653
654     //  Extract next directory level into dirName
655     vfatWSubString (pathName,
656                     pFileName,
657                     vfatGetNextPathElement (currentElement) - pFileName);
658     DPRINT ("  pathName:%S\n", pathName);
659
660     FCB = vfatGrabFCBFromTable (pVCB, pathName);
661     if (FCB == NULL)
662     {
663       vfatWSubString (elementName,
664                       currentElement,
665                       vfatGetNextPathElement (currentElement) - currentElement);
666       DPRINT ("  elementName:%S\n", elementName);
667
668       status = vfatDirFindFile (pVCB, parentFCB, elementName, &FCB);
669       if (status == STATUS_OBJECT_NAME_NOT_FOUND)
670       {
671         *pParentFCB = parentFCB;
672         *pFCB = NULL;
673         currentElement = vfatGetNextPathElement(currentElement);
674         if (*currentElement == L'\0' || vfatGetNextPathElement(currentElement + 1) == 0)
675         {
676           return  STATUS_OBJECT_NAME_NOT_FOUND;
677         }
678         else
679         {
680           return  STATUS_OBJECT_PATH_NOT_FOUND;
681         }
682       }
683       else if (!NT_SUCCESS (status))
684       {
685         vfatReleaseFCB (pVCB, parentFCB);
686         *pParentFCB = NULL;
687         *pFCB = NULL;
688
689         return  status;
690       }
691     }
692     currentElement = vfatGetNextPathElement (currentElement);
693   }
694
695   *pParentFCB = parentFCB;
696   *pFCB = FCB;
697
698   return  STATUS_SUCCESS;
699 }
700
701
702
703