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