[NTFS]
[reactos.git] / reactos / 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 /* GLOBALS *****************************************************************/
35
36
37 /* FUNCTIONS ****************************************************************/
38
39
40 NTSTATUS
41 NtfsOpenMft(PDEVICE_EXTENSION Vcb)
42 {
43 // PVOID Bitmap;
44 PFILE_RECORD_HEADER MftRecord;
45 PFILE_RECORD_HEADER FileRecord;
46 // PATTRIBUTE Attribute;
47 // PATTRIBUTE AttrData;
48 // PRESIDENT_ATTRIBUTE ResAttr;
49
50 NTSTATUS Status;
51 ULONG BytesPerFileRecord;
52 ULONG n;
53 ULONG i;
54
55 DPRINT1("NtfsOpenMft() called\n");
56
57 BytesPerFileRecord = Vcb->NtfsInfo.BytesPerFileRecord;
58
59 MftRecord = ExAllocatePoolWithTag(NonPagedPool,
60 BytesPerFileRecord,
61 TAG_NTFS);
62 if (MftRecord == NULL)
63 {
64 return STATUS_INSUFFICIENT_RESOURCES;
65 }
66
67 Status = NtfsReadSectors(Vcb->StorageDevice,
68 Vcb->NtfsInfo.MftStart.u.LowPart * Vcb->NtfsInfo.SectorsPerCluster,
69 BytesPerFileRecord / Vcb->NtfsInfo.BytesPerSector,
70 Vcb->NtfsInfo.BytesPerSector,
71 (PVOID)MftRecord,
72 FALSE);
73 if (!NT_SUCCESS(Status))
74 {
75 ExFreePool(MftRecord);
76 return Status;
77 }
78
79 FixupUpdateSequenceArray(MftRecord);
80
81 // Attribute = FindAttribute(MftRecord, AttributeBitmap, 0);
82
83 /* Get number of file records*/
84 n = AttributeDataLength(FindAttribute(MftRecord, AttributeData, 0)) / BytesPerFileRecord;
85
86 FileRecord = ExAllocatePoolWithTag(NonPagedPool,
87 BytesPerFileRecord,
88 TAG_NTFS);
89 if (FileRecord == NULL)
90 {
91 ExFreePool(MftRecord);
92 return STATUS_INSUFFICIENT_RESOURCES;
93 }
94
95 /* Enumerate MFT Records */
96 DPRINT("Enumerate MFT records\n");
97 for (i = 0; i < n; i++)
98 {
99 ReadFileRecord(Vcb,
100 i,
101 FileRecord,
102 MftRecord);
103
104 if (FileRecord->Ntfs.Type == NRH_FILE_TYPE &&
105 (FileRecord->Flags & FRH_IN_USE))
106 {
107 DPRINT("\nFile %lu\n\n", i);
108
109 /* Enumerate attributtes */
110 NtfsDumpFileAttributes (FileRecord);
111 DbgPrint("\n\n");
112 }
113 }
114
115 ExFreePool(FileRecord);
116 ExFreePool(MftRecord);
117
118 return Status;
119 }
120
121
122 PATTRIBUTE
123 FindAttribute(PFILE_RECORD_HEADER FileRecord,
124 ATTRIBUTE_TYPE Type,
125 PWSTR name)
126 {
127 PATTRIBUTE Attribute;
128
129 UNREFERENCED_PARAMETER(name);
130
131 Attribute = (PATTRIBUTE)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
132 while (Attribute < (PATTRIBUTE)((ULONG_PTR)FileRecord + FileRecord->BytesInUse) &&
133 Attribute->AttributeType != (ATTRIBUTE_TYPE)-1)
134 {
135 if (Attribute->AttributeType == Type)
136 {
137 return Attribute;
138 }
139
140 Attribute = (PATTRIBUTE)((ULONG_PTR)Attribute + Attribute->Length);
141 }
142
143 return NULL;
144 }
145
146
147 ULONG
148 AttributeAllocatedLength(PATTRIBUTE Attribute)
149 {
150 if (Attribute->Nonresident)
151 {
152 return ((PNONRESIDENT_ATTRIBUTE)Attribute)->AllocatedSize;
153 }
154
155 return ((PRESIDENT_ATTRIBUTE)Attribute)->ValueLength;
156 }
157
158
159 ULONG
160 AttributeDataLength(PATTRIBUTE Attribute)
161 {
162 if (Attribute->Nonresident)
163 {
164 return ((PNONRESIDENT_ATTRIBUTE)Attribute)->DataSize;
165 }
166
167 return ((PRESIDENT_ATTRIBUTE)Attribute)->ValueLength;
168 }
169
170
171 VOID
172 ReadAttribute(PATTRIBUTE attr,
173 PVOID buffer,
174 PDEVICE_EXTENSION Vcb,
175 PDEVICE_OBJECT DeviceObject)
176 {
177 PNONRESIDENT_ATTRIBUTE NresAttr = (PNONRESIDENT_ATTRIBUTE)attr;
178
179 UNREFERENCED_PARAMETER(DeviceObject);
180
181 if (attr->Nonresident == FALSE)
182 {
183 memcpy(buffer,
184 (PVOID)((ULONG_PTR)attr + ((PRESIDENT_ATTRIBUTE)attr)->ValueOffset),
185 ((PRESIDENT_ATTRIBUTE)attr)->ValueLength);
186 }
187
188 ReadExternalAttribute(Vcb,
189 NresAttr,
190 0,
191 (ULONG)(NresAttr->LastVcn) + 1,
192 buffer);
193 }
194
195
196 NTSTATUS
197 ReadFileRecord(PDEVICE_EXTENSION Vcb,
198 ULONG index,
199 PFILE_RECORD_HEADER file,
200 PFILE_RECORD_HEADER Mft)
201 {
202 PVOID p;
203 ULONG BytesPerFileRecord = Vcb->NtfsInfo.BytesPerFileRecord;
204 ULONG clusters = max(BytesPerFileRecord / Vcb->NtfsInfo.BytesPerCluster, 1);
205 ULONGLONG vcn = index * BytesPerFileRecord / Vcb->NtfsInfo.BytesPerCluster;
206 LONG m = (Vcb->NtfsInfo.BytesPerCluster / BytesPerFileRecord) - 1;
207 ULONG n = m > 0 ? (index & m) : 0;
208
209 p = ExAllocatePoolWithTag(NonPagedPool,
210 clusters * Vcb->NtfsInfo.BytesPerCluster,
211 TAG_NTFS);
212
213 ReadVCN (Vcb, Mft, AttributeData, vcn, clusters, p);
214
215 memcpy(file,
216 (PVOID)((ULONG_PTR)p + n * BytesPerFileRecord),
217 BytesPerFileRecord);
218
219 ExFreePool(p);
220
221 FixupUpdateSequenceArray(file);
222
223 return STATUS_SUCCESS;
224 }
225
226
227 VOID
228 ReadExternalAttribute(PDEVICE_EXTENSION Vcb,
229 PNONRESIDENT_ATTRIBUTE NresAttr,
230 ULONGLONG vcn,
231 ULONG count,
232 PVOID buffer)
233 {
234 ULONGLONG lcn;
235 ULONGLONG runcount;
236 ULONG readcount;
237 ULONG left;
238 ULONG n;
239
240 PUCHAR bytes = (PUCHAR)buffer;
241
242 for (left = count; left > 0; left -= readcount)
243 {
244 FindRun(NresAttr, vcn, &lcn, &runcount);
245
246 // readcount = (ULONG)(__min(runcount, left));
247 readcount = (ULONG)min(runcount, left);
248
249
250 n = readcount * Vcb->NtfsInfo.BytesPerCluster;
251
252 if (lcn == 0)
253 memset(bytes, 0, n);
254 else
255 ReadLCN(Vcb, lcn, readcount, bytes);
256
257 vcn += readcount;
258 bytes += n;
259 }
260 }
261
262
263 VOID
264 ReadVCN(PDEVICE_EXTENSION Vcb,
265 PFILE_RECORD_HEADER file,
266 ATTRIBUTE_TYPE type,
267 ULONGLONG vcn,
268 ULONG count,
269 PVOID buffer)
270 {
271 PNONRESIDENT_ATTRIBUTE NresAttr;
272 PATTRIBUTE attr;
273
274 attr = FindAttribute(file, type, 0);
275
276 NresAttr = (PNONRESIDENT_ATTRIBUTE) attr;
277
278 if (NresAttr == 0 || (vcn < NresAttr->StartVcn ||vcn > NresAttr->LastVcn))
279 {
280 // PATTRIBUTE attrList = FindAttribute(file,AttributeAttributeList,0);
281 DbgPrint("Exeption \n");
282 // KeDebugCheck(0);
283 }
284
285 ReadExternalAttribute(Vcb, NresAttr, vcn, count, buffer);
286 }
287
288
289 #if 0
290 BOOL bitset(PUCHAR bitmap, ULONG i)
291 {
292 return (bitmap[i>>3] & (1 << (i & 7))) !=0;
293 }
294 #endif
295
296
297 VOID
298 FixupUpdateSequenceArray(PFILE_RECORD_HEADER file)
299 {
300 PUSHORT usa = (PUSHORT)((ULONG_PTR)file + file->Ntfs.UsaOffset);
301 PUSHORT sector = (PUSHORT)file;
302 ULONG i;
303
304 for (i = 1; i < file->Ntfs.UsaCount; i++)
305 {
306 sector[255] = usa[i];
307 sector += 256;
308 }
309 }
310
311
312 NTSTATUS
313 ReadLCN(PDEVICE_EXTENSION Vcb,
314 ULONGLONG lcn,
315 ULONG count,
316 PVOID buffer)
317 {
318 LARGE_INTEGER DiskSector;
319
320 DiskSector.QuadPart = lcn;
321
322 return NtfsReadSectors(Vcb->StorageDevice,
323 DiskSector.u.LowPart * Vcb->NtfsInfo.SectorsPerCluster,
324 count * Vcb->NtfsInfo.SectorsPerCluster,
325 Vcb->NtfsInfo.BytesPerSector,
326 buffer,
327 FALSE);
328 }
329
330 /* EOF */