Sync with trunk r65656.
[reactos.git] / drivers / filesystems / ntfs / attrib.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2002,2003 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/attrib.c
22 * PURPOSE: NTFS filesystem driver
23 * PROGRAMMERS: Eric Kohl
24 * Valentin Verkhovsky
25 * Hervé Poussineau (hpoussin@reactos.org)
26 */
27
28 /* INCLUDES *****************************************************************/
29
30 #include "ntfs.h"
31
32 #define NDEBUG
33 #include <debug.h>
34
35 /* FUNCTIONS ****************************************************************/
36
37 PUCHAR
38 DecodeRun(PUCHAR DataRun,
39 LONGLONG *DataRunOffset,
40 ULONGLONG *DataRunLength)
41 {
42 UCHAR DataRunOffsetSize;
43 UCHAR DataRunLengthSize;
44 CHAR i;
45
46 DataRunOffsetSize = (*DataRun >> 4) & 0xF;
47 DataRunLengthSize = *DataRun & 0xF;
48 *DataRunOffset = 0;
49 *DataRunLength = 0;
50 DataRun++;
51 for (i = 0; i < DataRunLengthSize; i++)
52 {
53 *DataRunLength += ((ULONG64)*DataRun) << (i * 8);
54 DataRun++;
55 }
56
57 /* NTFS 3+ sparse files */
58 if (DataRunOffsetSize == 0)
59 {
60 *DataRunOffset = -1;
61 }
62 else
63 {
64 for (i = 0; i < DataRunOffsetSize - 1; i++)
65 {
66 *DataRunOffset += ((ULONG64)*DataRun) << (i * 8);
67 DataRun++;
68 }
69 /* The last byte contains sign so we must process it different way. */
70 *DataRunOffset = ((LONG64)(CHAR)(*(DataRun++)) << (i * 8)) + *DataRunOffset;
71 }
72
73 DPRINT("DataRunOffsetSize: %x\n", DataRunOffsetSize);
74 DPRINT("DataRunLengthSize: %x\n", DataRunLengthSize);
75 DPRINT("DataRunOffset: %x\n", *DataRunOffset);
76 DPRINT("DataRunLength: %x\n", *DataRunLength);
77
78 return DataRun;
79 }
80
81 BOOLEAN
82 FindRun(PNTFS_ATTR_RECORD NresAttr,
83 ULONGLONG vcn,
84 PULONGLONG lcn,
85 PULONGLONG count)
86 {
87 if (vcn < NresAttr->NonResident.LowestVCN || vcn > NresAttr->NonResident.HighestVCN)
88 return FALSE;
89
90 DecodeRun((PUCHAR)((ULONG_PTR)NresAttr + NresAttr->NonResident.MappingPairsOffset), (PLONGLONG)lcn, count);
91
92 return TRUE;
93 }
94
95
96 static
97 VOID
98 NtfsDumpFileNameAttribute(PNTFS_ATTR_RECORD Attribute)
99 {
100 PFILENAME_ATTRIBUTE FileNameAttr;
101
102 DbgPrint(" $FILE_NAME ");
103
104 // DbgPrint(" Length %lu Offset %hu ", Attribute->Resident.ValueLength, Attribute->Resident.ValueOffset);
105
106 FileNameAttr = (PFILENAME_ATTRIBUTE)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
107 DbgPrint(" (%x) '%.*S' ", FileNameAttr->NameType, FileNameAttr->NameLength, FileNameAttr->Name);
108 DbgPrint(" '%x' ", FileNameAttr->FileAttributes);
109 }
110
111
112 static
113 VOID
114 NtfsDumpStandardInformationAttribute(PNTFS_ATTR_RECORD Attribute)
115 {
116 PSTANDARD_INFORMATION StandardInfoAttr;
117
118 DbgPrint(" $STANDARD_INFORMATION ");
119
120 // DbgPrint(" Length %lu Offset %hu ", Attribute->Resident.ValueLength, Attribute->Resident.ValueOffset);
121
122 StandardInfoAttr = (PSTANDARD_INFORMATION)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
123 DbgPrint(" '%x' ", StandardInfoAttr->FileAttribute);
124 }
125
126
127 static
128 VOID
129 NtfsDumpVolumeNameAttribute(PNTFS_ATTR_RECORD Attribute)
130 {
131 PWCHAR VolumeName;
132
133 DbgPrint(" $VOLUME_NAME ");
134
135 // DbgPrint(" Length %lu Offset %hu ", Attribute->Resident.ValueLength, Attribute->Resident.ValueOffset);
136
137 VolumeName = (PWCHAR)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
138 DbgPrint(" '%.*S' ", Attribute->Resident.ValueLength / sizeof(WCHAR), VolumeName);
139 }
140
141
142 static
143 VOID
144 NtfsDumpVolumeInformationAttribute(PNTFS_ATTR_RECORD Attribute)
145 {
146 PVOLINFO_ATTRIBUTE VolInfoAttr;
147
148 DbgPrint(" $VOLUME_INFORMATION ");
149
150 // DbgPrint(" Length %lu Offset %hu ", Attribute->Resident.ValueLength, Attribute->Resident.ValueOffset);
151
152 VolInfoAttr = (PVOLINFO_ATTRIBUTE)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
153 DbgPrint(" NTFS Version %u.%u Flags 0x%04hx ",
154 VolInfoAttr->MajorVersion,
155 VolInfoAttr->MinorVersion,
156 VolInfoAttr->Flags);
157 }
158
159
160 static
161 VOID
162 NtfsDumpIndexRootAttribute(PNTFS_ATTR_RECORD Attribute)
163 {
164 PINDEX_ROOT_ATTRIBUTE IndexRootAttr;
165
166 IndexRootAttr = (PINDEX_ROOT_ATTRIBUTE)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
167
168 if (IndexRootAttr->AttributeType == AttributeFileName)
169 ASSERT(IndexRootAttr->CollationRule == COLLATION_FILE_NAME);
170
171 DbgPrint(" $INDEX_ROOT (%uB, %u) ", IndexRootAttr->SizeOfEntry, IndexRootAttr->ClustersPerIndexRecord);
172
173 if (IndexRootAttr->Header.Flags == INDEX_ROOT_SMALL)
174 {
175 DbgPrint(" (small) ");
176 }
177 else
178 {
179 ASSERT(IndexRootAttr->Header.Flags == INDEX_ROOT_LARGE);
180 DbgPrint(" (large) ");
181 }
182 }
183
184
185 static
186 VOID
187 NtfsDumpAttribute(PNTFS_ATTR_RECORD Attribute)
188 {
189 UNICODE_STRING Name;
190
191 ULONGLONG lcn = 0;
192 ULONGLONG runcount = 0;
193
194 switch (Attribute->Type)
195 {
196 case AttributeFileName:
197 NtfsDumpFileNameAttribute(Attribute);
198 break;
199
200 case AttributeStandardInformation:
201 NtfsDumpStandardInformationAttribute(Attribute);
202 break;
203
204 case AttributeAttributeList:
205 DbgPrint(" $ATTRIBUTE_LIST ");
206 break;
207
208 case AttributeObjectId:
209 DbgPrint(" $OBJECT_ID ");
210 break;
211
212 case AttributeSecurityDescriptor:
213 DbgPrint(" $SECURITY_DESCRIPTOR ");
214 break;
215
216 case AttributeVolumeName:
217 NtfsDumpVolumeNameAttribute(Attribute);
218 break;
219
220 case AttributeVolumeInformation:
221 NtfsDumpVolumeInformationAttribute(Attribute);
222 break;
223
224 case AttributeData:
225 DbgPrint(" $DATA ");
226 //DataBuf = ExAllocatePool(NonPagedPool,AttributeLengthAllocated(Attribute));
227 break;
228
229 case AttributeIndexRoot:
230 NtfsDumpIndexRootAttribute(Attribute);
231 break;
232
233 case AttributeIndexAllocation:
234 DbgPrint(" $INDEX_ALLOCATION ");
235 break;
236
237 case AttributeBitmap:
238 DbgPrint(" $BITMAP ");
239 break;
240
241 case AttributeReparsePoint:
242 DbgPrint(" $REPARSE_POINT ");
243 break;
244
245 case AttributeEAInformation:
246 DbgPrint(" $EA_INFORMATION ");
247 break;
248
249 case AttributeEA:
250 DbgPrint(" $EA ");
251 break;
252
253 case AttributePropertySet:
254 DbgPrint(" $PROPERTY_SET ");
255 break;
256
257 case AttributeLoggedUtilityStream:
258 DbgPrint(" $LOGGED_UTILITY_STREAM ");
259 break;
260
261 default:
262 DbgPrint(" Attribute %lx ",
263 Attribute->Type);
264 break;
265 }
266
267 if (Attribute->NameLength != 0)
268 {
269 Name.Length = Attribute->NameLength * sizeof(WCHAR);
270 Name.MaximumLength = Name.Length;
271 Name.Buffer = (PWCHAR)((ULONG_PTR)Attribute + Attribute->NameOffset);
272
273 DbgPrint("'%wZ' ", &Name);
274 }
275
276 DbgPrint("(%s)\n",
277 Attribute->IsNonResident ? "non-resident" : "resident");
278
279 if (Attribute->IsNonResident)
280 {
281 FindRun(Attribute,0,&lcn, &runcount);
282
283 DbgPrint(" AllocatedSize %I64u DataSize %I64u\n",
284 Attribute->NonResident.AllocatedSize, Attribute->NonResident.DataSize);
285 DbgPrint(" logical clusters: %I64u - %I64u\n",
286 lcn, lcn + runcount - 1);
287 }
288 }
289
290
291 VOID
292 NtfsDumpFileAttributes(PFILE_RECORD_HEADER FileRecord)
293 {
294 PNTFS_ATTR_RECORD Attribute;
295
296 Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
297 while (Attribute < (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->BytesInUse) &&
298 Attribute->Type != AttributeEnd)
299 {
300 NtfsDumpAttribute(Attribute);
301
302 Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Attribute + Attribute->Length);
303 }
304 }
305
306 PFILENAME_ATTRIBUTE
307 GetFileNameFromRecord(PFILE_RECORD_HEADER FileRecord, UCHAR NameType)
308 {
309 PNTFS_ATTR_RECORD Attribute;
310 PFILENAME_ATTRIBUTE Name;
311
312 Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
313 while (Attribute < (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->BytesInUse) &&
314 Attribute->Type != AttributeEnd)
315 {
316 if (Attribute->Type == AttributeFileName)
317 {
318 Name = (PFILENAME_ATTRIBUTE)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
319 if (Name->NameType == NameType ||
320 (Name->NameType == NTFS_FILE_NAME_WIN32_AND_DOS && NameType == NTFS_FILE_NAME_WIN32) ||
321 (Name->NameType == NTFS_FILE_NAME_WIN32_AND_DOS && NameType == NTFS_FILE_NAME_DOS))
322 {
323 return Name;
324 }
325 }
326
327 Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Attribute + Attribute->Length);
328 }
329
330 return NULL;
331 }
332
333 PSTANDARD_INFORMATION
334 GetStandardInformationFromRecord(PFILE_RECORD_HEADER FileRecord)
335 {
336 PNTFS_ATTR_RECORD Attribute;
337 PSTANDARD_INFORMATION StdInfo;
338
339 Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
340 while (Attribute < (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->BytesInUse) &&
341 Attribute->Type != AttributeEnd)
342 {
343 if (Attribute->Type == AttributeStandardInformation)
344 {
345 StdInfo = (PSTANDARD_INFORMATION)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
346 return StdInfo;
347 }
348
349 Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Attribute + Attribute->Length);
350 }
351
352 return NULL;
353 }
354
355 PFILENAME_ATTRIBUTE
356 GetBestFileNameFromRecord(PFILE_RECORD_HEADER FileRecord)
357 {
358 PFILENAME_ATTRIBUTE FileName;
359
360 FileName = GetFileNameFromRecord(FileRecord, NTFS_FILE_NAME_POSIX);
361 if (FileName == NULL)
362 {
363 FileName = GetFileNameFromRecord(FileRecord, NTFS_FILE_NAME_WIN32);
364 if (FileName == NULL)
365 {
366 FileName = GetFileNameFromRecord(FileRecord, NTFS_FILE_NAME_DOS);
367 }
368 }
369
370 return FileName;
371 }
372
373 /* EOF */