[NTFS] - Add some fixes and improvements to finfo.c from CR-123:
[reactos.git] / drivers / filesystems / ntfs / finfo.c
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 /**
400 * @name NtfsSetEndOfFile
401 * @implemented
402 *
403 * Sets the end of file (file size) for a given file.
404 *
405 * @param Fcb
406 * Pointer to an NTFS_FCB which describes the target file. Fcb->MainResource should have been
407 * acquired with ExAcquireResourceSharedLite().
408 *
409 * @param FileObject
410 * Pointer to a FILE_OBJECT describing the target file.
411 *
412 * @param DeviceExt
413 * Points to the target disk's DEVICE_EXTENSION
414 *
415 * @param IrpFlags
416 * ULONG describing the flags of the original IRP request (Irp->Flags).
417 *
418 * @param CaseSensitive
419 * Boolean indicating if the function should operate in case-sensitive mode. This will be TRUE
420 * if an application opened the file with the FILE_FLAG_POSIX_SEMANTICS flag.
421 *
422 * @param NewFileSize
423 * Pointer to a LARGE_INTEGER which indicates the new end of file (file size).
424 *
425 * @return
426 * STATUS_SUCCESS if successful,
427 * STATUS_USER_MAPPED_FILE if trying to truncate a file but MmCanFileBeTruncated() returned false,
428 * STATUS_OBJECT_NAME_NOT_FOUND if there was no $DATA attribute associated with the target file,
429 * STATUS_INVALID_PARAMETER if there was no $FILENAME attribute associated with the target file,
430 * STATUS_INSUFFICIENT_RESOURCES if an allocation failed,
431 * STATUS_ACCESS_DENIED if target file is a volume or if paging is involved.
432 *
433 * @remarks As this function sets the size of a file at the file-level
434 * (and not at the attribute level) it's not recommended to use this
435 * function alongside functions that operate on the data attribute directly.
436 *
437 */
438 NTSTATUS
439 NtfsSetEndOfFile(PNTFS_FCB Fcb,
440 PFILE_OBJECT FileObject,
441 PDEVICE_EXTENSION DeviceExt,
442 ULONG IrpFlags,
443 BOOLEAN CaseSensitive,
444 PLARGE_INTEGER NewFileSize)
445 {
446 LARGE_INTEGER CurrentFileSize;
447 PFILE_RECORD_HEADER FileRecord;
448 PNTFS_ATTR_CONTEXT DataContext;
449 ULONG AttributeOffset;
450 NTSTATUS Status = STATUS_SUCCESS;
451 ULONGLONG AllocationSize;
452 PFILENAME_ATTRIBUTE FileNameAttribute;
453 ULONGLONG ParentMFTId;
454 UNICODE_STRING FileName;
455
456
457 // Allocate non-paged memory for the file record
458 FileRecord = ExAllocatePoolWithTag(NonPagedPool, DeviceExt->NtfsInfo.BytesPerFileRecord, TAG_NTFS);
459 if (FileRecord == NULL)
460 {
461 DPRINT1("Couldn't allocate memory for file record!");
462 return STATUS_INSUFFICIENT_RESOURCES;
463 }
464
465 // read the file record
466 DPRINT("Reading file record...\n");
467 Status = ReadFileRecord(DeviceExt, Fcb->MFTIndex, FileRecord);
468 if (!NT_SUCCESS(Status))
469 {
470 // We couldn't get the file's record. Free the memory and return the error
471 DPRINT1("Can't find record for %wS!\n", Fcb->ObjectName);
472 ExFreePoolWithTag(FileRecord, TAG_NTFS);
473 return Status;
474 }
475
476 DPRINT("Found record for %wS\n", Fcb->ObjectName);
477
478 CurrentFileSize.QuadPart = NtfsGetFileSize(DeviceExt, FileRecord, L"", 0, (PULONGLONG)&CurrentFileSize);
479
480 // Are we trying to decrease the file size?
481 if (NewFileSize->QuadPart < CurrentFileSize.QuadPart)
482 {
483 // Is the file mapped?
484 if (!MmCanFileBeTruncated(FileObject->SectionObjectPointer,
485 NewFileSize))
486 {
487 DPRINT1("Couldn't decrease file size!\n");
488 ExFreePoolWithTag(FileRecord, TAG_NTFS);
489 return STATUS_USER_MAPPED_FILE;
490 }
491 }
492
493 // Find the attribute with the data stream for our file
494 DPRINT("Finding Data Attribute...\n");
495 Status = FindAttribute(DeviceExt,
496 FileRecord,
497 AttributeData,
498 Fcb->Stream,
499 wcslen(Fcb->Stream),
500 &DataContext,
501 &AttributeOffset);
502
503 // Did we fail to find the attribute?
504 if (!NT_SUCCESS(Status))
505 {
506 DPRINT1("No '%S' data stream associated with file!\n", Fcb->Stream);
507 ExFreePoolWithTag(FileRecord, TAG_NTFS);
508 return Status;
509 }
510
511 // Get the size of the data attribute
512 CurrentFileSize.QuadPart = AttributeDataLength(&DataContext->Record);
513
514 // Are we enlarging the attribute?
515 if (NewFileSize->QuadPart > CurrentFileSize.QuadPart)
516 {
517 // is increasing the stream size not allowed?
518 if ((Fcb->Flags & FCB_IS_VOLUME) ||
519 (IrpFlags & IRP_PAGING_IO))
520 {
521 // TODO - just fail for now
522 ReleaseAttributeContext(DataContext);
523 ExFreePoolWithTag(FileRecord, TAG_NTFS);
524 return STATUS_ACCESS_DENIED;
525 }
526 }
527
528 // set the attribute data length
529 Status = SetAttributeDataLength(FileObject, Fcb, DataContext, AttributeOffset, FileRecord, NewFileSize);
530 if (!NT_SUCCESS(Status))
531 {
532 ReleaseAttributeContext(DataContext);
533 ExFreePoolWithTag(FileRecord, TAG_NTFS);
534 return Status;
535 }
536
537 // now we need to update this file's size in every directory index entry that references it
538 // TODO: expand to work with every filename / hardlink stored in the file record.
539 FileNameAttribute = GetBestFileNameFromRecord(Fcb->Vcb, FileRecord);
540 if (FileNameAttribute == NULL)
541 {
542 DPRINT1("Unable to find FileName attribute associated with file!\n");
543 ReleaseAttributeContext(DataContext);
544 ExFreePoolWithTag(FileRecord, TAG_NTFS);
545 return STATUS_INVALID_PARAMETER;
546 }
547
548 ParentMFTId = FileNameAttribute->DirectoryFileReferenceNumber & NTFS_MFT_MASK;
549
550 FileName.Buffer = FileNameAttribute->Name;
551 FileName.Length = FileNameAttribute->NameLength * sizeof(WCHAR);
552 FileName.MaximumLength = FileName.Length;
553
554 AllocationSize = ROUND_UP(NewFileSize->QuadPart, Fcb->Vcb->NtfsInfo.BytesPerCluster);
555
556 Status = UpdateFileNameRecord(Fcb->Vcb,
557 ParentMFTId,
558 &FileName,
559 FALSE,
560 NewFileSize->QuadPart,
561 AllocationSize,
562 CaseSensitive);
563
564 ReleaseAttributeContext(DataContext);
565 ExFreePoolWithTag(FileRecord, TAG_NTFS);
566
567 return Status;
568 }
569
570 /**
571 * @name NtfsSetInformation
572 * @implemented
573 *
574 * Sets the specified file information.
575 *
576 * @param IrpContext
577 * Points to an NTFS_IRP_CONTEXT which describes the set operation
578 *
579 * @return
580 * STATUS_SUCCESS if successful,
581 * STATUS_NOT_IMPLEMENTED if trying to set an unimplemented information class,
582 * STATUS_USER_MAPPED_FILE if trying to truncate a file but MmCanFileBeTruncated() returned false,
583 * STATUS_OBJECT_NAME_NOT_FOUND if there was no $DATA attribute associated with the target file,
584 * STATUS_INVALID_PARAMETER if there was no $FILENAME attribute associated with the target file,
585 * STATUS_INSUFFICIENT_RESOURCES if an allocation failed,
586 * STATUS_ACCESS_DENIED if target file is a volume or if paging is involved.
587 *
588 * @remarks Called by NtfsDispatch() in response to an IRP_MJ_SET_INFORMATION request.
589 * Only the FileEndOfFileInformation InformationClass is fully implemented. FileAllocationInformation
590 * is a hack and not a true implementation, but it's enough to make SetEndOfFile() work.
591 * All other information classes are TODO.
592 *
593 */
594 NTSTATUS
595 NtfsSetInformation(PNTFS_IRP_CONTEXT IrpContext)
596 {
597 FILE_INFORMATION_CLASS FileInformationClass;
598 PIO_STACK_LOCATION Stack;
599 PDEVICE_EXTENSION DeviceExt;
600 PFILE_OBJECT FileObject;
601 PNTFS_FCB Fcb;
602 PVOID SystemBuffer;
603 ULONG BufferLength;
604 PIRP Irp;
605 PDEVICE_OBJECT DeviceObject;
606 NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
607
608 DPRINT1("NtfsSetInformation(%p)\n", IrpContext);
609
610 Irp = IrpContext->Irp;
611 Stack = IrpContext->Stack;
612 DeviceObject = IrpContext->DeviceObject;
613 DeviceExt = DeviceObject->DeviceExtension;
614 FileInformationClass = Stack->Parameters.QueryFile.FileInformationClass;
615 FileObject = IrpContext->FileObject;
616 Fcb = FileObject->FsContext;
617
618 SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
619 BufferLength = Stack->Parameters.QueryFile.Length;
620
621 if (!ExAcquireResourceSharedLite(&Fcb->MainResource,
622 BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
623 {
624 return NtfsMarkIrpContextForQueue(IrpContext);
625 }
626
627 switch (FileInformationClass)
628 {
629 PFILE_END_OF_FILE_INFORMATION EndOfFileInfo;
630
631 /* TODO: Allocation size is not actually the same as file end for NTFS,
632 however, few applications are likely to make the distinction. */
633 case FileAllocationInformation:
634 DPRINT1("FIXME: Using hacky method of setting FileAllocationInformation.\n");
635 case FileEndOfFileInformation:
636 EndOfFileInfo = (PFILE_END_OF_FILE_INFORMATION)SystemBuffer;
637 Status = NtfsSetEndOfFile(Fcb,
638 FileObject,
639 DeviceExt,
640 Irp->Flags,
641 BooleanFlagOn(Stack->Flags, SL_CASE_SENSITIVE),
642 &EndOfFileInfo->EndOfFile);
643 break;
644
645 // TODO: all other information classes
646
647 default:
648 DPRINT1("FIXME: Unimplemented information class %u\n", FileInformationClass);
649 Status = STATUS_NOT_IMPLEMENTED;
650 }
651
652 ExReleaseResourceLite(&Fcb->MainResource);
653
654 if (NT_SUCCESS(Status))
655 Irp->IoStatus.Information =
656 Stack->Parameters.QueryFile.Length - BufferLength;
657 else
658 Irp->IoStatus.Information = 0;
659
660 return Status;
661 }
662 /* EOF */