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)
12 /* ------------------------------------------------------- INCLUDES */
14 #include <ddk/ntddk.h>
23 /* -------------------------------------------------------- DEFINES */
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')
28 #define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
30 /* -------------------------------------------------------- PUBLICS */
33 vfatNewFCB(PWCHAR pFileName)
37 rcFCB = ExAllocatePoolWithTag (NonPagedPool, sizeof (VFATFCB), TAG_FCB);
38 memset (rcFCB, 0, sizeof (VFATFCB));
41 wcscpy (rcFCB->PathName, pFileName);
42 if (wcsrchr (rcFCB->PathName, '\\') != 0)
44 rcFCB->ObjectName = wcsrchr (rcFCB->PathName, '\\');
48 rcFCB->ObjectName = rcFCB->PathName;
51 ExInitializeResourceLite(&rcFCB->PagingIoResource);
52 ExInitializeResourceLite(&rcFCB->MainResource);
57 vfatDestroyFCB(PVFATFCB pFCB)
59 ExDeleteResourceLite(&pFCB->PagingIoResource);
60 ExDeleteResourceLite(&pFCB->MainResource);
61 if ((pFCB->Flags & FCB_IS_PAGE_FILE) && pFCB->FatChainSize)
62 ExFreePool(pFCB->FatChain);
67 vfatFCBIsDirectory(PDEVICE_EXTENSION pVCB, PVFATFCB FCB)
69 return FCB->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY;
73 vfatFCBIsRoot(PVFATFCB FCB)
75 return wcscmp (FCB->PathName, L"\\") == 0;
79 vfatGrabFCB(PDEVICE_EXTENSION pVCB, PVFATFCB pFCB)
83 DPRINT ("grabbing FCB at %x: %S, refCount:%d\n",
88 KeAcquireSpinLock (&pVCB->FcbListLock, &oldIrql);
90 KeReleaseSpinLock (&pVCB->FcbListLock, oldIrql);
94 vfatReleaseFCB(PDEVICE_EXTENSION pVCB, PVFATFCB pFCB)
98 DPRINT ("releasing FCB at %x: %S, refCount:%d\n",
103 KeAcquireSpinLock (&pVCB->FcbListLock, &oldIrql);
105 if (pFCB->RefCount <= 0 && (!vfatFCBIsDirectory (pVCB, pFCB) || pFCB->Flags & FCB_DELETE_PENDING))
107 RemoveEntryList (&pFCB->FcbListEntry);
108 KeReleaseSpinLock (&pVCB->FcbListLock, oldIrql);
109 if (vfatFCBIsDirectory(pVCB, pFCB))
111 CcRosReleaseFileCache(pFCB->FileObject, pFCB->RFCB.Bcb);
112 ExFreePool(pFCB->FileObject->FsContext2);
113 pFCB->FileObject->FsContext2 = NULL;
114 ObDereferenceObject(pFCB->FileObject);
116 vfatDestroyFCB (pFCB);
119 KeReleaseSpinLock (&pVCB->FcbListLock, oldIrql);
123 vfatAddFCBToTable(PDEVICE_EXTENSION pVCB, PVFATFCB pFCB)
127 KeAcquireSpinLock (&pVCB->FcbListLock, &oldIrql);
128 pFCB->pDevExt = pVCB;
129 InsertTailList (&pVCB->FcbListHead, &pFCB->FcbListEntry);
130 KeReleaseSpinLock (&pVCB->FcbListLock, oldIrql);
134 vfatGrabFCBFromTable(PDEVICE_EXTENSION pVCB, PWSTR pFileName)
138 PLIST_ENTRY current_entry;
140 KeAcquireSpinLock (&pVCB->FcbListLock, &oldIrql);
141 current_entry = pVCB->FcbListHead.Flink;
142 while (current_entry != &pVCB->FcbListHead)
144 rcFCB = CONTAINING_RECORD (current_entry, VFATFCB, FcbListEntry);
146 if (wstrcmpi (pFileName, rcFCB->PathName))
149 KeReleaseSpinLock (&pVCB->FcbListLock, oldIrql);
153 //FIXME: need to compare against short name in FCB here
155 current_entry = current_entry->Flink;
157 KeReleaseSpinLock (&pVCB->FcbListLock, oldIrql);
163 vfatFCBInitializeCacheFromVolume (PVCB vcb, PVFATFCB fcb)
166 PFILE_OBJECT fileObject;
167 ULONG fileCacheQuantum;
170 fileObject = IoCreateStreamFileObject (NULL, vcb->StorageDevice);
172 newCCB = ExAllocatePoolWithTag (NonPagedPool, sizeof (VFATCCB), TAG_CCB);
175 return STATUS_INSUFFICIENT_RESOURCES;
177 memset (newCCB, 0, sizeof (VFATCCB));
179 fileObject->Flags = fileObject->Flags | FO_FCB_IS_VALID |
180 FO_DIRECT_CACHE_PAGING_READ;
181 fileObject->SectionObjectPointers = &fcb->SectionObjectPointers;
182 fileObject->FsContext = (PVOID) &fcb->RFCB;
183 fileObject->FsContext2 = newCCB;
185 newCCB->PtrFileObject = fileObject;
186 fcb->FileObject = fileObject;
190 fileCacheQuantum = (vcb->FatInfo.BytesPerCluster >= PAGE_SIZE) ?
191 vcb->FatInfo.BytesPerCluster : PAGE_SIZE;
193 status = CcRosInitializeFileCache (fileObject,
196 if (!NT_SUCCESS (status))
198 DbgPrint ("CcRosInitializeFileCache failed\n");
202 fcb->Flags |= FCB_CACHE_INITIALIZED;
208 vfatMakeRootFCB(PDEVICE_EXTENSION pVCB)
211 ULONG FirstCluster, CurrentCluster, Size = 0;
212 NTSTATUS Status = STATUS_SUCCESS;
214 FCB = vfatNewFCB(L"\\");
215 memset(FCB->entry.Filename, ' ', 11);
216 FCB->entry.FileSize = pVCB->FatInfo.rootDirectorySectors * pVCB->FatInfo.BytesPerSector;
217 FCB->entry.Attrib = FILE_ATTRIBUTE_DIRECTORY;
218 if (pVCB->FatInfo.FatType == FAT32)
220 CurrentCluster = FirstCluster = pVCB->FatInfo.RootCluster;
221 FCB->entry.FirstCluster = FirstCluster & 0xffff;
222 FCB->entry.FirstClusterHigh = FirstCluster >> 16;
223 CurrentCluster = FirstCluster;
225 while (CurrentCluster != 0xffffffff && NT_SUCCESS(Status))
227 Size += pVCB->FatInfo.BytesPerCluster;
228 Status = NextCluster (pVCB, NULL, FirstCluster, &CurrentCluster, FALSE);
233 FCB->entry.FirstCluster = 1;
234 Size = pVCB->FatInfo.rootDirectorySectors * pVCB->FatInfo.BytesPerSector;
238 FCB->RFCB.FileSize.QuadPart = Size;
239 FCB->RFCB.ValidDataLength.QuadPart = Size;
240 FCB->RFCB.AllocationSize.QuadPart = Size;
242 vfatFCBInitializeCacheFromVolume(pVCB, FCB);
243 vfatAddFCBToTable(pVCB, FCB);
244 vfatGrabFCB(pVCB, FCB);
250 vfatOpenRootFCB(PDEVICE_EXTENSION pVCB)
254 FCB = vfatGrabFCBFromTable (pVCB, L"\\");
257 FCB = vfatMakeRootFCB (pVCB);
264 vfatMakeFCBFromDirEntry(PVCB vcb,
265 PVFATFCB directoryFCB,
267 PFAT_DIR_ENTRY dirEntry,
272 WCHAR pathName [MAX_PATH];
274 if (longName [0] != 0 && wcslen (directoryFCB->PathName) +
275 sizeof(WCHAR) + wcslen (longName) > MAX_PATH)
277 return STATUS_OBJECT_NAME_INVALID;
279 wcscpy (pathName, directoryFCB->PathName);
280 if (!vfatFCBIsRoot (directoryFCB))
282 wcscat (pathName, L"\\");
284 if (longName [0] != 0)
286 wcscat (pathName, longName);
290 WCHAR entryName [MAX_PATH];
292 vfatGetDirEntryName (dirEntry, entryName);
293 wcscat (pathName, entryName);
295 rcFCB = vfatNewFCB (pathName);
296 memcpy (&rcFCB->entry, dirEntry, sizeof (FAT_DIR_ENTRY));
298 if (vfatFCBIsDirectory(vcb, rcFCB))
300 ULONG FirstCluster, CurrentCluster;
303 FirstCluster = vfatDirEntryGetFirstCluster (vcb, &rcFCB->entry);
304 if (FirstCluster == 1)
306 Size = vcb->FatInfo.rootDirectorySectors * vcb->FatInfo.BytesPerSector;
310 CurrentCluster = FirstCluster;
311 while (CurrentCluster != 0xffffffff)
313 Size += vcb->FatInfo.BytesPerCluster;
314 Status = NextCluster (vcb, NULL, FirstCluster, &CurrentCluster, FALSE);
320 Size = rcFCB->entry.FileSize;
322 rcFCB->dirIndex = dirIndex;
323 rcFCB->RFCB.FileSize.QuadPart = Size;
324 rcFCB->RFCB.ValidDataLength.QuadPart = Size;
325 rcFCB->RFCB.AllocationSize.QuadPart = ROUND_UP(Size, vcb->FatInfo.BytesPerCluster);
327 if (vfatFCBIsDirectory(vcb, rcFCB))
329 vfatFCBInitializeCacheFromVolume(vcb, rcFCB);
331 vfatAddFCBToTable (vcb, rcFCB);
334 return STATUS_SUCCESS;
338 vfatAttachFCBToFileObject (PDEVICE_EXTENSION vcb,
340 PFILE_OBJECT fileObject)
345 newCCB = ExAllocatePoolWithTag (NonPagedPool, sizeof (VFATCCB), TAG_CCB);
348 return STATUS_INSUFFICIENT_RESOURCES;
350 memset (newCCB, 0, sizeof (VFATCCB));
352 fileObject->Flags = fileObject->Flags | FO_FCB_IS_VALID |
353 FO_DIRECT_CACHE_PAGING_READ;
354 fileObject->SectionObjectPointers = &fcb->SectionObjectPointers;
355 fileObject->FsContext = (PVOID) &fcb->RFCB;
356 fileObject->FsContext2 = newCCB;
358 newCCB->PtrFileObject = fileObject;
360 DPRINT ("file open: fcb:%x file size: %d\n", fcb, fcb->entry.FileSize);
362 return STATUS_SUCCESS;
366 vfatDirFindFile (PDEVICE_EXTENSION pDeviceExt,
367 PVFATFCB pDirectoryFCB,
369 PVFATFCB * pFoundFCB)
371 BOOL finishedScanningDirectory;
372 ULONG directoryIndex;
374 WCHAR defaultFileName [2];
375 WCHAR currentLongName [256];
376 FAT_DIR_ENTRY currentDirEntry;
377 WCHAR currentEntryName [256];
380 assert (pDirectoryFCB);
381 assert (pFileToFind);
383 DPRINT ("vfatDirFindFile(VCB:%08x, dirFCB:%08x, File:%S)\n",
387 DPRINT ("Dir Path:%S\n", pDirectoryFCB->PathName);
389 // default to '.' if no filename specified
390 if (wcslen (pFileToFind) == 0)
392 defaultFileName [0] = L'.';
393 defaultFileName [1] = 0;
394 pFileToFind = defaultFileName;
398 finishedScanningDirectory = FALSE;
399 while (!finishedScanningDirectory)
401 status = vfatGetNextDirEntry (pDeviceExt,
406 if (status == STATUS_NO_MORE_ENTRIES)
408 finishedScanningDirectory = TRUE;
411 else if (!NT_SUCCESS(status))
416 DPRINT (" Index:%d longName:%S\n",
420 if (!vfatIsDirEntryDeleted (¤tDirEntry)
421 && !vfatIsDirEntryVolume(¤tDirEntry))
423 if (currentLongName [0] != L'\0' && wstrcmpjoki (currentLongName, pFileToFind))
425 DPRINT ("Match found, %S\n", currentLongName);
426 status = vfatMakeFCBFromDirEntry (pDeviceExt,
436 vfatGetDirEntryName (¤tDirEntry, currentEntryName);
437 DPRINT (" entryName:%S\n", currentEntryName);
439 if (wstrcmpjoki (currentEntryName, pFileToFind))
441 DPRINT ("Match found, %S\n", currentEntryName);
442 status = vfatMakeFCBFromDirEntry (pDeviceExt,
454 return STATUS_OBJECT_NAME_NOT_FOUND;
458 vfatGetFCBForFile (PDEVICE_EXTENSION pVCB,
459 PVFATFCB *pParentFCB,
461 const PWSTR pFileName)
464 WCHAR pathName [MAX_PATH];
465 WCHAR elementName [MAX_PATH];
466 PWCHAR currentElement;
470 DPRINT ("vfatGetFCBForFile (%x,%x,%x,%S)\n",
476 // Trivial case, open of the root directory on volume
477 if (pFileName [0] == L'\0' || wcscmp (pFileName, L"\\") == 0)
479 DPRINT ("returning root FCB\n");
481 FCB = vfatOpenRootFCB (pVCB);
485 return (FCB != NULL) ? STATUS_SUCCESS : STATUS_OBJECT_PATH_NOT_FOUND;
489 currentElement = pFileName + 1;
490 wcscpy (pathName, L"\\");
491 FCB = vfatOpenRootFCB (pVCB);
495 // Parse filename and check each path element for existance and access
496 while (vfatGetNextPathElement (currentElement) != 0)
498 // Skip blank directory levels
499 if ((vfatGetNextPathElement (currentElement) - currentElement) == 0)
505 DPRINT ("Parsing, currentElement:%S\n", currentElement);
506 DPRINT (" parentFCB:%x FCB:%x\n", parentFCB, FCB);
508 // descend to next directory level
511 vfatReleaseFCB (pVCB, parentFCB);
514 // fail if element in FCB is not a directory
515 if (!vfatFCBIsDirectory (pVCB, FCB))
517 DPRINT ("Element in requested path is not a directory\n");
519 vfatReleaseFCB (pVCB, FCB);
524 return STATUS_OBJECT_PATH_NOT_FOUND;
528 // Extract next directory level into dirName
529 vfatWSubString (pathName,
531 vfatGetNextPathElement (currentElement) - pFileName);
532 DPRINT (" pathName:%S\n", pathName);
534 FCB = vfatGrabFCBFromTable (pVCB, pathName);
537 vfatWSubString (elementName,
539 vfatGetNextPathElement (currentElement) - currentElement);
540 DPRINT (" elementName:%S\n", elementName);
542 status = vfatDirFindFile (pVCB, parentFCB, elementName, &FCB);
543 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
545 *pParentFCB = parentFCB;
547 currentElement = vfatGetNextPathElement(currentElement);
548 if (*currentElement == L'\0' || vfatGetNextPathElement(currentElement + 1) == 0)
550 return STATUS_OBJECT_NAME_NOT_FOUND;
554 return STATUS_OBJECT_PATH_NOT_FOUND;
557 else if (!NT_SUCCESS (status))
559 vfatReleaseFCB (pVCB, parentFCB);
566 currentElement = vfatGetNextPathElement (currentElement);
569 *pParentFCB = parentFCB;
572 return STATUS_SUCCESS;