x
diff --git a/lib/fuse.c b/lib/fuse.c
index f033e04..cd919ed 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -27,11 +27,12 @@
strcmp(node1->name, node2->name) == 0;
}
-static struct node *new_node(fino_t parent, const char *name)
+static struct node *new_node(fino_t parent, const char *name, int mode)
{
struct node *node = g_new0(struct node, 1);
node->name = g_strdup(name);
node->parent = parent;
+ node->mode = mode;
return node;
}
@@ -63,20 +64,41 @@
return g_hash_table_lookup(f->nametab, &tmp);
}
-static fino_t find_node(struct fuse *f, fino_t parent, char *name, int create)
+static void unhash_node(struct fuse *f, struct node *node)
+{
+ g_hash_table_remove(f->nametab, node);
+ g_free(node->name);
+ node->parent = 0;
+ node->name = NULL;
+}
+
+static fino_t find_node(struct fuse *f, fino_t parent, char *name, int mode)
+{
+ struct node *node;
+ mode &= S_IFMT;
+
+ node = lookup_node(f, parent, name);
+ if(node != NULL) {
+ if(node->mode == mode)
+ return get_ino(node);
+
+ unhash_node(f, node);
+ }
+
+ node = new_node(parent, name, mode);
+ g_hash_table_insert(f->nametab, node, node);
+ return get_ino(node);
+}
+
+static fino_t find_node_dir(struct fuse *f, fino_t parent, char *name)
{
struct node *node;
node = lookup_node(f, parent, name);
if(node != NULL)
return get_ino(node);
-
- if(!create)
+ else
return (fino_t) -1;
-
- node = new_node(parent, name);
- g_hash_table_insert(f->nametab, node, node);
- return get_ino(node);
}
static char *get_path(fino_t ino)
@@ -91,6 +113,10 @@
struct node *node;
for(; ino != FUSE_ROOT_INO; ino = node->parent) {
node = get_node(ino);
+ if(node->name == NULL) {
+ g_string_free(s, TRUE);
+ return NULL;
+ }
g_string_prepend(s, node->name);
g_string_prepend_c(s, '/');
}
@@ -104,32 +130,42 @@
static char *get_path_name(fino_t ino, const char *name)
{
- char *path = get_path(ino);
- char *path2 = g_strconcat(path, "/", name, NULL);
+ char *path;
+ char *path2;
+
+ path = get_path(ino);
+ if(path == NULL)
+ return NULL;
+
+ path2 = g_strconcat(path, "/", name, NULL);
g_free(path);
return path2;
}
-static void remove_node(struct fuse *f, fino_t ino)
+static void destroy_node(struct fuse *f, fino_t ino)
{
struct node *node = get_node(ino);
- g_hash_table_remove(f->nametab, node);
+ unhash_node(f, node);
free_node(node);
}
+static void remove_node(struct fuse *f, fino_t dir, const char *name)
+{
+ struct node *node = lookup_node(f, dir, name);
+ assert(node != NULL);
+ unhash_node(f, 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);
+ unhash_node(f, 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);
@@ -159,7 +195,7 @@
size_t reclen;
size_t res;
- dirent.ino = find_node(dh->fuse, dh->dir, name, 0);
+ dirent.ino = find_node_dir(dh->fuse, dh->dir, name);
dirent.namelen = strlen(name);
strncpy(dirent.name, name, sizeof(dirent.name));
dirent.type = type;
@@ -213,14 +249,17 @@
struct stat buf;
struct fuse_lookup_out arg;
+ res = -ENOENT;
path = get_path_name(in->ino, name);
- res = -ENOSYS;
- if(f->op.getattr)
- res = f->op.getattr(path, &buf);
- g_free(path);
+ if(path != NULL) {
+ 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);
+ arg.ino = find_node(f, in->ino, name, arg.attr.mode);
}
send_reply(f, in, res, &arg, sizeof(arg));
}
@@ -230,7 +269,7 @@
size_t i;
for(i = 0; i < num; i++)
- remove_node(f, inos[i]);
+ destroy_node(f, inos[i]);
}
static void do_getattr(struct fuse *f, struct fuse_in_header *in)
@@ -240,30 +279,78 @@
struct stat buf;
struct fuse_getattr_out arg;
+ res = -ENOENT;
path = get_path(in->ino);
- res = -ENOSYS;
- if(f->op.getattr)
- res = f->op.getattr(path, &buf);
- g_free(path);
+ if(path != NULL) {
+ 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));
}
+static void do_setattr(struct fuse *f, struct fuse_in_header *in,
+ struct fuse_setattr_in *arg)
+{
+ int res;
+ char *path;
+ int valid = arg->valid;
+ struct fuse_attr *attr = &arg->attr;
+
+ res = -ENOENT;
+ path = get_path(in->ino);
+ if(path != NULL) {
+ res = 0;
+ if(!res && (valid & FATTR_MODE)) {
+ res = -ENOSYS;
+ if(f->op.chmod)
+ res = f->op.chmod(path, attr->mode);
+ }
+ if(!res && (valid & (FATTR_UID | FATTR_GID))) {
+ uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
+ gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
+
+ res = -ENOSYS;
+ if(f->op.chown)
+ res = f->op.chown(path, uid, gid);
+ }
+ if(!res && (valid & FATTR_SIZE)) {
+ res = -ENOSYS;
+ if(f->op.truncate)
+ res = f->op.truncate(path, attr->size);
+ }
+ if(!res && (valid & FATTR_UTIME)) {
+ struct utimbuf buf;
+ buf.actime = attr->atime;
+ buf.modtime = attr->mtime;
+ res = -ENOSYS;
+ if(f->op.utime)
+ res = f->op.utime(path, &buf);
+ }
+ g_free(path);
+ }
+ send_reply(f, in, res, NULL, 0);
+}
+
static void do_readlink(struct fuse *f, struct fuse_in_header *in)
{
int res;
char link[PATH_MAX + 1];
char *path;
- path = get_path(in->ino);
- res = -ENOSYS;
- if(f->op.readlink)
- res = f->op.readlink(path, link, sizeof(link));
- g_free(path);
-
- send_reply(f, in, res, link, res == 0 ? strlen(link) : 0);
+ res = -ENOENT;
+ path = get_path(in->ino);
+ if(path != NULL) {
+ res = -ENOSYS;
+ if(f->op.readlink)
+ res = f->op.readlink(path, link, sizeof(link));
+ g_free(path);
+ }
+ send_reply(f, in, res, link, !res ? strlen(link) : 0);
}
static void do_getdir(struct fuse *f, struct fuse_in_header *in)
@@ -277,12 +364,14 @@
dh.fp = tmpfile();
dh.dir = in->ino;
+ res = -ENOENT;
path = get_path(in->ino);
- res = -ENOSYS;
- if(f->op.getdir)
- res = f->op.getdir(path, &dh, (dirfiller_t) fill_dir);
- g_free(path);
-
+ if(path != NULL) {
+ res = -ENOSYS;
+ if(f->op.getdir)
+ res = f->op.getdir(path, &dh, (dirfiller_t) fill_dir);
+ g_free(path);
+ }
fflush(dh.fp);
arg.fd = fileno(dh.fp);
send_reply(f, in, res, &arg, sizeof(arg));
@@ -297,17 +386,20 @@
struct fuse_mknod_out outarg;
struct stat buf;
+ res = -ENOENT;
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);
- if(res == 0)
- res = f->op.getattr(path, &buf);
+ if(path != NULL) {
+ res = -ENOSYS;
+ if(f->op.mknod && f->op.getattr) {
+ res = f->op.mknod(path, inarg->mode, inarg->rdev);
+ if(res == 0)
+ res = f->op.getattr(path, &buf);
+ }
+ g_free(path);
}
- g_free(path);
if(res == 0) {
convert_stat(&buf, &outarg.attr);
- outarg.ino = find_node(f, in->ino, inarg->name, 1);
+ outarg.ino = find_node(f, in->ino, inarg->name, outarg.attr.mode);
}
send_reply(f, in, res, &outarg, sizeof(outarg));
@@ -319,11 +411,14 @@
int res;
char *path;
+ res = -ENOENT;
path = get_path_name(in->ino, inarg->name);
- res = -ENOSYS;
- if(f->op.mkdir)
- res = f->op.mkdir(path, inarg->mode);
- g_free(path);
+ if(path != NULL) {
+ res = -ENOSYS;
+ if(f->op.mkdir)
+ res = f->op.mkdir(path, inarg->mode);
+ g_free(path);
+ }
send_reply(f, in, res, NULL, 0);
}
@@ -332,17 +427,22 @@
int res;
char *path;
+ res = -ENOENT;
path = get_path_name(in->ino, name);
- res = -ENOSYS;
- if(in->opcode == FUSE_UNLINK) {
- if(f->op.unlink)
- res = f->op.unlink(path);
+ if(path != NULL) {
+ res = -ENOSYS;
+ if(in->opcode == FUSE_UNLINK) {
+ if(f->op.unlink)
+ res = f->op.unlink(path);
+ }
+ else {
+ if(f->op.rmdir)
+ res = f->op.rmdir(path);
+ }
+ g_free(path);
}
- else {
- if(f->op.rmdir)
- res = f->op.rmdir(path);
- }
- g_free(path);
+ if(res == 0)
+ remove_node(f, in->ino, name);
send_reply(f, in, res, NULL, 0);
}
@@ -352,11 +452,14 @@
int res;
char *path;
+ res = -ENOENT;
path = get_path_name(in->ino, name);
- res = -ENOSYS;
- if(f->op.symlink)
- res = f->op.symlink(link, path);
- g_free(path);
+ if(path != NULL) {
+ res = -ENOSYS;
+ if(f->op.symlink)
+ res = f->op.symlink(link, path);
+ g_free(path);
+ }
send_reply(f, in, res, NULL, 0);
}
@@ -368,31 +471,90 @@
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);
+ char *oldpath;
+ char *newpath;
- res = -ENOSYS;
- if(f->op.rename)
- res = f->op.rename(oldpath, newpath);
- if(res == 0)
- rename_node(f, olddir, oldname, newdir, newname);
+ res = -ENOENT;
+ oldpath = get_path_name(olddir, oldname);
+ if(oldpath != NULL) {
+ newpath = get_path_name(newdir, newname);
+ if(newpath != NULL) {
+ res = -ENOSYS;
+ if(f->op.rename)
+ res = f->op.rename(oldpath, newpath);
+ if(res == 0)
+ rename_node(f, olddir, oldname, newdir, newname);
+ g_free(newpath);
+ }
+ g_free(oldpath);
+ }
send_reply(f, in, res, NULL, 0);
}
static void do_link(struct fuse *f, struct fuse_in_header *in,
- struct fuse_link_in *inarg)
+ struct fuse_link_in *arg)
{
int res;
- char *oldpath = get_path(in->ino);
- char *newpath = get_path_name(inarg->newdir, inarg->name);
+ char *oldpath;
+ char *newpath;
- res = -ENOSYS;
- if(f->op.link)
- res = f->op.link(oldpath, newpath);
-
+ res = -ENOENT;
+ oldpath = get_path(in->ino);
+ if(oldpath != NULL) {
+ newpath = get_path_name(arg->newdir, arg->name);
+ if(newpath != NULL) {
+ res = -ENOSYS;
+ if(f->op.link)
+ res = f->op.link(oldpath, newpath);
+ g_free(newpath);
+ }
+ g_free(oldpath);
+ }
send_reply(f, in, res, NULL, 0);
}
+static void do_open(struct fuse *f, struct fuse_in_header *in,
+ struct fuse_open_in *arg)
+{
+ int res;
+ char *path;
+
+ res = -ENOENT;
+ path = get_path(in->ino);
+ if(path != NULL) {
+ res = -ENOSYS;
+ if(f->op.open)
+ res = f->op.open(path, arg->flags);
+ g_free(path);
+ }
+ send_reply(f, in, res, NULL, 0);
+}
+
+static void do_read(struct fuse *f, struct fuse_in_header *in,
+ struct fuse_read_in *arg)
+{
+ int res;
+ char *path;
+ char *buf = g_malloc(arg->size);
+ size_t size;
+
+ path = get_path(in->ino);
+ if(path != NULL) {
+ res = -ENOSYS;
+ if(f->op.pread)
+ res = f->op.pread(path, buf, arg->size, arg->offset);
+ g_free(path);
+ }
+
+ size = 0;
+ if(res > 0) {
+ size = res;
+ res = 0;
+ }
+
+ send_reply(f, in, res, buf, size);
+ g_free(buf);
+}
void fuse_loop(struct fuse *f)
{
@@ -435,6 +597,10 @@
do_getattr(f, in);
break;
+ case FUSE_SETATTR:
+ do_setattr(f, in, (struct fuse_setattr_in *) inarg);
+ break;
+
case FUSE_READLINK:
do_readlink(f, in);
break;
@@ -469,6 +635,14 @@
do_link(f, in, (struct fuse_link_in *) inarg);
break;
+ case FUSE_OPEN:
+ do_open(f, in, (struct fuse_open_in *) inarg);
+ break;
+
+ case FUSE_READ:
+ do_read(f, in, (struct fuse_read_in *) inarg);
+ break;
+
default:
fprintf(stderr, "Operation %i not implemented\n", in->opcode);
/* No need to send reply to async requests */
diff --git a/lib/fuse_i.h b/lib/fuse_i.h
index b3b907b..2d030ae 100644
--- a/lib/fuse_i.h
+++ b/lib/fuse_i.h
@@ -17,6 +17,7 @@
struct node {
char *name;
fino_t parent;
+ int mode;
};
struct fuse {
diff --git a/lib/mount.c b/lib/mount.c
index ace3c65..48d9d45 100644
--- a/lib/mount.c
+++ b/lib/mount.c
@@ -103,7 +103,6 @@
if(f->dir != NULL)
return 0;
- f->dir = g_strdup(dir);
f->fd = open(dev, O_RDWR);
if(f->fd == -1) {
perror(dev);
@@ -115,6 +114,7 @@
return -1;
add_mntent(dev, dir, type);
+ f->dir = g_strdup(dir);
return 0;
}