[FASTFAT] Only initialize directory cache on use.
[reactos.git] / drivers / filesystems / fastfat / vfat.h
index 4faab7e..1f29395 100644 (file)
@@ -5,8 +5,23 @@
 #include <ntdddisk.h>
 #include <dos.h>
 #include <pseh/pseh2.h>
+#ifdef KDBG
+#include <ndk/kdfuncs.h>
+#include <reactos/kdros.h>
+#endif
+
+#ifdef __GNUC__
+#define INIT_SECTION __attribute__((section ("INIT")))
+#else
+#define INIT_SECTION /* Done via alloc_text for MSC */
+#endif
 
 #define USE_ROS_CC_AND_FS
+#if 0
+#ifndef _MSC_VER
+#define ENABLE_SWAPOUT
+#endif
+#endif
 
 #define ROUND_DOWN(n, align) \
     (((ULONG)n) & ~((align) - 1l))
 #define ROUND_UP(n, align) \
     ROUND_DOWN(((ULONG)n) + (align) - 1, (align))
 
+#define ROUND_DOWN_64(n, align) \
+    (((ULONGLONG)n) & ~((align) - 1LL))
+
+#define ROUND_UP_64(n, align) \
+    ROUND_DOWN_64(((ULONGLONG)n) + (align) - 1LL, (align))
+
 #include <pshpack1.h>
 struct _BootSector
 {
@@ -180,9 +201,9 @@ typedef struct _slot slot;
 
 #define LONGNAME_MAX_LENGTH    256             // max length for a long filename
 
-#define ENTRY_DELETED(DeviceExt, DirEntry) ((DeviceExt)->Flags & VCB_IS_FATX ? FATX_ENTRY_DELETED(&((DirEntry)->FatX)) : FAT_ENTRY_DELETED(&((DirEntry)->Fat)))
-#define ENTRY_VOLUME(DeviceExt, DirEntry)  ((DeviceExt)->Flags & VCB_IS_FATX ? FATX_ENTRY_VOLUME(&((DirEntry)->FatX)) : FAT_ENTRY_VOLUME(&((DirEntry)->Fat)))
-#define ENTRY_END(DeviceExt, DirEntry)     ((DeviceExt)->Flags & VCB_IS_FATX ? FATX_ENTRY_END(&((DirEntry)->FatX)) : FAT_ENTRY_END(&((DirEntry)->Fat)))
+#define ENTRY_DELETED(IsFatX, DirEntry) (IsFatX ? FATX_ENTRY_DELETED(&((DirEntry)->FatX)) : FAT_ENTRY_DELETED(&((DirEntry)->Fat)))
+#define ENTRY_VOLUME(IsFatX, DirEntry) (IsFatX ? FATX_ENTRY_VOLUME(&((DirEntry)->FatX)) : FAT_ENTRY_VOLUME(&((DirEntry)->Fat)))
+#define ENTRY_END(IsFatX, DirEntry) (IsFatX ? FATX_ENTRY_END(&((DirEntry)->FatX)) : FAT_ENTRY_END(&((DirEntry)->Fat)))
 
 #define FAT_ENTRY_DELETED(DirEntry)  ((DirEntry)->Filename[0] == 0xe5)
 #define FAT_ENTRY_END(DirEntry)      ((DirEntry)->Filename[0] == 0)
@@ -218,12 +239,14 @@ typedef union _DIR_ENTRY DIR_ENTRY, *PDIR_ENTRY;
 #define VCB_VOLUME_LOCKED       0x0001
 #define VCB_DISMOUNT_PENDING    0x0002
 #define VCB_IS_FATX             0x0004
+#define VCB_IS_SYS_OR_HAS_PAGE  0x0008
 #define VCB_IS_DIRTY            0x4000 /* Volume is dirty */
 #define VCB_CLEAR_DIRTY         0x8000 /* Clean dirty flag at shutdown */
 
 typedef struct
 {
     ULONG VolumeID;
+    CHAR VolumeLabel[11];
     ULONG FATStart;
     ULONG FATCount;
     ULONG FATSectors;
@@ -242,6 +265,7 @@ typedef struct
 
 struct _VFATFCB;
 struct _VFAT_DIRENTRY_CONTEXT;
+struct _VFAT_MOVE_CONTEXT;
 
 typedef struct _HASHENTRY
 {
@@ -251,16 +275,32 @@ typedef struct _HASHENTRY
 }
 HASHENTRY;
 
-#define FCB_HASH_TABLE_SIZE 65536
-
 typedef struct DEVICE_EXTENSION *PDEVICE_EXTENSION;
 
 typedef NTSTATUS (*PGET_NEXT_CLUSTER)(PDEVICE_EXTENSION,ULONG,PULONG);
 typedef NTSTATUS (*PFIND_AND_MARK_AVAILABLE_CLUSTER)(PDEVICE_EXTENSION,PULONG);
 typedef NTSTATUS (*PWRITE_CLUSTER)(PDEVICE_EXTENSION,ULONG,ULONG,PULONG);
 
+typedef BOOLEAN (*PIS_DIRECTORY_EMPTY)(PDEVICE_EXTENSION,struct _VFATFCB*);
+typedef NTSTATUS (*PADD_ENTRY)(PDEVICE_EXTENSION,PUNICODE_STRING,struct _VFATFCB**,struct _VFATFCB*,ULONG,UCHAR,struct _VFAT_MOVE_CONTEXT*);
+typedef NTSTATUS (*PDEL_ENTRY)(PDEVICE_EXTENSION,struct _VFATFCB*,struct _VFAT_MOVE_CONTEXT*);
 typedef NTSTATUS (*PGET_NEXT_DIR_ENTRY)(PVOID*,PVOID*,struct _VFATFCB*,struct _VFAT_DIRENTRY_CONTEXT*,BOOLEAN);
 
+typedef struct _VFAT_DISPATCH
+{
+    PIS_DIRECTORY_EMPTY IsDirectoryEmpty;
+    PADD_ENTRY AddEntry;
+    PDEL_ENTRY DelEntry;
+    PGET_NEXT_DIR_ENTRY GetNextDirEntry;
+} VFAT_DISPATCH, *PVFAT_DISPATCH;
+
+#define STATISTICS_SIZE_NO_PAD (sizeof(FILESYSTEM_STATISTICS) + sizeof(FAT_STATISTICS))
+typedef struct _STATISTICS {
+    FILESYSTEM_STATISTICS Base;
+    FAT_STATISTICS Fat;
+    UCHAR Pad[((STATISTICS_SIZE_NO_PAD + 0x3f) & ~0x3f) - STATISTICS_SIZE_NO_PAD];
+} STATISTICS, *PSTATISTICS;
+
 typedef struct DEVICE_EXTENSION
 {
     ERESOURCE DirResource;
@@ -271,6 +311,7 @@ typedef struct DEVICE_EXTENSION
     ULONG HashTableSize;
     struct _HASHENTRY **FcbHashTable;
 
+    PDEVICE_OBJECT VolumeDevice;
     PDEVICE_OBJECT StorageDevice;
     PFILE_OBJECT FATFileObject;
     FATINFO FatInfo;
@@ -279,6 +320,7 @@ typedef struct DEVICE_EXTENSION
     BOOLEAN AvailableClustersValid;
     ULONG Flags;
     struct _VFATFCB *VolumeFcb;
+    PSTATISTICS Statistics;
 
     /* Pointers to functions for manipulating FAT. */
     PGET_NEXT_CLUSTER GetNextCluster;
@@ -286,9 +328,6 @@ typedef struct DEVICE_EXTENSION
     PWRITE_CLUSTER WriteCluster;
     ULONG CleanShutBitMask;
 
-    /* Pointers to functions for manipulating directory entries. */
-    PGET_NEXT_DIR_ENTRY GetNextDirEntry;
-
     ULONG BaseDateYear;
 
     LIST_ENTRY VolumeListEntry;
@@ -296,13 +335,68 @@ typedef struct DEVICE_EXTENSION
     /* Notifications */
     LIST_ENTRY NotifyList;
     PNOTIFY_SYNC NotifySync;
+
+    /* Incremented on IRP_MJ_CREATE, decremented on IRP_MJ_CLOSE */
+    ULONG OpenHandleCount;
+
+    /* VPBs for dismount */
+    PVPB IoVPB;
+    PVPB SpareVPB;
+
+    /* Pointers to functions for manipulating directory entries. */
+    VFAT_DISPATCH Dispatch;
 } DEVICE_EXTENSION, VCB, *PVCB;
 
+FORCEINLINE
+BOOLEAN
+VfatIsDirectoryEmpty(PDEVICE_EXTENSION DeviceExt,
+                     struct _VFATFCB* Fcb)
+{
+    return DeviceExt->Dispatch.IsDirectoryEmpty(DeviceExt, Fcb);
+}
+
+FORCEINLINE
+NTSTATUS
+VfatAddEntry(PDEVICE_EXTENSION DeviceExt,
+             PUNICODE_STRING NameU,
+             struct _VFATFCB** Fcb,
+             struct _VFATFCB* ParentFcb,
+             ULONG RequestedOptions,
+             UCHAR ReqAttr,
+             struct _VFAT_MOVE_CONTEXT* MoveContext)
+{
+    return DeviceExt->Dispatch.AddEntry(DeviceExt, NameU, Fcb, ParentFcb, RequestedOptions, ReqAttr, MoveContext);
+}
+
+FORCEINLINE
+NTSTATUS
+VfatDelEntry(PDEVICE_EXTENSION DeviceExt,
+             struct _VFATFCB* Fcb,
+             struct _VFAT_MOVE_CONTEXT* MoveContext)
+{
+    return DeviceExt->Dispatch.DelEntry(DeviceExt, Fcb, MoveContext);
+}
+
+FORCEINLINE
+NTSTATUS
+VfatGetNextDirEntry(PDEVICE_EXTENSION DeviceExt,
+                    PVOID *pContext,
+                    PVOID *pPage,
+                    struct _VFATFCB* pDirFcb,
+                    struct _VFAT_DIRENTRY_CONTEXT* DirContext,
+                    BOOLEAN First)
+{
+    return DeviceExt->Dispatch.GetNextDirEntry(pContext, pPage, pDirFcb, DirContext, First);
+}
+
+#define VFAT_BREAK_ON_CORRUPTION 1
+
 typedef struct
 {
     PDRIVER_OBJECT DriverObject;
     PDEVICE_OBJECT DeviceObject;
     ULONG Flags;
+    ULONG NumberProcessors;
     ERESOURCE VolumeListLock;
     LIST_ENTRY VolumeListHead;
     NPAGED_LOOKASIDE_LIST FcbLookasideList;
@@ -320,7 +414,12 @@ extern PVFAT_GLOBAL_DATA VfatGlobalData;
 #define FCB_IS_PAGE_FILE        0x0008
 #define FCB_IS_VOLUME           0x0010
 #define FCB_IS_DIRTY            0x0020
-#define FCB_IS_FATX_ENTRY       0x0040
+#ifdef KDBG
+#define FCB_CLEANED_UP          0x0040
+#define FCB_CLOSED              0x0080
+#endif
+
+#define NODE_TYPE_FCB ((CSHORT)0x0502)
 
 typedef struct _VFATFCB
 {
@@ -361,9 +460,15 @@ typedef struct _VFATFCB
     /* List of FCB's for this volume */
     LIST_ENTRY FcbListEntry;
 
+    /* List of FCB's for the parent */ 
+    LIST_ENTRY ParentListEntry;
+
     /* pointer to the parent fcb */
     struct _VFATFCB *parentFcb;
 
+    /* List for the children */
+    LIST_ENTRY ParentListHead;
+
     /* Flags for the fcb */
     ULONG Flags;
 
@@ -392,7 +497,7 @@ typedef struct _VFATFCB
     FILE_LOCK FileLock;
 
     /*
-     * Optimalization: caching of last read/write cluster+offset pair. Can't
+     * Optimization: caching of last read/write cluster+offset pair. Can't
      * be in VFATCCB because it must be reset everytime the allocated clusters
      * change.
      */
@@ -401,9 +506,12 @@ typedef struct _VFATFCB
     ULONG LastOffset;
 } VFATFCB, *PVFATFCB;
 
+#define CCB_DELETE_ON_CLOSE     0x0001
+
 typedef struct _VFATCCB
 {
     LARGE_INTEGER  CurrentByteOffset;
+    ULONG Flags;
     /* for DirectoryControl */
     ULONG Entry;
     /* for DirectoryControl */
@@ -433,8 +541,11 @@ typedef struct __DOSDATE
 }
 DOSDATE, *PDOSDATE;
 
-#define IRPCONTEXT_CANWAIT         0x0001
-#define IRPCONTEXT_PENDINGRETURNED  0x0002
+#define IRPCONTEXT_CANWAIT          0x0001
+#define IRPCONTEXT_COMPLETE         0x0002
+#define IRPCONTEXT_QUEUE            0x0004
+#define IRPCONTEXT_PENDINGRETURNED  0x0008
+#define IRPCONTEXT_DEFERRED_WRITE   0x0010
 
 typedef struct
 {
@@ -449,6 +560,7 @@ typedef struct
     PFILE_OBJECT FileObject;
     ULONG RefCount;
     KEVENT Event;
+    CCHAR PriorityBoost;
 } VFAT_IRP_CONTEXT, *PVFAT_IRP_CONTEXT;
 
 typedef struct _VFAT_DIRENTRY_CONTEXT
@@ -458,8 +570,71 @@ typedef struct _VFAT_DIRENTRY_CONTEXT
     DIR_ENTRY DirEntry;
     UNICODE_STRING LongNameU;
     UNICODE_STRING ShortNameU;
+    PDEVICE_EXTENSION DeviceExt;
 } VFAT_DIRENTRY_CONTEXT, *PVFAT_DIRENTRY_CONTEXT;
 
+typedef struct _VFAT_MOVE_CONTEXT
+{
+    ULONG FirstCluster;
+    ULONG FileSize;
+    USHORT CreationDate;
+    USHORT CreationTime;
+    BOOLEAN InPlace;
+} VFAT_MOVE_CONTEXT, *PVFAT_MOVE_CONTEXT;
+
+FORCEINLINE
+NTSTATUS
+VfatMarkIrpContextForQueue(PVFAT_IRP_CONTEXT IrpContext)
+{
+    PULONG Flags = &IrpContext->Flags;
+
+    *Flags &= ~IRPCONTEXT_COMPLETE;
+    *Flags |= IRPCONTEXT_QUEUE;
+
+    return STATUS_PENDING;
+}
+
+FORCEINLINE
+BOOLEAN
+vfatFCBIsDirectory(PVFATFCB FCB)
+{
+    return BooleanFlagOn(*FCB->Attributes, FILE_ATTRIBUTE_DIRECTORY);
+}
+
+FORCEINLINE
+BOOLEAN
+vfatFCBIsReadOnly(PVFATFCB FCB)
+{
+    return BooleanFlagOn(*FCB->Attributes, FILE_ATTRIBUTE_READONLY);
+}
+
+FORCEINLINE
+BOOLEAN
+vfatVolumeIsFatX(PDEVICE_EXTENSION DeviceExt)
+{
+    return BooleanFlagOn(DeviceExt->Flags, VCB_IS_FATX);
+}
+
+FORCEINLINE
+VOID
+vfatReportChange(
+    IN PDEVICE_EXTENSION DeviceExt,
+    IN PVFATFCB Fcb,
+    IN ULONG FilterMatch,
+    IN ULONG Action)
+{
+    FsRtlNotifyFullReportChange(DeviceExt->NotifySync,
+                                &(DeviceExt->NotifyList),
+                                (PSTRING)&Fcb->PathNameU,
+                                Fcb->PathNameU.Length - Fcb->LongNameU.Length,
+                                NULL, NULL, FilterMatch, Action, NULL);
+}
+
+#define vfatAddToStat(Vcb, Stat, Inc)                                                                         \
+{                                                                                                             \
+    PSTATISTICS Stats = &(Vcb)->Statistics[KeGetCurrentProcessorNumber() % VfatGlobalData->NumberProcessors]; \
+    Stats->Stat += Inc;                                                                                       \
+}
 
 /* blockdev.c */
 
@@ -533,11 +708,6 @@ vfat8Dot3ToString(
     PFAT_DIR_ENTRY pEntry,
     PUNICODE_STRING NameU);
 
-NTSTATUS
-ReadVolumeLabel(
-    PDEVICE_EXTENSION DeviceExt,
-    PVPB Vpb);
-
 /* dir.c */
 
 NTSTATUS
@@ -565,46 +735,18 @@ vfatDirEntryGetFirstCluster(
     PDEVICE_EXTENSION pDeviceExt,
     PDIR_ENTRY pDirEntry);
 
-BOOLEAN
-VfatIsDirectoryEmpty(
-    PVFATFCB Fcb);
-
-NTSTATUS
-FATGetNextDirEntry(
-    PVOID *pContext,
-    PVOID *pPage,
-    IN PVFATFCB pDirFcb,
-    IN PVFAT_DIRENTRY_CONTEXT DirContext,
-    BOOLEAN First);
-
-NTSTATUS
-FATXGetNextDirEntry(
-    PVOID *pContext,
-    PVOID *pPage,
-    IN PVFATFCB pDirFcb,
-    IN PVFAT_DIRENTRY_CONTEXT DirContext,
-    BOOLEAN First);
-
 /* dirwr.c */
 
 NTSTATUS
-VfatAddEntry(
-    PDEVICE_EXTENSION DeviceExt,
-    PUNICODE_STRING PathNameU,
-    PVFATFCB* Fcb,
-    PVFATFCB ParentFcb,
-    ULONG RequestedOptions,
-    UCHAR ReqAttr);
+vfatFCBInitializeCacheFromVolume(
+    PVCB vcb,
+    PVFATFCB fcb);
 
 NTSTATUS
 VfatUpdateEntry(
+    IN PDEVICE_EXTENSION DeviceExt,
     PVFATFCB pFcb);
 
-NTSTATUS
-VfatDelEntry(
-    PDEVICE_EXTENSION,
-    PVFATFCB);
-
 BOOLEAN
 vfatFindDirSpace(
     PDEVICE_EXTENSION DeviceExt,
@@ -612,6 +754,20 @@ vfatFindDirSpace(
     ULONG nbSlots,
     PULONG start);
 
+NTSTATUS
+vfatRenameEntry(
+    IN PDEVICE_EXTENSION DeviceExt,
+    IN PVFATFCB pFcb,
+    IN PUNICODE_STRING FileName,
+    IN BOOLEAN CaseChangeOnly);
+
+NTSTATUS
+VfatMoveEntry(
+    IN PDEVICE_EXTENSION DeviceExt,
+    IN PVFATFCB pFcb,
+    IN PUNICODE_STRING FileName,
+    IN PVFATFCB ParentFcb);
+
 /* ea.h */
 
 NTSTATUS
@@ -637,17 +793,6 @@ NTAPI
 VfatReleaseFromLazyWrite(
     IN PVOID Context);
 
-BOOLEAN
-NTAPI
-VfatAcquireForReadAhead(
-    IN PVOID Context,
-    IN BOOLEAN Wait);
-
-VOID
-NTAPI
-VfatReleaseFromReadAhead(
-    IN PVOID Context);
-
 /* fat.c */
 
 NTSTATUS
@@ -747,6 +892,19 @@ vfatNewFCB(
     PDEVICE_EXTENSION pVCB,
     PUNICODE_STRING pFileNameU);
 
+NTSTATUS
+vfatSetFCBNewDirName(
+    PDEVICE_EXTENSION pVCB,
+    PVFATFCB Fcb,
+    PVFATFCB ParentFcb);
+
+NTSTATUS
+vfatUpdateFCB(
+    PDEVICE_EXTENSION pVCB,
+    PVFATFCB Fcb,
+    PVFAT_DIRENTRY_CONTEXT DirContext,
+    PVFATFCB ParentFcb);
+
 VOID
 vfatDestroyFCB(
     PVFATFCB pFCB);
@@ -756,19 +914,41 @@ vfatDestroyCCB(
     PVFATCCB pCcb);
 
 VOID
+#ifndef KDBG
 vfatGrabFCB(
+#else
+_vfatGrabFCB(
+#endif
     PDEVICE_EXTENSION pVCB,
-    PVFATFCB pFCB);
+    PVFATFCB pFCB
+#ifdef KDBG
+    ,
+    PCSTR File,
+    ULONG Line,
+    PCSTR Func
+#endif
+    );
 
 VOID
+#ifndef KDBG
 vfatReleaseFCB(
+#else
+_vfatReleaseFCB(
+#endif
     PDEVICE_EXTENSION pVCB,
-    PVFATFCB pFCB);
-
-VOID
-vfatAddFCBToTable(
-    PDEVICE_EXTENSION pVCB,
-    PVFATFCB pFCB);
+    PVFATFCB pFCB
+#ifdef KDBG
+    ,
+    PCSTR File,
+    ULONG Line,
+    PCSTR Func
+#endif
+    );
+
+#ifdef KDBG
+#define vfatGrabFCB(v, f) _vfatGrabFCB(v, f, __FILE__, __LINE__, __FUNCTION__)
+#define vfatReleaseFCB(v, f) _vfatReleaseFCB(v, f, __FILE__, __LINE__, __FUNCTION__)
+#endif
 
 PVFATFCB
 vfatGrabFCBFromTable(
@@ -820,6 +1000,20 @@ vfatMakeFCBFromDirEntry(
 
 /* finfo.c */
 
+NTSTATUS
+VfatGetStandardInformation(
+    PVFATFCB FCB,
+    PFILE_STANDARD_INFORMATION StandardInfo,
+    PULONG BufferLength);
+
+NTSTATUS
+VfatGetBasicInformation(
+    PFILE_OBJECT FileObject,
+    PVFATFCB FCB,
+    PDEVICE_EXTENSION DeviceExt,
+    PFILE_BASIC_INFORMATION BasicInfo,
+    PULONG BufferLength);
+
 NTSTATUS
 VfatQueryInformation(
     PVFAT_IRP_CONTEXT IrpContext);
@@ -860,22 +1054,13 @@ DriverEntry(
     PDRIVER_OBJECT DriverObject,
     PUNICODE_STRING RegistryPath);
 
+#ifdef KDBG
+/* kdbg.c */
+KDBG_CLI_ROUTINE vfatKdbgHandler;
+#endif
 
 /* misc.c */
 
-NTSTATUS
-VfatQueueRequest(
-    PVFAT_IRP_CONTEXT IrpContext);
-
-PVFAT_IRP_CONTEXT
-VfatAllocateIrpContext(
-    PDEVICE_OBJECT DeviceObject,
-    PIRP Irp);
-
-VOID
-VfatFreeIrpContext(
-    PVFAT_IRP_CONTEXT IrpContext);
-
 DRIVER_DISPATCH
 VfatBuildRequest;
 
@@ -887,7 +1072,8 @@ VfatBuildRequest(
 
 PVOID
 VfatGetUserBuffer(
-    IN PIRP);
+    IN PIRP,
+    IN BOOLEAN Paging);
 
 NTSTATUS
 VfatLockUserBuffer(
@@ -895,6 +1081,24 @@ VfatLockUserBuffer(
     IN ULONG,
     IN LOCK_OPERATION);
 
+BOOLEAN
+VfatCheckForDismount(
+    IN PDEVICE_EXTENSION DeviceExt,
+    IN BOOLEAN Create);
+
+VOID
+vfatReportChange(
+    IN PDEVICE_EXTENSION DeviceExt,
+    IN PVFATFCB Fcb,
+    IN ULONG FilterMatch,
+    IN ULONG Action);
+
+VOID
+NTAPI
+VfatHandleDeferredWrite(
+    IN PVOID IrpContext,
+    IN PVOID Unused);
+
 /* pnp.c */
 
 NTSTATUS