X-Git-Url: http://git.vrable.net/?a=blobdiff_plain;f=bluesky%2Fdir.c;h=65827861c2ab26302ad22c9798b6ecc732a9efae;hb=8ff0fd08d6e1cc97cdb7e94b7cd97dc28c29e674;hp=14eb6eb13fb4a78cb477cce7a61ae2580247e18f;hpb=92a6fa8cd45e12f70f65f9d9fc6d1cdd6592878a;p=bluesky.git diff --git a/bluesky/dir.c b/bluesky/dir.c index 14eb6eb..6582786 100644 --- a/bluesky/dir.c +++ b/bluesky/dir.c @@ -3,14 +3,36 @@ * Copyright (C) 2009 The Regents of the University of California * Written by Michael Vrable * - * TODO: Licensing + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ #include #include #include -#include "bluesky.h" +#include "bluesky-private.h" /* Core filesystem: handling of directories. */ @@ -18,6 +40,7 @@ void bluesky_dirent_destroy(gpointer data) { BlueSkyDirent *dirent = (BlueSkyDirent *)data; g_free(dirent->name); + g_free(dirent->name_folded); g_free(dirent); } @@ -50,9 +73,42 @@ uint64_t bluesky_directory_lookup(BlueSkyInode *inode, gchar *name) 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); @@ -62,6 +118,7 @@ gboolean bluesky_directory_insert(BlueSkyInode *dir, gchar *name, uint64_t inum) BlueSkyDirent *d = g_new(BlueSkyDirent, 1); d->name = g_strdup(name); + d->name_folded = bluesky_lowercase(name); d->inum = inum; GSequence *dirents = dir->dirents; @@ -94,15 +151,16 @@ gboolean bluesky_directory_insert(BlueSkyInode *dir, gchar *name, uint64_t inum) /* 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); @@ -112,7 +170,8 @@ gboolean bluesky_directory_remove(BlueSkyInode *dir, gchar *name) 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); @@ -124,7 +183,48 @@ gboolean bluesky_directory_remove(BlueSkyInode *dir, gchar *name) g_sequence_remove(i); bluesky_inode_update_ctime(dir, 1); - bluesky_inode_flush(dir->fs, dir); + + 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; }