Commit 420a4c16 authored by Max Kellermann's avatar Max Kellermann

directory: simplify constructors and clarify API documentation

Pass only the "name" to a directory, instead of the full (relative) path.
parent 1bab7355
...@@ -199,7 +199,7 @@ simple_db_open(struct db *_db, G_GNUC_UNUSED GError **error_r) ...@@ -199,7 +199,7 @@ simple_db_open(struct db *_db, G_GNUC_UNUSED GError **error_r)
{ {
struct simple_db *db = (struct simple_db *)_db; struct simple_db *db = (struct simple_db *)_db;
db->root = directory_new("", NULL); db->root = directory_new_root();
db->mtime = 0; db->mtime = 0;
GError *error = NULL; GError *error = NULL;
...@@ -212,7 +212,7 @@ simple_db_open(struct db *_db, G_GNUC_UNUSED GError **error_r) ...@@ -212,7 +212,7 @@ simple_db_open(struct db *_db, G_GNUC_UNUSED GError **error_r)
if (!simple_db_check(db, error_r)) if (!simple_db_check(db, error_r))
return false; return false;
db->root = directory_new("", NULL); db->root = directory_new_root();
} }
return true; return true;
......
...@@ -66,12 +66,47 @@ directory_free(struct directory *directory) ...@@ -66,12 +66,47 @@ directory_free(struct directory *directory)
/*directory_get_path(NULL); */ /*directory_get_path(NULL); */
} }
void
directory_delete(struct directory *directory)
{
assert(directory != NULL);
assert(directory->parent != NULL);
dirvec_delete(&directory->parent->children, directory);
directory_free(directory);
}
const char * const char *
directory_get_name(const struct directory *directory) directory_get_name(const struct directory *directory)
{ {
return g_basename(directory->path); return g_basename(directory->path);
} }
struct directory *
directory_new_child(struct directory *parent, const char *name_utf8)
{
assert(parent != NULL);
assert(name_utf8 != NULL);
assert(*name_utf8 != 0);
char *allocated;
const char *path_utf8;
if (directory_is_root(parent)) {
allocated = NULL;
path_utf8 = name_utf8;
} else {
allocated = g_strconcat(directory_get_path(parent),
"/", name_utf8, NULL);
path_utf8 = allocated;
}
struct directory *directory = directory_new(path_utf8, parent);
g_free(allocated);
dirvec_add(&parent->children, directory);
return directory;
}
void void
directory_prune_empty(struct directory *directory) directory_prune_empty(struct directory *directory)
{ {
...@@ -83,10 +118,8 @@ directory_prune_empty(struct directory *directory) ...@@ -83,10 +118,8 @@ directory_prune_empty(struct directory *directory)
directory_prune_empty(child); directory_prune_empty(child);
if (directory_is_empty(child)) { if (directory_is_empty(child))
dirvec_delete(dv, child); directory_delete(child);
directory_free(child);
}
} }
if (!dv->nr) if (!dv->nr)
dirvec_destroy(dv); dirvec_destroy(dv);
......
...@@ -56,12 +56,37 @@ isRootDirectory(const char *name) ...@@ -56,12 +56,37 @@ isRootDirectory(const char *name)
return name[0] == 0 || (name[0] == '/' && name[1] == 0); return name[0] == 0 || (name[0] == '/' && name[1] == 0);
} }
/**
* Generic constructor for #directory object.
*/
G_GNUC_MALLOC
struct directory * struct directory *
directory_new(const char *dirname, struct directory *parent); directory_new(const char *dirname, struct directory *parent);
/**
* Create a new root #directory object.
*/
G_GNUC_MALLOC
static inline struct directory *
directory_new_root(void)
{
return directory_new("", NULL);
}
/**
* Free this #directory object (and the whole object tree within it),
* assuming it was already removed from the parent.
*/
void void
directory_free(struct directory *directory); directory_free(struct directory *directory);
/**
* Remove this #directory object from its parent and free it. This
* must not be called with the root directory.
*/
void
directory_delete(struct directory *directory);
static inline bool static inline bool
directory_is_empty(const struct directory *directory) directory_is_empty(const struct directory *directory)
{ {
...@@ -87,6 +112,7 @@ directory_is_root(const struct directory *directory) ...@@ -87,6 +112,7 @@ directory_is_root(const struct directory *directory)
/** /**
* Returns the base name of the directory. * Returns the base name of the directory.
*/ */
G_GNUC_PURE
const char * const char *
directory_get_name(const struct directory *directory); directory_get_name(const struct directory *directory);
...@@ -96,12 +122,27 @@ directory_get_child(const struct directory *directory, const char *name) ...@@ -96,12 +122,27 @@ directory_get_child(const struct directory *directory, const char *name)
return dirvec_find(&directory->children, name); return dirvec_find(&directory->children, name);
} }
/**
* Create a new #directory object as a child of the given one.
*
* @param parent the parent directory the new one will be added to
* @param name_utf8 the UTF-8 encoded name of the new sub directory
*/
G_GNUC_MALLOC
struct directory *
directory_new_child(struct directory *parent, const char *name_utf8);
/**
* Look up a sub directory, and create the object if it does not
* exist.
*/
static inline struct directory * static inline struct directory *
directory_new_child(struct directory *directory, const char *name) directory_make_child(struct directory *directory, const char *name_utf8)
{ {
struct directory *subdir = directory_new(name, directory); struct directory *child = directory_get_child(directory, name_utf8);
dirvec_add(&directory->children, subdir); if (child == NULL)
return subdir; child = directory_new_child(directory, name_utf8);
return child;
} }
void void
......
...@@ -81,7 +81,6 @@ static struct directory * ...@@ -81,7 +81,6 @@ static struct directory *
directory_load_subdir(FILE *fp, struct directory *parent, const char *name, directory_load_subdir(FILE *fp, struct directory *parent, const char *name,
GString *buffer, GError **error_r) GString *buffer, GError **error_r)
{ {
struct directory *directory;
const char *line; const char *line;
bool success; bool success;
...@@ -91,20 +90,13 @@ directory_load_subdir(FILE *fp, struct directory *parent, const char *name, ...@@ -91,20 +90,13 @@ directory_load_subdir(FILE *fp, struct directory *parent, const char *name,
return NULL; return NULL;
} }
if (directory_is_root(parent)) { struct directory *directory = directory_new_child(parent, name);
directory = directory_new(name, parent);
} else {
char *path = g_strconcat(directory_get_path(parent), "/",
name, NULL);
directory = directory_new(path, parent);
g_free(path);
}
line = read_text_line(fp, buffer); line = read_text_line(fp, buffer);
if (line == NULL) { if (line == NULL) {
g_set_error(error_r, directory_quark(), 0, g_set_error(error_r, directory_quark(), 0,
"Unexpected end of file"); "Unexpected end of file");
directory_free(directory); directory_delete(directory);
return NULL; return NULL;
} }
...@@ -117,7 +109,7 @@ directory_load_subdir(FILE *fp, struct directory *parent, const char *name, ...@@ -117,7 +109,7 @@ directory_load_subdir(FILE *fp, struct directory *parent, const char *name,
if (line == NULL) { if (line == NULL) {
g_set_error(error_r, directory_quark(), 0, g_set_error(error_r, directory_quark(), 0,
"Unexpected end of file"); "Unexpected end of file");
directory_free(directory); directory_delete(directory);
return NULL; return NULL;
} }
} }
...@@ -125,13 +117,13 @@ directory_load_subdir(FILE *fp, struct directory *parent, const char *name, ...@@ -125,13 +117,13 @@ directory_load_subdir(FILE *fp, struct directory *parent, const char *name,
if (!g_str_has_prefix(line, DIRECTORY_BEGIN)) { if (!g_str_has_prefix(line, DIRECTORY_BEGIN)) {
g_set_error(error_r, directory_quark(), 0, g_set_error(error_r, directory_quark(), 0,
"Malformed line: %s", line); "Malformed line: %s", line);
directory_free(directory); directory_delete(directory);
return NULL; return NULL;
} }
success = directory_load(fp, directory, buffer, error_r); success = directory_load(fp, directory, buffer, error_r);
if (!success) { if (!success) {
directory_free(directory); directory_delete(directory);
return NULL; return NULL;
} }
...@@ -153,8 +145,6 @@ directory_load(FILE *fp, struct directory *directory, ...@@ -153,8 +145,6 @@ directory_load(FILE *fp, struct directory *directory,
buffer, error); buffer, error);
if (subdir == NULL) if (subdir == NULL)
return false; return false;
dirvec_add(&directory->children, subdir);
} else if (g_str_has_prefix(line, SONG_BEGIN)) { } else if (g_str_has_prefix(line, SONG_BEGIN)) {
const char *name = line + sizeof(SONG_BEGIN) - 1; const char *name = line + sizeof(SONG_BEGIN) - 1;
struct song *song; struct song *song;
......
...@@ -140,9 +140,7 @@ delete_directory(struct directory *directory) ...@@ -140,9 +140,7 @@ delete_directory(struct directory *directory)
assert(directory->parent != NULL); assert(directory->parent != NULL);
clear_directory(directory); clear_directory(directory);
directory_delete(directory);
dirvec_delete(&directory->parent->children, directory);
directory_free(directory);
} }
static void static void
...@@ -272,7 +270,6 @@ removeDeletedFromDirectory(struct directory *directory) ...@@ -272,7 +270,6 @@ removeDeletedFromDirectory(struct directory *directory)
if (directory_exists(dv->base[i])) if (directory_exists(dv->base[i]))
continue; continue;
g_debug("removing directory: %s", dv->base[i]->path);
delete_directory(dv->base[i]); delete_directory(dv->base[i]);
modified = true; modified = true;
} }
...@@ -363,28 +360,6 @@ inodeFoundInParent(struct directory *parent, ino_t inode, dev_t device) ...@@ -363,28 +360,6 @@ inodeFoundInParent(struct directory *parent, ino_t inode, dev_t device)
return 0; return 0;
} }
static struct directory *
make_subdir(struct directory *parent, const char *name)
{
struct directory *directory;
directory = directory_get_child(parent, name);
if (directory == NULL) {
char *path;
if (directory_is_root(parent))
path = NULL;
else
name = path = g_strconcat(directory_get_path(parent),
"/", name, NULL);
directory = directory_new_child(parent, name);
g_free(path);
}
return directory;
}
#ifdef ENABLE_ARCHIVE #ifdef ENABLE_ARCHIVE
static void static void
update_archive_tree(struct directory *directory, char *name) update_archive_tree(struct directory *directory, char *name)
...@@ -397,9 +372,9 @@ update_archive_tree(struct directory *directory, char *name) ...@@ -397,9 +372,9 @@ update_archive_tree(struct directory *directory, char *name)
if (tmp) { if (tmp) {
*tmp = 0; *tmp = 0;
//add dir is not there already //add dir is not there already
if ((subdir = dirvec_find(&directory->children, name)) == NULL) { if ((subdir = directory_get_child(directory, name)) == NULL) {
//create new directory //create new directory
subdir = make_subdir(directory, name); subdir = directory_new_child(directory, name);
subdir->device = DEVICE_INARCHIVE; subdir->device = DEVICE_INARCHIVE;
} }
//create directories first //create directories first
...@@ -442,7 +417,7 @@ update_archive_file(struct directory *parent, const char *name, ...@@ -442,7 +417,7 @@ update_archive_file(struct directory *parent, const char *name,
struct directory *directory; struct directory *directory;
char *filepath; char *filepath;
directory = dirvec_find(&parent->children, name); directory = directory_get_child(parent, name);
if (directory != NULL && directory->mtime == st->st_mtime && if (directory != NULL && directory->mtime == st->st_mtime &&
!walk_discard) !walk_discard)
/* MPD has already scanned the archive, and it hasn't /* MPD has already scanned the archive, and it hasn't
...@@ -465,7 +440,7 @@ update_archive_file(struct directory *parent, const char *name, ...@@ -465,7 +440,7 @@ update_archive_file(struct directory *parent, const char *name,
if (directory == NULL) { if (directory == NULL) {
g_debug("creating archive directory: %s", name); g_debug("creating archive directory: %s", name);
directory = make_subdir(parent, name); directory = directory_new_child(parent, name);
/* mark this directory as archive (we use device for /* mark this directory as archive (we use device for
this) */ this) */
directory->device = DEVICE_INARCHIVE; directory->device = DEVICE_INARCHIVE;
...@@ -494,7 +469,7 @@ update_container_file( struct directory* directory, ...@@ -494,7 +469,7 @@ update_container_file( struct directory* directory,
char* vtrack = NULL; char* vtrack = NULL;
unsigned int tnum = 0; unsigned int tnum = 0;
char* pathname = map_directory_child_fs(directory, name); char* pathname = map_directory_child_fs(directory, name);
struct directory* contdir = dirvec_find(&directory->children, name); struct directory *contdir = directory_get_child(directory, name);
// directory exists already // directory exists already
if (contdir != NULL) if (contdir != NULL)
...@@ -515,7 +490,7 @@ update_container_file( struct directory* directory, ...@@ -515,7 +490,7 @@ update_container_file( struct directory* directory,
} }
} }
contdir = make_subdir(directory, name); contdir = directory_make_child(directory, name);
contdir->mtime = st->st_mtime; contdir->mtime = st->st_mtime;
contdir->device = DEVICE_CONTAINER; contdir->device = DEVICE_CONTAINER;
...@@ -670,7 +645,7 @@ updateInDirectory(struct directory *directory, ...@@ -670,7 +645,7 @@ updateInDirectory(struct directory *directory,
if (inodeFoundInParent(directory, st->st_ino, st->st_dev)) if (inodeFoundInParent(directory, st->st_ino, st->st_dev))
return; return;
subdir = make_subdir(directory, name); subdir = directory_make_child(directory, name);
assert(directory == subdir->parent); assert(directory == subdir->parent);
ret = updateDirectory(subdir, st); ret = updateDirectory(subdir, st);
...@@ -829,34 +804,27 @@ updateDirectory(struct directory *directory, const struct stat *st) ...@@ -829,34 +804,27 @@ updateDirectory(struct directory *directory, const struct stat *st)
} }
static struct directory * static struct directory *
directory_make_child_checked(struct directory *parent, const char *path) directory_make_child_checked(struct directory *parent, const char *name_utf8)
{ {
struct directory *directory; struct directory *directory;
char *base;
struct stat st; struct stat st;
struct song *conflicting; struct song *conflicting;
directory = directory_get_child(parent, path); directory = directory_get_child(parent, name_utf8);
if (directory != NULL) if (directory != NULL)
return directory; return directory;
base = g_path_get_basename(path); if (stat_directory_child(parent, name_utf8, &st) < 0 ||
inodeFoundInParent(parent, st.st_ino, st.st_dev))
if (stat_directory_child(parent, base, &st) < 0 ||
inodeFoundInParent(parent, st.st_ino, st.st_dev)) {
g_free(base);
return NULL; return NULL;
}
/* if we're adding directory paths, make sure to delete filenames /* if we're adding directory paths, make sure to delete filenames
with potentially the same name */ with potentially the same name */
conflicting = songvec_find(&parent->songs, base); conflicting = songvec_find(&parent->songs, name_utf8);
if (conflicting) if (conflicting)
delete_song(parent, conflicting); delete_song(parent, conflicting);
g_free(base); directory = directory_new_child(parent, name_utf8);
directory = directory_new_child(parent, path);
directory_set_stat(directory, &st); directory_set_stat(directory, &st);
return directory; return directory;
} }
...@@ -866,17 +834,20 @@ addParentPathToDB(const char *utf8path) ...@@ -866,17 +834,20 @@ addParentPathToDB(const char *utf8path)
{ {
struct directory *directory = db_get_root(); struct directory *directory = db_get_root();
char *duplicated = g_strdup(utf8path); char *duplicated = g_strdup(utf8path);
char *slash = duplicated; char *name_utf8 = duplicated, *slash;
while ((slash = strchr(slash, '/')) != NULL) { while ((slash = strchr(name_utf8, '/')) != NULL) {
*slash = 0; *slash = 0;
if (*name_utf8 == 0)
continue;
directory = directory_make_child_checked(directory, directory = directory_make_child_checked(directory,
duplicated); name_utf8);
if (directory == NULL || slash == NULL) if (directory == NULL)
break; break;
*slash++ = '/'; name_utf8 = slash + 1;
} }
g_free(duplicated); g_free(duplicated);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment