diff options
Diffstat (limited to 'fuse_sideload.c')
-rw-r--r-- | fuse_sideload.c | 52 |
1 files changed, 38 insertions, 14 deletions
diff --git a/fuse_sideload.c b/fuse_sideload.c index f5f20ea47..3259c5fb4 100644 --- a/fuse_sideload.c +++ b/fuse_sideload.c @@ -53,6 +53,7 @@ #include <string.h> #include <sys/inotify.h> #include <sys/mount.h> +#include <sys/param.h> #include <sys/resource.h> #include <sys/stat.h> #include <sys/statfs.h> @@ -105,27 +106,52 @@ static void fuse_reply(struct fuse_data* fd, __u64 unique, const void *data, siz vec[0].iov_base = &hdr; vec[0].iov_len = sizeof(hdr); - vec[1].iov_base = data; + vec[1].iov_base = /* const_cast */(void*)(data); vec[1].iov_len = len; res = writev(fd->ffd, vec, 2); if (res < 0) { - printf("*** REPLY FAILED *** %d\n", errno); + printf("*** REPLY FAILED *** %s\n", strerror(errno)); } } static int handle_init(void* data, struct fuse_data* fd, const struct fuse_in_header* hdr) { const struct fuse_init_in* req = data; struct fuse_init_out out; + size_t fuse_struct_size; + + + /* Kernel 2.6.16 is the first stable kernel with struct fuse_init_out + * defined (fuse version 7.6). The structure is the same from 7.6 through + * 7.22. Beginning with 7.23, the structure increased in size and added + * new parameters. + */ + if (req->major != FUSE_KERNEL_VERSION || req->minor < 6) { + printf("Fuse kernel version mismatch: Kernel version %d.%d, Expected at least %d.6", + req->major, req->minor, FUSE_KERNEL_VERSION); + return -1; + } + + out.minor = MIN(req->minor, FUSE_KERNEL_MINOR_VERSION); + fuse_struct_size = sizeof(out); +#if defined(FUSE_COMPAT_22_INIT_OUT_SIZE) + /* FUSE_KERNEL_VERSION >= 23. */ + + /* If the kernel only works on minor revs older than or equal to 22, + * then use the older structure size since this code only uses the 7.22 + * version of the structure. */ + if (req->minor <= 22) { + fuse_struct_size = FUSE_COMPAT_22_INIT_OUT_SIZE; + } +#endif out.major = FUSE_KERNEL_VERSION; - out.minor = FUSE_KERNEL_MINOR_VERSION; out.max_readahead = req->max_readahead; out.flags = 0; out.max_background = 32; out.congestion_threshold = 32; out.max_write = 4096; - fuse_reply(fd, hdr->unique, &out, sizeof(out)); + fuse_reply(fd, hdr->unique, &out, fuse_struct_size); return NO_STATUS; } @@ -404,7 +430,7 @@ int run_fuse_sideload(struct provider_vtab* vtab, void* cookie, char opts[256]; snprintf(opts, sizeof(opts), - ("fd=%d,user_id=%d,group_id=%d,max_read=%zu," + ("fd=%d,user_id=%d,group_id=%d,max_read=%u," "allow_other,rootmode=040000"), fd.ffd, fd.uid, fd.gid, block_size); @@ -416,14 +442,12 @@ int run_fuse_sideload(struct provider_vtab* vtab, void* cookie, } uint8_t request_buffer[sizeof(struct fuse_in_header) + PATH_MAX*8]; for (;;) { - ssize_t len = read(fd.ffd, request_buffer, sizeof(request_buffer)); - if (len < 0) { - if (errno != EINTR) { - perror("read request"); - if (errno == ENODEV) { - result = -1; - break; - } + ssize_t len = TEMP_FAILURE_RETRY(read(fd.ffd, request_buffer, sizeof(request_buffer))); + if (len == -1) { + perror("read request"); + if (errno == ENODEV) { + result = -1; + break; } continue; } @@ -482,7 +506,7 @@ int run_fuse_sideload(struct provider_vtab* vtab, void* cookie, outhdr.len = sizeof(outhdr); outhdr.error = result; outhdr.unique = hdr->unique; - write(fd.ffd, &outhdr, sizeof(outhdr)); + TEMP_FAILURE_RETRY(write(fd.ffd, &outhdr, sizeof(outhdr))); } } |