[NTFS]
[reactos.git] / reactos / 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(" '%.*S' ", FileNameAttr->NameLength, FileNameAttr->Name);
108 }
109
110
111 static
112 VOID
113 NtfsDumpVolumeNameAttribute(PNTFS_ATTR_RECORD Attribute)
114 {
115 PWCHAR VolumeName;
116
117 DbgPrint(" $VOLUME_NAME ");
118
119 // DbgPrint(" Length %lu Offset %hu ", Attribute->Resident.ValueLength, Attribute->Resident.ValueOffset);
120
121 VolumeName = (PWCHAR)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
122 DbgPrint(" '%.*S' ", Attribute->Resident.ValueLength / sizeof(WCHAR), VolumeName);
123 }
124
125
126 static
127 VOID
128 NtfsDumpVolumeInformationAttribute(PNTFS_ATTR_RECORD Attribute)
129 {
130 PVOLINFO_ATTRIBUTE VolInfoAttr;
131
132 DbgPrint(" $VOLUME_INFORMATION ");
133
134 // DbgPrint(" Length %lu Offset %hu ", Attribute->Resident.ValueLength, Attribute->Resident.ValueOffset);
135
136 VolInfoAttr = (PVOLINFO_ATTRIBUTE)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
137 DbgPrint(" NTFS Version %u.%u Flags 0x%04hx ",
138 VolInfoAttr->MajorVersion,
139 VolInfoAttr->MinorVersion,
140 VolInfoAttr->Flags);
141 }
142
143
144 static
145 VOID
146 NtfsDumpIndexRootAttribute(PNTFS_ATTR_RECORD Attribute)
147 {
148 PINDEX_ROOT_ATTRIBUTE IndexRootAttr;
149
150 IndexRootAttr = (PINDEX_ROOT_ATTRIBUTE)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
151
152 if (IndexRootAttr->AttributeType == AttributeFileName)
153 ASSERT(IndexRootAttr->CollationRule == COLLATION_FILE_NAME);
154
155 DbgPrint(" $INDEX_ROOT (%uB, %u) ", IndexRootAttr->SizeOfEntry, IndexRootAttr->ClustersPerIndexRecord);
156
157 if (IndexRootAttr->Header.Flags == INDEX_ROOT_SMALL)
158 {
159 DbgPrint(" (small) ");
160 }
161 else
162 {
163 ASSERT(IndexRootAttr->Header.Flags == INDEX_ROOT_LARGE);
164 DbgPrint(" (large) ");
165 }
166 }
167
168
169 static
170 VOID
171 NtfsDumpAttribute(PNTFS_ATTR_RECORD Attribute)
172 {
173 UNICODE_STRING Name;
174
175 ULONGLONG lcn = 0;
176 ULONGLONG runcount = 0;
177
178 switch (Attribute->Type)
179 {
180 case AttributeFileName:
181 NtfsDumpFileNameAttribute(Attribute);
182 break;
183
184 case AttributeStandardInformation:
185 DbgPrint(" $STANDARD_INFORMATION ");
186 break;
187
188 case AttributeAttributeList:
189 DbgPrint(" $ATTRIBUTE_LIST ");
190 break;
191
192 case AttributeObjectId:
193 DbgPrint(" $OBJECT_ID ");
194 break;
195
196 case AttributeSecurityDescriptor:
197 DbgPrint(" $SECURITY_DESCRIPTOR ");
198 break;
199
200 case AttributeVolumeName:
201 NtfsDumpVolumeNameAttribute(Attribute);
202 break;
203
204 case AttributeVolumeInformation:
205 NtfsDumpVolumeInformationAttribute(Attribute);
206 break;
207
208 case AttributeData:
209 DbgPrint(" $DATA ");
210 //DataBuf = ExAllocatePool(NonPagedPool,AttributeLengthAllocated(Attribute));
211 break;
212
213 case AttributeIndexRoot:
214 NtfsDumpIndexRootAttribute(Attribute);
215 break;
216
217 case AttributeIndexAllocation:
218 DbgPrint(" $INDEX_ALLOCATION ");
219 break;
220
221 case AttributeBitmap:
222 DbgPrint(" $BITMAP ");
223 break;
224
225 case AttributeReparsePoint:
226 DbgPrint(" $REPARSE_POINT ");
227 break;
228
229 case AttributeEAInformation:
230 DbgPrint(" $EA_INFORMATION ");
231 break;
232
233 case AttributeEA:
234 DbgPrint(" $EA ");
235 break;
236
237 case AttributePropertySet:
238 DbgPrint(" $PROPERTY_SET ");
239 break;
240
241 case AttributeLoggedUtilityStream:
242 DbgPrint(" $LOGGED_UTILITY_STREAM ");
243 break;
244
245 default:
246 DbgPrint(" Attribute %lx ",
247 Attribute->Type);
248 break;
249 }
250
251 if (Attribute->NameLength != 0)
252 {
253 Name.Length = Attribute->NameLength * sizeof(WCHAR);
254 Name.MaximumLength = Name.Length;
255 Name.Buffer = (PWCHAR)((ULONG_PTR)Attribute + Attribute->NameOffset);
256
257 DbgPrint("'%wZ' ", &Name);
258 }
259
260 DbgPrint("(%s)\n",
261 Attribute->IsNonResident ? "non-resident" : "resident");
262
263 if (Attribute->IsNonResident)
264 {
265 FindRun(Attribute,0,&lcn, &runcount);
266
267 DbgPrint(" AllocatedSize %I64u DataSize %I64u\n",
268 Attribute->NonResident.AllocatedSize, Attribute->NonResident.DataSize);
269 DbgPrint(" logical clusters: %I64u - %I64u\n",
270 lcn, lcn + runcount - 1);
271 }
272 }
273
274
275 VOID
276 NtfsDumpFileAttributes(PFILE_RECORD_HEADER FileRecord)
277 {
278 PNTFS_ATTR_RECORD Attribute;
279
280 Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
281 while (Attribute < (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->BytesInUse) &&
282 Attribute->Type != AttributeEnd)
283 {
284 NtfsDumpAttribute(Attribute);
285
286 Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Attribute + Attribute->Length);
287 }
288 }
289
290 PFILENAME_ATTRIBUTE
291 GetFileNameFromRecord(PFILE_RECORD_HEADER FileRecord, UCHAR NameType)
292 {
293 PNTFS_ATTR_RECORD Attribute;
294 PFILENAME_ATTRIBUTE Name;
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 if (Attribute->Type == AttributeFileName)
301 {
302 Name = (PFILENAME_ATTRIBUTE)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
303 if (Name->NameType == NameType ||
304 (Name->NameType == NTFS_FILE_NAME_WIN32_AND_DOS && NameType == NTFS_FILE_NAME_WIN32) ||
305 (Name->NameType == NTFS_FILE_NAME_WIN32_AND_DOS && NameType == NTFS_FILE_NAME_DOS))
306 {
307 return Name;
308 }
309 }
310
311 Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Attribute + Attribute->Length);
312 }
313
314 return NULL;
315 }
316
317 PFILENAME_ATTRIBUTE
318 GetBestFileNameFromRecord(PFILE_RECORD_HEADER FileRecord)
319 {
320 PFILENAME_ATTRIBUTE FileName;
321
322 FileName = GetFileNameFromRecord(FileRecord, NTFS_FILE_NAME_POSIX);
323 if (FileName == NULL)
324 {
325 FileName = GetFileNameFromRecord(FileRecord, NTFS_FILE_NAME_WIN32);
326 if (FileName == NULL)
327 {
328 FileName = GetFileNameFromRecord(FileRecord, NTFS_FILE_NAME_DOS);
329 }
330 }
331
332 return FileName;
333 }
334
335 /* EOF */