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.
This commit is contained in:
Jean-Pierre André 2020-03-07 10:31:12 +01:00
parent 3433dd0b3c
commit 32c27a8a4f
8 changed files with 35 additions and 10 deletions

View File

@ -432,6 +432,9 @@ struct fuse_operations {
* non-NULL cases, the area is of _IOC_SIZE(cmd) bytes. * non-NULL cases, the area is of _IOC_SIZE(cmd) bytes.
* *
* Introduced in version 2.8 * 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, int (*ioctl) (const char *, int cmd, void *arg,
struct fuse_file_info *, unsigned int flags, void *data); struct fuse_file_info *, unsigned int flags, void *data);

View File

@ -814,6 +814,9 @@ struct fuse_lowlevel_ops {
* *
* Introduced in version 2.8 * 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: * Valid replies:
* fuse_reply_ioctl_retry * fuse_reply_ioctl_retry
* fuse_reply_ioctl * fuse_reply_ioctl

View File

@ -111,7 +111,8 @@ struct ntfs_device_operations {
s64 offset); s64 offset);
int (*sync)(struct ntfs_device *dev); int (*sync)(struct ntfs_device *dev);
int (*stat)(struct ntfs_device *dev, struct stat *buf); 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, extern struct ntfs_device *ntfs_device_alloc(const char *name, const long state,

View File

@ -24,7 +24,12 @@
#ifndef IOCTL_H #ifndef IOCTL_H
#define IOCTL_H #define IOCTL_H
int ntfs_ioctl(ntfs_inode *ni, int cmd, void *arg, /*
* Using an "unsigned long cmd" internally, like in <sys/ioctl.h> 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); unsigned int flags, void *data);
#endif /* IOCTL_H */ #endif /* IOCTL_H */

View File

@ -369,8 +369,8 @@ static int ntfs_device_unix_io_stat(struct ntfs_device *dev, struct stat *buf)
* *
* Returns: * Returns:
*/ */
static int ntfs_device_unix_io_ioctl(struct ntfs_device *dev, int request, static int ntfs_device_unix_io_ioctl(struct ntfs_device *dev,
void *argp) unsigned long request, void *argp)
{ {
return ioctl(DEV_FD(dev), request, argp); return ioctl(DEV_FD(dev), request, argp);
} }

View File

@ -1847,14 +1847,14 @@ static __inline__ int ntfs_win32_blksszget(struct ntfs_device *dev,int *argp)
return -1; return -1;
} }
static int ntfs_device_win32_ioctl(struct ntfs_device *dev, int request, static int ntfs_device_win32_ioctl(struct ntfs_device *dev,
void *argp) unsigned long request, void *argp)
{ {
#if defined(BLKGETSIZE) | defined(BLKGETSIZE64) #if defined(BLKGETSIZE) | defined(BLKGETSIZE64)
win32_fd *fd = (win32_fd *)dev->d_private; win32_fd *fd = (win32_fd *)dev->d_private;
#endif #endif
ntfs_log_trace("win32_ioctl(%d) called.\n", request); ntfs_log_trace("win32_ioctl(0x%lx) called.\n", request);
switch (request) { switch (request) {
#if defined(BLKGETSIZE) #if defined(BLKGETSIZE)
case BLKGETSIZE: case BLKGETSIZE:
@ -1897,7 +1897,7 @@ static int ntfs_device_win32_ioctl(struct ntfs_device *dev, int request,
return 0; return 0;
#endif #endif
default: default:
ntfs_log_debug("unimplemented ioctl %d.\n", request); ntfs_log_debug("unimplemented ioctl 0x%lx.\n", request);
errno = EOPNOTSUPP; errno = EOPNOTSUPP;
return -1; return -1;
} }

View File

@ -3036,7 +3036,14 @@ static void ntfs_fuse_ioctl(fuse_req_t req __attribute__((unused)),
} }
memcpy(buf, data, in_bufsz); 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)) if (ntfs_inode_close (ni))
set_fuse_error(&ret); set_fuse_error(&ret);
} }

View File

@ -2777,7 +2777,13 @@ static int ntfs_fuse_ioctl(const char *path,
if (!ni) if (!ni)
return -errno; 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)) if (ntfs_inode_close (ni))
set_fuse_error(&ret); set_fuse_error(&ret);