OSDN Git Service

Code drop from //branches/cupcake/...@124589
[android-x86/external-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 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
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         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
249 io_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
262 typedef struct {
263         ULONG WinError;
264         int errnocode;
265 }ERROR_ENTRY;
266
267 static 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
318 static
319 unsigned
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
368 static
369 __inline
370 unsigned
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
386 static
387 NTSTATUS
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,
444                                                 FILE_SYNCHRONOUS_IO_NONALERT);
445
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,
462                                                         FILE_SYNCHRONOUS_IO_NONALERT);
463
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,
480                                                         FILE_SYNCHRONOUS_IO_NONALERT);
481                 }
482         }
483
484
485
486         //
487         // done
488         //
489
490         return Status;
491 }
492
493
494 static
495 NTSTATUS
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
515 static
516 __inline
517 NTSTATUS
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
531 static
532 __inline
533 NTSTATUS
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
547 static
548 __inline
549 NTSTATUS
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
558 static
559 __inline
560 NTSTATUS
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
574 static
575 __inline
576 BOOLEAN
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
588 static
589 __inline
590 NTSTATUS
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
605 static
606 PCSTR
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
747 static
748 VOID
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
813 static
814 BOOLEAN
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
888 static
889 BOOLEAN
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
944 BOOLEAN
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
957 BOOLEAN
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
972 BOOLEAN
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
994 errcode_t
995 ext2fs_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
1024 static __int64 FsSize = 0;
1025 static char knowndevice[1024] = "";
1026
1027
1028 errcode_t
1029 ext2fs_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
1074 static
1075 errcode_t
1076 nt_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
1171                 if(!NT_SUCCESS(_LockDrive(NtData->Handle)) /*|| !NT_SUCCESS(_DismountDrive(NtData->Handle))*/)
1172                 {
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
1228 static
1229 errcode_t
1230 nt_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
1282 static
1283 errcode_t
1284 nt_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
1318 static
1319 errcode_t
1320 nt_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
1400 static
1401 errcode_t
1402 nt_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
1478 static
1479 errcode_t
1480 nt_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