Synchronize with trunk revision 59636 (just before Alex's CreateProcess revamp).
[reactos.git] / drivers / filesystems / fastfat_new / fat.c
1 /*
2 * PROJECT: ReactOS FAT file system driver
3 * LICENSE: GNU GPLv3 as published by the Free Software Foundation
4 * FILE: drivers/filesystems/fastfat/fat.c
5 * PURPOSE: FAT support routines
6 * PROGRAMMERS: Aleksey Bragin <aleksey@reactos.org>
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #define NDEBUG
12 #include "fastfat.h"
13
14 /* PROTOTYPES ***************************************************************/
15
16 BOOLEAN
17 NTAPI
18 FatValidBpb(IN PBIOS_PARAMETER_BLOCK Bpb);
19
20 /* VARIABLES ****************************************************************/
21
22 BOOLEAN
23 NTAPI
24 FatValidBpb(IN PBIOS_PARAMETER_BLOCK Bpb)
25 {
26 return (FatValidBytesPerSector(Bpb->BytesPerSector)
27 && FatValidSectorsPerCluster(Bpb->SectorsPerCluster)
28 && Bpb->ReservedSectors > 0
29 && Bpb->Fats > 0
30 && (Bpb->Sectors > 0 || Bpb->LargeSectors > 0)
31 && (Bpb->SectorsPerFat > 0
32 || (Bpb->LargeSectorsPerFat > 0 && Bpb->FsVersion == 0))
33 && (Bpb->Media == 0xf0
34 || Bpb->Media == 0xf8
35 || Bpb->Media == 0xf9
36 || Bpb->Media == 0xfb
37 || Bpb->Media == 0xfc
38 || Bpb->Media == 0xfd
39 || Bpb->Media == 0xfe
40 || Bpb->Media == 0xff)
41 && (Bpb->SectorsPerFat == 0 || Bpb->RootEntries > 0)
42 && (Bpb->SectorsPerFat > 0 || !Bpb->MirrorDisabled));
43 }
44
45 /**
46 * Determines the index of the set bit.
47 *
48 * @param Number
49 * Number having a single bit set.
50 *
51 * @return
52 * Index of the set bit.
53 */
54 FORCEINLINE
55 ULONG
56 FatPowerOfTwo(
57 ULONG Number)
58 {
59 ULONG Temp;
60 Temp = Number
61 - ((Number >> 1) & 033333333333)
62 - ((Number >> 2) & 011111111111);
63 return (((Temp + (Temp >> 3)) & 030707070707) % 63);
64 }
65
66 VOID
67 NTAPI
68 FatiInitializeVcb(PVCB Vcb)
69 {
70 ULONG ClustersCapacity;
71
72 /* Various characteristics needed for navigation in FAT */
73 if ((Vcb->Sectors = Vcb->Bpb.Sectors) == 0)
74 Vcb->Sectors = Vcb->Bpb.LargeSectors;
75 if ((Vcb->SectorsPerFat = Vcb->Bpb.SectorsPerFat) == 0)
76 Vcb->SectorsPerFat = Vcb->Bpb.LargeSectorsPerFat;
77 Vcb->RootDirent = Vcb->Bpb.ReservedSectors + Vcb->Bpb.Fats * Vcb->SectorsPerFat;
78 Vcb->RootDirentSectors = BytesToSectors(Vcb,
79 Vcb->Bpb.RootEntries * sizeof(DIR_ENTRY));
80 Vcb->DataArea = Vcb->RootDirent + Vcb->RootDirentSectors;
81 Vcb->Clusters = (Vcb->Sectors - Vcb->Bpb.ReservedSectors
82 - Vcb->Bpb.Fats * Vcb->SectorsPerFat
83 - Vcb->RootDirentSectors) / Vcb->Bpb.SectorsPerCluster;
84 if (Vcb->BytesPerClusterLog < 4087)
85 {
86 Vcb->IndexDepth = 0x0c;
87 //Vcb->Methods = Fat12Methods;
88 }
89 else
90 {
91 Vcb->IndexDepth = 0x10;
92 //Vcb->Methods = Fat16Methods;
93 }
94 /* Large Sectors are used for FAT32 */
95 if (Vcb->Bpb.Sectors == 0) {
96 Vcb->IndexDepth = 0x20;
97 //Vcb->Methods = Fat32Methods;
98 }
99 ClustersCapacity = (SectorsToBytes(Vcb, Vcb->Sectors) * 0x8 / Vcb->IndexDepth) - 1;
100 if (Vcb->Clusters > ClustersCapacity)
101 Vcb->Clusters = ClustersCapacity;
102 Vcb->BytesPerCluster = SectorsToBytes(Vcb, Vcb->Bpb.SectorsPerCluster);
103 Vcb->BytesPerClusterLog = FatPowerOfTwo(Vcb->BytesPerCluster);
104 Vcb->BeyondLastClusterInFat = ((LONGLONG) Vcb->Clusters) * Vcb->IndexDepth / 0x8;
105
106 /* Update real volume size with the real value. */
107 Vcb->Header.FileSize.QuadPart =
108 Vcb->Header.AllocationSize.QuadPart = SectorsToBytes(Vcb, Vcb->Sectors);
109 }
110
111 NTSTATUS
112 NTAPI
113 FatInitializeVcb(IN PFAT_IRP_CONTEXT IrpContext,
114 IN PVCB Vcb,
115 IN PDEVICE_OBJECT TargetDeviceObject,
116 IN PVPB Vpb)
117 {
118 NTSTATUS Status;
119 PBCB Bcb;
120 PVOID Buffer;
121 LARGE_INTEGER Offset;
122
123 RtlZeroMemory(Vcb, sizeof(*Vcb));
124
125 /* Initialize list head, so that it will
126 * not fail in cleanup.
127 */
128 InitializeListHead(&Vcb->VcbLinks);
129
130 /* Setup FCB Header */
131 Vcb->Header.NodeTypeCode = FAT_NTC_VCB;
132 Vcb->Header.NodeByteSize = sizeof(*Vcb);
133
134 /* Setup Vcb fields */
135 Vcb->TargetDeviceObject = TargetDeviceObject;
136 ObReferenceObject(TargetDeviceObject);
137 Vcb->Vpb = Vpb;
138
139 /* Setup FCB Header */
140 ExInitializeFastMutex(&Vcb->HeaderMutex);
141 FsRtlSetupAdvancedHeader(&Vcb->Header, &Vcb->HeaderMutex);
142
143 /* Create Volume File Object */
144 Vcb->StreamFileObject = IoCreateStreamFileObject(NULL,
145 Vcb->TargetDeviceObject);
146
147 /* We have to setup all FCB fields needed for CC */
148 Vcb->StreamFileObject->FsContext = Vcb;
149 Vcb->StreamFileObject->SectionObjectPointer = &Vcb->SectionObjectPointers;
150
151 /* At least full boot sector should be available */
152 //Vcb->Header.FileSize.QuadPart = sizeof(PACKED_BOOT_SECTOR);
153 //Vcb->Header.AllocationSize.QuadPart = sizeof(PACKED_BOOT_SECTOR);
154 Vcb->Header.ValidDataLength.HighPart = MAXLONG;
155 Vcb->Header.ValidDataLength.LowPart = MAXULONG;
156
157 Vcb->Header.AllocationSize.QuadPart = Int32x32To64(5*1024, 1024*1024); //HACK: 5 Gb
158 Vcb->Header.FileSize.QuadPart = Vcb->Header.AllocationSize.QuadPart;
159
160 /* Set VCB to a good condition */
161 Vcb->Condition = VcbGood;
162
163 /* Initialize VCB's resource */
164 ExInitializeResourceLite(&Vcb->Resource);
165
166 /* Initialize close queue lists */
167 InitializeListHead(&Vcb->AsyncCloseList);
168 InitializeListHead(&Vcb->DelayedCloseList);
169
170 /* Initialize CC */
171 CcInitializeCacheMap(Vcb->StreamFileObject,
172 (PCC_FILE_SIZES)&Vcb->Header.AllocationSize,
173 FALSE,
174 &FatGlobalData.CacheMgrNoopCallbacks,
175 Vcb);
176
177 /* Read boot sector */
178 Offset.QuadPart = 0;
179 Bcb = NULL;
180
181 /* Note: Volume Read path does not require
182 * any of the parameters set further
183 * in this routine.
184 */
185 if (CcMapData(Vcb->StreamFileObject,
186 &Offset,
187 sizeof(PACKED_BOOT_SECTOR),
188 TRUE,
189 &Bcb,
190 &Buffer))
191 {
192 PPACKED_BOOT_SECTOR BootSector = (PPACKED_BOOT_SECTOR) Buffer;
193 FatUnpackBios(&Vcb->Bpb, &BootSector->PackedBpb);
194 if (!(FatBootSectorJumpValid(BootSector->Jump) &&
195 FatValidBpb(&Vcb->Bpb)))
196 {
197 Status = STATUS_UNRECOGNIZED_VOLUME;
198 }
199 CopyUchar4(&Vcb->Vpb->SerialNumber, BootSector->Id);
200 CcUnpinData(Bcb);
201 }
202 else
203 {
204 Status = STATUS_UNRECOGNIZED_VOLUME;
205 goto FatInitializeVcbCleanup;
206 }
207
208 /* Increase internal / residual open counter */
209 InterlockedIncrement((PLONG)&(Vcb->InternalOpenCount));
210 InterlockedIncrement((PLONG)&(Vcb->ResidualOpenCount));
211
212 /* Set up notifications */
213 FsRtlNotifyInitializeSync(&Vcb->NotifySync);
214 InitializeListHead(&Vcb->NotifyList);
215
216 /* Call helper function */
217 FatiInitializeVcb(Vcb);
218
219 /* Add this Vcb to global Vcb list */
220 (VOID)FatAcquireExclusiveGlobal(IrpContext);
221 InsertTailList(&FatGlobalData.VcbListHead, &Vcb->VcbLinks);
222 FatReleaseGlobal(IrpContext);
223
224 return STATUS_SUCCESS;
225
226 FatInitializeVcbCleanup:
227
228 /* Unwind the routine actions */
229 FatUninitializeVcb(Vcb);
230 return Status;
231 }
232
233 VOID
234 NTAPI
235 FatUninitializeVcb(IN PVCB Vcb)
236 {
237 LARGE_INTEGER ZeroSize;
238
239 ZeroSize.QuadPart = 0LL;
240
241 /* Close volume file */
242 if (Vcb->StreamFileObject != NULL)
243 {
244 /* Uninitialize CC. */
245 CcUninitializeCacheMap(Vcb->StreamFileObject, &ZeroSize, NULL);
246 ObDereferenceObject(Vcb->StreamFileObject);
247 Vcb->StreamFileObject = NULL;
248 }
249
250 /* Free ContextClose if it's not freed up already */
251 if (Vcb->CloseContext) ExFreePool(Vcb->CloseContext);
252
253 /* Free notifications stuff */
254 FsRtlNotifyUninitializeSync(&Vcb->NotifySync);
255
256 /* Unlink from global Vcb list. */
257 RemoveEntryList(&Vcb->VcbLinks);
258
259 /* Release Target Device */
260 ObDereferenceObject(Vcb->TargetDeviceObject);
261 Vcb->TargetDeviceObject = NULL;
262 }
263
264 /* EOF */
265
266