1 /* Copyright (C) 2020 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
3 /** \file upgrade_db.c Prepare the paraslash database for paraslash-0.7. */
9 #include "upgrade_db.lsg.h"
17 #define CMD_PTR (lls_cmd(0, upgrade_db_suite))
18 #define OPT_RESULT(_name, _lpr) \
19 (lls_opt_result(LSG_UPGRADE_DB_PARA_UPGRADE_DB_OPT_ ## _name, lpr))
20 #define OPT_GIVEN(_name, _lpr) (lls_opt_given(OPT_RESULT(_name, _lpr)))
21 #define OPT_UINT32_VAL(_name, _lpr) (lls_uint32_val(0, OPT_RESULT(_name, _lpr)))
22 #define OPT_STRING_VAL(_name, _lpr) (lls_string_val(0, OPT_RESULT(_name, _lpr)))
25 INIT_STDERR_LOGGING(loglevel);
27 /** Array of error strings. */
30 static void handle_help_flag(struct lls_parse_result *lpr)
34 if (OPT_GIVEN(DETAILED_HELP, lpr))
35 help = lls_long_help(CMD_PTR);
36 else if (OPT_GIVEN(HELP, lpr))
37 help = lls_short_help(CMD_PTR);
45 static struct stat *path_exists(const char *path)
47 static struct stat sb;
49 if (stat(path, &sb) < 0)
54 static bool is_dir(const char *path)
56 struct stat *sb = path_exists(path);
59 return (sb->st_mode & S_IFMT) == S_IFDIR;
62 __noreturn static void die(const char *msg)
64 PARA_EMERG_LOG("%s\n", msg);
68 static int string_compare(const struct osl_object *obj1, const struct osl_object *obj2)
70 const char *str1 = obj1->data;
71 const char *str2 = obj2->data;
72 return strncmp(str1, str2, PARA_MIN(obj1->size, obj2->size));
75 static char *src_db_dir, *dst_db_dir, *src_aft_dir, *dst_aft_dir;
77 static void set_paths(const struct lls_parse_result *lpr)
79 const char *home = get_homedir();
81 if (OPT_GIVEN(SRC_DATABASE_DIR, lpr))
82 src_db_dir = para_strdup(OPT_STRING_VAL(SRC_DATABASE_DIR,
85 src_db_dir = make_message(
86 "%s/.paraslash/afs_database-0.4", home);
87 if (OPT_GIVEN(DST_DATABASE_DIR, lpr))
88 dst_db_dir = para_strdup(OPT_STRING_VAL(DST_DATABASE_DIR,
91 dst_db_dir = make_message(
92 "%s/.paraslash/afs_database-0.7", home);
93 src_aft_dir = make_message("%s/audio_files", src_db_dir);
94 dst_aft_dir = make_message("%s/audio-files", src_db_dir);
95 PARA_NOTICE_LOG("source aft dir: %s\n", src_aft_dir);
96 PARA_NOTICE_LOG("destination aft dir: %s\n", dst_aft_dir);
99 static void check_sanity(void)
101 PARA_INFO_LOG("checking source and destination directories\n");
102 if (!is_dir(src_db_dir))
103 die("source db directory does not exist");
104 if (path_exists(dst_db_dir))
105 die("destination db already exists");
106 if (!is_dir(src_aft_dir))
107 die("source audio file table does not exist");
108 if (path_exists(dst_aft_dir))
109 die("destination audio file table already exists");
112 /** The columns of the audio file table (both old and new). */
113 enum audio_file_table_columns {
114 /** The hash on the content of the audio file. */
116 /** The full path in the filesystem. */
118 /** The audio file selector info. */
120 /** The audio format handler info. */
122 /** The chunk table info and the chunk table of the audio file. */
124 /** The number of columns of this table. */
130 static int src_aft_hash_compare(const struct osl_object *obj1,
131 const struct osl_object *obj2)
133 return hash_compare((unsigned char *)obj1->data,
134 (unsigned char *)obj2->data);
137 static struct osl_column_description src_aft_cols[] = {
139 .storage_type = OSL_MAPPED_STORAGE,
140 .storage_flags = OSL_RBTREE | OSL_FIXED_SIZE | OSL_UNIQUE,
142 .compare_function = src_aft_hash_compare,
143 .data_size = HASH_SIZE
146 .storage_type = OSL_MAPPED_STORAGE,
147 .storage_flags = OSL_RBTREE | OSL_UNIQUE,
149 .compare_function = string_compare,
152 .storage_type = OSL_MAPPED_STORAGE,
153 .storage_flags = OSL_FIXED_SIZE,
155 .data_size = AFSI_SIZE
158 .storage_type = OSL_MAPPED_STORAGE,
162 .storage_type = OSL_DISK_STORAGE,
167 static struct osl_table_description src_aft_desc = {
168 .name = "audio_files",
169 .num_columns = NUM_AFT_COLUMNS,
170 .flags = OSL_LARGE_TABLE,
171 .column_descriptions = src_aft_cols
174 static struct osl_table *src_aft, *dst_aft;
176 static void open_src_aft(void)
180 PARA_NOTICE_LOG("opening: %s\n", src_aft_dir);
181 src_aft_desc.dir = src_db_dir;
182 ret = osl(osl_open_table(&src_aft_desc, &src_aft));
184 PARA_EMERG_LOG("can not open source audio file table: %s\n",
185 para_strerror(-ret));
188 PARA_INFO_LOG("successfully opened source audio file table\n");
191 static int dst_aft_hash_compare(const struct osl_object *obj1,
192 const struct osl_object *obj2)
194 return hash2_compare((unsigned char *)obj1->data,
195 (unsigned char *)obj2->data);
198 /* identical to src_aft_cols except the comparator and the hash size. */
199 static struct osl_column_description dst_aft_cols[] = {
201 .storage_type = OSL_MAPPED_STORAGE,
202 .storage_flags = OSL_RBTREE | OSL_FIXED_SIZE | OSL_UNIQUE,
204 .compare_function = dst_aft_hash_compare,
205 .data_size = HASH2_SIZE
208 .storage_type = OSL_MAPPED_STORAGE,
209 .storage_flags = OSL_RBTREE | OSL_UNIQUE,
211 .compare_function = string_compare,
214 .storage_type = OSL_MAPPED_STORAGE,
215 .storage_flags = OSL_FIXED_SIZE,
217 .data_size = AFSI_SIZE
220 .storage_type = OSL_MAPPED_STORAGE,
224 .storage_type = OSL_DISK_STORAGE,
229 static struct osl_table_description dst_aft_desc = {
230 .name = "audio-files",
231 .num_columns = NUM_AFT_COLUMNS,
232 .flags = OSL_LARGE_TABLE,
233 .column_descriptions = dst_aft_cols
236 static int create_and_open_dst_aft(void)
240 PARA_NOTICE_LOG("creating %s\n", dst_aft_dir);
241 dst_aft_desc.dir = src_db_dir;
242 ret = osl(osl_create_table(&dst_aft_desc));
244 PARA_EMERG_LOG("could not create destination audio file table\n");
247 ret = osl(osl_open_table(&dst_aft_desc, &dst_aft));
249 PARA_EMERG_LOG("could not open destination audio file table: %s\n",
250 para_strerror(-ret));
253 PARA_INFO_LOG("successfully opened destination audio file table\n");
257 static int copy_aft_row(struct osl_row *row, void *data)
261 unsigned char hash2[HASH2_SIZE] = "\0";
262 struct osl_object objs[NUM_AFT_COLUMNS] = {
263 [AFTCOL_HASH] = {.data = hash2, .size = HASH2_SIZE}
266 ret = osl(osl_open_disk_object(src_aft, row, AFTCOL_CHUNKS,
267 objs + AFTCOL_CHUNKS));
269 PARA_ERROR_LOG("can not open disk object: %s\n",
270 para_strerror(-ret));
273 for (i = 0; i < NUM_AFT_COLUMNS; i++) {
274 if (i == AFTCOL_HASH) /* never assign to this index */
276 if (i == AFTCOL_CHUNKS) /* disk storage object handled above */
279 ret = osl(osl_get_object(src_aft, row, i, objs + i));
281 PARA_ERROR_LOG("get_object (col = %d): %s\n",
282 i, para_strerror(-ret));
285 if (i == AFTCOL_PATH)
286 PARA_DEBUG_LOG("copying %s\n", (char *)objs[i].data);
289 memcpy(hash2, n, sizeof(*n));
290 ret = osl(osl_add_row(dst_aft, objs));
292 PARA_ERROR_LOG("failed to add row: %s\n", para_strerror(-ret));
293 osl_close_disk_object(objs + AFTCOL_CHUNKS);
297 static int convert_aft(void)
302 osl_get_num_rows(src_aft, &n);
303 PARA_NOTICE_LOG("converting hash of %u rows to sha256\n", n);
305 ret = osl(osl_rbtree_loop(src_aft, AFTCOL_HASH, &n, copy_aft_row));
307 PARA_ERROR_LOG("osl_rbtree_loop failed\n");
311 static int remove_source_aft(void)
314 int fds[3] = {-1, -1, -1}; /* no redirection of stdin/stdout/stderr */
316 char *cmdline = make_message("rm -rf %s", src_aft_dir);
318 PARA_NOTICE_LOG("removing %s\n", src_aft_dir);
319 ret = para_exec_cmdline_pid(&pid, cmdline, fds);
321 PARA_ERROR_LOG("exec failure\n");
325 ret = waitpid(pid, &wstatus, 0);
326 } while (ret < 0 && errno == EINTR);
328 PARA_ERROR_LOG("waitpid failure\n");
333 static int rename_db(void)
335 PARA_NOTICE_LOG("renaming %s -> %s\n", src_db_dir, dst_db_dir);
336 if (rename(src_db_dir, dst_db_dir) < 0) {
337 int ret = -ERRNO_TO_PARA_ERROR(errno);
338 PARA_ERROR_LOG("rename failed\n");
344 int main(int argc, char *argv[])
346 struct lls_parse_result *lpr; /* command line */
350 ret = lls(lls_parse(argc, argv, CMD_PTR, &lpr, &errctx));
353 loglevel = OPT_UINT32_VAL(LOGLEVEL, lpr);
354 version_handle_flag("recv", OPT_GIVEN(VERSION, lpr));
355 handle_help_flag(lpr);
359 ret = create_and_open_dst_aft();
365 ret = remove_source_aft();
370 osl_close_table(dst_aft, OSL_MARK_CLEAN);
372 PARA_INFO_LOG("closing audio file tables\n");
373 osl_close_table(src_aft, OSL_MARK_CLEAN);
377 PARA_ERROR_LOG("%s\n", errctx);
379 PARA_ERROR_LOG("%s\n", para_strerror(-ret));
381 PARA_WARNING_LOG("success. Now start para_server and force-add"
382 " all audio files.\n");
384 return ret < 0? EXIT_FAILURE : EXIT_SUCCESS;