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 = ExAllocateFromNPagedLookasideList(&DeviceExt->FileRecLookasideList); 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 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord); 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 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord); 289 return Status; 290 } 291 292 // Convert enum value to friendly name 293 const PCSTR 294 GetInfoClassName(FILE_INFORMATION_CLASS infoClass) 295 { 296 const PCSTR fileInfoClassNames[] = { "???????", 297 "FileDirectoryInformation", 298 "FileFullDirectoryInformation", 299 "FileBothDirectoryInformation", 300 "FileBasicInformation", 301 "FileStandardInformation", 302 "FileInternalInformation", 303 "FileEaInformation", 304 "FileAccessInformation", 305 "FileNameInformation", 306 "FileRenameInformation", 307 "FileLinkInformation", 308 "FileNamesInformation", 309 "FileDispositionInformation", 310 "FilePositionInformation", 311 "FileFullEaInformation", 312 "FileModeInformation", 313 "FileAlignmentInformation", 314 "FileAllInformation", 315 "FileAllocationInformation", 316 "FileEndOfFileInformation", 317 "FileAlternateNameInformation", 318 "FileStreamInformation", 319 "FilePipeInformation", 320 "FilePipeLocalInformation", 321 "FilePipeRemoteInformation", 322 "FileMailslotQueryInformation", 323 "FileMailslotSetInformation", 324 "FileCompressionInformation", 325 "FileObjectIdInformation", 326 "FileCompletionInformation", 327 "FileMoveClusterInformation", 328 "FileQuotaInformation", 329 "FileReparsePointInformation", 330 "FileNetworkOpenInformation", 331 "FileAttributeTagInformation", 332 "FileTrackingInformation", 333 "FileIdBothDirectoryInformation", 334 "FileIdFullDirectoryInformation", 335 "FileValidDataLengthInformation", 336 "FileShortNameInformation", 337 "FileIoCompletionNotificationInformation", 338 "FileIoStatusBlockRangeInformation", 339 "FileIoPriorityHintInformation", 340 "FileSfioReserveInformation", 341 "FileSfioVolumeInformation", 342 "FileHardLinkInformation", 343 "FileProcessIdsUsingFileInformation", 344 "FileNormalizedNameInformation", 345 "FileNetworkPhysicalNameInformation", 346 "FileIdGlobalTxDirectoryInformation", 347 "FileIsRemoteDeviceInformation", 348 "FileAttributeCacheInformation", 349 "FileNumaNodeInformation", 350 "FileStandardLinkInformation", 351 "FileRemoteProtocolInformation", 352 "FileReplaceCompletionInformation", 353 "FileMaximumInformation", 354 "FileDirectoryInformation", 355 "FileFullDirectoryInformation", 356 "FileBothDirectoryInformation", 357 "FileBasicInformation", 358 "FileStandardInformation", 359 "FileInternalInformation", 360 "FileEaInformation", 361 "FileAccessInformation", 362 "FileNameInformation", 363 "FileRenameInformation", 364 "FileLinkInformation", 365 "FileNamesInformation", 366 "FileDispositionInformation", 367 "FilePositionInformation", 368 "FileFullEaInformation", 369 "FileModeInformation", 370 "FileAlignmentInformation", 371 "FileAllInformation", 372 "FileAllocationInformation", 373 "FileEndOfFileInformation", 374 "FileAlternateNameInformation", 375 "FileStreamInformation", 376 "FilePipeInformation", 377 "FilePipeLocalInformation", 378 "FilePipeRemoteInformation", 379 "FileMailslotQueryInformation", 380 "FileMailslotSetInformation", 381 "FileCompressionInformation", 382 "FileObjectIdInformation", 383 "FileCompletionInformation", 384 "FileMoveClusterInformation", 385 "FileQuotaInformation", 386 "FileReparsePointInformation", 387 "FileNetworkOpenInformation", 388 "FileAttributeTagInformation", 389 "FileTrackingInformation", 390 "FileIdBothDirectoryInformation", 391 "FileIdFullDirectoryInformation", 392 "FileValidDataLengthInformation", 393 "FileShortNameInformation", 394 "FileIoCompletionNotificationInformation", 395 "FileIoStatusBlockRangeInformation", 396 "FileIoPriorityHintInformation", 397 "FileSfioReserveInformation", 398 "FileSfioVolumeInformation", 399 "FileHardLinkInformation", 400 "FileProcessIdsUsingFileInformation", 401 "FileNormalizedNameInformation", 402 "FileNetworkPhysicalNameInformation", 403 "FileIdGlobalTxDirectoryInformation", 404 "FileIsRemoteDeviceInformation", 405 "FileAttributeCacheInformation", 406 "FileNumaNodeInformation", 407 "FileStandardLinkInformation", 408 "FileRemoteProtocolInformation", 409 "FileReplaceCompletionInformation", 410 "FileMaximumInformation" }; 411 return fileInfoClassNames[infoClass]; 412 } 413 414 /* 415 * FUNCTION: Retrieve the specified file information 416 */ 417 NTSTATUS 418 NtfsQueryInformation(PNTFS_IRP_CONTEXT IrpContext) 419 { 420 FILE_INFORMATION_CLASS FileInformationClass; 421 PIO_STACK_LOCATION Stack; 422 PFILE_OBJECT FileObject; 423 PNTFS_FCB Fcb; 424 PVOID SystemBuffer; 425 ULONG BufferLength; 426 PIRP Irp; 427 PDEVICE_OBJECT DeviceObject; 428 NTSTATUS Status = STATUS_SUCCESS; 429 430 DPRINT1("NtfsQueryInformation(%p)\n", IrpContext); 431 432 Irp = IrpContext->Irp; 433 Stack = IrpContext->Stack; 434 DeviceObject = IrpContext->DeviceObject; 435 FileInformationClass = Stack->Parameters.QueryFile.FileInformationClass; 436 FileObject = IrpContext->FileObject; 437 Fcb = FileObject->FsContext; 438 439 SystemBuffer = Irp->AssociatedIrp.SystemBuffer; 440 BufferLength = Stack->Parameters.QueryFile.Length; 441 442 if (!ExAcquireResourceSharedLite(&Fcb->MainResource, 443 BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT))) 444 { 445 return NtfsMarkIrpContextForQueue(IrpContext); 446 } 447 448 switch (FileInformationClass) 449 { 450 case FileStandardInformation: 451 Status = NtfsGetStandardInformation(Fcb, 452 DeviceObject, 453 SystemBuffer, 454 &BufferLength); 455 break; 456 457 case FilePositionInformation: 458 Status = NtfsGetPositionInformation(FileObject, 459 SystemBuffer, 460 &BufferLength); 461 break; 462 463 case FileBasicInformation: 464 Status = NtfsGetBasicInformation(FileObject, 465 Fcb, 466 DeviceObject, 467 SystemBuffer, 468 &BufferLength); 469 break; 470 471 case FileNameInformation: 472 Status = NtfsGetNameInformation(FileObject, 473 Fcb, 474 DeviceObject, 475 SystemBuffer, 476 &BufferLength); 477 break; 478 479 case FileInternalInformation: 480 Status = NtfsGetInternalInformation(Fcb, 481 SystemBuffer, 482 &BufferLength); 483 break; 484 485 case FileNetworkOpenInformation: 486 Status = NtfsGetNetworkOpenInformation(Fcb, 487 DeviceObject->DeviceExtension, 488 SystemBuffer, 489 &BufferLength); 490 break; 491 492 case FileStreamInformation: 493 Status = NtfsGetSteamInformation(Fcb, 494 DeviceObject->DeviceExtension, 495 SystemBuffer, 496 &BufferLength); 497 break; 498 499 case FileAlternateNameInformation: 500 case FileAllInformation: 501 DPRINT1("Unimplemented information class: %s\n", GetInfoClassName(FileInformationClass)); 502 Status = STATUS_NOT_IMPLEMENTED; 503 break; 504 505 default: 506 DPRINT1("Unimplemented information class: %s\n", GetInfoClassName(FileInformationClass)); 507 Status = STATUS_INVALID_PARAMETER; 508 } 509 510 ExReleaseResourceLite(&Fcb->MainResource); 511 512 if (NT_SUCCESS(Status)) 513 Irp->IoStatus.Information = 514 Stack->Parameters.QueryFile.Length - BufferLength; 515 else 516 Irp->IoStatus.Information = 0; 517 518 return Status; 519 } 520 521 /** 522 * @name NtfsSetEndOfFile 523 * @implemented 524 * 525 * Sets the end of file (file size) for a given file. 526 * 527 * @param Fcb 528 * Pointer to an NTFS_FCB which describes the target file. Fcb->MainResource should have been 529 * acquired with ExAcquireResourceSharedLite(). 530 * 531 * @param FileObject 532 * Pointer to a FILE_OBJECT describing the target file. 533 * 534 * @param DeviceExt 535 * Points to the target disk's DEVICE_EXTENSION 536 * 537 * @param IrpFlags 538 * ULONG describing the flags of the original IRP request (Irp->Flags). 539 * 540 * @param CaseSensitive 541 * Boolean indicating if the function should operate in case-sensitive mode. This will be TRUE 542 * if an application opened the file with the FILE_FLAG_POSIX_SEMANTICS flag. 543 * 544 * @param NewFileSize 545 * Pointer to a LARGE_INTEGER which indicates the new end of file (file size). 546 * 547 * @return 548 * STATUS_SUCCESS if successful, 549 * STATUS_USER_MAPPED_FILE if trying to truncate a file but MmCanFileBeTruncated() returned false, 550 * STATUS_OBJECT_NAME_NOT_FOUND if there was no $DATA attribute associated with the target file, 551 * STATUS_INVALID_PARAMETER if there was no $FILENAME attribute associated with the target file, 552 * STATUS_INSUFFICIENT_RESOURCES if an allocation failed, 553 * STATUS_ACCESS_DENIED if target file is a volume or if paging is involved. 554 * 555 * @remarks As this function sets the size of a file at the file-level 556 * (and not at the attribute level) it's not recommended to use this 557 * function alongside functions that operate on the data attribute directly. 558 * 559 */ 560 NTSTATUS 561 NtfsSetEndOfFile(PNTFS_FCB Fcb, 562 PFILE_OBJECT FileObject, 563 PDEVICE_EXTENSION DeviceExt, 564 ULONG IrpFlags, 565 BOOLEAN CaseSensitive, 566 PLARGE_INTEGER NewFileSize) 567 { 568 LARGE_INTEGER CurrentFileSize; 569 PFILE_RECORD_HEADER FileRecord; 570 PNTFS_ATTR_CONTEXT DataContext; 571 ULONG AttributeOffset; 572 NTSTATUS Status = STATUS_SUCCESS; 573 ULONGLONG AllocationSize; 574 PFILENAME_ATTRIBUTE FileNameAttribute; 575 ULONGLONG ParentMFTId; 576 UNICODE_STRING FileName; 577 578 579 // Allocate non-paged memory for the file record 580 FileRecord = ExAllocateFromNPagedLookasideList(&DeviceExt->FileRecLookasideList); 581 if (FileRecord == NULL) 582 { 583 DPRINT1("Couldn't allocate memory for file record!"); 584 return STATUS_INSUFFICIENT_RESOURCES; 585 } 586 587 // read the file record 588 DPRINT("Reading file record...\n"); 589 Status = ReadFileRecord(DeviceExt, Fcb->MFTIndex, FileRecord); 590 if (!NT_SUCCESS(Status)) 591 { 592 // We couldn't get the file's record. Free the memory and return the error 593 DPRINT1("Can't find record for %wS!\n", Fcb->ObjectName); 594 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord); 595 return Status; 596 } 597 598 DPRINT("Found record for %wS\n", Fcb->ObjectName); 599 600 CurrentFileSize.QuadPart = NtfsGetFileSize(DeviceExt, FileRecord, L"", 0, NULL); 601 602 // Are we trying to decrease the file size? 603 if (NewFileSize->QuadPart < CurrentFileSize.QuadPart) 604 { 605 // Is the file mapped? 606 if (!MmCanFileBeTruncated(FileObject->SectionObjectPointer, 607 NewFileSize)) 608 { 609 DPRINT1("Couldn't decrease file size!\n"); 610 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord); 611 return STATUS_USER_MAPPED_FILE; 612 } 613 } 614 615 // Find the attribute with the data stream for our file 616 DPRINT("Finding Data Attribute...\n"); 617 Status = FindAttribute(DeviceExt, 618 FileRecord, 619 AttributeData, 620 Fcb->Stream, 621 wcslen(Fcb->Stream), 622 &DataContext, 623 &AttributeOffset); 624 625 // Did we fail to find the attribute? 626 if (!NT_SUCCESS(Status)) 627 { 628 DPRINT1("No '%S' data stream associated with file!\n", Fcb->Stream); 629 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord); 630 return Status; 631 } 632 633 // Get the size of the data attribute 634 CurrentFileSize.QuadPart = AttributeDataLength(DataContext->pRecord); 635 636 // Are we enlarging the attribute? 637 if (NewFileSize->QuadPart > CurrentFileSize.QuadPart) 638 { 639 // is increasing the stream size not allowed? 640 if ((Fcb->Flags & FCB_IS_VOLUME) || 641 (IrpFlags & IRP_PAGING_IO)) 642 { 643 // TODO - just fail for now 644 ReleaseAttributeContext(DataContext); 645 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord); 646 return STATUS_ACCESS_DENIED; 647 } 648 } 649 650 // set the attribute data length 651 Status = SetAttributeDataLength(FileObject, Fcb, DataContext, AttributeOffset, FileRecord, NewFileSize); 652 if (!NT_SUCCESS(Status)) 653 { 654 ReleaseAttributeContext(DataContext); 655 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord); 656 return Status; 657 } 658 659 // now we need to update this file's size in every directory index entry that references it 660 // TODO: expand to work with every filename / hardlink stored in the file record. 661 FileNameAttribute = GetBestFileNameFromRecord(Fcb->Vcb, FileRecord); 662 if (FileNameAttribute == NULL) 663 { 664 DPRINT1("Unable to find FileName attribute associated with file!\n"); 665 ReleaseAttributeContext(DataContext); 666 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord); 667 return STATUS_INVALID_PARAMETER; 668 } 669 670 ParentMFTId = FileNameAttribute->DirectoryFileReferenceNumber & NTFS_MFT_MASK; 671 672 FileName.Buffer = FileNameAttribute->Name; 673 FileName.Length = FileNameAttribute->NameLength * sizeof(WCHAR); 674 FileName.MaximumLength = FileName.Length; 675 676 AllocationSize = AttributeAllocatedLength(DataContext->pRecord); 677 678 Status = UpdateFileNameRecord(Fcb->Vcb, 679 ParentMFTId, 680 &FileName, 681 FALSE, 682 NewFileSize->QuadPart, 683 AllocationSize, 684 CaseSensitive); 685 686 ReleaseAttributeContext(DataContext); 687 ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord); 688 689 return Status; 690 } 691 692 /** 693 * @name NtfsSetInformation 694 * @implemented 695 * 696 * Sets the specified file information. 697 * 698 * @param IrpContext 699 * Points to an NTFS_IRP_CONTEXT which describes the set operation 700 * 701 * @return 702 * STATUS_SUCCESS if successful, 703 * STATUS_NOT_IMPLEMENTED if trying to set an unimplemented information class, 704 * STATUS_USER_MAPPED_FILE if trying to truncate a file but MmCanFileBeTruncated() returned false, 705 * STATUS_OBJECT_NAME_NOT_FOUND if there was no $DATA attribute associated with the target file, 706 * STATUS_INVALID_PARAMETER if there was no $FILENAME attribute associated with the target file, 707 * STATUS_INSUFFICIENT_RESOURCES if an allocation failed, 708 * STATUS_ACCESS_DENIED if target file is a volume or if paging is involved. 709 * 710 * @remarks Called by NtfsDispatch() in response to an IRP_MJ_SET_INFORMATION request. 711 * Only the FileEndOfFileInformation InformationClass is fully implemented. FileAllocationInformation 712 * is a hack and not a true implementation, but it's enough to make SetEndOfFile() work. 713 * All other information classes are TODO. 714 * 715 */ 716 NTSTATUS 717 NtfsSetInformation(PNTFS_IRP_CONTEXT IrpContext) 718 { 719 FILE_INFORMATION_CLASS FileInformationClass; 720 PIO_STACK_LOCATION Stack; 721 PDEVICE_EXTENSION DeviceExt; 722 PFILE_OBJECT FileObject; 723 PNTFS_FCB Fcb; 724 PVOID SystemBuffer; 725 ULONG BufferLength; 726 PIRP Irp; 727 PDEVICE_OBJECT DeviceObject; 728 NTSTATUS Status = STATUS_NOT_IMPLEMENTED; 729 730 DPRINT1("NtfsSetInformation(%p)\n", IrpContext); 731 732 Irp = IrpContext->Irp; 733 Stack = IrpContext->Stack; 734 DeviceObject = IrpContext->DeviceObject; 735 DeviceExt = DeviceObject->DeviceExtension; 736 FileInformationClass = Stack->Parameters.QueryFile.FileInformationClass; 737 FileObject = IrpContext->FileObject; 738 Fcb = FileObject->FsContext; 739 740 SystemBuffer = Irp->AssociatedIrp.SystemBuffer; 741 BufferLength = Stack->Parameters.QueryFile.Length; 742 743 if (!ExAcquireResourceSharedLite(&Fcb->MainResource, 744 BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT))) 745 { 746 return NtfsMarkIrpContextForQueue(IrpContext); 747 } 748 749 switch (FileInformationClass) 750 { 751 PFILE_END_OF_FILE_INFORMATION EndOfFileInfo; 752 753 /* TODO: Allocation size is not actually the same as file end for NTFS, 754 however, few applications are likely to make the distinction. */ 755 case FileAllocationInformation: 756 DPRINT1("FIXME: Using hacky method of setting FileAllocationInformation.\n"); 757 case FileEndOfFileInformation: 758 EndOfFileInfo = (PFILE_END_OF_FILE_INFORMATION)SystemBuffer; 759 Status = NtfsSetEndOfFile(Fcb, 760 FileObject, 761 DeviceExt, 762 Irp->Flags, 763 BooleanFlagOn(Stack->Flags, SL_CASE_SENSITIVE), 764 &EndOfFileInfo->EndOfFile); 765 break; 766 767 // TODO: all other information classes 768 769 default: 770 DPRINT1("FIXME: Unimplemented information class: %s\n", GetInfoClassName(FileInformationClass)); 771 Status = STATUS_NOT_IMPLEMENTED; 772 } 773 774 ExReleaseResourceLite(&Fcb->MainResource); 775 776 if (NT_SUCCESS(Status)) 777 Irp->IoStatus.Information = 778 Stack->Parameters.QueryFile.Length - BufferLength; 779 else 780 Irp->IoStatus.Information = 0; 781 782 return Status; 783 } 784 /* EOF */ 785