|
|
@ -8,6 +8,7 @@ |
|
|
|
|
|
|
|
#define _GNU_SOURCE |
|
|
|
|
|
|
|
#include "ansi.h" |
|
|
|
#include "config.h" |
|
|
|
#include "fuse_i.h" |
|
|
|
#include "fuse_kernel.h" |
|
|
@ -199,18 +200,15 @@ fuse_send_msg(struct fuse_ll *f, |
|
|
|
fprintf(stderr, "NOTIFY: code=%d length=%u\n", |
|
|
|
out->error, out->len); |
|
|
|
} |
|
|
|
else if (out->error) |
|
|
|
{ |
|
|
|
fprintf(stderr, |
|
|
|
" unique: %llu, error: %i (%s), outsize: %i\n", |
|
|
|
(unsigned long long) out->unique, out->error, |
|
|
|
strerror(-out->error), out->len); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
fprintf(stderr, |
|
|
|
" unique: %llu, success, outsize: %i\n", |
|
|
|
(unsigned long long) out->unique, out->len); |
|
|
|
ANSI_RED"response:"ANSI_RESET |
|
|
|
" unique: %zu; error: %d (%s); len: %d;\n", |
|
|
|
out->unique, |
|
|
|
out->error, |
|
|
|
strerror(-out->error), |
|
|
|
out->len); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -225,7 +223,7 @@ fuse_send_reply_iov_nofree(fuse_req_t req, |
|
|
|
{ |
|
|
|
struct fuse_out_header out; |
|
|
|
|
|
|
|
if (error <= -1000 || error > 0) |
|
|
|
if((error <= -1000) || (error > 0)) |
|
|
|
{ |
|
|
|
fprintf(stderr,"fuse: bad error value: %i\n",error); |
|
|
|
error = -ERANGE; |
|
|
@ -410,6 +408,13 @@ fill_open(struct fuse_open_out *arg, |
|
|
|
arg->open_flags |= FOPEN_CACHE_DIR; |
|
|
|
} |
|
|
|
|
|
|
|
static |
|
|
|
void |
|
|
|
debug_fuse_entry_out(const struct fuse_entry_out *arg_) |
|
|
|
{ |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
int |
|
|
|
fuse_reply_entry(fuse_req_t req, |
|
|
|
const struct fuse_entry_param *e) |
|
|
@ -426,6 +431,9 @@ fuse_reply_entry(fuse_req_t req, |
|
|
|
memset(&arg, 0, sizeof(arg)); |
|
|
|
fill_entry(&arg, e); |
|
|
|
|
|
|
|
if(req->f->debug) |
|
|
|
debug_fuse_entry_out(&arg); |
|
|
|
|
|
|
|
return send_reply_ok(req, &arg, size); |
|
|
|
} |
|
|
|
|
|
|
@ -447,6 +455,49 @@ fuse_reply_create(fuse_req_t req, |
|
|
|
return send_reply_ok(req, buf, entrysize + sizeof(struct fuse_open_out)); |
|
|
|
} |
|
|
|
|
|
|
|
static |
|
|
|
void |
|
|
|
debug_fuse_attr_out(const struct fuse_attr_out *arg_) |
|
|
|
{ |
|
|
|
fprintf(stderr, |
|
|
|
ANSI_YELLOW"fuse_attr_out:"ANSI_RESET |
|
|
|
" attr_valid=%zu;" |
|
|
|
" attr_valid_nsec=%u;" |
|
|
|
" ino=%zu;" |
|
|
|
" size=%zu;" |
|
|
|
" blocks=%zu;" |
|
|
|
" atime=%zu;" |
|
|
|
" mtime=%zu;" |
|
|
|
" ctime=%zu;" |
|
|
|
" atimensec=%u;" |
|
|
|
" mtimensec=%u;" |
|
|
|
" ctimensec=%u;" |
|
|
|
" mode=%o;" |
|
|
|
" nlink=%u;" |
|
|
|
" uid=%u;" |
|
|
|
" gid=%u;" |
|
|
|
" rdev=%u;" |
|
|
|
" blksize=%u;" |
|
|
|
"\n", |
|
|
|
arg_->attr_valid, |
|
|
|
arg_->attr_valid_nsec, |
|
|
|
arg_->attr.ino, |
|
|
|
arg_->attr.size, |
|
|
|
arg_->attr.blocks, |
|
|
|
arg_->attr.atime, |
|
|
|
arg_->attr.mtime, |
|
|
|
arg_->attr.ctime, |
|
|
|
arg_->attr.atimensec, |
|
|
|
arg_->attr.mtimensec, |
|
|
|
arg_->attr.ctimensec, |
|
|
|
arg_->attr.mode, |
|
|
|
arg_->attr.nlink, |
|
|
|
arg_->attr.uid, |
|
|
|
arg_->attr.gid, |
|
|
|
arg_->attr.rdev, |
|
|
|
arg_->attr.blksize); |
|
|
|
} |
|
|
|
|
|
|
|
int |
|
|
|
fuse_reply_attr(fuse_req_t req, |
|
|
|
const struct stat *attr, |
|
|
@ -461,6 +512,9 @@ fuse_reply_attr(fuse_req_t req, |
|
|
|
arg.attr_valid_nsec = 0; |
|
|
|
convert_stat(attr,&arg.attr); |
|
|
|
|
|
|
|
if(req->f->debug) |
|
|
|
debug_fuse_attr_out(&arg); |
|
|
|
|
|
|
|
return send_reply_ok(req,&arg,size); |
|
|
|
} |
|
|
|
|
|
|
@ -1212,16 +1266,32 @@ do_batch_forget(fuse_req_t req, |
|
|
|
|
|
|
|
static |
|
|
|
void |
|
|
|
do_getattr(fuse_req_t req, |
|
|
|
fuse_ino_t nodeid, |
|
|
|
const void *inarg) |
|
|
|
debug_fuse_getattr_in(const struct fuse_getattr_in* arg_) |
|
|
|
{ |
|
|
|
fprintf(stderr, |
|
|
|
ANSI_YELLOW"fuse_getattr_in:"ANSI_RESET |
|
|
|
" getattr_flags: 0x%08X;" |
|
|
|
" fh: %zu;\n", |
|
|
|
arg_->getattr_flags, |
|
|
|
arg_->fh); |
|
|
|
} |
|
|
|
|
|
|
|
static |
|
|
|
void |
|
|
|
do_getattr(fuse_req_t req_, |
|
|
|
fuse_ino_t nodeid_, |
|
|
|
const void *inarg_) |
|
|
|
{ |
|
|
|
fuse_file_info_t *fip = NULL; |
|
|
|
fuse_file_info_t fi; |
|
|
|
fuse_file_info_t *fip; |
|
|
|
|
|
|
|
if (req->f->conn.proto_minor >= 9) |
|
|
|
fip = NULL; |
|
|
|
if(req_->f->conn.proto_minor >= 9) |
|
|
|
{ |
|
|
|
struct fuse_getattr_in *arg = (struct fuse_getattr_in *) inarg; |
|
|
|
struct fuse_getattr_in *arg = (struct fuse_getattr_in*)inarg_; |
|
|
|
|
|
|
|
if(req_->f->debug) |
|
|
|
debug_fuse_getattr_in(arg); |
|
|
|
|
|
|
|
if(arg->getattr_flags & FUSE_GETATTR_FH) |
|
|
|
{ |
|
|
@ -1231,10 +1301,10 @@ do_getattr(fuse_req_t req, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (req->f->op.getattr) |
|
|
|
req->f->op.getattr(req, nodeid, fip); |
|
|
|
if(req_->f->op.getattr) |
|
|
|
req_->f->op.getattr(req_,nodeid_,fip); |
|
|
|
else |
|
|
|
fuse_reply_err(req, ENOSYS); |
|
|
|
fuse_reply_err(req_,ENOSYS); |
|
|
|
} |
|
|
|
|
|
|
|
static |
|
|
@ -2134,6 +2204,133 @@ do_fallocate(fuse_req_t req, |
|
|
|
fuse_reply_err(req, ENOSYS); |
|
|
|
} |
|
|
|
|
|
|
|
static |
|
|
|
int |
|
|
|
is_compatible_protocol(const struct fuse_init_in *arg_) |
|
|
|
{ |
|
|
|
if(arg_->major != 7) |
|
|
|
return 0; |
|
|
|
if(arg_->minor < 13) |
|
|
|
return 0; |
|
|
|
|
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
#define FLAG_CASE(X) case FUSE_##X: return #X |
|
|
|
|
|
|
|
static |
|
|
|
const |
|
|
|
char* |
|
|
|
flag_to_str(const uint32_t offset_) |
|
|
|
{ |
|
|
|
switch(1 << offset_) |
|
|
|
{ |
|
|
|
FLAG_CASE(ASYNC_READ); |
|
|
|
FLAG_CASE(POSIX_LOCKS); |
|
|
|
FLAG_CASE(FILE_OPS); |
|
|
|
FLAG_CASE(ATOMIC_O_TRUNC); |
|
|
|
FLAG_CASE(EXPORT_SUPPORT); |
|
|
|
FLAG_CASE(BIG_WRITES); |
|
|
|
FLAG_CASE(DONT_MASK); |
|
|
|
FLAG_CASE(SPLICE_WRITE); |
|
|
|
FLAG_CASE(SPLICE_MOVE); |
|
|
|
FLAG_CASE(SPLICE_READ); |
|
|
|
FLAG_CASE(FLOCK_LOCKS); |
|
|
|
FLAG_CASE(HAS_IOCTL_DIR); |
|
|
|
FLAG_CASE(AUTO_INVAL_DATA); |
|
|
|
FLAG_CASE(DO_READDIRPLUS); |
|
|
|
FLAG_CASE(READDIRPLUS_AUTO); |
|
|
|
FLAG_CASE(ASYNC_DIO); |
|
|
|
FLAG_CASE(WRITEBACK_CACHE); |
|
|
|
FLAG_CASE(NO_OPEN_SUPPORT); |
|
|
|
FLAG_CASE(PARALLEL_DIROPS); |
|
|
|
FLAG_CASE(HANDLE_KILLPRIV); |
|
|
|
FLAG_CASE(POSIX_ACL); |
|
|
|
FLAG_CASE(ABORT_ERROR); |
|
|
|
FLAG_CASE(MAX_PAGES); |
|
|
|
FLAG_CASE(CACHE_SYMLINKS); |
|
|
|
FLAG_CASE(NO_OPENDIR_SUPPORT); |
|
|
|
FLAG_CASE(EXPLICIT_INVAL_DATA); |
|
|
|
FLAG_CASE(MAP_ALIGNMENT); |
|
|
|
} |
|
|
|
|
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
#undef FLAG_CASE |
|
|
|
|
|
|
|
static |
|
|
|
void |
|
|
|
debug_fuse_init_in(const struct fuse_init_in *arg_) |
|
|
|
{ |
|
|
|
fprintf(stderr, |
|
|
|
ANSI_YELLOW"fuse_init_in:"ANSI_RESET |
|
|
|
" major=%u;" |
|
|
|
" minor=%u;" |
|
|
|
" max_readahead=%u;" |
|
|
|
" flags=0x%08X (", |
|
|
|
arg_->major, |
|
|
|
arg_->minor, |
|
|
|
arg_->max_readahead, |
|
|
|
arg_->flags); |
|
|
|
for(int i = 0; i < (sizeof(arg_->flags)*8); i++) |
|
|
|
{ |
|
|
|
const char *str; |
|
|
|
|
|
|
|
if(!(arg_->flags & (1 << i))) |
|
|
|
continue; |
|
|
|
|
|
|
|
str = flag_to_str(i); |
|
|
|
if(str == NULL) |
|
|
|
break; |
|
|
|
|
|
|
|
fprintf(stderr,"%s,",str); |
|
|
|
} |
|
|
|
fprintf(stderr,")\n"); |
|
|
|
} |
|
|
|
|
|
|
|
static |
|
|
|
void |
|
|
|
debug_fuse_init_out(const struct fuse_init_out *arg_) |
|
|
|
{ |
|
|
|
fprintf(stderr, |
|
|
|
ANSI_YELLOW"fuse_init_out:"ANSI_RESET |
|
|
|
" major=%u;" |
|
|
|
" minor=%u;" |
|
|
|
" max_readahead=%u;" |
|
|
|
" max_background=%u;" |
|
|
|
" congestion_threshold=%u;" |
|
|
|
" max_write=%u;" |
|
|
|
" time_gran=%u;" |
|
|
|
" max_pages=%u;" |
|
|
|
" map_alignment=%u;" |
|
|
|
" flags=0x%08X (", |
|
|
|
arg_->major, |
|
|
|
arg_->minor, |
|
|
|
arg_->max_readahead, |
|
|
|
arg_->max_background, |
|
|
|
arg_->congestion_threshold, |
|
|
|
arg_->max_write, |
|
|
|
arg_->time_gran, |
|
|
|
arg_->max_pages, |
|
|
|
arg_->map_alignment, |
|
|
|
arg_->flags); |
|
|
|
for(int i = 0; i < (sizeof(arg_->flags)*8); i++) |
|
|
|
{ |
|
|
|
const char *str; |
|
|
|
|
|
|
|
if(!(arg_->flags & (1 << i))) |
|
|
|
continue; |
|
|
|
|
|
|
|
str = flag_to_str(i); |
|
|
|
if(str == NULL) |
|
|
|
break; |
|
|
|
|
|
|
|
fprintf(stderr,"%s,",str); |
|
|
|
} |
|
|
|
fprintf(stderr,")\n"); |
|
|
|
} |
|
|
|
|
|
|
|
static |
|
|
|
void |
|
|
|
do_init(fuse_req_t req, |
|
|
@ -2145,18 +2342,19 @@ do_init(fuse_req_t req, |
|
|
|
struct fuse_ll *f = req->f; |
|
|
|
size_t bufsize = fuse_chan_bufsize(req->ch); |
|
|
|
|
|
|
|
(void) nodeid; |
|
|
|
if (f->debug) |
|
|
|
if(!is_compatible_protocol(arg)) |
|
|
|
{ |
|
|
|
fprintf(stderr, "INIT: %u.%u\n", arg->major, arg->minor); |
|
|
|
if (arg->major == 7 && arg->minor >= 6) |
|
|
|
{ |
|
|
|
fprintf(stderr, "flags=0x%08x\n", arg->flags); |
|
|
|
fprintf(stderr, "max_readahead=0x%08x\n", |
|
|
|
arg->max_readahead); |
|
|
|
} |
|
|
|
fprintf(stderr, |
|
|
|
"fuse: unsupported protocol version - %u.%u\n", |
|
|
|
arg->major, |
|
|
|
arg->minor); |
|
|
|
fuse_reply_err(req,EPROTO); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if(f->debug) |
|
|
|
debug_fuse_init_in(arg); |
|
|
|
|
|
|
|
f->conn.proto_major = arg->major; |
|
|
|
f->conn.proto_minor = arg->minor; |
|
|
|
f->conn.capable = 0; |
|
|
@ -2168,14 +2366,6 @@ do_init(fuse_req_t req, |
|
|
|
outarg.minor = FUSE_KERNEL_MINOR_VERSION; |
|
|
|
outarg.max_pages = FUSE_DEFAULT_MAX_PAGES_PER_REQ; |
|
|
|
|
|
|
|
if (arg->major < 7) |
|
|
|
{ |
|
|
|
fprintf(stderr, "fuse: unsupported protocol version: %u.%u\n", |
|
|
|
arg->major, arg->minor); |
|
|
|
fuse_reply_err(req, EPROTO); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if(arg->major > 7) |
|
|
|
{ |
|
|
|
/* Wait for a second INIT request with a 7.X version */ |
|
|
@ -2183,8 +2373,6 @@ do_init(fuse_req_t req, |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (arg->minor >= 6) |
|
|
|
{ |
|
|
|
if(arg->max_readahead < f->conn.max_readahead) |
|
|
|
f->conn.max_readahead = arg->max_readahead; |
|
|
|
if(arg->flags & FUSE_ASYNC_READ) |
|
|
@ -2217,12 +2405,6 @@ do_init(fuse_req_t req, |
|
|
|
f->conn.capable |= FUSE_CAP_READDIR_PLUS; |
|
|
|
if(arg->flags & FUSE_READDIRPLUS_AUTO) |
|
|
|
f->conn.capable |= FUSE_CAP_READDIR_PLUS_AUTO; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
f->conn.want &= ~FUSE_CAP_ASYNC_READ; |
|
|
|
f->conn.max_readahead = 0; |
|
|
|
} |
|
|
|
|
|
|
|
if(req->f->conn.proto_minor >= 14) |
|
|
|
{ |
|
|
@ -2314,27 +2496,14 @@ do_init(fuse_req_t req, |
|
|
|
if(f->conn.congestion_threshold > f->conn.max_background) |
|
|
|
f->conn.congestion_threshold = f->conn.max_background; |
|
|
|
if(!f->conn.congestion_threshold) |
|
|
|
{ |
|
|
|
f->conn.congestion_threshold = f->conn.max_background * 3 / 4; |
|
|
|
} |
|
|
|
|
|
|
|
outarg.max_background = f->conn.max_background; |
|
|
|
outarg.congestion_threshold = f->conn.congestion_threshold; |
|
|
|
} |
|
|
|
|
|
|
|
if(f->debug) |
|
|
|
{ |
|
|
|
fprintf(stderr, " INIT: %u.%u\n", outarg.major, outarg.minor); |
|
|
|
fprintf(stderr, " flags=0x%08x\n", outarg.flags); |
|
|
|
fprintf(stderr, " max_readahead=0x%08x\n", |
|
|
|
outarg.max_readahead); |
|
|
|
fprintf(stderr, " max_write=0x%08x\n", outarg.max_write); |
|
|
|
fprintf(stderr, " max_background=%i\n", |
|
|
|
outarg.max_background); |
|
|
|
fprintf(stderr, " congestion_threshold=%i\n", |
|
|
|
outarg.congestion_threshold); |
|
|
|
fprintf(stderr, " max_pages=%d\n",outarg.max_pages); |
|
|
|
} |
|
|
|
debug_fuse_init_out(&outarg); |
|
|
|
|
|
|
|
size_t outargsize; |
|
|
|
if(arg->minor < 5) |
|
|
@ -2408,6 +2577,7 @@ do_notify_reply(fuse_req_t req, |
|
|
|
|
|
|
|
pthread_mutex_lock(&f->lock); |
|
|
|
head = &f->notify_list; |
|
|
|
|
|
|
|
for(nreq = head->next; nreq != head; nreq = nreq->next) |
|
|
|
{ |
|
|
|
if (nreq->unique == req->unique) |
|
|
@ -2474,6 +2644,7 @@ send_notify_iov(struct fuse_ll *f, |
|
|
|
int |
|
|
|
fuse_lowlevel_notify_poll(fuse_pollhandle_t *ph) |
|
|
|
{ |
|
|
|
|
|
|
|
if(ph != NULL) |
|
|
|
{ |
|
|
|
struct fuse_notify_poll_wakeup_out outarg; |
|
|
@ -2773,7 +2944,8 @@ fuse_req_interrupted(fuse_req_t req) |
|
|
|
return interrupted; |
|
|
|
} |
|
|
|
|
|
|
|
static struct { |
|
|
|
static struct |
|
|
|
{ |
|
|
|
void (*func)(fuse_req_t, fuse_ino_t, const void *); |
|
|
|
const char *name; |
|
|
|
} fuse_ll_ops[] = |
|
|
@ -2856,6 +3028,22 @@ fuse_ll_copy_from_pipe(struct fuse_bufvec *dst, |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static |
|
|
|
void |
|
|
|
debug_fuse_in_header(const struct fuse_in_header *hdr_) |
|
|
|
{ |
|
|
|
fprintf(stderr, |
|
|
|
ANSI_GREEN"opcode:"ANSI_RESET |
|
|
|
" %s (%u); unique: %zu; nodeid: %zu; uid: %u; gid: %u; pid: %u\n", |
|
|
|
opname(hdr_->opcode), |
|
|
|
hdr_->opcode, |
|
|
|
hdr_->unique, |
|
|
|
hdr_->nodeid, |
|
|
|
hdr_->uid, |
|
|
|
hdr_->gid, |
|
|
|
hdr_->pid); |
|
|
|
} |
|
|
|
|
|
|
|
static |
|
|
|
void |
|
|
|
fuse_ll_process_buf(void *data, |
|
|
@ -2899,22 +3087,18 @@ fuse_ll_process_buf(void *data, |
|
|
|
} |
|
|
|
|
|
|
|
if(f->debug) |
|
|
|
{ |
|
|
|
fprintf(stderr, |
|
|
|
"unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %zu, pid: %u\n", |
|
|
|
(unsigned long long) in->unique, |
|
|
|
opname((enum fuse_opcode) in->opcode), in->opcode, |
|
|
|
(unsigned long) in->nodeid, buf->size, in->pid); |
|
|
|
} |
|
|
|
debug_fuse_in_header(in); |
|
|
|
|
|
|
|
req = fuse_ll_alloc_req(f); |
|
|
|
if(req == NULL) |
|
|
|
{ |
|
|
|
struct fuse_out_header out = { |
|
|
|
struct fuse_out_header out = |
|
|
|
{ |
|
|
|
.unique = in->unique, |
|
|
|
.error = -ENOMEM, |
|
|
|
}; |
|
|
|
struct iovec iov = { |
|
|
|
struct iovec iov = |
|
|
|
{ |
|
|
|
.iov_base = &out, |
|
|
|
.iov_len = sizeof(struct fuse_out_header), |
|
|
|
}; |
|
|
@ -2962,7 +3146,8 @@ fuse_ll_process_buf(void *data, |
|
|
|
err = ENOSYS; |
|
|
|
if(in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func) |
|
|
|
goto reply_err; |
|
|
|
if (in->opcode != FUSE_INTERRUPT) { |
|
|
|
if(in->opcode != FUSE_INTERRUPT) |
|
|
|
{ |
|
|
|
struct fuse_req *intr; |
|
|
|
pthread_mutex_lock(&f->lock); |
|
|
|
intr = check_interrupt(f, req); |
|
|
@ -3300,6 +3485,7 @@ fuse_lowlevel_new_common(struct fuse_args *args, |
|
|
|
.destroy = fuse_ll_destroy, |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
if(sizeof(struct fuse_lowlevel_ops) < op_size) |
|
|
|
{ |
|
|
|
fprintf(stderr, "fuse: warning: library too old, some operations may not work\n"); |
|
|
@ -3332,9 +3518,6 @@ fuse_lowlevel_new_common(struct fuse_args *args, |
|
|
|
if(fuse_opt_parse(args, f, fuse_ll_opts, fuse_ll_opt_proc) == -1) |
|
|
|
goto out_key_destroy; |
|
|
|
|
|
|
|
if (f->debug) |
|
|
|
fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION); |
|
|
|
|
|
|
|
memcpy(&f->op, op, op_size); |
|
|
|
f->owner = getuid(); |
|
|
|
f->userdata = userdata; |
|
|
|