update: better package database

This commit is contained in:
ngn 2024-08-15 02:16:16 +03:00
parent e0f0dec222
commit 472cb9004e
11 changed files with 424 additions and 371 deletions

View File

@ -4,39 +4,26 @@
#include <sqlite3.h>
#include <stdbool.h>
#include <stdio.h>
#include <sys/types.h>
#define HASH_LEN 32
enum lm_query_index {
QUERY_CREATE_ENTRY_TABLE = 0,
QUERY_INSERT_ENTRY_SINGLE = 1,
QUERY_SELECT_ENTRY_SINGLE_1 = 2,
QUERY_SELECT_ENTRY_SINGLE_2 = 3,
QUERY_DELETE_ENTRY_SINGLE = 4,
QUERY_SELECT_ENTRY_ALL = 5,
QUERY_CREATE_FILE_TABLE = 6,
QUERY_INSERT_FILE_SINGLE = 7,
QUERY_DELETE_FILE_ALL = 8,
QUERY_DELETE_FILE_SINGLE = 9,
QUERY_SELECT_FILE_ALL = 10,
QUERY_SELECT_FILE_SINGLE = 11,
QUERY_UPDATE_FILE_1 = 12,
QUERY_UPDATE_FILE_2 = 13,
QUERY_CREATE_TABLE = 0,
QUERY_INSERT_SINGLE = 1,
QUERY_SELECT_SINGLE_1 = 2,
QUERY_SELECT_SINGLE_2 = 3,
QUERY_DELETE_SINGLE = 4,
QUERY_SELECT_ALL = 5,
};
enum lm_columns {
FILES_COLUMN_PATH = 1,
FILES_COLUMN_HASH = 2,
FILES_COLUMN_KEEP = 3,
FILES_COLUMN_ENTRY = 4,
ENTRIES_COLUMN_NAME = 1,
ENTRIES_COLUMN_VERSION = 2,
ENTRIES_COLUMN_DESC = 3,
ENTRIES_COLUMN_SIZE = 4,
ENTRIES_COLUMN_DEPENDS = 5,
COLUMN_NAME = 1,
COLUMN_VERSION = 2,
COLUMN_DESC = 3,
COLUMN_SIZE = 4,
COLUMN_DEPENDS = 5,
};
extern char *queries[];
@ -44,12 +31,9 @@ extern char *queries[];
typedef lm_pkg_data_t lm_entry_t;
typedef struct lm_database {
sqlite3 *entries_db;
sqlite3_stmt *entries_st;
sqlite3 *files_db;
sqlite3_stmt *files_st;
sqlite3 *sql;
sqlite3_stmt *st;
FILE *filesp;
char *dir;
} lm_database_t;
@ -79,8 +63,9 @@ bool lm_database_files_next(
lm_database_t *db, lm_entry_t *entry, char **path, char **hash, bool *keep); // gets the next file of the entry
bool lm_database_files_add(
lm_database_t *db, lm_entry_t *entry, char *path, char *hash); // adds a file to the files database
bool lm_database_files_del(lm_database_t *db, lm_entry_t *entry); // dels all files of belonging to a entry
bool lm_database_files_del_single(lm_database_t *db, char *path);
bool lm_database_files_del(
lm_database_t *db, lm_entry_t *entry); // dels files belonging to an entry that is not set as KEEP
bool lm_database_files_del_all(lm_database_t *db, lm_entry_t *entry); // dels all files of belonging to an entry
void lm_database_files_next_free(lm_database_t *db, lm_entry_t *entry, char **path, char **hash,
bool *keep); // frees resources used for lm_database_files_next

View File

@ -81,7 +81,7 @@ typedef enum lm_error {
LM_ERR_DbFilesOpenFail = 80,
LM_ERR_DbFilesDirFail = 81,
LM_ERR_DbFilesUnlinkFail = 82,
LM_ERR_DbFilesWriteFail = 83,
LM_ERR_DbFilesRenameFail = 83,
LM_ERR_DbKeepsNotFound = 84,
LM_ERR_DbKeepsOpenFail = 85,
LM_ERR_DbKeepsDirFail = 86,

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-08-11 01:42+0300\n"
"POT-Creation-Date: 2024-08-15 02:14+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -352,23 +352,27 @@ msgid "pool directory sub-paths are not accessible"
msgstr ""
#: src/error.c:100
msgid "package file list not found in the database"
msgid "file list not found for the package"
msgstr ""
#: src/error.c:101
msgid "failed to open package file list in the database"
#, c-format
msgid "failed to rename the file list for the package: %s"
msgstr ""
#: src/error.c:102
msgid "failed to access package file list database directory"
#, c-format
msgid "failed to open the package file list: %s"
msgstr ""
#: src/error.c:103
msgid "failed to remove package file list from the database"
#, c-format
msgid "failed to open the database directory: %s"
msgstr ""
#: src/error.c:104
msgid "failed to write to the file list in the database"
#, c-format
msgid "failed to remove package file list: %s"
msgstr ""
#: src/error.c:105

View File

@ -47,7 +47,8 @@ bool lm_ctx_check(lm_ctx_t *ctx, lm_entry_t *entry, lm_ctx_check_callback_t call
if(S_ISLNK(st.st_mode)){
pdebug(__func__, "%s seems to be a link, no hash verification to do", fp);
if(hash[0] != '\0'){
// hashes for links are just "#" chars
if(hash[0] != '#'){
lm_error_set(LM_ERR_FileNotLink, fp);
goto end;
}

View File

@ -137,14 +137,14 @@ bool __lm_ctx_extract_files(lm_ctx_t *ctx, lm_pkg_t *pkg, char *files, lm_ctx_in
current += archive_entry_size(entry);
type = archive_entry_filetype(entry);
if(exists(entry_path, NULL) && lm_database_files_iskeep(ctx->db, entry_path)){
if(exists(entry_path, NULL) && lm_package_data_keep_contains(&pkg->data, entry_path)){
pdebug(__func__, "not extracting %s, file is set as KEEP", entry_path);
continue;
}
switch (type) {
case AE_IFLNK:
if(!lm_database_files_add(ctx->db, &pkg->data, entry_path, "")){
if(!lm_database_files_add(ctx->db, &pkg->data, "################################", entry_path)){
char *suberr = lm_strerror_dup();
pdebug(__func__, "failed to add link to the database for %s: %s", pkg->data.name, suberr);
lm_error_set(LM_ERR_PkgFilesAddFail, entry_path, suberr);
@ -271,6 +271,8 @@ bool lm_ctx_install(lm_ctx_t *ctx, lm_pkg_t *pkg, bool run_install, lm_ctx_insta
goto end;
}
pdebug(__func__, "updating changes file for %s", pkg->data.name);
if(!lm_database_changes_update(ctx->db, &pkg->data, files->changes_file)){
char *suberr = lm_strerror_dup();
pdebug(__func__, "failed to update changes file for %s: %s", pkg->data.name, suberr);
@ -284,6 +286,13 @@ bool lm_ctx_install(lm_ctx_t *ctx, lm_pkg_t *pkg, bool run_install, lm_ctx_insta
goto end;
}
pdebug(__func__, "deleting file list for %s", pkg->data.name);
if(!lm_database_files_del_all(ctx->db, &pkg->data)){
pdebug(__func__, "failed to remove file list for %s: %s", pkg->data.name, lm_error());
goto end;
}
while((line_len = getline(&line, (size_t*)&line_len, hashes)) > 0){
if(NULL == line)
goto next;
@ -306,12 +315,7 @@ bool lm_ctx_install(lm_ctx_t *ctx, lm_pkg_t *pkg, bool run_install, lm_ctx_insta
pdebug(__func__, "(%lu) %s => %s", line_len, file, hash);
if(!lm_database_files_del_single(ctx->db, file)){
pdebug(__func__, "failed to remove file from the database for %s: %s", pkg->data.name, lm_error());
goto end;
}
if(!lm_database_files_add(ctx->db, &pkg->data, file, hash)){
if(!lm_database_files_add(ctx->db, &pkg->data, hash, file)){
char *suberr = lm_strerror_dup();
pdebug(__func__, "failed to add file to the database for %s: %s", pkg->data.name, suberr);
lm_error_set(LM_ERR_PkgFilesAddFail, file, suberr);
@ -325,6 +329,8 @@ bool lm_ctx_install(lm_ctx_t *ctx, lm_pkg_t *pkg, bool run_install, lm_ctx_insta
line_len = 0;
}
pdebug(__func__, "extracting files for %s", pkg->data.name);
if(!__lm_ctx_extract_files(ctx, pkg, files->files_archive, callback, data)){
char *suberr = lm_strerror_dup();
pdebug(__func__, "failed to extract the files archive for %s: %s", pkg->data.name, suberr);
@ -333,6 +339,8 @@ bool lm_ctx_install(lm_ctx_t *ctx, lm_pkg_t *pkg, bool run_install, lm_ctx_insta
goto end;
}
pdebug(__func__, "adding an entry for %s", pkg->data.name);
if(!lm_database_entry_add(ctx->db, &pkg->data)){
char *suberr = lm_strerror_dup();
pdebug(__func__, "failed to add %s to the database: %s", pkg->data.name, lm_strerror());
@ -341,6 +349,11 @@ bool lm_ctx_install(lm_ctx_t *ctx, lm_pkg_t *pkg, bool run_install, lm_ctx_insta
goto end;
}
if(run_install)
pdebug(__func__, "running the install script for %s", pkg->data.name);
else
pdebug(__func__, "saving the install script for %s", pkg->data.name);
if(run_install && !__lm_ctx_run_install(ctx->root, files->install_file)){
char *suberr = lm_strerror_dup();
pdebug(__func__, "failed to run install script: %s", lm_strerror());

View File

@ -55,13 +55,16 @@ bool lm_ctx_remove(lm_ctx_t *ctx, lm_entry_t *entry, lm_ctx_remove_callback_t ca
size_t total = 0, current = 0;
total = lm_database_files_count(ctx->db, entry);
pdebug(__func__, "removing %lu files", total);
while(lm_database_files_next(ctx->db, entry, &path, &hash, &in_keep)){
if(in_keep)
if(in_keep){
pdebug(__func__, "not removing file because it is set as keep: %s", path);
goto next;
}
fpath = join_alloc(ctx->root, path);
pdebug(__func__, "removing file %s (%s)", fpath, entry->name);
pdebug(__func__, "removing file %s (%s)", fpath, hash);
if(!exists(fpath, NULL)){
pdebug(__func__, "found file in database, but its not on the file system: %s", fpath);

View File

@ -8,17 +8,30 @@
#include <string.h>
#include <unistd.h>
size_t __lm_database_changes_get(lm_database_t *db, lm_entry_t *entry, char *path){
size_t changes_size = strlen(entry->name)+15;
size_t full_size = changes_size + strlen(db->dir);
if(NULL != path){
char changes_file[changes_size];
snprintf(changes_file, changes_size, "%s_changes", entry->name);
join(path, db->dir, changes_file);
}
return full_size;
}
#define __lm_changes_size() __lm_database_changes_get(db, entry, NULL)
#define __lm_changes_path(p) __lm_database_changes_get(db, entry, p)
bool lm_database_changes_update(lm_database_t *db, lm_entry_t *entry, char *file){
if(NULL == db || NULL == entry || NULL == file){
lm_error_set(LM_ERR_ArgNULL);
return false;
}
char changes_file[strlen(entry->name)+20];
sprintf(changes_file, "%s_changes", entry->name);
char changes_path[strlen(db->dir)+sizeof(changes_file)];
join(changes_path, db->dir, changes_file);
char changes_path[__lm_changes_size()];
__lm_changes_path(changes_path);
if(!copy_file(changes_path, file))
return false;
@ -37,11 +50,8 @@ bool lm_database_changes_del(lm_database_t *db, lm_entry_t *entry){
return false;
}
char changes_file[strlen(entry->name)+20];
sprintf(changes_file, "%s_changes", entry->name);
char changes_path[strlen(db->dir)+sizeof(changes_file)];
join(changes_path, db->dir, changes_file);
char changes_path[__lm_changes_size()];
__lm_changes_path(changes_path);
if(unlink(changes_path) < 0 && errno != ENOENT){
lm_error_set(LM_ERR_DbChangesUnlinkFail);
@ -52,15 +62,16 @@ bool lm_database_changes_del(lm_database_t *db, lm_entry_t *entry){
}
char *lm_database_changes_get(lm_database_t *db, lm_entry_t *entry){
char changes_file[strlen(entry->name)+20];
sprintf(changes_file, "%s_changes", entry->name);
if(NULL == db || NULL == entry){
lm_error_set(LM_ERR_ArgNULL);
return false;
}
char *changes_path = malloc(strlen(db->dir)+sizeof(changes_file));
join(changes_path, db->dir, changes_file);
char* changes_path = malloc(__lm_changes_size());
__lm_changes_path(changes_path);
if(!exists(changes_path, NULL)){
lm_error_set(LM_ERR_DbChangesNotExists);
free(changes_path);
return NULL;
}

View File

@ -31,34 +31,6 @@ char *queries[] = {
// QUERY_SELECT_PACKAGE_ALL
"SELECT * FROM packages",
// QUERY_CREATE_FILE_TABLE
"CREATE TABLE IF NOT EXISTS files (" \
" path TEXT PRIMARY KEY NOT NULL," \
" hash TEXT NOT NULL," \
" keep INT NOT NULL," \
" package TEXT NOT NULL);",
// QUERY_INSERT_FILE_SINGLE
"INSERT INTO files VALUES (?, ?, ?, ?)",
// QUERY_DELETE_FILE_ALL
"DELETE FROM files WHERE package = ? AND keep = 0",
// QUERY_DELETE_FILE_SINGLE
"DELETE FROM files WHERE path = ?",
// QUERY_SELECT_FILE_ALL
"SELECT * FROM files WHERE package = ?",
// QUERY_SELECT_FILE_SINGLE
"SELECT * FROM files WHERE path = ?",
// QUERY_UPDATE_FILE_1
"UPDATE files SET keep = 1 WHERE path = ?",
// QUERY_UPDATE_FILE_2
"UPDATE files SET keep = 0 WHERE path = ?",
};
lm_database_t *lm_database_new(char *path){
@ -77,35 +49,20 @@ lm_database_t *lm_database_new(char *path){
}
size_t pathlen = strlen(path);
char packagesdb[pathlen+20], filesdb[pathlen+20];
char packagesdb[pathlen+15];
join(packagesdb, path, "packages.db");
join(filesdb, path, "files.db");
if(sqlite3_open(packagesdb, &db->entries_db)){
pdebug(__func__, "(%s) failed to open databse: %s", packagesdb, sqlite3_errmsg(db->entries_db));
if(sqlite3_open(packagesdb, &db->sql)){
pdebug(__func__, "(%s) failed to open databse: %s", packagesdb, sqlite3_errmsg(db->sql));
lm_error_set(LM_ERR_DbSqlOpenFail);
return NULL;
}
if(sqlite3_open(filesdb, &db->files_db)){
pdebug(__func__, "(%s) failed to open databse: %s", filesdb, sqlite3_errmsg(db->files_db));
lm_error_set(LM_ERR_DbSqlOpenFail);
return NULL;
}
if(sqlite3_exec(db->entries_db, queries[QUERY_CREATE_ENTRY_TABLE], NULL, 0, &err) != SQLITE_OK){
if(sqlite3_exec(db->sql, queries[QUERY_CREATE_TABLE], NULL, 0, &err) != SQLITE_OK){
pdebug(__func__, "(%s) failed to create packages table: %s", packagesdb, err);
lm_error_set(LM_ERR_DbSqlCreateFail);
sqlite3_free(err);
db->entries_db = NULL;
}
if(sqlite3_exec(db->files_db, queries[QUERY_CREATE_FILE_TABLE], NULL, 0, &err) != SQLITE_OK){
pdebug(__func__, "(%s) failed to create files table: %s", filesdb, err);
lm_error_set(LM_ERR_DbSqlCreateFail);
sqlite3_free(err);
db->files_db = NULL;
db->sql = NULL;
}
db->dir = strdup(path);
@ -113,15 +70,13 @@ lm_database_t *lm_database_new(char *path){
}
void lm_database_free(lm_database_t *db){
if(NULL != db->entries_st)
sqlite3_finalize(db->entries_st);
if(NULL != db->st)
sqlite3_finalize(db->st);
if(NULL != db->files_st)
sqlite3_finalize(db->files_st);
sqlite3_close(db->entries_db);
sqlite3_close(db->files_db);
if(NULL != db->filesp)
fclose(db->filesp);
sqlite3_close(db->sql);
free(db->dir);
free(db);
}

View File

@ -28,35 +28,35 @@ bool lm_database_entry_add(lm_database_t *db, lm_entry_t *entry){
char depends[lm_package_data_depend_strlen(entry)];
bool ret = false;
if(sqlite3_prepare(db->entries_db, queries[QUERY_INSERT_ENTRY_SINGLE], strlen(queries[QUERY_INSERT_ENTRY_SINGLE]), &db->entries_st, NULL) != SQLITE_OK){
pdebug(__func__, "failed to prepare statement for inserting %s: %s", entry->name, sqlite3_errmsg(db->entries_db));
if(sqlite3_prepare(db->sql, queries[QUERY_INSERT_SINGLE], strlen(queries[QUERY_INSERT_SINGLE]), &db->st, NULL) != SQLITE_OK){
pdebug(__func__, "failed to prepare statement for inserting %s: %s", entry->name, sqlite3_errmsg(db->sql));
lm_error_set(LM_ERR_DbSqlPrepareFail);
goto end;
}
sqlite3_bind_text(db->entries_st, ENTRIES_COLUMN_NAME, entry->name, strlen(entry->name), SQLITE_STATIC);
sqlite3_bind_text(db->entries_st, ENTRIES_COLUMN_DESC, entry->desc, strlen(entry->desc), SQLITE_STATIC);
sqlite3_bind_text(db->entries_st, ENTRIES_COLUMN_VERSION, entry->version, strlen(entry->version), SQLITE_STATIC);
sqlite3_bind_int64(db->entries_st, ENTRIES_COLUMN_SIZE, entry->size);
sqlite3_bind_text(db->st, COLUMN_NAME, entry->name, strlen(entry->name), SQLITE_STATIC);
sqlite3_bind_text(db->st, COLUMN_DESC, entry->desc, strlen(entry->desc), SQLITE_STATIC);
sqlite3_bind_text(db->st, COLUMN_VERSION, entry->version, strlen(entry->version), SQLITE_STATIC);
sqlite3_bind_int64(db->st, COLUMN_SIZE, entry->size);
if(!lm_package_data_depend_tostr(entry, depends)){
pdebug(__func__, "failed to convert depends to string for inserting %s: %s", entry->name, lm_strerror());
goto end;
}
pdebug(__func__, "depend list for %s: %s", entry->name, depends);
sqlite3_bind_text(db->entries_st, ENTRIES_COLUMN_DEPENDS, depends, strlen(depends), SQLITE_STATIC);
sqlite3_bind_text(db->st, COLUMN_DEPENDS, depends, strlen(depends), SQLITE_STATIC);
if(!lm_database_step_all(db->entries_st)){
pdebug(__func__, "failed to execute insert statement for inserting %s: %s", entry->name, sqlite3_errmsg(db->entries_db));
if(!lm_database_step_all(db->st)){
pdebug(__func__, "failed to execute insert statement for inserting %s: %s", entry->name, sqlite3_errmsg(db->sql));
lm_error_set(LM_ERR_DbSqlInsertFail);
goto end;
}
ret = true;
end:
if(NULL != db->entries_st){
sqlite3_finalize(db->entries_st);
db->entries_st = NULL;
if(NULL != db->st){
sqlite3_finalize(db->st);
db->st = NULL;
}
return ret;
}
@ -71,26 +71,26 @@ bool lm_database_entry_find(lm_database_t *db, lm_entry_t *entry, char *name, ch
char *query = NULL;
if(NULL == version)
query = queries[QUERY_SELECT_ENTRY_SINGLE_1];
query = queries[QUERY_SELECT_SINGLE_1];
else
query = queries[QUERY_SELECT_ENTRY_SINGLE_2];
query = queries[QUERY_SELECT_SINGLE_2];
// package pointer should already be free'd
// we are initing it just in case the caller didn't
if(NULL != entry)
lm_entry_init(entry);
if(sqlite3_prepare(db->entries_db, query, strlen(query), &db->entries_st, NULL) != SQLITE_OK){
pdebug(__func__, "failed to prepare statement for finding %s: %s", name, sqlite3_errmsg(db->entries_db));
if(sqlite3_prepare(db->sql, query, strlen(query), &db->st, NULL) != SQLITE_OK){
pdebug(__func__, "failed to prepare statement for finding %s: %s", name, sqlite3_errmsg(db->sql));
lm_error_set(LM_ERR_DbSqlPrepareFail);
goto end;
}
sqlite3_bind_text(db->entries_st, ENTRIES_COLUMN_NAME, name, strlen(name), SQLITE_STATIC);
sqlite3_bind_text(db->st, COLUMN_NAME, name, strlen(name), SQLITE_STATIC);
if(NULL != version)
sqlite3_bind_text(db->entries_st, ENTRIES_COLUMN_VERSION, version, strlen(version), SQLITE_STATIC);
sqlite3_bind_text(db->st, COLUMN_VERSION, version, strlen(version), SQLITE_STATIC);
if(sqlite3_step(db->entries_st) != SQLITE_ROW){
if(sqlite3_step(db->st) != SQLITE_ROW){
pdebug(__func__, "got no rows for %s", name);
lm_error_set(LM_ERR_DbSqlNotFound);
goto end;
@ -101,12 +101,12 @@ bool lm_database_entry_find(lm_database_t *db, lm_entry_t *entry, char *name, ch
goto end;
}
entry->name = strdup((char*)sqlite3_column_text(db->entries_st, ENTRIES_COLUMN_NAME-1));
entry->desc = strdup((char*)sqlite3_column_text(db->entries_st, ENTRIES_COLUMN_DESC-1));
entry->version = strdup((char*)sqlite3_column_text(db->entries_st, ENTRIES_COLUMN_VERSION-1));
entry->size = sqlite3_column_int64(db->entries_st, ENTRIES_COLUMN_SIZE-1);
entry->name = strdup((char*)sqlite3_column_text(db->st, COLUMN_NAME-1));
entry->desc = strdup((char*)sqlite3_column_text(db->st, COLUMN_DESC-1));
entry->version = strdup((char*)sqlite3_column_text(db->st, COLUMN_VERSION-1));
entry->size = sqlite3_column_int64(db->st, COLUMN_SIZE-1);
char *depends = (char*)sqlite3_column_text(db->entries_st, ENTRIES_COLUMN_DEPENDS-1);
char *depends = (char*)sqlite3_column_text(db->st, COLUMN_DEPENDS-1);
if(!lm_package_data_depend_fromstr(entry, depends)){
pdebug(__func__, "failed to load depends for finding %s: %s", entry->name, lm_strerror());
// error is set by the function
@ -115,9 +115,9 @@ bool lm_database_entry_find(lm_database_t *db, lm_entry_t *entry, char *name, ch
ret = true;
end:
if(NULL != db->entries_st){
sqlite3_finalize(db->entries_st);
db->entries_st = NULL;
if(NULL != db->st){
sqlite3_finalize(db->st);
db->st = NULL;
}
return ret;
}
@ -130,25 +130,25 @@ bool lm_database_entry_del(lm_database_t *db, lm_entry_t *entry){
bool ret = false;
if(sqlite3_prepare(db->entries_db, queries[QUERY_DELETE_ENTRY_SINGLE], strlen(queries[QUERY_DELETE_ENTRY_SINGLE]), &db->entries_st, NULL) != SQLITE_OK){
pdebug(__func__, "failed to prepare statement for deleting %s: %s", entry->name, sqlite3_errmsg(db->entries_db));
if(sqlite3_prepare(db->sql, queries[QUERY_DELETE_SINGLE], strlen(queries[QUERY_DELETE_SINGLE]), &db->st, NULL) != SQLITE_OK){
pdebug(__func__, "failed to prepare statement for deleting %s: %s", entry->name, sqlite3_errmsg(db->sql));
lm_error_set(LM_ERR_DbSqlPrepareFail);
goto end;
}
sqlite3_bind_text(db->entries_st, ENTRIES_COLUMN_NAME, entry->name, strlen(entry->name), SQLITE_STATIC);
sqlite3_bind_text(db->st, COLUMN_NAME, entry->name, strlen(entry->name), SQLITE_STATIC);
if(sqlite3_step(db->entries_st) != SQLITE_DONE){
pdebug(__func__, "failed to execute delete statement for deleting %s: %s", entry->name, sqlite3_errmsg(db->entries_db));
if(sqlite3_step(db->st) != SQLITE_DONE){
pdebug(__func__, "failed to execute delete statement for deleting %s: %s", entry->name, sqlite3_errmsg(db->sql));
lm_error_set(LM_ERR_DbSqlDeleteFail);
goto end;
}
ret = true;
end:
if(NULL != db->entries_st){
sqlite3_finalize(db->entries_st);
db->entries_st = NULL;
if(NULL != db->st){
sqlite3_finalize(db->st);
db->st = NULL;
}
return ret;
}
@ -159,33 +159,33 @@ bool lm_database_entry_next(lm_database_t *db, lm_entry_t *entry){
return false;
}
if(NULL != db->entries_st)
if(NULL != db->st)
lm_entry_free(entry);
else if(NULL == db->entries_st &&
sqlite3_prepare(db->entries_db, queries[QUERY_SELECT_ENTRY_ALL], strlen(queries[QUERY_SELECT_ENTRY_ALL]), &db->entries_st, NULL) != SQLITE_OK){
pdebug(__func__, "failed to prepare statement for selecting all: %s", sqlite3_errmsg(db->entries_db));
else if(NULL == db->st &&
sqlite3_prepare(db->sql, queries[QUERY_SELECT_ALL], strlen(queries[QUERY_SELECT_ALL]), &db->st, NULL) != SQLITE_OK){
pdebug(__func__, "failed to prepare statement for selecting all: %s", sqlite3_errmsg(db->sql));
lm_error_set(LM_ERR_DbSqlPrepareFail);
return false;
}
lm_entry_init(entry);
if(sqlite3_step(db->entries_st) != SQLITE_ROW){
sqlite3_finalize(db->entries_st);
db->entries_st = NULL;
if(sqlite3_step(db->st) != SQLITE_ROW){
sqlite3_finalize(db->st);
db->st = NULL;
return false;
}
entry->name = strdup((char*)sqlite3_column_text(db->entries_st, ENTRIES_COLUMN_NAME-1));
entry->desc = strdup((char*)sqlite3_column_text(db->entries_st, ENTRIES_COLUMN_DESC-1));
entry->version = strdup((char*)sqlite3_column_text(db->entries_st, ENTRIES_COLUMN_VERSION-1));
entry->size = sqlite3_column_int64(db->entries_st, ENTRIES_COLUMN_SIZE-1);
entry->name = strdup((char*)sqlite3_column_text(db->st, COLUMN_NAME-1));
entry->desc = strdup((char*)sqlite3_column_text(db->st, COLUMN_DESC-1));
entry->version = strdup((char*)sqlite3_column_text(db->st, COLUMN_VERSION-1));
entry->size = sqlite3_column_int64(db->st, COLUMN_SIZE-1);
char *depends = (char*)sqlite3_column_text(db->entries_st, ENTRIES_COLUMN_DEPENDS-1);
char *depends = (char*)sqlite3_column_text(db->st, COLUMN_DEPENDS-1);
if(!lm_package_data_depend_fromstr(entry, depends)){
pdebug(__func__, "failed to load depends for finding %s: %s", entry->name, lm_strerror());
sqlite3_finalize(db->entries_st);
sqlite3_finalize(db->st);
return false;
}
@ -198,9 +198,9 @@ void lm_database_entry_next_free(lm_database_t *db, lm_entry_t *entry){
return;
}
if(NULL != db->entries_st){
sqlite3_finalize(db->entries_st);
db->entries_st = NULL;
if(NULL != db->st){
sqlite3_finalize(db->st);
db->st = NULL;
}
if(NULL != entry)

View File

@ -4,238 +4,316 @@
#include "../../include/util.h"
#include <sqlite3.h>
#include <stdio.h>
#include <errno.h>
#include <strings.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
ssize_t lm_database_files_count(lm_database_t *db, lm_entry_t *entry){
ssize_t count = 0;
#define LINE_MIN 36 // keep (1) + colon (1) + MD5 hash (32) + colon (1) + path (min 1)
#define KEEP_INDEX 0
#define HASH_INDEX 2
#define PATH_INDEX 35
if(NULL == db || NULL == entry){
lm_error_set(LM_ERR_ArgNULL);
goto end;
size_t __lm_database_files_get(lm_database_t *db, lm_entry_t *entry, char *path){
size_t name_size = strlen(entry->name)+20;
size_t full_size = name_size + strlen(db->dir);
if(NULL != path){
char files_name[name_size];
snprintf(files_name, name_size, "%s_files", entry->name);
join(path, db->dir, files_name);
}
if(sqlite3_prepare(db->files_db, queries[QUERY_SELECT_FILE_ALL], strlen(queries[QUERY_SELECT_FILE_ALL]), &db->files_st, NULL) != SQLITE_OK){
pdebug(__func__, "failed to prepare statement for selecting all: %s", sqlite3_errmsg(db->files_db));
lm_error_set(LM_ERR_DbSqlPrepareFail);
return full_size;
}
#define __lm_files_size() __lm_database_files_get(db, entry, NULL)
#define __lm_files_path(p) __lm_database_files_get(db, entry, p)
FILE *__lm_database_files_open(lm_database_t *db, lm_entry_t *entry, char *perms){
if(NULL == db || NULL == entry){
lm_error_set(LM_ERR_ArgNULL);
return false;
}
sqlite3_bind_text(db->files_st, 1, entry->name, strlen(entry->name), SQLITE_STATIC);
char files_path[__lm_files_size()];
FILE *filesp = NULL;
while(sqlite3_step(db->files_st) == SQLITE_ROW)
count++;
end:
if(NULL != db->files_st){
sqlite3_finalize(db->files_st);
db->files_st = NULL;
__lm_files_path(files_path);
if(!exists(files_path, NULL)){
lm_error_set(LM_ERR_DbFilesNotFound);
return NULL;
}
if(NULL == (filesp = fopen(files_path, perms))){
lm_error_set(LM_ERR_DbFilesOpenFail, files_path);
return NULL;
}
return filesp;
}
char *__lm_database_files_line_single(FILE *filesp, char *path) {
ssize_t line_len = 0;
char *line = NULL;
while ((line_len = getline(&line, (size_t*)&line_len, filesp)) >= LINE_MIN) {
// keep : hash : path
// 1 : 32 : ?
// ignore empty line
if(line[0] == 0)
goto next;
// remove newline
else if (line[line_len-1] == '\n')
line[line_len-1] = 0;
if(eq((line + PATH_INDEX), path))
return line;
next:
free(line);
line = NULL;
line_len = 0;
}
return line;
}
char *__lm_database_files_line_all(lm_database_t *db, char *path) {
size_t dirlen = strlen(db->dir);
struct dirent *ent = NULL;
FILE* filesp = NULL;
DIR *ddir = NULL;
char *ret = NULL;
if(NULL == (ddir = opendir(db->dir))){
lm_error_set(LM_ERR_DbFilesDirFail, db->dir);
goto end;
}
while(NULL != (ent = readdir(ddir))){
size_t entlen = strlen(ent->d_name);
char entpath[entlen+dirlen+10];
join(entpath, db->dir, ent->d_name);
if(NULL == (filesp = fopen(entpath, "r"))){
lm_error_set(LM_ERR_DbFilesOpenFail, entpath);
goto end;
}
if(NULL == (ret = __lm_database_files_line_single(filesp, path)))
goto end;
}
end:
if(NULL != ddir)
closedir(ddir);
if(NULL != filesp)
fclose(filesp);
return ret;
}
ssize_t lm_database_files_count(lm_database_t *db, lm_entry_t *entry){
if(NULL == db || NULL == entry){
lm_error_set(LM_ERR_ArgNULL);
return 0;
}
FILE *filesp = NULL;
ssize_t count = 0;
char c = 0;
if((filesp = __lm_database_files_open(db, entry, "r")) == NULL)
return 0; // error set by function
while((c = fgetc(filesp)) != EOF)
if(c == '\n')
count ++;
fclose(filesp);
return count;
}
bool lm_database_files_contains(lm_database_t *db, lm_entry_t *entry, char *path){
char *package = NULL;
if(NULL == db || NULL == entry || NULL == path){
lm_error_set(LM_ERR_ArgNULL);
return false;
}
FILE *filesp = NULL;
char *line = NULL;
bool ret = false;
if(NULL == db || NULL == path){
lm_error_set(LM_ERR_ArgNULL);
goto end;
}
if((filesp = __lm_database_files_open(db, entry, "r")) == NULL)
return false; // error set by function
if(sqlite3_prepare(db->files_db, queries[QUERY_SELECT_FILE_SINGLE], strlen(queries[QUERY_SELECT_FILE_SINGLE]), &db->files_st, NULL) != SQLITE_OK){
pdebug(__func__, "failed to prepare statement for selecting %s: %s", path, sqlite3_errmsg(db->files_db));
lm_error_set(LM_ERR_DbSqlPrepareFail);
goto end;
}
if((line = __lm_database_files_line_single(filesp, path)) != NULL)
ret = true;
sqlite3_bind_text(db->files_st, FILES_COLUMN_PATH, path, strlen(path), SQLITE_STATIC);
free(line);
if(sqlite3_step(db->files_st) != SQLITE_ROW){
pdebug(__func__, "failed to execute select statement for selecting %s: %s", path, sqlite3_errmsg(db->files_db));
lm_error_set(LM_ERR_DbSqlSelectFail);
goto end;
}
if(NULL != filesp)
fclose(filesp);
package = (char*)sqlite3_column_text(db->files_st, FILES_COLUMN_ENTRY-1);
ret = eq(package, entry->name);
end:
if(NULL != db->files_st){
sqlite3_finalize(db->files_st);
db->files_st = NULL;
}
return ret;
}
bool lm_database_files_matches(lm_database_t *db, char *path, char *hash){
char *hashdb = NULL;
bool ret = false;
if(NULL == db || NULL == path || NULL == hash){
lm_error_set(LM_ERR_ArgNULL);
goto end;
return false;
}
if(sqlite3_prepare(db->files_db, queries[QUERY_SELECT_FILE_SINGLE], strlen(queries[QUERY_SELECT_FILE_SINGLE]), &db->files_st, NULL) != SQLITE_OK){
pdebug(__func__, "failed to prepare statement for selecting %s: %s", path, sqlite3_errmsg(db->files_db));
lm_error_set(LM_ERR_DbSqlPrepareFail);
goto end;
}
char *line = NULL, *line_hash = NULL;
bool ret = false;
sqlite3_bind_text(db->files_st, 1, path, strlen(path), SQLITE_STATIC);
if(NULL == (line = __lm_database_files_line_all(db, path)))
return false;
if(sqlite3_step(db->files_st) != SQLITE_ROW){
pdebug(__func__, "failed to execute select statement for selecting %s: %s", path, sqlite3_errmsg(db->files_db));
lm_error_set(LM_ERR_DbSqlSelectFail);
goto end;
}
line_hash = line+2;
line[35] = 0;
hashdb = (char*)sqlite3_column_text(db->files_st, FILES_COLUMN_HASH-1);
ret = eq(hashdb, hash);
if(eq(line_hash, hash))
ret = true;
end:
if(NULL != db->files_st){
sqlite3_finalize(db->files_st);
db->files_st = NULL;
}
free(line);
return ret;
}
bool lm_database_files_iskeep(lm_database_t *db, char *path){
bool ret = false;
int iskeep = 0;
if(NULL == db || NULL == path){
lm_error_set(LM_ERR_ArgNULL);
goto end;
return false;
}
if(sqlite3_prepare(db->files_db, queries[QUERY_SELECT_FILE_SINGLE], strlen(queries[QUERY_SELECT_FILE_SINGLE]), &db->files_st, NULL) != SQLITE_OK){
pdebug(__func__, "failed to prepare statement for selecting %s: %s", path, sqlite3_errmsg(db->files_db));
lm_error_set(LM_ERR_DbSqlPrepareFail);
goto end;
}
sqlite3_bind_text(db->files_st, 1, path, strlen(path), SQLITE_STATIC);
if(!lm_database_step_all(db->files_st)){
pdebug(__func__, "failed to execute select statement for selecting %s: %s", path, sqlite3_errmsg(db->files_db));
lm_error_set(LM_ERR_DbSqlSelectFail);
goto end;
}
iskeep = sqlite3_column_int64(db->files_st, FILES_COLUMN_KEEP-1);
ret = iskeep == 1;
end:
if(NULL != db->files_st){
sqlite3_finalize(db->files_st);
db->files_st = NULL;
}
return ret;
}
bool lm_database_files_add(lm_database_t *db, lm_entry_t *entry, char *path, char *hash){
char *line = NULL;
bool ret = false;
if(NULL == db || NULL == entry || NULL == path || NULL == hash){
lm_error_set(LM_ERR_ArgNULL);
goto end;
}
if(sqlite3_prepare(db->files_db, queries[QUERY_INSERT_FILE_SINGLE], strlen(queries[QUERY_INSERT_FILE_SINGLE]), &db->files_st, NULL) != SQLITE_OK){
pdebug(__func__, "failed to prepare statement for inserting %s: %s", path, sqlite3_errmsg(db->files_db));
lm_error_set(LM_ERR_DbSqlPrepareFail);
goto end;
}
sqlite3_bind_text(db->files_st, FILES_COLUMN_PATH, path, strlen(path), SQLITE_STATIC);
sqlite3_bind_text(db->files_st, FILES_COLUMN_HASH, hash, strlen(hash), SQLITE_STATIC);
if(lm_package_data_keep_contains(entry, path))
sqlite3_bind_int(db->files_st, FILES_COLUMN_KEEP, 1);
else
sqlite3_bind_int(db->files_st, FILES_COLUMN_KEEP, 0);
sqlite3_bind_text(db->files_st, FILES_COLUMN_ENTRY, entry->name, strlen(entry->name), SQLITE_STATIC);
if(!lm_database_step_all(db->files_st)){
pdebug(__func__, "failed to execute insert statement for inserting %s: %s", entry->name, sqlite3_errmsg(db->files_db));
lm_error_set(LM_ERR_DbSqlInsertFail);
goto end;
}
if(NULL == (line = __lm_database_files_line_all(db, path)))
return false;
if(line[0] == '1')
ret = true;
end:
if(NULL != db->files_st){
sqlite3_finalize(db->files_st);
db->files_st = NULL;
}
free(line);
return ret;
}
bool lm_database_files_add(lm_database_t *db, lm_entry_t *entry, char *hash, char *path){
if(NULL == db || NULL == entry || NULL == hash || NULL == path){
lm_error_set(LM_ERR_ArgNULL);
return false;
}
char files_path[__lm_files_size()];
FILE *filesp = NULL;
__lm_files_path(files_path);
if(NULL == (filesp = fopen(files_path, "a"))){
lm_error_set(LM_ERR_DbFilesOpenFail, files_path);
return false;
}
fwrite(lm_package_data_keep_contains(entry, path) ? "1:" : "0:", 1, 2, filesp);
fwrite(hash, 1, strlen(hash), filesp);
fwrite(":", 1, 1, filesp);
fwrite(path, 1, strlen(path), filesp);
fwrite("\n", 1, 1, filesp);
fclose(filesp);
return true;
}
bool lm_database_files_del(lm_database_t *db, lm_entry_t *entry){
if(NULL == db || NULL == entry){
lm_error_set(LM_ERR_ArgNULL);
return false;
}
bool ret = false;
FILE *original = NULL, *temp = NULL;
char temp_name[strlen(entry->name)+15];
char temp_path[__lm_files_size()+10];
char real_path[__lm_files_size()], *line = NULL;
bool ret = false, empty = true;
ssize_t line_len = 0;
if(sqlite3_prepare(db->files_db, queries[QUERY_DELETE_FILE_ALL], strlen(queries[QUERY_DELETE_FILE_ALL]), &db->files_st, NULL) != SQLITE_OK){
pdebug(__func__, "failed to prepare statement for deleting %s: %s", entry->name, sqlite3_errmsg(db->files_db));
lm_error_set(LM_ERR_DbSqlPrepareFail);
__lm_files_path(real_path);
sprintf(temp_name, "%s_files.temp", entry->name);
join(temp_path, db->dir, temp_name);
if(NULL == (original = fopen(real_path, "r"))){
lm_error_set(LM_ERR_DbFilesOpenFail);
goto end;
}
sqlite3_bind_text(db->files_st, 1, entry->name, strlen(entry->name), SQLITE_STATIC);
if(!lm_database_step_all(db->files_st)){
pdebug(__func__, "failed to execute delete statement for deleting %s: %s", entry->name, sqlite3_errmsg(db->files_db));
lm_error_set(LM_ERR_DbSqlDeleteFail);
if(NULL == (temp = fopen(temp_path, "a"))){
lm_error_set(LM_ERR_DbFilesOpenFail);
goto end;
}
while ((line_len = getline(&line, (size_t*)&line_len, original)) >= LINE_MIN){
if(line[0] == '1'){
fwrite(line, 1, line_len, temp);
empty = false;
}
free(line);
line = NULL;
line_len = 0;
}
ret = true;
end:
if(NULL != db->files_st){
sqlite3_finalize(db->files_st);
db->files_st = NULL;
if(NULL != original)
fclose(original);
if(NULL != temp)
fclose(temp);
free(line);
if(ret && unlink(real_path) != 0){
lm_error_set(LM_ERR_DbFilesUnlinkFail, real_path);
ret = false;
}
if(empty || !ret){
unlink(temp_path);
}
else if(ret && rename(temp_path, real_path) != 0){
lm_error_set(LM_ERR_DbFilesRenameFail, real_path);
ret = false;
}
return ret;
}
bool lm_database_files_del_single(lm_database_t *db, char *path){
if(NULL == db || NULL == path){
bool lm_database_files_del_all(lm_database_t *db, lm_entry_t *entry){
if(NULL == db || NULL == entry){
lm_error_set(LM_ERR_ArgNULL);
return false;
}
bool ret = false;
char files_path[__lm_files_size()];
__lm_files_path(files_path);
if(sqlite3_prepare(db->files_db, queries[QUERY_DELETE_FILE_SINGLE], strlen(queries[QUERY_DELETE_FILE_SINGLE]), &db->files_st, NULL) != SQLITE_OK){
pdebug(__func__, "failed to prepare statement for deleting %s: %s", path, sqlite3_errmsg(db->files_db));
lm_error_set(LM_ERR_DbSqlPrepareFail);
goto end;
if(exists(files_path, NULL) && unlink(files_path) != 0){
lm_error_set(LM_ERR_DbFilesUnlinkFail, files_path);
return false;
}
sqlite3_bind_text(db->files_st, 1, path, strlen(path), SQLITE_STATIC);
if(!lm_database_step_all(db->files_st)){
pdebug(__func__, "failed to execute delete statement for deleting %s: %s", path, sqlite3_errmsg(db->files_db));
lm_error_set(LM_ERR_DbSqlDeleteFail);
goto end;
}
ret = true;
end:
if(NULL != db->files_st){
sqlite3_finalize(db->files_st);
db->files_st = NULL;
}
return ret;
return true;
}
bool lm_database_files_next(lm_database_t *db, lm_entry_t *entry, char **path, char **hash, bool *keep){
@ -244,51 +322,54 @@ bool lm_database_files_next(lm_database_t *db, lm_entry_t *entry, char **path, c
return false;
}
if(NULL == db->files_st){
if(sqlite3_prepare(db->files_db, queries[QUERY_SELECT_FILE_ALL], strlen(queries[QUERY_SELECT_FILE_ALL]), &db->files_st, NULL) != SQLITE_OK){
pdebug(__func__, "failed to prepare statement for selecting all: %s", sqlite3_errmsg(db->files_db));
lm_error_set(LM_ERR_DbSqlPrepareFail);
return false;
}
sqlite3_bind_text(db->files_st, 1, entry->name, strlen(entry->name), SQLITE_STATIC);
}
if(NULL == db->filesp && NULL == (db->filesp = __lm_database_files_open(db, entry, "r")))
return false; // error set by function
else if(NULL != db->files_st){
free(*path);
free(*hash);
ssize_t line_len = 0;
char *line = NULL;
if(NULL != *hash)
free(*hash-HASH_INDEX);
if((line_len = getline(&line, (size_t*)&line_len, db->filesp)) <= LINE_MIN)
goto eof;
if(line[line_len-1] == '\n')
line[line_len-1] = 0; // replace newline with null terminator
line[PATH_INDEX-1] = 0; // replace colon with null terminator
*keep = line[0] == '1';
*hash = line + HASH_INDEX;
*path = line + PATH_INDEX;
return true;
eof:
fclose(db->filesp);
free(line);
db->filesp = NULL;
*keep = false;
*path = NULL;
*hash = NULL;
*keep = false;
}
if(sqlite3_step(db->files_st) != SQLITE_ROW){
sqlite3_finalize(db->files_st);
db->files_st = NULL;
return false;
}
*path = strdup((char*)sqlite3_column_text(db->files_st, FILES_COLUMN_PATH-1));
*hash = strdup((char*)sqlite3_column_text(db->files_st, FILES_COLUMN_HASH-1));
*keep = sqlite3_column_int(db->files_st, FILES_COLUMN_KEEP-1) == 1;
return true;
}
void lm_database_files_next_free(lm_database_t *db, lm_entry_t *entry, char **path, char **hash, bool *keep){
if(NULL == db || NULL == entry || NULL == path || NULL == hash || NULL == keep){
lm_error_set(LM_ERR_ArgNULL);
return;
}
if(NULL != db->files_st){
sqlite3_finalize(db->files_st);
db->files_st = NULL;
}
if(NULL != db->filesp)
fclose(db->filesp);
if(NULL != path)
free(*path);
if(NULL != hash)
free(*hash);
if(NULL != *hash)
free(*hash-HASH_INDEX);
db->filesp = NULL;
*keep = false;
*path = NULL;
*hash = NULL;
}

View File

@ -97,11 +97,11 @@ void lm_error_set(lm_error_t code, ...) {
{.code = LM_ERR_PoolUrlEmpty, .desc = _("pool URL is empty or invalid") },
{.code = LM_ERR_PoolBadDir, .desc = _("pool directory path is not accessible") },
{.code = LM_ERR_PoolBadPaths, .desc = _("pool directory sub-paths are not accessible") },
{.code = LM_ERR_DbFilesNotFound, .desc = _("package file list not found in the database") },
{.code = LM_ERR_DbFilesOpenFail, .desc = _("failed to open package file list in the database") },
{.code = LM_ERR_DbFilesDirFail, .desc = _("failed to access package file list database directory") },
{.code = LM_ERR_DbFilesUnlinkFail, .desc = _("failed to remove package file list from the database") },
{.code = LM_ERR_DbFilesWriteFail, .desc = _("failed to write to the file list in the database") },
{.code = LM_ERR_DbFilesNotFound, .desc = _("file list not found for the package") },
{.code = LM_ERR_DbFilesRenameFail, .desc = _("failed to rename the file list for the package: %s") },
{.code = LM_ERR_DbFilesOpenFail, .desc = _("failed to open the package file list: %s") },
{.code = LM_ERR_DbFilesDirFail, .desc = _("failed to open the database directory: %s") },
{.code = LM_ERR_DbFilesUnlinkFail, .desc = _("failed to remove package file list: %s") },
{.code = LM_ERR_DbKeepsNotFound, .desc = _("package keep list not found in the database") },
{.code = LM_ERR_DbKeepsOpenFail, .desc = _("failed to open package keep list in the database") },
{.code = LM_ERR_DbKeepsDirFail, .desc = _("failed to access package keep list database directory") },