+ GSequence *dirents = dir->dirents;
+
+ /* Pick an unused cookie value for the directory at random. Restrict
+ * ourselves to positive 32-bit values (even if treated as signed), and
+ * keep the first four slots free. */
+ while (1) {
+ do {
+ d->cookie = g_random_int() & 0x7fffffff;
+ } while (d->cookie < 4);
+
+ /* If the directory is empty, we can't possibly have a collision, so
+ * just go with the first key chosen. */
+ if (g_sequence_get_length(dirents) == 0)
+ break;
+
+ /* Otherwise, try looking up the generated cookie. If we do not find a
+ * match, we can use this cookie value, otherwise we need to generate a
+ * new one and try again. Because of the check above for an empty
+ * directory, we know that the lookup will return something so no need
+ * to worry about NULL. */
+ GSequenceIter *i = g_sequence_search(dir->dirents, d,
+ bluesky_dirent_compare, NULL);
+ i = g_sequence_iter_prev(i);
+ if (((BlueSkyDirent *)g_sequence_get(i))->cookie != d->cookie)
+ break;
+ }
+
+ /* 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);
+
+ bluesky_inode_update_ctime(dir, 1);
+
+ return TRUE;
+}
+
+/* Remove an 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);
+
+ BlueSkyDirent *d = g_hash_table_lookup(dir->dirhash, name);
+ if (d == NULL) {
+ return FALSE;
+ }
+
+ g_hash_table_remove(dir->dirhash, name);
+