1 /* 2 * COPYRIGHT: See COPYRIGHT.TXT 3 * PROJECT: Ext2 File System Driver for WinNT/2K/XP 4 * FILE: create.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_xattr.h> 14 15 /* GLOBALS *****************************************************************/ 16 17 extern PEXT2_GLOBAL Ext2Global; 18 19 /* DEFINITIONS *************************************************************/ 20 21 #ifdef ALLOC_PRAGMA 22 #pragma alloc_text(PAGE, Ext2IsNameValid) 23 #pragma alloc_text(PAGE, Ext2FollowLink) 24 #pragma alloc_text(PAGE, Ext2IsSpecialSystemFile) 25 #pragma alloc_text(PAGE, Ext2LookupFile) 26 #pragma alloc_text(PAGE, Ext2ScanDir) 27 #pragma alloc_text(PAGE, Ext2CreateFile) 28 #pragma alloc_text(PAGE, Ext2CreateVolume) 29 #pragma alloc_text(PAGE, Ext2Create) 30 #pragma alloc_text(PAGE, Ext2CreateInode) 31 #pragma alloc_text(PAGE, Ext2SupersedeOrOverWriteFile) 32 #endif 33 34 35 BOOLEAN 36 Ext2IsNameValid(PUNICODE_STRING FileName) 37 { 38 USHORT i = 0; 39 PUSHORT pName = (PUSHORT) FileName->Buffer; 40 41 if (FileName == NULL) { 42 return FALSE; 43 } 44 45 while (i < (FileName->Length / sizeof(WCHAR))) { 46 47 if (pName[i] == 0) { 48 break; 49 } 50 51 if (pName[i] == L'|' || pName[i] == L':' || 52 pName[i] == L'/' || pName[i] == L'*' || 53 pName[i] == L'?' || pName[i] == L'\"' || 54 pName[i] == L'<' || pName[i] == L'>' ) { 55 56 return FALSE; 57 } 58 59 i++; 60 } 61 62 return TRUE; 63 } 64 65 66 NTSTATUS 67 Ext2FollowLink ( 68 IN PEXT2_IRP_CONTEXT IrpContext, 69 IN PEXT2_VCB Vcb, 70 IN PEXT2_MCB Parent, 71 IN PEXT2_MCB Mcb, 72 IN ULONG Linkdep 73 ) 74 { 75 NTSTATUS Status = STATUS_LINK_FAILED; 76 77 UNICODE_STRING UniName; 78 OEM_STRING OemName; 79 BOOLEAN bOemBuffer = FALSE; 80 81 PEXT2_MCB Target = NULL; 82 83 USHORT i; 84 85 _SEH2_TRY { 86 87 RtlZeroMemory(&UniName, sizeof(UNICODE_STRING)); 88 RtlZeroMemory(&OemName, sizeof(OEM_STRING)); 89 90 /* exit if we jump into a possible symlink forever loop */ 91 if ((Linkdep + 1) > EXT2_MAX_NESTED_LINKS || 92 IoGetRemainingStackSize() < 1024) { 93 _SEH2_LEAVE; 94 } 95 96 /* read the symlink target path */ 97 if (!Mcb->Inode.i_blocks) { 98 99 OemName.Buffer = (PUCHAR) (&Mcb->Inode.i_block[0]); 100 OemName.Length = (USHORT)Mcb->Inode.i_size; 101 OemName.MaximumLength = OemName.Length + 1; 102 103 } else { 104 105 OemName.Length = (USHORT)Mcb->Inode.i_size; 106 OemName.MaximumLength = OemName.Length + 1; 107 OemName.Buffer = Ext2AllocatePool(PagedPool, 108 OemName.MaximumLength, 109 'NL2E'); 110 if (OemName.Buffer == NULL) { 111 Status = STATUS_INSUFFICIENT_RESOURCES; 112 _SEH2_LEAVE; 113 } 114 bOemBuffer = TRUE; 115 RtlZeroMemory(OemName.Buffer, OemName.MaximumLength); 116 117 Status = Ext2ReadSymlink( 118 IrpContext, 119 Vcb, 120 Mcb, 121 OemName.Buffer, 122 (ULONG)(Mcb->Inode.i_size), 123 NULL); 124 if (!NT_SUCCESS(Status)) { 125 _SEH2_LEAVE; 126 } 127 } 128 129 /* convert Linux slash to Windows backslash */ 130 for (i=0; i < OemName.Length; i++) { 131 if (OemName.Buffer[i] == '/') { 132 OemName.Buffer[i] = '\\'; 133 } 134 } 135 136 /* convert oem string to unicode string */ 137 UniName.MaximumLength = (USHORT)Ext2OEMToUnicodeSize(Vcb, &OemName); 138 if (UniName.MaximumLength <= 0) { 139 Status = STATUS_INSUFFICIENT_RESOURCES; 140 _SEH2_LEAVE; 141 } 142 143 UniName.MaximumLength += 2; 144 UniName.Buffer = Ext2AllocatePool(PagedPool, 145 UniName.MaximumLength, 146 'NL2E'); 147 if (UniName.Buffer == NULL) { 148 Status = STATUS_INSUFFICIENT_RESOURCES; 149 _SEH2_LEAVE; 150 } 151 RtlZeroMemory(UniName.Buffer, UniName.MaximumLength); 152 Status = Ext2OEMToUnicode(Vcb, &UniName, &OemName); 153 if (!NT_SUCCESS(Status)) { 154 Status = STATUS_INSUFFICIENT_RESOURCES; 155 _SEH2_LEAVE; 156 } 157 158 /* search the real target */ 159 Status = Ext2LookupFile( 160 IrpContext, 161 Vcb, 162 &UniName, 163 Parent, 164 &Target, 165 Linkdep 166 ); 167 if (Target == NULL) { 168 Status = STATUS_LINK_FAILED; 169 } 170 171 if (Target == NULL /* link target doesn't exist */ || 172 Target == Mcb /* symlink points to itself */ || 173 IsMcbSpecialFile(Target) /* target not resolved*/ || 174 IsFileDeleted(Target) /* target deleted */ ) { 175 176 if (Target) { 177 ASSERT(Target->Refercount > 0); 178 Ext2DerefMcb(Target); 179 } 180 ClearLongFlag(Mcb->Flags, MCB_TYPE_SYMLINK); 181 SetLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL); 182 Mcb->Target = NULL; 183 184 } else if (IsMcbSymLink(Target)) { 185 186 ASSERT(Target->Refercount > 0); 187 ASSERT(Target->Target != NULL); 188 Ext2ReferMcb(Target->Target); 189 Mcb->Target = Target->Target; 190 Ext2DerefMcb(Target); 191 ASSERT(!IsMcbSymLink(Target->Target)); 192 SetLongFlag(Mcb->Flags, MCB_TYPE_SYMLINK); 193 ClearLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL); 194 ASSERT(Mcb->Target->Refercount > 0); 195 196 } else { 197 198 Mcb->Target = Target; 199 SetLongFlag(Mcb->Flags, MCB_TYPE_SYMLINK); 200 ClearLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL); 201 ASSERT(Mcb->Target->Refercount > 0); 202 } 203 204 /* add directory flag to file attribute */ 205 if (Mcb->Target && IsMcbDirectory(Mcb->Target)) { 206 Mcb->FileAttr |= FILE_ATTRIBUTE_DIRECTORY; 207 } 208 209 } _SEH2_FINALLY { 210 211 if (bOemBuffer) { 212 Ext2FreePool(OemName.Buffer, 'NL2E'); 213 } 214 215 if (UniName.Buffer) { 216 Ext2FreePool(UniName.Buffer, 'NL2E'); 217 } 218 } _SEH2_END; 219 220 return Status; 221 } 222 223 BOOLEAN 224 Ext2IsSpecialSystemFile( 225 IN PUNICODE_STRING FileName, 226 IN BOOLEAN bDirectory 227 ) 228 { 229 PWSTR SpecialFileList[] = { 230 L"pagefile.sys", 231 L"swapfile.sys", 232 L"hiberfil.sys", 233 NULL 234 }; 235 236 PWSTR SpecialDirList[] = { 237 L"Recycled", 238 L"RECYCLER", 239 L"$RECYCLE.BIN", 240 NULL 241 }; 242 243 PWSTR entryName; 244 ULONG length; 245 int i; 246 247 for (i = 0; TRUE; i++) { 248 249 if (bDirectory) { 250 entryName = SpecialDirList[i]; 251 } else { 252 entryName = SpecialFileList[i]; 253 } 254 255 if (NULL == entryName) { 256 break; 257 } 258 259 length = wcslen(entryName) * sizeof(WCHAR); 260 if (FileName->Length == length) { 261 if ( 0 == _wcsnicmp( entryName, 262 FileName->Buffer, 263 length / sizeof(WCHAR) )) { 264 return TRUE; 265 } 266 } 267 } 268 269 return FALSE; 270 } 271 272 NTSTATUS 273 Ext2LookupFile ( 274 IN PEXT2_IRP_CONTEXT IrpContext, 275 IN PEXT2_VCB Vcb, 276 IN PUNICODE_STRING FullName, 277 IN PEXT2_MCB Parent, 278 OUT PEXT2_MCB * Ext2Mcb, 279 IN ULONG Linkdep 280 ) 281 { 282 NTSTATUS Status = STATUS_OBJECT_NAME_NOT_FOUND; 283 UNICODE_STRING FileName; 284 PEXT2_MCB Mcb = NULL; 285 struct dentry *de = NULL; 286 287 USHORT i = 0, End; 288 ULONG Inode; 289 290 BOOLEAN bParent = FALSE; 291 BOOLEAN bDirectory = FALSE; 292 BOOLEAN LockAcquired = FALSE; 293 BOOLEAN bNotFollow = FALSE; 294 295 _SEH2_TRY { 296 297 ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE); 298 LockAcquired = TRUE; 299 300 bNotFollow = IsFlagOn(Linkdep, EXT2_LOOKUP_NOT_FOLLOW); 301 #ifndef __REACTOS__ 302 Linkdep = ClearFlag(Linkdep, EXT2_LOOKUP_FLAG_MASK); 303 #else 304 ClearFlag(Linkdep, EXT2_LOOKUP_FLAG_MASK); 305 #endif 306 307 *Ext2Mcb = NULL; 308 309 DEBUG(DL_RES, ("Ext2LookupFile: %wZ\n", FullName)); 310 311 /* check names and parameters */ 312 if (FullName->Buffer[0] == L'\\') { 313 Parent = Vcb->McbTree; 314 } else if (Parent) { 315 bParent = TRUE; 316 } else { 317 Parent = Vcb->McbTree; 318 } 319 320 /* make sure the parent is NULL */ 321 if (!IsMcbDirectory(Parent)) { 322 Status = STATUS_NOT_A_DIRECTORY; 323 _SEH2_LEAVE; 324 } 325 326 /* use symlink's target as parent directory */ 327 if (IsMcbSymLink(Parent)) { 328 Parent = Parent->Target; 329 ASSERT(!IsMcbSymLink(Parent)); 330 if (IsFileDeleted(Parent)) { 331 Status = STATUS_NOT_A_DIRECTORY; 332 _SEH2_LEAVE; 333 } 334 } 335 336 if (NULL == Parent) { 337 Status = STATUS_NOT_A_DIRECTORY; 338 _SEH2_LEAVE; 339 } 340 341 /* default is the parent Mcb*/ 342 Ext2ReferMcb(Parent); 343 Mcb = Parent; 344 345 /* is empty file name or root node */ 346 End = FullName->Length/sizeof(WCHAR); 347 if ( (End == 0) || (End == 1 && 348 FullName->Buffer[0] == L'\\')) { 349 Status = STATUS_SUCCESS; 350 _SEH2_LEAVE; 351 } 352 353 /* is a directory expected ? */ 354 while (FullName->Buffer[End - 1] == L'\\') { 355 bDirectory = TRUE; 356 End -= 1; 357 } 358 359 /* loop with every sub name */ 360 while (i < End) { 361 362 USHORT Start = 0; 363 364 /* zero the prefix '\' */ 365 while (i < End && FullName->Buffer[i] == L'\\') i++; 366 Start = i; 367 368 /* zero the suffix '\' */ 369 while (i < End && (FullName->Buffer[i] != L'\\')) i++; 370 371 if (i > Start) { 372 373 FileName = *FullName; 374 FileName.Buffer += Start; 375 FileName.Length = (USHORT)((i - Start) * 2); 376 377 /* make sure the parent is NULL */ 378 if (!IsMcbDirectory(Parent)) { 379 Status = STATUS_NOT_A_DIRECTORY; 380 Ext2DerefMcb(Parent); 381 break; 382 } 383 384 if (IsMcbSymLink(Parent)) { 385 if (IsFileDeleted(Parent->Target)) { 386 Status = STATUS_NOT_A_DIRECTORY; 387 Ext2DerefMcb(Parent); 388 break; 389 } else { 390 Ext2ReferMcb(Parent->Target); 391 Ext2DerefMcb(Parent); 392 Parent = Parent->Target; 393 } 394 } 395 396 /* search cached Mcb nodes */ 397 Mcb = Ext2SearchMcbWithoutLock(Parent, &FileName); 398 399 if (Mcb) { 400 401 /* derefer the parent Mcb */ 402 Ext2DerefMcb(Parent); 403 Status = STATUS_SUCCESS; 404 Parent = Mcb; 405 406 if (IsMcbSymLink(Mcb) && IsFileDeleted(Mcb->Target) && 407 Mcb->Refercount == 1) { 408 409 ASSERT(Mcb->Target); 410 ASSERT(Mcb->Target->Refercount > 0); 411 Ext2DerefMcb(Mcb->Target); 412 Mcb->Target = NULL; 413 ClearLongFlag(Mcb->Flags, MCB_TYPE_SYMLINK); 414 SetLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL); 415 Mcb->FileAttr = FILE_ATTRIBUTE_NORMAL; 416 } 417 418 } else { 419 420 /* need create new Mcb node */ 421 422 /* is a valid ext2 name */ 423 if (!Ext2IsNameValid(&FileName)) { 424 Status = STATUS_OBJECT_NAME_INVALID; 425 Ext2DerefMcb(Parent); 426 break; 427 } 428 429 /* seach the disk */ 430 de = NULL; 431 Status = Ext2ScanDir ( 432 IrpContext, 433 Vcb, 434 Parent, 435 &FileName, 436 &Inode, 437 &de); 438 439 if (NT_SUCCESS(Status)) { 440 441 /* check it's real parent */ 442 ASSERT (!IsMcbSymLink(Parent)); 443 444 /* allocate Mcb ... */ 445 Mcb = Ext2AllocateMcb(Vcb, &FileName, &Parent->FullName, 0); 446 if (!Mcb) { 447 Status = STATUS_INSUFFICIENT_RESOURCES; 448 Ext2DerefMcb(Parent); 449 break; 450 } 451 Mcb->de = de; 452 Mcb->de->d_inode = &Mcb->Inode; 453 Mcb->Inode.i_ino = Inode; 454 Mcb->Inode.i_sb = &Vcb->sb; 455 de = NULL; 456 457 /* load inode information */ 458 if (!Ext2LoadInode(Vcb, &Mcb->Inode)) { 459 Status = STATUS_CANT_WAIT; 460 Ext2DerefMcb(Parent); 461 Ext2FreeMcb(Vcb, Mcb); 462 break; 463 } 464 465 /* set inode attribute */ 466 if (!Ext2CheckFileAccess(Vcb, Mcb, Ext2FileCanWrite)) { 467 SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_READONLY); 468 } 469 470 if (S_ISDIR(Mcb->Inode.i_mode)) { 471 SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY); 472 } else { 473 if (S_ISREG(Mcb->Inode.i_mode)) { 474 SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_NORMAL); 475 } else if (S_ISLNK(Mcb->Inode.i_mode)) { 476 SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_REPARSE_POINT); 477 } else { 478 SetLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL); 479 } 480 } 481 482 /* process special files under root directory */ 483 if (IsMcbRoot(Parent)) { 484 /* set hidden and system attributes for 485 Recycled / RECYCLER / pagefile.sys */ 486 BOOLEAN IsDirectory = IsMcbDirectory(Mcb); 487 if (Ext2IsSpecialSystemFile(&Mcb->ShortName, IsDirectory)) { 488 SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_HIDDEN); 489 SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_SYSTEM); 490 } 491 } 492 493 Mcb->CreationTime = Ext2NtTime(Mcb->Inode.i_ctime); 494 Mcb->LastAccessTime = Ext2NtTime(Mcb->Inode.i_atime); 495 Mcb->LastWriteTime = Ext2NtTime(Mcb->Inode.i_mtime); 496 Mcb->ChangeTime = Ext2NtTime(Mcb->Inode.i_mtime); 497 498 /* process symlink */ 499 if (S_ISLNK(Mcb->Inode.i_mode) && !bNotFollow) { 500 Ext2FollowLink( IrpContext, 501 Vcb, 502 Parent, 503 Mcb, 504 Linkdep+1 505 ); 506 } 507 508 /* add reference ... */ 509 Ext2ReferMcb(Mcb); 510 511 /* add Mcb to it's parent tree*/ 512 Ext2InsertMcb(Vcb, Parent, Mcb); 513 514 /* it's safe to deref Parent Mcb */ 515 Ext2DerefMcb(Parent); 516 517 /* linking this Mcb*/ 518 Ext2LinkTailMcb(Vcb, Mcb); 519 520 /* set parent to preare re-scan */ 521 Parent = Mcb; 522 523 } else { 524 525 /* derefernce it's parent */ 526 Ext2DerefMcb(Parent); 527 break; 528 } 529 } 530 531 } else { 532 533 /* there seems too many \ or / */ 534 /* Mcb should be already set to Parent */ 535 ASSERT(Mcb == Parent); 536 Status = STATUS_SUCCESS; 537 break; 538 } 539 } 540 541 } _SEH2_FINALLY { 542 543 if (de) { 544 Ext2FreeEntry(de); 545 } 546 547 if (NT_SUCCESS(Status)) { 548 if (bDirectory) { 549 if (IsMcbDirectory(Mcb)) { 550 *Ext2Mcb = Mcb; 551 } else { 552 Ext2DerefMcb(Mcb); 553 Status = STATUS_NOT_A_DIRECTORY; 554 } 555 } else { 556 *Ext2Mcb = Mcb; 557 } 558 } 559 560 if (LockAcquired) { 561 ExReleaseResourceLite(&Vcb->McbLock); 562 } 563 } _SEH2_END; 564 565 return Status; 566 } 567 568 569 NTSTATUS 570 Ext2ScanDir ( 571 IN PEXT2_IRP_CONTEXT IrpContext, 572 IN PEXT2_VCB Vcb, 573 IN PEXT2_MCB Parent, 574 IN PUNICODE_STRING FileName, 575 OUT PULONG Inode, 576 OUT struct dentry **dentry 577 ) 578 { 579 struct ext3_dir_entry_2 *dir_entry = NULL; 580 struct buffer_head *bh = NULL; 581 struct dentry *de = NULL; 582 583 NTSTATUS Status = STATUS_NO_SUCH_FILE; 584 585 DEBUG(DL_RES, ("Ext2ScanDir: %wZ\\%wZ\n", &Parent->FullName, FileName)); 586 587 _SEH2_TRY { 588 589 /* grab parent's reference first */ 590 Ext2ReferMcb(Parent); 591 592 /* bad request ! Can a man be pregnant ? Maybe:) */ 593 if (!IsMcbDirectory(Parent)) { 594 Status = STATUS_NOT_A_DIRECTORY; 595 _SEH2_LEAVE; 596 } 597 598 /* parent is a symlink ? */ 599 if IsMcbSymLink(Parent) { 600 if (Parent->Target) { 601 Ext2ReferMcb(Parent->Target); 602 Ext2DerefMcb(Parent); 603 Parent = Parent->Target; 604 ASSERT(!IsMcbSymLink(Parent)); 605 } else { 606 DbgBreak(); 607 Status = STATUS_NOT_A_DIRECTORY; 608 _SEH2_LEAVE; 609 } 610 } 611 612 de = Ext2BuildEntry(Vcb, Parent, FileName); 613 if (!de) { 614 DEBUG(DL_ERR, ( "Ex2ScanDir: failed to allocate dentry.\n")); 615 Status = STATUS_INSUFFICIENT_RESOURCES; 616 _SEH2_LEAVE; 617 } 618 619 bh = ext3_find_entry(IrpContext, de, &dir_entry); 620 if (dir_entry) { 621 Status = STATUS_SUCCESS; 622 *Inode = dir_entry->inode; 623 *dentry = de; 624 } 625 626 } _SEH2_FINALLY { 627 628 Ext2DerefMcb(Parent); 629 630 if (bh) 631 __brelse(bh); 632 633 if (!NT_SUCCESS(Status)) { 634 if (de) 635 Ext2FreeEntry(de); 636 } 637 } _SEH2_END; 638 639 return Status; 640 } 641 642 NTSTATUS Ext2AddDotEntries(struct ext2_icb *icb, struct inode *dir, 643 struct inode *inode) 644 { 645 struct ext3_dir_entry_2 * de; 646 struct buffer_head * bh; 647 ext3_lblk_t block = 0; 648 int rc = 0; 649 650 bh = ext3_append(icb, inode, &block, &rc); 651 if (!bh) { 652 goto errorout; 653 } 654 655 de = (struct ext3_dir_entry_2 *) bh->b_data; 656 de->inode = cpu_to_le32(inode->i_ino); 657 de->name_len = 1; 658 de->rec_len = cpu_to_le16(EXT3_DIR_REC_LEN(de->name_len)); 659 strcpy (de->name, "."); 660 ext3_set_de_type(inode->i_sb, de, S_IFDIR); 661 de = (struct ext3_dir_entry_2 *) 662 ((char *) de + le16_to_cpu(de->rec_len)); 663 de->inode = cpu_to_le32(dir->i_ino); 664 de->rec_len = cpu_to_le16(inode->i_sb->s_blocksize-EXT3_DIR_REC_LEN(1)); 665 de->name_len = 2; 666 strcpy (de->name, ".."); 667 ext3_set_de_type(inode->i_sb, de, S_IFDIR); 668 inode->i_nlink = 2; 669 set_buffer_dirty(bh); 670 ext3_mark_inode_dirty(icb, inode); 671 672 errorout: 673 if (bh) 674 __brelse (bh); 675 676 return Ext2WinntError(rc); 677 } 678 679 // 680 // Any call to this routine must have Fcb's MainResource and FcbLock acquired. 681 // 682 683 NTSTATUS 684 Ext2OverwriteEa( 685 PEXT2_IRP_CONTEXT IrpContext, 686 PEXT2_VCB Vcb, 687 PEXT2_FCB Fcb, 688 PIO_STATUS_BLOCK Iosb 689 ) 690 { 691 PEXT2_MCB Mcb = NULL; 692 PIRP Irp; 693 PIO_STACK_LOCATION IrpSp; 694 695 struct ext4_xattr_ref xattr_ref; 696 BOOLEAN XattrRefAcquired = FALSE; 697 NTSTATUS Status = STATUS_UNSUCCESSFUL; 698 699 PFILE_FULL_EA_INFORMATION FullEa; 700 PCHAR EaBuffer; 701 ULONG EaBufferLength; 702 703 _SEH2_TRY { 704 705 Irp = IrpContext->Irp; 706 IrpSp = IoGetCurrentIrpStackLocation(Irp); 707 Mcb = Fcb->Mcb; 708 709 EaBuffer = Irp->AssociatedIrp.SystemBuffer; 710 EaBufferLength = IrpSp->Parameters.Create.EaLength; 711 712 if (!Mcb) 713 _SEH2_LEAVE; 714 715 // 716 // Return peacefully if there is no EaBuffer provided. 717 // 718 if (!EaBuffer) { 719 Status = STATUS_SUCCESS; 720 _SEH2_LEAVE; 721 } 722 723 // 724 // If the caller specifies an EaBuffer, but has no knowledge about Ea, 725 // we reject the request. 726 // 727 if (EaBuffer != NULL && 728 FlagOn(IrpSp->Parameters.Create.Options, FILE_NO_EA_KNOWLEDGE)) { 729 Status = STATUS_ACCESS_DENIED; 730 _SEH2_LEAVE; 731 } 732 733 // 734 // Check Ea Buffer validity. 735 // 736 Status = IoCheckEaBufferValidity((PFILE_FULL_EA_INFORMATION)EaBuffer, 737 EaBufferLength, (PULONG)&Iosb->Information); 738 if (!NT_SUCCESS(Status)) 739 _SEH2_LEAVE; 740 741 Status = Ext2WinntError(ext4_fs_get_xattr_ref(IrpContext, Vcb, Fcb->Mcb, &xattr_ref)); 742 if (!NT_SUCCESS(Status)) { 743 DbgPrint("ext4_fs_get_xattr_ref() failed!\n"); 744 _SEH2_LEAVE; 745 } 746 747 XattrRefAcquired = TRUE; 748 749 // 750 // Remove all existing EA entries. 751 // 752 ext4_xattr_purge_items(&xattr_ref); 753 xattr_ref.dirty = TRUE; 754 Status = STATUS_SUCCESS; 755 756 // Iterate the whole EA buffer to do inspection 757 for (FullEa = (PFILE_FULL_EA_INFORMATION)EaBuffer; 758 FullEa < (PFILE_FULL_EA_INFORMATION)&EaBuffer[EaBufferLength]; 759 FullEa = (PFILE_FULL_EA_INFORMATION)(FullEa->NextEntryOffset == 0 ? 760 &EaBuffer[EaBufferLength] : 761 (PCHAR)FullEa + FullEa->NextEntryOffset)) { 762 763 OEM_STRING EaName; 764 765 EaName.MaximumLength = EaName.Length = FullEa->EaNameLength; 766 EaName.Buffer = &FullEa->EaName[0]; 767 768 // Check if EA's name is valid 769 if (!Ext2IsEaNameValid(EaName)) { 770 Status = STATUS_INVALID_EA_NAME; 771 _SEH2_LEAVE; 772 } 773 } 774 775 // Now add EA entries to the inode 776 for (FullEa = (PFILE_FULL_EA_INFORMATION)EaBuffer; 777 FullEa < (PFILE_FULL_EA_INFORMATION)&EaBuffer[EaBufferLength]; 778 FullEa = (PFILE_FULL_EA_INFORMATION)(FullEa->NextEntryOffset == 0 ? 779 &EaBuffer[EaBufferLength] : 780 (PCHAR)FullEa + FullEa->NextEntryOffset)) { 781 782 int ret; 783 OEM_STRING EaName; 784 785 EaName.MaximumLength = EaName.Length = FullEa->EaNameLength; 786 EaName.Buffer = &FullEa->EaName[0]; 787 788 Status = Ext2WinntError(ret = 789 ext4_fs_set_xattr(&xattr_ref, 790 EXT4_XATTR_INDEX_USER, 791 EaName.Buffer, 792 EaName.Length, 793 &FullEa->EaName[0] + FullEa->EaNameLength + 1, 794 FullEa->EaValueLength, 795 TRUE)); 796 if (!NT_SUCCESS(Status) && ret != -ENODATA) 797 _SEH2_LEAVE; 798 799 if (ret == -ENODATA) { 800 Status = Ext2WinntError( 801 ext4_fs_set_xattr(&xattr_ref, 802 EXT4_XATTR_INDEX_USER, 803 EaName.Buffer, 804 EaName.Length, 805 &FullEa->EaName[0] + FullEa->EaNameLength + 1, 806 FullEa->EaValueLength, 807 FALSE)); 808 if (!NT_SUCCESS(Status)) 809 _SEH2_LEAVE; 810 811 } 812 } 813 } 814 _SEH2_FINALLY { 815 816 if (XattrRefAcquired) { 817 if (!NT_SUCCESS(Status)) { 818 xattr_ref.dirty = FALSE; 819 ext4_fs_put_xattr_ref(&xattr_ref); 820 } else { 821 Status = Ext2WinntError(ext4_fs_put_xattr_ref(&xattr_ref)); 822 } 823 } 824 } _SEH2_END; 825 return Status; 826 } 827 828 NTSTATUS 829 Ext2CreateFile( 830 PEXT2_IRP_CONTEXT IrpContext, 831 PEXT2_VCB Vcb, 832 PBOOLEAN OpPostIrp 833 ) 834 { 835 NTSTATUS Status = STATUS_UNSUCCESSFUL; 836 PIO_STACK_LOCATION IrpSp; 837 PEXT2_FCB Fcb = NULL; 838 PEXT2_MCB Mcb = NULL; 839 PEXT2_MCB SymLink = NULL; 840 PEXT2_CCB Ccb = NULL; 841 842 PEXT2_FCB ParentFcb = NULL; 843 PEXT2_MCB ParentMcb = NULL; 844 845 UNICODE_STRING FileName; 846 PIRP Irp; 847 848 ULONG Options; 849 ULONG CreateDisposition; 850 851 BOOLEAN bParentFcbCreated = FALSE; 852 #ifndef __REACTOS__ 853 BOOLEAN bDir = FALSE; 854 #endif 855 BOOLEAN bFcbAllocated = FALSE; 856 BOOLEAN bCreated = FALSE; 857 858 BOOLEAN bMainResourceAcquired = FALSE; 859 BOOLEAN bFcbLockAcquired = FALSE; 860 861 BOOLEAN OpenDirectory; 862 BOOLEAN OpenTargetDirectory; 863 BOOLEAN CreateDirectory; 864 BOOLEAN SequentialOnly; 865 BOOLEAN NoIntermediateBuffering; 866 BOOLEAN IsPagingFile; 867 BOOLEAN DirectoryFile; 868 BOOLEAN NonDirectoryFile; 869 BOOLEAN NoEaKnowledge; 870 BOOLEAN DeleteOnClose; 871 BOOLEAN TemporaryFile; 872 BOOLEAN CaseSensitive; 873 BOOLEAN OpenReparsePoint; 874 875 ACCESS_MASK DesiredAccess; 876 ULONG ShareAccess; 877 ULONG CcbFlags = 0; 878 879 RtlZeroMemory(&FileName, sizeof(UNICODE_STRING)); 880 881 Irp = IrpContext->Irp; 882 IrpSp = IoGetCurrentIrpStackLocation(Irp); 883 884 Options = IrpSp->Parameters.Create.Options; 885 886 DirectoryFile = IsFlagOn(Options, FILE_DIRECTORY_FILE); 887 OpenTargetDirectory = IsFlagOn(IrpSp->Flags, SL_OPEN_TARGET_DIRECTORY); 888 889 NonDirectoryFile = IsFlagOn(Options, FILE_NON_DIRECTORY_FILE); 890 SequentialOnly = IsFlagOn(Options, FILE_SEQUENTIAL_ONLY); 891 NoIntermediateBuffering = IsFlagOn( Options, FILE_NO_INTERMEDIATE_BUFFERING ); 892 NoEaKnowledge = IsFlagOn(Options, FILE_NO_EA_KNOWLEDGE); 893 DeleteOnClose = IsFlagOn(Options, FILE_DELETE_ON_CLOSE); 894 895 /* Try to open reparse point (symlink) itself ? */ 896 OpenReparsePoint = IsFlagOn(Options, FILE_OPEN_REPARSE_POINT); 897 898 CaseSensitive = IsFlagOn(IrpSp->Flags, SL_CASE_SENSITIVE); 899 900 TemporaryFile = IsFlagOn(IrpSp->Parameters.Create.FileAttributes, 901 FILE_ATTRIBUTE_TEMPORARY ); 902 903 CreateDisposition = (Options >> 24) & 0x000000ff; 904 905 IsPagingFile = IsFlagOn(IrpSp->Flags, SL_OPEN_PAGING_FILE); 906 907 CreateDirectory = (BOOLEAN)(DirectoryFile && 908 ((CreateDisposition == FILE_CREATE) || 909 (CreateDisposition == FILE_OPEN_IF))); 910 911 OpenDirectory = (BOOLEAN)(DirectoryFile && 912 ((CreateDisposition == FILE_OPEN) || 913 (CreateDisposition == FILE_OPEN_IF))); 914 915 DesiredAccess = IrpSp->Parameters.Create.SecurityContext->DesiredAccess; 916 ShareAccess = IrpSp->Parameters.Create.ShareAccess; 917 918 *OpPostIrp = FALSE; 919 920 _SEH2_TRY { 921 922 FileName.MaximumLength = IrpSp->FileObject->FileName.MaximumLength; 923 FileName.Length = IrpSp->FileObject->FileName.Length; 924 925 if (IrpSp->FileObject->RelatedFileObject) { 926 ParentFcb = (PEXT2_FCB)(IrpSp->FileObject->RelatedFileObject->FsContext); 927 } 928 929 if (ParentFcb) { 930 ParentMcb = ParentFcb->Mcb; 931 Ext2ReferMcb(ParentMcb); 932 ParentFcb = NULL; 933 } 934 935 if (FileName.Length == 0) { 936 937 if (ParentMcb) { 938 Mcb = ParentMcb; 939 Ext2ReferMcb(Mcb); 940 Status = STATUS_SUCCESS; 941 goto McbExisting; 942 } else { 943 DbgBreak(); 944 Status = STATUS_INVALID_PARAMETER; 945 _SEH2_LEAVE; 946 } 947 } 948 949 FileName.Buffer = Ext2AllocatePool( 950 PagedPool, 951 FileName.MaximumLength, 952 EXT2_FNAME_MAGIC 953 ); 954 955 if (!FileName.Buffer) { 956 DEBUG(DL_ERR, ( "Ex2CreateFile: failed to allocate FileName.\n")); 957 Status = STATUS_INSUFFICIENT_RESOURCES; 958 _SEH2_LEAVE; 959 } 960 961 INC_MEM_COUNT(PS_FILE_NAME, FileName.Buffer, FileName.MaximumLength); 962 963 RtlZeroMemory(FileName.Buffer, FileName.MaximumLength); 964 RtlCopyMemory(FileName.Buffer, IrpSp->FileObject->FileName.Buffer, FileName.Length); 965 966 if (IrpSp->FileObject->RelatedFileObject && FileName.Buffer[0] == L'\\') { 967 Status = STATUS_INVALID_PARAMETER; 968 _SEH2_LEAVE; 969 } 970 971 if ((FileName.Length > sizeof(WCHAR)) && 972 (FileName.Buffer[1] == L'\\') && 973 (FileName.Buffer[0] == L'\\')) { 974 975 FileName.Length -= sizeof(WCHAR); 976 977 RtlMoveMemory( &FileName.Buffer[0], 978 &FileName.Buffer[1], 979 FileName.Length ); 980 981 // 982 // Bad Name if there are still beginning backslashes. 983 // 984 985 if ((FileName.Length > sizeof(WCHAR)) && 986 (FileName.Buffer[1] == L'\\') && 987 (FileName.Buffer[0] == L'\\')) { 988 989 Status = STATUS_OBJECT_NAME_INVALID; 990 _SEH2_LEAVE; 991 } 992 } 993 994 if (IsFlagOn(Options, FILE_OPEN_BY_FILE_ID)) { 995 Status = STATUS_NOT_IMPLEMENTED; 996 _SEH2_LEAVE; 997 } 998 999 DEBUG(DL_INF, ( "Ext2CreateFile: %wZ Paging=%d Option: %xh:" 1000 "Dir=%d NonDir=%d OpenTarget=%d NC=%d DeleteOnClose=%d\n", 1001 &FileName, IsPagingFile, IrpSp->Parameters.Create.Options, 1002 DirectoryFile, NonDirectoryFile, OpenTargetDirectory, 1003 NoIntermediateBuffering, DeleteOnClose )); 1004 1005 DEBUG(DL_RES, ("Ext2CreateFile: Lookup 1st: %wZ at %S\n", 1006 &FileName, ParentMcb ? ParentMcb->FullName.Buffer : L" ")); 1007 Status = Ext2LookupFile( 1008 IrpContext, 1009 Vcb, 1010 &FileName, 1011 ParentMcb, 1012 &Mcb, 1013 0 /* always follow link */ 1014 ); 1015 McbExisting: 1016 1017 if (!NT_SUCCESS(Status)) { 1018 1019 UNICODE_STRING PathName; 1020 UNICODE_STRING RealName; 1021 UNICODE_STRING RemainName; 1022 1023 #ifndef __REACTOS__ 1024 LONG i = 0; 1025 #endif 1026 1027 PathName = FileName; 1028 Mcb = NULL; 1029 1030 /* here we've found the target file, but it's not matched. */ 1031 if (STATUS_OBJECT_NAME_NOT_FOUND != Status && 1032 STATUS_NO_SUCH_FILE != Status) { 1033 _SEH2_LEAVE; 1034 } 1035 1036 while (PathName.Length > 0 && 1037 PathName.Buffer[PathName.Length/2 - 1] == L'\\') { 1038 DirectoryFile = TRUE; 1039 PathName.Length -= 2; 1040 PathName.Buffer[PathName.Length / 2] = 0; 1041 } 1042 1043 if (!ParentMcb) { 1044 if (PathName.Buffer[0] != L'\\') { 1045 Status = STATUS_OBJECT_PATH_NOT_FOUND; 1046 _SEH2_LEAVE; 1047 } else { 1048 ParentMcb = Vcb->McbTree; 1049 Ext2ReferMcb(ParentMcb); 1050 } 1051 } 1052 1053 Dissecting: 1054 1055 FsRtlDissectName(PathName, &RealName, &RemainName); 1056 1057 if (((RemainName.Length != 0) && (RemainName.Buffer[0] == L'\\')) || 1058 (RealName.Length >= 256 * sizeof(WCHAR))) { 1059 Status = STATUS_OBJECT_NAME_INVALID; 1060 _SEH2_LEAVE; 1061 } 1062 1063 if (RemainName.Length != 0) { 1064 1065 PEXT2_MCB RetMcb = NULL; 1066 1067 DEBUG(DL_RES, ("Ext2CreateFile: Lookup 2nd: %wZ\\%wZ\n", 1068 &ParentMcb->FullName, &RealName)); 1069 1070 Status = Ext2LookupFile ( 1071 IrpContext, 1072 Vcb, 1073 &RealName, 1074 ParentMcb, 1075 &RetMcb, 1076 0); 1077 1078 /* quit name resolving loop */ 1079 if (!NT_SUCCESS(Status)) { 1080 if (Status == STATUS_NO_SUCH_FILE || 1081 Status == STATUS_OBJECT_NAME_NOT_FOUND) { 1082 Status = STATUS_OBJECT_PATH_NOT_FOUND; 1083 } 1084 _SEH2_LEAVE; 1085 } 1086 1087 /* deref ParentMcb */ 1088 Ext2DerefMcb(ParentMcb); 1089 1090 /* RetMcb is already refered */ 1091 ParentMcb = RetMcb; 1092 PathName = RemainName; 1093 1094 /* symlink must use it's target */ 1095 if (IsMcbSymLink(ParentMcb)) { 1096 Ext2ReferMcb(ParentMcb->Target); 1097 Ext2DerefMcb(ParentMcb); 1098 ParentMcb = ParentMcb->Target; 1099 ASSERT(!IsMcbSymLink(ParentMcb)); 1100 } 1101 1102 goto Dissecting; 1103 } 1104 1105 /* is name valid */ 1106 if ( FsRtlDoesNameContainWildCards(&RealName) || 1107 !Ext2IsNameValid(&RealName)) { 1108 Status = STATUS_OBJECT_NAME_INVALID; 1109 _SEH2_LEAVE; 1110 } 1111 1112 if (!bFcbLockAcquired) { 1113 ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE); 1114 bFcbLockAcquired = TRUE; 1115 } 1116 1117 /* get the ParentFcb, allocate it if needed ... */ 1118 ParentFcb = ParentMcb->Fcb; 1119 if (!ParentFcb) { 1120 ParentFcb = Ext2AllocateFcb(Vcb, ParentMcb); 1121 if (!ParentFcb) { 1122 Status = STATUS_INSUFFICIENT_RESOURCES; 1123 _SEH2_LEAVE; 1124 } 1125 bParentFcbCreated = TRUE; 1126 } 1127 Ext2ReferXcb(&ParentFcb->ReferenceCount); 1128 1129 if (bFcbLockAcquired) { 1130 ExReleaseResourceLite(&Vcb->FcbLock); 1131 bFcbLockAcquired = FALSE; 1132 } 1133 1134 // We need to create a new one ? 1135 if ((CreateDisposition == FILE_CREATE ) || 1136 (CreateDisposition == FILE_SUPERSEDE) || 1137 (CreateDisposition == FILE_OPEN_IF) || 1138 (CreateDisposition == FILE_OVERWRITE_IF)) { 1139 1140 if (IsVcbReadOnly(Vcb)) { 1141 Status = STATUS_MEDIA_WRITE_PROTECTED; 1142 _SEH2_LEAVE; 1143 } 1144 1145 if (!Ext2CheckFileAccess(Vcb, ParentMcb, Ext2FileCanWrite)) { 1146 Status = STATUS_ACCESS_DENIED; 1147 _SEH2_LEAVE; 1148 } 1149 1150 if (IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED)) { 1151 IoSetHardErrorOrVerifyDevice( IrpContext->Irp, 1152 Vcb->Vpb->RealDevice ); 1153 SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME); 1154 Ext2RaiseStatus(IrpContext, STATUS_MEDIA_WRITE_PROTECTED); 1155 } 1156 1157 if (DirectoryFile) { 1158 if (TemporaryFile) { 1159 DbgBreak(); 1160 Status = STATUS_INVALID_PARAMETER; 1161 _SEH2_LEAVE; 1162 } 1163 } 1164 1165 if (!ParentFcb) { 1166 Status = STATUS_OBJECT_PATH_NOT_FOUND; 1167 _SEH2_LEAVE; 1168 } 1169 1170 /* allocate inode and construct entry for this file */ 1171 Status = Ext2CreateInode( 1172 IrpContext, 1173 Vcb, 1174 ParentFcb, 1175 DirectoryFile ? EXT2_FT_DIR : EXT2_FT_REG_FILE, 1176 IrpSp->Parameters.Create.FileAttributes, 1177 &RealName 1178 ); 1179 1180 if (!NT_SUCCESS(Status)) { 1181 DbgBreak(); 1182 _SEH2_LEAVE; 1183 } 1184 1185 bCreated = TRUE; 1186 DEBUG(DL_RES, ("Ext2CreateFile: Confirm creation: %wZ\\%wZ\n", 1187 &ParentMcb->FullName, &RealName)); 1188 1189 Irp->IoStatus.Information = FILE_CREATED; 1190 Status = Ext2LookupFile ( 1191 IrpContext, 1192 Vcb, 1193 &RealName, 1194 ParentMcb, 1195 &Mcb, 1196 0); 1197 if (!NT_SUCCESS(Status)) { 1198 DbgBreak(); 1199 } 1200 1201 } else if (OpenTargetDirectory) { 1202 1203 if (IsVcbReadOnly(Vcb)) { 1204 Status = STATUS_MEDIA_WRITE_PROTECTED; 1205 _SEH2_LEAVE; 1206 } 1207 1208 if (!ParentFcb) { 1209 Status = STATUS_OBJECT_PATH_NOT_FOUND; 1210 _SEH2_LEAVE; 1211 } 1212 1213 RtlZeroMemory( IrpSp->FileObject->FileName.Buffer, 1214 IrpSp->FileObject->FileName.MaximumLength); 1215 IrpSp->FileObject->FileName.Length = RealName.Length; 1216 1217 RtlCopyMemory( IrpSp->FileObject->FileName.Buffer, 1218 RealName.Buffer, 1219 RealName.Length ); 1220 1221 Fcb = ParentFcb; 1222 Mcb = Fcb->Mcb; 1223 Ext2ReferMcb(Mcb); 1224 1225 Irp->IoStatus.Information = FILE_DOES_NOT_EXIST; 1226 Status = STATUS_SUCCESS; 1227 1228 } else { 1229 1230 Status = STATUS_OBJECT_NAME_NOT_FOUND; 1231 _SEH2_LEAVE; 1232 } 1233 1234 } else { // File / Dir already exists. 1235 1236 /* here already get Mcb referred */ 1237 if (OpenTargetDirectory) { 1238 1239 UNICODE_STRING RealName = FileName; 1240 USHORT i = 0; 1241 1242 while (RealName.Buffer[RealName.Length/2 - 1] == L'\\') { 1243 RealName.Length -= sizeof(WCHAR); 1244 RealName.Buffer[RealName.Length/2] = 0; 1245 } 1246 i = RealName.Length/2; 1247 while (i > 0 && RealName.Buffer[i - 1] != L'\\') 1248 i--; 1249 1250 if (IsVcbReadOnly(Vcb)) { 1251 Status = STATUS_MEDIA_WRITE_PROTECTED; 1252 Ext2DerefMcb(Mcb); 1253 _SEH2_LEAVE; 1254 } 1255 1256 Irp->IoStatus.Information = FILE_EXISTS; 1257 Status = STATUS_SUCCESS; 1258 1259 RtlZeroMemory( IrpSp->FileObject->FileName.Buffer, 1260 IrpSp->FileObject->FileName.MaximumLength); 1261 IrpSp->FileObject->FileName.Length = RealName.Length - i * sizeof(WCHAR); 1262 RtlCopyMemory( IrpSp->FileObject->FileName.Buffer, &RealName.Buffer[i], 1263 IrpSp->FileObject->FileName.Length ); 1264 1265 // use's it's parent since it's open-target operation 1266 Ext2ReferMcb(Mcb->Parent); 1267 Ext2DerefMcb(Mcb); 1268 Mcb = Mcb->Parent; 1269 1270 goto Openit; 1271 } 1272 1273 // We can not create if one exists 1274 if (CreateDisposition == FILE_CREATE) { 1275 Irp->IoStatus.Information = FILE_EXISTS; 1276 Status = STATUS_OBJECT_NAME_COLLISION; 1277 Ext2DerefMcb(Mcb); 1278 _SEH2_LEAVE; 1279 } 1280 1281 /* directory forbits us to do the followings ... */ 1282 if (IsMcbDirectory(Mcb)) { 1283 1284 if ((CreateDisposition != FILE_OPEN) && 1285 (CreateDisposition != FILE_OPEN_IF)) { 1286 1287 Status = STATUS_OBJECT_NAME_COLLISION; 1288 Ext2DerefMcb(Mcb); 1289 _SEH2_LEAVE; 1290 } 1291 1292 if (NonDirectoryFile) { 1293 Status = STATUS_FILE_IS_A_DIRECTORY; 1294 Ext2DerefMcb(Mcb); 1295 _SEH2_LEAVE; 1296 } 1297 1298 if (Mcb->Inode.i_ino == EXT2_ROOT_INO) { 1299 1300 if (OpenTargetDirectory) { 1301 DbgBreak(); 1302 Status = STATUS_INVALID_PARAMETER; 1303 Ext2DerefMcb(Mcb); 1304 _SEH2_LEAVE; 1305 } 1306 } 1307 1308 } else { 1309 1310 if (DirectoryFile) { 1311 Status = STATUS_NOT_A_DIRECTORY;; 1312 Ext2DerefMcb(Mcb); 1313 _SEH2_LEAVE; 1314 } 1315 } 1316 1317 Irp->IoStatus.Information = FILE_OPENED; 1318 } 1319 1320 Openit: 1321 1322 if (!bFcbLockAcquired) { 1323 ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE); 1324 bFcbLockAcquired = TRUE; 1325 } 1326 1327 /* Mcb should already be referred and symlink is too */ 1328 if (Mcb) { 1329 1330 ASSERT(Mcb->Refercount > 0); 1331 1332 /* refer it's target if it's a symlink, so both refered */ 1333 if (IsMcbSymLink(Mcb)) { 1334 1335 if (OpenReparsePoint) { 1336 /* set Ccb flag */ 1337 CcbFlags = CCB_OPEN_REPARSE_POINT; 1338 } else if (IsFileDeleted(Mcb->Target)) { 1339 DbgBreak(); 1340 SetLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL); 1341 ClearLongFlag(Mcb->Flags, MCB_TYPE_SYMLINK); 1342 Ext2DerefMcb(Mcb->Target); 1343 Mcb->Target = NULL; 1344 } else { 1345 SymLink = Mcb; 1346 Mcb = Mcb->Target; 1347 Ext2ReferMcb(Mcb); 1348 ASSERT (!IsMcbSymLink(Mcb)); 1349 } 1350 } 1351 1352 // Check readonly flag 1353 if (BooleanFlagOn(DesiredAccess, FILE_GENERIC_READ) && 1354 !Ext2CheckFileAccess(Vcb, Mcb, Ext2FileCanRead)) { 1355 Status = STATUS_ACCESS_DENIED; 1356 _SEH2_LEAVE; 1357 } 1358 if (!Ext2CheckFileAccess(Vcb, Mcb, Ext2FileCanWrite)) { 1359 if (BooleanFlagOn(DesiredAccess, FILE_WRITE_DATA | FILE_APPEND_DATA | 1360 FILE_ADD_SUBDIRECTORY | FILE_DELETE_CHILD)) { 1361 Status = STATUS_ACCESS_DENIED; 1362 _SEH2_LEAVE; 1363 } else if (IsFlagOn(Options, FILE_DELETE_ON_CLOSE )) { 1364 Status = STATUS_CANNOT_DELETE; 1365 _SEH2_LEAVE; 1366 } 1367 } 1368 1369 Fcb = Mcb->Fcb; 1370 if (Fcb == NULL) { 1371 1372 /* allocate Fcb for this file */ 1373 Fcb = Ext2AllocateFcb (Vcb, Mcb); 1374 if (Fcb) { 1375 bFcbAllocated = TRUE; 1376 } else { 1377 Status = STATUS_INSUFFICIENT_RESOURCES; 1378 } 1379 } else { 1380 if (IsPagingFile) { 1381 Status = STATUS_SHARING_VIOLATION; 1382 Fcb = NULL; 1383 } 1384 } 1385 1386 /* Now it's safe to defer Mcb */ 1387 Ext2DerefMcb(Mcb); 1388 } 1389 1390 if (Fcb) { 1391 /* grab Fcb's reference first to avoid the race between 1392 Ext2Close (it could free the Fcb we are accessing) */ 1393 Ext2ReferXcb(&Fcb->ReferenceCount); 1394 } 1395 1396 ExReleaseResourceLite(&Vcb->FcbLock); 1397 bFcbLockAcquired = FALSE; 1398 1399 if (Fcb) { 1400 1401 ExAcquireResourceExclusiveLite(&Fcb->MainResource, TRUE); 1402 bMainResourceAcquired = TRUE; 1403 1404 /* Open target directory ? */ 1405 if (NULL == Mcb) { 1406 DbgBreak(); 1407 Mcb = Fcb->Mcb; 1408 } 1409 1410 /* check Mcb reference */ 1411 ASSERT(Fcb->Mcb->Refercount > 0); 1412 1413 /* file delted ? */ 1414 if (IsFlagOn(Fcb->Mcb->Flags, MCB_FILE_DELETED)) { 1415 Status = STATUS_FILE_DELETED; 1416 _SEH2_LEAVE; 1417 } 1418 1419 if (DeleteOnClose && NULL == SymLink) { 1420 Status = Ext2IsFileRemovable(IrpContext, Vcb, Fcb, Ccb); 1421 if (!NT_SUCCESS(Status)) { 1422 _SEH2_LEAVE; 1423 } 1424 } 1425 1426 /* check access and oplock access for opened files */ 1427 if (!bFcbAllocated && !IsDirectory(Fcb)) { 1428 1429 /* whether there's batch oplock grabed on the file */ 1430 if (FsRtlCurrentBatchOplock(&Fcb->Oplock)) { 1431 1432 Irp->IoStatus.Information = FILE_OPBATCH_BREAK_UNDERWAY; 1433 1434 /* break the batch lock if the sharing check fails */ 1435 Status = FsRtlCheckOplock( &Fcb->Oplock, 1436 IrpContext->Irp, 1437 IrpContext, 1438 Ext2OplockComplete, 1439 Ext2LockIrp ); 1440 1441 if ( Status != STATUS_SUCCESS && 1442 Status != STATUS_OPLOCK_BREAK_IN_PROGRESS) { 1443 *OpPostIrp = TRUE; 1444 _SEH2_LEAVE; 1445 } 1446 } 1447 } 1448 1449 if (bCreated) { 1450 1451 // 1452 // This file is just created. 1453 // 1454 1455 Status = Ext2OverwriteEa(IrpContext, Vcb, Fcb, &Irp->IoStatus); 1456 if (!NT_SUCCESS(Status)) { 1457 Ext2DeleteFile(IrpContext, Vcb, Fcb, Mcb); 1458 _SEH2_LEAVE; 1459 } 1460 1461 if (DirectoryFile) { 1462 1463 Status = Ext2AddDotEntries(IrpContext, &ParentMcb->Inode, &Mcb->Inode); 1464 if (!NT_SUCCESS(Status)) { 1465 Ext2DeleteFile(IrpContext, Vcb, Fcb, Mcb); 1466 _SEH2_LEAVE; 1467 } 1468 1469 } else { 1470 1471 if ((LONGLONG)ext3_free_blocks_count(SUPER_BLOCK) <= 1472 Ext2TotalBlocks(Vcb, &Irp->Overlay.AllocationSize, NULL)) { 1473 DbgBreak(); 1474 Status = STATUS_DISK_FULL; 1475 _SEH2_LEAVE; 1476 } 1477 1478 /* disable data blocks allocation */ 1479 #if 0 1480 Fcb->Header.AllocationSize.QuadPart = 1481 Irp->Overlay.AllocationSize.QuadPart; 1482 1483 if (Fcb->Header.AllocationSize.QuadPart > 0) { 1484 Status = Ext2ExpandFile(IrpContext, 1485 Vcb, 1486 Fcb->Mcb, 1487 &(Fcb->Header.AllocationSize) 1488 ); 1489 SetLongFlag(Fcb->Flags, FCB_ALLOC_IN_CREATE); 1490 if (!NT_SUCCESS(Status)) { 1491 Fcb->Header.AllocationSize.QuadPart = 0; 1492 Ext2TruncateFile(IrpContext, Vcb, Fcb->Mcb, 1493 &Fcb->Header.AllocationSize); 1494 _SEH2_LEAVE; 1495 } 1496 } 1497 #endif 1498 } 1499 1500 } else { 1501 1502 // 1503 // This file alreayd exists. 1504 // 1505 1506 if (DeleteOnClose) { 1507 1508 if (IsVcbReadOnly(Vcb)) { 1509 Status = STATUS_MEDIA_WRITE_PROTECTED; 1510 _SEH2_LEAVE; 1511 } 1512 1513 if (IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED)) { 1514 Status = STATUS_MEDIA_WRITE_PROTECTED; 1515 1516 IoSetHardErrorOrVerifyDevice( IrpContext->Irp, 1517 Vcb->Vpb->RealDevice ); 1518 1519 SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME); 1520 1521 Ext2RaiseStatus(IrpContext, STATUS_MEDIA_WRITE_PROTECTED); 1522 } 1523 1524 } else { 1525 1526 // 1527 // Just to Open file (Open/OverWrite ...) 1528 // 1529 1530 if ((!IsDirectory(Fcb)) && (IsFlagOn(IrpSp->FileObject->Flags, 1531 FO_NO_INTERMEDIATE_BUFFERING))) { 1532 Fcb->Header.IsFastIoPossible = FastIoIsPossible; 1533 1534 if (Fcb->SectionObject.DataSectionObject != NULL) { 1535 1536 if (Fcb->NonCachedOpenCount == Fcb->OpenHandleCount) { 1537 1538 if (!IsVcbReadOnly(Vcb)) { 1539 CcFlushCache(&Fcb->SectionObject, NULL, 0, NULL); 1540 ClearLongFlag(Fcb->Flags, FCB_FILE_MODIFIED); 1541 } 1542 1543 CcPurgeCacheSection(&Fcb->SectionObject, 1544 NULL, 1545 0, 1546 FALSE ); 1547 } 1548 } 1549 } 1550 } 1551 } 1552 1553 if (!IsDirectory(Fcb)) { 1554 1555 if (!IsVcbReadOnly(Vcb)) { 1556 if ((CreateDisposition == FILE_SUPERSEDE) && !IsPagingFile) { 1557 DesiredAccess |= DELETE; 1558 } else if (((CreateDisposition == FILE_OVERWRITE) || 1559 (CreateDisposition == FILE_OVERWRITE_IF)) && !IsPagingFile) { 1560 DesiredAccess |= (FILE_WRITE_DATA | FILE_WRITE_EA | 1561 FILE_WRITE_ATTRIBUTES ); 1562 } 1563 } 1564 1565 if (!bFcbAllocated) { 1566 1567 // 1568 // check the oplock state of the file 1569 // 1570 1571 Status = FsRtlCheckOplock( &Fcb->Oplock, 1572 IrpContext->Irp, 1573 IrpContext, 1574 Ext2OplockComplete, 1575 Ext2LockIrp ); 1576 1577 if ( Status != STATUS_SUCCESS && 1578 Status != STATUS_OPLOCK_BREAK_IN_PROGRESS) { 1579 *OpPostIrp = TRUE; 1580 _SEH2_LEAVE; 1581 } 1582 } 1583 } 1584 1585 if (Fcb->OpenHandleCount > 0) { 1586 1587 /* check the shrae access conflicts */ 1588 Status = IoCheckShareAccess( DesiredAccess, 1589 ShareAccess, 1590 IrpSp->FileObject, 1591 &(Fcb->ShareAccess), 1592 TRUE ); 1593 if (!NT_SUCCESS(Status)) { 1594 _SEH2_LEAVE; 1595 } 1596 1597 } else { 1598 1599 /* set share access rights */ 1600 IoSetShareAccess( DesiredAccess, 1601 ShareAccess, 1602 IrpSp->FileObject, 1603 &(Fcb->ShareAccess) ); 1604 } 1605 1606 Ccb = Ext2AllocateCcb(CcbFlags, SymLink); 1607 if (!Ccb) { 1608 Status = STATUS_INSUFFICIENT_RESOURCES; 1609 DbgBreak(); 1610 _SEH2_LEAVE; 1611 } 1612 1613 if (DeleteOnClose) 1614 SetLongFlag(Ccb->Flags, CCB_DELETE_ON_CLOSE); 1615 1616 if (SymLink) 1617 Ccb->filp.f_dentry = SymLink->de; 1618 else 1619 Ccb->filp.f_dentry = Fcb->Mcb->de; 1620 1621 Ccb->filp.f_version = Fcb->Mcb->Inode.i_version; 1622 Ext2ReferXcb(&Fcb->OpenHandleCount); 1623 Ext2ReferXcb(&Fcb->ReferenceCount); 1624 1625 if (!IsDirectory(Fcb)) { 1626 if (NoIntermediateBuffering) { 1627 Fcb->NonCachedOpenCount++; 1628 SetFlag(IrpSp->FileObject->Flags, FO_CACHE_SUPPORTED); 1629 } else { 1630 SetFlag(IrpSp->FileObject->Flags, FO_CACHE_SUPPORTED); 1631 } 1632 } 1633 1634 Ext2ReferXcb(&Vcb->OpenHandleCount); 1635 Ext2ReferXcb(&Vcb->ReferenceCount); 1636 1637 IrpSp->FileObject->FsContext = (void*) Fcb; 1638 IrpSp->FileObject->FsContext2 = (void*) Ccb; 1639 IrpSp->FileObject->PrivateCacheMap = NULL; 1640 IrpSp->FileObject->SectionObjectPointer = &(Fcb->SectionObject); 1641 1642 DEBUG(DL_INF, ( "Ext2CreateFile: %wZ OpenCount=%u ReferCount=%u NonCachedCount=%u\n", 1643 &Fcb->Mcb->FullName, Fcb->OpenHandleCount, Fcb->ReferenceCount, Fcb->NonCachedOpenCount)); 1644 1645 Status = STATUS_SUCCESS; 1646 1647 if (bCreated) { 1648 1649 if (IsDirectory(Fcb)) { 1650 Ext2NotifyReportChange( 1651 IrpContext, 1652 Vcb, 1653 Fcb->Mcb, 1654 FILE_NOTIFY_CHANGE_DIR_NAME, 1655 FILE_ACTION_ADDED ); 1656 } else { 1657 Ext2NotifyReportChange( 1658 IrpContext, 1659 Vcb, 1660 Fcb->Mcb, 1661 FILE_NOTIFY_CHANGE_FILE_NAME, 1662 FILE_ACTION_ADDED ); 1663 } 1664 1665 } else if (!IsDirectory(Fcb)) { 1666 1667 if ( DeleteOnClose || 1668 IsFlagOn(DesiredAccess, FILE_WRITE_DATA) || 1669 (CreateDisposition == FILE_OVERWRITE) || 1670 (CreateDisposition == FILE_OVERWRITE_IF)) { 1671 if (!MmFlushImageSection( &Fcb->SectionObject, 1672 MmFlushForWrite )) { 1673 1674 Status = DeleteOnClose ? STATUS_CANNOT_DELETE : 1675 STATUS_SHARING_VIOLATION; 1676 _SEH2_LEAVE; 1677 } 1678 } 1679 1680 if ((CreateDisposition == FILE_SUPERSEDE) || 1681 (CreateDisposition == FILE_OVERWRITE) || 1682 (CreateDisposition == FILE_OVERWRITE_IF)) { 1683 1684 if (IsDirectory(Fcb)) { 1685 Status = STATUS_FILE_IS_A_DIRECTORY; 1686 _SEH2_LEAVE; 1687 } 1688 1689 if (SymLink != NULL) { 1690 DbgBreak(); 1691 Status = STATUS_INVALID_PARAMETER; 1692 _SEH2_LEAVE; 1693 } 1694 1695 if (IsVcbReadOnly(Vcb)) { 1696 Status = STATUS_MEDIA_WRITE_PROTECTED; 1697 _SEH2_LEAVE; 1698 } 1699 1700 if (IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED)) { 1701 1702 IoSetHardErrorOrVerifyDevice( IrpContext->Irp, 1703 Vcb->Vpb->RealDevice ); 1704 SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME); 1705 Ext2RaiseStatus(IrpContext, STATUS_MEDIA_WRITE_PROTECTED); 1706 } 1707 1708 Status = Ext2SupersedeOrOverWriteFile( 1709 IrpContext, 1710 IrpSp->FileObject, 1711 Vcb, 1712 Fcb, 1713 &Irp->Overlay.AllocationSize, 1714 CreateDisposition ); 1715 1716 if (!NT_SUCCESS(Status)) { 1717 DbgBreak(); 1718 _SEH2_LEAVE; 1719 } 1720 1721 Ext2NotifyReportChange( 1722 IrpContext, 1723 Vcb, 1724 Fcb->Mcb, 1725 FILE_NOTIFY_CHANGE_LAST_WRITE | 1726 FILE_NOTIFY_CHANGE_ATTRIBUTES | 1727 FILE_NOTIFY_CHANGE_SIZE, 1728 FILE_ACTION_MODIFIED ); 1729 1730 1731 if (CreateDisposition == FILE_SUPERSEDE) { 1732 Irp->IoStatus.Information = FILE_SUPERSEDED; 1733 } else { 1734 Irp->IoStatus.Information = FILE_OVERWRITTEN; 1735 } 1736 } 1737 } 1738 1739 } else { 1740 DbgBreak(); 1741 _SEH2_LEAVE; 1742 } 1743 1744 } _SEH2_FINALLY { 1745 1746 if (bFcbLockAcquired) { 1747 ExReleaseResourceLite(&Vcb->FcbLock); 1748 } 1749 1750 if (ParentMcb) { 1751 Ext2DerefMcb(ParentMcb); 1752 } 1753 1754 /* cleanup Fcb and Ccb, Mcb if necessary */ 1755 if (!NT_SUCCESS(Status)) { 1756 1757 if (Ccb != NULL) { 1758 1759 DbgBreak(); 1760 1761 ASSERT(Fcb != NULL); 1762 ASSERT(Fcb->Mcb != NULL); 1763 1764 DEBUG(DL_ERR, ("Ext2CreateFile: failed to create %wZ status = %xh\n", 1765 &Fcb->Mcb->FullName, Status)); 1766 1767 Ext2DerefXcb(&Fcb->OpenHandleCount); 1768 Ext2DerefXcb(&Fcb->ReferenceCount); 1769 1770 if (!IsDirectory(Fcb)) { 1771 if (NoIntermediateBuffering) { 1772 Fcb->NonCachedOpenCount--; 1773 } else { 1774 ClearFlag(IrpSp->FileObject->Flags, FO_CACHE_SUPPORTED); 1775 } 1776 } 1777 1778 Ext2DerefXcb(&Vcb->OpenHandleCount); 1779 Ext2DerefXcb(&Vcb->ReferenceCount); 1780 1781 IoRemoveShareAccess(IrpSp->FileObject, &Fcb->ShareAccess); 1782 1783 IrpSp->FileObject->FsContext = NULL; 1784 IrpSp->FileObject->FsContext2 = NULL; 1785 IrpSp->FileObject->PrivateCacheMap = NULL; 1786 IrpSp->FileObject->SectionObjectPointer = NULL; 1787 1788 Ext2FreeCcb(Vcb, Ccb); 1789 } 1790 1791 if (Fcb != NULL) { 1792 1793 if (IsFlagOn(Fcb->Flags, FCB_ALLOC_IN_CREATE)) { 1794 LARGE_INTEGER Size; 1795 ExAcquireResourceExclusiveLite(&Fcb->PagingIoResource, TRUE); 1796 _SEH2_TRY { 1797 Size.QuadPart = 0; 1798 Ext2TruncateFile(IrpContext, Vcb, Fcb->Mcb, &Size); 1799 } _SEH2_FINALLY { 1800 ExReleaseResourceLite(&Fcb->PagingIoResource); 1801 } _SEH2_END; 1802 } 1803 1804 if (bCreated) { 1805 Ext2DeleteFile(IrpContext, Vcb, Fcb, Mcb); 1806 } 1807 } 1808 } 1809 1810 if (bMainResourceAcquired) { 1811 ExReleaseResourceLite(&Fcb->MainResource); 1812 } 1813 1814 /* free file name buffer */ 1815 if (FileName.Buffer) { 1816 DEC_MEM_COUNT(PS_FILE_NAME, FileName.Buffer, FileName.MaximumLength); 1817 Ext2FreePool(FileName.Buffer, EXT2_FNAME_MAGIC); 1818 } 1819 1820 /* dereference Fcb and parent */ 1821 if (Fcb) { 1822 Ext2ReleaseFcb(Fcb); 1823 } 1824 if (ParentFcb) { 1825 Ext2ReleaseFcb(ParentFcb); 1826 } 1827 1828 /* drop SymLink's refer: If succeeds, Ext2AllocateCcb should refer 1829 it already. It fails, we need release the refer to let it freed */ 1830 if (SymLink) { 1831 Ext2DerefMcb(SymLink); 1832 } 1833 } _SEH2_END; 1834 1835 return Status; 1836 } 1837 1838 NTSTATUS 1839 Ext2CreateVolume(PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB Vcb) 1840 { 1841 PIO_STACK_LOCATION IrpSp; 1842 PIRP Irp; 1843 PEXT2_CCB Ccb; 1844 1845 NTSTATUS Status; 1846 1847 ACCESS_MASK DesiredAccess; 1848 ULONG ShareAccess; 1849 1850 ULONG Options; 1851 BOOLEAN DirectoryFile; 1852 BOOLEAN OpenTargetDirectory; 1853 1854 ULONG CreateDisposition; 1855 1856 Irp = IrpContext->Irp; 1857 IrpSp = IoGetCurrentIrpStackLocation(Irp); 1858 1859 Options = IrpSp->Parameters.Create.Options; 1860 1861 DirectoryFile = IsFlagOn(Options, FILE_DIRECTORY_FILE); 1862 OpenTargetDirectory = IsFlagOn(IrpSp->Flags, SL_OPEN_TARGET_DIRECTORY); 1863 1864 CreateDisposition = (Options >> 24) & 0x000000ff; 1865 1866 DesiredAccess = IrpSp->Parameters.Create.SecurityContext->DesiredAccess; 1867 ShareAccess = IrpSp->Parameters.Create.ShareAccess; 1868 1869 if (DirectoryFile) { 1870 return STATUS_NOT_A_DIRECTORY; 1871 } 1872 1873 if (OpenTargetDirectory) { 1874 DbgBreak(); 1875 return STATUS_INVALID_PARAMETER; 1876 } 1877 1878 if ( (CreateDisposition != FILE_OPEN) && 1879 (CreateDisposition != FILE_OPEN_IF) ) { 1880 return STATUS_ACCESS_DENIED; 1881 } 1882 1883 if ( !FlagOn(ShareAccess, FILE_SHARE_READ) && 1884 Vcb->OpenVolumeCount != 0 ) { 1885 return STATUS_SHARING_VIOLATION; 1886 } 1887 1888 Ccb = Ext2AllocateCcb(0, NULL); 1889 if (Ccb == NULL) { 1890 Status = STATUS_INSUFFICIENT_RESOURCES; 1891 goto errorout; 1892 } 1893 1894 Status = STATUS_SUCCESS; 1895 1896 if (Vcb->OpenVolumeCount > 0) { 1897 Status = IoCheckShareAccess( DesiredAccess, ShareAccess, 1898 IrpSp->FileObject, 1899 &(Vcb->ShareAccess), TRUE); 1900 1901 if (!NT_SUCCESS(Status)) { 1902 goto errorout; 1903 } 1904 } else { 1905 IoSetShareAccess( DesiredAccess, ShareAccess, 1906 IrpSp->FileObject, 1907 &(Vcb->ShareAccess) ); 1908 } 1909 1910 1911 if (Vcb->OpenVolumeCount == 0 && 1912 !IsFlagOn(ShareAccess, FILE_SHARE_READ) && 1913 !IsFlagOn(ShareAccess, FILE_SHARE_WRITE) ){ 1914 1915 if (!IsVcbReadOnly(Vcb)) { 1916 Ext2FlushFiles(IrpContext, Vcb, FALSE); 1917 Ext2FlushVolume(IrpContext, Vcb, FALSE); 1918 } 1919 1920 SetLongFlag(Vcb->Flags, VCB_VOLUME_LOCKED); 1921 Vcb->LockFile = IrpSp->FileObject; 1922 } else { 1923 1924 if (FlagOn(IrpSp->FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING) && 1925 FlagOn(DesiredAccess, FILE_READ_DATA | FILE_WRITE_DATA) ) { 1926 if (!IsVcbReadOnly(Vcb)) { 1927 Ext2FlushFiles(IrpContext, Vcb, FALSE); 1928 Ext2FlushVolume(IrpContext, Vcb, FALSE); 1929 } 1930 } 1931 } 1932 1933 IrpSp->FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING; 1934 IrpSp->FileObject->FsContext = Vcb; 1935 IrpSp->FileObject->FsContext2 = Ccb; 1936 IrpSp->FileObject->Vpb = Vcb->Vpb; 1937 1938 Ext2ReferXcb(&Vcb->ReferenceCount); 1939 Ext2ReferXcb(&Vcb->OpenHandleCount); 1940 Ext2ReferXcb(&Vcb->OpenVolumeCount); 1941 1942 Irp->IoStatus.Information = FILE_OPENED; 1943 1944 errorout: 1945 1946 return Status; 1947 } 1948 1949 1950 NTSTATUS 1951 Ext2Create (IN PEXT2_IRP_CONTEXT IrpContext) 1952 { 1953 PDEVICE_OBJECT DeviceObject; 1954 PIRP Irp; 1955 PIO_STACK_LOCATION IrpSp; 1956 PEXT2_VCB Vcb = 0; 1957 NTSTATUS Status = STATUS_OBJECT_NAME_NOT_FOUND; 1958 PEXT2_FCBVCB Xcb = NULL; 1959 BOOLEAN PostIrp = FALSE; 1960 BOOLEAN VcbResourceAcquired = FALSE; 1961 1962 DeviceObject = IrpContext->DeviceObject; 1963 Irp = IrpContext->Irp; 1964 IrpSp = IoGetCurrentIrpStackLocation(Irp); 1965 1966 Xcb = (PEXT2_FCBVCB) (IrpSp->FileObject->FsContext); 1967 1968 if (IsExt2FsDevice(DeviceObject)) { 1969 1970 DEBUG(DL_INF, ( "Ext2Create: Create on main device object.\n")); 1971 1972 Status = STATUS_SUCCESS; 1973 Irp->IoStatus.Information = FILE_OPENED; 1974 1975 Ext2CompleteIrpContext(IrpContext, Status); 1976 1977 return Status; 1978 } 1979 1980 _SEH2_TRY { 1981 1982 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension; 1983 ASSERT(Vcb->Identifier.Type == EXT2VCB); 1984 IrpSp->FileObject->Vpb = Vcb->Vpb; 1985 1986 if (!IsMounted(Vcb)) { 1987 DbgBreak(); 1988 if (IsFlagOn(Vcb->Flags, VCB_DEVICE_REMOVED)) { 1989 Status = STATUS_NO_SUCH_DEVICE; 1990 } else { 1991 Status = STATUS_VOLUME_DISMOUNTED; 1992 } 1993 _SEH2_LEAVE; 1994 } 1995 1996 if (!ExAcquireResourceExclusiveLite( 1997 &Vcb->MainResource, TRUE)) { 1998 Status = STATUS_PENDING; 1999 _SEH2_LEAVE; 2000 } 2001 VcbResourceAcquired = TRUE; 2002 2003 Ext2VerifyVcb(IrpContext, Vcb); 2004 2005 if (FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) { 2006 Status = STATUS_ACCESS_DENIED; 2007 if (IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) { 2008 Status = STATUS_VOLUME_DISMOUNTED; 2009 } 2010 _SEH2_LEAVE; 2011 } 2012 2013 if ( ((IrpSp->FileObject->FileName.Length == 0) && 2014 (IrpSp->FileObject->RelatedFileObject == NULL)) || 2015 (Xcb && Xcb->Identifier.Type == EXT2VCB) ) { 2016 Status = Ext2CreateVolume(IrpContext, Vcb); 2017 } else { 2018 2019 Status = Ext2CreateFile(IrpContext, Vcb, &PostIrp); 2020 } 2021 2022 } _SEH2_FINALLY { 2023 2024 if (VcbResourceAcquired) { 2025 ExReleaseResourceLite(&Vcb->MainResource); 2026 } 2027 2028 if (!IrpContext->ExceptionInProgress && !PostIrp) { 2029 if ( Status == STATUS_PENDING || 2030 Status == STATUS_CANT_WAIT) { 2031 Status = Ext2QueueRequest(IrpContext); 2032 } else { 2033 Ext2CompleteIrpContext(IrpContext, Status); 2034 } 2035 } 2036 } _SEH2_END; 2037 2038 return Status; 2039 } 2040 2041 NTSTATUS 2042 Ext2CreateInode( 2043 PEXT2_IRP_CONTEXT IrpContext, 2044 PEXT2_VCB Vcb, 2045 PEXT2_FCB Parent, 2046 ULONG Type, 2047 ULONG FileAttr, 2048 PUNICODE_STRING FileName) 2049 { 2050 NTSTATUS Status; 2051 ULONG iGrp; 2052 ULONG iNo; 2053 struct inode Inode = { 0 }; 2054 struct dentry *Dentry = NULL; 2055 struct ext3_super_block *es = EXT3_SB(&Vcb->sb)->s_es; 2056 2057 LARGE_INTEGER SysTime; 2058 2059 iGrp = (Parent->Inode->i_ino - 1) / BLOCKS_PER_GROUP; 2060 2061 DEBUG(DL_INF, ("Ext2CreateInode: %S in %S(Inode=%xh)\n", 2062 FileName->Buffer, 2063 Parent->Mcb->ShortName.Buffer, 2064 Parent->Inode->i_ino)); 2065 2066 Status = Ext2NewInode(IrpContext, Vcb, iGrp, Type, &iNo); 2067 if (!NT_SUCCESS(Status)) { 2068 goto errorout; 2069 } 2070 2071 KeQuerySystemTime(&SysTime); 2072 Ext2ClearInode(IrpContext, Vcb, iNo); 2073 Inode.i_sb = &Vcb->sb; 2074 Inode.i_ino = iNo; 2075 Inode.i_ctime = Inode.i_mtime = 2076 Inode.i_atime = Ext2LinuxTime(SysTime); 2077 if (IsFlagOn(Vcb->Flags, VCB_USER_IDS)) { 2078 Inode.i_uid = Vcb->uid; 2079 Inode.i_gid = Vcb->gid; 2080 } else { 2081 Inode.i_uid = Parent->Mcb->Inode.i_uid; 2082 Inode.i_gid = Parent->Mcb->Inode.i_gid; 2083 } 2084 Inode.i_generation = Parent->Inode->i_generation; 2085 Inode.i_mode = S_IPERMISSION_MASK & 2086 Parent->Inode->i_mode; 2087 if (Type == EXT2_FT_DIR) { 2088 Inode.i_mode |= S_IFDIR; 2089 } else if (Type == EXT2_FT_REG_FILE) { 2090 Inode.i_mode &= S_IFATTR; 2091 Inode.i_mode |= S_IFREG; 2092 } else { 2093 DbgBreak(); 2094 } 2095 if (le16_to_cpu(es->s_want_extra_isize)) 2096 Inode.i_extra_isize = le16_to_cpu(es->s_want_extra_isize); 2097 2098 /* Force using extent */ 2099 if (IsFlagOn(SUPER_BLOCK->s_feature_incompat, EXT4_FEATURE_INCOMPAT_EXTENTS)) { 2100 Inode.i_flags |= EXT2_EXTENTS_FL; 2101 ext4_ext_tree_init(IrpContext, NULL, &Inode); 2102 /* ext4_ext_tree_init will save inode body */ 2103 } else { 2104 /* save inode body to cache */ 2105 Ext2SaveInode(IrpContext, Vcb, &Inode); 2106 } 2107 2108 /* add new entry to its parent */ 2109 Status = Ext2AddEntry( 2110 IrpContext, 2111 Vcb, 2112 Parent, 2113 &Inode, 2114 FileName, 2115 &Dentry 2116 ); 2117 2118 if (!NT_SUCCESS(Status)) { 2119 DbgBreak(); 2120 Ext2FreeInode(IrpContext, Vcb, iNo, Type); 2121 goto errorout; 2122 } 2123 2124 DEBUG(DL_INF, ("Ext2CreateInode: New Inode = %xh (Type=%xh)\n", 2125 Inode.i_ino, Type)); 2126 2127 errorout: 2128 2129 if (Dentry) 2130 Ext2FreeEntry(Dentry); 2131 2132 return Status; 2133 } 2134 2135 2136 NTSTATUS 2137 Ext2SupersedeOrOverWriteFile( 2138 IN PEXT2_IRP_CONTEXT IrpContext, 2139 IN PFILE_OBJECT FileObject, 2140 IN PEXT2_VCB Vcb, 2141 IN PEXT2_FCB Fcb, 2142 IN PLARGE_INTEGER AllocationSize, 2143 IN ULONG Disposition 2144 ) 2145 { 2146 LARGE_INTEGER CurrentTime; 2147 LARGE_INTEGER Size; 2148 2149 KeQuerySystemTime(&CurrentTime); 2150 2151 Size.QuadPart = 0; 2152 if (!MmCanFileBeTruncated(&(Fcb->SectionObject), &(Size))) { 2153 return STATUS_USER_MAPPED_FILE; 2154 } 2155 2156 /* purge all file cache and shrink cache windows size */ 2157 CcPurgeCacheSection(&Fcb->SectionObject, NULL, 0, FALSE); 2158 Fcb->Header.AllocationSize.QuadPart = 2159 Fcb->Header.FileSize.QuadPart = 2160 Fcb->Header.ValidDataLength.QuadPart = 0; 2161 CcSetFileSizes(FileObject, 2162 (PCC_FILE_SIZES)&Fcb->Header.AllocationSize); 2163 2164 Size.QuadPart = CEILING_ALIGNED(ULONGLONG, 2165 (ULONGLONG)AllocationSize->QuadPart, 2166 (ULONGLONG)BLOCK_SIZE); 2167 2168 if ((loff_t)Size.QuadPart > Fcb->Inode->i_size) { 2169 Ext2ExpandFile(IrpContext, Vcb, Fcb->Mcb, &Size); 2170 } else { 2171 Ext2TruncateFile(IrpContext, Vcb, Fcb->Mcb, &Size); 2172 } 2173 2174 Fcb->Header.AllocationSize = Size; 2175 if (Fcb->Header.AllocationSize.QuadPart > 0) { 2176 SetLongFlag(Fcb->Flags, FCB_ALLOC_IN_CREATE); 2177 CcSetFileSizes(FileObject, 2178 (PCC_FILE_SIZES)&Fcb->Header.AllocationSize ); 2179 } 2180 2181 /* remove all extent mappings */ 2182 DEBUG(DL_EXT, ("Ext2SuperSede ...: %wZ\n", &Fcb->Mcb->FullName)); 2183 Fcb->Inode->i_size = 0; 2184 2185 if (Disposition == FILE_SUPERSEDE) { 2186 Fcb->Inode->i_ctime = Ext2LinuxTime(CurrentTime); 2187 } 2188 Fcb->Inode->i_atime = 2189 Fcb->Inode->i_mtime = Ext2LinuxTime(CurrentTime); 2190 Ext2SaveInode(IrpContext, Vcb, Fcb->Inode); 2191 2192 // See if we need to overwrite EA of the file 2193 return Ext2OverwriteEa(IrpContext, Vcb, Fcb, &IrpContext->Irp->IoStatus); 2194 } 2195