]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blame - lib/ext2fs/nt_io.c
Merge remote-tracking branch 'josch/libarchive' into josch-libarchive
[thirdparty/e2fsprogs.git] / lib / ext2fs / nt_io.c
CommitLineData
aa4115a4
TT
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.
00ab0435 7 * Copyright (C) 1998 Andrey Shedel (andreys@ns.cr.cyco.com)
aa4115a4
TT
8 *
9 * %Begin-Header%
543547a5
TT
10 * This file may be redistributed under the terms of the GNU Library
11 * General Public License, version 2.
aa4115a4
TT
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
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>
9f8046fc 181#include "ext2_fs.h"
aa4115a4
TT
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
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 = {
d4ecec45
TT
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
aa4115a4
TT
241};
242
aa4115a4
TT
243//
244// function to get API
245//
246
247io_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
260typedef struct {
261 ULONG WinError;
262 int errnocode;
263}ERROR_ENTRY;
264
265static 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
316static
317unsigned
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
366static
367__inline
368unsigned
369_MapNtStatus(
370 IN NTSTATUS Status
371 )
372{
373 return _MapDosError(RtlNtStatusToDosError(Status));
374}
375
376
377
378
379
380//
055866d8 381// Helper functions to make things easier
aa4115a4
TT
382//
383
384static
385NTSTATUS
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 //
055866d8 401 // Make Unicode name from input string
aa4115a4
TT
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 {
055866d8 414 return Status; // Unmappable character?
aa4115a4
TT
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,
fe70fd33 442 FILE_SYNCHRONOUS_IO_NONALERT);
aa4115a4
TT
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,
fe70fd33 460 FILE_SYNCHRONOUS_IO_NONALERT);
aa4115a4
TT
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,
fe70fd33 478 FILE_SYNCHRONOUS_IO_NONALERT);
aa4115a4
TT
479 }
480 }
481
482
483
484 //
485 // done
486 //
487
488 return Status;
489}
490
491
492static
493NTSTATUS
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
513static
514__inline
515NTSTATUS
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
529static
530__inline
531NTSTATUS
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
545static
546__inline
547NTSTATUS
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
556static
557__inline
558NTSTATUS
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
572static
573__inline
574BOOLEAN
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
586static
587__inline
588NTSTATUS
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
603static
604PCSTR
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 //
055866d8 676 // 3-d letter should be a digit.
aa4115a4
TT
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
745static
746VOID
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
811static
812BOOLEAN
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
886static
887BOOLEAN
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
942BOOLEAN
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
955BOOLEAN
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
970BOOLEAN
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
992errcode_t
993ext2fs_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
1022static __int64 FsSize = 0;
1023static char knowndevice[1024] = "";
1024
1025
1026errcode_t
1027ext2fs_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
1072static
1073errcode_t
1074nt_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
fe70fd33 1169 if(!NT_SUCCESS(_LockDrive(NtData->Handle)) /*|| !NT_SUCCESS(_DismountDrive(NtData->Handle))*/)
aa4115a4
TT
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 {
45e338f5 1192 free(io->name);
aa4115a4
TT
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
45e338f5 1204 free(NtData->Buffer);
aa4115a4
TT
1205 free(NtData);
1206 }
1207 }
1208 }
1209
1210 return Errno;
1211}
1212
1213
1214//
1215// Close api
1216//
1217
1218static
1219errcode_t
1220nt_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
45e338f5 1238 free(channel->name);
aa4115a4
TT
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
45e338f5 1250 free(NtData->Buffer);
aa4115a4
TT
1251 free(NtData);
1252 }
1253
1254 return 0;
1255}
1256
1257
1258
1259//
1260// set block size
1261//
1262
1263static
1264errcode_t
1265nt_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
1299static
1300errcode_t
1301nt_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
1381static
1382errcode_t
1383nt_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
1459static
1460errcode_t
1461nt_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