diff --git a/libntfs/win32_io.c b/libntfs/win32_io.c index e69de29b..9fecbfaa 100644 --- a/libntfs/win32_io.c +++ b/libntfs/win32_io.c @@ -0,0 +1,387 @@ +/* + * win32_io.c - A stdio-like disk I/O implementation for low-level disk access + * on Win32. Can access an NTFS volume while it is mounted. + * Part of the Linux-NTFS project. + * + * Copyright (c) 2003 Lode Leroy + * Copyright (c) 2003 Anton Altaparmakov + * + * This program/include file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program/include file is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (in the main directory of the Linux-NTFS + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include + +#include +#include + +/* + * Cannot use "../include/types.h" since it conflicts with "wintypes.h". + * define our own... + */ +typedef long long int s64; +struct flock; +struct stat; + +/* + * Need device, but prevent ../include/types.h to be loaded. + */ +#define _NTFS_TYPES_H +#include "device.h" + +#define FORCE_ALIGNED_READ + +typedef struct win32_fd { + HANDLE handle; + LARGE_INTEGER part_start; + LARGE_INTEGER part_end; + LARGE_INTEGER current_pos; +} win32_fd; + +#ifdef DEBUG +static __inline__ void Dprintf(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} +#else +static void Dprintf(const char *fmt, ...) +{ +} +#endif + +#define perror(msg) win32_perror(__FILE__,__LINE__,__FUNCTION__,msg) + +int +win32_perror(char *file, int line, char *func, char *msg) +{ + char buffer[1024] = ""; + DWORD err = GetLastError(); + + if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, buffer, + sizeof (buffer), NULL) <= 0) { + sprintf(buffer, "HRESULT 0x%lx", err); + } + fprintf(stderr, "%s(%d):%s\t%s %s\n", file, line, func, buffer, msg); + return 0; +} + +/** + * ntfs_device_win32_open - open a device + * @dev: ntfs device to open + * @flags: open flags + * + * If name is in format "(hd[0-9],[0-9])" then open a partition. + * If name is in format "(hd[0-9])" then open a volume. + * Otherwise open a file. + */ +static int ntfs_device_win32_open(struct ntfs_device *dev, int flags) +{ + int drive = 0, part = 0, numparams; + HANDLE handle; + win32_fd fd; + char drive_char, filename[256]; + + numparams = sscanf(dev->d_name, "/dev/hd%c%d", &drive_char, &part); + drive = toupper(drive_char) - 'A'; + part--; + + if (numparams >= 1) { + if (numparams == 2) + Dprintf("win32_open(%s) -> drive %d, part %d\n", + dev->d_name, drive, part); + else + Dprintf("win32_open(%s) -> drive %d\n", dev->d_name, + drive); + + sprintf(filename, "\\\\.\\PhysicalDrive%d", drive); + + handle = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, + NULL); + + if (handle == INVALID_HANDLE_VALUE) { + char msg[1024]; + + sprintf(msg, "CreateFile(%s) failed", filename); + perror(msg); + return -1; + } + + if (numparams == 1) { + fd.handle = handle; + fd.part_start.QuadPart = 0; + fd.part_end.QuadPart = -1; + fd.current_pos.QuadPart = 0; + } else { + char buffer[10240]; + DWORD numread; + DRIVE_LAYOUT_INFORMATION *drive_layout; + BOOL rvl; + + rvl = DeviceIoControl(handle, + IOCTL_DISK_GET_DRIVE_LAYOUT, NULL, 0, + &buffer, sizeof (buffer), &numread, + NULL); + if (!rvl) { + perror("ioctl failed"); + return -1; + } + + drive_layout = (DRIVE_LAYOUT_INFORMATION *)buffer; + + if (part >= drive_layout->PartitionCount) { + printf("partition %d not found on drive %d", + part, drive); + return -1; + } + + fd.handle = handle; + fd.part_start = drive_layout-> + PartitionEntry[part].StartingOffset; + fd.part_end.QuadPart = drive_layout-> + PartitionEntry[0].StartingOffset. + QuadPart + drive_layout-> + PartitionEntry[0].PartitionLength. + QuadPart; + fd.current_pos.QuadPart = 0; + } + } else { + BY_HANDLE_FILE_INFORMATION info; + BOOL rvl; + + Dprintf("win32_open(%s) -> file\n", dev->d_name); + + handle = CreateFile(dev->d_name, GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, 0, NULL); + + rvl = GetFileInformationByHandle(handle, &info); + if (!rvl) { + perror("ioctl failed"); + return -1; + } + + fd.handle = handle; + fd.part_start.QuadPart = 0; + fd.part_end.QuadPart = (((s64) info.nFileSizeHigh) << 32) + + ((s64) info.nFileSizeLow); + fd.current_pos.QuadPart = 0; + } + + Dprintf("win32_open(%s) -> %p, offset 0x%llx\n", dev->d_name, dev, + fd.part_start); + + dev->d_private = malloc(sizeof (win32_fd)); + memcpy(dev->d_private, &fd, sizeof (win32_fd)); + + return 0; +} + +static s64 ntfs_device_win32_seek(struct ntfs_device *dev, s64 offset, + int whence) +{ + LARGE_INTEGER abs_offset; + struct win32_fd *fd = (win32_fd *)dev->d_private; + int disp; + BOOL rvl; + + Dprintf("win32_seek(%lld=0x%llx,%d)\n", offset, offset, whence); + + switch (whence) { + case SEEK_SET: + disp = FILE_BEGIN; + abs_offset.QuadPart = fd->part_start.QuadPart + offset; + break; + case SEEK_CUR: + disp = FILE_CURRENT; + abs_offset.QuadPart = offset; + break; + case SEEK_END: + /* end of partition != end of disk */ + disp = FILE_BEGIN; + abs_offset.QuadPart = fd->part_end.QuadPart + offset; + break; + default: + printf("win32_seek() wrong mode %d\n", whence); + return -1; + } + + rvl = SetFilePointerEx(fd->handle, abs_offset, &fd->current_pos, disp); + if (!rvl) { + perror("SetFilePointer failed"); + return -1; + } + + return offset; +} + +static s64 ntfs_device_win32_read(struct ntfs_device *dev, void *buf, s64 count) +{ + struct win32_fd *fd = (win32_fd *)dev->d_private; + LARGE_INTEGER base, offset, numtoread; + DWORD numread = 0; + BOOL rvl = -1; + + offset.QuadPart = fd->current_pos.QuadPart & 0x1FF; + base.QuadPart = fd->current_pos.QuadPart - offset.QuadPart; + numtoread.QuadPart = ((count + offset.QuadPart - 1) | 0x1FF) + 1; + + Dprintf("win32_read(fd=%p,b=%p,count=0x%llx)->(%llx+%llx:%llx)\n", fd, + buf, count, base, offset, numtoread); + +#ifndef FORCE_ALIGNED_READ + if (((((long)buf) & ((s64)0x1FF)) == 0) && ((count & ((s64)0x1FF)) == 0) + && ((fd->current_pos.QuadPart & 0x1FF) == 0)) { + Dprintf("normal read\n"); + + rvl = ReadFile(fd->handle, (LPVOID)buf, count, &numread, + (LPOVERLAPPED)NULL); + } else { + BYTE *alignedbuffer; + + Dprintf("aligned read\n"); +#else + { + BYTE *alignedbuffer; +#endif + LARGE_INTEGER new_pos; + + alignedbuffer = (BYTE *)VirtualAlloc(NULL, count, MEM_COMMIT, + PAGE_READWRITE); + + Dprintf("set SetFilePointerEx(%llx)\n", base.QuadPart); + // FIXME: Why is rvl not being checked? (AIA) + rvl = SetFilePointerEx(fd->handle, base, NULL, FILE_BEGIN); + rvl = ReadFile(fd->handle, (LPVOID) alignedbuffer, + numtoread.QuadPart, &numread, + (LPOVERLAPPED)NULL); + + new_pos.QuadPart = fd->current_pos.QuadPart + count; + + Dprintf("reset SetFilePointerEx(%llx)\n", new_pos.QuadPart); + rvl = SetFilePointerEx(fd->handle, new_pos, &fd->current_pos, + FILE_BEGIN); + if (!rvl) + printf("SetFilePointerEx failed"); + + memcpy((void *)buf, alignedbuffer + offset.QuadPart, count); + VirtualFree(alignedbuffer, 0, MEM_RELEASE); + } + if (!rvl) { + perror("ReadFile failed"); + return -1; + } + + if (numread > count) + return count; + return numread; +} + +static int ntfs_device_win32_close(struct ntfs_device *dev) +{ + struct win32_fd *fd = (win32_fd *)dev->d_private; + BOOL rvl; + + Dprintf("win32_close(%p)\n", dev); + + rvl = CloseHandle(fd->handle); + fd->handle = 0; + + free(fd); + + if (!rvl) { + perror("CloseHandle failed"); + return -1; + } + + return 0; +} + +s64 win32_bias(struct ntfs_device *dev) +{ + struct win32_fd *fd = (win32_fd *)dev->d_private; + + return fd->part_start.QuadPart; +} + +s64 win32_filepos(struct ntfs_device *dev) +{ + struct win32_fd *fd = (win32_fd *)dev->d_private; + + return fd->current_pos.QuadPart; +} + +static int ntfs_device_win32_sync(struct ntfs_device *dev) +{ + Dprintf("win32_fsync() unimplemented\n"); + // FIXME: Should be returning error, e.g. ENOTSUP. (AIA) + return 0; +} + +static s64 ntfs_device_win32_write(struct ntfs_device *dev, const void *buffer, + s64 count) +{ + Dprintf("win32_write() unimplemented\n"); + // FIXME: Should be setting errno to e.g. ENOTSUP. (AIA) + return -1; +} + +static int ntfs_device_win32_stat(struct ntfs_device *dev, struct stat *buf) +{ + Dprintf("win32_fstat() unimplemented\n"); + // FIXME: Should be returning error, e.g. ENOTSUP. (AIA) + return 0; +} + +static int ntfs_device_win32_ioctl(struct ntfs_device *dev, int request, + void *argp) +{ + Dprintf("win32_ioctl() unimplemented\n"); + // FIXME: Should be returning error, e.g. ENOTSUP. (AIA) + return 0; +} + +extern s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count, + void *b); +static s64 ntfs_device_win32_pread(struct ntfs_device *dev, void *buf, + s64 count, s64 offset) +{ + return ntfs_pread(dev, offset, count, buf); +} + +extern s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count, + const void *b); +static s64 ntfs_device_win32_pwrite(struct ntfs_device *dev, const void *buf, + s64 count, s64 offset) +{ + return ntfs_pwrite(dev, offset, count, buf); +} + +struct ntfs_device_operations ntfs_device_win32_ops = { + .open = ntfs_device_win32_open, + .close = ntfs_device_win32_close, + .seek = ntfs_device_win32_seek, + .read = ntfs_device_win32_read, + .write = ntfs_device_win32_write, + .pread = ntfs_device_win32_pread, + .pwrite = ntfs_device_win32_pwrite, + .sync = ntfs_device_win32_sync, + .stat = ntfs_device_win32_stat, + .ioctl = ntfs_device_win32_ioctl +}; +