summaryrefslogtreecommitdiff
Diffstat
-rwxr-xr-xAUTHORS23
-rwxr-xr-xAndroid.mk89
-rwxr-xr-xAndroid.mk.bak89
-rwxr-xr-xCOPYING340
-rwxr-xr-xCOPYING.LIB482
-rwxr-xr-xCREDITS41
-rwxr-xr-xChangeLog7
-rwxr-xr-xINSTALL237
-rwxr-xr-xMakefile715
-rwxr-xr-xMakefile.am66
-rwxr-xr-xMakefile.in722
-rwxr-xr-xNEWS5
-rwxr-xr-xREADME68
-rwxr-xr-xaclocal.m47723
-rwxr-xr-xautogen.sh22
-rwxr-xr-xcompile142
-rwxr-xr-xconfig.guess1536
-rwxr-xr-xconfig.h361
-rwxr-xr-xconfig.h.in350
-rwxr-xr-xconfig.log3290
-rwxr-xr-xconfig.status1220
-rwxr-xr-xconfig.sub1658
-rwxr-xr-xconfigure25302
-rwxr-xr-xconfigure.ac441
-rwxr-xr-xdepcomp589
-rwxr-xr-xinclude/Makefile.am4
-rwxr-xr-xinclude/Makefile.in503
-rwxr-xr-xinclude/fuse-lite/Makefile.am10
-rwxr-xr-xinclude/fuse-lite/Makefile.in400
-rwxr-xr-xinclude/fuse-lite/fuse.h654
-rwxr-xr-xinclude/fuse-lite/fuse_common.h193
-rwxr-xr-xinclude/fuse-lite/fuse_kernel.h422
-rwxr-xr-xinclude/fuse-lite/fuse_lowlevel.h1375
-rwxr-xr-xinclude/fuse-lite/fuse_lowlevel_compat.h16
-rwxr-xr-xinclude/fuse-lite/fuse_opt.h261
-rwxr-xr-xinclude/ntfs-3g/Makefile.am45
-rwxr-xr-xinclude/ntfs-3g/Makefile.in471
-rwxr-xr-xinclude/ntfs-3g/acls.h199
-rwxr-xr-xinclude/ntfs-3g/attrib.h358
-rwxr-xr-xinclude/ntfs-3g/attrlist.h51
-rwxr-xr-xinclude/ntfs-3g/bitmap.h96
-rwxr-xr-xinclude/ntfs-3g/bootsect.h42
-rwxr-xr-xinclude/ntfs-3g/cache.h115
-rwxr-xr-xinclude/ntfs-3g/collate.h34
-rwxr-xr-xinclude/ntfs-3g/compat.h69
-rwxr-xr-xinclude/ntfs-3g/compress.h39
-rwxr-xr-xinclude/ntfs-3g/debug.h47
-rwxr-xr-xinclude/ntfs-3g/device.h128
-rwxr-xr-xinclude/ntfs-3g/device_io.h77
-rwxr-xr-xinclude/ntfs-3g/dir.h128
-rwxr-xr-xinclude/ntfs-3g/efs.h30
-rwxr-xr-xinclude/ntfs-3g/endians.h203
-rwxr-xr-xinclude/ntfs-3g/index.h167
-rwxr-xr-xinclude/ntfs-3g/inode.h225
-rwxr-xr-xinclude/ntfs-3g/layout.h2661
-rwxr-xr-xinclude/ntfs-3g/lcnalloc.h50
-rwxr-xr-xinclude/ntfs-3g/logfile.h394
-rwxr-xr-xinclude/ntfs-3g/logging.h118
-rwxr-xr-xinclude/ntfs-3g/mft.h132
-rwxr-xr-xinclude/ntfs-3g/misc.h30
-rwxr-xr-xinclude/ntfs-3g/mst.h34
-rwxr-xr-xinclude/ntfs-3g/ntfstime.h131
-rwxr-xr-xinclude/ntfs-3g/object_id.h35
-rwxr-xr-xinclude/ntfs-3g/param.h63
-rwxr-xr-xinclude/ntfs-3g/reparse.h39
-rwxr-xr-xinclude/ntfs-3g/runlist.h89
-rwxr-xr-xinclude/ntfs-3g/security.h353
-rwxr-xr-xinclude/ntfs-3g/support.h85
-rwxr-xr-xinclude/ntfs-3g/types.h124
-rwxr-xr-xinclude/ntfs-3g/unistr.h116
-rwxr-xr-xinclude/ntfs-3g/volume.h277
-rwxr-xr-xinstall-sh519
-rwxr-xr-xlibfuse-lite/Makefile.am28
-rwxr-xr-xlibfuse-lite/Makefile.in572
-rwxr-xr-xlibfuse-lite/fuse.c2789
-rwxr-xr-xlibfuse-lite/fuse_i.h25
-rwxr-xr-xlibfuse-lite/fuse_kern_chan.c96
-rwxr-xr-xlibfuse-lite/fuse_loop.c40
-rwxr-xr-xlibfuse-lite/fuse_lowlevel.c1395
-rwxr-xr-xlibfuse-lite/fuse_misc.h106
-rwxr-xr-xlibfuse-lite/fuse_opt.c368
-rwxr-xr-xlibfuse-lite/fuse_session.c183
-rwxr-xr-xlibfuse-lite/fuse_signals.c73
-rwxr-xr-xlibfuse-lite/fusermount.c772
-rwxr-xr-xlibfuse-lite/helper.c40
-rwxr-xr-xlibfuse-lite/mount.c256
-rwxr-xr-xlibfuse-lite/mount_util.c219
-rwxr-xr-xlibfuse-lite/mount_util.h22
-rwxr-xr-xlibntfs-3g/Makefile.am79
-rwxr-xr-xlibntfs-3g/Makefile.in841
-rwxr-xr-xlibntfs-3g/acls.c4296
-rwxr-xr-xlibntfs-3g/attrib.c5913
-rwxr-xr-xlibntfs-3g/attrlist.c314
-rwxr-xr-xlibntfs-3g/bitmap.c300
-rwxr-xr-xlibntfs-3g/bootsect.c285
-rwxr-xr-xlibntfs-3g/cache.c609
-rwxr-xr-xlibntfs-3g/collate.c271
-rwxr-xr-xlibntfs-3g/compat.c250
-rwxr-xr-xlibntfs-3g/compress.c1431
-rwxr-xr-xlibntfs-3g/debug.c79
-rwxr-xr-xlibntfs-3g/device.c730
-rwxr-xr-xlibntfs-3g/dir.c2582
-rwxr-xr-xlibntfs-3g/efs.c346
-rwxr-xr-xlibntfs-3g/index.c2063
-rwxr-xr-xlibntfs-3g/inode.c1566
-rwxr-xr-xlibntfs-3g/lcnalloc.c735
-rwxr-xr-xlibntfs-3g/libntfs-3g.pc.in10
-rwxr-xr-xlibntfs-3g/libntfs-3g.script.so.in2
-rwxr-xr-xlibntfs-3g/logfile.c737
-rwxr-xr-xlibntfs-3g/logging.c613
-rwxr-xr-xlibntfs-3g/mft.c1909
-rwxr-xr-xlibntfs-3g/misc.c61
-rwxr-xr-xlibntfs-3g/mst.c231
-rwxr-xr-xlibntfs-3g/object_id.c637
-rwxr-xr-xlibntfs-3g/reparse.c1222
-rwxr-xr-xlibntfs-3g/runlist.c2166
-rwxr-xr-xlibntfs-3g/security.c5167
-rwxr-xr-xlibntfs-3g/unistr.c1321
-rwxr-xr-xlibntfs-3g/unix_io.c386
-rwxr-xr-xlibntfs-3g/volume.c1663
-rwxr-xr-xlibntfs-3g/win32_io.c1477
-rwxr-xr-xlibtool7621
-rwxr-xr-xltmain.sh6956
-rwxr-xr-xm4/.keep0
-rwxr-xr-xmissing367
-rwxr-xr-xprog.IAB1071
-rwxr-xr-xprog.IAD5
-rwxr-xr-xprog.IMB466
-rwxr-xr-xprog.IMD2
-rwxr-xr-xprog.PFI2
-rwxr-xr-xprog.PO1
-rwxr-xr-xprog.PR14
-rwxr-xr-xprog.PRI219
-rwxr-xr-xprog.PS979
-rwxr-xr-xprog.SearchResults3
-rwxr-xr-xprog.WK39
-rwxr-xr-xsrc/lowntfs-3g.c4492
-rwxr-xr-xsrc/ntfs-3g.8.in349
-rwxr-xr-xsrc/ntfs-3g.c4461
-rwxr-xr-xsrc/ntfs-3g.probe.8.in81
-rwxr-xr-xsrc/ntfs-3g.probe.c163
-rwxr-xr-xsrc/ntfs-3g.secaudit.8.in171
-rwxr-xr-xsrc/ntfs-3g.usermap.8.in96
-rwxr-xr-xsrc/secaudit.c7176
-rwxr-xr-xsrc/secaudit.h731
-rwxr-xr-xsrc/test.c88
-rwxr-xr-xsrc/usermap.c1356
-rwxr-xr-xstamp-h11
148 files changed, 141286 insertions, 0 deletions
diff --git a/libntfs-3g/win32_io.c b/libntfs-3g/win32_io.c
new file mode 100755
index 0000000..ed9fa52
--- a/dev/null
+++ b/libntfs-3g/win32_io.c
@@ -0,0 +1,1477 @@
+/*
+ * 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_H
+struct ntfs_volume;
+typedef struct ntfs_volume ntfs_volume;
+
+#include "debug.h"
+#include "types.h"
+#include "device.h"
+
+#ifndef MAX_PATH
+#define MAX_PATH 1024
+#endif
+
+#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;
+ }
+ errno = ntfs_w32error_to_errno(GetLastError());
+ ntfs_log_trace("Couldn't retrieve disk geometry.\n");
+ fd->geo_cylinders = -1;
+ fd->geo_sectors = -1;
+ fd->geo_size = -1;
+ return -1;
+}
+
+/**
+ * ntfs_device_win32_open_file - open a file via win32 API
+ * @filename: name of the file to open
+ * @fd: pointer to win32 file device in which to put the result
+ * @flags: unix open status flags
+ *
+ * Return 0 if o.k.
+ * -1 if not, and errno set.
+ */
+static __inline__ int ntfs_device_win32_open_file(char *filename, win32_fd *fd,
+ int flags)
+{
+ HANDLE handle;
+
+ if (ntfs_device_win32_simple_open_file(filename, &handle, flags,
+ FALSE)) {
+ /* open error */
+ return -1;
+ }
+ /* fill fd */
+ fd->handle = handle;
+ fd->part_start = 0;
+ fd->part_length = ntfs_device_win32_getsize(handle);
+ fd->pos = 0;
+ fd->part_hidden_sectors = -1;
+ fd->geo_size = -1; /* used as a marker that this is a file */
+ fd->vol_handle = INVALID_HANDLE_VALUE;
+ return 0;
+}
+
+/**
+ * ntfs_device_win32_open_drive - open a drive via win32 API
+ * @drive_id: drive to open
+ * @fd: pointer to win32 file device in which to put the result
+ * @flags: unix open status flags
+ *
+ * return 0 if o.k.
+ * -1 if not, and errno set.
+ */
+static __inline__ int ntfs_device_win32_open_drive(int drive_id, win32_fd *fd,
+ int flags)
+{
+ HANDLE handle;
+ int err;
+ char filename[MAX_PATH];
+
+ sprintf(filename, "\\\\.\\PhysicalDrive%d", drive_id);
+ if ((err = ntfs_device_win32_simple_open_file(filename, &handle, flags,
+ TRUE))) {
+ /* open error */
+ return err;
+ }
+ /* store the drive geometry */
+ ntfs_device_win32_getgeo(handle, fd);
+ /* Just to be sure */
+ if (fd->geo_size == -1)
+ fd->geo_size = ntfs_device_win32_getdisklength(handle);
+ /* fill fd */
+ fd->handle = handle;
+ fd->part_start = 0;
+ fd->part_length = fd->geo_size;
+ fd->pos = 0;
+ fd->part_hidden_sectors = -1;
+ fd->vol_handle = INVALID_HANDLE_VALUE;
+ return 0;
+}
+
+/**
+ * ntfs_device_win32_open_volume_for_partition - find and open a volume
+ *
+ * Windows NT/2k/XP handles volumes instead of partitions.
+ * This function gets the partition details and return an open volume handle.
+ * That volume is the one whose only physical location on disk is the described
+ * partition.
+ *
+ * The function required Windows 2k/XP, otherwise it fails (gracefully).
+ *
+ * Return success: a valid open volume handle.
+ * fail : INVALID_HANDLE_VALUE
+ */
+static HANDLE ntfs_device_win32_open_volume_for_partition(unsigned int drive_id,
+ s64 part_offset, s64 part_length, int flags)
+{
+ HANDLE vol_find_handle;
+ TCHAR vol_name[MAX_PATH];
+
+ /* Make sure all the required imports exist. */
+ if (!fnFindFirstVolume || !fnFindNextVolume || !fnFindVolumeClose) {
+ ntfs_log_trace("Required dll imports not found.\n");
+ return INVALID_HANDLE_VALUE;
+ }
+ /* Start iterating through volumes. */
+ ntfs_log_trace("Entering with drive_id=%d, part_offset=%lld, "
+ "path_length=%lld, flags=%d.\n", drive_id,
+ (unsigned long long)part_offset,
+ (unsigned long long)part_length, flags);
+ 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) {
+ ntfs_log_trace("FindFirstVolume failed.\n");
+ return INVALID_HANDLE_VALUE;
+ }
+ do {
+ int vol_name_length;
+ HANDLE handle;
+
+ /* remove trailing '/' from vol_name */
+#ifdef UNICODE
+ vol_name_length = wcslen(vol_name);
+#else
+ vol_name_length = strlen(vol_name);
+#endif
+ if (vol_name_length>0)
+ vol_name[vol_name_length-1]=0;
+
+ ntfs_log_debug("Processing %s.\n", vol_name);
+ /* open the file */
+ handle = CreateFile(vol_name,
+ ntfs_device_unix_status_flags_to_win32(flags),
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+ OPEN_EXISTING, 0, NULL);
+ if (handle != INVALID_HANDLE_VALUE) {
+ DWORD bytesReturned;
+#define EXTENTS_SIZE sizeof(VOLUME_DISK_EXTENTS) + 9 * sizeof(DISK_EXTENT)
+ char extents[EXTENTS_SIZE];
+
+ /* Check physical locations. */
+ if (DeviceIoControl(handle,
+ IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
+ NULL, 0, extents, EXTENTS_SIZE,
+ &bytesReturned, NULL)) {
+ if (((VOLUME_DISK_EXTENTS *)extents)->
+ NumberOfDiskExtents == 1) {
+ DISK_EXTENT *extent = &((
+ VOLUME_DISK_EXTENTS *)
+ extents)->Extents[0];
+ if ((extent->DiskNumber==drive_id) &&
+ (extent->StartingOffset.
+ QuadPart==part_offset)
+ && (extent->
+ ExtentLength.QuadPart
+ == part_length)) {
+ /*
+ * Eureka! (Archimedes, 287 BC,
+ * "I have found it!")
+ */
+ fnFindVolumeClose(
+ vol_find_handle);
+ return handle;
+ }
+ }
+ }
+ } else
+ ntfs_log_trace("getExtents() Failed.\n");
+ } while (fnFindNextVolume(vol_find_handle, vol_name, MAX_PATH));
+ /* End of iteration through volumes. */
+ ntfs_log_trace("Closing, volume was not found.\n");
+ fnFindVolumeClose(vol_find_handle);
+ return INVALID_HANDLE_VALUE;
+}
+
+/**
+ * ntfs_device_win32_find_partition - locates partition details by id.
+ * @handle: HANDLE to the PhysicalDrive
+ * @partition_id: the partition number to locate
+ * @part_offset: pointer to where to put the offset to the partition
+ * @part_length: pointer to where to put the length of the partition
+ * @hidden_sectors: pointer to where to put the hidden sectors
+ *
+ * This function requires an open PhysicalDrive handle and a partition_id.
+ * If a partition with the required id is found on the supplied device,
+ * the partition attributes are returned back.
+ *
+ * Returns: TRUE if found, and sets the output parameters.
+ * FALSE if not and errno is set to the error code.
+ */
+static BOOL ntfs_device_win32_find_partition(HANDLE handle, DWORD partition_id,
+ s64 *part_offset, s64 *part_length, int *hidden_sectors)
+{
+ DRIVE_LAYOUT_INFORMATION *drive_layout;
+ unsigned int err, buf_size, part_count;
+ DWORD i;
+
+ /*
+ * There is no way to know the required buffer, so if the ioctl fails,
+ * try doubling the buffer size each time until the ioctl succeeds.
+ */
+ part_count = 8;
+ do {
+ buf_size = sizeof(DRIVE_LAYOUT_INFORMATION) +
+ part_count * sizeof(PARTITION_INFORMATION);
+ drive_layout = malloc(buf_size);
+ if (!drive_layout) {
+ errno = ENOMEM;
+ return FALSE;
+ }
+ if (DeviceIoControl(handle, IOCTL_DISK_GET_DRIVE_LAYOUT, NULL,
+ 0, (BYTE*)drive_layout, buf_size, &i, NULL))
+ break;
+ err = GetLastError();
+ free(drive_layout);
+ if (err != ERROR_INSUFFICIENT_BUFFER) {
+ ntfs_log_trace("GetDriveLayout failed.\n");
+ errno = ntfs_w32error_to_errno(err);
+ return FALSE;
+ }
+ ntfs_log_debug("More than %u partitions.\n", part_count);
+ part_count <<= 1;
+ if (part_count > 512) {
+ ntfs_log_trace("GetDriveLayout failed: More than 512 "
+ "partitions?\n");
+ errno = ENOBUFS;
+ return FALSE;
+ }
+ } while (1);
+ for (i = 0; i < drive_layout->PartitionCount; i++) {
+ if (drive_layout->PartitionEntry[i].PartitionNumber ==
+ partition_id) {
+ *part_offset = drive_layout->PartitionEntry[i].
+ StartingOffset.QuadPart;
+ *part_length = drive_layout->PartitionEntry[i].
+ PartitionLength.QuadPart;
+ *hidden_sectors = drive_layout->PartitionEntry[i].
+ HiddenSectors;
+ free(drive_layout);
+ return TRUE;
+ }
+ }
+ free(drive_layout);
+ errno = ENOENT;
+ return FALSE;
+}
+
+/**
+ * ntfs_device_win32_open_partition - open a partition via win32 API
+ * @drive_id: drive to open
+ * @partition_id: partition to open
+ * @fd: win32 file device to return
+ * @flags: unix open status flags
+ *
+ * Return 0 if o.k.
+ * -1 if not, and errno set.
+ *
+ * When fails, fd contents may have not been preserved.
+ */
+static int ntfs_device_win32_open_partition(int drive_id,
+ unsigned int partition_id, win32_fd *fd, int flags)
+{
+ s64 part_start, part_length;
+ HANDLE handle;
+ int err, hidden_sectors;
+ char drive_name[MAX_PATH];
+
+ sprintf(drive_name, "\\\\.\\PhysicalDrive%d", drive_id);
+ /* Open the entire device without locking, ask questions later */
+ if ((err = ntfs_device_win32_simple_open_file(drive_name, &handle,
+ flags, FALSE))) {
+ /* error */
+ return err;
+ }
+ if (ntfs_device_win32_find_partition(handle, partition_id, &part_start,
+ &part_length, &hidden_sectors)) {
+ s64 tmp;
+ HANDLE vol_handle = ntfs_device_win32_open_volume_for_partition(
+ drive_id, part_start, part_length, flags);
+ /* Store the drive geometry. */
+ ntfs_device_win32_getgeo(handle, fd);
+ fd->handle = handle;
+ fd->pos = 0;
+ fd->part_start = part_start;
+ fd->part_length = part_length;
+ fd->part_hidden_sectors = hidden_sectors;
+ tmp = ntfs_device_win32_getntfssize(vol_handle);
+ if (tmp > 0)
+ fd->geo_size = tmp;
+ else
+ fd->geo_size = fd->part_length;
+ if (vol_handle != INVALID_HANDLE_VALUE) {
+ if (((flags & O_RDWR) == O_RDWR) &&
+ ntfs_device_win32_lock(vol_handle)) {
+ CloseHandle(vol_handle);
+ CloseHandle(handle);
+ return -1;
+ }
+ fd->vol_handle = vol_handle;
+ } else {
+ if ((flags & O_RDWR) == O_RDWR) {
+ /* Access if read-write, no volume found. */
+ ntfs_log_trace("Partitions containing Spanned/"
+ "Mirrored volumes are not "
+ "supported in R/W status "
+ "yet.\n");
+ CloseHandle(handle);
+ errno = EOPNOTSUPP;
+ return -1;
+ }
+ fd->vol_handle = INVALID_HANDLE_VALUE;
+ }
+ return 0;
+ } else {
+ ntfs_log_debug("Partition %u not found on drive %d.\n",
+ partition_id, drive_id);
+ CloseHandle(handle);
+ errno = ENODEV;
+ return -1;
+ }
+}
+
+/**
+ * ntfs_device_win32_open - open a device
+ * @dev: a pointer to the NTFS_DEVICE to open
+ * @flags: unix open status flags
+ *
+ * @dev->d_name must hold the device name, the rest is ignored.
+ * Supported flags are O_RDONLY, O_WRONLY and O_RDWR.
+ *
+ * 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_id = 0, numparams;
+ unsigned int part = 0;
+ char drive_char;
+ win32_fd fd;
+ int err;
+
+ if (NDevOpen(dev)) {
+ 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:
+ ntfs_log_debug("win32_open(%s) -> file.\n", dev->d_name);
+ err = ntfs_device_win32_open_file(dev->d_name, &fd, flags);
+ break;
+ case 1:
+ ntfs_log_debug("win32_open(%s) -> drive %d.\n", dev->d_name,
+ drive_id);
+ err = ntfs_device_win32_open_drive(drive_id, &fd, flags);
+ break;
+ case 2:
+ ntfs_log_debug("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:
+ ntfs_log_debug("win32_open(%s) -> unknwon file format.\n",
+ dev->d_name);
+ err = -1;
+ }
+ if (err)
+ return err;
+ ntfs_log_debug("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;
+}
+
+/**
+ * ntfs_device_win32_seek - change current logical file position
+ * @dev: ntfs device obtained via ->open
+ * @offset: required offset from the whence anchor
+ * @whence: whence anchor specifying what @offset is relative to
+ *
+ * Return the new position on the volume on success and -1 on error with errno
+ * set to the error code.
+ *
+ * @whence may be one of the following:
+ * SEEK_SET - Offset is relative to file start.
+ * SEEK_CUR - Offset is relative to current position.
+ * SEEK_END - Offset is relative to end of file.
+ */
+static s64 ntfs_device_win32_seek(struct ntfs_device *dev, s64 offset,
+ int whence)
+{
+ s64 abs_ofs;
+ win32_fd *fd = (win32_fd *)dev->d_private;
+
+ ntfs_log_trace("seek offset = 0x%llx, whence = %d.\n", offset, whence);
+ switch (whence) {
+ case SEEK_SET:
+ abs_ofs = offset;
+ break;
+ case SEEK_CUR:
+ abs_ofs = fd->pos + offset;
+ break;
+ case SEEK_END:
+ /* End of partition != end of disk. */
+ if (fd->part_length == -1) {
+ ntfs_log_trace("Position relative to end of disk not "
+ "implemented.\n");
+ errno = EOPNOTSUPP;
+ return -1;
+ }
+ abs_ofs = fd->part_length + offset;
+ break;
+ default:
+ ntfs_log_trace("Wrong mode %d.\n", whence);
+ errno = EINVAL;
+ return -1;
+ }
+ if (abs_ofs < 0 || abs_ofs > fd->part_length) {
+ ntfs_log_trace("Seeking outsize seekable area.\n");
+ errno = EINVAL;
+ return -1;
+ }
+ fd->pos = abs_ofs;
+ return abs_ofs;
+}
+
+/**
+ * ntfs_device_win32_pio - positioned low level i/o
+ * @fd: win32 device descriptor obtained via ->open
+ * @pos: at which position to do i/o from/to
+ * @count: how many bytes should be transfered
+ * @b: source/destination buffer
+ * @write: TRUE if write transfer and FALSE if read transfer
+ *
+ * On success returns the number of bytes transfered (can be < @count) and on
+ * error returns -1 and errno set. Transfer starts from position @pos on @fd.
+ *
+ * Notes:
+ * - @pos, @buf, and @count must be aligned to NTFS_BLOCK_SIZE.
+ * - When dealing with volumes, a single call must not span both volume
+ * and disk extents.
+ * - Does not use/set @fd->pos.
+ */
+static s64 ntfs_device_win32_pio(win32_fd *fd, const s64 pos,
+ const s64 count, void *b, const BOOL write)
+{
+ LARGE_INTEGER li;
+ HANDLE handle;
+ DWORD bt;
+ BOOL res;
+
+ ntfs_log_trace("pos = 0x%llx, count = 0x%llx, direction = %s.\n",
+ (long long)pos, (long long)count, write ? "write" :
+ "read");
+ li.QuadPart = pos;
+ if (fd->vol_handle != INVALID_HANDLE_VALUE && pos < fd->geo_size) {
+ ntfs_log_debug("Transfering via vol_handle.\n");
+ handle = fd->vol_handle;
+ } else {
+ ntfs_log_debug("Transfering via handle.\n");
+ handle = fd->handle;
+ li.QuadPart += fd->part_start;
+ }
+ if (!fnSetFilePointerEx(handle, li, NULL, FILE_BEGIN)) {
+ errno = ntfs_w32error_to_errno(GetLastError());
+ ntfs_log_trace("SetFilePointer failed.\n");
+ return -1;
+ }
+ if (write)
+ res = WriteFile(handle, b, count, &bt, NULL);
+ else
+ res = ReadFile(handle, b, count, &bt, NULL);
+ if (!res) {
+ errno = ntfs_w32error_to_errno(GetLastError());
+ ntfs_log_trace("%sFile() failed.\n", write ? "Write" : "Read");
+ return -1;
+ }
+ return bt;
+}
+
+/**
+ * ntfs_device_win32_pread_simple - positioned simple read
+ * @fd: win32 device descriptor obtained via ->open
+ * @pos: at which position to read from
+ * @count: how many bytes should be read
+ * @b: a pointer to where to put the contents
+ *
+ * On success returns the number of bytes read (can be < @count) and on error
+ * returns -1 and errno set. Read starts from position @pos.
+ *
+ * Notes:
+ * - @pos, @buf, and @count must be aligned to NTFS_BLOCK_SIZE.
+ * - When dealing with volumes, a single call must not span both volume
+ * and disk extents.
+ * - Does not use/set @fd->pos.
+ */
+static inline s64 ntfs_device_win32_pread_simple(win32_fd *fd, const s64 pos,
+ const s64 count, void *b)
+{
+ return ntfs_device_win32_pio(fd, pos, count, b, FALSE);
+}
+
+/**
+ * ntfs_device_win32_read - read bytes from an ntfs device
+ * @dev: ntfs device obtained via ->open
+ * @b: pointer to where to put the contents
+ * @count: how many bytes should be read
+ *
+ * On success returns the number of bytes actually read (can be < @count).
+ * On error returns -1 with errno set.
+ */
+static s64 ntfs_device_win32_read(struct ntfs_device *dev, void *b, s64 count)
+{
+ s64 old_pos, to_read, i, br = 0;
+ win32_fd *fd = (win32_fd *)dev->d_private;
+ BYTE *alignedbuffer;
+ int old_ofs, ofs;
+
+ old_pos = fd->pos;
+ old_ofs = ofs = old_pos & (NTFS_BLOCK_SIZE - 1);
+ to_read = (ofs + count + NTFS_BLOCK_SIZE - 1) &
+ ~(s64)(NTFS_BLOCK_SIZE - 1);
+ /* Impose maximum of 2GB to be on the safe side. */
+ if (to_read > 0x80000000) {
+ int delta = to_read - count;
+ to_read = 0x80000000;
+ count = to_read - delta;
+ }
+ ntfs_log_trace("fd = %p, b = %p, count = 0x%llx, pos = 0x%llx, "
+ "ofs = %i, to_read = 0x%llx.\n", fd, b,
+ (long long)count, (long long)old_pos, ofs,
+ (long long)to_read);
+ if (!((unsigned long)b & (NTFS_BLOCK_SIZE - 1)) && !old_ofs &&
+ !(count & (NTFS_BLOCK_SIZE - 1)))
+ alignedbuffer = b;
+ else {
+ alignedbuffer = (BYTE *)VirtualAlloc(NULL, to_read, MEM_COMMIT,
+ PAGE_READWRITE);
+ if (!alignedbuffer) {
+ errno = ntfs_w32error_to_errno(GetLastError());
+ ntfs_log_trace("VirtualAlloc failed for read.\n");
+ return -1;
+ }
+ }
+ if (fd->vol_handle != INVALID_HANDLE_VALUE && old_pos < fd->geo_size) {
+ s64 vol_to_read = fd->geo_size - old_pos;
+ if (count > vol_to_read) {
+ br = ntfs_device_win32_pread_simple(fd,
+ old_pos & ~(s64)(NTFS_BLOCK_SIZE - 1),
+ ofs + vol_to_read, alignedbuffer);
+ if (br == -1)
+ goto read_error;
+ to_read -= br;
+ if (br < ofs) {
+ br = 0;
+ goto read_partial;
+ }
+ br -= ofs;
+ fd->pos += br;
+ ofs = fd->pos & (NTFS_BLOCK_SIZE - 1);
+ if (br != vol_to_read)
+ goto read_partial;
+ }
+ }
+ i = ntfs_device_win32_pread_simple(fd,
+ fd->pos & ~(s64)(NTFS_BLOCK_SIZE - 1), to_read,
+ alignedbuffer + br);
+ if (i == -1) {
+ if (br)
+ goto read_partial;
+ goto read_error;
+ }
+ if (i < ofs)
+ goto read_partial;
+ i -= ofs;
+ br += i;
+ if (br > count)
+ br = count;
+ fd->pos = old_pos + br;
+read_partial:
+ if (alignedbuffer != b) {
+ memcpy((void*)b, alignedbuffer + old_ofs, br);
+ VirtualFree(alignedbuffer, 0, MEM_RELEASE);
+ }
+ return br;
+read_error:
+ if (alignedbuffer != b)
+ VirtualFree(alignedbuffer, 0, MEM_RELEASE);
+ return -1;
+}
+
+/**
+ * ntfs_device_win32_close - close an open ntfs deivce
+ * @dev: ntfs device obtained via ->open
+ *
+ * Return 0 if o.k.
+ * -1 if not, and errno set. Note if error fd->vol_handle is trashed.
+ */
+static int ntfs_device_win32_close(struct ntfs_device *dev)
+{
+ win32_fd *fd = (win32_fd *)dev->d_private;
+ BOOL rvl;
+
+ ntfs_log_trace("Closing device %p.\n", dev);
+ if (!NDevOpen(dev)) {
+ errno = EBADF;
+ return -1;
+ }
+ if (fd->vol_handle != INVALID_HANDLE_VALUE) {
+ if (!NDevReadOnly(dev)) {
+ ntfs_device_win32_dismount(fd->vol_handle);
+ ntfs_device_win32_unlock(fd->vol_handle);
+ }
+ if (!CloseHandle(fd->vol_handle))
+ ntfs_log_trace("CloseHandle() failed for volume.\n");
+ }
+ rvl = CloseHandle(fd->handle);
+ free(fd);
+ if (!rvl) {
+ errno = ntfs_w32error_to_errno(GetLastError());
+ ntfs_log_trace("CloseHandle() failed.\n");
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * ntfs_device_win32_sync - flush write buffers to disk
+ * @dev: ntfs device obtained via ->open
+ *
+ * Return 0 if o.k.
+ * -1 if not, and errno set.
+ *
+ * Note: Volume syncing works differently in windows.
+ * Disk cannot be synced in windows.
+ */
+static int ntfs_device_win32_sync(struct ntfs_device *dev)
+{
+ int err = 0;
+ BOOL to_clear = TRUE;
+
+ if (!NDevReadOnly(dev) && NDevDirty(dev)) {
+ win32_fd *fd = (win32_fd *)dev->d_private;
+
+ if ((fd->vol_handle != INVALID_HANDLE_VALUE) &&
+ !FlushFileBuffers(fd->vol_handle)) {
+ to_clear = FALSE;
+ err = ntfs_w32error_to_errno(GetLastError());
+ }
+ if (!FlushFileBuffers(fd->handle)) {
+ to_clear = FALSE;
+ if (!err)
+ err = ntfs_w32error_to_errno(GetLastError());
+ }
+ if (!to_clear) {
+ ntfs_log_trace("Could not sync.\n");
+ errno = err;
+ return -1;
+ }
+ NDevClearDirty(dev);
+ }
+ return 0;
+}
+
+/**
+ * ntfs_device_win32_pwrite_simple - positioned simple write
+ * @fd: win32 device descriptor obtained via ->open
+ * @pos: at which position to write to
+ * @count: how many bytes should be written
+ * @b: a pointer to the data to write
+ *
+ * On success returns the number of bytes written and on error returns -1 and
+ * errno set. Write starts from position @pos.
+ *
+ * Notes:
+ * - @pos, @buf, and @count must be aligned to NTFS_BLOCK_SIZE.
+ * - When dealing with volumes, a single call must not span both volume
+ * and disk extents.
+ * - Does not use/set @fd->pos.
+ */
+static inline s64 ntfs_device_win32_pwrite_simple(win32_fd *fd, const s64 pos,
+ const s64 count, const void *b)
+{
+ return ntfs_device_win32_pio(fd, pos, count, (void *)b, TRUE);
+}
+
+/**
+ * ntfs_device_win32_write - write bytes to an ntfs device
+ * @dev: ntfs device obtained via ->open
+ * @b: pointer to the data to write
+ * @count: how many bytes should be written
+ *
+ * On success returns the number of bytes actually written.
+ * On error returns -1 with errno set.
+ */
+static s64 ntfs_device_win32_write(struct ntfs_device *dev, const void *b,
+ s64 count)
+{
+ s64 old_pos, to_write, i, bw = 0;
+ win32_fd *fd = (win32_fd *)dev->d_private;
+ BYTE *alignedbuffer;
+ int old_ofs, ofs;
+
+ old_pos = fd->pos;
+ old_ofs = ofs = old_pos & (NTFS_BLOCK_SIZE - 1);
+ to_write = (ofs + count + NTFS_BLOCK_SIZE - 1) &
+ ~(s64)(NTFS_BLOCK_SIZE - 1);
+ /* Impose maximum of 2GB to be on the safe side. */
+ if (to_write > 0x80000000) {
+ int delta = to_write - count;
+ to_write = 0x80000000;
+ count = to_write - delta;
+ }
+ ntfs_log_trace("fd = %p, b = %p, count = 0x%llx, pos = 0x%llx, "
+ "ofs = %i, to_write = 0x%llx.\n", fd, b,
+ (long long)count, (long long)old_pos, ofs,
+ (long long)to_write);
+ if (NDevReadOnly(dev)) {
+ ntfs_log_trace("Can't write on a R/O device.\n");
+ errno = EROFS;
+ return -1;
+ }
+ if (!count)
+ return 0;
+ NDevSetDirty(dev);
+ if (!((unsigned long)b & (NTFS_BLOCK_SIZE - 1)) && !old_ofs &&
+ !(count & (NTFS_BLOCK_SIZE - 1)))
+ alignedbuffer = (BYTE *)b;
+ else {
+ s64 end;
+
+ alignedbuffer = (BYTE *)VirtualAlloc(NULL, to_write,
+ MEM_COMMIT, PAGE_READWRITE);
+ if (!alignedbuffer) {
+ errno = ntfs_w32error_to_errno(GetLastError());
+ ntfs_log_trace("VirtualAlloc failed for write.\n");
+ return -1;
+ }
+ /* Read first sector if start of write not sector aligned. */
+ if (ofs) {
+ i = ntfs_device_win32_pread_simple(fd,
+ old_pos & ~(s64)(NTFS_BLOCK_SIZE - 1),
+ NTFS_BLOCK_SIZE, alignedbuffer);
+ if (i != NTFS_BLOCK_SIZE) {
+ if (i >= 0)
+ errno = EIO;
+ goto write_error;
+ }
+ }
+ /*
+ * Read last sector if end of write not sector aligned and last
+ * sector is either not the same as the first sector or it is
+ * the same as the first sector but this has not been read in
+ * yet, i.e. the start of the write is sector aligned.
+ */
+ end = old_pos + count;
+ if ((end & (NTFS_BLOCK_SIZE - 1)) &&
+ ((to_write > NTFS_BLOCK_SIZE) || !ofs)) {
+ i = ntfs_device_win32_pread_simple(fd,
+ end & ~(s64)(NTFS_BLOCK_SIZE - 1),
+ NTFS_BLOCK_SIZE, alignedbuffer +
+ to_write - NTFS_BLOCK_SIZE);
+ if (i != NTFS_BLOCK_SIZE) {
+ if (i >= 0)
+ errno = EIO;
+ goto write_error;
+ }
+ }
+ /* Copy the data to be written into @alignedbuffer. */
+ memcpy(alignedbuffer + ofs, b, count);
+ }
+ if (fd->vol_handle != INVALID_HANDLE_VALUE && old_pos < fd->geo_size) {
+ s64 vol_to_write = fd->geo_size - old_pos;
+ if (count > vol_to_write) {
+ bw = ntfs_device_win32_pwrite_simple(fd,
+ old_pos & ~(s64)(NTFS_BLOCK_SIZE - 1),
+ ofs + vol_to_write, alignedbuffer);
+ if (bw == -1)
+ goto write_error;
+ to_write -= bw;
+ if (bw < ofs) {
+ bw = 0;
+ goto write_partial;
+ }
+ bw -= ofs;
+ fd->pos += bw;
+ ofs = fd->pos & (NTFS_BLOCK_SIZE - 1);
+ if (bw != vol_to_write)
+ goto write_partial;
+ }
+ }
+ i = ntfs_device_win32_pwrite_simple(fd,
+ fd->pos & ~(s64)(NTFS_BLOCK_SIZE - 1), to_write,
+ alignedbuffer + bw);
+ if (i == -1) {
+ if (bw)
+ goto write_partial;
+ goto write_error;
+ }
+ if (i < ofs)
+ goto write_partial;
+ i -= ofs;
+ bw += i;
+ if (bw > count)
+ bw = count;
+ fd->pos = old_pos + bw;
+write_partial:
+ if (alignedbuffer != b)
+ VirtualFree(alignedbuffer, 0, MEM_RELEASE);
+ return bw;
+write_error:
+ bw = -1;
+ goto write_partial;
+}
+
+/**
+ * ntfs_device_win32_stat - get a unix-like stat structure for an ntfs device
+ * @dev: ntfs device obtained via ->open
+ * @buf: pointer to the stat structure to fill
+ *
+ * Note: Only st_mode, st_size, and st_blocks are filled.
+ *
+ * Return 0 if o.k.
+ * -1 if not and errno set. in this case handle is trashed.
+ */
+static int ntfs_device_win32_stat(struct ntfs_device *dev, struct stat *buf)
+{
+ win32_fd *fd = (win32_fd *)dev->d_private;
+ mode_t st_mode;
+
+ switch (GetFileType(fd->handle)) {
+ case FILE_TYPE_CHAR:
+ st_mode = S_IFCHR;
+ break;
+ case FILE_TYPE_DISK:
+ st_mode = S_IFBLK;
+ break;
+ case FILE_TYPE_PIPE:
+ st_mode = S_IFIFO;
+ break;
+ default:
+ st_mode = 0;
+ }
+ memset(buf, 0, sizeof(struct stat));
+ buf->st_mode = st_mode;
+ buf->st_size = fd->part_length;
+ if (buf->st_size != -1)
+ buf->st_blocks = buf->st_size >> 9;
+ else
+ buf->st_size = 0;
+ return 0;
+}
+
+/**
+ * ntfs_win32_hdio_getgeo - get drive geometry
+ * @dev: ntfs device obtained via ->open
+ * @argp: pointer to where to put the output
+ *
+ * Note: Works on windows NT/2k/XP only.
+ *
+ * Return 0 if o.k.
+ * -1 if not, and errno set. Note if error fd->handle is trashed.
+ */
+static __inline__ int ntfs_win32_hdio_getgeo(struct ntfs_device *dev,
+ struct hd_geometry *argp)
+{
+ win32_fd *fd = (win32_fd *)dev->d_private;
+
+ argp->heads = fd->geo_heads;
+ argp->sectors = fd->geo_sectors;
+ argp->cylinders = fd->geo_cylinders;
+ argp->start = fd->part_hidden_sectors;
+ return 0;
+}
+
+/**
+ * ntfs_win32_blksszget - get block device sector size
+ * @dev: ntfs device obtained via ->open
+ * @argp: pointer to where to put the output
+ *
+ * Note: Works on windows NT/2k/XP only.
+ *
+ * Return 0 if o.k.
+ * -1 if not, and errno set. Note if error fd->handle is trashed.
+ */
+static __inline__ int ntfs_win32_blksszget(struct ntfs_device *dev,int *argp)
+{
+ win32_fd *fd = (win32_fd *)dev->d_private;
+ DWORD bytesReturned;
+ DISK_GEOMETRY dg;
+
+ if (DeviceIoControl(fd->handle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0,
+ &dg, sizeof(DISK_GEOMETRY), &bytesReturned, NULL)) {
+ /* success */
+ *argp = dg.BytesPerSector;
+ return 0;
+ }
+ errno = ntfs_w32error_to_errno(GetLastError());
+ ntfs_log_trace("GET_DRIVE_GEOMETRY failed.\n");
+ return -1;
+}
+
+static int ntfs_device_win32_ioctl(struct ntfs_device *dev, int request,
+ void *argp)
+{
+ win32_fd *fd = (win32_fd *)dev->d_private;
+
+ ntfs_log_trace("win32_ioctl(%d) called.\n", request);
+ switch (request) {
+#if defined(BLKGETSIZE)
+ case BLKGETSIZE:
+ ntfs_log_debug("BLKGETSIZE detected.\n");
+ if (fd->part_length >= 0) {
+ *(int *)argp = (int)(fd->part_length / 512);
+ return 0;
+ }
+ errno = EOPNOTSUPP;
+ return -1;
+#endif
+#if defined(BLKGETSIZE64)
+ case BLKGETSIZE64:
+ ntfs_log_debug("BLKGETSIZE64 detected.\n");
+ if (fd->part_length >= 0) {
+ *(s64 *)argp = fd->part_length;
+ return 0;
+ }
+ errno = EOPNOTSUPP;
+ return -1;
+#endif
+#ifdef HDIO_GETGEO
+ case HDIO_GETGEO:
+ ntfs_log_debug("HDIO_GETGEO detected.\n");
+ return ntfs_win32_hdio_getgeo(dev, (struct hd_geometry *)argp);
+#endif
+#ifdef BLKSSZGET
+ case BLKSSZGET:
+ ntfs_log_debug("BLKSSZGET detected.\n");
+ return ntfs_win32_blksszget(dev, (int *)argp);
+#endif
+#ifdef BLKBSZSET
+ case BLKBSZSET:
+ ntfs_log_debug("BLKBSZSET detected.\n");
+ /* Nothing to do on Windows. */
+ return 0;
+#endif
+ default:
+ ntfs_log_debug("unimplemented ioctl %d.\n", request);
+ errno = EOPNOTSUPP;
+ return -1;
+ }
+}
+
+static s64 ntfs_device_win32_pread(struct ntfs_device *dev, void *b,
+ s64 count, s64 offset)
+{
+ return ntfs_pread(dev, offset, count, b);
+}
+
+static s64 ntfs_device_win32_pwrite(struct ntfs_device *dev, const void *b,
+ s64 count, s64 offset)
+{
+ return ntfs_pwrite(dev, offset, count, b);
+}
+
+struct ntfs_device_operations ntfs_device_win32_io_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
+};