abort();
}
-static void hash_name(struct fuse *f, struct node *node, fino_t parent,
- const char *name)
+static int hash_name(struct fuse *f, struct node *node, fino_t parent,
+ const char *name)
{
size_t hash = name_hash(f, parent, name);
node->parent = parent;
node->name = strdup(name);
+ if (node->name == NULL)
+ return -1;
+
node->name_next = f->name_table[hash];
- f->name_table[hash] = node;
+ f->name_table[hash] = node;
+ return 0;
}
static void unhash_name(struct fuse *f, struct node *node)
}
node = (struct node *) calloc(1, sizeof(struct node));
+ if (node == NULL)
+ return NULL;
+
node->mode = mode;
node->rdev = rdev;
node->open_count = 0;
node->is_hidden = 0;
node->ino = next_ino(f);
node->generation = f->generation;
+ if (hash_name(f, node, parent, name) == -1) {
+ free(node);
+ return NULL;
+ }
hash_ino(f, node);
- hash_name(f, node, parent, name);
out:
node->version = version;
if (newnode != NULL) {
if (hide) {
fprintf(stderr, "fuse: hidden file got created during hiding\n");
- err = -1;
+ err = -EBUSY;
goto out;
}
unhash_name(f, newnode);
}
unhash_name(f, node);
- hash_name(f, node, newdir, newname);
+ if (hash_name(f, node, newdir, newname) == -1) {
+ err = -ENOMEM;
+ goto out;
+ }
+
if (hide)
node->is_hidden = 1;
outsize = sizeof(struct fuse_out_header) + argsize;
outbuf = (char *) malloc(outsize);
- out = (struct fuse_out_header *) outbuf;
- memset(out, 0, sizeof(struct fuse_out_header));
- out->unique = in->unique;
- out->error = error;
- if (argsize != 0)
- memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
-
- res = send_reply_raw(f, outbuf, outsize, locked);
- free(outbuf);
+ if (outbuf == NULL) {
+ fprintf(stderr, "fuse: failed to allocate reply buffer\n");
+ res = -ENOMEM;
+ } else {
+ out = (struct fuse_out_header *) outbuf;
+ memset(out, 0, sizeof(struct fuse_out_header));
+ out->unique = in->unique;
+ out->error = error;
+ if (argsize != 0)
+ memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
+
+ res = send_reply_raw(f, outbuf, outsize, locked);
+ free(outbuf);
+ }
return res;
}
{
char newname[64];
char *newpath;
- int err = -1;
-
- if (!f->op.rename || !f->op.unlink)
- return -EBUSY;
+ int err = -EBUSY;
- newpath = hidden_name(f, dir, oldname, newname, sizeof(newname));
- if (newpath) {
- err = f->op.rename(oldpath, newpath);
- if (!err)
- err = rename_node(f, dir, oldname, dir, newname, 1);
- free(newpath);
+ if (f->op.rename && f->op.unlink) {
+ newpath = hidden_name(f, dir, oldname, newname, sizeof(newname));
+ if (newpath) {
+ int res = f->op.rename(oldpath, newpath);
+ if (res == 0)
+ err = rename_node(f, dir, oldname, dir, newname, 1);
+ free(newpath);
+ }
}
- if (err)
- return -EBUSY;
-
- return 0;
+ return err;
}
static int lookup_path(struct fuse *f, fino_t ino, int version, char *name,
memset(arg, 0, sizeof(struct fuse_entry_out));
convert_stat(&buf, &arg->attr);
node = find_node(f, ino, name, &arg->attr, version);
- arg->ino = node->ino;
- arg->generation = node->generation;
- arg->entry_valid = ENTRY_REVALIDATE_TIME;
- arg->entry_valid_nsec = 0;
- arg->attr_valid = ATTR_REVALIDATE_TIME;
- arg->attr_valid_nsec = 0;
- if (f->flags & FUSE_DEBUG) {
- printf(" INO: %li\n", arg->ino);
- fflush(stdout);
+ if (node == NULL)
+ res = -ENOMEM;
+ else {
+ arg->ino = node->ino;
+ arg->generation = node->generation;
+ arg->entry_valid = ENTRY_REVALIDATE_TIME;
+ arg->entry_valid_nsec = 0;
+ arg->attr_valid = ATTR_REVALIDATE_TIME;
+ arg->attr_valid_nsec = 0;
+ if (f->flags & FUSE_DEBUG) {
+ printf(" INO: %li\n", arg->ino);
+ fflush(stdout);
+ }
}
}
return res;
if (res == 0) {
res = f->op.rename(oldpath, newpath);
if (res == 0)
- rename_node(f, olddir, oldname, newdir, newname, 0);
+ res = rename_node(f, olddir, oldname, newdir, newname, 0);
}
}
free(newpath);
int res;
char *path;
char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
- struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
- char *buf = outbuf + sizeof(struct fuse_out_header);
- size_t size;
- size_t outsize;
-
- res = -ENOENT;
- path = get_path(f, in->ino);
- if (path != NULL) {
- if (f->flags & FUSE_DEBUG) {
- printf("READ[%u] %u bytes from %llu\n", arg->fh, arg->size,
- arg->offset);
- fflush(stdout);
+ if (outbuf == NULL)
+ send_reply(f, in, -ENOMEM, NULL, 0);
+ else {
+ struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
+ char *buf = outbuf + sizeof(struct fuse_out_header);
+ size_t size;
+ size_t outsize;
+
+ res = -ENOENT;
+ path = get_path(f, in->ino);
+ if (path != NULL) {
+ if (f->flags & FUSE_DEBUG) {
+ printf("READ[%u] %u bytes from %llu\n", arg->fh, arg->size,
+ arg->offset);
+ fflush(stdout);
+ }
+
+ res = -ENOSYS;
+ if (f->op.read)
+ res = f->op.read(path, buf, arg->size, arg->offset);
+ free(path);
}
-
- res = -ENOSYS;
- if (f->op.read)
- res = f->op.read(path, buf, arg->size, arg->offset);
- free(path);
- }
-
- size = 0;
- if (res >= 0) {
- size = res;
- res = 0;
- if (f->flags & FUSE_DEBUG) {
- printf(" READ[%u] %u bytes\n", arg->fh, size);
- fflush(stdout);
+
+ size = 0;
+ if (res >= 0) {
+ size = res;
+ res = 0;
+ if (f->flags & FUSE_DEBUG) {
+ printf(" READ[%u] %u bytes\n", arg->fh, size);
+ fflush(stdout);
+ }
}
+ memset(out, 0, sizeof(struct fuse_out_header));
+ out->unique = in->unique;
+ out->error = res;
+ outsize = sizeof(struct fuse_out_header) + size;
+
+ send_reply_raw(f, outbuf, outsize, 0);
+ free(outbuf);
}
- memset(out, 0, sizeof(struct fuse_out_header));
- out->unique = in->unique;
- out->error = res;
- outsize = sizeof(struct fuse_out_header) + size;
-
- send_reply_raw(f, outbuf, outsize, 0);
- free(outbuf);
}
static void do_write(struct fuse *f, struct fuse_in_header *in,
{
int res;
char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
- struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
- char *value = outbuf + sizeof(struct fuse_out_header);
-
- res = common_getxattr(f, in, name, value, size);
- size = 0;
- if (res > 0) {
- size = res;
- res = 0;
+ if (outbuf == NULL)
+ send_reply(f, in, -ENOMEM, NULL, 0);
+ else {
+ struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
+ char *value = outbuf + sizeof(struct fuse_out_header);
+
+ res = common_getxattr(f, in, name, value, size);
+ size = 0;
+ if (res > 0) {
+ size = res;
+ res = 0;
+ }
+ memset(out, 0, sizeof(struct fuse_out_header));
+ out->unique = in->unique;
+ out->error = res;
+
+ send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size, 0);
+ free(outbuf);
}
- memset(out, 0, sizeof(struct fuse_out_header));
- out->unique = in->unique;
- out->error = res;
-
- send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size, 0);
- free(outbuf);
}
static void do_getxattr_size(struct fuse *f, struct fuse_in_header *in,
{
int res;
char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
- struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
- char *list = outbuf + sizeof(struct fuse_out_header);
-
- res = common_listxattr(f, in, list, size);
- size = 0;
- if (res > 0) {
- size = res;
- res = 0;
+ if (outbuf == NULL)
+ send_reply(f, in, -ENOMEM, NULL, 0);
+ else {
+ struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
+ char *list = outbuf + sizeof(struct fuse_out_header);
+
+ res = common_listxattr(f, in, list, size);
+ size = 0;
+ if (res > 0) {
+ size = res;
+ res = 0;
+ }
+ memset(out, 0, sizeof(struct fuse_out_header));
+ out->unique = in->unique;
+ out->error = res;
+
+ send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size, 0);
+ free(outbuf);
}
- memset(out, 0, sizeof(struct fuse_out_header));
- out->unique = in->unique;
- out->error = res;
-
- send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size, 0);
- free(outbuf);
}
static void do_listxattr_size(struct fuse *f, struct fuse_in_header *in)
void *inarg;
cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
+ if (cmd == NULL) {
+ fprintf(stderr, "fuse: failed to allocate cmd in read\n");
+ return NULL;
+ }
cmd->buf = (char *) malloc(FUSE_MAX_IN);
+ if (cmd->buf == NULL) {
+ fprintf(stderr, "fuse: failed to allocate read buffer\n");
+ free(cmd);
+ return NULL;
+ }
in = (struct fuse_in_header *) cmd->buf;
inarg = cmd->buf + sizeof(struct fuse_in_header);
return cmd;
}
-void fuse_loop(struct fuse *f)
+int fuse_loop(struct fuse *f)
{
if (f == NULL)
- return;
+ return -1;
while (1) {
struct fuse_cmd *cmd;
if (__fuse_exited(f))
- return;
+ return 0;
cmd = __fuse_read_cmd(f);
if (cmd == NULL)
__fuse_process_cmd(f, cmd);
}
+ return 0;
}
int fuse_invalidate(struct fuse *f, const char *path)
return 0;
}
-static void parse_lib_opts(struct fuse *f, const char *opts)
+static int parse_lib_opts(struct fuse *f, const char *opts)
{
if (opts) {
char *xopts = strdup(opts);
char *s = xopts;
char *opt;
+
+ if (xopts == NULL)
+ return -1;
while((opt = strsep(&s, ","))) {
if (strcmp(opt, "debug") == 0)
}
free(xopts);
}
+ return 0;
}
struct fuse *fuse_new(int fd, const char *opts, const struct fuse_operations *op)
struct node *root;
f = (struct fuse *) calloc(1, sizeof(struct fuse));
+ if (f == NULL)
+ goto out;
- if (check_version(f) == -1) {
- free(f);
- return NULL;
- }
+ if (check_version(f) == -1)
+ goto out_free;
+
+ if (parse_lib_opts(f, opts) == -1)
+ goto out_free;
- parse_lib_opts(f, opts);
f->fd = fd;
f->ctr = 0;
f->generation = 0;
f->name_table_size = 14057;
f->name_table = (struct node **)
calloc(1, sizeof(struct node *) * f->name_table_size);
+ if (f->name_table == NULL)
+ goto out_free;
+
f->ino_table_size = 14057;
f->ino_table = (struct node **)
calloc(1, sizeof(struct node *) * f->ino_table_size);
+ if (f->ino_table == NULL)
+ goto out_free_name_table;
+
pthread_mutex_init(&f->lock, NULL);
f->numworker = 0;
f->numavail = 0;
f->exited = 0;
root = (struct node *) calloc(1, sizeof(struct node));
+ if (root == NULL)
+ goto out_free_ino_table;
+
root->mode = 0;
root->rdev = 0;
root->name = strdup("/");
+ if (root->name == NULL)
+ goto out_free_root;
+
root->parent = 0;
root->ino = FUSE_ROOT_INO;
root->generation = 0;
hash_ino(f, root);
return f;
+
+ out_free_root:
+ free(root);
+ out_free_ino_table:
+ free(f->ino_table);
+ out_free_name_table:
+ free(f->name_table);
+ out_free:
+ free(f);
+ out:
+ fprintf(stderr, "fuse: failed to allocate fuse object\n");
+ return NULL;
}
void fuse_destroy(struct fuse *f)
fuse_processor_t proc;
};
-static void start_thread(struct fuse_worker *w, pthread_t *thread_id);
+static int start_thread(struct fuse_worker *w, pthread_t *thread_id);
static void *do_work(void *data)
{
struct fuse_worker *w = (struct fuse_worker *) data;
struct fuse *f = w->f;
+ struct fuse_context *ctx;
+
+ ctx = (struct fuse_context *) malloc(sizeof(struct fuse_context));
+ if (ctx == NULL) {
+ fprintf(stderr, "fuse: failed to allocate fuse context\n");
+ pthread_mutex_lock(&f->lock);
+ f->numavail --;
+ pthread_mutex_unlock(&f->lock);
+ return NULL;
+ }
+ pthread_setspecific(f->context_key, ctx);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
if (f->numavail == 0 && f->numworker < FUSE_MAX_WORKERS) {
pthread_mutex_lock(&f->lock);
if (f->numworker < FUSE_MAX_WORKERS) {
+ /* FIXME: threads should be stored in a list instead
+ of an array */
+ int res;
pthread_t *thread_id = &w->threads[f->numworker];
f->numavail ++;
f->numworker ++;
pthread_mutex_unlock(&f->lock);
- start_thread(w, thread_id);
+ res = start_thread(w, thread_id);
+ if (res == -1) {
+ pthread_mutex_lock(&f->lock);
+ f->numavail --;
+ pthread_mutex_unlock(&f->lock);
+ }
} else
pthread_mutex_unlock(&f->lock);
}
return NULL;
}
-static void start_thread(struct fuse_worker *w, pthread_t *thread_id)
+static int start_thread(struct fuse_worker *w, pthread_t *thread_id)
{
sigset_t oldset;
sigset_t newset;
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
if (res != 0) {
fprintf(stderr, "Error creating thread: %s\n", strerror(res));
- exit(1);
+ return -1;
}
pthread_detach(*thread_id);
+ return 0;
}
static struct fuse_context *mt_getcontext(struct fuse *f)
{
- struct fuse_context *ctx;
-
- ctx = (struct fuse_context *) pthread_getspecific(f->context_key);
- if (ctx == NULL) {
- ctx = (struct fuse_context *) malloc(sizeof(struct fuse_context));
- pthread_setspecific(f->context_key, ctx);
- }
-
- return ctx;
+ return (struct fuse_context *) pthread_getspecific(f->context_key);
}
static void mt_freecontext(void *data)
free(data);
}
-void __fuse_loop_mt(struct fuse *f, fuse_processor_t proc, void *data)
+int __fuse_loop_mt(struct fuse *f, fuse_processor_t proc, void *data)
{
struct fuse_worker *w;
int res;
int i;
w = malloc(sizeof(struct fuse_worker));
+ if (w == NULL) {
+ fprintf(stderr, "fuse: failed to allocate worker structure\n");
+ return -1;
+ }
memset(w, 0, sizeof(struct fuse_worker));
w->f = f;
w->data = data;
res = pthread_key_create(&f->context_key, mt_freecontext);
if (res != 0) {
fprintf(stderr, "Failed to create thread specific key\n");
- exit(1);
+ return -1;
}
f->getcontext = mt_getcontext;
do_work(w);
pthread_mutex_unlock(&f->lock);
pthread_key_delete(f->context_key);
free(w);
+ return 0;
}
-void fuse_loop_mt(struct fuse *f)
+int fuse_loop_mt(struct fuse *f)
{
if (f == NULL)
- return;
+ return -1;
- __fuse_loop_mt(f, (fuse_processor_t) __fuse_process_cmd, NULL);
+ return __fuse_loop_mt(f, (fuse_processor_t) __fuse_process_cmd, NULL);
}