aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Garzik <jeff@garzik.org>2006-08-03 20:34:45 -0400
committerJeff Garzik <jeff@garzik.org>2006-08-03 20:34:45 -0400
commite9acf7d8ceb1b8b2772ab87cac74ea112cb94a5b (patch)
tree60919aed0f78af3221e44b68621b9a41b63b0c2d
parent5c596ffda389e9704a4742e1ae8393e9b702ac73 (diff)
downloaddbfs-e9acf7d8ceb1b8b2772ab87cac74ea112cb94a5b.tar.gz
Implement [hard]link operation.
Also: - include "." and ".." in list of invalid directory entry names - move dirent name validation to dbfs_dir_append() - dbfs_inode_free(NULL) is now supported
-rw-r--r--dbfs-backend.c54
-rw-r--r--dbfs.c28
-rw-r--r--dbfs.h1
-rw-r--r--libdbfs.c3
4 files changed, 72 insertions, 14 deletions
diff --git a/dbfs-backend.c b/dbfs-backend.c
index b4d7c44..34c9fc3 100644
--- a/dbfs-backend.c
+++ b/dbfs-backend.c
@@ -339,6 +339,19 @@ static int dbfs_dir_find_last(struct dbfs_dirent *de, void *userdata)
return 0;
}
+static int dbfs_name_validate(const char *name)
+{
+ if (strchr(name, '/'))
+ return -EINVAL;
+ if (!g_utf8_validate(name, -1, NULL))
+ return -EINVAL;
+ if (!strcmp(name, "."))
+ return -EINVAL;
+ if (!strcmp(name, ".."))
+ return -EINVAL;
+ return 0;
+}
+
static int dbfs_dir_append(guint64 parent, guint64 ino_n, const char *name)
{
struct dbfs_dirscan_info di;
@@ -348,6 +361,10 @@ static int dbfs_dir_append(guint64 parent, guint64 ino_n, const char *name)
unsigned int dir_size, namelen;
void *p;
+ rc = dbfs_name_validate(name);
+ if (rc)
+ return rc;
+
/* read parent directory from database */
rc = dbfs_dir_read(parent, &val);
if (rc)
@@ -449,6 +466,30 @@ int dbfs_symlink_write(guint64 ino, const char *link)
return gfs->meta->put(gfs->meta, NULL, &key, &val, 0) ? -EIO : 0;
}
+int dbfs_link(struct dbfs_inode *ino, guint64 ino_n, guint64 parent,
+ const char *name)
+{
+ guint32 nlink;
+ int rc;
+
+ /* make sure it doesn't exist yet */
+ rc = dbfs_dir_append(parent, ino_n, name);
+ if (rc)
+ return rc;
+
+ /* increment link count */
+ nlink = GUINT32_FROM_LE(ino->raw_inode->nlink);
+ nlink++;
+ ino->raw_inode->nlink = GUINT32_TO_LE(nlink);
+
+ /* write inode; if fails, undo directory modification */
+ rc = dbfs_inode_write(ino);
+ if (rc)
+ dbfs_dirent_del(parent, name);
+
+ return rc;
+}
+
int dbfs_unlink(guint64 parent, const char *name, unsigned long flags)
{
struct dbfs_inode *ino;
@@ -497,15 +538,6 @@ out:
return rc;
}
-static int dbfs_name_validate(const char *name)
-{
- if (strchr(name, '/'))
- return -EINVAL;
- if (!g_utf8_validate(name, -1, NULL))
- return -EINVAL;
- return 0;
-}
-
int dbfs_mknod(guint64 parent, const char *name, guint32 mode, guint64 rdev,
struct dbfs_inode **ino_out)
{
@@ -516,10 +548,6 @@ int dbfs_mknod(guint64 parent, const char *name, guint32 mode, guint64 rdev,
*ino_out = NULL;
- rc = dbfs_name_validate(name);
- if (rc)
- return rc;
-
rc = dbfs_inode_next(&ino);
if (rc)
return rc;
diff --git a/dbfs.c b/dbfs.c
index 6ad725a..10a7906 100644
--- a/dbfs.c
+++ b/dbfs.c
@@ -215,6 +215,32 @@ static void dbfs_op_unlink(fuse_req_t req, fuse_ino_t parent, const char *name)
fuse_reply_err(req, rc ? -rc : 0);
}
+static void dbfs_op_link(fuse_req_t req, fuse_ino_t ino_n, fuse_ino_t parent,
+ const char *newname)
+{
+ struct dbfs_inode *ino;
+ int rc;
+
+ /* read inode from database */
+ rc = dbfs_inode_read(ino_n, &ino);
+ if (rc) {
+ fuse_reply_err(req, ENOENT);
+ return;
+ }
+
+ /* attempt to create hard link */
+ rc = dbfs_link(ino, ino_n, parent, newname);
+ if (rc)
+ goto err_out;
+
+ dbfs_reply_ino(req, ino);
+ return;
+
+err_out:
+ dbfs_inode_free(ino);
+ fuse_reply_err(req, -rc);
+}
+
static int dbfs_chk_empty(struct dbfs_dirent *de, void *userdata)
{
if ((GUINT16_FROM_LE(de->namelen) == 1) && (!memcmp(de->name, ".", 1)))
@@ -390,7 +416,7 @@ static struct fuse_lowlevel_ops dbfs_ops = {
.rmdir = dbfs_op_rmdir,
.symlink = dbfs_op_symlink,
.rename = NULL,
- .link = NULL,
+ .link = dbfs_op_link,
.open = NULL,
.read = NULL,
.write = NULL,
diff --git a/dbfs.h b/dbfs.h
index 0803156..220a02f 100644
--- a/dbfs.h
+++ b/dbfs.h
@@ -86,6 +86,7 @@ extern int dbfs_dir_read(guint64 ino, DBT *val);
extern int dbfs_symlink_read(guint64 ino, DBT *val);
extern int dbfs_dir_foreach(void *dir, dbfs_dir_actor_t func, void *userdata);
extern int dbfs_dir_lookup(guint64 parent, const char *name, guint64 *ino);
+extern int dbfs_link(struct dbfs_inode *ino, guint64 ino_n, guint64 parent, const char *name);
extern int dbfs_unlink(guint64 parent, const char *name, unsigned long flags);
extern void dbfs_init(void *userdata);
extern void dbfs_exit(void *userdata);
diff --git a/libdbfs.c b/libdbfs.c
index 9b4d878..d51fa35 100644
--- a/libdbfs.c
+++ b/libdbfs.c
@@ -151,6 +151,9 @@ void dbfs_free(struct dbfs *fs)
void dbfs_inode_free(struct dbfs_inode *ino)
{
+ if (!ino) /* permit dbfs_inode_free(NULL) */
+ return;
+
free(ino->raw_inode);
g_free(ino);
}