blob: 93b94f1c377fcafc7443c084252940651ed84aa7 [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%
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
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>
181#include <linux/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
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 {
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
1228static
1229errcode_t
1230nt_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
1282static
1283errcode_t
1284nt_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
1318static
1319errcode_t
1320nt_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
1400static
1401errcode_t
1402nt_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
1478static
1479errcode_t
1480nt_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