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 Library
11 * General Public License, version 2.
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 .magic = EXT2_ET_MAGIC_IO_MANAGER,
234 .name = "NT I/O Manager",
237 .set_blksize = nt_set_blksize,
238 .read_blk = nt_read_blk,
239 .write_blk = nt_write_blk,
244 // function to get API
247 io_manager nt_io_manager()
249 return &struct_nt_manager;
257 // This is a code to convert Win32 errors to unix errno
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 }
328 for (i = 0; i < (sizeof(ErrorTable)/sizeof(ErrorTable[0])); ++i)
330 if (WinError == ErrorTable[i].WinError)
332 return ErrorTable[i].errnocode;
337 // not in table. Check ranges
340 if ((WinError >= ERROR_WRITE_PROTECT) &&
341 (WinError <= ERROR_SHARING_BUFFER_EXCEEDED))
345 else if ((WinError >= ERROR_INVALID_STARTING_CODESEG) &&
346 (WinError <= ERROR_INFLOOP_IN_RELOC_CHAIN))
363 // Function to map NT status to dos error.
373 return _MapDosError(RtlNtStatusToDosError(Status));
381 // Helper functions to make things easier
390 OUT PBOOLEAN OpenedReadonly OPTIONAL
393 UNICODE_STRING UnicodeString;
394 ANSI_STRING AnsiString;
397 OBJECT_ATTRIBUTES ObjectAttributes;
398 IO_STATUS_BLOCK IoStatusBlock;
401 // Make Unicode name from input string
404 UnicodeString.Buffer = &Buffer[0];
405 UnicodeString.Length = 0;
406 UnicodeString.MaximumLength = sizeof(Buffer); // in bytes!!!
408 RtlInitAnsiString(&AnsiString, Name);
410 Status = RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, FALSE);
412 if(!NT_SUCCESS(Status))
414 return Status; // Unmappable character?
421 InitializeObjectAttributes(&ObjectAttributes,
423 OBJ_CASE_INSENSITIVE,
428 // Try to open it in initial mode
431 if(ARGUMENT_PRESENT(OpenedReadonly))
433 *OpenedReadonly = Readonly;
437 Status = NtOpenFile(Handle,
438 SYNCHRONIZE | FILE_READ_DATA | (Readonly ? 0 : FILE_WRITE_DATA),
441 FILE_SHARE_WRITE | FILE_SHARE_READ,
442 FILE_SYNCHRONOUS_IO_NONALERT);
444 if(!NT_SUCCESS(Status))
447 // Maybe was just mounted? wait 0.5 sec and retry.
450 LARGE_INTEGER Interval;
451 Interval.QuadPart = -5000000; // 0.5 sec. from now
453 NtDelayExecution(FALSE, &Interval);
455 Status = NtOpenFile(Handle,
456 SYNCHRONIZE | FILE_READ_DATA | (Readonly ? 0 : FILE_WRITE_DATA),
459 FILE_SHARE_WRITE | FILE_SHARE_READ,
460 FILE_SYNCHRONOUS_IO_NONALERT);
463 // Try to satisfy mode
466 if((STATUS_ACCESS_DENIED == Status) && !Readonly)
468 if(ARGUMENT_PRESENT(OpenedReadonly))
470 *OpenedReadonly = TRUE;
473 Status = NtOpenFile(Handle,
474 SYNCHRONIZE | FILE_READ_DATA,
477 FILE_SHARE_WRITE | FILE_SHARE_READ,
478 FILE_SYNCHRONOUS_IO_NONALERT);
498 OUT PBOOLEAN OpenedReadonly OPTIONAL
503 sprintf(Buffer, "\\DosDevices\\%c:", Letter);
505 return _OpenNtName(Buffer, ReadOnly, Handle, OpenedReadonly);
520 IO_STATUS_BLOCK IoStatusBlock;
521 return NtFlushBuffersFile(Handle, &IoStatusBlock);
536 IO_STATUS_BLOCK IoStatusBlock;
537 return NtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_LOCK_VOLUME, 0, 0, 0, 0);
552 IO_STATUS_BLOCK IoStatusBlock;
553 return NtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_UNLOCK_VOLUME, 0, 0, 0, 0);
563 IO_STATUS_BLOCK IoStatusBlock;
564 return NtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_DISMOUNT_VOLUME, 0, 0, 0, 0);
579 IO_STATUS_BLOCK IoStatusBlock;
581 Status = NtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_IS_VOLUME_MOUNTED, 0, 0, 0, 0);
582 return (BOOLEAN)(STATUS_SUCCESS == Status);
593 return NtClose(Handle);
600 // Make NT name from any recognized name
605 _NormalizeDeviceName(
607 IN PSTR NormalizedDeviceNameBuffer
610 int PartitionNumber = -1;
616 // Do not try to parse NT name
625 // Strip leading '/dev/' if any
628 if(('/' == *(Device)) &&
629 ('d' == *(Device + 1)) &&
630 ('e' == *(Device + 2)) &&
631 ('v' == *(Device + 3)) &&
632 ('/' == *(Device + 4)))
644 // forms: hda[n], fd[n]
647 if('d' != *(Device + 1))
654 if((*(Device + 2) < 'a') || (*(Device + 2) > ('a' + 9)) ||
655 ((*(Device + 3) != '\0') &&
656 ((*(Device + 4) != '\0') ||
657 ((*(Device + 3) < '0') || (*(Device + 3) > '9'))
665 DiskNumber = (UCHAR)(*(Device + 2) - 'a');
667 if(*(Device + 3) != '\0')
669 PartitionNumber = (*(Device + 3) - '0');
673 else if('f' == *Device)
676 // 3-d letter should be a digit.
679 if((*(Device + 3) != '\0') ||
680 (*(Device + 2) < '0') || (*(Device + 2) > '9'))
685 DiskNumber = (UCHAR)(*(Device + 2) - '0');
703 strcpy(NormalizedDeviceNameBuffer, "\\Device\\");
713 strcat(NormalizedDeviceNameBuffer, "Floppy0");
717 strcat(NormalizedDeviceNameBuffer, "Harddisk0");
722 p = NormalizedDeviceNameBuffer + strlen(NormalizedDeviceNameBuffer) - 1;
723 *p = (CHAR)(*p + DiskNumber);
730 if(PartitionNumber >= 0)
732 strcat(NormalizedDeviceNameBuffer, "\\Partition0");
734 p = NormalizedDeviceNameBuffer + strlen(NormalizedDeviceNameBuffer) - 1;
735 *p = (CHAR)(*p + PartitionNumber);
739 return NormalizedDeviceNameBuffer;
749 OUT unsigned __int64 *FsSize
752 PARTITION_INFORMATION pi;
755 IO_STATUS_BLOCK IoStatusBlock;
767 RtlZeroMemory(&pi, sizeof(PARTITION_INFORMATION));
769 Status = NtDeviceIoControlFile(
770 h, NULL, NULL, NULL, &IoStatusBlock, IOCTL_DISK_GET_PARTITION_INFO,
771 &pi, sizeof(PARTITION_INFORMATION),
772 &pi, sizeof(PARTITION_INFORMATION));
775 if(NT_SUCCESS(Status))
777 *FsSize = pi.PartitionLength.QuadPart;
779 else if(STATUS_INVALID_DEVICE_REQUEST == Status)
782 // No partitions: get device info.
785 RtlZeroMemory(&gi, sizeof(DISK_GEOMETRY));
787 Status = NtDeviceIoControlFile(
788 h, NULL, NULL, NULL, &IoStatusBlock, IOCTL_DISK_GET_DRIVE_GEOMETRY,
789 &gi, sizeof(DISK_GEOMETRY),
790 &gi, sizeof(DISK_GEOMETRY));
793 if(NT_SUCCESS(Status))
798 gi.TracksPerCylinder *
799 gi.Cylinders.QuadPart;
808 // Open device by name.
817 OUT PBOOLEAN OpenedReadonly OPTIONAL,
818 OUT unsigned *Errno OPTIONAL
821 CHAR NormalizedDeviceName[512];
830 if(ARGUMENT_PRESENT(Errno))
837 if((((*Name) | 0x20) >= 'a') && (((*Name) | 0x20) <= 'z') &&
838 (':' == *(Name + 1)) && ('\0' == *(Name + 2)))
840 Status = _OpenDriveLetter(*Name, ReadOnly, Handle, OpenedReadonly);
848 Name = _NormalizeDeviceName(Name, NormalizedDeviceName);
856 if(ARGUMENT_PRESENT(Errno))
866 Status = _OpenNtName(Name, ReadOnly, Handle, OpenedReadonly);
870 if(!NT_SUCCESS(Status))
872 if(ARGUMENT_PRESENT(Errno))
873 *Errno = _MapNtStatus(Status);
883 // Raw block io. Sets dos errno
890 IN LARGE_INTEGER Offset,
897 IO_STATUS_BLOCK IoStatusBlock;
904 ASSERT(0 == (Bytes % 512));
905 ASSERT(0 == (Offset.LowPart % 512));
914 Status = NtReadFile(Handle, NULL, NULL, NULL,
915 &IoStatusBlock, Buffer, Bytes, &Offset, NULL);
919 Status = NtWriteFile(Handle, NULL, NULL, NULL,
920 &IoStatusBlock, Buffer, Bytes, &Offset, NULL);
928 if(NT_SUCCESS(Status))
934 *Errno = _MapNtStatus(Status);
945 IN LARGE_INTEGER Offset,
947 OUT const CHAR* Buffer,
951 return _BlockIo(Handle, Offset, Bytes, (PCHAR)Buffer, FALSE, Errno);
958 IN LARGE_INTEGER Offset,
964 return _BlockIo(Handle, Offset, Bytes, Buffer, TRUE, Errno);
976 IO_STATUS_BLOCK IoStatusBlock;
977 return STATUS_SUCCESS == NtDeviceIoControlFile(
978 Handle, NULL, NULL, NULL, &IoStatusBlock, IOCTL_DISK_SET_PARTITION_INFO,
985 //--------------------- interface part
988 // Interface functions.
989 // Is_mounted is set to 1 if the device is mounted, 0 otherwise
993 ext2fs_check_if_mounted(const char *file, int *mount_flags)
1000 if(!_Ext2OpenDevice(file, TRUE, &h, &Readonly, NULL))
1007 *mount_flags &= _IsMounted(h) ? EXT2_MF_MOUNTED : 0;
1019 // Returns the number of blocks in a partition
1022 static __int64 FsSize = 0;
1023 static char knowndevice[1024] = "";
1027 ext2fs_get_device_size(const char *file, int blocksize,
1033 if((0 == FsSize) || (0 != strcmp(knowndevice, file)))
1036 if(!_Ext2OpenDevice(file, TRUE, &h, &Readonly, NULL))
1048 _GetDeviceSize(h, &FsSize);
1049 strcpy(knowndevice, file);
1057 *retblocks = (blk_t)(unsigned __int64)(FsSize / blocksize);
1058 UNREFERENCED_PARAMETER(file);
1074 nt_open(const char *name, int flags, io_channel *channel)
1076 io_channel io = NULL;
1077 PNT_PRIVATE_DATA NtData = NULL;
1078 errcode_t Errno = 0;
1086 return EXT2_ET_BAD_DEVICE_NAME;
1092 // Allocate channel handle
1095 io = (io_channel) malloc(sizeof(struct struct_io_channel));
1103 RtlZeroMemory(io, sizeof(struct struct_io_channel));
1104 io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
1106 NtData = (PNT_PRIVATE_DATA)malloc(sizeof(NT_PRIVATE_DATA));
1115 io->manager = nt_io_manager();
1116 io->name = malloc(strlen(name) + 1);
1117 if (NULL == io->name)
1123 strcpy(io->name, name);
1124 io->private_data = NtData;
1125 io->block_size = 1024;
1127 io->write_error = 0;
1134 RtlZeroMemory(NtData, sizeof(NT_PRIVATE_DATA));
1136 NtData->magic = EXT2_ET_MAGIC_NT_IO_CHANNEL;
1137 NtData->BufferBlockNumber = 0xffffffff;
1138 NtData->BufferSize = 1024;
1139 NtData->Buffer = malloc(NtData->BufferSize);
1141 if (NULL == NtData->Buffer)
1151 if(!_Ext2OpenDevice(name, (BOOLEAN)!BooleanFlagOn(flags, EXT2_FLAG_RW), &NtData->Handle, &NtData->OpenedReadonly, &Errno))
1161 _GetDeviceSize(NtData->Handle, &FsSize);
1162 strcpy(knowndevice, name);
1169 if(!NT_SUCCESS(_LockDrive(NtData->Handle)) /*|| !NT_SUCCESS(_DismountDrive(NtData->Handle))*/)
1171 NtData->OpenedReadonly = TRUE;
1198 if(NULL != NtData->Handle)
1200 _UnlockDrive(NtData->Handle);
1201 _CloseDisk(NtData->Handle);
1204 free(NtData->Buffer);
1220 nt_close(io_channel channel)
1222 PNT_PRIVATE_DATA NtData = NULL;
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);
1233 if (--channel->refcount > 0)
1238 free(channel->name);
1243 if(NULL != NtData->Handle)
1245 _DismountDrive(NtData->Handle);
1246 _UnlockDrive(NtData->Handle);
1247 _CloseDisk(NtData->Handle);
1250 free(NtData->Buffer);
1265 nt_set_blksize(io_channel channel, int blksize)
1267 PNT_PRIVATE_DATA NtData = NULL;
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);
1273 if (channel->block_size != blksize)
1275 channel->block_size = blksize;
1277 free(NtData->Buffer);
1278 NtData->BufferBlockNumber = 0xffffffff;
1279 NtData->BufferSize = channel->block_size;
1280 ASSERT(0 == (NtData->BufferSize % 512));
1282 NtData->Buffer = malloc(NtData->BufferSize);
1284 if (NULL == NtData->Buffer)
1301 nt_read_blk(io_channel channel, unsigned long block,
1302 int count, void *buf)
1307 LARGE_INTEGER Offset;
1308 PNT_PRIVATE_DATA NtData = NULL;
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);
1316 // If it's in the cache, use it!
1320 (block == NtData->BufferBlockNumber) &&
1321 (NtData->BufferBlockNumber != 0xffffffff))
1323 memcpy(buf, NtData->Buffer, channel->block_size);
1327 Size = (count < 0) ? (ULONG)(-count) : (ULONG)(count * channel->block_size);
1329 Offset.QuadPart = block * channel->block_size;
1332 // If not fit to the block
1335 if(Size <= NtData->BufferSize)
1341 NtData->BufferBlockNumber = block;
1342 BufferToRead = NtData->Buffer;
1343 SizeToRead = NtData->BufferSize;
1349 ASSERT(0 == (SizeToRead % channel->block_size));
1352 if(!_RawRead(NtData->Handle, Offset, SizeToRead, BufferToRead, &Errno))
1355 if (channel->read_error)
1357 return (channel->read_error)(channel, block, count, buf,
1367 if(BufferToRead != buf)
1369 ASSERT(Size <= SizeToRead);
1370 memcpy(buf, BufferToRead, Size);
1383 nt_write_blk(io_channel channel, unsigned long block,
1384 int count, const void *buf)
1387 LARGE_INTEGER Offset;
1388 PNT_PRIVATE_DATA NtData = NULL;
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);
1395 if(NtData->OpenedReadonly)
1402 SizeToWrite = channel->block_size;
1406 NtData->BufferBlockNumber = 0xffffffff;
1410 SizeToWrite = (ULONG)(-count);
1414 SizeToWrite = (ULONG)(count * channel->block_size);
1419 ASSERT(0 == (SizeToWrite % 512));
1420 Offset.QuadPart = block * channel->block_size;
1422 if(!_RawWrite(NtData->Handle, Offset, SizeToWrite, buf, &Errno))
1424 if (channel->write_error)
1426 return (channel->write_error)(channel, block, count, buf,
1427 SizeToWrite, 0, Errno);
1440 if(SizeToWrite >= NtData->BufferSize)
1442 NtData->BufferBlockNumber = block;
1443 memcpy(NtData->Buffer, buf, NtData->BufferSize);
1446 NtData->Written = TRUE;
1455 // Flush data buffers to disk. Since we are currently using a
1456 // write-through cache, this is a no-op.
1461 nt_flush(io_channel channel)
1463 PNT_PRIVATE_DATA NtData = NULL;
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);
1469 if(NtData->OpenedReadonly)
1471 return 0; // EACCESS;
1476 // Flush file buffers.
1479 _FlushDrive(NtData->Handle);
1483 // Test and correct partition type.
1488 _SetPartType(NtData->Handle, 0x83);