update for HEAD-2003050101
[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->FileObject->SectionObjectPointers->SharedCacheMap)
160            {
161               CcRosReleaseFileCache(pFCB->FileObject);
162            }
163            vfatDestroyCCB(pFCB->FileObject->FsContext2);
164            pFCB->FileObject->FsContext2 = NULL;
165            pFCB->FileObject->FsContext = NULL;
166            ObDereferenceObject(pFCB->FileObject);
167         }
168         vfatDestroyFCB (pFCB);
169      }
170      else
171      {
172         KeReleaseSpinLock (&pVCB->FcbListLock, oldIrql);
173         tmpFcb = NULL;
174      }
175      pFCB = tmpFcb;
176   }
177 }
178
179 VOID
180 vfatAddFCBToTable(PDEVICE_EXTENSION  pVCB,  PVFATFCB  pFCB)
181 {
182   KIRQL  oldIrql;
183   ULONG Index;
184   ULONG ShortIndex;
185
186   Index = pFCB->Hash.Hash % FCB_HASH_TABLE_SIZE;
187   ShortIndex = pFCB->ShortHash.Hash % FCB_HASH_TABLE_SIZE;
188   KeAcquireSpinLock (&pVCB->FcbListLock, &oldIrql);
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 = fcb;
291   fileObject->FsContext2 = newCCB;
292   fcb->FileObject = fileObject;
293
294
295   fileCacheQuantum = (vcb->FatInfo.BytesPerCluster >= PAGE_SIZE) ?
296       vcb->FatInfo.BytesPerCluster : PAGE_SIZE;
297
298   status = CcRosInitializeFileCache (fileObject,
299                                      fileCacheQuantum);
300   if (!NT_SUCCESS (status))
301   {
302     DbgPrint ("CcRosInitializeFileCache failed\n");
303     KeBugCheck (0);
304   }
305
306   fcb->Flags |= FCB_CACHE_INITIALIZED;
307
308   return  status;
309 }
310
311 PVFATFCB
312 vfatMakeRootFCB(PDEVICE_EXTENSION  pVCB)
313 {
314   PVFATFCB  FCB;
315   ULONG FirstCluster, CurrentCluster, Size = 0;
316   NTSTATUS Status = STATUS_SUCCESS;
317
318   FCB = vfatNewFCB(L"\\");
319   memset(FCB->entry.Filename, ' ', 11);
320   FCB->ShortName[0] = L'\\';
321   FCB->ShortName[1] = 0;
322   FCB->ShortHash.Hash = FCB->Hash.Hash;
323   FCB->entry.FileSize = pVCB->FatInfo.rootDirectorySectors * pVCB->FatInfo.BytesPerSector;
324   FCB->entry.Attrib = FILE_ATTRIBUTE_DIRECTORY;
325   if (pVCB->FatInfo.FatType == FAT32)
326   {
327     CurrentCluster = FirstCluster = pVCB->FatInfo.RootCluster;
328     FCB->entry.FirstCluster = FirstCluster & 0xffff;
329     FCB->entry.FirstClusterHigh = FirstCluster >> 16;
330
331     while (CurrentCluster != 0xffffffff && NT_SUCCESS(Status))
332     {
333       Size += pVCB->FatInfo.BytesPerCluster;
334       Status = NextCluster (pVCB, NULL, FirstCluster, &CurrentCluster, FALSE);
335     }
336   }
337   else
338   {
339     FCB->entry.FirstCluster = 1;
340     Size = pVCB->FatInfo.rootDirectorySectors * pVCB->FatInfo.BytesPerSector;
341   }
342   FCB->RefCount = 2;
343   FCB->dirIndex = 0;
344   FCB->RFCB.FileSize.QuadPart = Size;
345   FCB->RFCB.ValidDataLength.QuadPart = Size;
346   FCB->RFCB.AllocationSize.QuadPart = Size;
347
348   vfatFCBInitializeCacheFromVolume(pVCB, FCB);
349   vfatAddFCBToTable(pVCB, FCB);
350
351   return(FCB);
352 }
353
354 PVFATFCB
355 vfatOpenRootFCB(PDEVICE_EXTENSION  pVCB)
356 {
357   PVFATFCB  FCB;
358
359   FCB = vfatGrabFCBFromTable (pVCB, L"\\");
360   if (FCB == NULL)
361   {
362     FCB = vfatMakeRootFCB (pVCB);
363   }
364
365   return  FCB;
366 }
367
368 NTSTATUS
369 vfatMakeFCBFromDirEntry(PVCB  vcb,
370                         PVFATFCB  directoryFCB,
371                         PWSTR  longName,
372                         PFAT_DIR_ENTRY  dirEntry,
373                         ULONG startIndex,
374                         ULONG dirIndex,
375                         PVFATFCB* fileFCB)
376 {
377   PVFATFCB  rcFCB;
378   WCHAR  pathName [MAX_PATH];
379   WCHAR  entryName [14];
380   ULONG Size;
381   ULONG hash;
382   
383   if (longName [0] != 0 && wcslen (directoryFCB->PathName) +
384         sizeof(WCHAR) + wcslen (longName) > MAX_PATH)
385   {
386     return  STATUS_OBJECT_NAME_INVALID;
387   }
388   wcscpy (pathName, directoryFCB->PathName);
389   if (!vfatFCBIsRoot (directoryFCB))
390   {
391     wcscat (pathName, L"\\");
392   }
393   hash = vfatNameHash(0, pathName);
394   vfatGetDirEntryName (dirEntry, entryName);
395   if (longName [0] != 0)
396   {
397     wcscat (pathName, longName);
398   }
399   else
400   {
401     wcscat (pathName, entryName);
402   }
403   rcFCB = vfatNewFCB (pathName);
404   memcpy (&rcFCB->entry, dirEntry, sizeof (FAT_DIR_ENTRY));
405   wcscpy(rcFCB->ShortName, entryName);
406   rcFCB->ShortHash.Hash = vfatNameHash(hash, entryName);
407   
408   if (vfatFCBIsDirectory(rcFCB))
409   {
410     ULONG FirstCluster, CurrentCluster;
411     NTSTATUS Status;
412     Size = 0;
413     FirstCluster = vfatDirEntryGetFirstCluster (vcb, &rcFCB->entry);
414     if (FirstCluster == 1)
415     {
416       Size = vcb->FatInfo.rootDirectorySectors * vcb->FatInfo.BytesPerSector;
417     }
418     else
419     {
420       CurrentCluster = FirstCluster;
421       while (CurrentCluster != 0xffffffff)
422       {
423          Size += vcb->FatInfo.BytesPerCluster;
424          Status = NextCluster (vcb, NULL, FirstCluster, &CurrentCluster, FALSE);
425       }
426     }
427   }
428   else
429   {
430     Size = rcFCB->entry.FileSize;
431   }
432   rcFCB->dirIndex = dirIndex;
433   rcFCB->startIndex = startIndex;
434   rcFCB->RFCB.FileSize.QuadPart = Size;
435   rcFCB->RFCB.ValidDataLength.QuadPart = Size;
436   rcFCB->RFCB.AllocationSize.QuadPart = ROUND_UP(Size, vcb->FatInfo.BytesPerCluster);
437   rcFCB->RefCount++;
438   if (vfatFCBIsDirectory(rcFCB))
439     {
440       vfatFCBInitializeCacheFromVolume(vcb, rcFCB);
441     }
442   rcFCB->parentFcb = directoryFCB;
443   vfatAddFCBToTable (vcb, rcFCB);
444   *fileFCB = rcFCB;
445
446   return  STATUS_SUCCESS;
447 }
448
449 NTSTATUS
450 vfatAttachFCBToFileObject (PDEVICE_EXTENSION  vcb,
451                            PVFATFCB  fcb,
452                            PFILE_OBJECT  fileObject)
453 {
454   NTSTATUS  status;
455   PVFATCCB  newCCB;
456
457   newCCB = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList);
458   if (newCCB == NULL)
459   {
460     return  STATUS_INSUFFICIENT_RESOURCES;
461   }
462   memset (newCCB, 0, sizeof (VFATCCB));
463
464   fileObject->Flags = fileObject->Flags | FO_FCB_IS_VALID |
465       FO_DIRECT_CACHE_PAGING_READ;
466   fileObject->SectionObjectPointers = &fcb->SectionObjectPointers;
467   fileObject->FsContext = fcb;
468   fileObject->FsContext2 = newCCB;
469   DPRINT ("file open: fcb:%x file size: %d\n", fcb, fcb->entry.FileSize);
470
471   return  STATUS_SUCCESS;
472 }
473
474 NTSTATUS
475 vfatDirFindFile (PDEVICE_EXTENSION  pDeviceExt,
476                  PVFATFCB  pDirectoryFCB,
477                  PWSTR  pFileToFind,
478                  PVFATFCB * pFoundFCB)
479 {
480   ULONG  directoryIndex;
481   ULONG startIndex;
482   NTSTATUS  status;
483   WCHAR  defaultFileName [2];
484   WCHAR  currentLongName [256];
485   FAT_DIR_ENTRY  currentDirEntry;
486   WCHAR  currentEntryName [256];
487   PVOID Context = NULL;
488   PVOID Page;
489
490   assert (pDeviceExt);
491   assert (pDirectoryFCB);
492   assert (pFileToFind);
493
494   DPRINT ("vfatDirFindFile(VCB:%08x, dirFCB:%08x, File:%S)\n",
495           pDeviceExt,
496           pDirectoryFCB,
497           pFileToFind);
498   DPRINT ("Dir Path:%S\n", pDirectoryFCB->PathName);
499
500   //  default to '.' if no filename specified
501   if (wcslen (pFileToFind) == 0)
502   {
503     defaultFileName [0] = L'.';
504     defaultFileName [1] = 0;
505     pFileToFind = defaultFileName;
506   }
507
508   directoryIndex = 0;
509   while (TRUE)
510   {
511     status = vfatGetNextDirEntry(&Context,
512                                  &Page, 
513                                  pDirectoryFCB,
514                                  &directoryIndex,
515                                  currentLongName,
516                                  &currentDirEntry,
517                                  &startIndex);
518     if (status == STATUS_NO_MORE_ENTRIES)
519     {
520       return STATUS_OBJECT_NAME_NOT_FOUND;
521     }
522
523     DPRINT ("  Index:%d  longName:%S\n",
524             directoryIndex,
525             currentLongName);
526
527     if (!vfatIsDirEntryVolume(&currentDirEntry))
528     {
529       if (currentLongName [0] != L'\0' && wstrcmpjoki (currentLongName, pFileToFind))
530       {
531         DPRINT ("Match found, %S\n", currentLongName);
532         status = vfatMakeFCBFromDirEntry (pDeviceExt,
533                                           pDirectoryFCB,
534                                           currentLongName,
535                                           &currentDirEntry,
536                                           startIndex, 
537                                           directoryIndex,
538                                           pFoundFCB);
539         CcUnpinData(Context);
540         return  status;
541       }
542       else
543       {
544         vfatGetDirEntryName (&currentDirEntry, currentEntryName);
545         DPRINT ("  entryName:%S\n", currentEntryName);
546
547         if (wstrcmpjoki (currentEntryName, pFileToFind))
548         {
549           DPRINT ("Match found, %S\n", currentEntryName);
550           status = vfatMakeFCBFromDirEntry (pDeviceExt,
551                                             pDirectoryFCB,
552                                             currentLongName,
553                                             &currentDirEntry,
554                                             startIndex,
555                                             directoryIndex,
556                                             pFoundFCB);
557           CcUnpinData(Context);
558           return  status;
559         }
560       }
561     }
562     directoryIndex++;
563   }
564
565   return  STATUS_OBJECT_NAME_NOT_FOUND;
566 }
567
568 NTSTATUS
569 vfatGetFCBForFile (PDEVICE_EXTENSION  pVCB,
570                    PVFATFCB  *pParentFCB,
571                    PVFATFCB  *pFCB,
572                    const PWSTR  pFileName)
573 {
574   NTSTATUS  status;
575   WCHAR  pathName [MAX_PATH];
576   WCHAR  elementName [MAX_PATH];
577   PWCHAR  currentElement;
578   PVFATFCB  FCB;
579   PVFATFCB  parentFCB;
580
581   DPRINT ("vfatGetFCBForFile (%x,%x,%x,%S)\n",
582           pVCB,
583           pParentFCB,
584           pFCB,
585           pFileName);
586
587   //  Trivial case, open of the root directory on volume
588   if (pFileName [0] == L'\0' || wcscmp (pFileName, L"\\") == 0)
589   {
590     DPRINT ("returning root FCB\n");
591
592     FCB = vfatOpenRootFCB (pVCB);
593     *pFCB = FCB;
594     *pParentFCB = NULL;
595
596     return  (FCB != NULL) ? STATUS_SUCCESS : STATUS_OBJECT_PATH_NOT_FOUND;
597   }
598
599   currentElement = wcsrchr(pFileName, L'\\');
600   wcsncpy(pathName, pFileName, currentElement - pFileName);
601   pathName[currentElement - pFileName] = L'\0';
602   currentElement++;
603
604   FCB = vfatGrabFCBFromTable(pVCB, pathName);
605   if (FCB == NULL)
606   {
607      currentElement = pFileName + 1;
608      wcscpy (pathName, L"\\");
609      FCB = vfatOpenRootFCB (pVCB);
610   }
611   parentFCB = NULL;
612
613   //  Parse filename and check each path element for existance and access
614   while (vfatGetNextPathElement (currentElement) != 0)
615   {
616     //  Skip blank directory levels
617     if ((vfatGetNextPathElement (currentElement) - currentElement) == 0)
618     {
619       currentElement++;
620       continue;
621     }
622
623     DPRINT ("Parsing, currentElement:%S\n", currentElement);
624     DPRINT ("  parentFCB:%x FCB:%x\n", parentFCB, FCB);
625
626     //  descend to next directory level
627     if (parentFCB)
628     {
629       vfatReleaseFCB (pVCB, parentFCB);
630       parentFCB = 0;
631     }
632     //  fail if element in FCB is not a directory
633     if (!vfatFCBIsDirectory (FCB))
634     {
635       DPRINT ("Element in requested path is not a directory\n");
636
637       vfatReleaseFCB (pVCB, FCB);
638       FCB = 0;
639       *pParentFCB = NULL;
640       *pFCB = NULL;
641
642       return  STATUS_OBJECT_PATH_NOT_FOUND;
643     }
644     parentFCB = FCB;
645
646     //  Extract next directory level into dirName
647     vfatWSubString (pathName,
648                     pFileName,
649                     vfatGetNextPathElement (currentElement) - pFileName);
650     DPRINT ("  pathName:%S\n", pathName);
651
652     FCB = vfatGrabFCBFromTable (pVCB, pathName);
653     if (FCB == NULL)
654     {
655       vfatWSubString (elementName,
656                       currentElement,
657                       vfatGetNextPathElement (currentElement) - currentElement);
658       DPRINT ("  elementName:%S\n", elementName);
659
660       status = vfatDirFindFile (pVCB, parentFCB, elementName, &FCB);
661       if (status == STATUS_OBJECT_NAME_NOT_FOUND)
662       {
663         *pParentFCB = parentFCB;
664         *pFCB = NULL;
665         currentElement = vfatGetNextPathElement(currentElement);
666         if (*currentElement == L'\0' || vfatGetNextPathElement(currentElement + 1) == 0)
667         {
668           return  STATUS_OBJECT_NAME_NOT_FOUND;
669         }
670         else
671         {
672           return  STATUS_OBJECT_PATH_NOT_FOUND;
673         }
674       }
675       else if (!NT_SUCCESS (status))
676       {
677         vfatReleaseFCB (pVCB, parentFCB);
678         *pParentFCB = NULL;
679         *pFCB = NULL;
680
681         return  status;
682       }
683     }
684     currentElement = vfatGetNextPathElement (currentElement);
685   }
686
687   *pParentFCB = parentFCB;
688   *pFCB = FCB;
689
690   return  STATUS_SUCCESS;
691 }
692
693
694
695