2 * nt_io.c --- This is the Nt I/O interface to the I/O manager.
4 * Implements a one-block write-through cache.
6 * Copyright (C) 1993, 1994, 1995 Theodore Ts'o.
7 * Copyright (C) 1998 Andrey Shedel (andreys@ns.cr.cyco.com)
10 * This file may be redistributed under the terms of the GNU Public
21 // I need some warnings to disable...
25 #pragma warning(disable:4514) // unreferenced inline function has been removed
26 #pragma warning(push,4)
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
46 RtlNtStatusToDosError(
62 OUT PHANDLE FileHandle,
63 IN ACCESS_MASK DesiredAccess,
64 IN POBJECT_ATTRIBUTES ObjectAttributes,
65 OUT PIO_STATUS_BLOCK IoStatusBlock,
75 OUT PIO_STATUS_BLOCK IoStatusBlock
84 IN HANDLE Event OPTIONAL,
85 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
86 IN PVOID ApcContext OPTIONAL,
87 OUT PIO_STATUS_BLOCK IoStatusBlock,
90 IN PLARGE_INTEGER ByteOffset OPTIONAL,
91 IN PULONG Key OPTIONAL
99 IN HANDLE Event OPTIONAL,
100 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
101 IN PVOID ApcContext OPTIONAL,
102 OUT PIO_STATUS_BLOCK IoStatusBlock,
105 IN PLARGE_INTEGER ByteOffset OPTIONAL,
106 IN PULONG Key OPTIONAL
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
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
146 IN BOOLEAN Alertable,
147 IN PLARGE_INTEGER Interval
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)
161 #define BooleanFlagOn(Flags,SingleFlag) ((BOOLEAN)((((Flags) & (SingleFlag)) != 0)))
165 // Include Win32 error codes.
168 #include <winerror.h>
180 #include <linux/types.h>
184 #include "et/com_err.h"
185 #include "ext2fs/ext2fs.h"
186 #include "ext2fs/ext2_err.h"
192 // For checking structure magic numbers...
196 #define EXT2_CHECK_MAGIC(struct, code) \
197 if ((struct)->magic != (code)) return (code)
199 #define EXT2_ET_MAGIC_NT_IO_CHANNEL 0x10ed
203 // Private data block
206 typedef struct _NT_PRIVATE_DATA {
211 __u32 BufferBlockNumber;
213 BOOLEAN OpenedReadonly;
215 }NT_PRIVATE_DATA, *PNT_PRIVATE_DATA;
220 // Standard interface prototypes
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);
232 static struct struct_io_manager struct_nt_manager = {
233 EXT2_ET_MAGIC_IO_MANAGER,
246 // function to get API
249 io_manager nt_io_manager()
251 return &struct_nt_manager;
259 // This is a code to convert Win32 errors to unix errno
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 }
330 for (i = 0; i < (sizeof(ErrorTable)/sizeof(ErrorTable[0])); ++i)
332 if (WinError == ErrorTable[i].WinError)
334 return ErrorTable[i].errnocode;
339 // not in table. Check ranges
342 if ((WinError >= ERROR_WRITE_PROTECT) &&
343 (WinError <= ERROR_SHARING_BUFFER_EXCEEDED))
347 else if ((WinError >= ERROR_INVALID_STARTING_CODESEG) &&
348 (WinError <= ERROR_INFLOOP_IN_RELOC_CHAIN))
365 // Function to map NT status to dos error.
375 return _MapDosError(RtlNtStatusToDosError(Status));
383 // Helper functions to make things easyer
392 OUT PBOOLEAN OpenedReadonly OPTIONAL
395 UNICODE_STRING UnicodeString;
396 ANSI_STRING AnsiString;
399 OBJECT_ATTRIBUTES ObjectAttributes;
400 IO_STATUS_BLOCK IoStatusBlock;
403 // Make Unicode name from inlut string
406 UnicodeString.Buffer = &Buffer[0];
407 UnicodeString.Length = 0;
408 UnicodeString.MaximumLength = sizeof(Buffer); // in bytes!!!
410 RtlInitAnsiString(&AnsiString, Name);
412 Status = RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, FALSE);
414 if(!NT_SUCCESS(Status))
416 return Status; // Unpappable character?
423 InitializeObjectAttributes(&ObjectAttributes,
425 OBJ_CASE_INSENSITIVE,
430 // Try to open it in initial mode
433 if(ARGUMENT_PRESENT(OpenedReadonly))
435 *OpenedReadonly = Readonly;
439 Status = NtOpenFile(Handle,
440 SYNCHRONIZE | FILE_READ_DATA | (Readonly ? 0 : FILE_WRITE_DATA),
443 FILE_SHARE_WRITE | FILE_SHARE_READ,
444 FILE_SYNCHRONOUS_IO_NONALERT);
446 if(!NT_SUCCESS(Status))
449 // Maybe was just mounted? wait 0.5 sec and retry.
452 LARGE_INTEGER Interval;
453 Interval.QuadPart = -5000000; // 0.5 sec. from now
455 NtDelayExecution(FALSE, &Interval);
457 Status = NtOpenFile(Handle,
458 SYNCHRONIZE | FILE_READ_DATA | (Readonly ? 0 : FILE_WRITE_DATA),
461 FILE_SHARE_WRITE | FILE_SHARE_READ,
462 FILE_SYNCHRONOUS_IO_NONALERT);
465 // Try to satisfy mode
468 if((STATUS_ACCESS_DENIED == Status) && !Readonly)
470 if(ARGUMENT_PRESENT(OpenedReadonly))
472 *OpenedReadonly = TRUE;
475 Status = NtOpenFile(Handle,
476 SYNCHRONIZE | FILE_READ_DATA,
479 FILE_SHARE_WRITE | FILE_SHARE_READ,
480 FILE_SYNCHRONOUS_IO_NONALERT);
500 OUT PBOOLEAN OpenedReadonly OPTIONAL
505 sprintf(Buffer, "\\DosDevices\\%c:", Letter);
507 return _OpenNtName(Buffer, ReadOnly, Handle, OpenedReadonly);
522 IO_STATUS_BLOCK IoStatusBlock;
523 return NtFlushBuffersFile(Handle, &IoStatusBlock);
538 IO_STATUS_BLOCK IoStatusBlock;
539 return NtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_LOCK_VOLUME, 0, 0, 0, 0);
554 IO_STATUS_BLOCK IoStatusBlock;
555 return NtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_UNLOCK_VOLUME, 0, 0, 0, 0);
565 IO_STATUS_BLOCK IoStatusBlock;
566 return NtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_DISMOUNT_VOLUME, 0, 0, 0, 0);
581 IO_STATUS_BLOCK IoStatusBlock;
583 Status = NtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_IS_VOLUME_MOUNTED, 0, 0, 0, 0);
584 return (BOOLEAN)(STATUS_SUCCESS == Status);
595 return NtClose(Handle);
602 // Make NT name from any recognized name
607 _NormalizeDeviceName(
609 IN PSTR NormalizedDeviceNameBuffer
612 int PartitionNumber = -1;
618 // Do not try to parse NT name
627 // Strip leading '/dev/' if any
630 if(('/' == *(Device)) &&
631 ('d' == *(Device + 1)) &&
632 ('e' == *(Device + 2)) &&
633 ('v' == *(Device + 3)) &&
634 ('/' == *(Device + 4)))
646 // forms: hda[n], fd[n]
649 if('d' != *(Device + 1))
656 if((*(Device + 2) < 'a') || (*(Device + 2) > ('a' + 9)) ||
657 ((*(Device + 3) != '\0') &&
658 ((*(Device + 4) != '\0') ||
659 ((*(Device + 3) < '0') || (*(Device + 3) > '9'))
667 DiskNumber = (UCHAR)(*(Device + 2) - 'a');
669 if(*(Device + 3) != '\0')
671 PartitionNumber = (*(Device + 3) - '0');
675 else if('f' == *Device)
678 // 3-d letted should be a digit.
681 if((*(Device + 3) != '\0') ||
682 (*(Device + 2) < '0') || (*(Device + 2) > '9'))
687 DiskNumber = (UCHAR)(*(Device + 2) - '0');
705 strcpy(NormalizedDeviceNameBuffer, "\\Device\\");
715 strcat(NormalizedDeviceNameBuffer, "Floppy0");
719 strcat(NormalizedDeviceNameBuffer, "Harddisk0");
724 p = NormalizedDeviceNameBuffer + strlen(NormalizedDeviceNameBuffer) - 1;
725 *p = (CHAR)(*p + DiskNumber);
732 if(PartitionNumber >= 0)
734 strcat(NormalizedDeviceNameBuffer, "\\Partition0");
736 p = NormalizedDeviceNameBuffer + strlen(NormalizedDeviceNameBuffer) - 1;
737 *p = (CHAR)(*p + PartitionNumber);
741 return NormalizedDeviceNameBuffer;
751 OUT unsigned __int64 *FsSize
754 PARTITION_INFORMATION pi;
757 IO_STATUS_BLOCK IoStatusBlock;
769 RtlZeroMemory(&pi, sizeof(PARTITION_INFORMATION));
771 Status = NtDeviceIoControlFile(
772 h, NULL, NULL, NULL, &IoStatusBlock, IOCTL_DISK_GET_PARTITION_INFO,
773 &pi, sizeof(PARTITION_INFORMATION),
774 &pi, sizeof(PARTITION_INFORMATION));
777 if(NT_SUCCESS(Status))
779 *FsSize = pi.PartitionLength.QuadPart;
781 else if(STATUS_INVALID_DEVICE_REQUEST == Status)
784 // No partitions: get device info.
787 RtlZeroMemory(&gi, sizeof(DISK_GEOMETRY));
789 Status = NtDeviceIoControlFile(
790 h, NULL, NULL, NULL, &IoStatusBlock, IOCTL_DISK_GET_DRIVE_GEOMETRY,
791 &gi, sizeof(DISK_GEOMETRY),
792 &gi, sizeof(DISK_GEOMETRY));
795 if(NT_SUCCESS(Status))
800 gi.TracksPerCylinder *
801 gi.Cylinders.QuadPart;
810 // Open device by name.
819 OUT PBOOLEAN OpenedReadonly OPTIONAL,
820 OUT unsigned *Errno OPTIONAL
823 CHAR NormalizedDeviceName[512];
832 if(ARGUMENT_PRESENT(Errno))
839 if((((*Name) | 0x20) >= 'a') && (((*Name) | 0x20) <= 'z') &&
840 (':' == *(Name + 1)) && ('\0' == *(Name + 2)))
842 Status = _OpenDriveLetter(*Name, ReadOnly, Handle, OpenedReadonly);
850 Name = _NormalizeDeviceName(Name, NormalizedDeviceName);
858 if(ARGUMENT_PRESENT(Errno))
868 Status = _OpenNtName(Name, ReadOnly, Handle, OpenedReadonly);
872 if(!NT_SUCCESS(Status))
874 if(ARGUMENT_PRESENT(Errno))
875 *Errno = _MapNtStatus(Status);
885 // Raw block io. Sets dos errno
892 IN LARGE_INTEGER Offset,
899 IO_STATUS_BLOCK IoStatusBlock;
906 ASSERT(0 == (Bytes % 512));
907 ASSERT(0 == (Offset.LowPart % 512));
916 Status = NtReadFile(Handle, NULL, NULL, NULL,
917 &IoStatusBlock, Buffer, Bytes, &Offset, NULL);
921 Status = NtWriteFile(Handle, NULL, NULL, NULL,
922 &IoStatusBlock, Buffer, Bytes, &Offset, NULL);
930 if(NT_SUCCESS(Status))
936 *Errno = _MapNtStatus(Status);
947 IN LARGE_INTEGER Offset,
949 OUT const CHAR* Buffer,
953 return _BlockIo(Handle, Offset, Bytes, (PCHAR)Buffer, FALSE, Errno);
960 IN LARGE_INTEGER Offset,
966 return _BlockIo(Handle, Offset, Bytes, Buffer, TRUE, Errno);
978 IO_STATUS_BLOCK IoStatusBlock;
979 return STATUS_SUCCESS == NtDeviceIoControlFile(
980 Handle, NULL, NULL, NULL, &IoStatusBlock, IOCTL_DISK_SET_PARTITION_INFO,
987 //--------------------- interface part
990 // Interface functions.
991 // Is_mounted is set to 1 if the device is mounted, 0 otherwise
995 ext2fs_check_if_mounted(const char *file, int *mount_flags)
1002 if(!_Ext2OpenDevice(file, TRUE, &h, &Readonly, NULL))
1009 *mount_flags &= _IsMounted(h) ? EXT2_MF_MOUNTED : 0;
1021 // Returns the number of blocks in a partition
1024 static __int64 FsSize = 0;
1025 static char knowndevice[1024] = "";
1029 ext2fs_get_device_size(const char *file, int blocksize,
1035 if((0 == FsSize) || (0 != strcmp(knowndevice, file)))
1038 if(!_Ext2OpenDevice(file, TRUE, &h, &Readonly, NULL))
1050 _GetDeviceSize(h, &FsSize);
1051 strcpy(knowndevice, file);
1059 *retblocks = (blk_t)(unsigned __int64)(FsSize / blocksize);
1060 UNREFERENCED_PARAMETER(file);
1076 nt_open(const char *name, int flags, io_channel *channel)
1078 io_channel io = NULL;
1079 PNT_PRIVATE_DATA NtData = NULL;
1080 errcode_t Errno = 0;
1088 return EXT2_ET_BAD_DEVICE_NAME;
1094 // Allocate channel handle
1097 io = (io_channel) malloc(sizeof(struct struct_io_channel));
1105 RtlZeroMemory(io, sizeof(struct struct_io_channel));
1106 io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
1108 NtData = (PNT_PRIVATE_DATA)malloc(sizeof(NT_PRIVATE_DATA));
1117 io->manager = nt_io_manager();
1118 io->name = malloc(strlen(name) + 1);
1119 if (NULL == io->name)
1125 strcpy(io->name, name);
1126 io->private_data = NtData;
1127 io->block_size = 1024;
1129 io->write_error = 0;
1136 RtlZeroMemory(NtData, sizeof(NT_PRIVATE_DATA));
1138 NtData->magic = EXT2_ET_MAGIC_NT_IO_CHANNEL;
1139 NtData->BufferBlockNumber = 0xffffffff;
1140 NtData->BufferSize = 1024;
1141 NtData->Buffer = malloc(NtData->BufferSize);
1143 if (NULL == NtData->Buffer)
1153 if(!_Ext2OpenDevice(name, (BOOLEAN)!BooleanFlagOn(flags, EXT2_FLAG_RW), &NtData->Handle, &NtData->OpenedReadonly, &Errno))
1163 _GetDeviceSize(NtData->Handle, &FsSize);
1164 strcpy(knowndevice, name);
1171 if(!NT_SUCCESS(_LockDrive(NtData->Handle)) /*|| !NT_SUCCESS(_DismountDrive(NtData->Handle))*/)
1173 NtData->OpenedReadonly = TRUE;
1194 if(NULL != io->name)
1204 if(NULL != NtData->Handle)
1206 _UnlockDrive(NtData->Handle);
1207 _CloseDisk(NtData->Handle);
1210 if(NULL != NtData->Buffer)
1212 free(NtData->Buffer);
1230 nt_close(io_channel channel)
1232 PNT_PRIVATE_DATA NtData = NULL;
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);
1243 if (--channel->refcount > 0)
1248 if(NULL != channel->name)
1250 free(channel->name);
1258 if(NULL != NtData->Handle)
1260 _DismountDrive(NtData->Handle);
1261 _UnlockDrive(NtData->Handle);
1262 _CloseDisk(NtData->Handle);
1265 if(NULL != NtData->Buffer)
1267 free(NtData->Buffer);
1284 nt_set_blksize(io_channel channel, int blksize)
1286 PNT_PRIVATE_DATA NtData = NULL;
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);
1292 if (channel->block_size != blksize)
1294 channel->block_size = blksize;
1296 free(NtData->Buffer);
1297 NtData->BufferBlockNumber = 0xffffffff;
1298 NtData->BufferSize = channel->block_size;
1299 ASSERT(0 == (NtData->BufferSize % 512));
1301 NtData->Buffer = malloc(NtData->BufferSize);
1303 if (NULL == NtData->Buffer)
1320 nt_read_blk(io_channel channel, unsigned long block,
1321 int count, void *buf)
1326 LARGE_INTEGER Offset;
1327 PNT_PRIVATE_DATA NtData = NULL;
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);
1335 // If it's in the cache, use it!
1339 (block == NtData->BufferBlockNumber) &&
1340 (NtData->BufferBlockNumber != 0xffffffff))
1342 memcpy(buf, NtData->Buffer, channel->block_size);
1346 Size = (count < 0) ? (ULONG)(-count) : (ULONG)(count * channel->block_size);
1348 Offset.QuadPart = block * channel->block_size;
1351 // If not fit to the block
1354 if(Size <= NtData->BufferSize)
1360 NtData->BufferBlockNumber = block;
1361 BufferToRead = NtData->Buffer;
1362 SizeToRead = NtData->BufferSize;
1368 ASSERT(0 == (SizeToRead % channel->block_size));
1371 if(!_RawRead(NtData->Handle, Offset, SizeToRead, BufferToRead, &Errno))
1374 if (channel->read_error)
1376 return (channel->read_error)(channel, block, count, buf,
1386 if(BufferToRead != buf)
1388 ASSERT(Size <= SizeToRead);
1389 memcpy(buf, BufferToRead, Size);
1402 nt_write_blk(io_channel channel, unsigned long block,
1403 int count, const void *buf)
1406 LARGE_INTEGER Offset;
1407 PNT_PRIVATE_DATA NtData = NULL;
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);
1414 if(NtData->OpenedReadonly)
1421 SizeToWrite = channel->block_size;
1425 NtData->BufferBlockNumber = 0xffffffff;
1429 SizeToWrite = (ULONG)(-count);
1433 SizeToWrite = (ULONG)(count * channel->block_size);
1438 ASSERT(0 == (SizeToWrite % 512));
1439 Offset.QuadPart = block * channel->block_size;
1441 if(!_RawWrite(NtData->Handle, Offset, SizeToWrite, buf, &Errno))
1443 if (channel->write_error)
1445 return (channel->write_error)(channel, block, count, buf,
1446 SizeToWrite, 0, Errno);
1459 if(SizeToWrite >= NtData->BufferSize)
1461 NtData->BufferBlockNumber = block;
1462 memcpy(NtData->Buffer, buf, NtData->BufferSize);
1465 NtData->Written = TRUE;
1474 // Flush data buffers to disk. Since we are currently using a
1475 // write-through cache, this is a no-op.
1480 nt_flush(io_channel channel)
1482 PNT_PRIVATE_DATA NtData = NULL;
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);
1488 if(NtData->OpenedReadonly)
1490 return 0; // EACCESS;
1495 // Flush file buffers.
1498 _FlushDrive(NtData->Handle);
1502 // Test and correct partition type.
1507 _SetPartType(NtData->Handle, 0x83);