parent
d73865047c
commit
edd4221a68
@ -1,217 +0,0 @@
|
|||||||
From c26a519da1ed182e7cfd67e7a353932dda53d811 Mon Sep 17 00:00:00 2001
|
|
||||||
From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= <jpandre@users.sourceforge.net>
|
|
||||||
Date: Mon, 4 Aug 2014 17:39:50 +0200
|
|
||||||
Subject: [PATCH] Fixed fstrim(8) applied to partitions
|
|
||||||
|
|
||||||
The new way goes via /sys/dev/block/MAJOR:MINOR to map partitions to
|
|
||||||
devices and get discard parameters of the parent device. It also ensures
|
|
||||||
that the partition is aligned to the discard block size.
|
|
||||||
|
|
||||||
Contributed by Richard W.M. Jones
|
|
||||||
---
|
|
||||||
libntfs-3g/ioctl.c | 140 ++++++++++++++++++++++++++---------------------------
|
|
||||||
1 file changed, 68 insertions(+), 72 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/libntfs-3g/ioctl.c b/libntfs-3g/ioctl.c
|
|
||||||
index bbbceb9..eb7c8e7 100644
|
|
||||||
--- a/libntfs-3g/ioctl.c
|
|
||||||
+++ b/libntfs-3g/ioctl.c
|
|
||||||
@@ -66,8 +66,6 @@
|
|
||||||
#include <linux/fs.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
-#include <dirent.h>
|
|
||||||
-
|
|
||||||
#include "compat.h"
|
|
||||||
#include "debug.h"
|
|
||||||
#include "bitmap.h"
|
|
||||||
@@ -135,17 +133,14 @@ static int read_u64(const char *path, u64 *n)
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find discard limits for current backing device.
|
|
||||||
- * XXX Kernel makes this a pain in the neck.
|
|
||||||
*/
|
|
||||||
-static int fstrim_limits(ntfs_volume *vol, u64 *discard_granularity,
|
|
||||||
+static int fstrim_limits(ntfs_volume *vol,
|
|
||||||
+ u64 *discard_alignment,
|
|
||||||
+ u64 *discard_granularity,
|
|
||||||
u64 *discard_max_bytes)
|
|
||||||
{
|
|
||||||
struct stat statbuf;
|
|
||||||
- DIR *dir;
|
|
||||||
- struct dirent *d;
|
|
||||||
- char path[80];
|
|
||||||
- char line[64];
|
|
||||||
- char dev[64];
|
|
||||||
+ char path1[80], path2[80];
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* Stat the backing device. Caller has ensured it is a block device. */
|
|
||||||
@@ -155,82 +150,78 @@ static int fstrim_limits(ntfs_volume *vol, u64 *discard_granularity,
|
|
||||||
return -errno;
|
|
||||||
}
|
|
||||||
|
|
||||||
- /* Now look for a /sys/block/<dev>/dev file which contains
|
|
||||||
- * "major:minor\n".
|
|
||||||
+ /* For whole devices,
|
|
||||||
+ * /sys/dev/block/MAJOR:MINOR/discard_alignment
|
|
||||||
+ * /sys/dev/block/MAJOR:MINOR/queue/discard_granularity
|
|
||||||
+ * /sys/dev/block/MAJOR:MINOR/queue/discard_max_bytes
|
|
||||||
+ * will exist.
|
|
||||||
+ * For partitions, we also need to check the parent device:
|
|
||||||
+ * /sys/dev/block/MAJOR:MINOR/../queue/discard_granularity
|
|
||||||
+ * /sys/dev/block/MAJOR:MINOR/../queue/discard_max_bytes
|
|
||||||
*/
|
|
||||||
- snprintf(dev, sizeof dev, "%d:%d\n",
|
|
||||||
+ snprintf(path1, sizeof path1, "/sys/dev/block/%d:%d",
|
|
||||||
major(statbuf.st_rdev), minor(statbuf.st_rdev));
|
|
||||||
|
|
||||||
- dir = opendir("/sys/block");
|
|
||||||
- if (dir == NULL) {
|
|
||||||
- ntfs_log_debug("fstrim_limits: could not open /sys/block\n");
|
|
||||||
- return -errno;
|
|
||||||
+ snprintf(path2, sizeof path2, "%s/discard_alignment", path1);
|
|
||||||
+ ret = read_u64(path2, discard_alignment);
|
|
||||||
+ if (ret) {
|
|
||||||
+ if (ret != -ENOENT)
|
|
||||||
+ return ret;
|
|
||||||
+ else
|
|
||||||
+ /* We would expect this file to exist on all
|
|
||||||
+ * modern kernels. But for the sake of very
|
|
||||||
+ * old kernels:
|
|
||||||
+ */
|
|
||||||
+ goto not_found;
|
|
||||||
}
|
|
||||||
- for (;;) {
|
|
||||||
- errno = 0;
|
|
||||||
- d = readdir(dir);
|
|
||||||
- if (!d) break;
|
|
||||||
|
|
||||||
- snprintf(path, sizeof path, "/sys/block/%s/dev", d->d_name);
|
|
||||||
- ret = read_line(path, line, sizeof line);
|
|
||||||
- if (ret)
|
|
||||||
- continue;
|
|
||||||
- if (strcmp(line, dev) == 0)
|
|
||||||
- goto found;
|
|
||||||
+ snprintf(path2, sizeof path2, "%s/queue/discard_granularity", path1);
|
|
||||||
+ ret = read_u64(path2, discard_granularity);
|
|
||||||
+ if (ret) {
|
|
||||||
+ if (ret != -ENOENT)
|
|
||||||
+ return ret;
|
|
||||||
+ else {
|
|
||||||
+ snprintf(path2, sizeof path2,
|
|
||||||
+ "%s/../queue/discard_granularity", path1);
|
|
||||||
+ ret = read_u64(path2, discard_granularity);
|
|
||||||
+ if (ret) {
|
|
||||||
+ if (ret != -ENOENT)
|
|
||||||
+ return ret;
|
|
||||||
+ else
|
|
||||||
+ goto not_found;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
|
|
||||||
- /* Check readdir didn't fail. */
|
|
||||||
- if (errno != 0) {
|
|
||||||
- ret = -errno;
|
|
||||||
- ntfs_log_debug("fstrim_limits: readdir failed\n");
|
|
||||||
- goto out;
|
|
||||||
+ snprintf(path2, sizeof path2, "%s/queue/discard_max_bytes", path1);
|
|
||||||
+ ret = read_u64(path2, discard_max_bytes);
|
|
||||||
+ if (ret) {
|
|
||||||
+ if (ret != -ENOENT)
|
|
||||||
+ return ret;
|
|
||||||
+ else {
|
|
||||||
+ snprintf(path2, sizeof path2,
|
|
||||||
+ "%s/../queue/discard_max_bytes", path1);
|
|
||||||
+ ret = read_u64(path2, discard_max_bytes);
|
|
||||||
+ if (ret) {
|
|
||||||
+ if (ret != -ENOENT)
|
|
||||||
+ return ret;
|
|
||||||
+ else
|
|
||||||
+ goto not_found;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
|
|
||||||
+ return 0;
|
|
||||||
+
|
|
||||||
+not_found:
|
|
||||||
/* If we reach here then we didn't find the device. This is
|
|
||||||
* not an error, but set discard_max_bytes = 0 to indicate
|
|
||||||
* that discard is not available.
|
|
||||||
*/
|
|
||||||
+ *discard_alignment = 0;
|
|
||||||
*discard_granularity = 0;
|
|
||||||
*discard_max_bytes = 0;
|
|
||||||
- ntfs_log_debug("fstrim_limits: /sys/block entry corresponding to device %s not found\n",
|
|
||||||
- vol->dev->d_name);
|
|
||||||
- ret = 0;
|
|
||||||
- goto out;
|
|
||||||
-
|
|
||||||
-found:
|
|
||||||
- /* Found the device at /sys/block/ + d->d_name */
|
|
||||||
- snprintf (path, sizeof path,
|
|
||||||
- "/sys/block/%s/queue/discard_granularity",
|
|
||||||
- d->d_name);
|
|
||||||
- ret = read_u64(path, discard_granularity);
|
|
||||||
- if (ret) {
|
|
||||||
- ntfs_log_debug("fstrim_limits: could not read %s\n", path);
|
|
||||||
- goto out;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- snprintf (path, sizeof path,
|
|
||||||
- "/sys/block/%s/queue/discard_max_bytes",
|
|
||||||
- d->d_name);
|
|
||||||
- ret = read_u64(path, discard_max_bytes);
|
|
||||||
- if (ret) {
|
|
||||||
- ntfs_log_debug("fstrim_limits: could not read %s\n", path);
|
|
||||||
- goto out;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- ntfs_log_debug("fstrim_limits: device %s discard granularity = %llu max_bytes = %llu\n",
|
|
||||||
- d->d_name,
|
|
||||||
- (unsigned long long) *discard_granularity,
|
|
||||||
- (unsigned long long) *discard_max_bytes);
|
|
||||||
-
|
|
||||||
- ret = 0;
|
|
||||||
-out:
|
|
||||||
- if (closedir (dir) == -1) {
|
|
||||||
- ret = -errno;
|
|
||||||
- ntfs_log_debug("fstrim_limits: closedir failed\n");
|
|
||||||
- return ret;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- return ret;
|
|
||||||
+ return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define FSTRIM_BUFSIZ 4096
|
|
||||||
@@ -247,7 +238,7 @@ static int fstrim(ntfs_volume *vol, void *data)
|
|
||||||
u64 start = range->start;
|
|
||||||
u64 len = range->len;
|
|
||||||
u64 minlen = range->minlen;
|
|
||||||
- u64 discard_granularity, discard_max_bytes;
|
|
||||||
+ u64 discard_alignment, discard_granularity, discard_max_bytes;
|
|
||||||
u8 *buf = NULL;
|
|
||||||
LCN start_buf;
|
|
||||||
int ret;
|
|
||||||
@@ -279,9 +270,14 @@ static int fstrim(ntfs_volume *vol, void *data)
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
}
|
|
||||||
|
|
||||||
- ret = fstrim_limits(vol, &discard_granularity, &discard_max_bytes);
|
|
||||||
+ ret = fstrim_limits(vol, &discard_alignment,
|
|
||||||
+ &discard_granularity, &discard_max_bytes);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
+ if (discard_alignment != 0) {
|
|
||||||
+ ntfs_log_debug("fstrim: backing device is not aligned for discards\n");
|
|
||||||
+ return -EOPNOTSUPP;
|
|
||||||
+ }
|
|
||||||
if (discard_granularity > vol->cluster_size) {
|
|
||||||
ntfs_log_debug("fstrim: discard granularity of backing device is larger than cluster size\n");
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
--
|
|
||||||
1.9.3
|
|
||||||
|
|
@ -1,610 +0,0 @@
|
|||||||
diff -ur ntfs-3g_ntfsprogs-2014.2.15/include/fuse-lite/fuse_common.h ntfs-3g_ntfsprogs-2014.2.15.new/include/fuse-lite/fuse_common.h
|
|
||||||
--- ntfs-3g_ntfsprogs-2014.2.15/include/fuse-lite/fuse_common.h 2014-02-15 14:07:52.000000000 +0000
|
|
||||||
+++ ntfs-3g_ntfsprogs-2014.2.15.new/include/fuse-lite/fuse_common.h 2014-07-31 13:47:17.401904166 +0100
|
|
||||||
@@ -49,6 +49,22 @@
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define FUSE_CAP_BIG_WRITES (1 << 5)
|
|
||||||
+#define FUSE_CAP_IOCTL_DIR (1 << 11)
|
|
||||||
+
|
|
||||||
+/**
|
|
||||||
+ * Ioctl flags
|
|
||||||
+ *
|
|
||||||
+ * FUSE_IOCTL_COMPAT: 32bit compat ioctl on 64bit machine
|
|
||||||
+ * FUSE_IOCTL_UNRESTRICTED: not restricted to well-formed ioctls, retry allowed
|
|
||||||
+ * FUSE_IOCTL_RETRY: retry with new iovecs
|
|
||||||
+ * FUSE_IOCTL_DIR: is a directory
|
|
||||||
+ */
|
|
||||||
+#define FUSE_IOCTL_COMPAT (1 << 0)
|
|
||||||
+#define FUSE_IOCTL_UNRESTRICTED (1 << 1)
|
|
||||||
+#define FUSE_IOCTL_RETRY (1 << 2)
|
|
||||||
+#define FUSE_IOCTL_DIR (1 << 4)
|
|
||||||
+
|
|
||||||
+#define FUSE_IOCTL_MAX_IOV 256
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Information about open files
|
|
||||||
diff -ur ntfs-3g_ntfsprogs-2014.2.15/include/fuse-lite/fuse.h ntfs-3g_ntfsprogs-2014.2.15.new/include/fuse-lite/fuse.h
|
|
||||||
--- ntfs-3g_ntfsprogs-2014.2.15/include/fuse-lite/fuse.h 2014-02-15 14:07:52.000000000 +0000
|
|
||||||
+++ ntfs-3g_ntfsprogs-2014.2.15.new/include/fuse-lite/fuse.h 2014-07-31 13:47:17.401904166 +0100
|
|
||||||
@@ -420,9 +420,27 @@
|
|
||||||
* Introduced in version 2.6
|
|
||||||
*/
|
|
||||||
int (*bmap) (const char *, size_t blocksize, uint64_t *idx);
|
|
||||||
- unsigned int flag_nullpath_ok : 1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
+ * Ioctl
|
|
||||||
+ *
|
|
||||||
+ * flags will have FUSE_IOCTL_COMPAT set for 32bit ioctls in
|
|
||||||
+ * 64bit environment. The size and direction of data is
|
|
||||||
+ * determined by _IOC_*() decoding of cmd. For _IOC_NONE,
|
|
||||||
+ * data will be NULL, for _IOC_WRITE data is out area, for
|
|
||||||
+ * _IOC_READ in area and if both are set in/out area. In all
|
|
||||||
+ * non-NULL cases, the area is of _IOC_SIZE(cmd) bytes.
|
|
||||||
+ *
|
|
||||||
+ * Introduced in version 2.8
|
|
||||||
+ */
|
|
||||||
+ int (*ioctl) (const char *, int cmd, void *arg,
|
|
||||||
+ struct fuse_file_info *, unsigned int flags, void *data);
|
|
||||||
+
|
|
||||||
+ /*
|
|
||||||
+ * The flags below have been discarded, they should not be used
|
|
||||||
+ */
|
|
||||||
+ unsigned int flag_nullpath_ok : 1;
|
|
||||||
+ /**
|
|
||||||
* Reserved flags, don't set
|
|
||||||
*/
|
|
||||||
unsigned int flag_reserved : 30;
|
|
||||||
@@ -450,10 +468,8 @@
|
|
||||||
/** Private filesystem data */
|
|
||||||
void *private_data;
|
|
||||||
|
|
||||||
-#ifdef POSIXACLS
|
|
||||||
/** Umask of the calling process (introduced in version 2.8) */
|
|
||||||
mode_t umask;
|
|
||||||
-#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------- *
|
|
||||||
@@ -601,6 +617,8 @@
|
|
||||||
const char *name);
|
|
||||||
int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize,
|
|
||||||
uint64_t *idx);
|
|
||||||
+int fuse_fs_ioctl(struct fuse_fs *fs, const char *path, int cmd, void *arg,
|
|
||||||
+ struct fuse_file_info *fi, unsigned int flags, void *data);
|
|
||||||
void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn);
|
|
||||||
void fuse_fs_destroy(struct fuse_fs *fs);
|
|
||||||
|
|
||||||
diff -ur ntfs-3g_ntfsprogs-2014.2.15/include/fuse-lite/fuse_kernel.h ntfs-3g_ntfsprogs-2014.2.15.new/include/fuse-lite/fuse_kernel.h
|
|
||||||
--- ntfs-3g_ntfsprogs-2014.2.15/include/fuse-lite/fuse_kernel.h 2014-02-15 14:07:52.000000000 +0000
|
|
||||||
+++ ntfs-3g_ntfsprogs-2014.2.15.new/include/fuse-lite/fuse_kernel.h 2014-07-31 13:47:17.401904166 +0100
|
|
||||||
@@ -48,13 +48,19 @@
|
|
||||||
/** Version number of this interface */
|
|
||||||
#define FUSE_KERNEL_VERSION 7
|
|
||||||
|
|
||||||
-/** Minor version number of this interface */
|
|
||||||
-#ifdef POSIXACLS
|
|
||||||
-#define FUSE_KERNEL_MINOR_VERSION 12
|
|
||||||
+/** Minor version number of this interface
|
|
||||||
+ * We introduce ourself as 7.18 (Posix ACLS : 7.12, IOCTL_DIR : 7.18)
|
|
||||||
+ * and we expect features features defined for 7.18, but not implemented
|
|
||||||
+ * here to not be triggered by ntfs-3g.
|
|
||||||
+ */
|
|
||||||
+#define FUSE_KERNEL_MINOR_VERSION 18
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * For binary compatibility with old kernels we accept falling back to 7.8
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#define FUSE_KERNEL_MAJOR_FALLBACK 7
|
|
||||||
#define FUSE_KERNEL_MINOR_FALLBACK 8
|
|
||||||
-#else
|
|
||||||
-#define FUSE_KERNEL_MINOR_VERSION 8
|
|
||||||
-#endif
|
|
||||||
|
|
||||||
/** The node ID of the root inode */
|
|
||||||
#define FUSE_ROOT_ID 1
|
|
||||||
@@ -83,9 +89,7 @@
|
|
||||||
__u32 uid;
|
|
||||||
__u32 gid;
|
|
||||||
__u32 rdev;
|
|
||||||
-#ifdef POSIXACLS
|
|
||||||
__u64 filling; /* JPA needed for minor >= 12, but meaning unknown */
|
|
||||||
-#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fuse_kstatfs {
|
|
||||||
@@ -132,11 +136,13 @@
|
|
||||||
* INIT request/reply flags
|
|
||||||
* FUSE_BIG_WRITES: allow big writes to be issued to the file system
|
|
||||||
* FUSE_DONT_MASK: don't apply umask to file mode on create operations
|
|
||||||
+ * FUSE_HAS_IOCTL_DIR: kernel supports ioctl on directories
|
|
||||||
*/
|
|
||||||
#define FUSE_ASYNC_READ (1 << 0)
|
|
||||||
#define FUSE_POSIX_LOCKS (1 << 1)
|
|
||||||
#define FUSE_BIG_WRITES (1 << 5)
|
|
||||||
#define FUSE_DONT_MASK (1 << 6)
|
|
||||||
+#define FUSE_HAS_IOCTL_DIR (1 << 11)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Release flags
|
|
||||||
@@ -180,6 +186,7 @@
|
|
||||||
FUSE_INTERRUPT = 36,
|
|
||||||
FUSE_BMAP = 37,
|
|
||||||
FUSE_DESTROY = 38,
|
|
||||||
+ FUSE_IOCTL = 39,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* The read buffer is required to be at least 8k, but may be much larger */
|
|
||||||
@@ -215,10 +222,8 @@
|
|
||||||
struct fuse_mknod_in {
|
|
||||||
__u32 mode;
|
|
||||||
__u32 rdev;
|
|
||||||
-#ifdef POSIXACLS
|
|
||||||
__u32 umask;
|
|
||||||
__u32 padding;
|
|
||||||
-#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fuse_mkdir_in {
|
|
||||||
@@ -255,20 +260,14 @@
|
|
||||||
|
|
||||||
struct fuse_open_in {
|
|
||||||
__u32 flags;
|
|
||||||
-#ifdef POSIXACLS
|
|
||||||
- __u32 unused;
|
|
||||||
-#else
|
|
||||||
- __u32 mode;
|
|
||||||
-#endif
|
|
||||||
+ __u32 mode; /* unused for protocol < 7.12 */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fuse_create_in {
|
|
||||||
__u32 flags;
|
|
||||||
__u32 mode;
|
|
||||||
-#ifdef POSIXACLS
|
|
||||||
__u32 umask;
|
|
||||||
__u32 padding;
|
|
||||||
-#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fuse_open_out {
|
|
||||||
@@ -305,11 +304,9 @@
|
|
||||||
__u64 offset;
|
|
||||||
__u32 size;
|
|
||||||
__u32 write_flags;
|
|
||||||
-#ifdef POSIXACLS
|
|
||||||
__u64 lock_owner; /* JPA */
|
|
||||||
__u32 flags; /* JPA */
|
|
||||||
__u32 padding; /* JPA */
|
|
||||||
-#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fuse_write_out {
|
|
||||||
@@ -389,6 +386,27 @@
|
|
||||||
__u64 block;
|
|
||||||
};
|
|
||||||
|
|
||||||
+struct fuse_ioctl_in {
|
|
||||||
+ __u64 fh;
|
|
||||||
+ __u32 flags;
|
|
||||||
+ __u32 cmd;
|
|
||||||
+ __u64 arg;
|
|
||||||
+ __u32 in_size;
|
|
||||||
+ __u32 out_size;
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+struct fuse_ioctl_iovec {
|
|
||||||
+ __u64 base;
|
|
||||||
+ __u64 len;
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+struct fuse_ioctl_out {
|
|
||||||
+ __s32 result;
|
|
||||||
+ __u32 flags;
|
|
||||||
+ __u32 in_iovs;
|
|
||||||
+ __u32 out_iovs;
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
struct fuse_in_header {
|
|
||||||
__u32 len;
|
|
||||||
__u32 opcode;
|
|
||||||
diff -ur ntfs-3g_ntfsprogs-2014.2.15/include/fuse-lite/fuse_lowlevel.h ntfs-3g_ntfsprogs-2014.2.15.new/include/fuse-lite/fuse_lowlevel.h
|
|
||||||
--- ntfs-3g_ntfsprogs-2014.2.15/include/fuse-lite/fuse_lowlevel.h 2014-02-15 14:07:52.000000000 +0000
|
|
||||||
+++ ntfs-3g_ntfsprogs-2014.2.15.new/include/fuse-lite/fuse_lowlevel.h 2014-07-31 13:47:17.402904167 +0100
|
|
||||||
@@ -101,10 +101,8 @@
|
|
||||||
/** Thread ID of the calling process */
|
|
||||||
pid_t pid;
|
|
||||||
|
|
||||||
-#ifdef POSIXACLS
|
|
||||||
/** Umask of the calling process (introduced in version 2.8) */
|
|
||||||
mode_t umask;
|
|
||||||
-#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
/* 'to_set' flags in setattr */
|
|
||||||
@@ -805,6 +803,37 @@
|
|
||||||
*/
|
|
||||||
void (*bmap) (fuse_req_t req, fuse_ino_t ino, size_t blocksize,
|
|
||||||
uint64_t idx);
|
|
||||||
+ /**
|
|
||||||
+ * Ioctl
|
|
||||||
+ *
|
|
||||||
+ * Note: For unrestricted ioctls (not allowed for FUSE
|
|
||||||
+ * servers), data in and out areas can be discovered by giving
|
|
||||||
+ * iovs and setting FUSE_IOCTL_RETRY in @flags. For
|
|
||||||
+ * restricted ioctls, kernel prepares in/out data area
|
|
||||||
+ * according to the information encoded in cmd.
|
|
||||||
+ *
|
|
||||||
+ * Introduced in version 2.8
|
|
||||||
+ *
|
|
||||||
+ * Valid replies:
|
|
||||||
+ * fuse_reply_ioctl_retry
|
|
||||||
+ * fuse_reply_ioctl
|
|
||||||
+ * fuse_reply_ioctl_iov
|
|
||||||
+ * fuse_reply_err
|
|
||||||
+ *
|
|
||||||
+ * @param req request handle
|
|
||||||
+ * @param ino the inode number
|
|
||||||
+ * @param cmd ioctl command
|
|
||||||
+ * @param arg ioctl argument
|
|
||||||
+ * @param fi file information
|
|
||||||
+ * @param flags for FUSE_IOCTL_* flags
|
|
||||||
+ * @param in_buf data fetched from the caller
|
|
||||||
+ * @param in_bufsz number of fetched bytes
|
|
||||||
+ * @param out_bufsz maximum size of output data
|
|
||||||
+ */
|
|
||||||
+ void (*ioctl) (fuse_req_t req, fuse_ino_t ino, int cmd, void *arg,
|
|
||||||
+ struct fuse_file_info *fi, unsigned flags,
|
|
||||||
+ const void *in_buf, size_t in_bufsz, size_t out_bufsz);
|
|
||||||
+
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
@@ -1022,6 +1051,20 @@
|
|
||||||
const char *name, const struct stat *stbuf,
|
|
||||||
off_t off);
|
|
||||||
|
|
||||||
+/**
|
|
||||||
+ * Reply to finish ioctl
|
|
||||||
+ *
|
|
||||||
+ * Possible requests:
|
|
||||||
+ * ioctl
|
|
||||||
+ *
|
|
||||||
+ * @param req request handle
|
|
||||||
+ * @param result result to be passed to the caller
|
|
||||||
+ * @param buf buffer containing output data
|
|
||||||
+ * @param size length of output data
|
|
||||||
+ */
|
|
||||||
+int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size);
|
|
||||||
+
|
|
||||||
+
|
|
||||||
/* ----------------------------------------------------------- *
|
|
||||||
* Utility functions *
|
|
||||||
* ----------------------------------------------------------- */
|
|
||||||
diff -ur ntfs-3g_ntfsprogs-2014.2.15/libfuse-lite/fuse.c ntfs-3g_ntfsprogs-2014.2.15.new/libfuse-lite/fuse.c
|
|
||||||
--- ntfs-3g_ntfsprogs-2014.2.15/libfuse-lite/fuse.c 2014-02-15 14:07:52.000000000 +0000
|
|
||||||
+++ ntfs-3g_ntfsprogs-2014.2.15.new/libfuse-lite/fuse.c 2014-07-31 13:47:17.403904167 +0100
|
|
||||||
@@ -1040,6 +1040,21 @@
|
|
||||||
return -ENOSYS;
|
|
||||||
}
|
|
||||||
|
|
||||||
+int fuse_fs_ioctl(struct fuse_fs *fs, const char *path, int cmd, void *arg,
|
|
||||||
+ struct fuse_file_info *fi, unsigned int flags, void *data)
|
|
||||||
+{
|
|
||||||
+ fuse_get_context()->private_data = fs->user_data;
|
|
||||||
+ if (fs->op.ioctl) {
|
|
||||||
+/*
|
|
||||||
+ if (fs->debug)
|
|
||||||
+ fprintf(stderr, "ioctl[%llu] 0x%x flags: 0x%x\n",
|
|
||||||
+ (unsigned long long) fi->fh, cmd, flags);
|
|
||||||
+*/
|
|
||||||
+ return fs->op.ioctl(path, cmd, arg, fi, flags, data);
|
|
||||||
+ } else
|
|
||||||
+ return -ENOSYS;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static int is_open(struct fuse *f, fuse_ino_t dir, const char *name)
|
|
||||||
{
|
|
||||||
struct node *node;
|
|
||||||
@@ -2716,6 +2731,60 @@
|
|
||||||
reply_err(req, err);
|
|
||||||
}
|
|
||||||
|
|
||||||
+static void fuse_lib_ioctl(fuse_req_t req, fuse_ino_t ino, int cmd, void *arg,
|
|
||||||
+ struct fuse_file_info *llfi, unsigned int flags,
|
|
||||||
+ const void *in_buf, size_t in_bufsz,
|
|
||||||
+ size_t out_bufsz)
|
|
||||||
+{
|
|
||||||
+ struct fuse *f = req_fuse_prepare(req);
|
|
||||||
+ struct fuse_intr_data d;
|
|
||||||
+ struct fuse_file_info fi;
|
|
||||||
+ char *path, *out_buf = NULL;
|
|
||||||
+ int err;
|
|
||||||
+
|
|
||||||
+ err = -EPERM;
|
|
||||||
+ if (flags & FUSE_IOCTL_UNRESTRICTED)
|
|
||||||
+ goto err;
|
|
||||||
+
|
|
||||||
+ if (flags & FUSE_IOCTL_DIR)
|
|
||||||
+ get_dirhandle(llfi, &fi);
|
|
||||||
+ else
|
|
||||||
+ fi = *llfi;
|
|
||||||
+
|
|
||||||
+ if (out_bufsz) {
|
|
||||||
+ err = -ENOMEM;
|
|
||||||
+ out_buf = malloc(out_bufsz);
|
|
||||||
+ if (!out_buf)
|
|
||||||
+ goto err;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ assert(!in_bufsz || !out_bufsz || in_bufsz == out_bufsz);
|
|
||||||
+ if (out_buf)
|
|
||||||
+ memcpy(out_buf, in_buf, in_bufsz);
|
|
||||||
+
|
|
||||||
+ path = get_path(f, ino); /* Should be get_path_nullok() */
|
|
||||||
+ if (!path) {
|
|
||||||
+ err = ENOENT;
|
|
||||||
+ goto err;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ fuse_prepare_interrupt(f, req, &d);
|
|
||||||
+
|
|
||||||
+ /* Note : const qualifier dropped */
|
|
||||||
+ err = fuse_fs_ioctl(f->fs, path, cmd, arg, &fi, flags,
|
|
||||||
+ out_buf ? (void*)out_buf : (void*)(uintptr_t)in_buf);
|
|
||||||
+
|
|
||||||
+ fuse_finish_interrupt(f, req, &d);
|
|
||||||
+ free(path);
|
|
||||||
+
|
|
||||||
+ fuse_reply_ioctl(req, err, out_buf, out_bufsz);
|
|
||||||
+ goto out;
|
|
||||||
+err:
|
|
||||||
+ reply_err(req, err);
|
|
||||||
+out:
|
|
||||||
+ free(out_buf);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static struct fuse_lowlevel_ops fuse_path_ops = {
|
|
||||||
.init = fuse_lib_init,
|
|
||||||
.destroy = fuse_lib_destroy,
|
|
||||||
@@ -2751,6 +2820,7 @@
|
|
||||||
.getlk = fuse_lib_getlk,
|
|
||||||
.setlk = fuse_lib_setlk,
|
|
||||||
.bmap = fuse_lib_bmap,
|
|
||||||
+ .ioctl = fuse_lib_ioctl,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fuse_session *fuse_get_session(struct fuse *f)
|
|
||||||
diff -ur ntfs-3g_ntfsprogs-2014.2.15/libfuse-lite/fuse_lowlevel.c ntfs-3g_ntfsprogs-2014.2.15.new/libfuse-lite/fuse_lowlevel.c
|
|
||||||
--- ntfs-3g_ntfsprogs-2014.2.15/libfuse-lite/fuse_lowlevel.c 2014-02-15 14:07:52.000000000 +0000
|
|
||||||
+++ ntfs-3g_ntfsprogs-2014.2.15.new/libfuse-lite/fuse_lowlevel.c 2014-07-31 13:47:17.403904167 +0100
|
|
||||||
@@ -333,12 +333,8 @@
|
|
||||||
|
|
||||||
memset(&arg, 0, sizeof(arg));
|
|
||||||
fill_entry(&arg, e);
|
|
||||||
-#ifdef POSIXACLS
|
|
||||||
return send_reply_ok(req, &arg, (req->f->conn.proto_minor >= 12
|
|
||||||
? sizeof(arg) : FUSE_COMPAT_ENTRY_OUT_SIZE));
|
|
||||||
-#else
|
|
||||||
- return send_reply_ok(req, &arg, sizeof(arg));
|
|
||||||
-#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
|
|
||||||
@@ -351,7 +347,6 @@
|
|
||||||
|
|
||||||
memset(&arg, 0, sizeof(arg));
|
|
||||||
fill_entry(&arg.e, e);
|
|
||||||
-#ifdef POSIXACLS
|
|
||||||
if (req->f->conn.proto_minor < 12) {
|
|
||||||
fill_open((struct fuse_open_out*)
|
|
||||||
((char*)&arg + FUSE_COMPAT_ENTRY_OUT_SIZE), f);
|
|
||||||
@@ -361,10 +356,6 @@
|
|
||||||
fill_open(&arg.o, f);
|
|
||||||
return send_reply_ok(req, &arg, sizeof(arg));
|
|
||||||
}
|
|
||||||
-#else
|
|
||||||
- fill_open(&arg.o, f);
|
|
||||||
- return send_reply_ok(req, &arg, sizeof(arg));
|
|
||||||
-#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
|
|
||||||
@@ -377,12 +368,8 @@
|
|
||||||
arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
|
|
||||||
convert_stat(attr, &arg.attr);
|
|
||||||
|
|
||||||
-#ifdef POSIXACLS
|
|
||||||
return send_reply_ok(req, &arg, (req->f->conn.proto_minor >= 12
|
|
||||||
? sizeof(arg) : FUSE_COMPAT_FUSE_ATTR_OUT_SIZE));
|
|
||||||
-#else
|
|
||||||
- return send_reply_ok(req, &arg, sizeof(arg));
|
|
||||||
-#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
int fuse_reply_readlink(fuse_req_t req, const char *linkname)
|
|
||||||
@@ -462,6 +449,28 @@
|
|
||||||
return send_reply_ok(req, &arg, sizeof(arg));
|
|
||||||
}
|
|
||||||
|
|
||||||
+int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size)
|
|
||||||
+{
|
|
||||||
+ struct fuse_ioctl_out arg;
|
|
||||||
+ struct iovec iov[3];
|
|
||||||
+ size_t count = 1;
|
|
||||||
+
|
|
||||||
+ memset(&arg, 0, sizeof(arg));
|
|
||||||
+ arg.result = result;
|
|
||||||
+ iov[count].iov_base = &arg;
|
|
||||||
+ iov[count].iov_len = sizeof(arg);
|
|
||||||
+ count++;
|
|
||||||
+
|
|
||||||
+ if (size) {
|
|
||||||
+ /* Note : const qualifier dropped */
|
|
||||||
+ iov[count].iov_base = (char *)(uintptr_t) buf;
|
|
||||||
+ iov[count].iov_len = size;
|
|
||||||
+ count++;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return send_reply_iov(req, 0, iov, count);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
|
|
||||||
{
|
|
||||||
const char *name = (const char *) inarg;
|
|
||||||
@@ -538,11 +547,9 @@
|
|
||||||
const struct fuse_mknod_in *arg = (const struct fuse_mknod_in *) inarg;
|
|
||||||
const char *name = PARAM(arg);
|
|
||||||
|
|
||||||
-#ifdef POSIXACLS
|
|
||||||
if (req->f->conn.proto_minor >= 12)
|
|
||||||
req->ctx.umask = arg->umask;
|
|
||||||
else
|
|
||||||
-#endif
|
|
||||||
name = (const char *) inarg + FUSE_COMPAT_MKNOD_IN_SIZE;
|
|
||||||
|
|
||||||
if (req->f->op.mknod)
|
|
||||||
@@ -555,10 +562,8 @@
|
|
||||||
{
|
|
||||||
const struct fuse_mkdir_in *arg = (const struct fuse_mkdir_in *) inarg;
|
|
||||||
|
|
||||||
-#ifdef POSIXACLS
|
|
||||||
if (req->f->conn.proto_minor >= 12)
|
|
||||||
req->ctx.umask = arg->umask;
|
|
||||||
-#endif
|
|
||||||
|
|
||||||
if (req->f->op.mkdir)
|
|
||||||
req->f->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
|
|
||||||
@@ -630,11 +635,9 @@
|
|
||||||
memset(&fi, 0, sizeof(fi));
|
|
||||||
fi.flags = arg->flags;
|
|
||||||
|
|
||||||
-#ifdef POSIXACLS
|
|
||||||
if (req->f->conn.proto_minor >= 12)
|
|
||||||
req->ctx.umask = arg->umask;
|
|
||||||
else
|
|
||||||
-#endif
|
|
||||||
name = (const char *) inarg + sizeof(struct fuse_open_in);
|
|
||||||
|
|
||||||
req->f->op.create(req, nodeid, name, arg->mode, &fi);
|
|
||||||
@@ -682,7 +685,6 @@
|
|
||||||
fi.writepage = arg->write_flags & 1;
|
|
||||||
|
|
||||||
if (req->f->op.write) {
|
|
||||||
-#ifdef POSIXACLS
|
|
||||||
const char *buf;
|
|
||||||
|
|
||||||
if (req->f->conn.proto_minor >= 12)
|
|
||||||
@@ -690,9 +692,6 @@
|
|
||||||
else
|
|
||||||
buf = ((const char*)arg) + FUSE_COMPAT_WRITE_IN_SIZE;
|
|
||||||
req->f->op.write(req, nodeid, buf, arg->size, arg->offset, &fi);
|
|
||||||
-#else
|
|
||||||
- req->f->op.write(req, nodeid, PARAM(arg), arg->size, arg->offset, &fi);
|
|
||||||
-#endif
|
|
||||||
} else
|
|
||||||
fuse_reply_err(req, ENOSYS);
|
|
||||||
}
|
|
||||||
@@ -1011,6 +1010,39 @@
|
|
||||||
fuse_reply_err(req, ENOSYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
+static void do_ioctl(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
|
|
||||||
+{
|
|
||||||
+ const struct fuse_ioctl_in *arg = (const struct fuse_ioctl_in *) inarg;
|
|
||||||
+ unsigned int flags = arg->flags;
|
|
||||||
+ const void *in_buf = arg->in_size ? PARAM(arg) : NULL;
|
|
||||||
+ struct fuse_file_info fi;
|
|
||||||
+
|
|
||||||
+ if (flags & FUSE_IOCTL_DIR &&
|
|
||||||
+ !(req->f->conn.want & FUSE_CAP_IOCTL_DIR)) {
|
|
||||||
+ fuse_reply_err(req, ENOTTY);
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ memset(&fi, 0, sizeof(fi));
|
|
||||||
+ fi.fh = arg->fh;
|
|
||||||
+
|
|
||||||
+/* TODO JPA (need req->ioctl_64bit in obscure fuse_req_t)
|
|
||||||
+// probably a 64 bit ioctl on a 32-bit cpu
|
|
||||||
+// this is to forward a request from the kernel
|
|
||||||
+ if (sizeof(void *) == 4 && req->f->conn.proto_minor >= 16 &&
|
|
||||||
+ !(flags & FUSE_IOCTL_32BIT)) {
|
|
||||||
+ req->ioctl_64bit = 1;
|
|
||||||
+ }
|
|
||||||
+*/
|
|
||||||
+
|
|
||||||
+ if (req->f->op.ioctl)
|
|
||||||
+ req->f->op.ioctl(req, nodeid, arg->cmd,
|
|
||||||
+ (void *)(uintptr_t)arg->arg, &fi, flags,
|
|
||||||
+ in_buf, arg->in_size, arg->out_size);
|
|
||||||
+ else
|
|
||||||
+ fuse_reply_err(req, ENOSYS);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
|
|
||||||
{
|
|
||||||
const struct fuse_init_in *arg = (const struct fuse_init_in *) inarg;
|
|
||||||
@@ -1047,6 +1079,8 @@
|
|
||||||
#endif
|
|
||||||
if (arg->flags & FUSE_BIG_WRITES)
|
|
||||||
f->conn.capable |= FUSE_CAP_BIG_WRITES;
|
|
||||||
+ if (arg->flags & FUSE_HAS_IOCTL_DIR)
|
|
||||||
+ f->conn.capable |= FUSE_CAP_IOCTL_DIR;
|
|
||||||
} else {
|
|
||||||
f->conn.async_read = 0;
|
|
||||||
f->conn.max_readahead = 0;
|
|
||||||
@@ -1069,28 +1103,28 @@
|
|
||||||
memset(&outarg, 0, sizeof(outarg));
|
|
||||||
outarg.major = FUSE_KERNEL_VERSION;
|
|
||||||
/*
|
|
||||||
- * if POSIXACLS is not set, protocol 7.8 provides a good
|
|
||||||
- * compatibility with older kernel modules.
|
|
||||||
- * if POSIXACLS is set, we try to use protocol 7.12 supposed
|
|
||||||
- * to have the ability to process the umask conditionnally,
|
|
||||||
- * but, when using an older kernel module, we fallback to 7.8
|
|
||||||
+ * Suggest using protocol 7.18 when available, and fallback
|
|
||||||
+ * to 7.8 when running on an old kernel.
|
|
||||||
+ * Protocol 7.12 has the ability to process the umask
|
|
||||||
+ * conditionnally (as needed if POSIXACLS is set)
|
|
||||||
+ * Protocol 7.18 has the ability to process the ioctls
|
|
||||||
*/
|
|
||||||
-#ifdef POSIXACLS
|
|
||||||
- if (arg->major > 7 || (arg->major == 7 && arg->minor >= 12))
|
|
||||||
+ if (arg->major > 7 || (arg->major == 7 && arg->minor >= 18)) {
|
|
||||||
outarg.minor = FUSE_KERNEL_MINOR_VERSION;
|
|
||||||
- else
|
|
||||||
- outarg.minor = FUSE_KERNEL_MINOR_FALLBACK;
|
|
||||||
-#else
|
|
||||||
- outarg.minor = FUSE_KERNEL_MINOR_VERSION;
|
|
||||||
+ if (f->conn.want & FUSE_CAP_IOCTL_DIR)
|
|
||||||
+ outarg.flags |= FUSE_HAS_IOCTL_DIR;
|
|
||||||
+#ifdef POSIXACLS
|
|
||||||
+ if (f->conn.want & FUSE_CAP_DONT_MASK)
|
|
||||||
+ outarg.flags |= FUSE_DONT_MASK;
|
|
||||||
#endif
|
|
||||||
+ } else {
|
|
||||||
+ outarg.major = FUSE_KERNEL_MAJOR_FALLBACK;
|
|
||||||
+ outarg.minor = FUSE_KERNEL_MINOR_FALLBACK;
|
|
||||||
+ }
|
|
||||||
if (f->conn.async_read)
|
|
||||||
outarg.flags |= FUSE_ASYNC_READ;
|
|
||||||
if (f->op.getlk && f->op.setlk)
|
|
||||||
outarg.flags |= FUSE_POSIX_LOCKS;
|
|
||||||
-#ifdef POSIXACLS
|
|
||||||
- if (f->conn.want & FUSE_CAP_DONT_MASK)
|
|
||||||
- outarg.flags |= FUSE_DONT_MASK;
|
|
||||||
-#endif
|
|
||||||
if (f->conn.want & FUSE_CAP_BIG_WRITES)
|
|
||||||
outarg.flags |= FUSE_BIG_WRITES;
|
|
||||||
outarg.max_readahead = f->conn.max_readahead;
|
|
||||||
@@ -1191,6 +1225,7 @@
|
|
||||||
[FUSE_CREATE] = { do_create, "CREATE" },
|
|
||||||
[FUSE_INTERRUPT] = { do_interrupt, "INTERRUPT" },
|
|
||||||
[FUSE_BMAP] = { do_bmap, "BMAP" },
|
|
||||||
+ [FUSE_IOCTL] = { do_ioctl, "IOCTL" },
|
|
||||||
[FUSE_DESTROY] = { do_destroy, "DESTROY" },
|
|
||||||
};
|
|
||||||
|
|
@ -1,648 +0,0 @@
|
|||||||
diff -urN ntfs-3g_ntfsprogs-2014.2.15.old/configure.ac ntfs-3g_ntfsprogs-2014.2.15/configure.ac
|
|
||||||
--- ntfs-3g_ntfsprogs-2014.2.15.old/configure.ac 2014-02-15 14:07:52.000000000 +0000
|
|
||||||
+++ ntfs-3g_ntfsprogs-2014.2.15/configure.ac 2014-07-31 13:51:24.425065808 +0100
|
|
||||||
@@ -463,7 +463,8 @@
|
|
||||||
regex.h endian.h byteswap.h sys/byteorder.h sys/disk.h sys/endian.h \
|
|
||||||
sys/param.h sys/ioctl.h sys/mkdev.h sys/mount.h sys/stat.h sys/types.h \
|
|
||||||
sys/vfs.h sys/statvfs.h sys/sysmacros.h linux/major.h linux/fd.h \
|
|
||||||
- linux/hdreg.h machine/endian.h windows.h syslog.h pwd.h malloc.h])
|
|
||||||
+ linux/fs.h inttypes.h linux/hdreg.h \
|
|
||||||
+ machine/endian.h windows.h syslog.h pwd.h malloc.h])
|
|
||||||
|
|
||||||
# Checks for typedefs, structures, and compiler characteristics.
|
|
||||||
AC_HEADER_STDBOOL
|
|
||||||
diff -urN ntfs-3g_ntfsprogs-2014.2.15.old/include/ntfs-3g/ioctl.h ntfs-3g_ntfsprogs-2014.2.15/include/ntfs-3g/ioctl.h
|
|
||||||
--- ntfs-3g_ntfsprogs-2014.2.15.old/include/ntfs-3g/ioctl.h 1970-01-01 01:00:00.000000000 +0100
|
|
||||||
+++ ntfs-3g_ntfsprogs-2014.2.15/include/ntfs-3g/ioctl.h 2014-07-31 13:51:24.426065810 +0100
|
|
||||||
@@ -0,0 +1,30 @@
|
|
||||||
+/*
|
|
||||||
+ *
|
|
||||||
+ * Copyright (c) 2014 Jean-Pierre Andre
|
|
||||||
+ *
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * This program 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 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
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#ifndef IOCTL_H
|
|
||||||
+#define IOCTL_H
|
|
||||||
+
|
|
||||||
+int ntfs_ioctl(ntfs_inode *ni, int cmd, void *arg,
|
|
||||||
+ unsigned int flags, void *data);
|
|
||||||
+
|
|
||||||
+#endif /* IOCTL_H */
|
|
||||||
diff -urN ntfs-3g_ntfsprogs-2014.2.15.old/include/ntfs-3g/volume.h ntfs-3g_ntfsprogs-2014.2.15/include/ntfs-3g/volume.h
|
|
||||||
--- ntfs-3g_ntfsprogs-2014.2.15.old/include/ntfs-3g/volume.h 2014-02-15 14:07:52.000000000 +0000
|
|
||||||
+++ ntfs-3g_ntfsprogs-2014.2.15/include/ntfs-3g/volume.h 2014-07-31 13:51:24.426065810 +0100
|
|
||||||
@@ -36,9 +36,7 @@
|
|
||||||
#ifdef HAVE_SYS_PARAM_H
|
|
||||||
#include <sys/param.h>
|
|
||||||
#endif
|
|
||||||
-#ifdef HAVE_SYS_MOUNT_H
|
|
||||||
-#include <sys/mount.h>
|
|
||||||
-#endif
|
|
||||||
+ /* Do not #include <sys/mount.h> here : conflicts with <linux/fs.h> */
|
|
||||||
#ifdef HAVE_MNTENT_H
|
|
||||||
#include <mntent.h>
|
|
||||||
#endif
|
|
||||||
diff -urN ntfs-3g_ntfsprogs-2014.2.15.old/libntfs-3g/ioctl.c ntfs-3g_ntfsprogs-2014.2.15/libntfs-3g/ioctl.c
|
|
||||||
--- ntfs-3g_ntfsprogs-2014.2.15.old/libntfs-3g/ioctl.c 1970-01-01 01:00:00.000000000 +0100
|
|
||||||
+++ ntfs-3g_ntfsprogs-2014.2.15/libntfs-3g/ioctl.c 2014-07-31 13:51:24.427065813 +0100
|
|
||||||
@@ -0,0 +1,382 @@
|
|
||||||
+/**
|
|
||||||
+ * ioctl.c - Processing of ioctls
|
|
||||||
+ *
|
|
||||||
+ * This module is part of ntfs-3g library
|
|
||||||
+ *
|
|
||||||
+ * Copyright (c) 2014 Jean-Pierre Andre
|
|
||||||
+ * Copyright (c) 2014 Red Hat, Inc.
|
|
||||||
+ *
|
|
||||||
+ * 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_STDIO_H
|
|
||||||
+#include <stdio.h>
|
|
||||||
+#endif
|
|
||||||
+#ifdef HAVE_INTTYPES_H
|
|
||||||
+#include <inttypes.h>
|
|
||||||
+#endif
|
|
||||||
+#ifdef HAVE_STRING_H
|
|
||||||
+#include <string.h>
|
|
||||||
+#endif
|
|
||||||
+#ifdef HAVE_ERRNO_H
|
|
||||||
+#include <errno.h>
|
|
||||||
+#endif
|
|
||||||
+#ifdef HAVE_FCNTL_H
|
|
||||||
+#include <fcntl.h>
|
|
||||||
+#endif
|
|
||||||
+#ifdef HAVE_UNISTD_H
|
|
||||||
+#include <unistd.h>
|
|
||||||
+#endif
|
|
||||||
+#ifdef HAVE_STDLIB_H
|
|
||||||
+#include <stdlib.h>
|
|
||||||
+#endif
|
|
||||||
+#ifdef HAVE_LIMITS_H
|
|
||||||
+#include <limits.h>
|
|
||||||
+#endif
|
|
||||||
+#include <syslog.h>
|
|
||||||
+
|
|
||||||
+#ifdef HAVE_SETXATTR
|
|
||||||
+#include <sys/xattr.h>
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
+#ifdef HAVE_SYS_TYPES_H
|
|
||||||
+#include <sys/types.h>
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
+#ifdef HAVE_SYS_STAT_H
|
|
||||||
+#include <sys/stat.h>
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
+#ifdef HAVE_LINUX_FS_H
|
|
||||||
+#include <linux/fs.h>
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
+#include <dirent.h>
|
|
||||||
+
|
|
||||||
+#include "compat.h"
|
|
||||||
+#include "debug.h"
|
|
||||||
+#include "bitmap.h"
|
|
||||||
+#include "attrib.h"
|
|
||||||
+#include "inode.h"
|
|
||||||
+#include "layout.h"
|
|
||||||
+#include "volume.h"
|
|
||||||
+#include "index.h"
|
|
||||||
+#include "logging.h"
|
|
||||||
+#include "ntfstime.h"
|
|
||||||
+#include "unistr.h"
|
|
||||||
+#include "dir.h"
|
|
||||||
+#include "security.h"
|
|
||||||
+#include "ioctl.h"
|
|
||||||
+#include "misc.h"
|
|
||||||
+
|
|
||||||
+#if defined(FITRIM) && defined(BLKDISCARD)
|
|
||||||
+
|
|
||||||
+/* Issue a TRIM request to the underlying device for the given clusters. */
|
|
||||||
+static int fstrim_clusters(ntfs_volume *vol, LCN lcn, s64 length)
|
|
||||||
+{
|
|
||||||
+ struct ntfs_device *dev = vol->dev;
|
|
||||||
+ uint64_t range[2];
|
|
||||||
+
|
|
||||||
+ ntfs_log_debug("fstrim_clusters: %lld length %lld\n",
|
|
||||||
+ (long long) lcn, (long long) length);
|
|
||||||
+
|
|
||||||
+ range[0] = lcn << vol->cluster_size_bits;
|
|
||||||
+ range[1] = length << vol->cluster_size_bits;
|
|
||||||
+
|
|
||||||
+ if (dev->d_ops->ioctl(dev, BLKDISCARD, range) == -1) {
|
|
||||||
+ ntfs_log_debug("fstrim_one_cluster: ioctl failed: %m\n");
|
|
||||||
+ return -errno;
|
|
||||||
+ }
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int read_line(const char *path, char *line, size_t max_bytes)
|
|
||||||
+{
|
|
||||||
+ FILE *fp;
|
|
||||||
+
|
|
||||||
+ fp = fopen(path, "r");
|
|
||||||
+ if (fp == NULL)
|
|
||||||
+ return -errno;
|
|
||||||
+ if (fgets(line, max_bytes, fp) == NULL) {
|
|
||||||
+ int ret = -EIO; /* fgets doesn't set errno */
|
|
||||||
+ fclose(fp);
|
|
||||||
+ return ret;
|
|
||||||
+ }
|
|
||||||
+ fclose (fp);
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int read_u64(const char *path, u64 *n)
|
|
||||||
+{
|
|
||||||
+ char line[64];
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ ret = read_line(path, line, sizeof line);
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+ if (sscanf(line, "%" SCNu64, n) != 1)
|
|
||||||
+ return -EINVAL;
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+/* Find discard limits for current backing device.
|
|
||||||
+ * XXX Kernel makes this a pain in the neck.
|
|
||||||
+ */
|
|
||||||
+static int fstrim_limits(ntfs_volume *vol, u64 *discard_granularity,
|
|
||||||
+ u64 *discard_max_bytes)
|
|
||||||
+{
|
|
||||||
+ struct stat statbuf;
|
|
||||||
+ DIR *dir;
|
|
||||||
+ struct dirent *d;
|
|
||||||
+ char path[80];
|
|
||||||
+ char line[64];
|
|
||||||
+ char dev[64];
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ /* Stat the backing device. Caller has ensured it is a block device. */
|
|
||||||
+ if (stat(vol->dev->d_name, &statbuf) == -1) {
|
|
||||||
+ ntfs_log_debug("fstrim_limits: could not stat %s\n",
|
|
||||||
+ vol->dev->d_name);
|
|
||||||
+ return -errno;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* Now look for a /sys/block/<dev>/dev file which contains
|
|
||||||
+ * "major:minor\n".
|
|
||||||
+ */
|
|
||||||
+ snprintf(dev, sizeof dev, "%d:%d\n",
|
|
||||||
+ major(statbuf.st_rdev), minor(statbuf.st_rdev));
|
|
||||||
+
|
|
||||||
+ dir = opendir("/sys/block");
|
|
||||||
+ if (dir == NULL) {
|
|
||||||
+ ntfs_log_debug("fstrim_limits: could not open /sys/block\n");
|
|
||||||
+ return -errno;
|
|
||||||
+ }
|
|
||||||
+ for (;;) {
|
|
||||||
+ errno = 0;
|
|
||||||
+ d = readdir(dir);
|
|
||||||
+ if (!d) break;
|
|
||||||
+
|
|
||||||
+ snprintf(path, sizeof path, "/sys/block/%s/dev", d->d_name);
|
|
||||||
+ ret = read_line(path, line, sizeof line);
|
|
||||||
+ if (ret)
|
|
||||||
+ continue;
|
|
||||||
+ if (strcmp(line, dev) == 0)
|
|
||||||
+ goto found;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* Check readdir didn't fail. */
|
|
||||||
+ if (errno != 0) {
|
|
||||||
+ ret = -errno;
|
|
||||||
+ ntfs_log_debug("fstrim_limits: readdir failed\n");
|
|
||||||
+ goto out;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* If we reach here then we didn't find the device. This is
|
|
||||||
+ * not an error, but set discard_max_bytes = 0 to indicate
|
|
||||||
+ * that discard is not available.
|
|
||||||
+ */
|
|
||||||
+ *discard_granularity = 0;
|
|
||||||
+ *discard_max_bytes = 0;
|
|
||||||
+ ntfs_log_debug("fstrim_limits: /sys/block entry corresponding to device %s not found\n",
|
|
||||||
+ vol->dev->d_name);
|
|
||||||
+ ret = 0;
|
|
||||||
+ goto out;
|
|
||||||
+
|
|
||||||
+found:
|
|
||||||
+ /* Found the device at /sys/block/ + d->d_name */
|
|
||||||
+ snprintf (path, sizeof path,
|
|
||||||
+ "/sys/block/%s/queue/discard_granularity",
|
|
||||||
+ d->d_name);
|
|
||||||
+ ret = read_u64(path, discard_granularity);
|
|
||||||
+ if (ret) {
|
|
||||||
+ ntfs_log_debug("fstrim_limits: could not read %s\n", path);
|
|
||||||
+ goto out;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ snprintf (path, sizeof path,
|
|
||||||
+ "/sys/block/%s/queue/discard_max_bytes",
|
|
||||||
+ d->d_name);
|
|
||||||
+ ret = read_u64(path, discard_max_bytes);
|
|
||||||
+ if (ret) {
|
|
||||||
+ ntfs_log_debug("fstrim_limits: could not read %s\n", path);
|
|
||||||
+ goto out;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ ntfs_log_debug("fstrim_limits: device %s discard granularity = %llu max_bytes = %llu\n",
|
|
||||||
+ d->d_name,
|
|
||||||
+ (unsigned long long) *discard_granularity,
|
|
||||||
+ (unsigned long long) *discard_max_bytes);
|
|
||||||
+
|
|
||||||
+ ret = 0;
|
|
||||||
+out:
|
|
||||||
+ if (closedir (dir) == -1) {
|
|
||||||
+ ret = -errno;
|
|
||||||
+ ntfs_log_debug("fstrim_limits: closedir failed\n");
|
|
||||||
+ return ret;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+#define FSTRIM_BUFSIZ 4096
|
|
||||||
+
|
|
||||||
+/* Trim the filesystem.
|
|
||||||
+ *
|
|
||||||
+ * Free blocks between 'start' and 'start+len-1' (both byte offsets)
|
|
||||||
+ * are found and TRIM requests are sent to the block device. 'minlen'
|
|
||||||
+ * is the minimum continguous free range to discard.
|
|
||||||
+ */
|
|
||||||
+static int fstrim(ntfs_volume *vol, void *data)
|
|
||||||
+{
|
|
||||||
+ struct fstrim_range *range = data;
|
|
||||||
+ u64 start = range->start;
|
|
||||||
+ u64 len = range->len;
|
|
||||||
+ u64 minlen = range->minlen;
|
|
||||||
+ u64 discard_granularity, discard_max_bytes;
|
|
||||||
+ u8 *buf = NULL;
|
|
||||||
+ LCN start_buf;
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ ntfs_log_debug("fstrim: start=%llu len=%llu minlen=%llu\n",
|
|
||||||
+ (unsigned long long) start,
|
|
||||||
+ (unsigned long long) len,
|
|
||||||
+ (unsigned long long) minlen);
|
|
||||||
+
|
|
||||||
+ /* Fail if user tries to use the fstrim -o/-l/-m options.
|
|
||||||
+ * XXX We could fix these limitations in future.
|
|
||||||
+ */
|
|
||||||
+ if (start != 0 || len != (uint64_t)-1) {
|
|
||||||
+ ntfs_log_debug("fstrim: setting start or length is not supported\n");
|
|
||||||
+ return -EINVAL;
|
|
||||||
+ }
|
|
||||||
+ if (minlen > vol->cluster_size) {
|
|
||||||
+ ntfs_log_debug("fstrim: minlen > cluster size is not supported\n");
|
|
||||||
+ return -EINVAL;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* Only block devices are supported. It would be possible to
|
|
||||||
+ * support backing files (ie. without using loop) but the
|
|
||||||
+ * ioctls used to punch holes in files are completely
|
|
||||||
+ * different.
|
|
||||||
+ */
|
|
||||||
+ if (!NDevBlock(vol->dev)) {
|
|
||||||
+ ntfs_log_debug("fstrim: not supported for non-block-device\n");
|
|
||||||
+ return -EOPNOTSUPP;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ ret = fstrim_limits(vol, &discard_granularity, &discard_max_bytes);
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+ if (discard_granularity > vol->cluster_size) {
|
|
||||||
+ ntfs_log_debug("fstrim: discard granularity of backing device is larger than cluster size\n");
|
|
||||||
+ return -EOPNOTSUPP;
|
|
||||||
+ }
|
|
||||||
+ if (discard_max_bytes == 0) {
|
|
||||||
+ ntfs_log_debug("fstrim: backing device does not support discard (discard_max_bytes == 0)\n");
|
|
||||||
+ return -EOPNOTSUPP;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* Sync the device before doing anything. */
|
|
||||||
+ ret = ntfs_device_sync(vol->dev);
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ /* Read through the bitmap. */
|
|
||||||
+ buf = ntfs_malloc(FSTRIM_BUFSIZ);
|
|
||||||
+ if (buf == NULL)
|
|
||||||
+ return -errno;
|
|
||||||
+ for (start_buf = 0; start_buf < vol->nr_clusters;
|
|
||||||
+ start_buf += FSTRIM_BUFSIZ * 8) {
|
|
||||||
+ s64 count;
|
|
||||||
+ s64 br;
|
|
||||||
+ LCN end_buf, start_lcn;
|
|
||||||
+
|
|
||||||
+ /* start_buf is LCN of first cluster in the current buffer.
|
|
||||||
+ * end_buf is LCN of last cluster + 1 in the current buffer.
|
|
||||||
+ */
|
|
||||||
+ end_buf = start_buf + FSTRIM_BUFSIZ*8;
|
|
||||||
+ if (end_buf > vol->nr_clusters)
|
|
||||||
+ end_buf = vol->nr_clusters;
|
|
||||||
+ count = (end_buf - start_buf) / 8;
|
|
||||||
+
|
|
||||||
+ br = ntfs_attr_pread(vol->lcnbmp_na, start_buf/8, count, buf);
|
|
||||||
+ if (br != count) {
|
|
||||||
+ if (br >= 0)
|
|
||||||
+ ret = -EIO;
|
|
||||||
+ else
|
|
||||||
+ ret = -errno;
|
|
||||||
+ goto free_out;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* Trim the clusters in large as possible blocks, but
|
|
||||||
+ * not larger than discard_max_bytes.
|
|
||||||
+ */
|
|
||||||
+ for (start_lcn = start_buf; start_lcn < end_buf; ++start_lcn) {
|
|
||||||
+ if (!ntfs_bit_get(buf, start_lcn-start_buf)) {
|
|
||||||
+ LCN end_lcn;
|
|
||||||
+
|
|
||||||
+ /* Cluster 'start_lcn' is not in use,
|
|
||||||
+ * find end of this run.
|
|
||||||
+ */
|
|
||||||
+ end_lcn = start_lcn+1;
|
|
||||||
+ while (end_lcn < end_buf &&
|
|
||||||
+ (u64) (end_lcn-start_lcn) << vol->cluster_size_bits
|
|
||||||
+ < discard_max_bytes &&
|
|
||||||
+ !ntfs_bit_get(buf, end_lcn-start_buf))
|
|
||||||
+ end_lcn++;
|
|
||||||
+
|
|
||||||
+ ret = fstrim_clusters(vol,
|
|
||||||
+ start_lcn, end_lcn-start_lcn);
|
|
||||||
+ if (ret)
|
|
||||||
+ goto free_out;
|
|
||||||
+
|
|
||||||
+ start_lcn = end_lcn-1;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ ret = 0;
|
|
||||||
+free_out:
|
|
||||||
+ free(buf);
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+#endif /* FITRIM && BLKDISCARD */
|
|
||||||
+
|
|
||||||
+int ntfs_ioctl(ntfs_inode *ni, int cmd, void *arg __attribute__((unused)),
|
|
||||||
+ unsigned int flags __attribute__((unused)), void *data)
|
|
||||||
+{
|
|
||||||
+ int ret = 0;
|
|
||||||
+
|
|
||||||
+ switch (cmd) {
|
|
||||||
+#if defined(FITRIM) && defined(BLKDISCARD)
|
|
||||||
+ case FITRIM:
|
|
||||||
+ if (!ni || !data)
|
|
||||||
+ ret = -EINVAL;
|
|
||||||
+ else
|
|
||||||
+ ret = fstrim(ni->vol, data);
|
|
||||||
+ break;
|
|
||||||
+#else
|
|
||||||
+#warning FITRIM or BLKDISCARD not defined
|
|
||||||
+#endif
|
|
||||||
+ default :
|
|
||||||
+ ret = -EINVAL;
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+ return (ret);
|
|
||||||
+}
|
|
||||||
diff -urN ntfs-3g_ntfsprogs-2014.2.15.old/libntfs-3g/Makefile.am ntfs-3g_ntfsprogs-2014.2.15/libntfs-3g/Makefile.am
|
|
||||||
--- ntfs-3g_ntfsprogs-2014.2.15.old/libntfs-3g/Makefile.am 2014-02-15 14:07:52.000000000 +0000
|
|
||||||
+++ ntfs-3g_ntfsprogs-2014.2.15/libntfs-3g/Makefile.am 2014-07-31 13:51:24.426065810 +0100
|
|
||||||
@@ -30,6 +30,7 @@
|
|
||||||
efs.c \
|
|
||||||
index.c \
|
|
||||||
inode.c \
|
|
||||||
+ ioctl.c \
|
|
||||||
lcnalloc.c \
|
|
||||||
logfile.c \
|
|
||||||
logging.c \
|
|
||||||
diff -urN ntfs-3g_ntfsprogs-2014.2.15.old/src/lowntfs-3g.c ntfs-3g_ntfsprogs-2014.2.15/src/lowntfs-3g.c
|
|
||||||
--- ntfs-3g_ntfsprogs-2014.2.15.old/src/lowntfs-3g.c 2014-02-15 14:07:52.000000000 +0000
|
|
||||||
+++ ntfs-3g_ntfsprogs-2014.2.15/src/lowntfs-3g.c 2014-07-31 13:51:24.429065815 +0100
|
|
||||||
@@ -81,7 +81,12 @@
|
|
||||||
#include <sys/dirent.h>
|
|
||||||
#endif /* defined(__APPLE__) || defined(__DARWIN__) */
|
|
||||||
|
|
||||||
+#ifdef HAVE_LINUX_FS_H
|
|
||||||
+#include <linux/fs.h>
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
#include "compat.h"
|
|
||||||
+#include "bitmap.h"
|
|
||||||
#include "attrib.h"
|
|
||||||
#include "inode.h"
|
|
||||||
#include "volume.h"
|
|
||||||
@@ -97,6 +102,7 @@
|
|
||||||
#include "logging.h"
|
|
||||||
#include "xattrs.h"
|
|
||||||
#include "misc.h"
|
|
||||||
+#include "ioctl.h"
|
|
||||||
|
|
||||||
#include "ntfs-3g_common.h"
|
|
||||||
|
|
||||||
@@ -564,8 +570,6 @@
|
|
||||||
}
|
|
||||||
#endif /* defined(__APPLE__) || defined(__DARWIN__) */
|
|
||||||
|
|
||||||
-#if defined(FUSE_CAP_DONT_MASK) || defined(FUSE_CAP_BIG_WRITES) \
|
|
||||||
- || (defined(__APPLE__) || defined(__DARWIN__))
|
|
||||||
static void ntfs_init(void *userdata __attribute__((unused)),
|
|
||||||
struct fuse_conn_info *conn)
|
|
||||||
{
|
|
||||||
@@ -582,8 +586,8 @@
|
|
||||||
>= SAFE_CAPACITY_FOR_BIG_WRITES))
|
|
||||||
conn->want |= FUSE_CAP_BIG_WRITES;
|
|
||||||
#endif
|
|
||||||
+ conn->want |= FUSE_CAP_IOCTL_DIR;
|
|
||||||
}
|
|
||||||
-#endif /* defined(FUSE_CAP_DONT_MASK) || (defined(__APPLE__) || defined(__DARWIN__)) */
|
|
||||||
|
|
||||||
static int ntfs_fuse_getstat(struct SECURITY_CONTEXT *scx,
|
|
||||||
ntfs_inode *ni, struct stat *stbuf)
|
|
||||||
@@ -2573,6 +2577,48 @@
|
|
||||||
fuse_reply_err(req, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
+static void ntfs_fuse_ioctl(fuse_req_t req __attribute__((unused)),
|
|
||||||
+ fuse_ino_t ino __attribute__((unused)),
|
|
||||||
+ int cmd, void *arg,
|
|
||||||
+ struct fuse_file_info *fi __attribute__((unused)),
|
|
||||||
+ unsigned flags, const void *data,
|
|
||||||
+ size_t in_bufsz, size_t out_bufsz)
|
|
||||||
+{
|
|
||||||
+ ntfs_inode *ni;
|
|
||||||
+ char *buf = (char*)NULL;
|
|
||||||
+ int bufsz;
|
|
||||||
+ int ret = 0;
|
|
||||||
+
|
|
||||||
+ if (flags & FUSE_IOCTL_COMPAT) {
|
|
||||||
+ ret = -ENOSYS;
|
|
||||||
+ } else {
|
|
||||||
+ ni = ntfs_inode_open(ctx->vol, INODE(ino));
|
|
||||||
+ if (!ni) {
|
|
||||||
+ ret = -errno;
|
|
||||||
+ goto fail;
|
|
||||||
+ }
|
|
||||||
+ bufsz = (in_bufsz > out_bufsz ? in_bufsz : out_bufsz);
|
|
||||||
+ if (bufsz) {
|
|
||||||
+ buf = ntfs_malloc(bufsz);
|
|
||||||
+ if (!buf) {
|
|
||||||
+ ret = ENOMEM;
|
|
||||||
+ goto fail;
|
|
||||||
+ }
|
|
||||||
+ memcpy(buf, data, in_bufsz);
|
|
||||||
+ }
|
|
||||||
+ ret = ntfs_ioctl(ni, cmd, arg, flags, buf);
|
|
||||||
+ if (ntfs_inode_close (ni))
|
|
||||||
+ set_fuse_error(&ret);
|
|
||||||
+ }
|
|
||||||
+ if (ret)
|
|
||||||
+fail :
|
|
||||||
+ fuse_reply_err(req, -ret);
|
|
||||||
+ else
|
|
||||||
+ fuse_reply_ioctl(req, 0, buf, out_bufsz);
|
|
||||||
+ if (buf)
|
|
||||||
+ free(buf);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static void ntfs_fuse_bmap(fuse_req_t req, fuse_ino_t ino, size_t blocksize,
|
|
||||||
uint64_t vidx)
|
|
||||||
{
|
|
||||||
@@ -3496,6 +3542,7 @@
|
|
||||||
.fsyncdir = ntfs_fuse_fsync,
|
|
||||||
.bmap = ntfs_fuse_bmap,
|
|
||||||
.destroy = ntfs_fuse_destroy2,
|
|
||||||
+ .ioctl = ntfs_fuse_ioctl,
|
|
||||||
#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
|
|
||||||
.access = ntfs_fuse_access,
|
|
||||||
#endif
|
|
||||||
@@ -3512,10 +3559,7 @@
|
|
||||||
.setbkuptime = ntfs_macfuse_setbkuptime,
|
|
||||||
.setchgtime = ntfs_macfuse_setchgtime,
|
|
||||||
#endif /* defined(__APPLE__) || defined(__DARWIN__) */
|
|
||||||
-#if defined(FUSE_CAP_DONT_MASK) || defined(FUSE_CAP_BIG_WRITES) \
|
|
||||||
- || (defined(__APPLE__) || defined(__DARWIN__))
|
|
||||||
.init = ntfs_init
|
|
||||||
-#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
static int ntfs_fuse_init(void)
|
|
||||||
diff -urN ntfs-3g_ntfsprogs-2014.2.15.old/src/ntfs-3g.c ntfs-3g_ntfsprogs-2014.2.15/src/ntfs-3g.c
|
|
||||||
--- ntfs-3g_ntfsprogs-2014.2.15.old/src/ntfs-3g.c 2014-02-15 14:07:52.000000000 +0000
|
|
||||||
+++ ntfs-3g_ntfsprogs-2014.2.15/src/ntfs-3g.c 2014-07-31 13:51:24.430065816 +0100
|
|
||||||
@@ -96,6 +96,7 @@
|
|
||||||
#include "logging.h"
|
|
||||||
#include "xattrs.h"
|
|
||||||
#include "misc.h"
|
|
||||||
+#include "ioctl.h"
|
|
||||||
|
|
||||||
#include "ntfs-3g_common.h"
|
|
||||||
|
|
||||||
@@ -636,8 +637,6 @@
|
|
||||||
}
|
|
||||||
#endif /* defined(__APPLE__) || defined(__DARWIN__) */
|
|
||||||
|
|
||||||
-#if defined(FUSE_CAP_DONT_MASK) || defined(FUSE_CAP_BIG_WRITES) \
|
|
||||||
- || (defined(__APPLE__) || defined(__DARWIN__))
|
|
||||||
static void *ntfs_init(struct fuse_conn_info *conn)
|
|
||||||
{
|
|
||||||
#if defined(__APPLE__) || defined(__DARWIN__)
|
|
||||||
@@ -653,9 +652,9 @@
|
|
||||||
>= SAFE_CAPACITY_FOR_BIG_WRITES))
|
|
||||||
conn->want |= FUSE_CAP_BIG_WRITES;
|
|
||||||
#endif
|
|
||||||
+ conn->want |= FUSE_CAP_IOCTL_DIR;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
-#endif /* defined(FUSE_CAP_DONT_MASK) || (defined(__APPLE__) || defined(__DARWIN__)) */
|
|
||||||
|
|
||||||
static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf)
|
|
||||||
{
|
|
||||||
@@ -2412,6 +2411,28 @@
|
|
||||||
return (ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
+static int ntfs_fuse_ioctl(const char *path,
|
|
||||||
+ int cmd, void *arg,
|
|
||||||
+ struct fuse_file_info *fi __attribute__((unused)),
|
|
||||||
+ unsigned int flags, void *data)
|
|
||||||
+{
|
|
||||||
+ ntfs_inode *ni;
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ if (flags & FUSE_IOCTL_COMPAT)
|
|
||||||
+ return -ENOSYS;
|
|
||||||
+
|
|
||||||
+ ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
|
|
||||||
+ if (!ni)
|
|
||||||
+ return -errno;
|
|
||||||
+
|
|
||||||
+ ret = ntfs_ioctl(ni, cmd, arg, flags, data);
|
|
||||||
+
|
|
||||||
+ if (ntfs_inode_close (ni))
|
|
||||||
+ set_fuse_error(&ret);
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static int ntfs_fuse_bmap(const char *path, size_t blocksize, uint64_t *idx)
|
|
||||||
{
|
|
||||||
ntfs_inode *ni;
|
|
||||||
@@ -3335,6 +3356,7 @@
|
|
||||||
.fsyncdir = ntfs_fuse_fsync,
|
|
||||||
.bmap = ntfs_fuse_bmap,
|
|
||||||
.destroy = ntfs_fuse_destroy2,
|
|
||||||
+ .ioctl = ntfs_fuse_ioctl,
|
|
||||||
#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
|
|
||||||
.access = ntfs_fuse_access,
|
|
||||||
.opendir = ntfs_fuse_opendir,
|
|
||||||
@@ -3352,10 +3374,7 @@
|
|
||||||
.setbkuptime = ntfs_macfuse_setbkuptime,
|
|
||||||
.setchgtime = ntfs_macfuse_setchgtime,
|
|
||||||
#endif /* defined(__APPLE__) || defined(__DARWIN__) */
|
|
||||||
-#if defined(FUSE_CAP_DONT_MASK) || defined(FUSE_CAP_BIG_WRITES) \
|
|
||||||
- || (defined(__APPLE__) || defined(__DARWIN__))
|
|
||||||
.init = ntfs_init
|
|
||||||
-#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
static int ntfs_fuse_init(void)
|
|
@ -1,39 +0,0 @@
|
|||||||
--- libntfs-3g/compress.c.ref 2013-05-07 10:50:28.000000000 +0200
|
|
||||||
+++ libntfs-3g/compress.c 2013-05-13 16:37:17.000000000 +0200
|
|
||||||
@@ -5,7 +5,7 @@
|
|
||||||
* Copyright (c) 2004-2005 Anton Altaparmakov
|
|
||||||
* Copyright (c) 2004-2006 Szabolcs Szakacsits
|
|
||||||
* Copyright (c) 2005 Yura Pakhuchiy
|
|
||||||
- * Copyright (c) 2009-2011 Jean-Pierre Andre
|
|
||||||
+ * Copyright (c) 2009-2013 Jean-Pierre Andre
|
|
||||||
*
|
|
||||||
* 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
|
|
||||||
@@ -753,6 +753,7 @@
|
|
||||||
ofs = 0;
|
|
||||||
} else {
|
|
||||||
s64 tdata_size, tinitialized_size;
|
|
||||||
+ int decompsz;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Compressed cb, decompress it into the temporary buffer, then
|
|
||||||
@@ -810,7 +811,10 @@
|
|
||||||
if (cb_pos + 2 <= cb_end)
|
|
||||||
*(u16*)cb_pos = 0;
|
|
||||||
ntfs_log_debug("Successfully read the compression block.\n");
|
|
||||||
- if (ntfs_decompress(dest, cb_size, cb, cb_size) < 0) {
|
|
||||||
+ /* Do not decompress beyond the requested block */
|
|
||||||
+ to_read = min(count, cb_size - ofs);
|
|
||||||
+ decompsz = ((ofs + to_read - 1) | (NTFS_SB_SIZE - 1)) + 1;
|
|
||||||
+ if (ntfs_decompress(dest, decompsz, cb, cb_size) < 0) {
|
|
||||||
err = errno;
|
|
||||||
free(cb);
|
|
||||||
free(dest);
|
|
||||||
@@ -819,7 +823,6 @@
|
|
||||||
errno = err;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
- to_read = min(count, cb_size - ofs);
|
|
||||||
memcpy(b, dest + ofs, to_read);
|
|
||||||
total += to_read;
|
|
||||||
count -= to_read;
|
|
@ -1,24 +0,0 @@
|
|||||||
Index: libfuse-lite/mount_util.c
|
|
||||||
===================================================================
|
|
||||||
RCS file: /cvsroot/ntfs-3g/ntfs-3g/libfuse-lite/mount_util.c,v
|
|
||||||
retrieving revision 1.5
|
|
||||||
diff -u -p -r1.5 mount_util.c
|
|
||||||
--- libfuse-lite/mount_util.c 27 Jun 2008 12:37:02 -0000 1.5
|
|
||||||
+++ libfuse-lite/mount_util.c 30 Mar 2009 13:30:36 -0000
|
|
||||||
@@ -96,6 +96,7 @@ int fuse_mnt_add_mount(const char *progn
|
|
||||||
strerror(errno));
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
+/*
|
|
||||||
res = waitpid(res, &status, 0);
|
|
||||||
if (res == -1) {
|
|
||||||
fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
|
|
||||||
@@ -103,7 +104,7 @@ int fuse_mnt_add_mount(const char *progn
|
|
||||||
}
|
|
||||||
if (status != 0)
|
|
||||||
return -1;
|
|
||||||
-
|
|
||||||
+*/
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
|||||||
diff -up ntfs-3g_ntfsprogs-2014.2.15/src/ntfs-3g_common.c.ref ntfs-3g_ntfsprogs-2014.2.15/src/ntfs-3g_common.c
|
|
||||||
--- ntfs-3g_ntfsprogs-2014.2.15/src/ntfs-3g_common.c.ref 2015-01-13 14:31:55.648115825 -0500
|
|
||||||
+++ ntfs-3g_ntfsprogs-2014.2.15/src/ntfs-3g_common.c 2015-01-13 14:32:47.514838649 -0500
|
|
||||||
@@ -553,7 +553,7 @@ int ntfs_parse_options(struct ntfs_optio
|
|
||||||
{
|
|
||||||
int c;
|
|
||||||
|
|
||||||
- static const char *sopt = "-o:hnvV";
|
|
||||||
+ static const char *sopt = "-o:hnsvV";
|
|
||||||
static const struct option lopt[] = {
|
|
||||||
{ "options", required_argument, NULL, 'o' },
|
|
||||||
{ "help", no_argument, NULL, 'h' },
|
|
||||||
@@ -613,6 +613,11 @@ int ntfs_parse_options(struct ntfs_optio
|
|
||||||
* we don't use it because mount(8) passes it.
|
|
||||||
*/
|
|
||||||
break;
|
|
||||||
+ case 's':
|
|
||||||
+ /*
|
|
||||||
+ * no effect - automount passes it, meaning sloppy
|
|
||||||
+ */
|
|
||||||
+ break;
|
|
||||||
case 'V':
|
|
||||||
ntfs_log_info("%s %s %s %d\n", EXEC_NAME, VERSION,
|
|
||||||
FUSE_TYPE, fuse_version());
|
|
@ -1,28 +0,0 @@
|
|||||||
--- src/lowntfs-3g.c.ref 2013-04-04 09:47:16.000000000 +0200
|
|
||||||
+++ src/lowntfs-3g.c 2013-05-05 15:08:39.000000000 +0200
|
|
||||||
@@ -620,9 +620,9 @@
|
|
||||||
* Check whether it's Interix symbolic link, block or
|
|
||||||
* character device.
|
|
||||||
*/
|
|
||||||
- if ((size_t)na->data_size <= sizeof(INTX_FILE_TYPES)
|
|
||||||
+ if ((u64)na->data_size <= sizeof(INTX_FILE_TYPES)
|
|
||||||
+ sizeof(ntfschar) * PATH_MAX
|
|
||||||
- && (size_t)na->data_size >
|
|
||||||
+ && (u64)na->data_size >
|
|
||||||
sizeof(INTX_FILE_TYPES)) {
|
|
||||||
INTX_FILE *intx_file;
|
|
||||||
|
|
||||||
--- src/ntfs-3g.c.ref 2013-04-04 09:47:16.000000000 +0200
|
|
||||||
+++ src/ntfs-3g.c 2013-05-05 15:09:13.000000000 +0200
|
|
||||||
@@ -792,9 +792,9 @@
|
|
||||||
* Check whether it's Interix symbolic link, block or
|
|
||||||
* character device.
|
|
||||||
*/
|
|
||||||
- if ((size_t)na->data_size <= sizeof(INTX_FILE_TYPES)
|
|
||||||
+ if ((u64)na->data_size <= sizeof(INTX_FILE_TYPES)
|
|
||||||
+ sizeof(ntfschar) * PATH_MAX
|
|
||||||
- && (size_t)na->data_size >
|
|
||||||
+ && (u64)na->data_size >
|
|
||||||
sizeof(INTX_FILE_TYPES)
|
|
||||||
&& !stream_name_len) {
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
|||||||
--- ntfsprogs/ntfsck.c.old 2013-01-13 07:46:35.000000000 +0100
|
|
||||||
+++ ntfsprogs/ntfsck.c 2013-04-13 12:04:06.000000000 +0200
|
|
||||||
@@ -616,9 +616,9 @@
|
|
||||||
|
|
||||||
// Remove update seq & check it.
|
|
||||||
usa = *(u16*)(buffer+usa_ofs); // The value that should be at the end of every sector.
|
|
||||||
- assert_u32_equal(usa_count-1, buflen/bytes_per_sector, "USA length");
|
|
||||||
+ assert_u32_equal(usa_count-1, buflen/NTFS_BLOCK_SIZE, "USA length");
|
|
||||||
for (i=1;i<usa_count;i++) {
|
|
||||||
- u16 *fixup = (u16*)(buffer+bytes_per_sector*i-2); // the value at the end of the sector.
|
|
||||||
+ u16 *fixup = (u16*)(buffer+NTFS_BLOCK_SIZE*i-2); // the value at the end of the sector.
|
|
||||||
u16 saved_val = *(u16*)(buffer+usa_ofs+2*i); // the actual data value that was saved in the us array.
|
|
||||||
|
|
||||||
assert_u32_equal(*fixup, usa, "fixup");
|
|
Loading…
Reference in new issue