- Make NTFS compile on msvc.
[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 PNONRESIDENT_ATTRIBUTE NresAttr = (PNONRESIDENT_ATTRIBUTE)attr;
173 if (attr->Nonresident == FALSE)
174 {
175 memcpy (buffer,
176 (PVOID)((ULONG_PTR)attr + ((PRESIDENT_ATTRIBUTE)attr)->ValueOffset),
177 ((PRESIDENT_ATTRIBUTE)attr)->ValueLength);
178 }
179
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 ULONGLONG vcn = index * BytesPerFileRecord / Vcb->NtfsInfo.BytesPerCluster;
198 LONG m = (Vcb->NtfsInfo.BytesPerCluster / BytesPerFileRecord) - 1;
199 ULONG n = m > 0 ? (index & m) : 0;
200
201 p = ExAllocatePool(NonPagedPool, clusters * Vcb->NtfsInfo.BytesPerCluster);
202
203 ReadVCN (Vcb, Mft, AttributeData, vcn, clusters, p);
204
205 memcpy(file, (PVOID)((ULONG_PTR)p + n * BytesPerFileRecord), BytesPerFileRecord);
206
207 ExFreePool(p);
208
209 FixupUpdateSequenceArray(file);
210
211 return STATUS_SUCCESS;
212 }
213
214
215
216 VOID
217 ReadExternalAttribute (PDEVICE_EXTENSION Vcb,
218 PNONRESIDENT_ATTRIBUTE NresAttr,
219 ULONGLONG vcn,
220 ULONG count,
221 PVOID buffer)
222 {
223 ULONGLONG lcn;
224 ULONGLONG runcount;
225 ULONG readcount;
226 ULONG left;
227 ULONG n;
228
229 PUCHAR bytes = (PUCHAR)buffer;
230
231 for (left = count; left>0; left -=readcount)
232 {
233 FindRun(NresAttr, vcn, &lcn, &runcount);
234
235 // readcount = (ULONG)(__min(runcount, left));
236 readcount = (ULONG)min (runcount, left);
237
238
239 n = readcount * Vcb->NtfsInfo.BytesPerCluster;
240
241 if (lcn == 0)
242 memset(bytes, 0, n);
243 else
244 ReadLCN(Vcb, lcn, readcount, bytes);
245
246 vcn += readcount;
247 bytes += n;
248
249
250 }
251 }
252
253
254 VOID
255 ReadVCN (PDEVICE_EXTENSION Vcb,
256 PFILE_RECORD_HEADER file,
257 ATTRIBUTE_TYPE type,
258 ULONGLONG vcn,
259 ULONG count,
260 PVOID buffer)
261 {
262 PNONRESIDENT_ATTRIBUTE NresAttr;
263 PATTRIBUTE attr;
264
265 attr = FindAttribute(file, type, 0);
266
267 NresAttr = (PNONRESIDENT_ATTRIBUTE) attr;
268
269 if (NresAttr == 0 || (vcn < NresAttr->StartVcn ||vcn > NresAttr->LastVcn))
270 {
271 // PATTRIBUTE attrList = FindAttribute(file,AttributeAttributeList,0);
272 DbgPrint("Exeption \n");
273 // KeDebugCheck(0);
274 }
275
276 ReadExternalAttribute(Vcb, NresAttr, vcn, count, buffer);
277 }
278
279
280 #if 0
281 BOOL bitset(PUCHAR bitmap, ULONG i)
282 {
283 return (bitmap[i>>3] & (1 << (i & 7))) !=0;
284 }
285 #endif
286
287
288 VOID FixupUpdateSequenceArray(PFILE_RECORD_HEADER file)
289 {
290 PUSHORT usa = (PUSHORT)((ULONG_PTR)file + file->Ntfs.UsaOffset);
291 PUSHORT sector = (PUSHORT)file;
292 ULONG i;
293
294 for( i =1; i < file->Ntfs.UsaCount; i++)
295 {
296 sector[255] = usa[i];
297 sector += 256;
298
299 }
300
301 }
302
303
304 NTSTATUS
305 ReadLCN (PDEVICE_EXTENSION Vcb,
306 ULONGLONG lcn,
307 ULONG count,
308 PVOID buffer)
309 {
310 LARGE_INTEGER DiskSector;
311
312 DiskSector.QuadPart = lcn;
313
314 return NtfsReadSectors (Vcb->StorageDevice,
315 DiskSector.u.LowPart * Vcb->NtfsInfo.SectorsPerCluster,
316 count * Vcb->NtfsInfo.SectorsPerCluster,
317 Vcb->NtfsInfo.BytesPerSector,
318 buffer,
319 FALSE);
320 }
321
322 /* EOF */