X-Git-Url: http://git.vrable.net/?a=blobdiff_plain;f=dir.c;h=eab71bef2c5a3837ebf6b47769231bb0f3ba4e63;hb=8819789ef2264b26aebfae489932a447f6e0f65f;hp=c4cbec20cbd0d8a71d115cf90cf2e41599e47072;hpb=a6d16121ebce069728e454b9bd4c5716d59c8809;p=bluesky.git diff --git a/dir.c b/dir.c index c4cbec2..eab71be 100644 --- a/dir.c +++ b/dir.c @@ -16,7 +16,8 @@ /* Hash a filename for a directory lookup. The string is hashed to a 64-bit * value. It is guaranteed that the hash values 0, 1, and 2 are never returned * (to allow the hash value to be used as an NFS cookie for a READDIR - * operation). */ + * operation). TODO: We perhaps should make this a keyed hash, and may want to + * use something cheaper than MD5 to compute. */ uint64_t bluesky_directory_hash(gchar *name) { GChecksum *csum = g_checksum_new(G_CHECKSUM_MD5); @@ -73,17 +74,22 @@ uint64_t bluesky_directory_lookup(BlueSkyInode *inode, gchar *name) BlueSkyDirent d = {name, hash, 0}; GSequenceIter *i = g_sequence_search(inode->dirents, &d, bluesky_dirent_compare, NULL); + + /* g_sequence_search will return an iterator pointing just beyond the + * desired node if there is a match, so that when inserting the new node + * will go after the match. But we are trying to do a lookup, so back up + * by one position. */ i = g_sequence_iter_prev(i); if (g_sequence_iter_is_end(i)) return 0; BlueSkyDirent *dirent = g_sequence_get(i); - g_print("Lookup(%s) -> 0x%016llx\n", name, dirent->hash); if (dirent->hash != hash) return 0; if (g_strcmp0(name, dirent->name) != 0) return 0; + g_print("Lookup(%s) -> 0x%016llx\n", name, dirent->hash); return dirent->inum; } @@ -96,13 +102,24 @@ gboolean bluesky_directory_insert(BlueSkyInode *dir, gchar *name, uint64_t inum) uint64_t hash = bluesky_directory_hash(name); BlueSkyDirent *d = g_new(BlueSkyDirent, 1); - d->name = name; + d->name = g_strdup(name); d->hash = hash; d->inum = inum; GSequenceIter *i = g_sequence_search(dir->dirents, d, bluesky_dirent_compare, NULL); + + /* If a directory entry already exists, return failure. The caller must + * delete the old entry and try again. TODO: We'll fail on a hash + * collision; we should handle that case. */ + if (!g_sequence_iter_is_end(g_sequence_iter_prev(i))) { + BlueSkyDirent *d2 = g_sequence_get(g_sequence_iter_prev(i)); + if (d2->hash == hash) + return FALSE; + } + g_sequence_insert_before(i, d); + dir->change_count++; return TRUE; }