diff options
author | Jeff Garzik <jeff@garzik.org> | 2006-04-25 01:21:17 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-04-25 01:21:17 -0400 |
commit | f82d3780aac855871e7c117c8efd982861599918 (patch) | |
tree | 5d39251e2d8665b4798f789594b5a6c5ed21d608 | |
parent | 7e3ab79542f53c6861c8a0069c864c2b630583a5 (diff) | |
download | dbfs-f82d3780aac855871e7c117c8efd982861599918.tar.gz |
Implement mknod. dirent endian fixes.
-rw-r--r-- | dbfs-backend.c | 275 | ||||
-rw-r--r-- | dbfs.c | 8 | ||||
-rw-r--r-- | dbfs.h | 2 | ||||
-rw-r--r-- | libdbfs.c | 2 |
4 files changed, 265 insertions, 22 deletions
diff --git a/dbfs-backend.c b/dbfs-backend.c index 87bb065..1e68aa9 100644 --- a/dbfs-backend.c +++ b/dbfs-backend.c @@ -5,6 +5,7 @@ #include <string.h> #include <errno.h> #include <unistd.h> +#include <time.h> #include <glib.h> #include <db.h> #include "dbfs.h" @@ -236,13 +237,11 @@ int dbfs_dir_foreach(void *dir, dbfs_dir_actor_t func, void *userdata) struct dbfs_dirent *de; void *p; int rc = 0; + unsigned int namelen; p = dir; while (1) { de = p; - de->magic = GUINT32_FROM_LE(de->magic); - de->namelen = GUINT16_FROM_LE(de->namelen); - de->ino = GUINT64_FROM_LE(de->ino); g_assert (de->magic == DBFS_DE_MAGIC); if (!de->namelen) @@ -256,8 +255,9 @@ int dbfs_dir_foreach(void *dir, dbfs_dir_actor_t func, void *userdata) /* align things so that compiler structures * do not wind up misaligned. */ - p += sizeof(struct dbfs_dirent) + de->namelen + - (4 - (de->namelen & 0x3)); + namelen = GUINT16_FROM_LE(de->namelen); + p += sizeof(struct dbfs_dirent) + namelen + + (4 - (namelen & 0x3)); } return rc; @@ -268,7 +268,7 @@ static int dbfs_dir_scan1(struct dbfs_dirent *de, void *userdata) struct dbfs_dirscan_info *di = userdata; if (!di->start_ent) { - if ((de->namelen == di->namelen) && + if ((GUINT16_FROM_LE(de->namelen) == di->namelen) && (!memcmp(de->name, di->name, di->namelen))) di->start_ent = de; } @@ -398,22 +398,261 @@ out: return rc; } -int dbfs_mknod(guint64 parent, const char *name, guint32 mode, guint64 rdev, - struct dbfs_inode **ino) +static int dbfs_name_validate(const char *name) +{ + if (strchr(name, '/')) + return -EINVAL; + if (!g_utf8_validate(name, -1, NULL)) + return -EINVAL; + return 0; +} + +static int dbfs_inode_next(struct dbfs_inode **ino_out) +{ + struct dbfs_inode *ino; + int rc; + guint64 curtime, start = gfs->next_inode; + + *ino_out = NULL; + + /* loop through inode numbers starting at gfs->next_inode, + * and stop on first error. Error ENOENT means the + * inode number was not found, and can therefore be used + * as the next free inode number. + */ + while (1) { + rc = dbfs_inode_read(gfs->next_inode, &ino); + if (rc) + break; + + dbfs_inode_free(ino); + gfs->next_inode++; + if (gfs->next_inode < 2) + gfs->next_inode = 2; + if (gfs->next_inode == start) { /* loop */ + rc = -EBUSY; + break; + } + } + + if (rc != -ENOENT) + return rc; + + /* allocate an empty inode */ + ino = g_new0(struct dbfs_inode, 1); + ino->raw_ino_size = sizeof(struct dbfs_raw_inode); + ino->raw_inode = malloc(ino->raw_ino_size); + memset(ino->raw_inode, 0, ino->raw_ino_size); + + ino->raw_inode->ino = GUINT64_TO_LE(gfs->next_inode++); + curtime = GUINT64_TO_LE(time(NULL)); + ino->raw_inode->ctime = curtime; + ino->raw_inode->atime = curtime; + ino->raw_inode->mtime = curtime; + + *ino_out = ino; + + return 0; +} + +static int dbfs_dir_new(guint64 parent, guint64 ino_n, struct dbfs_inode *ino) { - /* FIXME */ - *ino = NULL; - return -EIO; + void *mem, *p, *q; + struct dbfs_dirent *de; + size_t namelen; + DBT val; + int rc; + + p = mem = malloc(128); + memset(mem, 0, 128); + + /* + * add entry for "." + */ + de = p; + de->magic = GUINT32_TO_LE(DBFS_DE_MAGIC); + de->namelen = GUINT16_TO_LE(1); + de->ino = GUINT64_TO_LE(ino_n); - /* To do: + q = p + sizeof(struct dbfs_dirent); + memcpy(q, ".", 1); - - fail if invalid name - - allocate new inode number - - create inode record - - if dir, create dir record - - attempt to add name to parent directory - - fail if already exists + namelen = GUINT16_FROM_LE(de->namelen); + p += sizeof(struct dbfs_dirent) + namelen + + (4 - (namelen & 0x3)); + /* + * add entry for ".." */ + de = p; + de->magic = GUINT32_TO_LE(DBFS_DE_MAGIC); + de->namelen = GUINT16_TO_LE(2); + de->ino = GUINT64_TO_LE(parent); + + q = p + sizeof(struct dbfs_dirent); + memcpy(q, "..", 2); + + namelen = GUINT16_FROM_LE(de->namelen); + p += sizeof(struct dbfs_dirent) + namelen + + (4 - (namelen & 0x3)); + + /* + * add terminating entry + */ + de = p; + de->magic = GUINT32_TO_LE(DBFS_DE_MAGIC); + + namelen = GUINT16_FROM_LE(de->namelen); + p += sizeof(struct dbfs_dirent) + namelen + + (4 - (namelen & 0x3)); + + /* + * store dir in database + */ + memset(&val, 0, sizeof(val)); + val.data = mem; + val.size = p - mem; + + rc = dbfs_dir_write(ino_n, &val); + if (rc) { + dbfs_inode_del(ino); + dbfs_inode_free(ino); + return rc; + } + + free(mem); + + return 0; +} + +static int dbfs_dir_find_last(struct dbfs_dirent *de, void *userdata) +{ + struct dbfs_dirscan_info *di = userdata; + + di->end_ent = de; + + return 0; +} + +static int dbfs_dir_append(guint64 parent, guint64 ino_n, const char *name) +{ + struct dbfs_dirscan_info di; + struct dbfs_dirent *de; + DBT val; + int rc; + unsigned int dir_size, namelen; + void *p; + + /* read parent directory from database */ + rc = dbfs_dir_read(parent, &val); + if (rc) + return rc; + + memset(&di, 0, sizeof(di)); + di.name = name; + di.namelen = strlen(name); + + /* scan for name in directory, abort if found */ + rc = dbfs_dir_foreach(val.data, dbfs_dir_scan1, &di); + if (rc != -ENOENT) { + if (rc == 0) + rc = -EEXIST; + goto out; + } + + /* get pointer to last entry */ + rc = dbfs_dir_foreach(val.data, dbfs_dir_find_last, &di); + if (rc) + goto out; + + /* adjust pointer 'p' to point to terminator entry */ + de = p = di.end_ent; + namelen = GUINT16_FROM_LE(de->namelen); + p += sizeof(struct dbfs_dirent) + namelen + + (4 - (namelen & 0x3)); + + /* increase directory data area size */ + dir_size = p - val.data; + val.size = dir_size + (3 * sizeof(struct dbfs_dirent)) + di.namelen; + val.data = realloc(val.data, val.size); + p = val.data + dir_size; + + /* append directory entry */ + de = p; + de->magic = GUINT32_TO_LE(DBFS_DE_MAGIC); + de->namelen = GUINT16_TO_LE(di.namelen); + de->ino = GUINT64_TO_LE(ino_n); + memcpy(de->name, name, di.namelen); + + namelen = di.namelen; + p += sizeof(struct dbfs_dirent) + namelen + + (4 - (namelen & 0x3)); + + /* append terminator entry */ + de = p; + memset(de, 0, sizeof(*de)); + de->magic = GUINT32_TO_LE(DBFS_DE_MAGIC); + + namelen = 0; + p += sizeof(struct dbfs_dirent) + namelen + + (4 - (namelen & 0x3)); + + val.size = p - val.data; + + rc = dbfs_dir_write(parent, &val); + +out: + free(val.data); + return rc; +} + +int dbfs_mknod(guint64 parent, const char *name, guint32 mode, guint64 rdev, + struct dbfs_inode **ino_out) +{ + struct dbfs_inode *ino; + int rc, is_dir; + unsigned int nlink = 1; + guint64 ino_n; + + *ino_out = NULL; + + rc = dbfs_name_validate(name); + if (rc) + return rc; + + rc = dbfs_inode_next(&ino); + if (rc) + return rc; + + is_dir = S_ISDIR(mode); + if (is_dir) + nlink++; + ino_n = GUINT64_FROM_LE(ino->raw_inode->ino); + ino->raw_inode->mode = GUINT32_TO_LE(mode); + ino->raw_inode->nlink = GUINT32_TO_LE(nlink); + ino->raw_inode->rdev = GUINT64_TO_LE(rdev); + + rc = dbfs_inode_write(ino); + if (rc) + goto err_out; + + if (is_dir) { + rc = dbfs_dir_new(parent, ino_n, ino); + if (rc) + goto err_out_del; + } + + rc = dbfs_dir_append(parent, ino_n, name); + if (rc) + goto err_out_del; + + *ino_out = ino; + return 0; + +err_out_del: + dbfs_inode_del(ino); +err_out: + dbfs_inode_free(ino); + return rc; } @@ -203,9 +203,9 @@ static void dbfs_op_unlink(fuse_req_t req, fuse_ino_t parent, const char *name) static int dbfs_chk_empty(struct dbfs_dirent *de, void *userdata) { - if ((de->namelen == 1) && (!memcmp(de->name, ".", 1))) + if ((GUINT16_FROM_LE(de->namelen) == 1) && (!memcmp(de->name, ".", 1))) return 0; - if ((de->namelen == 2) && (!memcmp(de->name, "..", 2))) + if ((GUINT16_FROM_LE(de->namelen) == 2) && (!memcmp(de->name, "..", 2))) return 0; return ENOTEMPTY; } @@ -312,8 +312,8 @@ static int dbfs_fill_dirbuf(struct dbfs_dirent *de, void *userdata) char *s; /* add dirent to buffer; use g_strndup solely to append nul */ - s = g_strndup(de->name, de->namelen); - dirbuf_add(b, s, de->ino); + s = g_strndup(de->name, GUINT16_FROM_LE(de->namelen)); + dirbuf_add(b, s, GUINT64_FROM_LE(de->ino)); free(s); return 0; } @@ -69,6 +69,8 @@ struct dbfs { DB_ENV *env; DB *meta; + + guint64 next_inode; }; @@ -121,6 +121,8 @@ struct dbfs *dbfs_new(void) fs = g_new0(struct dbfs, 1); if (!fs) return NULL; + + fs->next_inode = 2ULL; fs->home = getenv("DB_HOME"); if (!fs->home) |