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