x
diff --git a/lib/fuse.c b/lib/fuse.c
index 62695f0..f033e04 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -12,6 +12,7 @@
#include <string.h>
#include <unistd.h>
#include <errno.h>
+#include <assert.h>
static guint name_hash(const struct node *node)
@@ -29,7 +30,7 @@
static struct node *new_node(fino_t parent, const char *name)
{
struct node *node = g_new0(struct node, 1);
- node->name = strdup(name);
+ node->name = g_strdup(name);
node->parent = parent;
return node;
}
@@ -51,15 +52,22 @@
return (((fino_t) node) - 0x8000000) >> 3;
}
+static struct node *lookup_node(struct fuse *f, fino_t parent,
+ const char *name)
+{
+ struct node tmp;
+
+ tmp.name = (char *) name;
+ tmp.parent = parent;
+
+ return g_hash_table_lookup(f->nametab, &tmp);
+}
+
static fino_t find_node(struct fuse *f, fino_t parent, char *name, int create)
{
struct node *node;
- struct node tmp;
-
- tmp.name = name;
- tmp.parent = parent;
- node = g_hash_table_lookup(f->nametab, &tmp);
+ node = lookup_node(f, parent, name);
if(node != NULL)
return get_ino(node);
@@ -109,6 +117,27 @@
free_node(node);
}
+static void rename_node(struct fuse *f, fino_t olddir, const char *oldname,
+ fino_t newdir, const char *newname)
+{
+ struct node *node = lookup_node(f, olddir, oldname);
+ struct node *newnode = lookup_node(f, newdir, newname);
+
+ assert(node != NULL);
+
+ /* The overwritten node is left to dangle until deleted */
+ if(newnode != NULL)
+ g_hash_table_remove(f->nametab, newnode);
+
+ /* The renamed node is not freed, since it's pointer is the key */
+ g_hash_table_remove(f->nametab, node);
+ g_free(node->name);
+ node->name = g_strdup(newname);
+ node->parent = newdir;
+ g_hash_table_insert(f->nametab, node, node);
+}
+
+
static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
{
attr->mode = stbuf->st_mode;
@@ -124,23 +153,6 @@
attr->ctime = stbuf->st_ctime;
}
-static int get_attributes(struct fuse *f, fino_t ino, struct fuse_attr *attr)
-{
- char *path;
- struct stat buf;
- int res;
-
- path = get_path(ino);
- res = -ENOSYS;
- if(f->op.getattr)
- res = f->op.getattr(path, &buf);
- g_free(path);
- if(res == 0)
- convert_stat(&buf, attr);
-
- return res;
-}
-
static int fill_dir(struct fuse_dh *dh, char *name, int type)
{
struct fuse_dirent dirent;
@@ -160,7 +172,7 @@
return 0;
}
-static void send_reply(struct fuse *f, struct fuse_in_header *in, int result,
+static void send_reply(struct fuse *f, struct fuse_in_header *in, int error,
void *arg, size_t argsize)
{
int res;
@@ -168,25 +180,24 @@
size_t outsize;
struct fuse_out_header *out;
- if(result > 0) {
- fprintf(stderr, "positive result to operation %i : %i\n", in->opcode,
- result);
- result = -ERANGE;
+ if(error > 0) {
+ fprintf(stderr, "positive error code: %i\n", error);
+ error = -ERANGE;
}
- if(result != 0)
+ if(error)
argsize = 0;
outsize = sizeof(struct fuse_out_header) + argsize;
outbuf = (char *) g_malloc(outsize);
out = (struct fuse_out_header *) outbuf;
out->unique = in->unique;
- out->result = result;
+ out->error = error;
if(argsize != 0)
memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
- printf(" unique: %i, result: %i (%s), outsize: %i\n", out->unique,
- out->result, strerror(-out->result), outsize);
+ printf(" unique: %i, error: %i (%s), outsize: %i\n", out->unique,
+ out->error, strerror(-out->error), outsize);
res = write(f->fd, outbuf, outsize);
if(res == -1)
@@ -198,11 +209,19 @@
static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name)
{
int res;
+ char *path;
+ struct stat buf;
struct fuse_lookup_out arg;
- arg.ino = find_node(f, in->ino, name, 1);
- res = get_attributes(f, arg.ino, &arg.attr);
-
+ path = get_path_name(in->ino, name);
+ res = -ENOSYS;
+ if(f->op.getattr)
+ res = f->op.getattr(path, &buf);
+ g_free(path);
+ if(res == 0) {
+ convert_stat(&buf, &arg.attr);
+ arg.ino = find_node(f, in->ino, name, 1);
+ }
send_reply(f, in, res, &arg, sizeof(arg));
}
@@ -217,9 +236,18 @@
static void do_getattr(struct fuse *f, struct fuse_in_header *in)
{
int res;
+ char *path;
+ struct stat buf;
struct fuse_getattr_out arg;
- res = get_attributes(f, in->ino, &arg.attr);
+ path = get_path(in->ino);
+ res = -ENOSYS;
+ if(f->op.getattr)
+ res = f->op.getattr(path, &buf);
+ g_free(path);
+ if(res == 0)
+ convert_stat(&buf, &arg.attr);
+
send_reply(f, in, res, &arg, sizeof(arg));
}
@@ -269,8 +297,7 @@
struct fuse_mknod_out outarg;
struct stat buf;
- outarg.ino = find_node(f, in->ino, inarg->name, 1);
- path = get_path(outarg.ino);
+ path = get_path_name(in->ino, inarg->name);
res = -ENOSYS;
if(f->op.mknod && f->op.getattr) {
res = f->op.mknod(path, inarg->mode, inarg->rdev);
@@ -278,9 +305,10 @@
res = f->op.getattr(path, &buf);
}
g_free(path);
-
- if(res == 0)
+ if(res == 0) {
convert_stat(&buf, &outarg.attr);
+ outarg.ino = find_node(f, in->ino, inarg->name, 1);
+ }
send_reply(f, in, res, &outarg, sizeof(outarg));
}
@@ -332,6 +360,39 @@
send_reply(f, in, res, NULL, 0);
}
+static void do_rename(struct fuse *f, struct fuse_in_header *in,
+ struct fuse_rename_in *inarg)
+{
+ int res;
+ fino_t olddir = in->ino;
+ fino_t newdir = inarg->newdir;
+ char *oldname = inarg->names;
+ char *newname = inarg->names + strlen(oldname) + 1;
+ char *oldpath = get_path_name(olddir, oldname);
+ char *newpath = get_path_name(newdir, newname);
+
+ res = -ENOSYS;
+ if(f->op.rename)
+ res = f->op.rename(oldpath, newpath);
+ if(res == 0)
+ rename_node(f, olddir, oldname, newdir, newname);
+ send_reply(f, in, res, NULL, 0);
+}
+
+static void do_link(struct fuse *f, struct fuse_in_header *in,
+ struct fuse_link_in *inarg)
+{
+ int res;
+ char *oldpath = get_path(in->ino);
+ char *newpath = get_path_name(inarg->newdir, inarg->name);
+
+ res = -ENOSYS;
+ if(f->op.link)
+ res = f->op.link(oldpath, newpath);
+
+ send_reply(f, in, res, NULL, 0);
+}
+
void fuse_loop(struct fuse *f)
{
@@ -400,6 +461,14 @@
((char *) inarg) + strlen((char *) inarg) + 1);
break;
+ case FUSE_RENAME:
+ do_rename(f, in, (struct fuse_rename_in *) inarg);
+ break;
+
+ case FUSE_LINK:
+ do_link(f, in, (struct fuse_link_in *) inarg);
+ break;
+
default:
fprintf(stderr, "Operation %i not implemented\n", in->opcode);
/* No need to send reply to async requests */