1 /* 2 * COPYRIGHT: See COPYRIGHT.TXT 3 * PROJECT: Ext2 File System Driver for WinNT/2K/XP 4 * FILE: fileinfo.c 5 * PROGRAMMER: Matt Wu <mattwu@163.com> 6 * HOMEPAGE: http://www.ext2fsd.com 7 * UPDATE HISTORY: 8 */ 9 10 /* INCLUDES *****************************************************************/ 11 12 #include "ext2fs.h" 13 #include <linux/ext4.h> 14 #include "linux/ext4_xattr.h" 15 16 /* GLOBALS ***************************************************************/ 17 18 extern PEXT2_GLOBAL Ext2Global; 19 20 /* DEFINITIONS *************************************************************/ 21 22 #ifdef ALLOC_PRAGMA 23 #pragma alloc_text(PAGE, Ext2QueryFileInformation) 24 #pragma alloc_text(PAGE, Ext2SetFileInformation) 25 #pragma alloc_text(PAGE, Ext2ExpandFile) 26 #pragma alloc_text(PAGE, Ext2TruncateFile) 27 #pragma alloc_text(PAGE, Ext2SetDispositionInfo) 28 #pragma alloc_text(PAGE, Ext2SetRenameInfo) 29 #pragma alloc_text(PAGE, Ext2SetLinkInfo) 30 #pragma alloc_text(PAGE, Ext2DeleteFile) 31 #endif 32 33 static int Ext2IterateAllEa(struct ext4_xattr_ref *xattr_ref, struct ext4_xattr_item *item, BOOL is_last) 34 { 35 PULONG EaSize = xattr_ref->iter_arg; 36 ULONG EaEntrySize = 4 + 1 + 1 + 2 + item->name_len + 1 + item->data_size; 37 38 *EaSize += EaEntrySize - 4; 39 return EXT4_XATTR_ITERATE_CONT; 40 } 41 42 NTSTATUS 43 Ext2QueryFileInformation (IN PEXT2_IRP_CONTEXT IrpContext) 44 { 45 PDEVICE_OBJECT DeviceObject; 46 NTSTATUS Status = STATUS_UNSUCCESSFUL; 47 PFILE_OBJECT FileObject; 48 PEXT2_VCB Vcb = NULL; 49 PEXT2_FCB Fcb = NULL; 50 PEXT2_MCB Mcb = NULL; 51 PEXT2_CCB Ccb = NULL; 52 PIRP Irp = NULL; 53 PIO_STACK_LOCATION IoStackLocation; 54 FILE_INFORMATION_CLASS FileInformationClass; 55 ULONG Length; 56 PVOID Buffer; 57 BOOLEAN FcbResourceAcquired = FALSE; 58 59 _SEH2_TRY { 60 61 ASSERT(IrpContext != NULL); 62 ASSERT((IrpContext->Identifier.Type == EXT2ICX) && 63 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); 64 65 DeviceObject = IrpContext->DeviceObject; 66 67 // 68 // This request is not allowed on the main device object 69 // 70 if (IsExt2FsDevice(DeviceObject)) { 71 Status = STATUS_INVALID_DEVICE_REQUEST; 72 _SEH2_LEAVE; 73 } 74 75 FileObject = IrpContext->FileObject; 76 Fcb = (PEXT2_FCB) FileObject->FsContext; 77 if (Fcb == NULL) { 78 Status = STATUS_INVALID_PARAMETER; 79 _SEH2_LEAVE; 80 } 81 82 // 83 // This request is not allowed on volumes 84 // 85 if (Fcb->Identifier.Type == EXT2VCB) { 86 Status = STATUS_INVALID_PARAMETER; 87 _SEH2_LEAVE; 88 } 89 90 if (!((Fcb->Identifier.Type == EXT2FCB) && 91 (Fcb->Identifier.Size == sizeof(EXT2_FCB)))) { 92 Status = STATUS_INVALID_PARAMETER; 93 _SEH2_LEAVE; 94 } 95 96 Vcb = Fcb->Vcb; 97 98 { 99 if (!ExAcquireResourceSharedLite( 100 &Fcb->MainResource, 101 IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) 102 )) { 103 104 Status = STATUS_PENDING; 105 _SEH2_LEAVE; 106 } 107 108 FcbResourceAcquired = TRUE; 109 } 110 111 Ccb = (PEXT2_CCB) FileObject->FsContext2; 112 ASSERT(Ccb != NULL); 113 ASSERT((Ccb->Identifier.Type == EXT2CCB) && 114 (Ccb->Identifier.Size == sizeof(EXT2_CCB))); 115 Mcb = Ccb->SymLink; 116 if (!Mcb) 117 Mcb = Fcb->Mcb; 118 119 Irp = IrpContext->Irp; 120 IoStackLocation = IoGetCurrentIrpStackLocation(Irp); 121 FileInformationClass = 122 IoStackLocation->Parameters.QueryFile.FileInformationClass; 123 124 Length = IoStackLocation->Parameters.QueryFile.Length; 125 Buffer = Irp->AssociatedIrp.SystemBuffer; 126 RtlZeroMemory(Buffer, Length); 127 128 switch (FileInformationClass) { 129 130 case FileBasicInformation: 131 { 132 PFILE_BASIC_INFORMATION FileBasicInformation; 133 134 if (Length < sizeof(FILE_BASIC_INFORMATION)) { 135 Status = STATUS_BUFFER_OVERFLOW; 136 _SEH2_LEAVE; 137 } 138 139 FileBasicInformation = (PFILE_BASIC_INFORMATION) Buffer; 140 141 FileBasicInformation->CreationTime = Mcb->CreationTime; 142 FileBasicInformation->LastAccessTime = Mcb->LastAccessTime; 143 FileBasicInformation->LastWriteTime = Mcb->LastWriteTime; 144 FileBasicInformation->ChangeTime = Mcb->ChangeTime; 145 146 FileBasicInformation->FileAttributes = Mcb->FileAttr; 147 if (IsLinkInvalid(Mcb)) { 148 ClearFlag(FileBasicInformation->FileAttributes, FILE_ATTRIBUTE_DIRECTORY); 149 } 150 if (FileBasicInformation->FileAttributes == 0) { 151 FileBasicInformation->FileAttributes = FILE_ATTRIBUTE_NORMAL; 152 } 153 154 Irp->IoStatus.Information = sizeof(FILE_BASIC_INFORMATION); 155 Status = STATUS_SUCCESS; 156 } 157 break; 158 159 case FileStandardInformation: 160 { 161 PFILE_STANDARD_INFORMATION FSI; 162 163 if (Length < sizeof(FILE_STANDARD_INFORMATION)) { 164 Status = STATUS_BUFFER_OVERFLOW; 165 _SEH2_LEAVE; 166 } 167 168 FSI = (PFILE_STANDARD_INFORMATION) Buffer; 169 170 FSI->NumberOfLinks = Mcb->Inode.i_nlink; 171 172 if (IsVcbReadOnly(Fcb->Vcb)) 173 FSI->DeletePending = FALSE; 174 else 175 FSI->DeletePending = IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING); 176 177 if (IsLinkInvalid(Mcb)) { 178 FSI->Directory = FALSE; 179 FSI->AllocationSize.QuadPart = 0; 180 FSI->EndOfFile.QuadPart = 0; 181 } else if (IsMcbDirectory(Mcb)) { 182 FSI->Directory = TRUE; 183 FSI->AllocationSize.QuadPart = 0; 184 FSI->EndOfFile.QuadPart = 0; 185 } else { 186 FSI->Directory = FALSE; 187 FSI->AllocationSize = Fcb->Header.AllocationSize; 188 FSI->EndOfFile = Fcb->Header.FileSize; 189 } 190 191 Irp->IoStatus.Information = sizeof(FILE_STANDARD_INFORMATION); 192 Status = STATUS_SUCCESS; 193 } 194 break; 195 196 case FileInternalInformation: 197 { 198 PFILE_INTERNAL_INFORMATION FileInternalInformation; 199 200 if (Length < sizeof(FILE_INTERNAL_INFORMATION)) { 201 Status = STATUS_BUFFER_OVERFLOW; 202 _SEH2_LEAVE; 203 } 204 205 FileInternalInformation = (PFILE_INTERNAL_INFORMATION) Buffer; 206 207 /* we use the inode number as the internal index */ 208 FileInternalInformation->IndexNumber.QuadPart = (LONGLONG)Mcb->Inode.i_ino; 209 210 Irp->IoStatus.Information = sizeof(FILE_INTERNAL_INFORMATION); 211 Status = STATUS_SUCCESS; 212 } 213 break; 214 215 216 case FileEaInformation: 217 { 218 struct ext4_xattr_ref xattr_ref; 219 PFILE_EA_INFORMATION FileEaInformation; 220 221 if (Length < sizeof(FILE_EA_INFORMATION)) { 222 Status = STATUS_BUFFER_OVERFLOW; 223 _SEH2_LEAVE; 224 } 225 226 FileEaInformation = (PFILE_EA_INFORMATION) Buffer; 227 FileEaInformation->EaSize = 0; 228 229 Status = Ext2WinntError(ext4_fs_get_xattr_ref(IrpContext, Vcb, Fcb->Mcb, &xattr_ref)); 230 if (!NT_SUCCESS(Status)) 231 _SEH2_LEAVE; 232 233 xattr_ref.iter_arg = &FileEaInformation->EaSize; 234 ext4_fs_xattr_iterate(&xattr_ref, Ext2IterateAllEa); 235 ext4_fs_put_xattr_ref(&xattr_ref); 236 237 if (FileEaInformation->EaSize) 238 FileEaInformation->EaSize += 4; 239 240 Irp->IoStatus.Information = sizeof(FILE_EA_INFORMATION); 241 Status = STATUS_SUCCESS; 242 } 243 break; 244 245 case FileNameInformation: 246 { 247 PFILE_NAME_INFORMATION FileNameInformation; 248 ULONG BytesToCopy = 0; 249 250 if (Length < (ULONG)FIELD_OFFSET(FILE_NAME_INFORMATION, FileName) + 251 Mcb->FullName.Length) { 252 BytesToCopy = Length - FIELD_OFFSET(FILE_NAME_INFORMATION, FileName); 253 Status = STATUS_BUFFER_OVERFLOW; 254 } else { 255 BytesToCopy = Mcb->FullName.Length; 256 Status = STATUS_SUCCESS; 257 } 258 259 FileNameInformation = (PFILE_NAME_INFORMATION) Buffer; 260 FileNameInformation->FileNameLength = Mcb->FullName.Length; 261 262 RtlCopyMemory( 263 FileNameInformation->FileName, 264 Mcb->FullName.Buffer, 265 BytesToCopy ); 266 267 Irp->IoStatus.Information = BytesToCopy + 268 + FIELD_OFFSET(FILE_NAME_INFORMATION, FileName); 269 } 270 break; 271 272 case FilePositionInformation: 273 { 274 PFILE_POSITION_INFORMATION FilePositionInformation; 275 276 if (Length < sizeof(FILE_POSITION_INFORMATION)) { 277 Status = STATUS_BUFFER_OVERFLOW; 278 _SEH2_LEAVE; 279 } 280 281 FilePositionInformation = (PFILE_POSITION_INFORMATION) Buffer; 282 FilePositionInformation->CurrentByteOffset = 283 FileObject->CurrentByteOffset; 284 285 Irp->IoStatus.Information = sizeof(FILE_POSITION_INFORMATION); 286 Status = STATUS_SUCCESS; 287 } 288 break; 289 290 case FileAllInformation: 291 { 292 PFILE_ALL_INFORMATION FileAllInformation; 293 PFILE_BASIC_INFORMATION FileBasicInformation; 294 PFILE_STANDARD_INFORMATION FSI; 295 PFILE_INTERNAL_INFORMATION FileInternalInformation; 296 PFILE_EA_INFORMATION FileEaInformation; 297 PFILE_POSITION_INFORMATION FilePositionInformation; 298 PFILE_NAME_INFORMATION FileNameInformation; 299 300 if (Length < sizeof(FILE_ALL_INFORMATION)) { 301 Status = STATUS_BUFFER_OVERFLOW; 302 _SEH2_LEAVE; 303 } 304 305 FileAllInformation = (PFILE_ALL_INFORMATION) Buffer; 306 307 FileBasicInformation = 308 &FileAllInformation->BasicInformation; 309 310 FSI = 311 &FileAllInformation->StandardInformation; 312 313 FileInternalInformation = 314 &FileAllInformation->InternalInformation; 315 316 FileEaInformation = 317 &FileAllInformation->EaInformation; 318 319 FilePositionInformation = 320 &FileAllInformation->PositionInformation; 321 322 FileNameInformation = 323 &FileAllInformation->NameInformation; 324 325 FileBasicInformation->CreationTime = Mcb->CreationTime; 326 FileBasicInformation->LastAccessTime = Mcb->LastAccessTime; 327 FileBasicInformation->LastWriteTime = Mcb->LastWriteTime; 328 FileBasicInformation->ChangeTime = Mcb->ChangeTime; 329 330 FileBasicInformation->FileAttributes = Mcb->FileAttr; 331 if (IsMcbSymLink(Mcb) && IsFileDeleted(Mcb->Target)) { 332 ClearFlag(FileBasicInformation->FileAttributes, FILE_ATTRIBUTE_DIRECTORY); 333 } 334 if (FileBasicInformation->FileAttributes == 0) { 335 FileBasicInformation->FileAttributes = FILE_ATTRIBUTE_NORMAL; 336 } 337 338 FSI->NumberOfLinks = Mcb->Inode.i_nlink; 339 340 if (IsVcbReadOnly(Fcb->Vcb)) 341 FSI->DeletePending = FALSE; 342 else 343 FSI->DeletePending = IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING); 344 345 if (IsLinkInvalid(Mcb)) { 346 FSI->Directory = FALSE; 347 FSI->AllocationSize.QuadPart = 0; 348 FSI->EndOfFile.QuadPart = 0; 349 } else if (IsDirectory(Fcb)) { 350 FSI->Directory = TRUE; 351 FSI->AllocationSize.QuadPart = 0; 352 FSI->EndOfFile.QuadPart = 0; 353 } else { 354 FSI->Directory = FALSE; 355 FSI->AllocationSize = Fcb->Header.AllocationSize; 356 FSI->EndOfFile = Fcb->Header.FileSize; 357 } 358 359 // The "inode number" 360 FileInternalInformation->IndexNumber.QuadPart = (LONGLONG)Mcb->Inode.i_ino; 361 362 // Romfs doesn't have any extended attributes 363 FileEaInformation->EaSize = 0; 364 365 FilePositionInformation->CurrentByteOffset = 366 FileObject->CurrentByteOffset; 367 368 FileNameInformation->FileNameLength = Mcb->ShortName.Length; 369 370 if (Length < sizeof(FILE_ALL_INFORMATION) + 371 Mcb->ShortName.Length - sizeof(WCHAR)) { 372 Irp->IoStatus.Information = sizeof(FILE_ALL_INFORMATION); 373 Status = STATUS_BUFFER_OVERFLOW; 374 RtlCopyMemory( 375 FileNameInformation->FileName, 376 Mcb->ShortName.Buffer, 377 Length - FIELD_OFFSET(FILE_ALL_INFORMATION, 378 NameInformation.FileName) 379 ); 380 _SEH2_LEAVE; 381 } 382 383 RtlCopyMemory( 384 FileNameInformation->FileName, 385 Mcb->ShortName.Buffer, 386 Mcb->ShortName.Length 387 ); 388 389 Irp->IoStatus.Information = sizeof(FILE_ALL_INFORMATION) + 390 Mcb->ShortName.Length - sizeof(WCHAR); 391 #if 0 392 sizeof(FILE_ACCESS_INFORMATION) - 393 sizeof(FILE_MODE_INFORMATION) - 394 sizeof(FILE_ALIGNMENT_INFORMATION); 395 #endif 396 397 Status = STATUS_SUCCESS; 398 } 399 break; 400 401 /* 402 case FileAlternateNameInformation: 403 { 404 // TODO: Handle FileAlternateNameInformation 405 406 // Here we would like to use RtlGenerate8dot3Name but I don't 407 // know how to use the argument PGENERATE_NAME_CONTEXT 408 } 409 */ 410 411 case FileNetworkOpenInformation: 412 { 413 PFILE_NETWORK_OPEN_INFORMATION PFNOI; 414 415 if (Length < sizeof(FILE_NETWORK_OPEN_INFORMATION)) { 416 Status = STATUS_BUFFER_OVERFLOW; 417 _SEH2_LEAVE; 418 } 419 420 PFNOI = (PFILE_NETWORK_OPEN_INFORMATION) Buffer; 421 422 PFNOI->FileAttributes = Mcb->FileAttr; 423 if (IsLinkInvalid(Mcb)) { 424 ClearFlag(PFNOI->FileAttributes, FILE_ATTRIBUTE_DIRECTORY); 425 PFNOI->AllocationSize.QuadPart = 0; 426 PFNOI->EndOfFile.QuadPart = 0; 427 } else if (IsDirectory(Fcb)) { 428 PFNOI->AllocationSize.QuadPart = 0; 429 PFNOI->EndOfFile.QuadPart = 0; 430 } else { 431 PFNOI->AllocationSize = Fcb->Header.AllocationSize; 432 PFNOI->EndOfFile = Fcb->Header.FileSize; 433 } 434 435 if (PFNOI->FileAttributes == 0) { 436 PFNOI->FileAttributes = FILE_ATTRIBUTE_NORMAL; 437 } 438 439 PFNOI->CreationTime = Mcb->CreationTime; 440 PFNOI->LastAccessTime = Mcb->LastAccessTime; 441 PFNOI->LastWriteTime = Mcb->LastWriteTime; 442 PFNOI->ChangeTime = Mcb->ChangeTime; 443 444 445 Irp->IoStatus.Information = 446 sizeof(FILE_NETWORK_OPEN_INFORMATION); 447 Status = STATUS_SUCCESS; 448 } 449 break; 450 451 #if (_WIN32_WINNT >= 0x0500) 452 453 case FileAttributeTagInformation: 454 { 455 PFILE_ATTRIBUTE_TAG_INFORMATION FATI; 456 457 if (Length < sizeof(FILE_ATTRIBUTE_TAG_INFORMATION)) { 458 Status = STATUS_BUFFER_OVERFLOW; 459 _SEH2_LEAVE; 460 } 461 462 FATI = (PFILE_ATTRIBUTE_TAG_INFORMATION) Buffer; 463 FATI->FileAttributes = Mcb->FileAttr; 464 if (IsLinkInvalid(Mcb)) { 465 ClearFlag(FATI->FileAttributes, FILE_ATTRIBUTE_DIRECTORY); 466 } 467 if (FATI->FileAttributes == 0) { 468 FATI->FileAttributes = FILE_ATTRIBUTE_NORMAL; 469 } 470 FATI->ReparseTag = IO_REPARSE_TAG_RESERVED_ZERO; 471 Irp->IoStatus.Information = sizeof(FILE_ATTRIBUTE_TAG_INFORMATION); 472 Status = STATUS_SUCCESS; 473 } 474 break; 475 #endif // (_WIN32_WINNT >= 0x0500) 476 477 case FileStreamInformation: 478 Status = STATUS_INVALID_PARAMETER; 479 break; 480 481 default: 482 DEBUG(DL_WRN, ( "Ext2QueryInformation: invalid class: %d\n", 483 FileInformationClass)); 484 Status = STATUS_INVALID_PARAMETER; /* STATUS_INVALID_INFO_CLASS; */ 485 break; 486 } 487 488 } _SEH2_FINALLY { 489 490 if (FcbResourceAcquired) { 491 ExReleaseResourceLite(&Fcb->MainResource); 492 } 493 494 if (!IrpContext->ExceptionInProgress) { 495 if (Status == STATUS_PENDING || 496 Status == STATUS_CANT_WAIT) { 497 Status = Ext2QueueRequest(IrpContext); 498 } else { 499 Ext2CompleteIrpContext(IrpContext, Status); 500 } 501 } 502 } _SEH2_END; 503 504 return Status; 505 } 506 507 508 NTSTATUS 509 Ext2SetFileInformation (IN PEXT2_IRP_CONTEXT IrpContext) 510 { 511 PDEVICE_OBJECT DeviceObject; 512 NTSTATUS Status = STATUS_UNSUCCESSFUL; 513 PEXT2_VCB Vcb = NULL; 514 PFILE_OBJECT FileObject = NULL; 515 PEXT2_FCB Fcb = NULL; 516 PEXT2_CCB Ccb = NULL; 517 PEXT2_MCB Mcb = NULL; 518 PIRP Irp = NULL; 519 PIO_STACK_LOCATION IoStackLocation = NULL; 520 FILE_INFORMATION_CLASS FileInformationClass; 521 522 ULONG NotifyFilter = 0; 523 524 ULONG Length; 525 PVOID Buffer; 526 527 BOOLEAN FcbMainResourceAcquired = FALSE; 528 BOOLEAN FcbPagingIoResourceAcquired = FALSE; 529 530 _SEH2_TRY { 531 532 ASSERT(IrpContext != NULL); 533 534 ASSERT((IrpContext->Identifier.Type == EXT2ICX) && 535 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); 536 DeviceObject = IrpContext->DeviceObject; 537 538 // 539 // This request is not allowed on the main device object 540 // 541 if (IsExt2FsDevice(DeviceObject)) { 542 Status = STATUS_INVALID_DEVICE_REQUEST; 543 _SEH2_LEAVE; 544 } 545 546 /* check io stack location of irp stack */ 547 Irp = IrpContext->Irp; 548 IoStackLocation = IoGetCurrentIrpStackLocation(Irp); 549 FileInformationClass = 550 IoStackLocation->Parameters.SetFile.FileInformationClass; 551 Length = IoStackLocation->Parameters.SetFile.Length; 552 Buffer = Irp->AssociatedIrp.SystemBuffer; 553 554 /* check Vcb */ 555 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension; 556 ASSERT(Vcb != NULL); 557 ASSERT((Vcb->Identifier.Type == EXT2VCB) && 558 (Vcb->Identifier.Size == sizeof(EXT2_VCB))); 559 if (!IsMounted(Vcb)) { 560 Status = STATUS_INVALID_DEVICE_REQUEST; 561 _SEH2_LEAVE; 562 } 563 564 if (FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) { 565 Status = STATUS_ACCESS_DENIED; 566 _SEH2_LEAVE; 567 } 568 569 FileObject = IrpContext->FileObject; 570 Fcb = (PEXT2_FCB) FileObject->FsContext; 571 572 // This request is issued to volumes, just return success 573 if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB) { 574 Status = STATUS_SUCCESS; 575 _SEH2_LEAVE; 576 } 577 ASSERT((Fcb->Identifier.Type == EXT2FCB) && 578 (Fcb->Identifier.Size == sizeof(EXT2_FCB))); 579 580 if (IsFlagOn(Fcb->Mcb->Flags, MCB_FILE_DELETED)) { 581 Status = STATUS_FILE_DELETED; 582 _SEH2_LEAVE; 583 } 584 585 Ccb = (PEXT2_CCB) FileObject->FsContext2; 586 ASSERT(Ccb != NULL); 587 ASSERT((Ccb->Identifier.Type == EXT2CCB) && 588 (Ccb->Identifier.Size == sizeof(EXT2_CCB))); 589 Mcb = Ccb->SymLink; 590 if (Mcb) { 591 if (IsFlagOn(Mcb->Flags, MCB_FILE_DELETED)) { 592 Status = STATUS_FILE_DELETED; 593 _SEH2_LEAVE; 594 } 595 } else { 596 Mcb = Fcb->Mcb; 597 } 598 599 if (FileInformationClass != FilePositionInformation) { 600 if (IsVcbReadOnly(Vcb)) { 601 Status = STATUS_MEDIA_WRITE_PROTECTED; 602 _SEH2_LEAVE; 603 } 604 if (!Ext2CheckFileAccess(Vcb, Mcb, Ext2FileCanWrite)) { 605 Status = STATUS_ACCESS_DENIED; 606 _SEH2_LEAVE; 607 } 608 } 609 610 if ( !IsDirectory(Fcb) && !FlagOn(Fcb->Flags, FCB_PAGE_FILE) && 611 ((FileInformationClass == FileEndOfFileInformation) || 612 (FileInformationClass == FileValidDataLengthInformation) || 613 (FileInformationClass == FileAllocationInformation))) { 614 615 Status = FsRtlCheckOplock( &Fcb->Oplock, 616 Irp, 617 IrpContext, 618 NULL, 619 NULL ); 620 621 if (Status != STATUS_SUCCESS) { 622 _SEH2_LEAVE; 623 } 624 625 // 626 // Set the flag indicating if Fast I/O is possible 627 // 628 629 Fcb->Header.IsFastIoPossible = Ext2IsFastIoPossible(Fcb); 630 } 631 632 /* for renaming or set link, we must not grab any Fcb locks, 633 and later we will get Dcb or Fcb resources exclusively. */ 634 if (!IsFlagOn(Fcb->Flags, FCB_PAGE_FILE) && 635 FileInformationClass != FileRenameInformation && 636 FileInformationClass != FileLinkInformation) { 637 638 if (!ExAcquireResourceExclusiveLite( 639 &Fcb->MainResource, 640 IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) { 641 Status = STATUS_PENDING; 642 _SEH2_LEAVE; 643 } 644 645 FcbMainResourceAcquired = TRUE; 646 647 if ( FileInformationClass == FileAllocationInformation || 648 FileInformationClass == FileEndOfFileInformation || 649 FileInformationClass == FileValidDataLengthInformation) { 650 651 if (!ExAcquireResourceExclusiveLite( 652 &Fcb->PagingIoResource, 653 IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) { 654 Status = STATUS_PENDING; 655 DbgBreak(); 656 _SEH2_LEAVE; 657 } 658 FcbPagingIoResourceAcquired = TRUE; 659 } 660 } 661 662 switch (FileInformationClass) { 663 664 case FileBasicInformation: 665 { 666 PFILE_BASIC_INFORMATION FBI = (PFILE_BASIC_INFORMATION) Buffer; 667 struct inode *Inode = &Mcb->Inode; 668 669 if (FBI->CreationTime.QuadPart != 0 && FBI->CreationTime.QuadPart != -1) { 670 Inode->i_ctime = Ext2LinuxTime(FBI->CreationTime); 671 Mcb->CreationTime = Ext2NtTime(Inode->i_ctime); 672 NotifyFilter |= FILE_NOTIFY_CHANGE_CREATION; 673 } 674 675 if (FBI->LastAccessTime.QuadPart != 0 && FBI->LastAccessTime.QuadPart != -1) { 676 Inode->i_atime = Ext2LinuxTime(FBI->LastAccessTime); 677 Mcb->LastAccessTime = Ext2NtTime(Inode->i_atime); 678 NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_ACCESS; 679 } 680 681 if (FBI->LastWriteTime.QuadPart != 0 && FBI->LastWriteTime.QuadPart != -1) { 682 Inode->i_mtime = Ext2LinuxTime(FBI->LastWriteTime); 683 Mcb->LastWriteTime = Ext2NtTime(Inode->i_mtime); 684 NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_WRITE; 685 SetFlag(Ccb->Flags, CCB_LAST_WRITE_UPDATED); 686 } 687 688 if (FBI->ChangeTime.QuadPart !=0 && FBI->ChangeTime.QuadPart != -1) { 689 Mcb->ChangeTime = FBI->ChangeTime; 690 } 691 692 if (FBI->FileAttributes != 0) { 693 694 BOOLEAN bIsDirectory = IsDirectory(Fcb); 695 NotifyFilter |= FILE_NOTIFY_CHANGE_ATTRIBUTES; 696 697 if (IsFlagOn(FBI->FileAttributes, FILE_ATTRIBUTE_READONLY)) { 698 Ext2SetOwnerReadOnly(Inode->i_mode); 699 } else { 700 Ext2SetOwnerWritable(Inode->i_mode); 701 } 702 703 if (FBI->FileAttributes & FILE_ATTRIBUTE_TEMPORARY) { 704 SetFlag(FileObject->Flags, FO_TEMPORARY_FILE); 705 } else { 706 ClearFlag(FileObject->Flags, FO_TEMPORARY_FILE); 707 } 708 709 Mcb->FileAttr = FBI->FileAttributes; 710 if (bIsDirectory) { 711 SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY); 712 ClearFlag(Mcb->FileAttr, FILE_ATTRIBUTE_NORMAL); 713 } 714 } 715 716 if (NotifyFilter != 0) { 717 if (Ext2SaveInode(IrpContext, Vcb, Inode)) { 718 Status = STATUS_SUCCESS; 719 } 720 } 721 722 ClearFlag(NotifyFilter, FILE_NOTIFY_CHANGE_LAST_ACCESS); 723 Status = STATUS_SUCCESS; 724 } 725 726 break; 727 728 case FileAllocationInformation: 729 { 730 PFILE_ALLOCATION_INFORMATION FAI = (PFILE_ALLOCATION_INFORMATION)Buffer; 731 LARGE_INTEGER AllocationSize; 732 733 if (IsMcbDirectory(Mcb) || IsMcbSpecialFile(Mcb)) { 734 Status = STATUS_INVALID_DEVICE_REQUEST; 735 _SEH2_LEAVE; 736 } else { 737 Status = STATUS_SUCCESS; 738 } 739 740 /* set Mcb to it's target */ 741 if (IsMcbSymLink(Mcb)) { 742 ASSERT(Fcb->Mcb == Mcb->Target); 743 } 744 Mcb = Fcb->Mcb; 745 746 /* get user specified allocationsize aligned with BLOCK_SIZE */ 747 AllocationSize.QuadPart = CEILING_ALIGNED(ULONGLONG, 748 (ULONGLONG)FAI->AllocationSize.QuadPart, 749 (ULONGLONG)BLOCK_SIZE); 750 751 if (AllocationSize.QuadPart > Fcb->Header.AllocationSize.QuadPart) { 752 753 Status = Ext2ExpandFile(IrpContext, Vcb, Mcb, &AllocationSize); 754 Fcb->Header.AllocationSize = AllocationSize; 755 NotifyFilter = FILE_NOTIFY_CHANGE_SIZE; 756 SetLongFlag(Fcb->Flags, FCB_ALLOC_IN_SETINFO); 757 758 } else if (AllocationSize.QuadPart < Fcb->Header.AllocationSize.QuadPart) { 759 760 if (MmCanFileBeTruncated(&(Fcb->SectionObject), &AllocationSize)) { 761 762 /* truncate file blocks */ 763 Status = Ext2TruncateFile(IrpContext, Vcb, Mcb, &AllocationSize); 764 765 if (NT_SUCCESS(Status)) { 766 ClearLongFlag(Fcb->Flags, FCB_ALLOC_IN_CREATE); 767 } 768 769 NotifyFilter = FILE_NOTIFY_CHANGE_SIZE; 770 Fcb->Header.AllocationSize.QuadPart = AllocationSize.QuadPart; 771 if (Mcb->Inode.i_size > (loff_t)AllocationSize.QuadPart) { 772 Mcb->Inode.i_size = AllocationSize.QuadPart; 773 } 774 Fcb->Header.FileSize.QuadPart = Mcb->Inode.i_size; 775 if (Fcb->Header.ValidDataLength.QuadPart > Fcb->Header.FileSize.QuadPart) { 776 Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart; 777 } 778 779 } else { 780 781 Status = STATUS_USER_MAPPED_FILE; 782 DbgBreak(); 783 _SEH2_LEAVE; 784 } 785 } 786 787 if (NotifyFilter) { 788 789 SetFlag(FileObject->Flags, FO_FILE_MODIFIED); 790 SetLongFlag(Fcb->Flags, FCB_FILE_MODIFIED); 791 Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode); 792 if (CcIsFileCached(FileObject)) { 793 CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); 794 } 795 } 796 797 DEBUG(DL_IO, ("Ext2SetInformation: %wZ NewSize=%I64xh AllocationSize=%I64xh " 798 "FileSize=%I64xh VDL=%I64xh i_size=%I64xh status = %xh\n", 799 &Fcb->Mcb->ShortName, AllocationSize.QuadPart, 800 Fcb->Header.AllocationSize.QuadPart, 801 Fcb->Header.FileSize.QuadPart, Fcb->Header.ValidDataLength.QuadPart, 802 Mcb->Inode.i_size, Status)); 803 } 804 805 break; 806 807 case FileEndOfFileInformation: 808 { 809 PFILE_END_OF_FILE_INFORMATION FEOFI = (PFILE_END_OF_FILE_INFORMATION) Buffer; 810 LARGE_INTEGER NewSize, OldSize, EndOfFile; 811 812 if (IsMcbDirectory(Mcb) || IsMcbSpecialFile(Mcb)) { 813 Status = STATUS_INVALID_DEVICE_REQUEST; 814 _SEH2_LEAVE; 815 } else { 816 Status = STATUS_SUCCESS; 817 } 818 819 /* set Mcb to it's target */ 820 if (IsMcbSymLink(Mcb)) { 821 ASSERT(Fcb->Mcb == Mcb->Target); 822 } 823 Mcb = Fcb->Mcb; 824 825 OldSize = Fcb->Header.AllocationSize; 826 EndOfFile = FEOFI->EndOfFile; 827 828 if (IoStackLocation->Parameters.SetFile.AdvanceOnly) { 829 830 if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) { 831 _SEH2_LEAVE; 832 } 833 834 if (EndOfFile.QuadPart > Fcb->Header.FileSize.QuadPart) { 835 EndOfFile.QuadPart = Fcb->Header.FileSize.QuadPart; 836 } 837 838 if (EndOfFile.QuadPart > Fcb->Header.ValidDataLength.QuadPart) { 839 Fcb->Header.ValidDataLength.QuadPart = EndOfFile.QuadPart; 840 NotifyFilter = FILE_NOTIFY_CHANGE_SIZE; 841 } 842 843 _SEH2_LEAVE; 844 } 845 846 NewSize.QuadPart = CEILING_ALIGNED(ULONGLONG, 847 EndOfFile.QuadPart, BLOCK_SIZE); 848 849 if (NewSize.QuadPart > OldSize.QuadPart) { 850 851 Fcb->Header.AllocationSize = NewSize; 852 Status = Ext2ExpandFile( 853 IrpContext, 854 Vcb, 855 Mcb, 856 &(Fcb->Header.AllocationSize) 857 ); 858 NotifyFilter = FILE_NOTIFY_CHANGE_SIZE; 859 SetLongFlag(Fcb->Flags, FCB_ALLOC_IN_SETINFO); 860 861 862 } else if (NewSize.QuadPart == OldSize.QuadPart) { 863 864 /* we are luck ;) */ 865 Status = STATUS_SUCCESS; 866 867 } else { 868 869 /* don't truncate file data since it's still being written */ 870 if (IsFlagOn(Fcb->Flags, FCB_ALLOC_IN_WRITE)) { 871 872 Status = STATUS_SUCCESS; 873 874 } else { 875 876 if (!MmCanFileBeTruncated(&(Fcb->SectionObject), &NewSize)) { 877 Status = STATUS_USER_MAPPED_FILE; 878 DbgBreak(); 879 _SEH2_LEAVE; 880 } 881 882 /* truncate file blocks */ 883 Status = Ext2TruncateFile(IrpContext, Vcb, Mcb, &NewSize); 884 885 /* restore original file size */ 886 if (NT_SUCCESS(Status)) { 887 ClearLongFlag(Fcb->Flags, FCB_ALLOC_IN_CREATE); 888 } 889 890 /* update file allocateion size */ 891 Fcb->Header.AllocationSize.QuadPart = NewSize.QuadPart; 892 893 ASSERT((loff_t)NewSize.QuadPart >= Mcb->Inode.i_size); 894 if ((loff_t)Fcb->Header.FileSize.QuadPart < Mcb->Inode.i_size) { 895 Fcb->Header.FileSize.QuadPart = Mcb->Inode.i_size; 896 } 897 if (Fcb->Header.ValidDataLength.QuadPart > Fcb->Header.FileSize.QuadPart) { 898 Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart; 899 } 900 901 SetFlag(FileObject->Flags, FO_FILE_MODIFIED); 902 SetLongFlag(Fcb->Flags, FCB_FILE_MODIFIED); 903 } 904 905 NotifyFilter = FILE_NOTIFY_CHANGE_SIZE; 906 } 907 908 if (NT_SUCCESS(Status)) { 909 910 Fcb->Header.FileSize.QuadPart = Mcb->Inode.i_size = EndOfFile.QuadPart; 911 if (CcIsFileCached(FileObject)) { 912 CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); 913 } 914 915 if (Fcb->Header.FileSize.QuadPart >= 0x80000000 && 916 !IsFlagOn(SUPER_BLOCK->s_feature_ro_compat, EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) { 917 SetFlag(SUPER_BLOCK->s_feature_ro_compat, EXT2_FEATURE_RO_COMPAT_LARGE_FILE); 918 Ext2SaveSuper(IrpContext, Vcb); 919 } 920 921 SetFlag(FileObject->Flags, FO_FILE_MODIFIED); 922 SetLongFlag(Fcb->Flags, FCB_FILE_MODIFIED); 923 NotifyFilter = FILE_NOTIFY_CHANGE_SIZE; 924 } 925 926 927 Ext2SaveInode( IrpContext, Vcb, &Mcb->Inode); 928 929 DEBUG(DL_IO, ("Ext2SetInformation: FileEndOfFileInformation %wZ EndofFile=%I64xh " 930 "AllocatieonSize=%I64xh FileSize=%I64xh VDL=%I64xh i_size=%I64xh status = %xh\n", 931 &Fcb->Mcb->ShortName, EndOfFile.QuadPart, Fcb->Header.AllocationSize.QuadPart, 932 Fcb->Header.FileSize.QuadPart, Fcb->Header.ValidDataLength.QuadPart, 933 Mcb->Inode.i_size, Status)); 934 } 935 936 break; 937 938 case FileValidDataLengthInformation: 939 { 940 PFILE_VALID_DATA_LENGTH_INFORMATION FVDL = (PFILE_VALID_DATA_LENGTH_INFORMATION) Buffer; 941 LARGE_INTEGER NewVDL; 942 943 if (IsMcbDirectory(Mcb) || IsMcbSpecialFile(Mcb)) { 944 Status = STATUS_INVALID_DEVICE_REQUEST; 945 _SEH2_LEAVE; 946 } else { 947 Status = STATUS_SUCCESS; 948 } 949 950 NewVDL = FVDL->ValidDataLength; 951 if ((NewVDL.QuadPart < Fcb->Header.ValidDataLength.QuadPart)) { 952 Status = STATUS_INVALID_PARAMETER; 953 _SEH2_LEAVE; 954 } 955 if (NewVDL.QuadPart > Fcb->Header.FileSize.QuadPart) 956 NewVDL = Fcb->Header.FileSize; 957 958 if (!MmCanFileBeTruncated(FileObject->SectionObjectPointer, 959 &NewVDL)) { 960 Status = STATUS_USER_MAPPED_FILE; 961 _SEH2_LEAVE; 962 } 963 964 Fcb->Header.ValidDataLength = NewVDL; 965 FileObject->Flags |= FO_FILE_MODIFIED; 966 if (CcIsFileCached(FileObject)) { 967 CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); 968 } 969 } 970 971 break; 972 973 case FileDispositionInformation: 974 { 975 PFILE_DISPOSITION_INFORMATION FDI = (PFILE_DISPOSITION_INFORMATION)Buffer; 976 977 Status = Ext2SetDispositionInfo(IrpContext, Vcb, Fcb, Ccb, FDI->DeleteFile); 978 979 DEBUG(DL_INF, ( "Ext2SetInformation: SetDispositionInformation: DeleteFile=%d %wZ status = %xh\n", 980 FDI->DeleteFile, &Mcb->ShortName, Status)); 981 } 982 983 break; 984 985 case FileRenameInformation: 986 { 987 Status = Ext2SetRenameInfo(IrpContext, Vcb, Fcb, Ccb); 988 } 989 990 break; 991 992 993 case FileLinkInformation: 994 { 995 Status = Ext2SetLinkInfo(IrpContext, Vcb, Fcb, Ccb); 996 } 997 998 break; 999 1000 // 1001 // This is the only set file information request supported on read 1002 // only file systems 1003 // 1004 case FilePositionInformation: 1005 { 1006 PFILE_POSITION_INFORMATION FilePositionInformation; 1007 1008 if (Length < sizeof(FILE_POSITION_INFORMATION)) { 1009 Status = STATUS_INVALID_PARAMETER; 1010 _SEH2_LEAVE; 1011 } 1012 1013 FilePositionInformation = (PFILE_POSITION_INFORMATION) Buffer; 1014 1015 if ((FlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING)) && 1016 (FilePositionInformation->CurrentByteOffset.LowPart & 1017 DeviceObject->AlignmentRequirement) ) { 1018 Status = STATUS_INVALID_PARAMETER; 1019 _SEH2_LEAVE; 1020 } 1021 1022 FileObject->CurrentByteOffset = 1023 FilePositionInformation->CurrentByteOffset; 1024 1025 Status = STATUS_SUCCESS; 1026 _SEH2_LEAVE; 1027 } 1028 1029 break; 1030 1031 default: 1032 DEBUG(DL_WRN, ( "Ext2SetInformation: invalid class: %d\n", 1033 FileInformationClass)); 1034 Status = STATUS_INVALID_PARAMETER;/* STATUS_INVALID_INFO_CLASS; */ 1035 } 1036 1037 } _SEH2_FINALLY { 1038 1039 if (FcbPagingIoResourceAcquired) { 1040 ExReleaseResourceLite(&Fcb->PagingIoResource); 1041 } 1042 1043 if (NT_SUCCESS(Status) && (NotifyFilter != 0)) { 1044 Ext2NotifyReportChange( 1045 IrpContext, 1046 Vcb, 1047 Mcb, 1048 NotifyFilter, 1049 FILE_ACTION_MODIFIED ); 1050 1051 } 1052 1053 if (FcbMainResourceAcquired) { 1054 ExReleaseResourceLite(&Fcb->MainResource); 1055 } 1056 1057 if (!IrpContext->ExceptionInProgress) { 1058 if (Status == STATUS_PENDING || 1059 Status == STATUS_CANT_WAIT ) { 1060 DbgBreak(); 1061 Status = Ext2QueueRequest(IrpContext); 1062 } else { 1063 Ext2CompleteIrpContext(IrpContext, Status); 1064 } 1065 } 1066 } _SEH2_END; 1067 1068 return Status; 1069 } 1070 1071 ULONG 1072 Ext2TotalBlocks( 1073 PEXT2_VCB Vcb, 1074 PLARGE_INTEGER Size, 1075 PULONG pMeta 1076 ) 1077 { 1078 ULONG Blocks, Meta =0, Remain; 1079 1080 Blocks = (ULONG)((Size->QuadPart + BLOCK_SIZE - 1) >> BLOCK_BITS); 1081 if (Blocks <= EXT2_NDIR_BLOCKS) 1082 goto errorout; 1083 Blocks -= EXT2_NDIR_BLOCKS; 1084 1085 Meta += 1; 1086 if (Blocks <= Vcb->max_blocks_per_layer[1]) { 1087 goto errorout; 1088 } 1089 Blocks -= Vcb->max_blocks_per_layer[1]; 1090 1091 level2: 1092 1093 if (Blocks <= Vcb->max_blocks_per_layer[2]) { 1094 Meta += 1 + ((Blocks + BLOCK_SIZE/4 - 1) >> (BLOCK_BITS - 2)); 1095 goto errorout; 1096 } 1097 Meta += 1 + BLOCK_SIZE/4; 1098 Blocks -= Vcb->max_blocks_per_layer[2]; 1099 1100 if (Blocks > Vcb->max_blocks_per_layer[3]) { 1101 Blocks = Vcb->max_blocks_per_layer[3]; 1102 } 1103 1104 ASSERT(Vcb->max_blocks_per_layer[2]); 1105 Remain = Blocks % Vcb->max_blocks_per_layer[2]; 1106 Blocks = Blocks / Vcb->max_blocks_per_layer[2]; 1107 Meta += 1 + Blocks * (1 + BLOCK_SIZE/4); 1108 if (Remain) { 1109 Blocks = Remain; 1110 goto level2; 1111 } 1112 1113 errorout: 1114 1115 if (pMeta) 1116 *pMeta = Meta; 1117 Blocks = (ULONG)((Size->QuadPart + BLOCK_SIZE - 1) >> BLOCK_BITS); 1118 return (Blocks + Meta); 1119 } 1120 1121 NTSTATUS 1122 Ext2BlockMap( 1123 IN PEXT2_IRP_CONTEXT IrpContext, 1124 IN PEXT2_VCB Vcb, 1125 IN PEXT2_MCB Mcb, 1126 IN ULONG Index, 1127 IN BOOLEAN bAlloc, 1128 OUT PULONG pBlock, 1129 OUT PULONG Number 1130 ) 1131 { 1132 NTSTATUS status; 1133 1134 if (INODE_HAS_EXTENT(&Mcb->Inode)) { 1135 status = Ext2MapExtent(IrpContext, Vcb, Mcb, Index, 1136 bAlloc, pBlock, Number ); 1137 } else { 1138 status = Ext2MapIndirect(IrpContext, Vcb, Mcb, Index, 1139 bAlloc, pBlock, Number ); 1140 } 1141 1142 return status; 1143 } 1144 1145 1146 NTSTATUS 1147 Ext2ExpandFile( 1148 PEXT2_IRP_CONTEXT IrpContext, 1149 PEXT2_VCB Vcb, 1150 PEXT2_MCB Mcb, 1151 PLARGE_INTEGER Size 1152 ) 1153 { 1154 NTSTATUS status = STATUS_SUCCESS; 1155 ULONG Start = 0; 1156 ULONG End = 0; 1157 1158 Start = (ULONG)((Mcb->Inode.i_size + BLOCK_SIZE - 1) >> BLOCK_BITS); 1159 End = (ULONG)((Size->QuadPart + BLOCK_SIZE - 1) >> BLOCK_BITS); 1160 1161 /* it's a truncate operation, not expanding */ 1162 if (Start >= End) { 1163 Size->QuadPart = ((LONGLONG) Start) << BLOCK_BITS; 1164 return STATUS_SUCCESS; 1165 } 1166 1167 /* ignore special files */ 1168 if (IsMcbSpecialFile(Mcb)) { 1169 return STATUS_INVALID_DEVICE_REQUEST; 1170 } 1171 1172 /* expandind file extents */ 1173 if (INODE_HAS_EXTENT(&Mcb->Inode)) { 1174 1175 status = Ext2ExpandExtent(IrpContext, Vcb, Mcb, Start, End, Size); 1176 1177 } else { 1178 1179 BOOLEAN do_expand; 1180 1181 #if EXT2_PRE_ALLOCATION_SUPPORT 1182 do_expand = TRUE; 1183 #else 1184 do_expand = (IrpContext->MajorFunction == IRP_MJ_WRITE) || 1185 IsMcbDirectory(Mcb); 1186 #endif 1187 if (!do_expand) 1188 goto errorout; 1189 1190 status = Ext2ExpandIndirect(IrpContext, Vcb, Mcb, Start, End, Size); 1191 } 1192 1193 errorout: 1194 return status; 1195 } 1196 1197 1198 NTSTATUS 1199 Ext2TruncateFile( 1200 PEXT2_IRP_CONTEXT IrpContext, 1201 PEXT2_VCB Vcb, 1202 PEXT2_MCB Mcb, 1203 PLARGE_INTEGER Size 1204 ) 1205 { 1206 NTSTATUS status = STATUS_SUCCESS; 1207 1208 if (INODE_HAS_EXTENT(&Mcb->Inode)) { 1209 status = Ext2TruncateExtent(IrpContext, Vcb, Mcb, Size); 1210 } else { 1211 status = Ext2TruncateIndirect(IrpContext, Vcb, Mcb, Size); 1212 } 1213 1214 /* check and clear data/meta mcb extents */ 1215 if (Size->QuadPart == 0) { 1216 1217 /* check and remove all data extents */ 1218 if (Ext2ListExtents(&Mcb->Extents)) { 1219 DbgBreak(); 1220 } 1221 Ext2ClearAllExtents(&Mcb->Extents); 1222 /* check and remove all meta extents */ 1223 if (Ext2ListExtents(&Mcb->MetaExts)) { 1224 DbgBreak(); 1225 } 1226 Ext2ClearAllExtents(&Mcb->MetaExts); 1227 ClearLongFlag(Mcb->Flags, MCB_ZONE_INITED); 1228 } 1229 1230 return status; 1231 } 1232 1233 NTSTATUS 1234 Ext2IsFileRemovable( 1235 IN PEXT2_IRP_CONTEXT IrpContext, 1236 IN PEXT2_VCB Vcb, 1237 IN PEXT2_FCB Fcb, 1238 IN PEXT2_CCB Ccb 1239 ) 1240 { 1241 PEXT2_MCB Mcb = Fcb->Mcb; 1242 1243 if (Mcb->Inode.i_ino == EXT2_ROOT_INO) { 1244 return STATUS_CANNOT_DELETE; 1245 } 1246 1247 if (IsMcbDirectory(Mcb)) { 1248 if (!Ext2IsDirectoryEmpty(IrpContext, Vcb, Mcb)) { 1249 return STATUS_DIRECTORY_NOT_EMPTY; 1250 } 1251 } 1252 1253 if (!MmFlushImageSection(&Fcb->SectionObject, 1254 MmFlushForDelete )) { 1255 return STATUS_CANNOT_DELETE; 1256 } 1257 1258 if (IsMcbDirectory(Mcb)) { 1259 FsRtlNotifyFullChangeDirectory( 1260 Vcb->NotifySync, 1261 &Vcb->NotifyList, 1262 Ccb, 1263 NULL, 1264 FALSE, 1265 FALSE, 1266 0, 1267 NULL, 1268 NULL, 1269 NULL 1270 ); 1271 } 1272 1273 return STATUS_SUCCESS; 1274 } 1275 1276 NTSTATUS 1277 Ext2SetDispositionInfo( 1278 PEXT2_IRP_CONTEXT IrpContext, 1279 PEXT2_VCB Vcb, 1280 PEXT2_FCB Fcb, 1281 PEXT2_CCB Ccb, 1282 BOOLEAN bDelete 1283 ) 1284 { 1285 PIRP Irp = IrpContext->Irp; 1286 PIO_STACK_LOCATION IrpSp; 1287 NTSTATUS status = STATUS_SUCCESS; 1288 PEXT2_MCB Mcb = Fcb->Mcb; 1289 1290 IrpSp = IoGetCurrentIrpStackLocation(Irp); 1291 1292 DEBUG(DL_INF, ( "Ext2SetDispositionInfo: bDelete=%x\n", bDelete)); 1293 1294 if (bDelete) { 1295 1296 DEBUG(DL_INF, ( "Ext2SetDispositionInformation: Removing %wZ.\n", 1297 &Mcb->FullName)); 1298 1299 if (Ccb->SymLink || IsInodeSymLink(&Mcb->Inode)) { 1300 /* always allow deleting on symlinks */ 1301 } else { 1302 status = Ext2IsFileRemovable(IrpContext, Vcb, Fcb, Ccb); 1303 } 1304 1305 if (NT_SUCCESS(status)) { 1306 SetLongFlag(Fcb->Flags, FCB_DELETE_PENDING); 1307 IrpSp->FileObject->DeletePending = TRUE; 1308 } 1309 1310 } else { 1311 1312 ClearLongFlag(Fcb->Flags, FCB_DELETE_PENDING); 1313 IrpSp->FileObject->DeletePending = FALSE; 1314 } 1315 1316 return status; 1317 } 1318 1319 NTSTATUS 1320 Ext2SetRenameInfo( 1321 PEXT2_IRP_CONTEXT IrpContext, 1322 PEXT2_VCB Vcb, 1323 PEXT2_FCB Fcb, 1324 PEXT2_CCB Ccb 1325 ) 1326 { 1327 PEXT2_MCB Mcb = Fcb->Mcb; 1328 1329 PEXT2_FCB TargetDcb = NULL; /* Dcb of target directory */ 1330 PEXT2_MCB TargetMcb = NULL; 1331 PEXT2_FCB ParentDcb = NULL; /* Dcb of it's current parent */ 1332 PEXT2_MCB ParentMcb = NULL; 1333 1334 PEXT2_FCB ExistingFcb = NULL; /* Target file Fcb if it exists*/ 1335 PEXT2_MCB ExistingMcb = NULL; 1336 1337 UNICODE_STRING FileName; 1338 1339 NTSTATUS Status; 1340 1341 PIRP Irp; 1342 PIO_STACK_LOCATION IrpSp; 1343 1344 PFILE_OBJECT FileObject; 1345 PFILE_OBJECT TargetObject; 1346 1347 struct dentry *NewEntry = NULL; 1348 1349 BOOLEAN ReplaceIfExists; 1350 BOOLEAN bMove = FALSE; 1351 BOOLEAN bTargetRemoved = FALSE; 1352 1353 BOOLEAN bFcbLockAcquired = FALSE; 1354 1355 PFILE_RENAME_INFORMATION FRI; 1356 1357 if (Ccb->SymLink) { 1358 Mcb = Ccb->SymLink; 1359 } 1360 1361 if (Mcb->Inode.i_ino == EXT2_ROOT_INO) { 1362 Status = STATUS_INVALID_PARAMETER; 1363 goto errorout; 1364 } 1365 1366 Irp = IrpContext->Irp; 1367 IrpSp = IoGetCurrentIrpStackLocation(Irp); 1368 1369 FileObject = IrpSp->FileObject; 1370 TargetObject = IrpSp->Parameters.SetFile.FileObject; 1371 ReplaceIfExists = IrpSp->Parameters.SetFile.ReplaceIfExists; 1372 1373 FRI = (PFILE_RENAME_INFORMATION)Irp->AssociatedIrp.SystemBuffer; 1374 1375 if (TargetObject == NULL) { 1376 1377 UNICODE_STRING NewName; 1378 1379 NewName.Buffer = FRI->FileName; 1380 NewName.MaximumLength = NewName.Length = (USHORT)FRI->FileNameLength; 1381 1382 while (NewName.Length > 0 && NewName.Buffer[NewName.Length/2 - 1] == L'\\') { 1383 NewName.Buffer[NewName.Length/2 - 1] = 0; 1384 NewName.Length -= 2; 1385 } 1386 1387 while (NewName.Length > 0 && NewName.Buffer[NewName.Length/2 - 1] != L'\\') { 1388 NewName.Length -= 2; 1389 } 1390 1391 NewName.Buffer = (USHORT *)((UCHAR *)NewName.Buffer + NewName.Length); 1392 NewName.Length = (USHORT)(FRI->FileNameLength - NewName.Length); 1393 1394 FileName = NewName; 1395 1396 TargetMcb = Mcb->Parent; 1397 if (IsMcbSymLink(TargetMcb)) { 1398 TargetMcb = TargetMcb->Target; 1399 ASSERT(!IsMcbSymLink(TargetMcb)); 1400 } 1401 1402 if (TargetMcb == NULL || FileName.Length >= EXT2_NAME_LEN*2) { 1403 Status = STATUS_OBJECT_NAME_INVALID; 1404 goto errorout; 1405 } 1406 1407 } else { 1408 1409 TargetDcb = (PEXT2_FCB)(TargetObject->FsContext); 1410 1411 if (!TargetDcb || TargetDcb->Vcb != Vcb) { 1412 1413 DbgBreak(); 1414 1415 Status = STATUS_INVALID_PARAMETER; 1416 goto errorout; 1417 } 1418 1419 TargetMcb = TargetDcb->Mcb; 1420 FileName = TargetObject->FileName; 1421 } 1422 1423 if (FsRtlDoesNameContainWildCards(&FileName)) { 1424 Status = STATUS_OBJECT_NAME_INVALID; 1425 goto errorout; 1426 } 1427 1428 if (TargetMcb->Inode.i_ino == Mcb->Parent->Inode.i_ino) { 1429 if (FsRtlAreNamesEqual( &FileName, 1430 &(Mcb->ShortName), 1431 FALSE, 1432 NULL )) { 1433 Status = STATUS_SUCCESS; 1434 goto errorout; 1435 } 1436 } else { 1437 bMove = TRUE; 1438 } 1439 1440 if (!bFcbLockAcquired) { 1441 ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE); 1442 bFcbLockAcquired = TRUE; 1443 } 1444 1445 TargetDcb = TargetMcb->Fcb; 1446 if (TargetDcb == NULL) { 1447 TargetDcb = Ext2AllocateFcb(Vcb, TargetMcb); 1448 } 1449 if (TargetDcb) { 1450 Ext2ReferXcb(&TargetDcb->ReferenceCount); 1451 } 1452 1453 ParentMcb = Mcb->Parent; 1454 ParentDcb = ParentMcb->Fcb; 1455 1456 if ((TargetMcb->Inode.i_ino != ParentMcb->Inode.i_ino)) { 1457 1458 if (ParentDcb == NULL) { 1459 ParentDcb = Ext2AllocateFcb(Vcb, ParentMcb); 1460 } 1461 } 1462 if (ParentDcb) { 1463 Ext2ReferXcb(&ParentDcb->ReferenceCount); 1464 } 1465 1466 if (bFcbLockAcquired) { 1467 ExReleaseResourceLite(&Vcb->FcbLock); 1468 bFcbLockAcquired = FALSE; 1469 } 1470 1471 if (!TargetDcb || !ParentDcb) { 1472 Status = STATUS_INSUFFICIENT_RESOURCES; 1473 goto errorout; 1474 } 1475 1476 DEBUG(DL_RES, ("Ext2SetRenameInfo: rename %wZ to %wZ\\%wZ\n", 1477 &Mcb->FullName, &TargetMcb->FullName, &FileName)); 1478 1479 Status = Ext2LookupFile( 1480 IrpContext, 1481 Vcb, 1482 &FileName, 1483 TargetMcb, 1484 &ExistingMcb, 1485 0 1486 ); 1487 1488 if (NT_SUCCESS(Status) && ExistingMcb != Mcb) { 1489 1490 if (!ReplaceIfExists) { 1491 1492 Status = STATUS_OBJECT_NAME_COLLISION; 1493 DEBUG(DL_RES, ("Ext2SetRenameInfo: Target file %wZ exists\n", 1494 &ExistingMcb->FullName)); 1495 goto errorout; 1496 1497 } else { 1498 1499 if ( (ExistingFcb = ExistingMcb->Fcb) && !IsMcbSymLink(ExistingMcb) ) { 1500 1501 Status = Ext2IsFileRemovable(IrpContext, Vcb, ExistingFcb, Ccb); 1502 if (!NT_SUCCESS(Status)) { 1503 DEBUG(DL_REN, ("Ext2SetRenameInfo: Target file %wZ cannot be removed.\n", 1504 &ExistingMcb->FullName)); 1505 goto errorout; 1506 } 1507 } 1508 1509 Status = Ext2DeleteFile(IrpContext, Vcb, ExistingFcb, ExistingMcb); 1510 if (!NT_SUCCESS(Status)) { 1511 DEBUG(DL_REN, ("Ext2SetRenameInfo: Failed to delete %wZ with status: %xh.\n", 1512 &FileName, Status)); 1513 1514 goto errorout; 1515 } 1516 1517 bTargetRemoved = TRUE; 1518 } 1519 } 1520 1521 /* remove directory entry of old name */ 1522 Status = Ext2RemoveEntry(IrpContext, Vcb, ParentDcb, Mcb); 1523 if (!NT_SUCCESS(Status)) { 1524 DEBUG(DL_REN, ("Ext2SetRenameInfo: Failed to remove entry %wZ with status %xh.\n", 1525 &Mcb->FullName, Status)); 1526 DbgBreak(); 1527 goto errorout; 1528 } 1529 1530 /* add new entry for new target name */ 1531 Status = Ext2AddEntry(IrpContext, Vcb, TargetDcb, &Mcb->Inode, &FileName, &NewEntry); 1532 if (!NT_SUCCESS(Status)) { 1533 DEBUG(DL_REN, ("Ext2SetRenameInfo: Failed to add entry for %wZ with status: %xh.\n", 1534 &FileName, Status)); 1535 Ext2AddEntry(IrpContext, Vcb, ParentDcb, &Mcb->Inode, &Mcb->ShortName, &NewEntry); 1536 goto errorout; 1537 } 1538 1539 /* correct the inode number in .. entry */ 1540 if (IsMcbDirectory(Mcb)) { 1541 Status = Ext2SetParentEntry( 1542 IrpContext, Vcb, Fcb, 1543 ParentMcb->Inode.i_ino, 1544 TargetMcb->Inode.i_ino ); 1545 if (!NT_SUCCESS(Status)) { 1546 DEBUG(DL_REN, ("Ext2SetRenameInfo: Failed to set parent refer of %wZ with %xh.\n", 1547 &Mcb->FullName, Status)); 1548 DbgBreak(); 1549 goto errorout; 1550 } 1551 } 1552 1553 /* Update current dentry from the newly created one. We need keep the original 1554 dentry to assure children's links are valid if current entry is a directory */ 1555 if (Mcb->de) { 1556 char *np = Mcb->de->d_name.name; 1557 *(Mcb->de) = *NewEntry; 1558 NewEntry->d_name.name = np; 1559 } 1560 1561 if (bTargetRemoved) { 1562 Ext2NotifyReportChange( 1563 IrpContext, 1564 Vcb, 1565 ExistingMcb, 1566 (IsMcbDirectory(ExistingMcb) ? 1567 FILE_NOTIFY_CHANGE_DIR_NAME : 1568 FILE_NOTIFY_CHANGE_FILE_NAME ), 1569 FILE_ACTION_REMOVED); 1570 } 1571 1572 if (NT_SUCCESS(Status)) { 1573 1574 if (bMove) { 1575 Ext2NotifyReportChange( 1576 IrpContext, 1577 Vcb, 1578 Mcb, 1579 (IsDirectory(Fcb) ? 1580 FILE_NOTIFY_CHANGE_DIR_NAME : 1581 FILE_NOTIFY_CHANGE_FILE_NAME ), 1582 FILE_ACTION_REMOVED); 1583 1584 } else { 1585 Ext2NotifyReportChange( 1586 IrpContext, 1587 Vcb, 1588 Mcb, 1589 (IsDirectory(Fcb) ? 1590 FILE_NOTIFY_CHANGE_DIR_NAME : 1591 FILE_NOTIFY_CHANGE_FILE_NAME ), 1592 FILE_ACTION_RENAMED_OLD_NAME); 1593 1594 } 1595 1596 if (TargetMcb->Inode.i_ino != ParentMcb->Inode.i_ino) { 1597 Ext2RemoveMcb(Vcb, Mcb); 1598 Ext2InsertMcb(Vcb, TargetMcb, Mcb); 1599 } 1600 1601 if (!Ext2BuildName( &Mcb->ShortName, 1602 &FileName, NULL )) { 1603 Status = STATUS_INSUFFICIENT_RESOURCES; 1604 goto errorout; 1605 } 1606 1607 if (!Ext2BuildName( &Mcb->FullName, 1608 &FileName, 1609 &TargetMcb->FullName)) { 1610 Status = STATUS_INSUFFICIENT_RESOURCES; 1611 goto errorout; 1612 } 1613 1614 if (bMove) { 1615 Ext2NotifyReportChange( 1616 IrpContext, 1617 Vcb, 1618 Mcb, 1619 (IsDirectory(Fcb) ? 1620 FILE_NOTIFY_CHANGE_DIR_NAME : 1621 FILE_NOTIFY_CHANGE_FILE_NAME ), 1622 FILE_ACTION_ADDED); 1623 } else { 1624 Ext2NotifyReportChange( 1625 IrpContext, 1626 Vcb, 1627 Mcb, 1628 (IsDirectory(Fcb) ? 1629 FILE_NOTIFY_CHANGE_DIR_NAME : 1630 FILE_NOTIFY_CHANGE_FILE_NAME ), 1631 FILE_ACTION_RENAMED_NEW_NAME ); 1632 } 1633 } 1634 1635 errorout: 1636 1637 if (bFcbLockAcquired) { 1638 ExReleaseResourceLite(&Vcb->FcbLock); 1639 bFcbLockAcquired = FALSE; 1640 } 1641 1642 if (NewEntry) 1643 Ext2FreeEntry(NewEntry); 1644 1645 if (TargetDcb) { 1646 Ext2ReleaseFcb(TargetDcb); 1647 } 1648 1649 if (ParentDcb) { 1650 Ext2ReleaseFcb(ParentDcb); 1651 } 1652 1653 if (ExistingMcb) 1654 Ext2DerefMcb(ExistingMcb); 1655 1656 return Status; 1657 } 1658 1659 NTSTATUS 1660 Ext2SetLinkInfo( 1661 PEXT2_IRP_CONTEXT IrpContext, 1662 PEXT2_VCB Vcb, 1663 PEXT2_FCB Fcb, 1664 PEXT2_CCB Ccb 1665 ) 1666 { 1667 PEXT2_MCB Mcb = Fcb->Mcb; 1668 1669 PEXT2_FCB TargetDcb = NULL; /* Dcb of target directory */ 1670 PEXT2_MCB TargetMcb = NULL; 1671 PEXT2_FCB ParentDcb = NULL; /* Dcb of it's current parent */ 1672 PEXT2_MCB ParentMcb = NULL; 1673 1674 PEXT2_FCB ExistingFcb = NULL; /* Target file Fcb if it exists*/ 1675 PEXT2_MCB ExistingMcb = NULL; 1676 PEXT2_MCB LinkMcb = NULL; /* Mcb for new hardlink */ 1677 1678 UNICODE_STRING FileName; 1679 1680 NTSTATUS Status; 1681 1682 PIRP Irp; 1683 PIO_STACK_LOCATION IrpSp; 1684 1685 PFILE_OBJECT FileObject; 1686 PFILE_OBJECT TargetObject; 1687 1688 BOOLEAN ReplaceIfExists; 1689 BOOLEAN bTargetRemoved = FALSE; 1690 1691 BOOLEAN bFcbLockAcquired = FALSE; 1692 1693 PFILE_LINK_INFORMATION FLI; 1694 1695 if (Ccb->SymLink) { 1696 Mcb = Ccb->SymLink; 1697 } 1698 1699 if (IsMcbDirectory(Mcb)) { 1700 Status = STATUS_INVALID_PARAMETER; 1701 goto errorout; 1702 } 1703 1704 Irp = IrpContext->Irp; 1705 IrpSp = IoGetCurrentIrpStackLocation(Irp); 1706 1707 FileObject = IrpSp->FileObject; 1708 TargetObject = IrpSp->Parameters.SetFile.FileObject; 1709 ReplaceIfExists = IrpSp->Parameters.SetFile.ReplaceIfExists; 1710 1711 FLI = (PFILE_LINK_INFORMATION)Irp->AssociatedIrp.SystemBuffer; 1712 1713 if (TargetObject == NULL) { 1714 1715 UNICODE_STRING NewName; 1716 1717 NewName.Buffer = FLI->FileName; 1718 NewName.MaximumLength = NewName.Length = (USHORT)FLI->FileNameLength; 1719 1720 while (NewName.Length > 0 && NewName.Buffer[NewName.Length/2 - 1] == L'\\') { 1721 NewName.Buffer[NewName.Length/2 - 1] = 0; 1722 NewName.Length -= 2; 1723 } 1724 1725 while (NewName.Length > 0 && NewName.Buffer[NewName.Length/2 - 1] != L'\\') { 1726 NewName.Length -= 2; 1727 } 1728 1729 NewName.Buffer = (USHORT *)((UCHAR *)NewName.Buffer + NewName.Length); 1730 NewName.Length = (USHORT)(FLI->FileNameLength - NewName.Length); 1731 1732 FileName = NewName; 1733 1734 TargetMcb = Mcb->Parent; 1735 if (IsMcbSymLink(TargetMcb)) { 1736 TargetMcb = TargetMcb->Target; 1737 ASSERT(!IsMcbSymLink(TargetMcb)); 1738 } 1739 1740 if (TargetMcb == NULL || FileName.Length >= EXT2_NAME_LEN*2) { 1741 Status = STATUS_OBJECT_NAME_INVALID; 1742 goto errorout; 1743 } 1744 1745 } else { 1746 1747 TargetDcb = (PEXT2_FCB)(TargetObject->FsContext); 1748 if (!TargetDcb || TargetDcb->Vcb != Vcb) { 1749 DbgBreak(); 1750 Status = STATUS_INVALID_PARAMETER; 1751 goto errorout; 1752 } 1753 1754 TargetMcb = TargetDcb->Mcb; 1755 FileName = TargetObject->FileName; 1756 } 1757 1758 if (FsRtlDoesNameContainWildCards(&FileName)) { 1759 Status = STATUS_OBJECT_NAME_INVALID; 1760 goto errorout; 1761 } 1762 1763 if (TargetMcb->Inode.i_ino == Mcb->Parent->Inode.i_ino) { 1764 if (FsRtlAreNamesEqual( &FileName, 1765 &(Mcb->ShortName), 1766 FALSE, 1767 NULL )) { 1768 Status = STATUS_SUCCESS; 1769 goto errorout; 1770 } 1771 } 1772 1773 ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE); 1774 bFcbLockAcquired = TRUE; 1775 1776 TargetDcb = TargetMcb->Fcb; 1777 if (TargetDcb == NULL) { 1778 TargetDcb = Ext2AllocateFcb(Vcb, TargetMcb); 1779 } 1780 if (TargetDcb) { 1781 Ext2ReferXcb(&TargetDcb->ReferenceCount); 1782 } 1783 1784 ParentMcb = Mcb->Parent; 1785 ParentDcb = ParentMcb->Fcb; 1786 1787 if ((TargetMcb->Inode.i_ino != ParentMcb->Inode.i_ino)) { 1788 1789 if (ParentDcb == NULL) { 1790 ParentDcb = Ext2AllocateFcb(Vcb, ParentMcb); 1791 } 1792 } 1793 if (ParentDcb) { 1794 Ext2ReferXcb(&ParentDcb->ReferenceCount); 1795 } 1796 1797 if (bFcbLockAcquired) { 1798 ExReleaseResourceLite(&Vcb->FcbLock); 1799 bFcbLockAcquired = FALSE; 1800 } 1801 1802 if (!TargetDcb || !ParentDcb) { 1803 Status = STATUS_INSUFFICIENT_RESOURCES; 1804 goto errorout; 1805 } 1806 1807 DEBUG(DL_RES, ("Ext2SetLinkInfo: %wZ\\%wZ -> %wZ\n", 1808 &TargetMcb->FullName, &FileName, &Mcb->FullName)); 1809 1810 Status = Ext2LookupFile(IrpContext, Vcb, &FileName, 1811 TargetMcb, &ExistingMcb, 0); 1812 if (NT_SUCCESS(Status) && ExistingMcb != Mcb) { 1813 1814 if (!ReplaceIfExists) { 1815 1816 Status = STATUS_OBJECT_NAME_COLLISION; 1817 DEBUG(DL_RES, ("Ext2SetRenameInfo: Target file %wZ exists\n", 1818 &ExistingMcb->FullName)); 1819 goto errorout; 1820 1821 } else { 1822 1823 if ( (ExistingFcb = ExistingMcb->Fcb) && !IsMcbSymLink(ExistingMcb) ) { 1824 Status = Ext2IsFileRemovable(IrpContext, Vcb, ExistingFcb, Ccb); 1825 if (!NT_SUCCESS(Status)) { 1826 DEBUG(DL_REN, ("Ext2SetRenameInfo: Target file %wZ cannot be removed.\n", 1827 &ExistingMcb->FullName)); 1828 goto errorout; 1829 } 1830 } 1831 1832 Status = Ext2DeleteFile(IrpContext, Vcb, ExistingFcb, ExistingMcb); 1833 if (!NT_SUCCESS(Status)) { 1834 DEBUG(DL_REN, ("Ext2SetRenameInfo: Failed to delete %wZ with status: %xh.\n", 1835 &FileName, Status)); 1836 1837 goto errorout; 1838 } 1839 bTargetRemoved = TRUE; 1840 } 1841 } 1842 1843 /* add new entry for new target name */ 1844 Status = Ext2AddEntry(IrpContext, Vcb, TargetDcb, &Mcb->Inode, &FileName, NULL); 1845 if (!NT_SUCCESS(Status)) { 1846 DEBUG(DL_REN, ("Ext2SetLinkInfo: Failed to add entry for %wZ with status: %xh.\n", 1847 &FileName, Status)); 1848 goto errorout; 1849 } 1850 1851 if (bTargetRemoved) { 1852 Ext2NotifyReportChange( 1853 IrpContext, 1854 Vcb, 1855 ExistingMcb, 1856 (IsMcbDirectory(ExistingMcb) ? 1857 FILE_NOTIFY_CHANGE_DIR_NAME : 1858 FILE_NOTIFY_CHANGE_FILE_NAME ), 1859 FILE_ACTION_REMOVED); 1860 } 1861 1862 if (NT_SUCCESS(Status)) { 1863 1864 Ext2LookupFile(IrpContext, Vcb, &FileName, TargetMcb, &LinkMcb, 0); 1865 if (!LinkMcb) 1866 goto errorout; 1867 1868 Ext2NotifyReportChange( 1869 IrpContext, 1870 Vcb, 1871 LinkMcb, 1872 FILE_NOTIFY_CHANGE_FILE_NAME, 1873 FILE_ACTION_ADDED); 1874 } 1875 1876 errorout: 1877 1878 if (bFcbLockAcquired) { 1879 ExReleaseResourceLite(&Vcb->FcbLock); 1880 bFcbLockAcquired = FALSE; 1881 } 1882 1883 if (TargetDcb) { 1884 Ext2ReleaseFcb(TargetDcb); 1885 } 1886 1887 if (ParentDcb) { 1888 Ext2ReleaseFcb(ParentDcb); 1889 } 1890 1891 if (ExistingMcb) 1892 Ext2DerefMcb(ExistingMcb); 1893 1894 if (LinkMcb) 1895 Ext2DerefMcb(LinkMcb); 1896 1897 return Status; 1898 } 1899 1900 ULONG 1901 Ext2InodeType(PEXT2_MCB Mcb) 1902 { 1903 if (IsMcbSymLink(Mcb)) { 1904 return EXT2_FT_SYMLINK; 1905 } 1906 1907 if (IsMcbDirectory(Mcb)) { 1908 return EXT2_FT_DIR; 1909 } 1910 1911 return EXT2_FT_REG_FILE; 1912 } 1913 1914 NTSTATUS 1915 Ext2DeleteFile( 1916 PEXT2_IRP_CONTEXT IrpContext, 1917 PEXT2_VCB Vcb, 1918 PEXT2_FCB Fcb, 1919 PEXT2_MCB Mcb 1920 ) 1921 { 1922 PEXT2_FCB Dcb = NULL; 1923 1924 NTSTATUS Status = STATUS_UNSUCCESSFUL; 1925 1926 BOOLEAN VcbResourceAcquired = FALSE; 1927 BOOLEAN FcbPagingIoAcquired = FALSE; 1928 BOOLEAN FcbResourceAcquired = FALSE; 1929 BOOLEAN DcbResourceAcquired = FALSE; 1930 1931 LARGE_INTEGER Size; 1932 LARGE_INTEGER SysTime; 1933 1934 BOOLEAN bFcbLockAcquired = FALSE; 1935 1936 DEBUG(DL_INF, ( "Ext2DeleteFile: File %wZ (%xh) will be deleted!\n", 1937 &Mcb->FullName, Mcb->Inode.i_ino)); 1938 1939 if (IsFlagOn(Mcb->Flags, MCB_FILE_DELETED)) { 1940 return STATUS_SUCCESS; 1941 } 1942 1943 if (!IsMcbSymLink(Mcb) && IsMcbDirectory(Mcb)) { 1944 if (!Ext2IsDirectoryEmpty(IrpContext, Vcb, Mcb)) { 1945 return STATUS_DIRECTORY_NOT_EMPTY; 1946 } 1947 } 1948 1949 _SEH2_TRY { 1950 1951 Ext2ReferMcb(Mcb); 1952 1953 ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE); 1954 VcbResourceAcquired = TRUE; 1955 1956 ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE); 1957 bFcbLockAcquired = TRUE; 1958 1959 /* Mcb->Parent could be NULL when working with layered file systems */ 1960 if (Mcb->Parent) { 1961 Dcb = Mcb->Parent->Fcb; 1962 if (!Dcb) 1963 Dcb = Ext2AllocateFcb(Vcb, Mcb->Parent); 1964 } 1965 if (Dcb) 1966 Ext2ReferXcb(&Dcb->ReferenceCount); 1967 1968 if (bFcbLockAcquired) { 1969 ExReleaseResourceLite(&Vcb->FcbLock); 1970 bFcbLockAcquired = FALSE; 1971 } 1972 1973 if (Dcb) { 1974 DcbResourceAcquired = 1975 ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE); 1976 1977 /* remove it's entry form it's parent */ 1978 Status = Ext2RemoveEntry(IrpContext, Vcb, Dcb, Mcb); 1979 } 1980 1981 if (NT_SUCCESS(Status)) { 1982 1983 SetFlag(Mcb->Flags, MCB_FILE_DELETED); 1984 Ext2RemoveMcb(Vcb, Mcb); 1985 1986 if (Fcb) { 1987 FcbResourceAcquired = 1988 ExAcquireResourceExclusiveLite(&Fcb->MainResource, TRUE); 1989 1990 FcbPagingIoAcquired = 1991 ExAcquireResourceExclusiveLite(&Fcb->PagingIoResource, TRUE); 1992 } 1993 1994 if (DcbResourceAcquired) { 1995 ExReleaseResourceLite(&Dcb->MainResource); 1996 DcbResourceAcquired = FALSE; 1997 } 1998 1999 if (VcbResourceAcquired) { 2000 ExReleaseResourceLite(&Vcb->MainResource); 2001 VcbResourceAcquired = FALSE; 2002 } 2003 2004 if (IsMcbSymLink(Mcb)) { 2005 if (Mcb->Inode.i_nlink > 0) { 2006 Status = STATUS_CANNOT_DELETE; 2007 _SEH2_LEAVE; 2008 } 2009 } else if (!IsMcbDirectory(Mcb)) { 2010 if (Mcb->Inode.i_nlink > 0) { 2011 _SEH2_LEAVE; 2012 } 2013 } else { 2014 if (Mcb->Inode.i_nlink >= 2) { 2015 _SEH2_LEAVE; 2016 } 2017 } 2018 2019 if (S_ISLNK(Mcb->Inode.i_mode)) { 2020 2021 /* for symlink, we should do differenctly */ 2022 if (Mcb->Inode.i_size > EXT2_LINKLEN_IN_INODE) { 2023 Size.QuadPart = (LONGLONG)0; 2024 Status = Ext2TruncateFile(IrpContext, Vcb, Mcb, &Size); 2025 } 2026 2027 } else { 2028 2029 /* truncate file size */ 2030 Size.QuadPart = (LONGLONG)0; 2031 Status = Ext2TruncateFile(IrpContext, Vcb, Mcb, &Size); 2032 2033 /* check file offset mappings */ 2034 DEBUG(DL_EXT, ("Ext2DeleteFile ...: %wZ\n", &Mcb->FullName)); 2035 2036 if (Fcb) { 2037 Fcb->Header.AllocationSize.QuadPart = Size.QuadPart; 2038 if (Fcb->Header.FileSize.QuadPart > Size.QuadPart) { 2039 Fcb->Header.FileSize.QuadPart = Size.QuadPart; 2040 Fcb->Mcb->Inode.i_size = Size.QuadPart; 2041 } 2042 if (Fcb->Header.ValidDataLength.QuadPart > Fcb->Header.FileSize.QuadPart) { 2043 Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart; 2044 } 2045 } else if (Mcb) { 2046 /* Update the inode's data length . It should be ZERO if succeeds. */ 2047 if (Mcb->Inode.i_size > (loff_t)Size.QuadPart) { 2048 Mcb->Inode.i_size = Size.QuadPart; 2049 } 2050 } 2051 } 2052 2053 /* set delete time and free the inode */ 2054 KeQuerySystemTime(&SysTime); 2055 Mcb->Inode.i_nlink = 0; 2056 Mcb->Inode.i_dtime = Ext2LinuxTime(SysTime); 2057 Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode); 2058 Ext2FreeInode(IrpContext, Vcb, Mcb->Inode.i_ino, Ext2InodeType(Mcb)); 2059 } 2060 2061 } _SEH2_FINALLY { 2062 2063 if (FcbPagingIoAcquired) { 2064 ExReleaseResourceLite(&Fcb->PagingIoResource); 2065 } 2066 2067 if (FcbResourceAcquired) { 2068 ExReleaseResourceLite(&Fcb->MainResource); 2069 } 2070 2071 if (DcbResourceAcquired) { 2072 ExReleaseResourceLite(&Dcb->MainResource); 2073 } 2074 2075 if (bFcbLockAcquired) { 2076 ExReleaseResourceLite(&Vcb->FcbLock); 2077 } 2078 2079 if (VcbResourceAcquired) { 2080 ExReleaseResourceLite(&Vcb->MainResource); 2081 } 2082 2083 if (Dcb) { 2084 Ext2ReleaseFcb(Dcb); 2085 } 2086 2087 Ext2DerefMcb(Mcb); 2088 } _SEH2_END; 2089 2090 DEBUG(DL_INF, ( "Ext2DeleteFile: %wZ Succeed... EXT2SB->S_FREE_BLOCKS = %I64xh .\n", 2091 &Mcb->FullName, ext3_free_blocks_count(SUPER_BLOCK))); 2092 2093 return Status; 2094 } 2095