1 /* 2 * nt_io.c --- This is the Nt I/O interface to the I/O manager. 3 * 4 * Implements a one-block write-through cache. 5 * 6 * Copyright (C) 1993, 1994, 1995 Theodore Ts'o. 7 * Copyright (C) 1998 Andrey Shedel (andreys (at) ns.cr.cyco.com) 8 * 9 * %Begin-Header% 10 * This file may be redistributed under the terms of the GNU Library 11 * General Public License, version 2. 12 * %End-Header% 13 */ 14 15 #ifdef HAVE_CONFIG_H 16 #endif 17 18 19 // 20 // I need some warnings to disable... 21 // 22 23 24 #pragma warning(disable:4514) // unreferenced inline function has been removed 25 #pragma warning(push,4) 26 27 #pragma warning(disable:4201) // nonstandard extension used : nameless struct/union) 28 #pragma warning(disable:4214) // nonstandard extension used : bit field types other than int 29 #pragma warning(disable:4115) // named type definition in parentheses 30 31 #include <ntddk.h> 32 #include <ntdddisk.h> 33 #include <ntstatus.h> 34 35 #pragma warning(pop) 36 37 38 // 39 // Some native APIs. 40 // 41 42 NTSYSAPI 43 ULONG 44 NTAPI 45 RtlNtStatusToDosError( 46 IN NTSTATUS Status 47 ); 48 49 NTSYSAPI 50 NTSTATUS 51 NTAPI 52 NtClose( 53 IN HANDLE Handle 54 ); 55 56 57 NTSYSAPI 58 NTSTATUS 59 NTAPI 60 NtOpenFile( 61 OUT PHANDLE FileHandle, 62 IN ACCESS_MASK DesiredAccess, 63 IN POBJECT_ATTRIBUTES ObjectAttributes, 64 OUT PIO_STATUS_BLOCK IoStatusBlock, 65 IN ULONG ShareAccess, 66 IN ULONG OpenOptions 67 ); 68 69 NTSYSAPI 70 NTSTATUS 71 NTAPI 72 NtFlushBuffersFile( 73 IN HANDLE FileHandle, 74 OUT PIO_STATUS_BLOCK IoStatusBlock 75 ); 76 77 78 NTSYSAPI 79 NTSTATUS 80 NTAPI 81 NtReadFile( 82 IN HANDLE FileHandle, 83 IN HANDLE Event OPTIONAL, 84 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, 85 IN PVOID ApcContext OPTIONAL, 86 OUT PIO_STATUS_BLOCK IoStatusBlock, 87 OUT PVOID Buffer, 88 IN ULONG Length, 89 IN PLARGE_INTEGER ByteOffset OPTIONAL, 90 IN PULONG Key OPTIONAL 91 ); 92 93 NTSYSAPI 94 NTSTATUS 95 NTAPI 96 NtWriteFile( 97 IN HANDLE FileHandle, 98 IN HANDLE Event OPTIONAL, 99 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, 100 IN PVOID ApcContext OPTIONAL, 101 OUT PIO_STATUS_BLOCK IoStatusBlock, 102 IN PVOID Buffer, 103 IN ULONG Length, 104 IN PLARGE_INTEGER ByteOffset OPTIONAL, 105 IN PULONG Key OPTIONAL 106 ); 107 108 NTSYSAPI 109 NTSTATUS 110 NTAPI 111 NtDeviceIoControlFile( 112 IN HANDLE FileHandle, 113 IN HANDLE Event OPTIONAL, 114 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, 115 IN PVOID ApcContext OPTIONAL, 116 OUT PIO_STATUS_BLOCK IoStatusBlock, 117 IN ULONG IoControlCode, 118 IN PVOID InputBuffer OPTIONAL, 119 IN ULONG InputBufferLength, 120 OUT PVOID OutputBuffer OPTIONAL, 121 IN ULONG OutputBufferLength 122 ); 123 124 NTSYSAPI 125 NTSTATUS 126 NTAPI 127 NtFsControlFile( 128 IN HANDLE FileHandle, 129 IN HANDLE Event OPTIONAL, 130 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, 131 IN PVOID ApcContext OPTIONAL, 132 OUT PIO_STATUS_BLOCK IoStatusBlock, 133 IN ULONG IoControlCode, 134 IN PVOID InputBuffer OPTIONAL, 135 IN ULONG InputBufferLength, 136 OUT PVOID OutputBuffer OPTIONAL, 137 IN ULONG OutputBufferLength 138 ); 139 140 141 NTSYSAPI 142 NTSTATUS 143 NTAPI 144 NtDelayExecution( 145 IN BOOLEAN Alertable, 146 IN PLARGE_INTEGER Interval 147 ); 148 149 150 #define FSCTL_LOCK_VOLUME CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 6, METHOD_BUFFERED, FILE_ANY_ACCESS) 151 #define FSCTL_UNLOCK_VOLUME CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 7, METHOD_BUFFERED, FILE_ANY_ACCESS) 152 #define FSCTL_DISMOUNT_VOLUME CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 8, METHOD_BUFFERED, FILE_ANY_ACCESS) 153 #define FSCTL_IS_VOLUME_MOUNTED CTL_CODE(FILE_DEVICE_FILE_SYSTEM,10, METHOD_BUFFERED, FILE_ANY_ACCESS) 154 155 156 // 157 // useful macros 158 // 159 160 #define BooleanFlagOn(Flags,SingleFlag) ((BOOLEAN)((((Flags) & (SingleFlag)) != 0))) 161 162 163 // 164 // Include Win32 error codes. 165 // 166 167 #include <winerror.h> 168 169 // 170 // standard stuff 171 // 172 173 #include <assert.h> 174 #include <stdio.h> 175 #include <string.h> 176 #include <stdlib.h> 177 #include <malloc.h> 178 179 #include <linux/types.h> 180 #include "ext2_fs.h" 181 #include <errno.h> 182 183 #include "et/com_err.h" 184 #include "ext2fs/ext2fs.h" 185 #include "ext2fs/ext2_err.h" 186 187 188 189 190 // 191 // For checking structure magic numbers... 192 // 193 194 195 #define EXT2_CHECK_MAGIC(struct, code) \ 196 if ((struct)->magic != (code)) return (code) 197 198 #define EXT2_ET_MAGIC_NT_IO_CHANNEL 0x10ed 199 200 201 // 202 // Private data block 203 // 204 205 typedef struct _NT_PRIVATE_DATA { 206 int magic; 207 HANDLE Handle; 208 int Flags; 209 PCHAR Buffer; 210 __u32 BufferBlockNumber; 211 ULONG BufferSize; 212 BOOLEAN OpenedReadonly; 213 BOOLEAN Written; 214 }NT_PRIVATE_DATA, *PNT_PRIVATE_DATA; 215 216 217 218 // 219 // Standard interface prototypes 220 // 221 222 static errcode_t nt_open(const char *name, int flags, io_channel *channel); 223 static errcode_t nt_close(io_channel channel); 224 static errcode_t nt_set_blksize(io_channel channel, int blksize); 225 static errcode_t nt_read_blk(io_channel channel, unsigned long block, 226 int count, void *data); 227 static errcode_t nt_write_blk(io_channel channel, unsigned long block, 228 int count, const void *data); 229 static errcode_t nt_flush(io_channel channel); 230 231 static struct struct_io_manager struct_nt_manager = { 232 EXT2_ET_MAGIC_IO_MANAGER, 233 "NT I/O Manager", 234 nt_open, 235 nt_close, 236 nt_set_blksize, 237 nt_read_blk, 238 nt_write_blk, 239 nt_flush 240 }; 241 242 243 244 // 245 // function to get API 246 // 247 248 io_manager nt_io_manager() 249 { 250 return &struct_nt_manager; 251 } 252 253 254 255 256 257 // 258 // This is a code to convert Win32 errors to unix errno 259 // 260 261 typedef struct { 262 ULONG WinError; 263 int errnocode; 264 }ERROR_ENTRY; 265 266 static ERROR_ENTRY ErrorTable[] = { 267 { ERROR_INVALID_FUNCTION, EINVAL }, 268 { ERROR_FILE_NOT_FOUND, ENOENT }, 269 { ERROR_PATH_NOT_FOUND, ENOENT }, 270 { ERROR_TOO_MANY_OPEN_FILES, EMFILE }, 271 { ERROR_ACCESS_DENIED, EACCES }, 272 { ERROR_INVALID_HANDLE, EBADF }, 273 { ERROR_ARENA_TRASHED, ENOMEM }, 274 { ERROR_NOT_ENOUGH_MEMORY, ENOMEM }, 275 { ERROR_INVALID_BLOCK, ENOMEM }, 276 { ERROR_BAD_ENVIRONMENT, E2BIG }, 277 { ERROR_BAD_FORMAT, ENOEXEC }, 278 { ERROR_INVALID_ACCESS, EINVAL }, 279 { ERROR_INVALID_DATA, EINVAL }, 280 { ERROR_INVALID_DRIVE, ENOENT }, 281 { ERROR_CURRENT_DIRECTORY, EACCES }, 282 { ERROR_NOT_SAME_DEVICE, EXDEV }, 283 { ERROR_NO_MORE_FILES, ENOENT }, 284 { ERROR_LOCK_VIOLATION, EACCES }, 285 { ERROR_BAD_NETPATH, ENOENT }, 286 { ERROR_NETWORK_ACCESS_DENIED, EACCES }, 287 { ERROR_BAD_NET_NAME, ENOENT }, 288 { ERROR_FILE_EXISTS, EEXIST }, 289 { ERROR_CANNOT_MAKE, EACCES }, 290 { ERROR_FAIL_I24, EACCES }, 291 { ERROR_INVALID_PARAMETER, EINVAL }, 292 { ERROR_NO_PROC_SLOTS, EAGAIN }, 293 { ERROR_DRIVE_LOCKED, EACCES }, 294 { ERROR_BROKEN_PIPE, EPIPE }, 295 { ERROR_DISK_FULL, ENOSPC }, 296 { ERROR_INVALID_TARGET_HANDLE, EBADF }, 297 { ERROR_INVALID_HANDLE, EINVAL }, 298 { ERROR_WAIT_NO_CHILDREN, ECHILD }, 299 { ERROR_CHILD_NOT_COMPLETE, ECHILD }, 300 { ERROR_DIRECT_ACCESS_HANDLE, EBADF }, 301 { ERROR_NEGATIVE_SEEK, EINVAL }, 302 { ERROR_SEEK_ON_DEVICE, EACCES }, 303 { ERROR_DIR_NOT_EMPTY, ENOTEMPTY }, 304 { ERROR_NOT_LOCKED, EACCES }, 305 { ERROR_BAD_PATHNAME, ENOENT }, 306 { ERROR_MAX_THRDS_REACHED, EAGAIN }, 307 { ERROR_LOCK_FAILED, EACCES }, 308 { ERROR_ALREADY_EXISTS, EEXIST }, 309 { ERROR_FILENAME_EXCED_RANGE, ENOENT }, 310 { ERROR_NESTING_NOT_ALLOWED, EAGAIN }, 311 { ERROR_NOT_ENOUGH_QUOTA, ENOMEM } 312 }; 313 314 315 316 317 static 318 unsigned 319 _MapDosError ( 320 IN ULONG WinError 321 ) 322 { 323 int i; 324 325 // 326 // Lookup 327 // 328 329 for (i = 0; i < (sizeof(ErrorTable)/sizeof(ErrorTable[0])); ++i) 330 { 331 if (WinError == ErrorTable[i].WinError) 332 { 333 return ErrorTable[i].errnocode; 334 } 335 } 336 337 // 338 // not in table. Check ranges 339 // 340 341 if ((WinError >= ERROR_WRITE_PROTECT) && 342 (WinError <= ERROR_SHARING_BUFFER_EXCEEDED)) 343 { 344 return EACCES; 345 } 346 else if ((WinError >= ERROR_INVALID_STARTING_CODESEG) && 347 (WinError <= ERROR_INFLOOP_IN_RELOC_CHAIN)) 348 { 349 return ENOEXEC; 350 } 351 else 352 { 353 return EINVAL; 354 } 355 } 356 357 358 359 360 361 362 363 // 364 // Function to map NT status to dos error. 365 // 366 367 static 368 __inline 369 unsigned 370 _MapNtStatus( 371 IN NTSTATUS Status 372 ) 373 { 374 return _MapDosError(RtlNtStatusToDosError(Status)); 375 } 376 377 378 379 380 381 // 382 // Helper functions to make things easyer 383 // 384 385 static 386 NTSTATUS 387 _OpenNtName( 388 IN PCSTR Name, 389 IN BOOLEAN Readonly, 390 OUT PHANDLE Handle, 391 OUT PBOOLEAN OpenedReadonly OPTIONAL 392 ) 393 { 394 UNICODE_STRING UnicodeString; 395 ANSI_STRING AnsiString; 396 WCHAR Buffer[512]; 397 NTSTATUS Status; 398 OBJECT_ATTRIBUTES ObjectAttributes; 399 IO_STATUS_BLOCK IoStatusBlock; 400 401 // 402 // Make Unicode name from inlut string 403 // 404 405 UnicodeString.Buffer = &Buffer[0]; 406 UnicodeString.Length = 0; 407 UnicodeString.MaximumLength = sizeof(Buffer); // in bytes!!! 408 409 RtlInitAnsiString(&AnsiString, Name); 410 411 Status = RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, FALSE); 412 413 if(!NT_SUCCESS(Status)) 414 { 415 return Status; // Unpappable character? 416 } 417 418 // 419 // Initialize object 420 // 421 422 InitializeObjectAttributes(&ObjectAttributes, 423 &UnicodeString, 424 OBJ_CASE_INSENSITIVE, 425 NULL, 426 NULL ); 427 428 // 429 // Try to open it in initial mode 430 // 431 432 if(ARGUMENT_PRESENT(OpenedReadonly)) 433 { 434 *OpenedReadonly = Readonly; 435 } 436 437 438 Status = NtOpenFile(Handle, 439 SYNCHRONIZE | FILE_READ_DATA | (Readonly ? 0 : FILE_WRITE_DATA), 440 &ObjectAttributes, 441 &IoStatusBlock, 442 FILE_SHARE_WRITE | FILE_SHARE_READ, 443 FILE_SYNCHRONOUS_IO_NONALERT); 444 445 if(!NT_SUCCESS(Status)) 446 { 447 // 448 // Maybe was just mounted? wait 0.5 sec and retry. 449 // 450 451 LARGE_INTEGER Interval; 452 Interval.QuadPart = -5000000; // 0.5 sec. from now 453 454 NtDelayExecution(FALSE, &Interval); 455 456 Status = NtOpenFile(Handle, 457 SYNCHRONIZE | FILE_READ_DATA | (Readonly ? 0 : FILE_WRITE_DATA), 458 &ObjectAttributes, 459 &IoStatusBlock, 460 FILE_SHARE_WRITE | FILE_SHARE_READ, 461 FILE_SYNCHRONOUS_IO_NONALERT); 462 463 // 464 // Try to satisfy mode 465 // 466 467 if((STATUS_ACCESS_DENIED == Status) && !Readonly) 468 { 469 if(ARGUMENT_PRESENT(OpenedReadonly)) 470 { 471 *OpenedReadonly = TRUE; 472 } 473 474 Status = NtOpenFile(Handle, 475 SYNCHRONIZE | FILE_READ_DATA, 476 &ObjectAttributes, 477 &IoStatusBlock, 478 FILE_SHARE_WRITE | FILE_SHARE_READ, 479 FILE_SYNCHRONOUS_IO_NONALERT); 480 } 481 } 482 483 484 485 // 486 // done 487 // 488 489 return Status; 490 } 491 492 493 static 494 NTSTATUS 495 _OpenDriveLetter( 496 IN CHAR Letter, 497 IN BOOLEAN ReadOnly, 498 OUT PHANDLE Handle, 499 OUT PBOOLEAN OpenedReadonly OPTIONAL 500 ) 501 { 502 CHAR Buffer[100]; 503 504 sprintf(Buffer, "\\DosDevices\\%c:", Letter); 505 506 return _OpenNtName(Buffer, ReadOnly, Handle, OpenedReadonly); 507 } 508 509 510 // 511 // Flush device 512 // 513 514 static 515 __inline 516 NTSTATUS 517 _FlushDrive( 518 IN HANDLE Handle 519 ) 520 { 521 IO_STATUS_BLOCK IoStatusBlock; 522 return NtFlushBuffersFile(Handle, &IoStatusBlock); 523 } 524 525 526 // 527 // lock drive 528 // 529 530 static 531 __inline 532 NTSTATUS 533 _LockDrive( 534 IN HANDLE Handle 535 ) 536 { 537 IO_STATUS_BLOCK IoStatusBlock; 538 return NtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_LOCK_VOLUME, 0, 0, 0, 0); 539 } 540 541 542 // 543 // unlock drive 544 // 545 546 static 547 __inline 548 NTSTATUS 549 _UnlockDrive( 550 IN HANDLE Handle 551 ) 552 { 553 IO_STATUS_BLOCK IoStatusBlock; 554 return NtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_UNLOCK_VOLUME, 0, 0, 0, 0); 555 } 556 557 static 558 __inline 559 NTSTATUS 560 _DismountDrive( 561 IN HANDLE Handle 562 ) 563 { 564 IO_STATUS_BLOCK IoStatusBlock; 565 return NtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_DISMOUNT_VOLUME, 0, 0, 0, 0); 566 } 567 568 569 // 570 // is mounted 571 // 572 573 static 574 __inline 575 BOOLEAN 576 _IsMounted( 577 IN HANDLE Handle 578 ) 579 { 580 IO_STATUS_BLOCK IoStatusBlock; 581 NTSTATUS Status; 582 Status = NtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_IS_VOLUME_MOUNTED, 0, 0, 0, 0); 583 return (BOOLEAN)(STATUS_SUCCESS == Status); 584 } 585 586 587 static 588 __inline 589 NTSTATUS 590 _CloseDisk( 591 IN HANDLE Handle 592 ) 593 { 594 return NtClose(Handle); 595 } 596 597 598 599 600 // 601 // Make NT name from any recognized name 602 // 603 604 static 605 PCSTR 606 _NormalizeDeviceName( 607 IN PCSTR Device, 608 IN PSTR NormalizedDeviceNameBuffer 609 ) 610 { 611 int PartitionNumber = -1; 612 UCHAR DiskNumber; 613 PSTR p; 614 615 616 // 617 // Do not try to parse NT name 618 // 619 620 if('\\' == *Device) 621 return Device; 622 623 624 625 // 626 // Strip leading '/dev/' if any 627 // 628 629 if(('/' == *(Device)) && 630 ('d' == *(Device + 1)) && 631 ('e' == *(Device + 2)) && 632 ('v' == *(Device + 3)) && 633 ('/' == *(Device + 4))) 634 { 635 Device += 5; 636 } 637 638 if('\0' == *Device) 639 { 640 return NULL; 641 } 642 643 644 // 645 // forms: hda[n], fd[n] 646 // 647 648 if('d' != *(Device + 1)) 649 { 650 return NULL; 651 } 652 653 if('h' == *Device) 654 { 655 if((*(Device + 2) < 'a') || (*(Device + 2) > ('a' + 9)) || 656 ((*(Device + 3) != '\0') && 657 ((*(Device + 4) != '\0') || 658 ((*(Device + 3) < '0') || (*(Device + 3) > '9')) 659 ) 660 ) 661 ) 662 { 663 return NULL; 664 } 665 666 DiskNumber = (UCHAR)(*(Device + 2) - 'a'); 667 668 if(*(Device + 3) != '\0') 669 { 670 PartitionNumber = (*(Device + 3) - '0'); 671 } 672 673 } 674 else if('f' == *Device) 675 { 676 // 677 // 3-d letted should be a digit. 678 // 679 680 if((*(Device + 3) != '\0') || 681 (*(Device + 2) < '0') || (*(Device + 2) > '9')) 682 { 683 return NULL; 684 } 685 686 DiskNumber = (UCHAR)(*(Device + 2) - '0'); 687 688 } 689 else 690 { 691 // 692 // invalid prefix 693 // 694 695 return NULL; 696 } 697 698 699 700 // 701 // Prefix 702 // 703 704 strcpy(NormalizedDeviceNameBuffer, "\\Device\\"); 705 706 // 707 // Media name 708 // 709 710 switch(*Device) 711 { 712 713 case 'f': 714 strcat(NormalizedDeviceNameBuffer, "Floppy0"); 715 break; 716 717 case 'h': 718 strcat(NormalizedDeviceNameBuffer, "Harddisk0"); 719 break; 720 } 721 722 723 p = NormalizedDeviceNameBuffer + strlen(NormalizedDeviceNameBuffer) - 1; 724 *p = (CHAR)(*p + DiskNumber); 725 726 727 // 728 // Partition nr. 729 // 730 731 if(PartitionNumber >= 0) 732 { 733 strcat(NormalizedDeviceNameBuffer, "\\Partition0"); 734 735 p = NormalizedDeviceNameBuffer + strlen(NormalizedDeviceNameBuffer) - 1; 736 *p = (CHAR)(*p + PartitionNumber); 737 } 738 739 740 return NormalizedDeviceNameBuffer; 741 } 742 743 744 745 746 static 747 VOID 748 _GetDeviceSize( 749 IN HANDLE h, 750 OUT unsigned __int64 *FsSize 751 ) 752 { 753 PARTITION_INFORMATION pi; 754 DISK_GEOMETRY gi; 755 NTSTATUS Status; 756 IO_STATUS_BLOCK IoStatusBlock; 757 758 // 759 // Zero it 760 // 761 762 *FsSize = 0; 763 764 // 765 // Call driver 766 // 767 768 RtlZeroMemory(&pi, sizeof(PARTITION_INFORMATION)); 769 770 Status = NtDeviceIoControlFile( 771 h, NULL, NULL, NULL, &IoStatusBlock, IOCTL_DISK_GET_PARTITION_INFO, 772 &pi, sizeof(PARTITION_INFORMATION), 773 &pi, sizeof(PARTITION_INFORMATION)); 774 775 776 if(NT_SUCCESS(Status)) 777 { 778 *FsSize = pi.PartitionLength.QuadPart; 779 } 780 else if(STATUS_INVALID_DEVICE_REQUEST == Status) 781 { 782 // 783 // No partitions: get device info. 784 // 785 786 RtlZeroMemory(&gi, sizeof(DISK_GEOMETRY)); 787 788 Status = NtDeviceIoControlFile( 789 h, NULL, NULL, NULL, &IoStatusBlock, IOCTL_DISK_GET_DRIVE_GEOMETRY, 790 &gi, sizeof(DISK_GEOMETRY), 791 &gi, sizeof(DISK_GEOMETRY)); 792 793 794 if(NT_SUCCESS(Status)) 795 { 796 *FsSize = 797 gi.BytesPerSector * 798 gi.SectorsPerTrack * 799 gi.TracksPerCylinder * 800 gi.Cylinders.QuadPart; 801 } 802 803 } 804 } 805 806 807 808 // 809 // Open device by name. 810 // 811 812 static 813 BOOLEAN 814 _Ext2OpenDevice( 815 IN PCSTR Name, 816 IN BOOLEAN ReadOnly, 817 OUT PHANDLE Handle, 818 OUT PBOOLEAN OpenedReadonly OPTIONAL, 819 OUT unsigned *Errno OPTIONAL 820 ) 821 { 822 CHAR NormalizedDeviceName[512]; 823 NTSTATUS Status; 824 825 if(NULL == Name) 826 { 827 // 828 // Set not found 829 // 830 831 if(ARGUMENT_PRESENT(Errno)) 832 *Errno = ENOENT; 833 834 return FALSE; 835 } 836 837 838 if((((*Name) | 0x20) >= 'a') && (((*Name) | 0x20) <= 'z') && 839 (':' == *(Name + 1)) && ('\0' == *(Name + 2))) 840 { 841 Status = _OpenDriveLetter(*Name, ReadOnly, Handle, OpenedReadonly); 842 } 843 else 844 { 845 // 846 // Make name 847 // 848 849 Name = _NormalizeDeviceName(Name, NormalizedDeviceName); 850 851 if(NULL == Name) 852 { 853 // 854 // Set not found 855 // 856 857 if(ARGUMENT_PRESENT(Errno)) 858 *Errno = ENOENT; 859 860 return FALSE; 861 } 862 863 // 864 // Try to open it 865 // 866 867 Status = _OpenNtName(Name, ReadOnly, Handle, OpenedReadonly); 868 } 869 870 871 if(!NT_SUCCESS(Status)) 872 { 873 if(ARGUMENT_PRESENT(Errno)) 874 *Errno = _MapNtStatus(Status); 875 876 return FALSE; 877 } 878 879 return TRUE; 880 } 881 882 883 // 884 // Raw block io. Sets dos errno 885 // 886 887 static 888 BOOLEAN 889 _BlockIo( 890 IN HANDLE Handle, 891 IN LARGE_INTEGER Offset, 892 IN ULONG Bytes, 893 IN OUT PCHAR Buffer, 894 IN BOOLEAN Read, 895 OUT unsigned* Errno 896 ) 897 { 898 IO_STATUS_BLOCK IoStatusBlock; 899 NTSTATUS Status; 900 901 // 902 // Should be aligned 903 // 904 905 ASSERT(0 == (Bytes % 512)); 906 ASSERT(0 == (Offset.LowPart % 512)); 907 908 909 // 910 // perform io 911 // 912 913 if(Read) 914 { 915 Status = NtReadFile(Handle, NULL, NULL, NULL, 916 &IoStatusBlock, Buffer, Bytes, &Offset, NULL); 917 } 918 else 919 { 920 Status = NtWriteFile(Handle, NULL, NULL, NULL, 921 &IoStatusBlock, Buffer, Bytes, &Offset, NULL); 922 } 923 924 925 // 926 // translate error 927 // 928 929 if(NT_SUCCESS(Status)) 930 { 931 *Errno = 0; 932 return TRUE; 933 } 934 935 *Errno = _MapNtStatus(Status); 936 937 return FALSE; 938 } 939 940 941 942 __inline 943 BOOLEAN 944 _RawWrite( 945 IN HANDLE Handle, 946 IN LARGE_INTEGER Offset, 947 IN ULONG Bytes, 948 OUT const CHAR* Buffer, 949 OUT unsigned* Errno 950 ) 951 { 952 return _BlockIo(Handle, Offset, Bytes, (PCHAR)Buffer, FALSE, Errno); 953 } 954 955 __inline 956 BOOLEAN 957 _RawRead( 958 IN HANDLE Handle, 959 IN LARGE_INTEGER Offset, 960 IN ULONG Bytes, 961 IN PCHAR Buffer, 962 OUT unsigned* Errno 963 ) 964 { 965 return _BlockIo(Handle, Offset, Bytes, Buffer, TRUE, Errno); 966 } 967 968 969 970 __inline 971 BOOLEAN 972 _SetPartType( 973 IN HANDLE Handle, 974 IN UCHAR Type 975 ) 976 { 977 IO_STATUS_BLOCK IoStatusBlock; 978 return STATUS_SUCCESS == NtDeviceIoControlFile( 979 Handle, NULL, NULL, NULL, &IoStatusBlock, IOCTL_DISK_SET_PARTITION_INFO, 980 &Type, sizeof(Type), 981 NULL, 0); 982 } 983 984 985 986 //--------------------- interface part 987 988 // 989 // Interface functions. 990 // Is_mounted is set to 1 if the device is mounted, 0 otherwise 991 // 992 993 errcode_t 994 ext2fs_check_if_mounted(const char *file, int *mount_flags) 995 { 996 HANDLE h; 997 BOOLEAN Readonly; 998 999 *mount_flags = 0; 1000 1001 if(!_Ext2OpenDevice(file, TRUE, &h, &Readonly, NULL)) 1002 { 1003 return 0; 1004 } 1005 1006 1007 __try{ 1008 *mount_flags &= _IsMounted(h) ? EXT2_MF_MOUNTED : 0; 1009 } 1010 __finally{ 1011 _CloseDisk(h); 1012 } 1013 1014 return 0; 1015 } 1016 1017 1018 1019 // 1020 // Returns the number of blocks in a partition 1021 // 1022 1023 static __int64 FsSize = 0; 1024 static char knowndevice[1024] = ""; 1025 1026 1027 errcode_t 1028 ext2fs_get_device_size(const char *file, int blocksize, 1029 blk_t *retblocks) 1030 { 1031 HANDLE h; 1032 BOOLEAN Readonly; 1033 1034 if((0 == FsSize) || (0 != strcmp(knowndevice, file))) 1035 { 1036 1037 if(!_Ext2OpenDevice(file, TRUE, &h, &Readonly, NULL)) 1038 { 1039 return 0; 1040 } 1041 1042 1043 __try{ 1044 1045 // 1046 // Get size 1047 // 1048 1049 _GetDeviceSize(h, &FsSize); 1050 strcpy(knowndevice, file); 1051 } 1052 __finally{ 1053 _CloseDisk(h); 1054 } 1055 1056 } 1057 1058 *retblocks = (blk_t)(unsigned __int64)(FsSize / blocksize); 1059 UNREFERENCED_PARAMETER(file); 1060 return 0; 1061 } 1062 1063 1064 1065 1066 1067 1068 // 1069 // Table elements 1070 // 1071 1072 1073 static 1074 errcode_t 1075 nt_open(const char *name, int flags, io_channel *channel) 1076 { 1077 io_channel io = NULL; 1078 PNT_PRIVATE_DATA NtData = NULL; 1079 errcode_t Errno = 0; 1080 1081 // 1082 // Check name 1083 // 1084 1085 if (NULL == name) 1086 { 1087 return EXT2_ET_BAD_DEVICE_NAME; 1088 } 1089 1090 __try{ 1091 1092 // 1093 // Allocate channel handle 1094 // 1095 1096 io = (io_channel) malloc(sizeof(struct struct_io_channel)); 1097 1098 if (NULL == io) 1099 { 1100 Errno = ENOMEM; 1101 __leave; 1102 } 1103 1104 RtlZeroMemory(io, sizeof(struct struct_io_channel)); 1105 io->magic = EXT2_ET_MAGIC_IO_CHANNEL; 1106 1107 NtData = (PNT_PRIVATE_DATA)malloc(sizeof(NT_PRIVATE_DATA)); 1108 1109 if (NULL == NtData) 1110 { 1111 Errno = ENOMEM; 1112 __leave; 1113 } 1114 1115 1116 io->manager = nt_io_manager(); 1117 io->name = malloc(strlen(name) + 1); 1118 if (NULL == io->name) 1119 { 1120 Errno = ENOMEM; 1121 __leave; 1122 } 1123 1124 strcpy(io->name, name); 1125 io->private_data = NtData; 1126 io->block_size = 1024; 1127 io->read_error = 0; 1128 io->write_error = 0; 1129 io->refcount = 1; 1130 1131 // 1132 // Initialize data 1133 // 1134 1135 RtlZeroMemory(NtData, sizeof(NT_PRIVATE_DATA)); 1136 1137 NtData->magic = EXT2_ET_MAGIC_NT_IO_CHANNEL; 1138 NtData->BufferBlockNumber = 0xffffffff; 1139 NtData->BufferSize = 1024; 1140 NtData->Buffer = malloc(NtData->BufferSize); 1141 1142 if (NULL == NtData->Buffer) 1143 { 1144 Errno = ENOMEM; 1145 __leave; 1146 } 1147 1148 // 1149 // Open it 1150 // 1151 1152 if(!_Ext2OpenDevice(name, (BOOLEAN)!BooleanFlagOn(flags, EXT2_FLAG_RW), &NtData->Handle, &NtData->OpenedReadonly, &Errno)) 1153 { 1154 __leave; 1155 } 1156 1157 1158 // 1159 // get size 1160 // 1161 1162 _GetDeviceSize(NtData->Handle, &FsSize); 1163 strcpy(knowndevice, name); 1164 1165 1166 // 1167 // Lock/dismount 1168 // 1169 1170 if(!NT_SUCCESS(_LockDrive(NtData->Handle)) /*|| !NT_SUCCESS(_DismountDrive(NtData->Handle))*/) 1171 { 1172 NtData->OpenedReadonly = TRUE; 1173 } 1174 1175 // 1176 // Done 1177 // 1178 1179 *channel = io; 1180 1181 1182 } 1183 __finally{ 1184 1185 if(0 != Errno) 1186 { 1187 // 1188 // Cleanup 1189 // 1190 1191 if (NULL != io) 1192 { 1193 free(io->name); 1194 free(io); 1195 } 1196 1197 if (NULL != NtData) 1198 { 1199 if(NULL != NtData->Handle) 1200 { 1201 _UnlockDrive(NtData->Handle); 1202 _CloseDisk(NtData->Handle); 1203 } 1204 1205 free(NtData->Buffer); 1206 free(NtData); 1207 } 1208 } 1209 } 1210 1211 return Errno; 1212 } 1213 1214 1215 // 1216 // Close api 1217 // 1218 1219 static 1220 errcode_t 1221 nt_close(io_channel channel) 1222 { 1223 PNT_PRIVATE_DATA NtData = NULL; 1224 1225 if(NULL == channel) 1226 { 1227 return 0; 1228 } 1229 1230 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 1231 NtData = (PNT_PRIVATE_DATA) channel->private_data; 1232 EXT2_CHECK_MAGIC(NtData, EXT2_ET_MAGIC_NT_IO_CHANNEL); 1233 1234 if (--channel->refcount > 0) 1235 { 1236 return 0; 1237 } 1238 1239 free(channel->name); 1240 free(channel); 1241 1242 if (NULL != NtData) 1243 { 1244 if(NULL != NtData->Handle) 1245 { 1246 _DismountDrive(NtData->Handle); 1247 _UnlockDrive(NtData->Handle); 1248 _CloseDisk(NtData->Handle); 1249 } 1250 1251 free(NtData->Buffer); 1252 free(NtData); 1253 } 1254 1255 return 0; 1256 } 1257 1258 1259 1260 // 1261 // set block size 1262 // 1263 1264 static 1265 errcode_t 1266 nt_set_blksize(io_channel channel, int blksize) 1267 { 1268 PNT_PRIVATE_DATA NtData = NULL; 1269 1270 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 1271 NtData = (PNT_PRIVATE_DATA) channel->private_data; 1272 EXT2_CHECK_MAGIC(NtData, EXT2_ET_MAGIC_NT_IO_CHANNEL); 1273 1274 if (channel->block_size != blksize) 1275 { 1276 channel->block_size = blksize; 1277 1278 free(NtData->Buffer); 1279 NtData->BufferBlockNumber = 0xffffffff; 1280 NtData->BufferSize = channel->block_size; 1281 ASSERT(0 == (NtData->BufferSize % 512)); 1282 1283 NtData->Buffer = malloc(NtData->BufferSize); 1284 1285 if (NULL == NtData->Buffer) 1286 { 1287 return ENOMEM; 1288 } 1289 1290 } 1291 1292 return 0; 1293 } 1294 1295 1296 // 1297 // read block 1298 // 1299 1300 static 1301 errcode_t 1302 nt_read_blk(io_channel channel, unsigned long block, 1303 int count, void *buf) 1304 { 1305 PVOID BufferToRead; 1306 ULONG SizeToRead; 1307 ULONG Size; 1308 LARGE_INTEGER Offset; 1309 PNT_PRIVATE_DATA NtData = NULL; 1310 unsigned Errno = 0; 1311 1312 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 1313 NtData = (PNT_PRIVATE_DATA) channel->private_data; 1314 EXT2_CHECK_MAGIC(NtData, EXT2_ET_MAGIC_NT_IO_CHANNEL); 1315 1316 // 1317 // If it's in the cache, use it! 1318 // 1319 1320 if ((1 == count) && 1321 (block == NtData->BufferBlockNumber) && 1322 (NtData->BufferBlockNumber != 0xffffffff)) 1323 { 1324 memcpy(buf, NtData->Buffer, channel->block_size); 1325 return 0; 1326 } 1327 1328 Size = (count < 0) ? (ULONG)(-count) : (ULONG)(count * channel->block_size); 1329 1330 Offset.QuadPart = block * channel->block_size; 1331 1332 // 1333 // If not fit to the block 1334 // 1335 1336 if(Size <= NtData->BufferSize) 1337 { 1338 // 1339 // Update the cache 1340 // 1341 1342 NtData->BufferBlockNumber = block; 1343 BufferToRead = NtData->Buffer; 1344 SizeToRead = NtData->BufferSize; 1345 } 1346 else 1347 { 1348 SizeToRead = Size; 1349 BufferToRead = buf; 1350 ASSERT(0 == (SizeToRead % channel->block_size)); 1351 } 1352 1353 if(!_RawRead(NtData->Handle, Offset, SizeToRead, BufferToRead, &Errno)) 1354 { 1355 1356 if (channel->read_error) 1357 { 1358 return (channel->read_error)(channel, block, count, buf, 1359 Size, 0, Errno); 1360 } 1361 else 1362 { 1363 return Errno; 1364 } 1365 } 1366 1367 1368 if(BufferToRead != buf) 1369 { 1370 ASSERT(Size <= SizeToRead); 1371 memcpy(buf, BufferToRead, Size); 1372 } 1373 1374 return 0; 1375 } 1376 1377 1378 // 1379 // write block 1380 // 1381 1382 static 1383 errcode_t 1384 nt_write_blk(io_channel channel, unsigned long block, 1385 int count, const void *buf) 1386 { 1387 ULONG SizeToWrite; 1388 LARGE_INTEGER Offset; 1389 PNT_PRIVATE_DATA NtData = NULL; 1390 unsigned Errno = 0; 1391 1392 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 1393 NtData = (PNT_PRIVATE_DATA) channel->private_data; 1394 EXT2_CHECK_MAGIC(NtData, EXT2_ET_MAGIC_NT_IO_CHANNEL); 1395 1396 if(NtData->OpenedReadonly) 1397 { 1398 return EACCES; 1399 } 1400 1401 if (count == 1) 1402 { 1403 SizeToWrite = channel->block_size; 1404 } 1405 else 1406 { 1407 NtData->BufferBlockNumber = 0xffffffff; 1408 1409 if (count < 0) 1410 { 1411 SizeToWrite = (ULONG)(-count); 1412 } 1413 else 1414 { 1415 SizeToWrite = (ULONG)(count * channel->block_size); 1416 } 1417 } 1418 1419 1420 ASSERT(0 == (SizeToWrite % 512)); 1421 Offset.QuadPart = block * channel->block_size; 1422 1423 if(!_RawWrite(NtData->Handle, Offset, SizeToWrite, buf, &Errno)) 1424 { 1425 if (channel->write_error) 1426 { 1427 return (channel->write_error)(channel, block, count, buf, 1428 SizeToWrite, 0, Errno); 1429 } 1430 else 1431 { 1432 return Errno; 1433 } 1434 } 1435 1436 1437 // 1438 // Stash a copy. 1439 // 1440 1441 if(SizeToWrite >= NtData->BufferSize) 1442 { 1443 NtData->BufferBlockNumber = block; 1444 memcpy(NtData->Buffer, buf, NtData->BufferSize); 1445 } 1446 1447 NtData->Written = TRUE; 1448 1449 return 0; 1450 1451 } 1452 1453 1454 1455 // 1456 // Flush data buffers to disk. Since we are currently using a 1457 // write-through cache, this is a no-op. 1458 // 1459 1460 static 1461 errcode_t 1462 nt_flush(io_channel channel) 1463 { 1464 PNT_PRIVATE_DATA NtData = NULL; 1465 1466 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 1467 NtData = (PNT_PRIVATE_DATA) channel->private_data; 1468 EXT2_CHECK_MAGIC(NtData, EXT2_ET_MAGIC_NT_IO_CHANNEL); 1469 1470 if(NtData->OpenedReadonly) 1471 { 1472 return 0; // EACCESS; 1473 } 1474 1475 1476 // 1477 // Flush file buffers. 1478 // 1479 1480 _FlushDrive(NtData->Handle); 1481 1482 1483 // 1484 // Test and correct partition type. 1485 // 1486 1487 if(NtData->Written) 1488 { 1489 _SetPartType(NtData->Handle, 0x83); 1490 } 1491 1492 return 0; 1493 } 1494 1495 1496