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