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