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