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.)
edge.strict_endians
antona 2005-06-03 10:27:32 +00:00
parent 683b707b43
commit b8a543a27e
2 changed files with 112 additions and 86 deletions

View File

@ -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

View File

@ -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;
}