static int _db_and_parsers_setup(lms_t *lms, struct db **db_ret, void ***parser_match_ret) { void **parser_match; struct db *db; int r = 0; db = _db_open(lms->db_path); if (!db) { r = -1; return r; } if (lms_parsers_setup(lms, db->handle) != 0) { fprintf(stderr, "ERROR: could not setup parsers.\n"); r = -2; goto err; } if (_db_compile_all_stmts(db) != 0) { fprintf(stderr, "ERROR: could not compile statements.\n"); r = -3; goto err; } if (lms_parsers_start(lms, db->handle) != 0) { fprintf(stderr, "ERROR: could not start parsers.\n"); r = -4; goto err; } if (lms->n_parsers < 1) { fprintf(stderr, "ERROR: no parser could be started, exit.\n"); r = -5; goto err; } parser_match = malloc(lms->n_parsers * sizeof(*parser_match)); if (!parser_match) { perror("malloc"); r = -6; goto err; } *parser_match_ret = parser_match; *db_ret = db; return r; err: lms_parsers_finish(lms, db->handle); _db_close(db); return r; }
/** * Process the given directory or file *without fork()-ing* into child process. * * This will add or update media found in the given directory or its children. * Note that if a parser hangs during the process, this call will also hang. * * @param lms previously allocated Light Media Scanner instance. * @param top_path top directory or file to scan. * * @return On success 0 is returned. */ int lms_process_single_process(lms_t *lms, const char *top_path) { struct sinfo sinfo; int r; r = _lms_process_check_valid(lms, top_path); if (r < 0) return r; sinfo.common.lms = lms; sinfo.commit_counter = 0; sinfo.total_committed = 0; r = _db_and_parsers_setup(sinfo.common.lms, &sinfo.db, &sinfo.parser_match); if (r < 0) return r; r = lms_db_update_id_get(sinfo.db->handle); if (r < 0) { fprintf(stderr, "ERROR: could not get global update id.\n"); goto done; } sinfo.common.update_id = r + 1; lms_db_begin_transaction(sinfo.db->transaction_begin); r = _process_trigger(&sinfo.common, top_path, _process_file_single_process); /* Check only if there are remaining commits to do */ if (sinfo.commit_counter) { sinfo.total_committed += sinfo.commit_counter; lms_db_update_id_set(sinfo.db->handle, sinfo.common.update_id); } lms_db_end_transaction(sinfo.db->transaction_commit); done: free(sinfo.parser_match); lms_parsers_finish(lms, sinfo.db->handle); _db_close(sinfo.db); return r; }
/* * conv_esdb: * external representation -> local structure. */ static int conv_esdb(struct _citrus_esdb *esdb, struct _region *fr) { struct _citrus_db *db; const char *str; char buf[100]; uint32_t csid, i, num_charsets, tmp, version; int ret; /* open db */ ret = _db_open(&db, fr, _CITRUS_ESDB_MAGIC, &_db_hash_std, NULL); if (ret) goto err0; /* check version */ ret = _db_lookup32_by_s(db, _CITRUS_ESDB_SYM_VERSION, &version, NULL); if (ret) goto err1; switch (version) { case 0x00000001: /* current version */ /* initial version */ break; default: ret = EFTYPE; goto err1; } /* get encoding/variable */ ret = _db_lookupstr_by_s(db, _CITRUS_ESDB_SYM_ENCODING, &str, NULL); if (ret) goto err1; esdb->db_encname = strdup(str); if (esdb->db_encname == NULL) { ret = errno; goto err1; } esdb->db_len_variable = 0; esdb->db_variable = NULL; ret = _db_lookupstr_by_s(db, _CITRUS_ESDB_SYM_VARIABLE, &str, NULL); if (ret == 0) { esdb->db_len_variable = strlen(str) + 1; esdb->db_variable = strdup(str); if (esdb->db_variable == NULL) { ret = errno; goto err2; } } else if (ret != ENOENT) goto err2; /* get number of charsets */ ret = _db_lookup32_by_s(db, _CITRUS_ESDB_SYM_NUM_CHARSETS, &num_charsets, NULL); if (ret) goto err3; esdb->db_num_charsets = num_charsets; /* get invalid character */ ret = _db_lookup32_by_s(db, _CITRUS_ESDB_SYM_INVALID, &tmp, NULL); if (ret == 0) { esdb->db_use_invalid = 1; esdb->db_invalid = tmp; } else if (ret == ENOENT) esdb->db_use_invalid = 0; else goto err3; /* get charsets */ esdb->db_charsets = malloc(num_charsets * sizeof(*esdb->db_charsets)); if (esdb->db_charsets == NULL) { ret = errno; goto err3; } for (i = 0; i < num_charsets; i++) { snprintf(buf, sizeof(buf), _CITRUS_ESDB_SYM_CSID_PREFIX "%d", i); ret = _db_lookup32_by_s(db, buf, &csid, NULL); if (ret) goto err4; esdb->db_charsets[i].ec_csid = csid; snprintf(buf, sizeof(buf), _CITRUS_ESDB_SYM_CSNAME_PREFIX "%d", i); ret = _db_lookupstr_by_s(db, buf, &str, NULL); if (ret) goto err4; esdb->db_charsets[i].ec_csname = strdup(str); if (esdb->db_charsets[i].ec_csname == NULL) { ret = errno; goto err4; } } _db_close(db); return (0); err4: for (; i > 0; i--) free(esdb->db_charsets[i - 1].ec_csname); free(esdb->db_charsets); err3: free(esdb->db_variable); err2: free(esdb->db_encname); err1: _db_close(db); if (ret == ENOENT) ret = EFTYPE; err0: return (ret); }
static int find_best_pivot_pvdb(const char *src, const char *dst, char *pivot, size_t pvlen, unsigned long *rnorm) { int ret, num, i; struct _region fr, r1, r2; struct _citrus_db *db1, *db2, *db3; char buf[LINE_MAX]; unsigned long norm; uint32_t val32; ret = _map_file(&fr, CS_PIVOT ".pvdb"); if (ret) { if (ret == ENOENT) ret = NO_SUCH_FILE; return ret; } ret = _db_open(&db1, &fr, _CITRUS_PIVOT_MAGIC, _db_hash_std, NULL); if (ret) goto quit1; ret = open_subdb(&db2, db1, src); if (ret) goto quit2; num = _db_get_num_entries(db2); *rnorm = ULONG_MAX; for (i = 0; i < num; i++) { /* iterate each pivot */ ret = _db_get_entry(db2, i, &r1, &r2); if (ret) goto quit3; /* r1:pivot name, r2:norm among src and pivot */ ret = get32(&r2, &val32); if (ret) goto quit3; norm = val32; snprintf(buf, sizeof(buf), "%.*s", (int)_region_size(&r1), (char *)_region_head(&r1)); /* buf: pivot name */ ret = open_subdb(&db3, db1, buf); if (ret) goto quit3; if (_db_lookup_by_s(db3, dst, &r2, NULL) != 0) /* don't break the loop, test all src/dst pairs. */ goto quit4; /* r2: norm among pivot and dst */ ret = get32(&r2, &val32); if (ret) goto quit4; norm += val32; /* judge minimum norm */ if (norm < *rnorm) { *rnorm = norm; strlcpy(pivot, buf, pvlen); } quit4: _db_close(db3); if (ret) goto quit3; } quit3: _db_close(db2); quit2: _db_close(db1); quit1: _unmap_file(&fr); if (ret) return ret; if (*rnorm == ULONG_MAX) return ENOENT; return 0; }
static void seq_close_db(struct _citrus_lookup *cl) { _db_close(cl->cl_db); _unmap_file(&cl->cl_dbfile); }
static int _slave_work(struct pinfo *pinfo) { lms_t *lms = pinfo->common.lms; struct fds *fds = &pinfo->slave; int r, len, base; char path[PATH_SIZE]; void **parser_match; struct db *db; unsigned int total_committed, counter; r = _db_and_parsers_setup(lms, &db, &parser_match); if (r < 0) return r; r = lms_db_update_id_get(db->handle); if (r < 0) { fprintf(stderr, "ERROR: could not get global update id.\n"); goto done; } pinfo->common.update_id = r + 1; counter = 0; total_committed = 0; lms_db_begin_transaction(db->transaction_begin); while (((r = _slave_recv_path(fds, &len, &base, path)) == 0) && len > 0) { r = _db_and_parsers_process_file( lms, db, parser_match, path, len, base, pinfo->common.update_id); _slave_send_reply(fds, r); if (r < 0 || (r == LMS_PROGRESS_STATUS_UP_TO_DATE || r == LMS_PROGRESS_STATUS_SKIPPED)) continue; counter++; if (counter > lms->commit_interval) { if (!total_committed) { total_committed += counter; lms_db_update_id_set(db->handle, pinfo->common.update_id); } lms_db_end_transaction(db->transaction_commit); lms_db_begin_transaction(db->transaction_begin); counter = 0; } } if (counter) { total_committed += counter; lms_db_update_id_set(db->handle, pinfo->common.update_id); } lms_db_end_transaction(db->transaction_commit); done: free(parser_match); lms_parsers_finish(lms, db->handle); _db_close(db); return r; }