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 #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
nt_io_manager()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
_MapDosError(IN ULONG WinError)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
_MapNtStatus(IN NTSTATUS Status)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
_OpenNtName(IN PCSTR Name,IN BOOLEAN Readonly,OUT PHANDLE Handle,OUT PBOOLEAN OpenedReadonly OPTIONAL)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
_OpenDriveLetter(IN CHAR Letter,IN BOOLEAN ReadOnly,OUT PHANDLE Handle,OUT PBOOLEAN OpenedReadonly OPTIONAL)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
_FlushDrive(IN HANDLE Handle)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
_LockDrive(IN HANDLE Handle)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
_UnlockDrive(IN HANDLE Handle)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
_DismountDrive(IN HANDLE Handle)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
_IsMounted(IN HANDLE Handle)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
_CloseDisk(IN HANDLE Handle)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
_NormalizeDeviceName(IN PCSTR Device,IN PSTR NormalizedDeviceNameBuffer)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
_GetDeviceSize(IN HANDLE h,OUT unsigned __int64 * FsSize)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
_Ext2OpenDevice(IN PCSTR Name,IN BOOLEAN ReadOnly,OUT PHANDLE Handle,OUT PBOOLEAN OpenedReadonly OPTIONAL,OUT unsigned * Errno OPTIONAL)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
_BlockIo(IN HANDLE Handle,IN LARGE_INTEGER Offset,IN ULONG Bytes,IN OUT PCHAR Buffer,IN BOOLEAN Read,OUT unsigned * Errno)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
_RawWrite(IN HANDLE Handle,IN LARGE_INTEGER Offset,IN ULONG Bytes,OUT const CHAR * Buffer,OUT unsigned * Errno)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
_RawRead(IN HANDLE Handle,IN LARGE_INTEGER Offset,IN ULONG Bytes,IN PCHAR Buffer,OUT unsigned * Errno)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
_SetPartType(IN HANDLE Handle,IN UCHAR Type)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
ext2fs_check_if_mounted(const char * file,int * mount_flags)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
ext2fs_get_device_size(const char * file,int blocksize,blk_t * retblocks)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
nt_open(const char * name,int flags,io_channel * channel)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
nt_close(io_channel channel)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
nt_set_blksize(io_channel channel,int blksize)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
nt_read_blk(io_channel channel,unsigned long block,int count,void * buf)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
nt_write_blk(io_channel channel,unsigned long block,int count,const void * buf)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
nt_flush(io_channel channel)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