|
@ -16,6 +16,7 @@ |
|
|
|
|
|
|
|
|
#include "config.hpp"
|
|
|
#include "config.hpp"
|
|
|
#include "dirinfo.hpp"
|
|
|
#include "dirinfo.hpp"
|
|
|
|
|
|
#include "endian.hpp"
|
|
|
#include "errno.hpp"
|
|
|
#include "errno.hpp"
|
|
|
#include "fileinfo.hpp"
|
|
|
#include "fileinfo.hpp"
|
|
|
#include "fs_base_close.hpp"
|
|
|
#include "fs_base_close.hpp"
|
|
@ -35,17 +36,67 @@ |
|
|
using std::string; |
|
|
using std::string; |
|
|
using std::vector; |
|
|
using std::vector; |
|
|
|
|
|
|
|
|
|
|
|
#ifndef FS_IOC_GETFLAGS
|
|
|
|
|
|
# define FS_IOC_GETFLAGS _IOR('f',1,long)
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef FS_IOC_SETFLAGS
|
|
|
|
|
|
# define FS_IOC_SETFLAGS _IOW('f',2,long)
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef FS_IOC_GETVERSION
|
|
|
|
|
|
# define FS_IOC_GETVERSION _IOR('v',1,long)
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef FS_IOC_SETVERSION
|
|
|
|
|
|
# define FS_IOC_SETVERSION _IOW('v',2,long)
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
There is a bug with FUSE and these ioctl commands. The regular |
|
|
|
|
|
libfuse high level API assumes the output buffer size based on the |
|
|
|
|
|
command and gives no control over this. FS_IOC_GETFLAGS and |
|
|
|
|
|
FS_IOC_SETFLAGS however are defined as `long` when in fact it is an |
|
|
|
|
|
`int`. On 64bit systems where long is 8 bytes this can lead to |
|
|
|
|
|
libfuse telling the kernel to write 8 bytes and if the user only |
|
|
|
|
|
allocated an integer then it will overwrite the 4 bytes after the |
|
|
|
|
|
variable which could result in data corruption and/or crashes. |
|
|
|
|
|
|
|
|
|
|
|
I've modified the API to allow changing of the output buffer |
|
|
|
|
|
size. This fixes the issue on little endian systems because the |
|
|
|
|
|
lower 4 bytes are the same regardless of what the user |
|
|
|
|
|
allocated. However, on big endian systems thats not the case and it |
|
|
|
|
|
is not possible to safely handle the situation. |
|
|
|
|
|
|
|
|
|
|
|
https://lwn.net/Articles/575846/
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
namespace l |
|
|
namespace l |
|
|
{ |
|
|
{ |
|
|
static |
|
|
static |
|
|
int |
|
|
int |
|
|
ioctl(const int fd_, |
|
|
ioctl(const int fd_, |
|
|
const unsigned long cmd_, |
|
|
|
|
|
void *data_) |
|
|
|
|
|
|
|
|
const int cmd_, |
|
|
|
|
|
void *data_, |
|
|
|
|
|
uint32_t *out_bufsz_) |
|
|
{ |
|
|
{ |
|
|
int rv; |
|
|
int rv; |
|
|
|
|
|
|
|
|
rv = fs::ioctl(fd_,cmd_,data_); |
|
|
|
|
|
|
|
|
switch(cmd_) |
|
|
|
|
|
{ |
|
|
|
|
|
case FS_IOC_GETFLAGS: |
|
|
|
|
|
case FS_IOC_SETFLAGS: |
|
|
|
|
|
case FS_IOC_GETVERSION: |
|
|
|
|
|
case FS_IOC_SETVERSION: |
|
|
|
|
|
if(endian::is_big() && (sizeof(long) != sizeof(int))) |
|
|
|
|
|
return -ENOTTY; |
|
|
|
|
|
*out_bufsz_ = 4; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
rv = ((_IOC_DIR(cmd_) == _IOC_NONE) ? |
|
|
|
|
|
fs::ioctl(fd_,cmd_) : |
|
|
|
|
|
fs::ioctl(fd_,cmd_,data_)); |
|
|
|
|
|
|
|
|
return ((rv == -1) ? -errno : rv); |
|
|
return ((rv == -1) ? -errno : rv); |
|
|
} |
|
|
} |
|
@ -53,12 +104,13 @@ namespace l |
|
|
static |
|
|
static |
|
|
int |
|
|
int |
|
|
ioctl_file(fuse_file_info *ffi_, |
|
|
ioctl_file(fuse_file_info *ffi_, |
|
|
const unsigned long cmd_, |
|
|
|
|
|
void *data_) |
|
|
|
|
|
|
|
|
const int cmd_, |
|
|
|
|
|
void *data_, |
|
|
|
|
|
uint32_t *out_bufsz_) |
|
|
{ |
|
|
{ |
|
|
FileInfo *fi = reinterpret_cast<FileInfo*>(ffi_->fh); |
|
|
FileInfo *fi = reinterpret_cast<FileInfo*>(ffi_->fh); |
|
|
|
|
|
|
|
|
return l::ioctl(fi->fd,cmd_,data_); |
|
|
|
|
|
|
|
|
return l::ioctl(fi->fd,cmd_,data_,out_bufsz_); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -72,8 +124,9 @@ namespace l |
|
|
const Branches &branches_, |
|
|
const Branches &branches_, |
|
|
const uint64_t minfreespace_, |
|
|
const uint64_t minfreespace_, |
|
|
const char *fusepath_, |
|
|
const char *fusepath_, |
|
|
const unsigned long cmd_, |
|
|
|
|
|
void *data_) |
|
|
|
|
|
|
|
|
const int cmd_, |
|
|
|
|
|
void *data_, |
|
|
|
|
|
uint32_t *out_bufsz_) |
|
|
{ |
|
|
{ |
|
|
int fd; |
|
|
int fd; |
|
|
int rv; |
|
|
int rv; |
|
@ -91,7 +144,7 @@ namespace l |
|
|
if(fd == -1) |
|
|
if(fd == -1) |
|
|
return -errno; |
|
|
return -errno; |
|
|
|
|
|
|
|
|
rv = l::ioctl(fd,cmd_,data_); |
|
|
|
|
|
|
|
|
rv = l::ioctl(fd,cmd_,data_,out_bufsz_); |
|
|
|
|
|
|
|
|
fs::close(fd); |
|
|
fs::close(fd); |
|
|
|
|
|
|
|
@ -101,8 +154,9 @@ namespace l |
|
|
static |
|
|
static |
|
|
int |
|
|
int |
|
|
ioctl_dir(fuse_file_info *ffi_, |
|
|
ioctl_dir(fuse_file_info *ffi_, |
|
|
const unsigned long cmd_, |
|
|
|
|
|
void *data_) |
|
|
|
|
|
|
|
|
const int cmd_, |
|
|
|
|
|
void *data_, |
|
|
|
|
|
uint32_t *out_bufsz_) |
|
|
{ |
|
|
{ |
|
|
DirInfo *di = reinterpret_cast<DirInfo*>(ffi_->fh); |
|
|
DirInfo *di = reinterpret_cast<DirInfo*>(ffi_->fh); |
|
|
const fuse_context *fc = fuse_get_context(); |
|
|
const fuse_context *fc = fuse_get_context(); |
|
@ -115,7 +169,8 @@ namespace l |
|
|
config.minfreespace, |
|
|
config.minfreespace, |
|
|
di->fusepath.c_str(), |
|
|
di->fusepath.c_str(), |
|
|
cmd_, |
|
|
cmd_, |
|
|
data_); |
|
|
|
|
|
|
|
|
data_, |
|
|
|
|
|
out_bufsz_); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -127,12 +182,12 @@ namespace FUSE |
|
|
void *arg_, |
|
|
void *arg_, |
|
|
fuse_file_info *ffi_, |
|
|
fuse_file_info *ffi_, |
|
|
unsigned int flags_, |
|
|
unsigned int flags_, |
|
|
void *data_) |
|
|
|
|
|
|
|
|
void *data_, |
|
|
|
|
|
uint32_t *out_bufsz_) |
|
|
{ |
|
|
{ |
|
|
if(flags_ & FUSE_IOCTL_DIR) |
|
|
if(flags_ & FUSE_IOCTL_DIR) |
|
|
return l::ioctl_dir(ffi_,cmd_,data_); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return l::ioctl_dir(ffi_,cmd_,data_,out_bufsz_); |
|
|
|
|
|
|
|
|
return l::ioctl_file(ffi_,cmd_,data_); |
|
|
|
|
|
|
|
|
return l::ioctl_file(ffi_,cmd_,data_,out_bufsz_); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |