* Sync up to trunk HEAD (r62285). Branch guys deserve the significant speedups too ;)
[reactos.git] / drivers / filesystems / ntfs / mft.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2002 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
18 *
19 * COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS kernel
21 * FILE: drivers/filesystem/ntfs/mft.c
22 * PURPOSE: NTFS filesystem driver
23 * PROGRAMMER: Eric Kohl
24 * Updated by Valentin Verkhovsky 2003/09/12
25 */
26
27 /* INCLUDES *****************************************************************/
28
29 #include "ntfs.h"
30
31 #define NDEBUG
32 #include <debug.h>
33
34 /* FUNCTIONS ****************************************************************/
35
36 NTSTATUS
37 NtfsOpenMft(PDEVICE_EXTENSION Vcb)
38 {
39 // PVOID Bitmap;
40 PFILE_RECORD_HEADER MftRecord;
41 PFILE_RECORD_HEADER FileRecord;
42 // PATTRIBUTE Attribute;
43 // PATTRIBUTE AttrData;
44 // PRESIDENT_ATTRIBUTE ResAttr;
45
46 NTSTATUS Status;
47 ULONG BytesPerFileRecord;
48 ULONG n;
49 ULONG i;
50
51 DPRINT1("NtfsOpenMft() called\n");
52
53 BytesPerFileRecord = Vcb->NtfsInfo.BytesPerFileRecord;
54
55 MftRecord = ExAllocatePoolWithTag(NonPagedPool,
56 BytesPerFileRecord,
57 TAG_NTFS);
58 if (MftRecord == NULL)
59 {
60 return STATUS_INSUFFICIENT_RESOURCES;
61 }
62
63 Status = NtfsReadSectors(Vcb->StorageDevice,
64 Vcb->NtfsInfo.MftStart.u.LowPart * Vcb->NtfsInfo.SectorsPerCluster,
65 BytesPerFileRecord / Vcb->NtfsInfo.BytesPerSector,
66 Vcb->NtfsInfo.BytesPerSector,
67 (PVOID)MftRecord,
68 FALSE);
69 if (!NT_SUCCESS(Status))
70 {
71 ExFreePool(MftRecord);
72 return Status;
73 }
74
75 FixupUpdateSequenceArray(MftRecord);
76
77 // Attribute = FindAttribute(MftRecord, AttributeBitmap, 0);
78
79 /* Get number of file records*/
80 n = AttributeDataLength(FindAttribute(MftRecord, AttributeData, 0)) / BytesPerFileRecord;
81
82 FileRecord = ExAllocatePoolWithTag(NonPagedPool,
83 BytesPerFileRecord,
84 TAG_NTFS);
85 if (FileRecord == NULL)
86 {
87 ExFreePool(MftRecord);
88 return STATUS_INSUFFICIENT_RESOURCES;
89 }
90
91 /* Enumerate MFT Records */
92 DPRINT("Enumerate MFT records\n");
93 for (i = 0; i < n; i++)
94 {
95 ReadFileRecord(Vcb,
96 i,
97 FileRecord,
98 MftRecord);
99
100 if (FileRecord->Ntfs.Type == NRH_FILE_TYPE &&
101 (FileRecord->Flags & FRH_IN_USE))
102 {
103 DPRINT("\nFile %lu\n\n", i);
104
105 /* Enumerate attributtes */
106 NtfsDumpFileAttributes (FileRecord);
107 DbgPrint("\n\n");
108 }
109 }
110
111 ExFreePool(FileRecord);
112 ExFreePool(MftRecord);
113
114 return Status;
115 }
116
117
118 PATTRIBUTE
119 FindAttribute(PFILE_RECORD_HEADER FileRecord,
120 ATTRIBUTE_TYPE Type,
121 PWSTR name)
122 {
123 PATTRIBUTE Attribute;
124
125 UNREFERENCED_PARAMETER(name);
126
127 Attribute = (PATTRIBUTE)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
128 while (Attribute < (PATTRIBUTE)((ULONG_PTR)FileRecord + FileRecord->BytesInUse) &&
129 Attribute->AttributeType != (ATTRIBUTE_TYPE)-1)
130 {
131 if (Attribute->AttributeType == Type)
132 {
133 return Attribute;
134 }
135
136 Attribute = (PATTRIBUTE)((ULONG_PTR)Attribute + Attribute->Length);
137 }
138
139 return NULL;
140 }
141
142
143 ULONG
144 AttributeAllocatedLength(PATTRIBUTE Attribute)
145 {
146 if (Attribute->Nonresident)
147 {
148 return ((PNONRESIDENT_ATTRIBUTE)Attribute)->AllocatedSize;
149 }
150
151 return ((PRESIDENT_ATTRIBUTE)Attribute)->ValueLength;
152 }
153
154
155 ULONG
156 AttributeDataLength(PATTRIBUTE Attribute)
157 {
158 if (Attribute->Nonresident)
159 {
160 return ((PNONRESIDENT_ATTRIBUTE)Attribute)->DataSize;
161 }
162
163 return ((PRESIDENT_ATTRIBUTE)Attribute)->ValueLength;
164 }
165
166
167 VOID
168 ReadAttribute(PATTRIBUTE attr,
169 PVOID buffer,
170 PDEVICE_EXTENSION Vcb,
171 PDEVICE_OBJECT DeviceObject)
172 {
173 PNONRESIDENT_ATTRIBUTE NresAttr = (PNONRESIDENT_ATTRIBUTE)attr;
174
175 UNREFERENCED_PARAMETER(DeviceObject);
176
177 if (attr->Nonresident == FALSE)
178 {
179 memcpy(buffer,
180 (PVOID)((ULONG_PTR)attr + ((PRESIDENT_ATTRIBUTE)attr)->ValueOffset),
181 ((PRESIDENT_ATTRIBUTE)attr)->ValueLength);
182 }
183
184 ReadExternalAttribute(Vcb,
185 NresAttr,
186 0,
187 (ULONG)(NresAttr->LastVcn) + 1,
188 buffer);
189 }
190
191
192 NTSTATUS
193 ReadFileRecord(PDEVICE_EXTENSION Vcb,
194 ULONG index,
195 PFILE_RECORD_HEADER file,
196 PFILE_RECORD_HEADER Mft)
197 {
198 PVOID p;
199 ULONG BytesPerFileRecord = Vcb->NtfsInfo.BytesPerFileRecord;
200 ULONG clusters = max(BytesPerFileRecord / Vcb->NtfsInfo.BytesPerCluster, 1);
201 ULONGLONG vcn = index * BytesPerFileRecord / Vcb->NtfsInfo.BytesPerCluster;
202 LONG m = (Vcb->NtfsInfo.BytesPerCluster / BytesPerFileRecord) - 1;
203 ULONG n = m > 0 ? (index & m) : 0;
204
205 p = ExAllocatePoolWithTag(NonPagedPool,
206 clusters * Vcb->NtfsInfo.BytesPerCluster,
207 TAG_NTFS);
208
209 ReadVCN (Vcb, Mft, AttributeData, vcn, clusters, p);
210
211 memcpy(file,
212 (PVOID)((ULONG_PTR)p + n * BytesPerFileRecord),
213 BytesPerFileRecord);
214
215 ExFreePool(p);
216
217 FixupUpdateSequenceArray(file);
218
219 return STATUS_SUCCESS;
220 }
221
222
223 VOID
224 ReadExternalAttribute(PDEVICE_EXTENSION Vcb,
225 PNONRESIDENT_ATTRIBUTE NresAttr,
226 ULONGLONG vcn,
227 ULONG count,
228 PVOID buffer)
229 {
230 ULONGLONG lcn;
231 ULONGLONG runcount;
232 ULONG readcount;
233 ULONG left;
234 ULONG n;
235
236 PUCHAR bytes = (PUCHAR)buffer;
237
238 for (left = count; left > 0; left -= readcount)
239 {
240 FindRun(NresAttr, vcn, &lcn, &runcount);
241
242 // readcount = (ULONG)(__min(runcount, left));
243 readcount = (ULONG)min(runcount, left);
244
245
246 n = readcount * Vcb->NtfsInfo.BytesPerCluster;
247
248 if (lcn == 0)
249 memset(bytes, 0, n);
250 else
251 ReadLCN(Vcb, lcn, readcount, bytes);
252
253 vcn += readcount;
254 bytes += n;
255 }
256 }
257
258
259 VOID
260 ReadVCN(PDEVICE_EXTENSION Vcb,
261 PFILE_RECORD_HEADER file,
262 ATTRIBUTE_TYPE type,
263 ULONGLONG vcn,
264 ULONG count,
265 PVOID buffer)
266 {
267 PNONRESIDENT_ATTRIBUTE NresAttr;
268 PATTRIBUTE attr;
269
270 attr = FindAttribute(file, type, 0);
271
272 NresAttr = (PNONRESIDENT_ATTRIBUTE) attr;
273
274 if (NresAttr == 0 || (vcn < NresAttr->StartVcn ||vcn > NresAttr->LastVcn))
275 {
276 // PATTRIBUTE attrList = FindAttribute(file,AttributeAttributeList,0);
277 DbgPrint("Exeption \n");
278 // KeDebugCheck(0);
279 }
280
281 ReadExternalAttribute(Vcb, NresAttr, vcn, count, buffer);
282 }
283
284
285 #if 0
286 BOOL bitset(PUCHAR bitmap, ULONG i)
287 {
288 return (bitmap[i>>3] & (1 << (i & 7))) !=0;
289 }
290 #endif
291
292
293 VOID
294 FixupUpdateSequenceArray(PFILE_RECORD_HEADER file)
295 {
296 PUSHORT usa = (PUSHORT)((ULONG_PTR)file + file->Ntfs.UsaOffset);
297 PUSHORT sector = (PUSHORT)file;
298 ULONG i;
299
300 for (i = 1; i < file->Ntfs.UsaCount; i++)
301 {
302 sector[255] = usa[i];
303 sector += 256;
304 }
305 }
306
307
308 NTSTATUS
309 ReadLCN(PDEVICE_EXTENSION Vcb,
310 ULONGLONG lcn,
311 ULONG count,
312 PVOID buffer)
313 {
314 LARGE_INTEGER DiskSector;
315
316 DiskSector.QuadPart = lcn;
317
318 return NtfsReadSectors(Vcb->StorageDevice,
319 DiskSector.u.LowPart * Vcb->NtfsInfo.SectorsPerCluster,
320 count * Vcb->NtfsInfo.SectorsPerCluster,
321 Vcb->NtfsInfo.BytesPerSector,
322 buffer,
323 FALSE);
324 }
325
326 /* EOF */