UpdateArchive.cxx 3.98 KB
Newer Older
1
/*
Max Kellermann's avatar
Max Kellermann committed
2
 * Copyright (C) 2003-2013 The Music Player Daemon Project
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 * http://www.musicpd.org
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "config.h" /* must be first for large file support */
Max Kellermann's avatar
Max Kellermann committed
21 22
#include "UpdateArchive.hxx"
#include "UpdateInternal.hxx"
Max Kellermann's avatar
Max Kellermann committed
23
#include "DatabaseLock.hxx"
24 25
#include "directory.h"
#include "song.h"
Max Kellermann's avatar
Max Kellermann committed
26 27

extern "C" {
28 29 30
#include "mapper.h"
#include "archive_list.h"
#include "archive_plugin.h"
Max Kellermann's avatar
Max Kellermann committed
31
}
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159

#include <glib.h>

#include <string.h>

static void
update_archive_tree(struct directory *directory, char *name)
{
	char *tmp = strchr(name, '/');
	if (tmp) {
		*tmp = 0;
		//add dir is not there already
		db_lock();
		struct directory *subdir =
			directory_make_child(directory, name);
		subdir->device = DEVICE_INARCHIVE;
		db_unlock();
		//create directories first
		update_archive_tree(subdir, tmp+1);
	} else {
		if (strlen(name) == 0) {
			g_warning("archive returned directory only");
			return;
		}

		//add file
		db_lock();
		struct song *song = directory_get_song(directory, name);
		db_unlock();
		if (song == NULL) {
			song = song_file_load(name, directory);
			if (song != NULL) {
				db_lock();
				directory_add_song(directory, song);
				db_unlock();

				modified = true;
				g_message("added %s/%s",
					  directory_get_path(directory), name);
			}
		}
	}
}

/**
 * Updates the file listing from an archive file.
 *
 * @param parent the parent directory the archive file resides in
 * @param name the UTF-8 encoded base name of the archive file
 * @param st stat() information on the archive file
 * @param plugin the archive plugin which fits this archive type
 */
static void
update_archive_file2(struct directory *parent, const char *name,
		     const struct stat *st,
		     const struct archive_plugin *plugin)
{
	db_lock();
	struct directory *directory = directory_get_child(parent, name);
	db_unlock();

	if (directory != NULL && directory->mtime == st->st_mtime &&
	    !walk_discard)
		/* MPD has already scanned the archive, and it hasn't
		   changed since - don't consider updating it */
		return;

	char *path_fs = map_directory_child_fs(parent, name);

	/* open archive */
	GError *error = NULL;
	struct archive_file *file = archive_file_open(plugin, path_fs, &error);
	if (file == NULL) {
		g_free(path_fs);
		g_warning("%s", error->message);
		g_error_free(error);
		return;
	}

	g_debug("archive %s opened", path_fs);
	g_free(path_fs);

	if (directory == NULL) {
		g_debug("creating archive directory: %s", name);
		db_lock();
		directory = directory_new_child(parent, name);
		/* mark this directory as archive (we use device for
		   this) */
		directory->device = DEVICE_INARCHIVE;
		db_unlock();
	}

	directory->mtime = st->st_mtime;

	archive_file_scan_reset(file);

	char *filepath;
	while ((filepath = archive_file_scan_next(file)) != NULL) {
		/* split name into directory and file */
		g_debug("adding archive file: %s", filepath);
		update_archive_tree(directory, filepath);
	}

	archive_file_close(file);
}

bool
update_archive_file(struct directory *directory,
		    const char *name, const char *suffix,
		    const struct stat *st)
{
#ifdef ENABLE_ARCHIVE
	const struct archive_plugin *plugin =
		archive_plugin_from_suffix(suffix);
	if (plugin == NULL)
		return false;

	update_archive_file2(directory, name, st, plugin);
	return true;
#else
	(void)directory;
	(void)name;
	(void)suffix;
	(void)st;

	return false;
#endif
}