📄 win32_io.c
字号:
/* * 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. * Originated from the Linux-NTFS project. * * Copyright (c) 2003-2004 Lode Leroy * Copyright (c) 2003-2006 Anton Altaparmakov * Copyright (c) 2004-2005 Yuval Fledel * * 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 NTFS-3G * 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 "config.h"#ifdef HAVE_WINDOWS_H#include <windows.h>#endif#include <winioctl.h>#ifdef HAVE_STDIO_H#include <stdio.h>#endif#ifdef HAVE_CTYPE_H#include <ctype.h>#endif#ifdef HAVE_ERRNO_H#include <errno.h>#endif#ifdef HAVE_FCNTL_H#include <fcntl.h>#endif/* Prevent volume.h from being be loaded, as it conflicts with winnt.h. */#define _NTFS_VOLUME_Hstruct ntfs_volume;typedef struct ntfs_volume ntfs_volume;#include "debug.h"#include "types.h"#include "device.h"#ifndef NTFS_BLOCK_SIZE#define NTFS_BLOCK_SIZE 512#define NTFS_BLOCK_SIZE_BITS 9#endif#ifndef IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS#define IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS 5636096#endif/* Windows 2k+ imports. */typedef HANDLE (WINAPI *LPFN_FINDFIRSTVOLUME)(LPTSTR, DWORD);typedef BOOL (WINAPI *LPFN_FINDNEXTVOLUME)(HANDLE, LPTSTR, DWORD);typedef BOOL (WINAPI *LPFN_FINDVOLUMECLOSE)(HANDLE);typedef BOOL (WINAPI *LPFN_SETFILEPOINTEREX)(HANDLE, LARGE_INTEGER, PLARGE_INTEGER, DWORD);static LPFN_FINDFIRSTVOLUME fnFindFirstVolume = NULL;static LPFN_FINDNEXTVOLUME fnFindNextVolume = NULL;static LPFN_FINDVOLUMECLOSE fnFindVolumeClose = NULL;static LPFN_SETFILEPOINTEREX fnSetFilePointerEx = NULL;#ifdef UNICODE#define FNPOSTFIX "W"#else#define FNPOSTFIX "A"#endif/** * struct win32_fd - */typedef struct { HANDLE handle; s64 pos; /* Logical current position on the volume. */ s64 part_start; s64 part_length; int part_hidden_sectors; s64 geo_size, geo_cylinders; DWORD geo_sectors, geo_heads; HANDLE vol_handle;} win32_fd;/** * ntfs_w32error_to_errno - convert a win32 error code to the unix one * @w32error: the win32 error code * * Limited to a relatively small but useful number of codes. */static int ntfs_w32error_to_errno(unsigned int w32error){ ntfs_log_trace("Converting w32error 0x%x.\n",w32error); switch (w32error) { case ERROR_INVALID_FUNCTION: return EBADRQC; case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: case ERROR_INVALID_NAME: return ENOENT; case ERROR_TOO_MANY_OPEN_FILES: return EMFILE; case ERROR_ACCESS_DENIED: return EACCES; case ERROR_INVALID_HANDLE: return EBADF; case ERROR_NOT_ENOUGH_MEMORY: return ENOMEM; case ERROR_OUTOFMEMORY: return ENOSPC; case ERROR_INVALID_DRIVE: case ERROR_BAD_UNIT: return ENODEV; case ERROR_WRITE_PROTECT: return EROFS; case ERROR_NOT_READY: case ERROR_SHARING_VIOLATION: return EBUSY; case ERROR_BAD_COMMAND: return EINVAL; case ERROR_SEEK: case ERROR_NEGATIVE_SEEK: return ESPIPE; case ERROR_NOT_SUPPORTED: return EOPNOTSUPP; case ERROR_BAD_NETPATH: return ENOSHARE; default: /* generic message */ return ENOMSG; }}/** * libntfs_SetFilePointerEx - emulation for SetFilePointerEx() * * We use this to emulate SetFilePointerEx() when it is not present. This can * happen since SetFilePointerEx() only exists in Win2k+. */static BOOL WINAPI libntfs_SetFilePointerEx(HANDLE hFile, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod){ liDistanceToMove.LowPart = SetFilePointer(hFile, liDistanceToMove.LowPart, &liDistanceToMove.HighPart, dwMoveMethod); if (liDistanceToMove.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) { if (lpNewFilePointer) lpNewFilePointer->QuadPart = -1; return FALSE; } if (lpNewFilePointer) lpNewFilePointer->QuadPart = liDistanceToMove.QuadPart; return TRUE;}/** * ntfs_device_win32_init_imports - initialize the function pointers * * The Find*Volume and SetFilePointerEx functions exist only on win2k+, as such * we cannot just staticly import them. * * This function initializes the imports if the functions do exist and in the * SetFilePointerEx case, we emulate the function ourselves if it is not * present. * * Note: The values are cached, do be afraid to run it more than once. */static void ntfs_device_win32_init_imports(void){ HMODULE kernel32 = GetModuleHandle("kernel32"); if (!kernel32) { errno = ntfs_w32error_to_errno(GetLastError()); ntfs_log_trace("kernel32.dll could not be imported.\n"); } if (!fnSetFilePointerEx) { if (kernel32) fnSetFilePointerEx = (LPFN_SETFILEPOINTEREX) GetProcAddress(kernel32, "SetFilePointerEx"); /* * If we did not get kernel32.dll or it is not Win2k+, emulate * SetFilePointerEx(). */ if (!fnSetFilePointerEx) { ntfs_log_debug("SetFilePonterEx() not found in " "kernel32.dll: Enabling emulation.\n"); fnSetFilePointerEx = libntfs_SetFilePointerEx; } } /* Cannot do lookups if we could not get kernel32.dll... */ if (!kernel32) return; if (!fnFindFirstVolume) fnFindFirstVolume = (LPFN_FINDFIRSTVOLUME) GetProcAddress(kernel32, "FindFirstVolume" FNPOSTFIX); if (!fnFindNextVolume) fnFindNextVolume = (LPFN_FINDNEXTVOLUME) GetProcAddress(kernel32, "FindNextVolume" FNPOSTFIX); if (!fnFindVolumeClose) fnFindVolumeClose = (LPFN_FINDVOLUMECLOSE) GetProcAddress(kernel32, "FindVolumeClose");}/** * ntfs_device_unix_status_flags_to_win32 - convert unix->win32 open flags * @flags: unix open status flags * * Supported flags are O_RDONLY, O_WRONLY and O_RDWR. */static __inline__ int ntfs_device_unix_status_flags_to_win32(int flags){ int win_mode; switch (flags & O_ACCMODE) { case O_RDONLY: win_mode = FILE_READ_DATA; break; case O_WRONLY: win_mode = FILE_WRITE_DATA; break; case O_RDWR: win_mode = FILE_READ_DATA | FILE_WRITE_DATA; break; default: /* error */ ntfs_log_trace("Unknown status flags.\n"); win_mode = 0; } return win_mode;}/** * ntfs_device_win32_simple_open_file - just open a file via win32 API * @filename: name of the file to open * @handle: pointer the a HANDLE in which to put the result * @flags: unix open status flags * @locking: will the function gain an exclusive lock on the file? * * Supported flags are O_RDONLY, O_WRONLY and O_RDWR. * * Return 0 if o.k. * -1 if not, and errno set. In this case handle is trashed. */static int ntfs_device_win32_simple_open_file(const char *filename, HANDLE *handle, int flags, BOOL locking){ *handle = CreateFile(filename, ntfs_device_unix_status_flags_to_win32(flags), locking ? 0 : (FILE_SHARE_WRITE | FILE_SHARE_READ), NULL, OPEN_EXISTING, 0, NULL); if (*handle == INVALID_HANDLE_VALUE) { errno = ntfs_w32error_to_errno(GetLastError()); ntfs_log_trace("CreateFile(%s) failed.\n", filename); return -1; } return 0;}/** * ntfs_device_win32_lock - lock the volume * @handle: a win32 HANDLE for a volume to lock * * Locking a volume means no one can access its contents. * Exiting the process automatically unlocks the volume, except in old NT4s. * * Return 0 if o.k. * -1 if not, and errno set. */static int ntfs_device_win32_lock(HANDLE handle){ DWORD i; if (!DeviceIoControl(handle, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &i, NULL)) { errno = ntfs_w32error_to_errno(GetLastError()); ntfs_log_trace("Couldn't lock volume.\n"); return -1; } ntfs_log_debug("Volume locked.\n"); return 0;}/** * ntfs_device_win32_unlock - unlock the volume * @handle: the win32 HANDLE which the volume was locked with * * Return 0 if o.k. * -1 if not, and errno set. */static int ntfs_device_win32_unlock(HANDLE handle){ DWORD i; if (!DeviceIoControl(handle, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &i, NULL)) { errno = ntfs_w32error_to_errno(GetLastError()); ntfs_log_trace("Couldn't unlock volume.\n"); return -1; } ntfs_log_debug("Volume unlocked.\n"); return 0;}/** * ntfs_device_win32_dismount - dismount a volume * @handle: a win32 HANDLE for a volume to dismount * * Dismounting means the system will refresh the volume in the first change it * gets. Usefull after altering the file structures. * The volume must be locked by the current process while dismounting. * A side effect is that the volume is also unlocked, but you must not rely om * this. * * Return 0 if o.k. * -1 if not, and errno set. */static int ntfs_device_win32_dismount(HANDLE handle){ DWORD i; if (!DeviceIoControl(handle, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &i, NULL)) { errno = ntfs_w32error_to_errno(GetLastError()); ntfs_log_trace("Couldn't dismount volume.\n"); return -1; } ntfs_log_debug("Volume dismounted.\n"); return 0;}/** * ntfs_device_win32_getsize - get file size via win32 API * @handle: pointer the file HANDLE obtained via open * * Only works on ordinary files. * * Return The file size if o.k. * -1 if not, and errno set. */static s64 ntfs_device_win32_getsize(HANDLE handle){ DWORD loword, hiword; loword = GetFileSize(handle, &hiword); if (loword == INVALID_FILE_SIZE) { errno = ntfs_w32error_to_errno(GetLastError()); ntfs_log_trace("Couldn't get file size.\n"); return -1; } return ((s64)hiword << 32) + loword;}/** * ntfs_device_win32_getdisklength - get disk size via win32 API * @handle: pointer the file HANDLE obtained via open * @argp: pointer to result buffer * * Only works on PhysicalDriveX type handles. * * Return The disk size if o.k. * -1 if not, and errno set. */static s64 ntfs_device_win32_getdisklength(HANDLE handle){ GET_LENGTH_INFORMATION buf; DWORD i; if (!DeviceIoControl(handle, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &buf, sizeof(buf), &i, NULL)) { errno = ntfs_w32error_to_errno(GetLastError()); ntfs_log_trace("Couldn't get disk length.\n"); return -1; } ntfs_log_debug("Disk length: %lld.\n", buf.Length.QuadPart); return buf.Length.QuadPart;}/** * ntfs_device_win32_getntfssize - get NTFS volume size via win32 API * @handle: pointer the file HANDLE obtained via open * @argp: pointer to result buffer * * Only works on NTFS volume handles. * An annoying bug in windows is that an NTFS volume does not occupy the entire * partition, namely not the last sector (which holds the backup boot sector, * and normally not interesting). * Use this function to get the length of the accessible space through a given * volume handle. * * Return The volume size if o.k. * -1 if not, and errno set. */static s64 ntfs_device_win32_getntfssize(HANDLE handle){ s64 rvl;#ifdef FSCTL_GET_NTFS_VOLUME_DATA DWORD i; NTFS_VOLUME_DATA_BUFFER buf; if (!DeviceIoControl(handle, FSCTL_GET_NTFS_VOLUME_DATA, NULL, 0, &buf, sizeof(buf), &i, NULL)) { errno = ntfs_w32error_to_errno(GetLastError()); ntfs_log_trace("Couldn't get NTFS volume length.\n"); return -1; } rvl = buf.NumberSectors.QuadPart * buf.BytesPerSector; ntfs_log_debug("NTFS volume length: 0x%llx.\n", (long long)rvl);#else errno = EINVAL; rvl = -1;#endif return rvl;}/** * ntfs_device_win32_getgeo - get CHS information of a drive * @handle: an open handle to the PhysicalDevice * @fd: a win_fd structure that will be filled * * Return 0 if o.k. * -1 if not, and errno set. * * In Windows NT+: fills size, sectors, and cylinders and sets heads to -1. * In Windows XP+: fills size, sectors, cylinders, and heads. * * Note: In pre XP, this requires write permission, even though nothing is * actually written. * * If fails, sets sectors, cylinders, heads, and size to -1. */static int ntfs_device_win32_getgeo(HANDLE handle, win32_fd *fd){ DWORD i; BOOL rvl; BYTE b[sizeof(DISK_GEOMETRY) + sizeof(DISK_PARTITION_INFO) + sizeof(DISK_DETECTION_INFO) + 512]; rvl = DeviceIoControl(handle, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, &b, sizeof(b), &i, NULL); if (rvl) { ntfs_log_debug("GET_DRIVE_GEOMETRY_EX detected.\n"); DISK_DETECTION_INFO *ddi = (PDISK_DETECTION_INFO) (((PBYTE)(&((PDISK_GEOMETRY_EX)b)->Data)) + (((PDISK_PARTITION_INFO) (&((PDISK_GEOMETRY_EX)b)->Data))-> SizeOfPartitionInfo)); fd->geo_cylinders = ((DISK_GEOMETRY*)&b)->Cylinders.QuadPart; fd->geo_sectors = ((DISK_GEOMETRY*)&b)->SectorsPerTrack; fd->geo_size = ((DISK_GEOMETRY_EX*)&b)->DiskSize.QuadPart; switch (ddi->DetectionType) { case DetectInt13: fd->geo_cylinders = ddi->Int13.MaxCylinders; fd->geo_sectors = ddi->Int13.SectorsPerTrack; fd->geo_heads = ddi->Int13.MaxHeads; return 0; case DetectExInt13: fd->geo_cylinders = ddi->ExInt13.ExCylinders; fd->geo_sectors = ddi->ExInt13.ExSectorsPerTrack; fd->geo_heads = ddi->ExInt13.ExHeads; return 0; case DetectNone: default: break; } } else fd->geo_heads = -1; rvl = DeviceIoControl(handle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &b, sizeof(b), &i, NULL); if (rvl) { ntfs_log_debug("GET_DRIVE_GEOMETRY detected.\n"); fd->geo_cylinders = ((DISK_GEOMETRY*)&b)->Cylinders.QuadPart; fd->geo_sectors = ((DISK_GEOMETRY*)&b)->SectorsPerTrack; fd->geo_size = fd->geo_cylinders * fd->geo_sectors * ((DISK_GEOMETRY*)&b)->TracksPerCylinder * ((DISK_GEOMETRY*)&b)->BytesPerSector; return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -