diff options
author | Jeff Garzik <jeff@garzik.org> | 2006-08-03 20:34:45 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-08-03 20:34:45 -0400 |
commit | e9acf7d8ceb1b8b2772ab87cac74ea112cb94a5b (patch) | |
tree | 60919aed0f78af3221e44b68621b9a41b63b0c2d | |
parent | 5c596ffda389e9704a4742e1ae8393e9b702ac73 (diff) | |
download | dbfs-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.c | 54 | ||||
-rw-r--r-- | dbfs.c | 28 | ||||
-rw-r--r-- | dbfs.h | 1 | ||||
-rw-r--r-- | libdbfs.c | 3 |
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; @@ -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, @@ -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); @@ -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); } |