xref: /reactos/drivers/filesystems/ntfs/finfo.c (revision c2c66aff)
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., 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/dirctl.c
22  * PURPOSE:          NTFS filesystem driver
23  * PROGRAMMERS:      Eric Kohl
24  *                   Hervé Poussineau (hpoussin@reactos.org)
25  *                   Pierre Schweitzer (pierre@reactos.org)
26  */
27 
28 /* INCLUDES *****************************************************************/
29 
30 #include "ntfs.h"
31 
32 #define NDEBUG
33 #include <debug.h>
34 
35 /* FUNCTIONS ****************************************************************/
36 
37 /*
38  * FUNCTION: Retrieve the standard file information
39  */
40 static
41 NTSTATUS
42 NtfsGetStandardInformation(PNTFS_FCB Fcb,
43                            PDEVICE_OBJECT DeviceObject,
44                            PFILE_STANDARD_INFORMATION StandardInfo,
45                            PULONG BufferLength)
46 {
47     UNREFERENCED_PARAMETER(DeviceObject);
48 
49     DPRINT1("NtfsGetStandardInformation(%p, %p, %p, %p)\n", Fcb, DeviceObject, StandardInfo, BufferLength);
50 
51     if (*BufferLength < sizeof(FILE_STANDARD_INFORMATION))
52         return STATUS_BUFFER_TOO_SMALL;
53 
54     /* PRECONDITION */
55     ASSERT(StandardInfo != NULL);
56     ASSERT(Fcb != NULL);
57 
58     RtlZeroMemory(StandardInfo,
59                   sizeof(FILE_STANDARD_INFORMATION));
60 
61     StandardInfo->AllocationSize = Fcb->RFCB.AllocationSize;
62     StandardInfo->EndOfFile = Fcb->RFCB.FileSize;
63     StandardInfo->NumberOfLinks = Fcb->LinkCount;
64     StandardInfo->DeletePending = FALSE;
65     StandardInfo->Directory = NtfsFCBIsDirectory(Fcb);
66 
67     *BufferLength -= sizeof(FILE_STANDARD_INFORMATION);
68 
69     return STATUS_SUCCESS;
70 }
71 
72 
73 static
74 NTSTATUS
75 NtfsGetPositionInformation(PFILE_OBJECT FileObject,
76                            PFILE_POSITION_INFORMATION PositionInfo,
77                            PULONG BufferLength)
78 {
79     DPRINT1("NtfsGetPositionInformation(%p, %p, %p)\n", FileObject, PositionInfo, BufferLength);
80 
81     if (*BufferLength < sizeof(FILE_POSITION_INFORMATION))
82         return STATUS_BUFFER_TOO_SMALL;
83 
84     PositionInfo->CurrentByteOffset.QuadPart = FileObject->CurrentByteOffset.QuadPart;
85 
86     DPRINT("Getting position %I64x\n",
87            PositionInfo->CurrentByteOffset.QuadPart);
88 
89     *BufferLength -= sizeof(FILE_POSITION_INFORMATION);
90 
91     return STATUS_SUCCESS;
92 }
93 
94 
95 static
96 NTSTATUS
97 NtfsGetBasicInformation(PFILE_OBJECT FileObject,
98                         PNTFS_FCB Fcb,
99                         PDEVICE_OBJECT DeviceObject,
100                         PFILE_BASIC_INFORMATION BasicInfo,
101                         PULONG BufferLength)
102 {
103     PFILENAME_ATTRIBUTE FileName = &Fcb->Entry;
104 
105     DPRINT1("NtfsGetBasicInformation(%p, %p, %p, %p, %p)\n", FileObject, Fcb, DeviceObject, BasicInfo, BufferLength);
106 
107     if (*BufferLength < sizeof(FILE_BASIC_INFORMATION))
108         return STATUS_BUFFER_TOO_SMALL;
109 
110     BasicInfo->CreationTime.QuadPart = FileName->CreationTime;
111     BasicInfo->LastAccessTime.QuadPart = FileName->LastAccessTime;
112     BasicInfo->LastWriteTime.QuadPart = FileName->LastWriteTime;
113     BasicInfo->ChangeTime.QuadPart = FileName->ChangeTime;
114 
115     NtfsFileFlagsToAttributes(FileName->FileAttributes, &BasicInfo->FileAttributes);
116 
117     *BufferLength -= sizeof(FILE_BASIC_INFORMATION);
118 
119     return STATUS_SUCCESS;
120 }
121 
122 
123 /*
124  * FUNCTION: Retrieve the file name information
125  */
126 static
127 NTSTATUS
128 NtfsGetNameInformation(PFILE_OBJECT FileObject,
129                        PNTFS_FCB Fcb,
130                        PDEVICE_OBJECT DeviceObject,
131                        PFILE_NAME_INFORMATION NameInfo,
132                        PULONG BufferLength)
133 {
134     ULONG BytesToCopy;
135 
136     UNREFERENCED_PARAMETER(FileObject);
137     UNREFERENCED_PARAMETER(DeviceObject);
138 
139     DPRINT1("NtfsGetNameInformation(%p, %p, %p, %p, %p)\n", FileObject, Fcb, DeviceObject, NameInfo, BufferLength);
140 
141     ASSERT(NameInfo != NULL);
142     ASSERT(Fcb != NULL);
143 
144     /* If buffer can't hold at least the file name length, bail out */
145     if (*BufferLength < (ULONG)FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]))
146         return STATUS_BUFFER_TOO_SMALL;
147 
148     /* Save file name length, and as much file len, as buffer length allows */
149     NameInfo->FileNameLength = wcslen(Fcb->PathName) * sizeof(WCHAR);
150 
151     /* Calculate amount of bytes to copy not to overflow the buffer */
152     BytesToCopy = min(NameInfo->FileNameLength,
153                       *BufferLength - FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]));
154 
155     /* Fill in the bytes */
156     RtlCopyMemory(NameInfo->FileName, Fcb->PathName, BytesToCopy);
157 
158     /* Check if we could write more but are not able to */
159     if (*BufferLength < NameInfo->FileNameLength + (ULONG)FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]))
160     {
161         /* Return number of bytes written */
162         *BufferLength -= FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]) + BytesToCopy;
163         return STATUS_BUFFER_OVERFLOW;
164     }
165 
166     /* We filled up as many bytes, as needed */
167     *BufferLength -= (FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]) + NameInfo->FileNameLength);
168 
169     return STATUS_SUCCESS;
170 }
171 
172 
173 static
174 NTSTATUS
175 NtfsGetInternalInformation(PNTFS_FCB Fcb,
176                            PFILE_INTERNAL_INFORMATION InternalInfo,
177                            PULONG BufferLength)
178 {
179     DPRINT1("NtfsGetInternalInformation(%p, %p, %p)\n", Fcb, InternalInfo, BufferLength);
180 
181     ASSERT(InternalInfo);
182     ASSERT(Fcb);
183 
184     if (*BufferLength < sizeof(FILE_INTERNAL_INFORMATION))
185         return STATUS_BUFFER_TOO_SMALL;
186 
187     InternalInfo->IndexNumber.QuadPart = Fcb->MFTIndex;
188 
189     *BufferLength -= sizeof(FILE_INTERNAL_INFORMATION);
190 
191     return STATUS_SUCCESS;
192 }
193 
194 static
195 NTSTATUS
196 NtfsGetNetworkOpenInformation(PNTFS_FCB Fcb,
197                               PDEVICE_EXTENSION DeviceExt,
198                               PFILE_NETWORK_OPEN_INFORMATION NetworkInfo,
199                               PULONG BufferLength)
200 {
201     PFILENAME_ATTRIBUTE FileName = &Fcb->Entry;
202 
203     DPRINT1("NtfsGetNetworkOpenInformation(%p, %p, %p, %p)\n", Fcb, DeviceExt, NetworkInfo, BufferLength);
204 
205     if (*BufferLength < sizeof(FILE_NETWORK_OPEN_INFORMATION))
206         return STATUS_BUFFER_TOO_SMALL;
207 
208     NetworkInfo->CreationTime.QuadPart = FileName->CreationTime;
209     NetworkInfo->LastAccessTime.QuadPart = FileName->LastAccessTime;
210     NetworkInfo->LastWriteTime.QuadPart = FileName->LastWriteTime;
211     NetworkInfo->ChangeTime.QuadPart = FileName->ChangeTime;
212 
213     NetworkInfo->EndOfFile = Fcb->RFCB.FileSize;
214     NetworkInfo->AllocationSize = Fcb->RFCB.AllocationSize;
215 
216     NtfsFileFlagsToAttributes(FileName->FileAttributes, &NetworkInfo->FileAttributes);
217 
218     *BufferLength -= sizeof(FILE_NETWORK_OPEN_INFORMATION);
219     return STATUS_SUCCESS;
220 }
221 
222 static
223 NTSTATUS
224 NtfsGetSteamInformation(PNTFS_FCB Fcb,
225                         PDEVICE_EXTENSION DeviceExt,
226                         PFILE_STREAM_INFORMATION StreamInfo,
227                         PULONG BufferLength)
228 {
229     ULONG CurrentSize;
230     FIND_ATTR_CONTXT Context;
231     PNTFS_ATTR_RECORD Attribute;
232     NTSTATUS Status, BrowseStatus;
233     PFILE_RECORD_HEADER FileRecord;
234     PFILE_STREAM_INFORMATION CurrentInfo = StreamInfo, Previous = NULL;
235 
236     if (*BufferLength < sizeof(FILE_STREAM_INFORMATION))
237         return STATUS_BUFFER_TOO_SMALL;
238 
239     FileRecord = ExAllocatePoolWithTag(NonPagedPool, DeviceExt->NtfsInfo.BytesPerFileRecord, TAG_NTFS);
240     if (FileRecord == NULL)
241     {
242         DPRINT1("Not enough memory!\n");
243         return STATUS_INSUFFICIENT_RESOURCES;
244     }
245 
246     Status = ReadFileRecord(DeviceExt, Fcb->MFTIndex, FileRecord);
247     if (!NT_SUCCESS(Status))
248     {
249         DPRINT1("Can't find record!\n");
250         ExFreePoolWithTag(FileRecord, TAG_NTFS);
251         return Status;
252     }
253 
254     BrowseStatus = FindFirstAttribute(&Context, DeviceExt, FileRecord, FALSE, &Attribute);
255     while (NT_SUCCESS(BrowseStatus))
256     {
257         if (Attribute->Type == AttributeData)
258         {
259             CurrentSize = FIELD_OFFSET(FILE_STREAM_INFORMATION, StreamName) + Attribute->NameLength * sizeof(WCHAR) + wcslen(L"::$DATA") * sizeof(WCHAR);
260 
261             if (CurrentSize > *BufferLength)
262             {
263                 Status = STATUS_BUFFER_OVERFLOW;
264                 break;
265             }
266 
267             CurrentInfo->NextEntryOffset = 0;
268             CurrentInfo->StreamNameLength = (Attribute->NameLength + wcslen(L"::$DATA")) * sizeof(WCHAR);
269             CurrentInfo->StreamSize.QuadPart = AttributeDataLength(Attribute);
270             CurrentInfo->StreamAllocationSize.QuadPart = AttributeAllocatedLength(Attribute);
271             CurrentInfo->StreamName[0] = L':';
272             RtlMoveMemory(&CurrentInfo->StreamName[1], (PWCHAR)((ULONG_PTR)Attribute + Attribute->NameOffset), CurrentInfo->StreamNameLength);
273             RtlMoveMemory(&CurrentInfo->StreamName[Attribute->NameLength + 1], L":$DATA", sizeof(L":$DATA") - sizeof(UNICODE_NULL));
274 
275             if (Previous != NULL)
276             {
277                 Previous->NextEntryOffset = (ULONG_PTR)CurrentInfo - (ULONG_PTR)Previous;
278             }
279             Previous = CurrentInfo;
280             CurrentInfo = (PFILE_STREAM_INFORMATION)((ULONG_PTR)CurrentInfo + CurrentSize);
281             *BufferLength -= CurrentSize;
282         }
283 
284         BrowseStatus = FindNextAttribute(&Context, &Attribute);
285     }
286 
287     FindCloseAttribute(&Context);
288     ExFreePoolWithTag(FileRecord, TAG_NTFS);
289     return Status;
290 }
291 
292 /*
293  * FUNCTION: Retrieve the specified file information
294  */
295 NTSTATUS
296 NtfsQueryInformation(PNTFS_IRP_CONTEXT IrpContext)
297 {
298     FILE_INFORMATION_CLASS FileInformationClass;
299     PIO_STACK_LOCATION Stack;
300     PFILE_OBJECT FileObject;
301     PNTFS_FCB Fcb;
302     PVOID SystemBuffer;
303     ULONG BufferLength;
304     PIRP Irp;
305     PDEVICE_OBJECT DeviceObject;
306     NTSTATUS Status = STATUS_SUCCESS;
307 
308     DPRINT1("NtfsQueryInformation(%p)\n", IrpContext);
309 
310     Irp = IrpContext->Irp;
311     Stack = IrpContext->Stack;
312     DeviceObject = IrpContext->DeviceObject;
313     FileInformationClass = Stack->Parameters.QueryFile.FileInformationClass;
314     FileObject = IrpContext->FileObject;
315     Fcb = FileObject->FsContext;
316 
317     SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
318     BufferLength = Stack->Parameters.QueryFile.Length;
319 
320     if (!ExAcquireResourceSharedLite(&Fcb->MainResource,
321                                      BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
322     {
323         return NtfsMarkIrpContextForQueue(IrpContext);
324     }
325 
326     switch (FileInformationClass)
327     {
328         case FileStandardInformation:
329             Status = NtfsGetStandardInformation(Fcb,
330                                                 DeviceObject,
331                                                 SystemBuffer,
332                                                 &BufferLength);
333             break;
334 
335         case FilePositionInformation:
336             Status = NtfsGetPositionInformation(FileObject,
337                                                 SystemBuffer,
338                                                 &BufferLength);
339             break;
340 
341         case FileBasicInformation:
342             Status = NtfsGetBasicInformation(FileObject,
343                                              Fcb,
344                                              DeviceObject,
345                                              SystemBuffer,
346                                              &BufferLength);
347             break;
348 
349         case FileNameInformation:
350             Status = NtfsGetNameInformation(FileObject,
351                                             Fcb,
352                                             DeviceObject,
353                                             SystemBuffer,
354                                             &BufferLength);
355             break;
356 
357         case FileInternalInformation:
358             Status = NtfsGetInternalInformation(Fcb,
359                                                 SystemBuffer,
360                                                 &BufferLength);
361             break;
362 
363         case FileNetworkOpenInformation:
364             Status = NtfsGetNetworkOpenInformation(Fcb,
365                                                    DeviceObject->DeviceExtension,
366                                                    SystemBuffer,
367                                                    &BufferLength);
368             break;
369 
370         case FileStreamInformation:
371             Status = NtfsGetSteamInformation(Fcb,
372                                              DeviceObject->DeviceExtension,
373                                              SystemBuffer,
374                                              &BufferLength);
375             break;
376 
377         case FileAlternateNameInformation:
378         case FileAllInformation:
379             DPRINT1("Unimplemented information class %u\n", FileInformationClass);
380             Status = STATUS_NOT_IMPLEMENTED;
381             break;
382 
383         default:
384             DPRINT1("Unimplemented information class %u\n", FileInformationClass);
385             Status = STATUS_INVALID_PARAMETER;
386     }
387 
388     ExReleaseResourceLite(&Fcb->MainResource);
389 
390     if (NT_SUCCESS(Status))
391         Irp->IoStatus.Information =
392             Stack->Parameters.QueryFile.Length - BufferLength;
393     else
394         Irp->IoStatus.Information = 0;
395 
396     return Status;
397 }
398 
399 /* EOF */
400