Merge trunk head (r43756)
[reactos.git] / reactos / 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 CC */
167 CcInitializeCacheMap(Vcb->StreamFileObject,
168 (PCC_FILE_SIZES)&Vcb->Header.AllocationSize,
169 FALSE,
170 &FatGlobalData.CacheMgrNoopCallbacks,
171 Vcb);
172
173 /* Read boot sector */
174 Offset.QuadPart = 0;
175 Bcb = NULL;
176
177 /* Note: Volume Read path does not require
178 * any of the parameters set further
179 * in this routine.
180 */
181 if (CcMapData(Vcb->StreamFileObject,
182 &Offset,
183 sizeof(PACKED_BOOT_SECTOR),
184 TRUE,
185 &Bcb,
186 &Buffer))
187 {
188 PPACKED_BOOT_SECTOR BootSector = (PPACKED_BOOT_SECTOR) Buffer;
189 FatUnpackBios(&Vcb->Bpb, &BootSector->PackedBpb);
190 if (!(FatBootSectorJumpValid(BootSector->Jump) &&
191 FatValidBpb(&Vcb->Bpb)))
192 {
193 Status = STATUS_UNRECOGNIZED_VOLUME;
194 }
195 CopyUchar4(&Vcb->Vpb->SerialNumber, BootSector->Id);
196 CcUnpinData(Bcb);
197 }
198 else
199 {
200 Status = STATUS_UNRECOGNIZED_VOLUME;
201 goto FatInitializeVcbCleanup;
202 }
203
204 /* Set up notifications */
205 FsRtlNotifyInitializeSync(&Vcb->NotifySync);
206 InitializeListHead(&Vcb->NotifyList);
207
208 /* Call helper function */
209 FatiInitializeVcb(Vcb);
210
211 /* Add this Vcb to global Vcb list */
212 (VOID)FatAcquireExclusiveGlobal(IrpContext);
213 InsertTailList(&FatGlobalData.VcbListHead, &Vcb->VcbLinks);
214 FatReleaseGlobal(IrpContext);
215
216 return STATUS_SUCCESS;
217
218 FatInitializeVcbCleanup:
219
220 /* Unwind the routine actions */
221 FatUninitializeVcb(Vcb);
222 return Status;
223 }
224
225 VOID
226 NTAPI
227 FatUninitializeVcb(IN PVCB Vcb)
228 {
229 LARGE_INTEGER ZeroSize;
230
231 ZeroSize.QuadPart = 0LL;
232
233 /* Close volume file */
234 if (Vcb->StreamFileObject != NULL)
235 {
236 /* Uninitialize CC. */
237 CcUninitializeCacheMap(Vcb->StreamFileObject, &ZeroSize, NULL);
238 ObDereferenceObject(Vcb->StreamFileObject);
239 Vcb->StreamFileObject = NULL;
240 }
241
242 /* Free notifications stuff */
243 FsRtlNotifyUninitializeSync(&Vcb->NotifySync);
244
245 /* Unlink from global Vcb list. */
246 RemoveEntryList(&Vcb->VcbLinks);
247
248 /* Release Target Device */
249 ObDereferenceObject(Vcb->TargetDeviceObject);
250 Vcb->TargetDeviceObject = NULL;
251 }
252
253 /* EOF */
254
255