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