Whamcloud - gitweb
Fix clang warnings on architectures with a 64-bit long
[tools/e2fsprogs.git] / lib / ext2fs / nt_io.c
1 /*
2  * nt_io.c --- This is the Nt I/O interface to the I/O manager.
3  *
4  * Implements a one-block write-through cache.
5  *
6  * Copyright (C) 1993, 1994, 1995 Theodore Ts'o.
7  * Copyright (C) 1998 Andrey Shedel (andreys@ns.cr.cyco.com)
8  *
9  * %Begin-Header%
10  * This file may be redistributed under the terms of the GNU Library
11  * General Public License, version 2.
12  * %End-Header%
13  */
14
15 #ifdef HAVE_CONFIG_H
16 #include "config.h"
17 #endif
18
19
20 //
21 // I need some warnings to disable...
22 //
23
24
25 #pragma warning(disable:4514) // unreferenced inline function has been removed
26 #pragma warning(push,4)
27
28 #pragma warning(disable:4201) // nonstandard extension used : nameless struct/union)
29 #pragma warning(disable:4214) // nonstandard extension used : bit field types other than int
30 #pragma warning(disable:4115) // named type definition in parentheses
31
32 #include <ntddk.h>
33 #include <ntdddisk.h>
34 #include <ntstatus.h>
35
36 #pragma warning(pop)
37
38
39 //
40 // Some native APIs.
41 //
42
43 NTSYSAPI
44 ULONG
45 NTAPI
46 RtlNtStatusToDosError(
47     IN NTSTATUS Status
48    );
49
50 NTSYSAPI
51 NTSTATUS
52 NTAPI
53 NtClose(
54     IN HANDLE Handle
55    );
56
57
58 NTSYSAPI
59 NTSTATUS
60 NTAPI
61 NtOpenFile(
62     OUT PHANDLE FileHandle,
63     IN ACCESS_MASK DesiredAccess,
64     IN POBJECT_ATTRIBUTES ObjectAttributes,
65     OUT PIO_STATUS_BLOCK IoStatusBlock,
66     IN ULONG ShareAccess,
67     IN ULONG OpenOptions
68     );
69
70 NTSYSAPI
71 NTSTATUS
72 NTAPI
73 NtFlushBuffersFile(
74     IN HANDLE FileHandle,
75     OUT PIO_STATUS_BLOCK IoStatusBlock
76    );
77
78
79 NTSYSAPI
80 NTSTATUS
81 NTAPI
82 NtReadFile(
83     IN HANDLE FileHandle,
84     IN HANDLE Event OPTIONAL,
85     IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
86     IN PVOID ApcContext OPTIONAL,
87     OUT PIO_STATUS_BLOCK IoStatusBlock,
88     OUT PVOID Buffer,
89     IN ULONG Length,
90     IN PLARGE_INTEGER ByteOffset OPTIONAL,
91     IN PULONG Key OPTIONAL
92     );
93
94 NTSYSAPI
95 NTSTATUS
96 NTAPI
97 NtWriteFile(
98     IN HANDLE FileHandle,
99     IN HANDLE Event OPTIONAL,
100     IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
101     IN PVOID ApcContext OPTIONAL,
102     OUT PIO_STATUS_BLOCK IoStatusBlock,
103     IN PVOID Buffer,
104     IN ULONG Length,
105     IN PLARGE_INTEGER ByteOffset OPTIONAL,
106     IN PULONG Key OPTIONAL
107     );
108
109 NTSYSAPI
110 NTSTATUS
111 NTAPI
112 NtDeviceIoControlFile(
113     IN HANDLE FileHandle,
114     IN HANDLE Event OPTIONAL,
115     IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
116     IN PVOID ApcContext OPTIONAL,
117     OUT PIO_STATUS_BLOCK IoStatusBlock,
118     IN ULONG IoControlCode,
119     IN PVOID InputBuffer OPTIONAL,
120     IN ULONG InputBufferLength,
121     OUT PVOID OutputBuffer OPTIONAL,
122     IN ULONG OutputBufferLength
123     );
124
125 NTSYSAPI
126 NTSTATUS
127 NTAPI
128 NtFsControlFile(
129     IN HANDLE FileHandle,
130     IN HANDLE Event OPTIONAL,
131     IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
132     IN PVOID ApcContext OPTIONAL,
133     OUT PIO_STATUS_BLOCK IoStatusBlock,
134     IN ULONG IoControlCode,
135     IN PVOID InputBuffer OPTIONAL,
136     IN ULONG InputBufferLength,
137     OUT PVOID OutputBuffer OPTIONAL,
138     IN ULONG OutputBufferLength
139     );
140
141
142 NTSYSAPI
143 NTSTATUS
144 NTAPI
145 NtDelayExecution(
146     IN BOOLEAN Alertable,
147     IN PLARGE_INTEGER Interval
148     );
149
150
151 #define FSCTL_LOCK_VOLUME               CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 6, METHOD_BUFFERED, FILE_ANY_ACCESS)
152 #define FSCTL_UNLOCK_VOLUME             CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 7, METHOD_BUFFERED, FILE_ANY_ACCESS)
153 #define FSCTL_DISMOUNT_VOLUME           CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 8, METHOD_BUFFERED, FILE_ANY_ACCESS)
154 #define FSCTL_IS_VOLUME_MOUNTED         CTL_CODE(FILE_DEVICE_FILE_SYSTEM,10, METHOD_BUFFERED, FILE_ANY_ACCESS)
155
156
157 //
158 // useful macros
159 //
160
161 #define BooleanFlagOn(Flags,SingleFlag) ((BOOLEAN)((((Flags) & (SingleFlag)) != 0)))
162
163
164 //
165 // Include Win32 error codes.
166 //
167
168 #include <winerror.h>
169
170 //
171 // standard stuff
172 //
173
174 #include <assert.h>
175 #include <stdio.h>
176 #include <string.h>
177 #include <stdlib.h>
178 #include <malloc.h>
179
180 #include <linux/types.h>
181 #include "ext2_fs.h"
182 #include <errno.h>
183
184 #include "et/com_err.h"
185 #include "ext2fs/ext2fs.h"
186 #include "ext2fs/ext2_err.h"
187
188
189
190
191 //
192 // For checking structure magic numbers...
193 //
194
195
196 #define EXT2_CHECK_MAGIC(struct, code) \
197           if ((struct)->magic != (code)) return (code)
198
199 #define EXT2_ET_MAGIC_NT_IO_CHANNEL  0x10ed
200
201
202 //
203 // Private data block
204 //
205
206 typedef struct _NT_PRIVATE_DATA {
207         int        magic;
208         HANDLE Handle;
209         int        Flags;
210         PCHAR  Buffer;
211         __u32  BufferBlockNumber;
212         ULONG  BufferSize;
213         BOOLEAN OpenedReadonly;
214         BOOLEAN Written;
215 }NT_PRIVATE_DATA, *PNT_PRIVATE_DATA;
216
217
218
219 //
220 // Standard interface prototypes
221 //
222
223 static errcode_t nt_open(const char *name, int flags, io_channel *channel);
224 static errcode_t nt_close(io_channel channel);
225 static errcode_t nt_set_blksize(io_channel channel, int blksize);
226 static errcode_t nt_read_blk(io_channel channel, unsigned long block,
227                                int count, void *data);
228 static errcode_t nt_write_blk(io_channel channel, unsigned long block,
229                                 int count, const void *data);
230 static errcode_t nt_flush(io_channel channel);
231
232 static struct struct_io_manager struct_nt_manager = {
233         .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
241 };
242
243 //
244 // function to get API
245 //
246
247 io_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
260 typedef struct {
261         ULONG WinError;
262         int errnocode;
263 }ERROR_ENTRY;
264
265 static 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
316 static
317 unsigned
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
366 static
367 __inline
368 unsigned
369 _MapNtStatus(
370     IN NTSTATUS Status
371    )
372 {
373         return _MapDosError(RtlNtStatusToDosError(Status));
374 }
375
376
377
378
379
380 //
381 // Helper functions to make things easier
382 //
383
384 static
385 NTSTATUS
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         //
401         // Make Unicode name from input string
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         {
414                 return Status; // Unmappable character?
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,
442                                                 FILE_SYNCHRONOUS_IO_NONALERT);
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,
460                                                         FILE_SYNCHRONOUS_IO_NONALERT);
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,
478                                                         FILE_SYNCHRONOUS_IO_NONALERT);
479                 }
480         }
481
482
483
484         //
485         // done
486         //
487
488         return Status;
489 }
490
491
492 static
493 NTSTATUS
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
513 static
514 __inline
515 NTSTATUS
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
529 static
530 __inline
531 NTSTATUS
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
545 static
546 __inline
547 NTSTATUS
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
556 static
557 __inline
558 NTSTATUS
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
572 static
573 __inline
574 BOOLEAN
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
586 static
587 __inline
588 NTSTATUS
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
603 static
604 PCSTR
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                 //
676                 // 3-d letter should be a digit.
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
745 static
746 VOID
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
811 static
812 BOOLEAN
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
886 static
887 BOOLEAN
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
942 BOOLEAN
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
955 BOOLEAN
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
970 BOOLEAN
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
992 errcode_t
993 ext2fs_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
1022 static __int64 FsSize = 0;
1023 static char knowndevice[1024] = "";
1024
1025
1026 errcode_t
1027 ext2fs_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
1072 static
1073 errcode_t
1074 nt_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
1169                 if(!NT_SUCCESS(_LockDrive(NtData->Handle)) /*|| !NT_SUCCESS(_DismountDrive(NtData->Handle))*/)
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                         {
1192                                 free(io->name);
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
1204                                 free(NtData->Buffer);
1205                                 free(NtData);
1206                         }
1207                 }
1208         }
1209
1210         return Errno;
1211 }
1212
1213
1214 //
1215 // Close api
1216 //
1217
1218 static
1219 errcode_t
1220 nt_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
1238         free(channel->name);
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
1250                 free(NtData->Buffer);
1251                 free(NtData);
1252         }
1253
1254         return 0;
1255 }
1256
1257
1258
1259 //
1260 // set block size
1261 //
1262
1263 static
1264 errcode_t
1265 nt_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
1299 static
1300 errcode_t
1301 nt_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
1381 static
1382 errcode_t
1383 nt_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
1459 static
1460 errcode_t
1461 nt_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