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