*/
#include <stdint.h>
+#include <inttypes.h>
#include <glib.h>
-#include "bluesky.h"
+#include "bluesky-private.h"
/* Core filesystem: handling of directories. */
{
BlueSkyDirent *dirent = (BlueSkyDirent *)data;
g_free(dirent->name);
+ g_free(dirent->name_folded);
g_free(dirent);
}
return d->inum;
}
+/* Case-insensitive lookup. */
+uint64_t bluesky_directory_ilookup(BlueSkyInode *inode, gchar *name)
+{
+ g_return_val_if_fail(inode->type == BLUESKY_DIRECTORY, 0);
+ g_return_val_if_fail(inode->dirhash_folded != NULL, 0);
+
+ name = bluesky_lowercase(name);
+ BlueSkyDirent *d = g_hash_table_lookup(inode->dirhash_folded, name);
+ g_free(name);
+
+ if (d == NULL)
+ return 0;
+ else
+ return d->inum;
+}
+
+/* Iterate through a directory listing. This returns one directory entry at a
+ * time, finding the first entry with a directory cookie value larger than the
+ * supplied one. Use a cookie of 0 to start reading from the start of a
+ * directory. */
+BlueSkyDirent *bluesky_directory_read(BlueSkyInode *dir, uint32_t cookie)
+{
+ BlueSkyDirent start = {NULL, NULL, cookie, 0};
+ GSequenceIter *i = g_sequence_search(dir->dirents, &start,
+ bluesky_dirent_compare, NULL);
+
+ if (g_sequence_iter_is_end(i))
+ return NULL;
+ else
+ return g_sequence_get(i);
+}
+
/* Insert a new entry into a directory. Should be called with the inode lock
* already held. */
-gboolean bluesky_directory_insert(BlueSkyInode *dir, gchar *name, uint64_t inum)
+gboolean bluesky_directory_insert(BlueSkyInode *dir,
+ const gchar *name, uint64_t inum)
{
g_return_val_if_fail(dir->type == BLUESKY_DIRECTORY, FALSE);
BlueSkyDirent *d = g_new(BlueSkyDirent, 1);
d->name = g_strdup(name);
+ d->name_folded = bluesky_lowercase(name);
d->inum = inum;
GSequence *dirents = dir->dirents;
/* Add the directory entry to both indices. */
g_sequence_insert_sorted(dirents, d, bluesky_dirent_compare, NULL);
g_hash_table_insert(dir->dirhash, d->name, d);
+ g_hash_table_insert(dir->dirhash_folded, d->name_folded, d);
bluesky_inode_update_ctime(dir, 1);
- bluesky_inode_flush(dir->fs, dir);
+ //bluesky_inode_do_sync(dir); // TODO: Needed?
return TRUE;
}
-/* Remove an from a directory. Should be called with the inode lock already
- * held. */
+/* Remove an entry from a directory. Should be called with the inode lock
+ * already held. */
gboolean bluesky_directory_remove(BlueSkyInode *dir, gchar *name)
{
g_return_val_if_fail(dir->type == BLUESKY_DIRECTORY, FALSE);
return FALSE;
}
- g_hash_table_remove(dir->dirhash, name);
+ g_hash_table_remove(dir->dirhash, d->name);
+ g_hash_table_remove(dir->dirhash_folded, d->name_folded);
GSequenceIter *i = g_sequence_search(dir->dirents, d,
bluesky_dirent_compare, NULL);
g_sequence_remove(i);
- bluesky_dirent_destroy(d);
-
bluesky_inode_update_ctime(dir, 1);
return TRUE;
}
+/* Rename a file. If desired (if overwrite is true) and if the target already
+ * exists, it will be unlinked first. */
+gboolean bluesky_rename(BlueSkyInode *dir1, gchar *name1,
+ BlueSkyInode *dir2, gchar *name2,
+ gboolean case_sensitive,
+ gboolean overwrite)
+{
+ g_return_val_if_fail(dir1->type == BLUESKY_DIRECTORY, FALSE);
+ g_return_val_if_fail(dir2->type == BLUESKY_DIRECTORY, FALSE);
+
+ BlueSkyDirent *d1, *d2;
+
+ d1 = g_hash_table_lookup(case_sensitive ? dir1->dirhash
+ : dir1->dirhash_folded, name1);
+ d2 = g_hash_table_lookup(case_sensitive ? dir2->dirhash
+ : dir2->dirhash_folded, name2);
+
+ if (d1 == NULL)
+ return FALSE;
+
+ uint64_t inum = d1->inum;
+
+ /* Check that this rename does not cause a directory to be moved into one
+ * of its descendants, as that would create a loop of directories
+ * disconnected from the root. */
+ /* TODO */
+
+ if (d2 != NULL) {
+ if (!overwrite)
+ return FALSE;
+
+ bluesky_directory_remove(dir2, name2);
+
+ // TODO: Drop inode reference
+ }
+
+ bluesky_directory_remove(dir1, name1);
+ bluesky_directory_insert(dir2, name2, inum);
+
+ return TRUE;
+}
+
/* Dump the contents of a directory to stdout. Debugging only. */
void bluesky_directory_dump(BlueSkyInode *dir)
{
while (!g_sequence_iter_is_end(i)) {
BlueSkyDirent *d = g_sequence_get(i);
- g_print(" 0x%08x [inum=%lld] %s\n", d->cookie, d->inum, d->name);
+ g_print(" 0x%08x [inum=%"PRIu64"] %s\n",
+ d->cookie, d->inum, d->name);
i = g_sequence_iter_next(i);
}
}