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