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