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