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@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 43NTSYSAPI 44ULONG 45NTAPI 46RtlNtStatusToDosError( 47 IN NTSTATUS Status 48 ); 49 50NTSYSAPI 51NTSTATUS 52NTAPI 53NtClose( 54 IN HANDLE Handle 55 ); 56 57 58NTSYSAPI 59NTSTATUS 60NTAPI 61NtOpenFile( 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 70NTSYSAPI 71NTSTATUS 72NTAPI 73NtFlushBuffersFile( 74 IN HANDLE FileHandle, 75 OUT PIO_STATUS_BLOCK IoStatusBlock 76 ); 77 78 79NTSYSAPI 80NTSTATUS 81NTAPI 82NtReadFile( 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 94NTSYSAPI 95NTSTATUS 96NTAPI 97NtWriteFile( 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 109NTSYSAPI 110NTSTATUS 111NTAPI 112NtDeviceIoControlFile( 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 125NTSYSAPI 126NTSTATUS 127NTAPI 128NtFsControlFile( 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 142NTSYSAPI 143NTSTATUS 144NTAPI 145NtDelayExecution( 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 206typedef 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 223static errcode_t nt_open(const char *name, int flags, io_channel *channel); 224static errcode_t nt_close(io_channel channel); 225static errcode_t nt_set_blksize(io_channel channel, int blksize); 226static errcode_t nt_read_blk(io_channel channel, unsigned long block, 227 int count, void *data); 228static errcode_t nt_write_blk(io_channel channel, unsigned long block, 229 int count, const void *data); 230static errcode_t nt_flush(io_channel channel); 231 232static 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 247io_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 260typedef struct { 261 ULONG WinError; 262 int errnocode; 263}ERROR_ENTRY; 264 265static 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 316static 317unsigned 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 366static 367__inline 368unsigned 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 384static 385NTSTATUS 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 492static 493NTSTATUS 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 513static 514__inline 515NTSTATUS 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 529static 530__inline 531NTSTATUS 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 545static 546__inline 547NTSTATUS 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 556static 557__inline 558NTSTATUS 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 572static 573__inline 574BOOLEAN 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 586static 587__inline 588NTSTATUS 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 603static 604PCSTR 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 745static 746VOID 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 811static 812BOOLEAN 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 886static 887BOOLEAN 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 942BOOLEAN 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 955BOOLEAN 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 970BOOLEAN 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 992errcode_t 993ext2fs_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 1022static __int64 FsSize = 0; 1023static char knowndevice[1024] = ""; 1024 1025 1026errcode_t 1027ext2fs_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 1072static 1073errcode_t 1074nt_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 1218static 1219errcode_t 1220nt_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 1263static 1264errcode_t 1265nt_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 1299static 1300errcode_t 1301nt_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 1381static 1382errcode_t 1383nt_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 1459static 1460errcode_t 1461nt_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