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