From b8a543a27e17003fa6e1766fbd53e010a734677d Mon Sep 17 00:00:00 2001 From: antona Date: Fri, 3 Jun 2005 10:27:32 +0000 Subject: [PATCH] Do dynamic run-time detection of SetFilePointerEx() instead of defunct autoconf crap. Also, fix a really stupid bug in the emulated SetFilePointerEx() which caused the segfaults. (It unconditionally wrote to a pointer even when it was NULL.) --- ChangeLog | 3 +- libntfs/win32_io.c | 195 +++++++++++++++++++++++++-------------------- 2 files changed, 112 insertions(+), 86 deletions(-) diff --git a/ChangeLog b/ChangeLog index c452c9c6..93575b4c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -130,7 +130,8 @@ xx/xx/2005 - 2.0.0-WIP - ntfsresize: fix segfault during filesystem check if NTFS was corrupted in a way that clusters were referenced outside of the volume. (Szaka) - Major rewrite of libntfs/win32_io.c and in particular seek, read, and - write related code. + write related code. As part of this perform run-time detection of + presence of SetFilePointerEx() and if not present emulate it. - ntfsclone: --rescue works at the lowest, sector and not cluster level thus more data can be rescued. The contents of the unreadable sectors are filled by character '?' and the beginning of such sectors are diff --git a/libntfs/win32_io.c b/libntfs/win32_io.c index db0b79ab..44ee1afa 100644 --- a/libntfs/win32_io.c +++ b/libntfs/win32_io.c @@ -54,17 +54,22 @@ typedef struct ntfs_volume ntfs_volume; #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); +/* 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 FUNCTIONPOSTFIX "W" +#define FNPOSTFIX "W" #else -#define FUNCTIONPOSTFIX "A" +#define FNPOSTFIX "A" #endif typedef struct win32_fd { @@ -79,29 +84,11 @@ typedef struct win32_fd { HANDLE vol_handle; } win32_fd; -#ifndef HAVE_SETFILEPOINTEREX -static BOOL WINAPI 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) { - lpNewFilePointer->QuadPart = -1; - return FALSE; - } - lpNewFilePointer->QuadPart = liDistanceToMove.QuadPart; - return TRUE; -} -#endif - /** * ntfs_w32error_to_errno - Convert a win32 error code to the unix one * @w32error The win32 error code. * - * Limited to a reletevly small but useful number of codes + * Limited to a relatively small but useful number of codes. */ static int ntfs_w32error_to_errno(unsigned int w32error) { @@ -146,6 +133,80 @@ static int ntfs_w32error_to_errno(unsigned int w32error) } } +/** + * 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()); + Dputs("Error: kernel32.dll not found in memory."); + } + 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) { + Dputs("SetFilePonterEx() not found in kernel32.dll: " + "Enabling emulation."); + 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. @@ -431,30 +492,6 @@ static int ntfs_device_win32_getgeo(HANDLE handle, win32_fd *fd) return -1; } -/** - * ntfs_device_win32_init_imports - initialize the fnFind*Volume variables. - * - * The Find*Volume functions exist only on win2k+, as such we can't - * just staticly import it. - * This function initialize the imports if the function do exist. - * - * Note: The values are cached, do be afraid to run it more than once. - */ -static void ntfs_device_win32_init_imports(void) -{ - if (!fnFindFirstVolume) - fnFindFirstVolume = (LPFN_FINDFIRSTVOLUME) - GetProcAddress(GetModuleHandle("kernel32"), - "FindFirstVolume"FUNCTIONPOSTFIX); - if (!fnFindNextVolume) - fnFindNextVolume = (LPFN_FINDNEXTVOLUME) - GetProcAddress(GetModuleHandle("kernel32"), - "FindNextVolume"FUNCTIONPOSTFIX); - if (!fnFindVolumeClose) - fnFindVolumeClose = (LPFN_FINDVOLUMECLOSE) - GetProcAddress(GetModuleHandle("kernel32"), "FindVolumeClose"); -} - /** * ntfs_device_win32_open_file - Open a file via win32 API * @filename: Name of the file to open. @@ -549,24 +586,20 @@ static HANDLE ntfs_device_win32_open_volume_for_partition(unsigned int drive_id, HANDLE vol_find_handle; TCHAR vol_name[MAX_PATH]; - ntfs_device_win32_init_imports(); - /* make sure all the required imports exist */ + /* Make sure all the required imports exist. */ if (!fnFindFirstVolume || !fnFindNextVolume || !fnFindVolumeClose) { - Dputs("win32_is_mounted: Imports not found."); + Dputs("win32_is_mounted: Required dll imports not found."); return INVALID_HANDLE_VALUE; } - - /* start iterating through volumes. */ + /* Start iterating through volumes. */ Dprintf("win32_open_volume_for_partition: Start\n"); vol_find_handle = fnFindFirstVolume(vol_name, MAX_PATH); - - /* if a valid handle could not be aquired, reply with "don't know" */ - if (vol_find_handle==INVALID_HANDLE_VALUE) { + /* If a valid handle could not be aquired, reply with "don't know". */ + if (vol_find_handle == INVALID_HANDLE_VALUE) { Dprintf("win32_open_volume_for_partition: " "FindFirstVolume failed."); return INVALID_HANDLE_VALUE; } - do { int vol_name_length; HANDLE handle; @@ -766,47 +799,39 @@ static int ntfs_device_win32_open(struct ntfs_device *dev, int flags) errno = EBUSY; return -1; } - + ntfs_device_win32_init_imports(); numparams = sscanf(dev->d_name, "/dev/hd%c%u", &drive_char, &part); drive_id = toupper(drive_char) - 'A'; - switch (numparams) { - case 0: - Dprintf("win32_open(%s) -> file\n", dev->d_name); - err = ntfs_device_win32_open_file(dev->d_name,&fd,flags); - break; - case 1: - Dprintf("win32_open(%s) -> drive %d\n", dev->d_name, drive_id); - err = ntfs_device_win32_open_drive(drive_id,&fd,flags); - break; - case 2: - Dprintf("win32_open(%s) -> drive %d, part %u\n", - dev->d_name, drive_id, part); - err = ntfs_device_win32_open_partition(drive_id,part,&fd,flags); - break; - default: - Dprintf("win32_open(%s) -> unknwon file format\n", dev->d_name); - err = -1; + case 0: + Dprintf("win32_open(%s) -> file\n", dev->d_name); + err = ntfs_device_win32_open_file(dev->d_name, &fd, flags); + break; + case 1: + Dprintf("win32_open(%s) -> drive %d\n", dev->d_name, drive_id); + err = ntfs_device_win32_open_drive(drive_id, &fd, flags); + break; + case 2: + Dprintf("win32_open(%s) -> drive %d, part %u\n", dev->d_name, + drive_id, part); + err = ntfs_device_win32_open_partition(drive_id, part, &fd, + flags); + break; + default: + Dprintf("win32_open(%s) -> unknwon file format\n", dev->d_name); + err = -1; } - - if (err) { - /* error */ + if (err) return err; - } - Dprintf("win32_open(%s) -> %p, offset 0x%llx\n", dev->d_name, dev, fd.part_start); - /* Setup our read-only flag. */ if ((flags & O_RDWR) != O_RDWR) NDevSetReadOnly(dev); - dev->d_private = malloc(sizeof(win32_fd)); memcpy(dev->d_private, &fd, sizeof(win32_fd)); - NDevSetOpen(dev); NDevClearDirty(dev); - return 0; }