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