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 DPRINT("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 DPRINT("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 RtlZeroMemory(BasicInfo, sizeof(FILE_BASIC_INFORMATION)); 111 112 BasicInfo->CreationTime.QuadPart = FileName->CreationTime; 113 BasicInfo->LastAccessTime.QuadPart = FileName->LastAccessTime; 114 BasicInfo->LastWriteTime.QuadPart = FileName->LastWriteTime; 115 BasicInfo->ChangeTime.QuadPart = FileName->ChangeTime; 116 117 NtfsFileFlagsToAttributes(FileName->FileAttributes, &BasicInfo->FileAttributes); 118 119 *BufferLength -= sizeof(FILE_BASIC_INFORMATION); 120 121 return STATUS_SUCCESS; 122 } 123 124 125 /* 126 * FUNCTION: Retrieve the file name information 127 */ 128 static 129 NTSTATUS 130 NtfsGetNameInformation(PFILE_OBJECT FileObject, 131 PNTFS_FCB Fcb, 132 PDEVICE_OBJECT DeviceObject, 133 PFILE_NAME_INFORMATION NameInfo, 134 PULONG BufferLength) 135 { 136 ULONG BytesToCopy; 137 138 UNREFERENCED_PARAMETER(FileObject); 139 UNREFERENCED_PARAMETER(DeviceObject); 140 141 DPRINT("NtfsGetNameInformation(%p, %p, %p, %p, %p)\n", FileObject, Fcb, DeviceObject, NameInfo, BufferLength); 142 143 ASSERT(NameInfo != NULL); 144 ASSERT(Fcb != NULL); 145 146 /* If buffer can't hold at least the file name length, bail out */ 147 if (*BufferLength < (ULONG)FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0])) 148 return STATUS_BUFFER_TOO_SMALL; 149 150 /* Save file name length, and as much file len, as buffer length allows */ 151 NameInfo->FileNameLength = wcslen(Fcb->PathName) * sizeof(WCHAR); 152 153 /* Calculate amount of bytes to copy not to overflow the buffer */ 154 BytesToCopy = min(NameInfo->FileNameLength, 155 *BufferLength - FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0])); 156 157 /* Fill in the bytes */ 158 RtlCopyMemory(NameInfo->FileName, Fcb->PathName, BytesToCopy); 159 160 /* Check if we could write more but are not able to */ 161 if (*BufferLength < NameInfo->FileNameLength + (ULONG)FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0])) 162 { 163 /* Return number of bytes written */ 164 *BufferLength -= FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]) + BytesToCopy; 165 return STATUS_BUFFER_OVERFLOW; 166 } 167 168 /* We filled up as many bytes, as needed */ 169 *BufferLength -= (FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]) + NameInfo->FileNameLength); 170 171 return STATUS_SUCCESS; 172 } 173 174 175 static 176 NTSTATUS 177 NtfsGetInternalInformation(PNTFS_FCB Fcb, 178 PFILE_INTERNAL_INFORMATION InternalInfo, 179 PULONG BufferLength) 180 { 181 DPRINT1("NtfsGetInternalInformation(%p, %p, %p)\n", Fcb, InternalInfo, BufferLength); 182 183 ASSERT(InternalInfo); 184 ASSERT(Fcb); 185 186 if (*BufferLength < sizeof(FILE_INTERNAL_INFORMATION)) 187 return STATUS_BUFFER_TOO_SMALL; 188 189 InternalInfo->IndexNumber.QuadPart = Fcb->MFTIndex; 190 191 *BufferLength -= sizeof(FILE_INTERNAL_INFORMATION); 192 193 return STATUS_SUCCESS; 194 } 195 196 static 197 NTSTATUS 198 NtfsGetNetworkOpenInformation(PNTFS_FCB Fcb, 199 PDEVICE_EXTENSION DeviceExt, 200 PFILE_NETWORK_OPEN_INFORMATION NetworkInfo, 201 PULONG BufferLength) 202 { 203 PFILENAME_ATTRIBUTE FileName = &Fcb->Entry; 204 205 DPRINT("NtfsGetNetworkOpenInformation(%p, %p, %p, %p)\n", Fcb, DeviceExt, NetworkInfo, BufferLength); 206 207 if (*BufferLength < sizeof(FILE_NETWORK_OPEN_INFORMATION)) 208 return STATUS_BUFFER_TOO_SMALL; 209 210 NetworkInfo->CreationTime.QuadPart = FileName->CreationTime; 211 NetworkInfo->LastAccessTime.QuadPart = FileName->LastAccessTime; 212 NetworkInfo->LastWriteTime.QuadPart = FileName->LastWriteTime; 213 NetworkInfo->ChangeTime.QuadPart = FileName->ChangeTime; 214 215 NetworkInfo->EndOfFile = Fcb->RFCB.FileSize; 216 NetworkInfo->AllocationSize = Fcb->RFCB.AllocationSize; 217 218 NtfsFileFlagsToAttributes(FileName->FileAttributes, &NetworkInfo->FileAttributes); 219 220 *BufferLength -= sizeof(FILE_NETWORK_OPEN_INFORMATION); 221 return STATUS_SUCCESS; 222 } 223 224 static 225 NTSTATUS 226 NtfsGetSteamInformation(PNTFS_FCB Fcb, 227 PDEVICE_EXTENSION DeviceExt, 228 PFILE_STREAM_INFORMATION StreamInfo, 229 PULONG BufferLength) 230 { 231 ULONG CurrentSize; 232 FIND_ATTR_CONTXT Context; 233 PNTFS_ATTR_RECORD Attribute; 234 NTSTATUS Status, BrowseStatus; 235 PFILE_RECORD_HEADER FileRecord; 236 PFILE_STREAM_INFORMATION CurrentInfo = StreamInfo, Previous = NULL; 237 238 if (*BufferLength < sizeof(FILE_STREAM_INFORMATION)) 239 return STATUS_BUFFER_TOO_SMALL; 240 241 FileRecord = ExAllocateFromNPagedLookasideList(&DeviceExt->FileRecLookasideList); 242 if (FileRecord == NULL) 243 { 244 DPRINT1("Not enough memory!\n"); 245 return STATUS_INSUFFICIENT_RESOURCES; 246 } 247 248 Status = ReadFileRecord(DeviceExt, Fcb->MFTIndex, FileRecord); 249 if (!NT_SUCCESS(Status)) 250 { 251 DPRINT1("Can't find record!\n"); 252 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord); 253 return Status; 254 } 255 256 BrowseStatus = FindFirstAttribute(&Context, DeviceExt, FileRecord, FALSE, &Attribute); 257 while (NT_SUCCESS(BrowseStatus)) 258 { 259 if (Attribute->Type == AttributeData) 260 { 261 CurrentSize = FIELD_OFFSET(FILE_STREAM_INFORMATION, StreamName) + Attribute->NameLength * sizeof(WCHAR) + wcslen(L"::$DATA") * sizeof(WCHAR); 262 263 if (CurrentSize > *BufferLength) 264 { 265 Status = STATUS_BUFFER_OVERFLOW; 266 break; 267 } 268 269 CurrentInfo->NextEntryOffset = 0; 270 CurrentInfo->StreamNameLength = (Attribute->NameLength + wcslen(L"::$DATA")) * sizeof(WCHAR); 271 CurrentInfo->StreamSize.QuadPart = AttributeDataLength(Attribute); 272 CurrentInfo->StreamAllocationSize.QuadPart = AttributeAllocatedLength(Attribute); 273 CurrentInfo->StreamName[0] = L':'; 274 RtlMoveMemory(&CurrentInfo->StreamName[1], (PWCHAR)((ULONG_PTR)Attribute + Attribute->NameOffset), CurrentInfo->StreamNameLength); 275 RtlMoveMemory(&CurrentInfo->StreamName[Attribute->NameLength + 1], L":$DATA", sizeof(L":$DATA") - sizeof(UNICODE_NULL)); 276 277 if (Previous != NULL) 278 { 279 Previous->NextEntryOffset = (ULONG_PTR)CurrentInfo - (ULONG_PTR)Previous; 280 } 281 Previous = CurrentInfo; 282 CurrentInfo = (PFILE_STREAM_INFORMATION)((ULONG_PTR)CurrentInfo + CurrentSize); 283 *BufferLength -= CurrentSize; 284 } 285 286 BrowseStatus = FindNextAttribute(&Context, &Attribute); 287 } 288 289 FindCloseAttribute(&Context); 290 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord); 291 return Status; 292 } 293 294 // Convert enum value to friendly name 295 const PCSTR 296 GetInfoClassName(FILE_INFORMATION_CLASS infoClass) 297 { 298 const PCSTR fileInfoClassNames[] = { "???????", 299 "FileDirectoryInformation", 300 "FileFullDirectoryInformation", 301 "FileBothDirectoryInformation", 302 "FileBasicInformation", 303 "FileStandardInformation", 304 "FileInternalInformation", 305 "FileEaInformation", 306 "FileAccessInformation", 307 "FileNameInformation", 308 "FileRenameInformation", 309 "FileLinkInformation", 310 "FileNamesInformation", 311 "FileDispositionInformation", 312 "FilePositionInformation", 313 "FileFullEaInformation", 314 "FileModeInformation", 315 "FileAlignmentInformation", 316 "FileAllInformation", 317 "FileAllocationInformation", 318 "FileEndOfFileInformation", 319 "FileAlternateNameInformation", 320 "FileStreamInformation", 321 "FilePipeInformation", 322 "FilePipeLocalInformation", 323 "FilePipeRemoteInformation", 324 "FileMailslotQueryInformation", 325 "FileMailslotSetInformation", 326 "FileCompressionInformation", 327 "FileObjectIdInformation", 328 "FileCompletionInformation", 329 "FileMoveClusterInformation", 330 "FileQuotaInformation", 331 "FileReparsePointInformation", 332 "FileNetworkOpenInformation", 333 "FileAttributeTagInformation", 334 "FileTrackingInformation", 335 "FileIdBothDirectoryInformation", 336 "FileIdFullDirectoryInformation", 337 "FileValidDataLengthInformation", 338 "FileShortNameInformation", 339 "FileIoCompletionNotificationInformation", 340 "FileIoStatusBlockRangeInformation", 341 "FileIoPriorityHintInformation", 342 "FileSfioReserveInformation", 343 "FileSfioVolumeInformation", 344 "FileHardLinkInformation", 345 "FileProcessIdsUsingFileInformation", 346 "FileNormalizedNameInformation", 347 "FileNetworkPhysicalNameInformation", 348 "FileIdGlobalTxDirectoryInformation", 349 "FileIsRemoteDeviceInformation", 350 "FileAttributeCacheInformation", 351 "FileNumaNodeInformation", 352 "FileStandardLinkInformation", 353 "FileRemoteProtocolInformation", 354 "FileReplaceCompletionInformation", 355 "FileMaximumInformation", 356 "FileDirectoryInformation", 357 "FileFullDirectoryInformation", 358 "FileBothDirectoryInformation", 359 "FileBasicInformation", 360 "FileStandardInformation", 361 "FileInternalInformation", 362 "FileEaInformation", 363 "FileAccessInformation", 364 "FileNameInformation", 365 "FileRenameInformation", 366 "FileLinkInformation", 367 "FileNamesInformation", 368 "FileDispositionInformation", 369 "FilePositionInformation", 370 "FileFullEaInformation", 371 "FileModeInformation", 372 "FileAlignmentInformation", 373 "FileAllInformation", 374 "FileAllocationInformation", 375 "FileEndOfFileInformation", 376 "FileAlternateNameInformation", 377 "FileStreamInformation", 378 "FilePipeInformation", 379 "FilePipeLocalInformation", 380 "FilePipeRemoteInformation", 381 "FileMailslotQueryInformation", 382 "FileMailslotSetInformation", 383 "FileCompressionInformation", 384 "FileObjectIdInformation", 385 "FileCompletionInformation", 386 "FileMoveClusterInformation", 387 "FileQuotaInformation", 388 "FileReparsePointInformation", 389 "FileNetworkOpenInformation", 390 "FileAttributeTagInformation", 391 "FileTrackingInformation", 392 "FileIdBothDirectoryInformation", 393 "FileIdFullDirectoryInformation", 394 "FileValidDataLengthInformation", 395 "FileShortNameInformation", 396 "FileIoCompletionNotificationInformation", 397 "FileIoStatusBlockRangeInformation", 398 "FileIoPriorityHintInformation", 399 "FileSfioReserveInformation", 400 "FileSfioVolumeInformation", 401 "FileHardLinkInformation", 402 "FileProcessIdsUsingFileInformation", 403 "FileNormalizedNameInformation", 404 "FileNetworkPhysicalNameInformation", 405 "FileIdGlobalTxDirectoryInformation", 406 "FileIsRemoteDeviceInformation", 407 "FileAttributeCacheInformation", 408 "FileNumaNodeInformation", 409 "FileStandardLinkInformation", 410 "FileRemoteProtocolInformation", 411 "FileReplaceCompletionInformation", 412 "FileMaximumInformation" }; 413 return fileInfoClassNames[infoClass]; 414 } 415 416 /* 417 * FUNCTION: Retrieve the specified file information 418 */ 419 NTSTATUS 420 NtfsQueryInformation(PNTFS_IRP_CONTEXT IrpContext) 421 { 422 FILE_INFORMATION_CLASS FileInformationClass; 423 PIO_STACK_LOCATION Stack; 424 PFILE_OBJECT FileObject; 425 PNTFS_FCB Fcb; 426 PVOID SystemBuffer; 427 ULONG BufferLength; 428 PIRP Irp; 429 PDEVICE_OBJECT DeviceObject; 430 NTSTATUS Status = STATUS_SUCCESS; 431 432 DPRINT1("NtfsQueryInformation(%p)\n", IrpContext); 433 434 Irp = IrpContext->Irp; 435 Stack = IrpContext->Stack; 436 DeviceObject = IrpContext->DeviceObject; 437 FileInformationClass = Stack->Parameters.QueryFile.FileInformationClass; 438 FileObject = IrpContext->FileObject; 439 Fcb = FileObject->FsContext; 440 441 SystemBuffer = Irp->AssociatedIrp.SystemBuffer; 442 BufferLength = Stack->Parameters.QueryFile.Length; 443 444 if (!ExAcquireResourceSharedLite(&Fcb->MainResource, 445 BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT))) 446 { 447 return NtfsMarkIrpContextForQueue(IrpContext); 448 } 449 450 switch (FileInformationClass) 451 { 452 case FileStandardInformation: 453 Status = NtfsGetStandardInformation(Fcb, 454 DeviceObject, 455 SystemBuffer, 456 &BufferLength); 457 break; 458 459 case FilePositionInformation: 460 Status = NtfsGetPositionInformation(FileObject, 461 SystemBuffer, 462 &BufferLength); 463 break; 464 465 case FileBasicInformation: 466 Status = NtfsGetBasicInformation(FileObject, 467 Fcb, 468 DeviceObject, 469 SystemBuffer, 470 &BufferLength); 471 break; 472 473 case FileNameInformation: 474 Status = NtfsGetNameInformation(FileObject, 475 Fcb, 476 DeviceObject, 477 SystemBuffer, 478 &BufferLength); 479 break; 480 481 case FileInternalInformation: 482 Status = NtfsGetInternalInformation(Fcb, 483 SystemBuffer, 484 &BufferLength); 485 break; 486 487 case FileNetworkOpenInformation: 488 Status = NtfsGetNetworkOpenInformation(Fcb, 489 DeviceObject->DeviceExtension, 490 SystemBuffer, 491 &BufferLength); 492 break; 493 494 case FileStreamInformation: 495 Status = NtfsGetSteamInformation(Fcb, 496 DeviceObject->DeviceExtension, 497 SystemBuffer, 498 &BufferLength); 499 break; 500 501 case FileAlternateNameInformation: 502 case FileAllInformation: 503 DPRINT1("Unimplemented information class: %s\n", GetInfoClassName(FileInformationClass)); 504 Status = STATUS_NOT_IMPLEMENTED; 505 break; 506 507 default: 508 DPRINT1("Unimplemented information class: %s\n", GetInfoClassName(FileInformationClass)); 509 Status = STATUS_INVALID_PARAMETER; 510 } 511 512 ExReleaseResourceLite(&Fcb->MainResource); 513 514 if (NT_SUCCESS(Status)) 515 Irp->IoStatus.Information = 516 Stack->Parameters.QueryFile.Length - BufferLength; 517 else 518 Irp->IoStatus.Information = 0; 519 520 return Status; 521 } 522 523 /** 524 * @name NtfsSetEndOfFile 525 * @implemented 526 * 527 * Sets the end of file (file size) for a given file. 528 * 529 * @param Fcb 530 * Pointer to an NTFS_FCB which describes the target file. Fcb->MainResource should have been 531 * acquired with ExAcquireResourceSharedLite(). 532 * 533 * @param FileObject 534 * Pointer to a FILE_OBJECT describing the target file. 535 * 536 * @param DeviceExt 537 * Points to the target disk's DEVICE_EXTENSION 538 * 539 * @param IrpFlags 540 * ULONG describing the flags of the original IRP request (Irp->Flags). 541 * 542 * @param CaseSensitive 543 * Boolean indicating if the function should operate in case-sensitive mode. This will be TRUE 544 * if an application opened the file with the FILE_FLAG_POSIX_SEMANTICS flag. 545 * 546 * @param NewFileSize 547 * Pointer to a LARGE_INTEGER which indicates the new end of file (file size). 548 * 549 * @return 550 * STATUS_SUCCESS if successful, 551 * STATUS_USER_MAPPED_FILE if trying to truncate a file but MmCanFileBeTruncated() returned false, 552 * STATUS_OBJECT_NAME_NOT_FOUND if there was no $DATA attribute associated with the target file, 553 * STATUS_INVALID_PARAMETER if there was no $FILENAME attribute associated with the target file, 554 * STATUS_INSUFFICIENT_RESOURCES if an allocation failed, 555 * STATUS_ACCESS_DENIED if target file is a volume or if paging is involved. 556 * 557 * @remarks As this function sets the size of a file at the file-level 558 * (and not at the attribute level) it's not recommended to use this 559 * function alongside functions that operate on the data attribute directly. 560 * 561 */ 562 NTSTATUS 563 NtfsSetEndOfFile(PNTFS_FCB Fcb, 564 PFILE_OBJECT FileObject, 565 PDEVICE_EXTENSION DeviceExt, 566 ULONG IrpFlags, 567 BOOLEAN CaseSensitive, 568 PLARGE_INTEGER NewFileSize) 569 { 570 LARGE_INTEGER CurrentFileSize; 571 PFILE_RECORD_HEADER FileRecord; 572 PNTFS_ATTR_CONTEXT DataContext; 573 ULONG AttributeOffset; 574 NTSTATUS Status = STATUS_SUCCESS; 575 ULONGLONG AllocationSize; 576 PFILENAME_ATTRIBUTE FileNameAttribute; 577 ULONGLONG ParentMFTId; 578 UNICODE_STRING FileName; 579 580 581 // Allocate non-paged memory for the file record 582 FileRecord = ExAllocateFromNPagedLookasideList(&DeviceExt->FileRecLookasideList); 583 if (FileRecord == NULL) 584 { 585 DPRINT1("Couldn't allocate memory for file record!"); 586 return STATUS_INSUFFICIENT_RESOURCES; 587 } 588 589 // read the file record 590 DPRINT("Reading file record...\n"); 591 Status = ReadFileRecord(DeviceExt, Fcb->MFTIndex, FileRecord); 592 if (!NT_SUCCESS(Status)) 593 { 594 // We couldn't get the file's record. Free the memory and return the error 595 DPRINT1("Can't find record for %wS!\n", Fcb->ObjectName); 596 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord); 597 return Status; 598 } 599 600 DPRINT("Found record for %wS\n", Fcb->ObjectName); 601 602 CurrentFileSize.QuadPart = NtfsGetFileSize(DeviceExt, FileRecord, L"", 0, NULL); 603 604 // Are we trying to decrease the file size? 605 if (NewFileSize->QuadPart < CurrentFileSize.QuadPart) 606 { 607 // Is the file mapped? 608 if (!MmCanFileBeTruncated(FileObject->SectionObjectPointer, 609 NewFileSize)) 610 { 611 DPRINT1("Couldn't decrease file size!\n"); 612 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord); 613 return STATUS_USER_MAPPED_FILE; 614 } 615 } 616 617 // Find the attribute with the data stream for our file 618 DPRINT("Finding Data Attribute...\n"); 619 Status = FindAttribute(DeviceExt, 620 FileRecord, 621 AttributeData, 622 Fcb->Stream, 623 wcslen(Fcb->Stream), 624 &DataContext, 625 &AttributeOffset); 626 627 // Did we fail to find the attribute? 628 if (!NT_SUCCESS(Status)) 629 { 630 DPRINT1("No '%S' data stream associated with file!\n", Fcb->Stream); 631 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord); 632 return Status; 633 } 634 635 // Get the size of the data attribute 636 CurrentFileSize.QuadPart = AttributeDataLength(DataContext->pRecord); 637 638 // Are we enlarging the attribute? 639 if (NewFileSize->QuadPart > CurrentFileSize.QuadPart) 640 { 641 // is increasing the stream size not allowed? 642 if ((Fcb->Flags & FCB_IS_VOLUME) || 643 (IrpFlags & IRP_PAGING_IO)) 644 { 645 // TODO - just fail for now 646 ReleaseAttributeContext(DataContext); 647 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord); 648 return STATUS_ACCESS_DENIED; 649 } 650 } 651 652 // set the attribute data length 653 Status = SetAttributeDataLength(FileObject, Fcb, DataContext, AttributeOffset, FileRecord, NewFileSize); 654 if (!NT_SUCCESS(Status)) 655 { 656 ReleaseAttributeContext(DataContext); 657 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord); 658 return Status; 659 } 660 661 // now we need to update this file's size in every directory index entry that references it 662 // TODO: expand to work with every filename / hardlink stored in the file record. 663 FileNameAttribute = GetBestFileNameFromRecord(Fcb->Vcb, FileRecord); 664 if (FileNameAttribute == NULL) 665 { 666 DPRINT1("Unable to find FileName attribute associated with file!\n"); 667 ReleaseAttributeContext(DataContext); 668 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord); 669 return STATUS_INVALID_PARAMETER; 670 } 671 672 ParentMFTId = FileNameAttribute->DirectoryFileReferenceNumber & NTFS_MFT_MASK; 673 674 FileName.Buffer = FileNameAttribute->Name; 675 FileName.Length = FileNameAttribute->NameLength * sizeof(WCHAR); 676 FileName.MaximumLength = FileName.Length; 677 678 AllocationSize = AttributeAllocatedLength(DataContext->pRecord); 679 680 Status = UpdateFileNameRecord(Fcb->Vcb, 681 ParentMFTId, 682 &FileName, 683 FALSE, 684 NewFileSize->QuadPart, 685 AllocationSize, 686 CaseSensitive); 687 688 ReleaseAttributeContext(DataContext); 689 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord); 690 691 return Status; 692 } 693 694 /** 695 * @name NtfsSetInformation 696 * @implemented 697 * 698 * Sets the specified file information. 699 * 700 * @param IrpContext 701 * Points to an NTFS_IRP_CONTEXT which describes the set operation 702 * 703 * @return 704 * STATUS_SUCCESS if successful, 705 * STATUS_NOT_IMPLEMENTED if trying to set an unimplemented information class, 706 * STATUS_USER_MAPPED_FILE if trying to truncate a file but MmCanFileBeTruncated() returned false, 707 * STATUS_OBJECT_NAME_NOT_FOUND if there was no $DATA attribute associated with the target file, 708 * STATUS_INVALID_PARAMETER if there was no $FILENAME attribute associated with the target file, 709 * STATUS_INSUFFICIENT_RESOURCES if an allocation failed, 710 * STATUS_ACCESS_DENIED if target file is a volume or if paging is involved. 711 * 712 * @remarks Called by NtfsDispatch() in response to an IRP_MJ_SET_INFORMATION request. 713 * Only the FileEndOfFileInformation InformationClass is fully implemented. FileAllocationInformation 714 * is a hack and not a true implementation, but it's enough to make SetEndOfFile() work. 715 * All other information classes are TODO. 716 * 717 */ 718 NTSTATUS 719 NtfsSetInformation(PNTFS_IRP_CONTEXT IrpContext) 720 { 721 FILE_INFORMATION_CLASS FileInformationClass; 722 PIO_STACK_LOCATION Stack; 723 PDEVICE_EXTENSION DeviceExt; 724 PFILE_OBJECT FileObject; 725 PNTFS_FCB Fcb; 726 PVOID SystemBuffer; 727 ULONG BufferLength; 728 PIRP Irp; 729 PDEVICE_OBJECT DeviceObject; 730 NTSTATUS Status = STATUS_NOT_IMPLEMENTED; 731 732 DPRINT("NtfsSetInformation(%p)\n", IrpContext); 733 734 Irp = IrpContext->Irp; 735 Stack = IrpContext->Stack; 736 DeviceObject = IrpContext->DeviceObject; 737 DeviceExt = DeviceObject->DeviceExtension; 738 FileInformationClass = Stack->Parameters.QueryFile.FileInformationClass; 739 FileObject = IrpContext->FileObject; 740 Fcb = FileObject->FsContext; 741 742 SystemBuffer = Irp->AssociatedIrp.SystemBuffer; 743 BufferLength = Stack->Parameters.QueryFile.Length; 744 745 if (!ExAcquireResourceSharedLite(&Fcb->MainResource, 746 BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT))) 747 { 748 return NtfsMarkIrpContextForQueue(IrpContext); 749 } 750 751 switch (FileInformationClass) 752 { 753 PFILE_END_OF_FILE_INFORMATION EndOfFileInfo; 754 755 /* TODO: Allocation size is not actually the same as file end for NTFS, 756 however, few applications are likely to make the distinction. */ 757 case FileAllocationInformation: 758 DPRINT1("FIXME: Using hacky method of setting FileAllocationInformation.\n"); 759 case FileEndOfFileInformation: 760 EndOfFileInfo = (PFILE_END_OF_FILE_INFORMATION)SystemBuffer; 761 Status = NtfsSetEndOfFile(Fcb, 762 FileObject, 763 DeviceExt, 764 Irp->Flags, 765 BooleanFlagOn(Stack->Flags, SL_CASE_SENSITIVE), 766 &EndOfFileInfo->EndOfFile); 767 break; 768 769 // TODO: all other information classes 770 771 default: 772 DPRINT1("FIXME: Unimplemented information class: %s\n", GetInfoClassName(FileInformationClass)); 773 Status = STATUS_NOT_IMPLEMENTED; 774 } 775 776 ExReleaseResourceLite(&Fcb->MainResource); 777 778 if (NT_SUCCESS(Status)) 779 Irp->IoStatus.Information = 780 Stack->Parameters.QueryFile.Length - BufferLength; 781 else 782 Irp->IoStatus.Information = 0; 783 784 return Status; 785 } 786 /* EOF */ 787