From 32c27a8a4fda5205e579165baa716231efb6c1cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Sat, 7 Mar 2020 10:31:12 +0100 Subject: [PATCH] Defined the request argument of ioctl() as unsigned long On linux the request argument of ioctl() is defined as an unsigned long, but the fuse protocol squashes it into a signed int. As a consequence the value received by ntfs-3g may appear as negative and different from the value defined by the corresponding macro. So define the request argument as unsigned long in ntfs-3g. It has however to be fed as unsigned from fuse until the fuse protocol is updated. --- include/fuse-lite/fuse.h | 3 +++ include/fuse-lite/fuse_lowlevel.h | 3 +++ include/ntfs-3g/device.h | 3 ++- include/ntfs-3g/ioctl.h | 7 ++++++- libntfs-3g/unix_io.c | 4 ++-- libntfs-3g/win32_io.c | 8 ++++---- src/lowntfs-3g.c | 9 ++++++++- src/ntfs-3g.c | 8 +++++++- 8 files changed, 35 insertions(+), 10 deletions(-) diff --git a/include/fuse-lite/fuse.h b/include/fuse-lite/fuse.h index 2e3d53d8..b4ec2323 100644 --- a/include/fuse-lite/fuse.h +++ b/include/fuse-lite/fuse.h @@ -432,6 +432,9 @@ struct fuse_operations { * non-NULL cases, the area is of _IOC_SIZE(cmd) bytes. * * Introduced in version 2.8 + * + * Note : the unsigned long request submitted by the application + * is truncated to 32 bits, and forwarded as a signed int. */ int (*ioctl) (const char *, int cmd, void *arg, struct fuse_file_info *, unsigned int flags, void *data); diff --git a/include/fuse-lite/fuse_lowlevel.h b/include/fuse-lite/fuse_lowlevel.h index 8c84d965..3b10c35d 100644 --- a/include/fuse-lite/fuse_lowlevel.h +++ b/include/fuse-lite/fuse_lowlevel.h @@ -814,6 +814,9 @@ struct fuse_lowlevel_ops { * * Introduced in version 2.8 * + * Note : the unsigned long request submitted by the application + * is truncated to 32 bits, and forwarded as a signed int. + * * Valid replies: * fuse_reply_ioctl_retry * fuse_reply_ioctl diff --git a/include/ntfs-3g/device.h b/include/ntfs-3g/device.h index c7cc9b64..709cb4fa 100644 --- a/include/ntfs-3g/device.h +++ b/include/ntfs-3g/device.h @@ -111,7 +111,8 @@ struct ntfs_device_operations { s64 offset); int (*sync)(struct ntfs_device *dev); int (*stat)(struct ntfs_device *dev, struct stat *buf); - int (*ioctl)(struct ntfs_device *dev, int request, void *argp); + int (*ioctl)(struct ntfs_device *dev, unsigned long request, + void *argp); }; extern struct ntfs_device *ntfs_device_alloc(const char *name, const long state, diff --git a/include/ntfs-3g/ioctl.h b/include/ntfs-3g/ioctl.h index 4ed6c010..2b25c782 100644 --- a/include/ntfs-3g/ioctl.h +++ b/include/ntfs-3g/ioctl.h @@ -24,7 +24,12 @@ #ifndef IOCTL_H #define IOCTL_H -int ntfs_ioctl(ntfs_inode *ni, int cmd, void *arg, +/* + * Using an "unsigned long cmd" internally, like in for Linux + * Note however that fuse truncates the arg to 32 bits, and that + * some commands (e.g. FITRIM) do not fit in a signed 32 bit field. + */ +int ntfs_ioctl(ntfs_inode *ni, unsigned long cmd, void *arg, unsigned int flags, void *data); #endif /* IOCTL_H */ diff --git a/libntfs-3g/unix_io.c b/libntfs-3g/unix_io.c index 1103c7e3..5495a6a4 100644 --- a/libntfs-3g/unix_io.c +++ b/libntfs-3g/unix_io.c @@ -369,8 +369,8 @@ static int ntfs_device_unix_io_stat(struct ntfs_device *dev, struct stat *buf) * * Returns: */ -static int ntfs_device_unix_io_ioctl(struct ntfs_device *dev, int request, - void *argp) +static int ntfs_device_unix_io_ioctl(struct ntfs_device *dev, + unsigned long request, void *argp) { return ioctl(DEV_FD(dev), request, argp); } diff --git a/libntfs-3g/win32_io.c b/libntfs-3g/win32_io.c index e5cfb640..9c72dee3 100644 --- a/libntfs-3g/win32_io.c +++ b/libntfs-3g/win32_io.c @@ -1847,14 +1847,14 @@ static __inline__ int ntfs_win32_blksszget(struct ntfs_device *dev,int *argp) return -1; } -static int ntfs_device_win32_ioctl(struct ntfs_device *dev, int request, - void *argp) +static int ntfs_device_win32_ioctl(struct ntfs_device *dev, + unsigned long request, void *argp) { #if defined(BLKGETSIZE) | defined(BLKGETSIZE64) win32_fd *fd = (win32_fd *)dev->d_private; #endif - ntfs_log_trace("win32_ioctl(%d) called.\n", request); + ntfs_log_trace("win32_ioctl(0x%lx) called.\n", request); switch (request) { #if defined(BLKGETSIZE) case BLKGETSIZE: @@ -1897,7 +1897,7 @@ static int ntfs_device_win32_ioctl(struct ntfs_device *dev, int request, return 0; #endif default: - ntfs_log_debug("unimplemented ioctl %d.\n", request); + ntfs_log_debug("unimplemented ioctl 0x%lx.\n", request); errno = EOPNOTSUPP; return -1; } diff --git a/src/lowntfs-3g.c b/src/lowntfs-3g.c index 983ab010..7fa0b195 100644 --- a/src/lowntfs-3g.c +++ b/src/lowntfs-3g.c @@ -3036,7 +3036,14 @@ static void ntfs_fuse_ioctl(fuse_req_t req __attribute__((unused)), } memcpy(buf, data, in_bufsz); } - ret = ntfs_ioctl(ni, cmd, arg, flags, buf); + /* + * Linux defines the request argument of ioctl() to be an + * unsigned long, which fuse 2.x forwards as a signed int + * into which the request sometimes does not fit. + * So we must expand the value and make sure it is not + * sign-extended. + */ + ret = ntfs_ioctl(ni, (unsigned int)cmd, arg, flags, buf); if (ntfs_inode_close (ni)) set_fuse_error(&ret); } diff --git a/src/ntfs-3g.c b/src/ntfs-3g.c index 465f1525..5b3cfc8d 100644 --- a/src/ntfs-3g.c +++ b/src/ntfs-3g.c @@ -2777,7 +2777,13 @@ static int ntfs_fuse_ioctl(const char *path, if (!ni) return -errno; - ret = ntfs_ioctl(ni, cmd, arg, flags, data); + /* + * Linux defines the request argument of ioctl() to be an + * unsigned long, which fuse 2.x forwards as a signed int into + * which the request sometimes does not fit. + * So we must expand the value and make sure it is not sign-extended. + */ + ret = ntfs_ioctl(ni, (unsigned int)cmd, arg, flags, data); if (ntfs_inode_close (ni)) set_fuse_error(&ret);