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