3 * nt_io.c --- This is the Nt I/O interface to the I/O manager.
5 * Implements a one-block write-through cache.
7 * Copyright (C) 1993, 1994, 1995 Theodore Ts'o.
8 * Copyright (C) 1998 Andrey Shedel
11 * This file may be redistributed under the terms of the GNU Public
22 // I need some warnings to disable...
26 #pragma warning(disable:4514) // unreferenced inline function has been removed
27 #pragma warning(push,4)
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
47 RtlNtStatusToDosError(
63 OUT PHANDLE FileHandle,
64 IN ACCESS_MASK DesiredAccess,
65 IN POBJECT_ATTRIBUTES ObjectAttributes,
66 OUT PIO_STATUS_BLOCK IoStatusBlock,
76 OUT PIO_STATUS_BLOCK IoStatusBlock
85 IN HANDLE Event OPTIONAL,
86 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
87 IN PVOID ApcContext OPTIONAL,
88 OUT PIO_STATUS_BLOCK IoStatusBlock,
91 IN PLARGE_INTEGER ByteOffset OPTIONAL,
92 IN PULONG Key OPTIONAL
100 IN HANDLE Event OPTIONAL,
101 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
102 IN PVOID ApcContext OPTIONAL,
103 OUT PIO_STATUS_BLOCK IoStatusBlock,
106 IN PLARGE_INTEGER ByteOffset OPTIONAL,
107 IN PULONG Key OPTIONAL
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
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
147 IN BOOLEAN Alertable,
148 IN PLARGE_INTEGER Interval
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)
162 #define BooleanFlagOn(Flags,SingleFlag) ((BOOLEAN)((((Flags) & (SingleFlag)) != 0)))
166 // Include Win32 error codes.
169 #include <winerror.h>
181 #include <linux/types.h>
182 #include <linux/ext2_fs.h>
185 #include "et/com_err.h"
186 #include "ext2fs/ext2fs.h"
187 #include "ext2fs/ext2_err.h"
193 // For checking structure magic numbers...
197 #define EXT2_CHECK_MAGIC(struct, code) \
198 if ((struct)->magic != (code)) return (code)
200 #define EXT2_ET_MAGIC_NT_IO_CHANNEL 0x10ed
204 // Private data block
207 typedef struct _NT_PRIVATE_DATA {
212 __u32 BufferBlockNumber;
214 BOOLEAN OpenedReadonly;
216 }NT_PRIVATE_DATA, *PNT_PRIVATE_DATA;
221 // Standard interface prototypes
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);
233 static struct struct_io_manager struct_nt_manager = {
234 EXT2_ET_MAGIC_IO_MANAGER,
247 // function to get API
250 io_manager nt_io_manager()
252 return &struct_nt_manager;
260 // This is a code to convert Win32 errors to unix errno
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 }
331 for (i = 0; i < (sizeof(ErrorTable)/sizeof(ErrorTable[0])); ++i)
333 if (WinError == ErrorTable[i].WinError)
335 return ErrorTable[i].errnocode;
340 // not in table. Check ranges
343 if ((WinError >= ERROR_WRITE_PROTECT) &&
344 (WinError <= ERROR_SHARING_BUFFER_EXCEEDED))
348 else if ((WinError >= ERROR_INVALID_STARTING_CODESEG) &&
349 (WinError <= ERROR_INFLOOP_IN_RELOC_CHAIN))
366 // Function to map NT status to dos error.
376 return _MapDosError(RtlNtStatusToDosError(Status));
384 // Helper functions to make things easyer
393 OUT PBOOLEAN OpenedReadonly OPTIONAL
396 UNICODE_STRING UnicodeString;
397 ANSI_STRING AnsiString;
400 OBJECT_ATTRIBUTES ObjectAttributes;
401 IO_STATUS_BLOCK IoStatusBlock;
404 // Make Unicode name from inlut string
407 UnicodeString.Buffer = &Buffer[0];
408 UnicodeString.Length = 0;
409 UnicodeString.MaximumLength = sizeof(Buffer); // in bytes!!!
411 RtlInitAnsiString(&AnsiString, Name);
413 Status = RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, FALSE);
415 if(!NT_SUCCESS(Status))
417 return Status; // Unpappable character?
424 InitializeObjectAttributes(&ObjectAttributes,
426 OBJ_CASE_INSENSITIVE,
431 // Try to open it in initial mode
434 if(ARGUMENT_PRESENT(OpenedReadonly))
436 *OpenedReadonly = Readonly;
440 Status = NtOpenFile(Handle,
441 SYNCHRONIZE | FILE_READ_DATA | (Readonly ? 0 : FILE_WRITE_DATA),
444 FILE_SHARE_WRITE | FILE_SHARE_READ,
445 FILE_SYNCHRONOUS_IO_NONALERT);
447 if(!NT_SUCCESS(Status))
450 // Maybe was just mounted? wait 0.5 sec and retry.
453 LARGE_INTEGER Interval;
454 Interval.QuadPart = -5000000; // 0.5 sec. from now
456 NtDelayExecution(FALSE, &Interval);
458 Status = NtOpenFile(Handle,
459 SYNCHRONIZE | FILE_READ_DATA | (Readonly ? 0 : FILE_WRITE_DATA),
462 FILE_SHARE_WRITE | FILE_SHARE_READ,
463 FILE_SYNCHRONOUS_IO_NONALERT);
466 // Try to satisfy mode
469 if((STATUS_ACCESS_DENIED == Status) && !Readonly)
471 if(ARGUMENT_PRESENT(OpenedReadonly))
473 *OpenedReadonly = TRUE;
476 Status = NtOpenFile(Handle,
477 SYNCHRONIZE | FILE_READ_DATA,
480 FILE_SHARE_WRITE | FILE_SHARE_READ,
481 FILE_SYNCHRONOUS_IO_NONALERT);
501 OUT PBOOLEAN OpenedReadonly OPTIONAL
506 sprintf(Buffer, "\\DosDevices\\%c:", Letter);
508 return _OpenNtName(Buffer, ReadOnly, Handle, OpenedReadonly);
523 IO_STATUS_BLOCK IoStatusBlock;
524 return NtFlushBuffersFile(Handle, &IoStatusBlock);
539 IO_STATUS_BLOCK IoStatusBlock;
540 return NtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_LOCK_VOLUME, 0, 0, 0, 0);
555 IO_STATUS_BLOCK IoStatusBlock;
556 return NtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_UNLOCK_VOLUME, 0, 0, 0, 0);
566 IO_STATUS_BLOCK IoStatusBlock;
567 return NtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_DISMOUNT_VOLUME, 0, 0, 0, 0);
582 IO_STATUS_BLOCK IoStatusBlock;
584 Status = NtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_IS_VOLUME_MOUNTED, 0, 0, 0, 0);
585 return (BOOLEAN)(STATUS_SUCCESS == Status);
596 return NtClose(Handle);
603 // Make NT name from any recognized name
608 _NormalizeDeviceName(
610 IN PSTR NormalizedDeviceNameBuffer
613 int PartitionNumber = -1;
619 // Do not try to parse NT name
628 // Strip leading '/dev/' if any
631 if(('/' == *(Device)) &&
632 ('d' == *(Device + 1)) &&
633 ('e' == *(Device + 2)) &&
634 ('v' == *(Device + 3)) &&
635 ('/' == *(Device + 4)))
647 // forms: hda[n], fd[n]
650 if('d' != *(Device + 1))
657 if((*(Device + 2) < 'a') || (*(Device + 2) > ('a' + 9)) ||
658 ((*(Device + 3) != '\0') &&
659 ((*(Device + 4) != '\0') ||
660 ((*(Device + 3) < '0') || (*(Device + 3) > '9'))
668 DiskNumber = (UCHAR)(*(Device + 2) - 'a');
670 if(*(Device + 3) != '\0')
672 PartitionNumber = (*(Device + 3) - '0');
676 else if('f' == *Device)
679 // 3-d letted should be a digit.
682 if((*(Device + 3) != '\0') ||
683 (*(Device + 2) < '0') || (*(Device + 2) > '9'))
688 DiskNumber = (UCHAR)(*(Device + 2) - '0');
706 strcpy(NormalizedDeviceNameBuffer, "\\Device\\");
716 strcat(NormalizedDeviceNameBuffer, "Floppy0");
720 strcat(NormalizedDeviceNameBuffer, "Harddisk0");
725 p = NormalizedDeviceNameBuffer + strlen(NormalizedDeviceNameBuffer) - 1;
726 *p = (CHAR)(*p + DiskNumber);
733 if(PartitionNumber >= 0)
735 strcat(NormalizedDeviceNameBuffer, "\\Partition0");
737 p = NormalizedDeviceNameBuffer + strlen(NormalizedDeviceNameBuffer) - 1;
738 *p = (CHAR)(*p + PartitionNumber);
742 return NormalizedDeviceNameBuffer;
752 OUT unsigned __int64 *FsSize
755 PARTITION_INFORMATION pi;
758 IO_STATUS_BLOCK IoStatusBlock;
770 RtlZeroMemory(&pi, sizeof(PARTITION_INFORMATION));
772 Status = NtDeviceIoControlFile(
773 h, NULL, NULL, NULL, &IoStatusBlock, IOCTL_DISK_GET_PARTITION_INFO,
774 &pi, sizeof(PARTITION_INFORMATION),
775 &pi, sizeof(PARTITION_INFORMATION));
778 if(NT_SUCCESS(Status))
780 *FsSize = pi.PartitionLength.QuadPart;
782 else if(STATUS_INVALID_DEVICE_REQUEST == Status)
785 // No partitions: get device info.
788 RtlZeroMemory(&gi, sizeof(DISK_GEOMETRY));
790 Status = NtDeviceIoControlFile(
791 h, NULL, NULL, NULL, &IoStatusBlock, IOCTL_DISK_GET_DRIVE_GEOMETRY,
792 &gi, sizeof(DISK_GEOMETRY),
793 &gi, sizeof(DISK_GEOMETRY));
796 if(NT_SUCCESS(Status))
801 gi.TracksPerCylinder *
802 gi.Cylinders.QuadPart;
811 // Open device by name.
820 OUT PBOOLEAN OpenedReadonly OPTIONAL,
821 OUT unsigned *Errno OPTIONAL
824 CHAR NormalizedDeviceName[512];
833 if(ARGUMENT_PRESENT(Errno))
840 if((((*Name) | 0x20) >= 'a') && (((*Name) | 0x20) <= 'z') &&
841 (':' == *(Name + 1)) && ('\0' == *(Name + 2)))
843 Status = _OpenDriveLetter(*Name, ReadOnly, Handle, OpenedReadonly);
851 Name = _NormalizeDeviceName(Name, NormalizedDeviceName);
859 if(ARGUMENT_PRESENT(Errno))
869 Status = _OpenNtName(Name, ReadOnly, Handle, OpenedReadonly);
873 if(!NT_SUCCESS(Status))
875 if(ARGUMENT_PRESENT(Errno))
876 *Errno = _MapNtStatus(Status);
886 // Raw block io. Sets dos errno
893 IN LARGE_INTEGER Offset,
900 IO_STATUS_BLOCK IoStatusBlock;
907 ASSERT(0 == (Bytes % 512));
908 ASSERT(0 == (Offset.LowPart % 512));
917 Status = NtReadFile(Handle, NULL, NULL, NULL,
918 &IoStatusBlock, Buffer, Bytes, &Offset, NULL);
922 Status = NtWriteFile(Handle, NULL, NULL, NULL,
923 &IoStatusBlock, Buffer, Bytes, &Offset, NULL);
931 if(NT_SUCCESS(Status))
937 *Errno = _MapNtStatus(Status);
948 IN LARGE_INTEGER Offset,
950 OUT const CHAR* Buffer,
954 return _BlockIo(Handle, Offset, Bytes, (PCHAR)Buffer, FALSE, Errno);
961 IN LARGE_INTEGER Offset,
967 return _BlockIo(Handle, Offset, Bytes, Buffer, TRUE, Errno);
979 IO_STATUS_BLOCK IoStatusBlock;
980 return STATUS_SUCCESS == NtDeviceIoControlFile(
981 Handle, NULL, NULL, NULL, &IoStatusBlock, IOCTL_DISK_SET_PARTITION_INFO,
988 //--------------------- interface part
991 // Interface functions.
992 // Is_mounted is set to 1 if the device is mounted, 0 otherwise
996 ext2fs_check_if_mounted(const char *file, int *mount_flags)
1003 if(!_Ext2OpenDevice(file, TRUE, &h, &Readonly, NULL))
1010 *mount_flags &= _IsMounted(h) ? EXT2_MF_MOUNTED : 0;
1022 // Returns the number of blocks in a partition
1025 static __int64 FsSize = 0;
1026 static char knowndevice[1024] = "";
1030 ext2fs_get_device_size(const char *file, int blocksize,
1036 if((0 == FsSize) || (0 != strcmp(knowndevice, file)))
1039 if(!_Ext2OpenDevice(file, TRUE, &h, &Readonly, NULL))
1051 _GetDeviceSize(h, &FsSize);
1052 strcpy(knowndevice, file);
1060 *retblocks = (blk_t)(unsigned __int64)(FsSize / blocksize);
1061 UNREFERENCED_PARAMETER(file);
1077 nt_open(const char *name, int flags, io_channel *channel)
1079 io_channel io = NULL;
1080 PNT_PRIVATE_DATA NtData = NULL;
1081 errcode_t Errno = 0;
1089 return EXT2_ET_BAD_DEVICE_NAME;
1095 // Allocate channel handle
1098 io = (io_channel) malloc(sizeof(struct struct_io_channel));
1106 RtlZeroMemory(io, sizeof(struct struct_io_channel));
1107 io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
1109 NtData = (PNT_PRIVATE_DATA)malloc(sizeof(NT_PRIVATE_DATA));
1118 io->manager = nt_io_manager();
1119 io->name = malloc(strlen(name) + 1);
1120 if (NULL == io->name)
1126 strcpy(io->name, name);
1127 io->private_data = NtData;
1128 io->block_size = 1024;
1130 io->write_error = 0;
1137 RtlZeroMemory(NtData, sizeof(NT_PRIVATE_DATA));
1139 NtData->magic = EXT2_ET_MAGIC_NT_IO_CHANNEL;
1140 NtData->BufferBlockNumber = 0xffffffff;
1141 NtData->BufferSize = 1024;
1142 NtData->Buffer = malloc(NtData->BufferSize);
1144 if (NULL == NtData->Buffer)
1154 if(!_Ext2OpenDevice(name, (BOOLEAN)!BooleanFlagOn(flags, EXT2_FLAG_RW), &NtData->Handle, &NtData->OpenedReadonly, &Errno))
1164 _GetDeviceSize(NtData->Handle, &FsSize);
1165 strcpy(knowndevice, name);
1172 if(!NT_SUCCESS(_LockDrive(NtData->Handle)) /*|| !NT_SUCCESS(_DismountDrive(NtData->Handle))*/)
1174 NtData->OpenedReadonly = TRUE;
1195 if(NULL != io->name)
1205 if(NULL != NtData->Handle)
1207 _UnlockDrive(NtData->Handle);
1208 _CloseDisk(NtData->Handle);
1211 if(NULL != NtData->Buffer)
1213 free(NtData->Buffer);
1231 nt_close(io_channel channel)
1233 PNT_PRIVATE_DATA NtData = NULL;
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);
1244 if (--channel->refcount > 0)
1249 if(NULL != channel->name)
1251 free(channel->name);
1259 if(NULL != NtData->Handle)
1261 _DismountDrive(NtData->Handle);
1262 _UnlockDrive(NtData->Handle);
1263 _CloseDisk(NtData->Handle);
1266 if(NULL != NtData->Buffer)
1268 free(NtData->Buffer);
1285 nt_set_blksize(io_channel channel, int blksize)
1287 PNT_PRIVATE_DATA NtData = NULL;
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);
1293 if (channel->block_size != blksize)
1295 channel->block_size = blksize;
1297 free(NtData->Buffer);
1298 NtData->BufferBlockNumber = 0xffffffff;
1299 NtData->BufferSize = channel->block_size;
1300 ASSERT(0 == (NtData->BufferSize % 512));
1302 NtData->Buffer = malloc(NtData->BufferSize);
1304 if (NULL == NtData->Buffer)
1321 nt_read_blk(io_channel channel, unsigned long block,
1322 int count, void *buf)
1327 LARGE_INTEGER Offset;
1328 PNT_PRIVATE_DATA NtData = NULL;
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);
1336 // If it's in the cache, use it!
1340 (block == NtData->BufferBlockNumber) &&
1341 (NtData->BufferBlockNumber != 0xffffffff))
1343 memcpy(buf, NtData->Buffer, channel->block_size);
1347 Size = (count < 0) ? (ULONG)(-count) : (ULONG)(count * channel->block_size);
1349 Offset.QuadPart = block * channel->block_size;
1352 // If not fit to the block
1355 if(Size <= NtData->BufferSize)
1361 NtData->BufferBlockNumber = block;
1362 BufferToRead = NtData->Buffer;
1363 SizeToRead = NtData->BufferSize;
1369 ASSERT(0 == (SizeToRead % channel->block_size));
1372 if(!_RawRead(NtData->Handle, Offset, SizeToRead, BufferToRead, &Errno))
1375 if (channel->read_error)
1377 return (channel->read_error)(channel, block, count, buf,
1387 if(BufferToRead != buf)
1389 ASSERT(Size <= SizeToRead);
1390 memcpy(buf, BufferToRead, Size);
1403 nt_write_blk(io_channel channel, unsigned long block,
1404 int count, const void *buf)
1407 LARGE_INTEGER Offset;
1408 PNT_PRIVATE_DATA NtData = NULL;
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);
1415 if(NtData->OpenedReadonly)
1422 SizeToWrite = channel->block_size;
1426 NtData->BufferBlockNumber = 0xffffffff;
1430 SizeToWrite = (ULONG)(-count);
1434 SizeToWrite = (ULONG)(count * channel->block_size);
1439 ASSERT(0 == (SizeToWrite % 512));
1440 Offset.QuadPart = block * channel->block_size;
1442 if(!_RawWrite(NtData->Handle, Offset, SizeToWrite, buf, &Errno))
1444 if (channel->write_error)
1446 return (channel->write_error)(channel, block, count, buf,
1447 SizeToWrite, 0, Errno);
1460 if(SizeToWrite >= NtData->BufferSize)
1462 NtData->BufferBlockNumber = block;
1463 memcpy(NtData->Buffer, buf, NtData->BufferSize);
1466 NtData->Written = TRUE;
1475 // Flush data buffers to disk. Since we are currently using a
1476 // write-through cache, this is a no-op.
1481 nt_flush(io_channel channel)
1483 PNT_PRIVATE_DATA NtData = NULL;
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);
1489 if(NtData->OpenedReadonly)
1491 return 0; // EACCESS;
1496 // Flush file buffers.
1499 _FlushDrive(NtData->Handle);
1503 // Test and correct partition type.
1508 _SetPartType(NtData->Handle, 0x83);