diff --git a/examples/client/main.c b/examples/client/main.c index 1c58d50..8c4235d 100644 --- a/examples/client/main.c +++ b/examples/client/main.c @@ -30,13 +30,8 @@ int main(int argc, char *argv[]) { lm_ctx_pool_get_info(&ctx, true, true, NULL, NULL); lm_ctx_pool_get_list(&ctx, true, true, NULL, NULL); - if (lm_ctx_package_get(&ctx, "which", NULL) == NULL) { - printf("failed to get the package: %s (%d)\n", lm_strerror(), lm_error()); - goto end; - } - - if (!lm_ctx_package_verify(&ctx, "which", NULL)) { - printf("failed to verify package: %s (%d)\n", lm_strerror(), lm_error()); + if(!lm_ctx_install(&ctx, "which")){ + printf("failed to install the package: %s (%d)\n", lm_strerror(), lm_error()); goto end; } diff --git a/include/ctx.h b/include/ctx.h index da35225..369af8d 100644 --- a/include/ctx.h +++ b/include/ctx.h @@ -3,7 +3,16 @@ #include "types.h" #include +typedef struct lm_ctx { + lm_pool_t *pools; // pool list + char *root; // root path for package installtion + char *temp; // temp path + char *data; // package database path + const char *version; // libmp version (read-only) +} lm_ctx_t; + typedef bool (*lm_ctx_pool_callback_t)(lm_ctx_t *ctx, lm_pool_t *pool, bool status, void *data); +typedef bool (*lm_ctx_database_callback_t)(lm_ctx_t *ctx, lm_pkg_t *pkg, void *data); void lm_ctx_init(lm_ctx_t *ctx); bool lm_ctx_set_data(lm_ctx_t *ctx, char *dir); @@ -11,6 +20,12 @@ bool lm_ctx_set_root(lm_ctx_t *ctx, char *dir); bool lm_ctx_set_temp(lm_ctx_t *ctx, char *dir); void lm_ctx_free(lm_ctx_t *ctx); +lm_pkg_t *lm_ctx_find(lm_ctx_t *ctx, char *name, char *version); +bool lm_ctx_install(lm_ctx_t *ctx, char *package); +bool lm_ctx_remove(lm_ctx_t *ctx, char *package); +bool lm_ctx_verify(lm_ctx_t *ctx, char *package); +bool lm_ctx_update(lm_ctx_t *ctx); + lm_pool_t *lm_ctx_pool_add(lm_ctx_t *ctx, char *name, char *url); bool lm_ctx_pool_del(lm_ctx_t *ctx, char *name); void lm_ctx_pool_clear(lm_ctx_t *ctx); @@ -21,8 +36,11 @@ void lm_ctx_pool_get_info( void lm_ctx_pool_get_list( lm_ctx_t *ctx, bool allow_update, bool force_update, lm_ctx_pool_callback_t callback, void *data); -lm_pkg_t *lm_ctx_package_install(lm_ctx_t *ctx, char *name, char *version); -lm_pkg_t *lm_ctx_package_get(lm_ctx_t *ctx, char *name, char *version); -bool lm_ctx_package_verify(lm_ctx_t *ctx, char *name, char *version); +bool lm_ctx_package_install(lm_ctx_t *ctx, lm_pkg_t *pkg); +bool lm_ctx_package_remove(lm_ctx_t *ctx, lm_pkg_t *pkg); +bool lm_ctx_package_verify(lm_ctx_t *ctx, lm_pkg_t *pkg); lm_database_t *lm_ctx_database_new(lm_ctx_t *ctx); +bool lm_ctx_database_is_installed(lm_ctx_t *ctx, lm_pkg_t *pkg, bool check_version); +bool lm_ctx_database_find(lm_ctx_t *ctx, lm_pkg_t *pkg, char *name); +bool lm_ctx_database_foreach(lm_ctx_t *ctx, lm_ctx_database_callback_t callback, void *data); diff --git a/include/database.h b/include/database.h index 671761a..41017eb 100644 --- a/include/database.h +++ b/include/database.h @@ -9,14 +9,16 @@ typedef enum lm_query_index { QUERY_INSERT_PACKAGE = 1, QUERY_SELECT_PACKAGE = 2, QUERY_DELETE_PACKAGE = 3, + QUERY_ALL_PACKAGE = 4, } lm_query_index_t; extern char *queries[]; typedef struct lm_database { - char *dir; - lm_pkg_t *pkg; - sqlite3 *sql; + sqlite3_stmt *st; + sqlite3 *sql; + char *dir; + lm_pkg_t *pkg; } lm_database_t; typedef bool (*lm_database_files_eachfunc_t)(lm_pkg_t *pkg, char *path, char *hash, void *data); @@ -26,6 +28,7 @@ lm_database_t *lm_database_new(char *path); void lm_database_free(lm_database_t *db); bool lm_database_find(lm_database_t *db, lm_pkg_t *pkg, char *name); +bool lm_database_next(lm_database_t *db, lm_pkg_t *pkg); bool lm_database_add(lm_database_t *db, lm_pkg_t *pkg); bool lm_database_del(lm_database_t *db, lm_pkg_t *pkg); diff --git a/include/error.h b/include/error.h index 3918c21..0e2907a 100644 --- a/include/error.h +++ b/include/error.h @@ -91,6 +91,10 @@ typedef enum lm_error { LM_ERR_DbKeepsDirFail = 86, LM_ERR_DbKeepsUnlinkFail = 87, LM_ERR_DbSqlNotFound = 88, + LM_ERR_DependNotFound = 89, + LM_ERR_InstallDownloadFail = 90, + LM_ERR_PkgNotDownloaded = 91, + LM_ERR_PkgRemoveDownloadFail = 92, } lm_error_t; typedef struct lm_error_desc { @@ -98,6 +102,7 @@ typedef struct lm_error_desc { char *desc; } lm_error_desc_t; -void lm_error_set(lm_error_t code); +void lm_error_set(lm_error_t code, ...); +void lm_error_clear(); lm_error_t lm_error(); char *lm_strerror(); diff --git a/include/package.h b/include/package.h index bc2d06f..2dc0192 100644 --- a/include/package.h +++ b/include/package.h @@ -16,6 +16,7 @@ void lm_package_init(lm_pkg_t *pkg); bool lm_package_data_load(lm_pkg_t *pkg, char *file); void lm_package_data_free(lm_pkg_t *pkg); +bool lm_package_downloaded(lm_pkg_t *pkg); bool lm_package_depend_add(lm_pkg_t *pkg, char *depend); size_t lm_package_depend_count(lm_pkg_t *pkg); size_t lm_package_depend_strlen(lm_pkg_t *pkg); diff --git a/include/pool.h b/include/pool.h index d5c43d7..f8aeb78 100644 --- a/include/pool.h +++ b/include/pool.h @@ -21,19 +21,19 @@ void lm_pool_test(lm_pool_t *pool); void lm_pool_free(lm_pool_t *pool); lm_pkg_t *lm_pool_package_find(lm_pool_t *pool, char *name, char *version); +bool lm_pool_package_download(lm_pool_t *pool, lm_pkg_t *pkg); bool lm_pool_package_add(lm_pool_t *pool, lm_pkg_t *pkg); -bool lm_pool_package_get(lm_pool_t *pool, lm_pkg_t *pkg); bool lm_pool_path_set_dir(lm_pool_t *pool, char *dir); bool lm_pool_path_is_empty(lm_pool_t *pool); void lm_pool_path_free(lm_pool_t *pool); bool lm_pool_info_load(lm_pool_t *pool); -bool lm_pool_info_get(lm_pool_t *pool); +bool lm_pool_info_download(lm_pool_t *pool); void lm_pool_info_free(lm_pool_t *pool); bool lm_pool_list_load(lm_pool_t *pool); -bool lm_pool_list_get(lm_pool_t *pool); +bool lm_pool_list_download(lm_pool_t *pool); void lm_pool_list_free(lm_pool_t *pool); void lm_pool_serve(lm_pool_t *pool, lm_mptp_t *packet, int sock, struct sockaddr *addr); diff --git a/include/types.h b/include/types.h index ab880e2..313a04c 100644 --- a/include/types.h +++ b/include/types.h @@ -16,14 +16,15 @@ typedef struct lm_pkg_path { } lm_pkg_path_t; typedef struct lm_pkg { - struct lm_pkg *next; - lm_pkg_path_t paths; - char *name; - char *desc; - char **depends; - char **keeps; - char *version; - size_t size; + struct lm_pool *pool; + struct lm_pkg *next; + lm_pkg_path_t paths; + char *name; + char *desc; + char **depends; + char **keeps; + char *version; + size_t size; } lm_pkg_t; typedef struct lm_pool_info { @@ -48,11 +49,3 @@ typedef struct lm_pool { bool available; char *name; } lm_pool_t; - -typedef struct lm_ctx { - lm_pool_t *pools; // pool list - char *root; // root path for package installtion - char *temp; // temp path - char *data; // package database path - const char *version; // libmp version (read-only) -} lm_ctx_t; diff --git a/include/util.h b/include/util.h index 9d69d3c..034d336 100644 --- a/include/util.h +++ b/include/util.h @@ -34,3 +34,8 @@ void sockaddr_to_str(struct sockaddr *addr, char *str); int join_multiple(char *res, const char *base, const char *pth, const char *pth2); int join(char *res, const char *base, const char *pth); char *join_alloc(const char *base, const char *pth); + +bool pkglist_contains(lm_pkg_t *list, lm_pkg_t *pkg); +lm_pkg_t *pkglist_del(lm_pkg_t *list, lm_pkg_t *pkg); +lm_pkg_t *pkglist_add(lm_pkg_t *list, lm_pkg_t *pkg); +void pkglist_free(lm_pkg_t *list); diff --git a/locale/tr/LC_MESSAGES/libmp.po b/locale/tr/LC_MESSAGES/libmp.po index 09b810c..e3f531a 100644 --- a/locale/tr/LC_MESSAGES/libmp.po +++ b/locale/tr/LC_MESSAGES/libmp.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-03 03:40+0300\n" +"POT-Creation-Date: 2024-07-04 03:04+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,370 +17,389 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: src/error.c:13 +#: src/error.c:19 msgid "no error" msgstr "hata yok" -#: src/error.c:14 +#: src/error.c:20 #, fuzzy msgid "URL contains an invalid character" msgstr "URL contains an invalid char" -#: src/error.c:15 +#: src/error.c:21 msgid "URL does not have a valid protocol field" msgstr "URL does not have a valid protocol field" -#: src/error.c:16 +#: src/error.c:22 msgid "URL is too large" msgstr "URL is too large" -#: src/error.c:17 +#: src/error.c:23 msgid "URL hostname is too large" msgstr "URL hostname is too large" -#: src/error.c:18 +#: src/error.c:24 msgid "URL path is too large" msgstr "URL path is too large" -#: src/error.c:19 +#: src/error.c:25 msgid "URL does not have a valid hostname" msgstr "URL does not have a valid hostname" -#: src/error.c:20 +#: src/error.c:26 #, fuzzy msgid "URL does not have a valid port number" msgstr "URL does not have a valid hostname" -#: src/error.c:21 +#: src/error.c:27 msgid "URL does not have a valid path" msgstr "URL does not have a valid path" -#: src/error.c:22 +#: src/error.c:28 #, fuzzy msgid "hostname does not contain a valid port number" msgstr "URL does not contain a hostname with a valid port number" -#: src/error.c:23 +#: src/error.c:29 #, fuzzy msgid "hostname is not valid" msgstr "URL hostname is too large" -#: src/error.c:24 +#: src/error.c:30 msgid "URL protocol port number is unknown" msgstr "URL protocol port number is unknown" -#: src/error.c:25 +#: src/error.c:31 msgid "URL is incomplete" msgstr "URL tamamlanmamış" -#: src/error.c:26 +#: src/error.c:32 msgid "pool does not support the specified protocol" msgstr "pool does not support the specified protocol" -#: src/error.c:27 +#: src/error.c:33 msgid "unsupported MPTP version" msgstr "" -#: src/error.c:28 +#: src/error.c:34 msgid "invalid MPTP request/response code" msgstr "" -#: src/error.c:29 +#: src/error.c:35 msgid "invalid MPTP URL" msgstr "" -#: src/error.c:30 +#: src/error.c:36 msgid "failed to resolve hostname for MPTP connection" msgstr "" -#: src/error.c:31 +#: src/error.c:37 msgid "failed to create a MPTP socket" msgstr "" -#: src/error.c:32 +#: src/error.c:38 msgid "failed to connect to the MPTP host" msgstr "" -#: src/error.c:33 +#: src/error.c:39 msgid "failed receive MPTP data from host" msgstr "" -#: src/error.c:34 +#: src/error.c:40 msgid "failed send MPTP data to host" msgstr "" -#: src/error.c:35 +#: src/error.c:41 #, fuzzy msgid "MPTP data size is invalid" msgstr "URL path is too large" -#: src/error.c:36 +#: src/error.c:42 #, fuzzy msgid "MPTP host size is invalid" msgstr "URL path is too large" -#: src/error.c:37 +#: src/error.c:43 msgid "failed to set MPTP socket options" msgstr "" -#: src/error.c:38 +#: src/error.c:44 msgid "MPTP connection timed out" msgstr "" -#: src/error.c:39 +#: src/error.c:45 msgid "failed to bind MPTP socket" msgstr "" -#: src/error.c:40 +#: src/error.c:46 msgid "required argument is a NULL pointer or 0" msgstr "" -#: src/error.c:41 +#: src/error.c:47 msgid "not a MPTP request" msgstr "" -#: src/error.c:42 +#: src/error.c:48 msgid "not a MPTP response" msgstr "" -#: src/error.c:43 +#: src/error.c:49 msgid "MPTP request last flag is not set" msgstr "" -#: src/error.c:44 +#: src/error.c:50 msgid "host port not specified" msgstr "" -#: src/error.c:45 +#: src/error.c:51 msgid "pool info is badly formatted or is not complete" msgstr "" -#: src/error.c:46 +#: src/error.c:52 msgid "failed to write block from archive" msgstr "" -#: src/error.c:47 +#: src/error.c:53 msgid "failed to read block from archive" msgstr "" -#: src/error.c:48 +#: src/error.c:54 msgid "failed to open archive" msgstr "" -#: src/error.c:49 +#: src/error.c:55 msgid "failed to write archive header" msgstr "" -#: src/error.c:50 +#: src/error.c:56 msgid "failed to finish writing the archive entry" msgstr "" -#: src/error.c:51 +#: src/error.c:57 msgid "failed to create new archive reader/writer" msgstr "" -#: src/error.c:52 +#: src/error.c:58 msgid "failed to resolve full path for archive file" msgstr "" -#: src/error.c:53 +#: src/error.c:59 msgid "failed to read the next header of the archive" msgstr "" -#: src/error.c:54 +#: src/error.c:60 msgid "failed to obtain current working directory" msgstr "" -#: src/error.c:55 +#: src/error.c:61 msgid "failed to open extracted pool list directory" msgstr "" -#: src/error.c:56 +#: src/error.c:62 msgid "failed to read access the pool list file" msgstr "" -#: src/error.c:57 +#: src/error.c:63 msgid "failed to read access the pool info file" msgstr "" -#: src/error.c:58 +#: src/error.c:64 msgid "failed to parse package data" msgstr "" -#: src/error.c:59 +#: src/error.c:65 #, fuzzy msgid "package name is invalid" msgstr "URL hostname is too large" -#: src/error.c:60 +#: src/error.c:66 msgid "data path is not set with in the ctx" msgstr "" -#: src/error.c:61 +#: src/error.c:67 msgid "specified temp path does not exist" msgstr "" -#: src/error.c:62 +#: src/error.c:68 msgid "specified temp path is not a directory" msgstr "" -#: src/error.c:63 +#: src/error.c:69 msgid "specified temp directory does not have write access" msgstr "" -#: src/error.c:64 +#: src/error.c:70 msgid "specified root path does not exist" msgstr "" -#: src/error.c:65 +#: src/error.c:71 msgid "specified root path is not a directory" msgstr "" -#: src/error.c:66 +#: src/error.c:72 msgid "specified root directory does not have write access" msgstr "" -#: src/error.c:67 +#: src/error.c:73 msgid "specified data path does not exist" msgstr "" -#: src/error.c:68 +#: src/error.c:74 msgid "specified data path is not a directory" msgstr "" -#: src/error.c:69 +#: src/error.c:75 msgid "failed to create specified data directory" msgstr "" -#: src/error.c:70 +#: src/error.c:76 msgid "pool did not respond ping with pong" msgstr "" -#: src/error.c:71 +#: src/error.c:77 msgid "package file and directory paths are empty" msgstr "" -#: src/error.c:72 +#: src/error.c:78 msgid "failed to to open target file for sending" msgstr "" -#: src/error.c:73 +#: src/error.c:79 msgid "failed to to delete target file for receiving" msgstr "" -#: src/error.c:74 +#: src/error.c:80 msgid "failed to to open target file for receiving" msgstr "" -#: src/error.c:75 +#: src/error.c:81 msgid "got a bad response code for receiving the target file" msgstr "" -#: src/error.c:76 +#: src/error.c:82 msgid "failed to write to the target file for receiving" msgstr "" -#: src/error.c:77 +#: src/error.c:83 #, fuzzy msgid "package not found" msgstr "URL hostname is too large" -#: src/error.c:78 +#: src/error.c:84 msgid "failed to access to the database file/directory" msgstr "" -#: src/error.c:79 +#: src/error.c:85 msgid "failed to open SQLite database" msgstr "" -#: src/error.c:80 +#: src/error.c:86 msgid "failed to create table in SQLite database" msgstr "" -#: src/error.c:81 +#: src/error.c:87 msgid "failed to prepare statement for SQLite database" msgstr "" -#: src/error.c:82 +#: src/error.c:88 msgid "failed to insert to the table in SQLite database" msgstr "" -#: src/error.c:83 +#: src/error.c:89 msgid "failed to find entry in SQLite database" msgstr "" -#: src/error.c:84 +#: src/error.c:90 msgid "failed to init GPG for package verification" msgstr "" -#: src/error.c:85 +#: src/error.c:91 msgid "failed to import signature to GPG for package verification" msgstr "" -#: src/error.c:86 +#: src/error.c:92 msgid "failed to import archive to GPG for package verification" msgstr "" -#: src/error.c:87 +#: src/error.c:93 msgid "package signature verification failed with zero matches" msgstr "" -#: src/error.c:88 +#: src/error.c:94 msgid "package signature verification failed with zero results" msgstr "" -#: src/error.c:89 +#: src/error.c:95 msgid "pool file and directory paths are empty" msgstr "" -#: src/error.c:90 +#: src/error.c:96 msgid "pool is not avaliable for connection" msgstr "" -#: src/error.c:91 +#: src/error.c:97 msgid "pool URL is empty or invalid" msgstr "" -#: src/error.c:92 +#: src/error.c:98 msgid "pool directory path is not accessible" msgstr "" -#: src/error.c:93 +#: src/error.c:99 msgid "pool directory sub-paths are not accessible" msgstr "" -#: src/error.c:94 +#: src/error.c:100 msgid "package file list not found in the database" msgstr "" -#: src/error.c:95 +#: src/error.c:101 msgid "failed to open package file list in the database" msgstr "" -#: src/error.c:96 +#: src/error.c:102 msgid "failed to access package file list database directory" msgstr "" -#: src/error.c:97 +#: src/error.c:103 msgid "failed to remove package file list from the database" msgstr "" -#: src/error.c:98 +#: src/error.c:104 msgid "failed to write to the file list in the database" msgstr "" -#: src/error.c:99 +#: src/error.c:105 msgid "package keep list not found in the database" msgstr "" -#: src/error.c:100 +#: src/error.c:106 msgid "failed to open package keep list in the database" msgstr "" -#: src/error.c:101 +#: src/error.c:107 msgid "failed to access package keep list database directory" msgstr "" -#: src/error.c:102 +#: src/error.c:108 msgid "failed to remove package keep list from the database" msgstr "" + +#: src/error.c:109 +#, c-format +msgid "failed to find %s (dependency of %s)" +msgstr "" + +#: src/error.c:110 +#, c-format +msgid "failed to download %s for installation: %s" +msgstr "" + +#: src/error.c:111 +#, fuzzy +msgid "package is not downloaded" +msgstr "URL hostname is too large" + +#: src/error.c:112 +msgid "failed to remove downloaded package" +msgstr "" diff --git a/src/ctx/ctx.c b/src/ctx/ctx.c index 568b34e..7f1b663 100644 --- a/src/ctx/ctx.c +++ b/src/ctx/ctx.c @@ -14,6 +14,8 @@ void lm_ctx_init(lm_ctx_t *ctx) { bzero(ctx, sizeof(lm_ctx_t)); ctx->version = LM_VERSION; + + lm_error_clear(); } bool lm_ctx_set_temp(lm_ctx_t *ctx, char *dir){ @@ -81,5 +83,7 @@ void lm_ctx_free(lm_ctx_t *ctx) { free(ctx->data); free(ctx->root); free(ctx->temp); + + lm_error_clear(); return; } diff --git a/src/ctx/database.c b/src/ctx/database.c index f00a7df..4aeec46 100644 --- a/src/ctx/database.c +++ b/src/ctx/database.c @@ -1,4 +1,5 @@ #include "../../include/database.h" +#include "../../include/error.h" #include "../../include/util.h" #include "../../include/ctx.h" @@ -9,3 +10,52 @@ lm_database_t *lm_ctx_database_new(lm_ctx_t *ctx){ join(dbpath, ctx->data, "db"); return lm_database_new(dbpath); } + +bool lm_ctx_database_is_installed(lm_ctx_t *ctx, lm_pkg_t *pkg, bool check_version){ + lm_database_t *db = lm_ctx_database_new(ctx); + lm_pkg_t found; + bool ret = false; + + if(NULL == db) + return false; + + if(!lm_database_find(db, &found, pkg->name)) + goto end; + + if(check_version && !eq(found.version, pkg->version)) + goto end; + + ret = true; +end: + lm_database_free(db); + return ret; +} + +bool lm_ctx_database_find(lm_ctx_t *ctx, lm_pkg_t *pkg, char *name){ + if(NULL == ctx || NULL == pkg || NULL == name){ + lm_error_set(LM_ERR_ArgNULL); + return false; + } + + lm_database_t *db = lm_ctx_database_new(ctx); + if(!lm_database_find(db, pkg, name)) + return false; + return true; +} + +bool lm_ctx_database_foreach(lm_ctx_t *ctx, lm_ctx_database_callback_t callback, void *data){ + if(NULL == ctx || NULL == callback){ + lm_error_set(LM_ERR_ArgNULL); + return false; + } + + lm_database_t *db = lm_ctx_database_new(ctx); + lm_pkg_t pkg; + + while(lm_database_next(db, &pkg)){ + if(!callback(ctx, &pkg, data)) + break; + } + + return true; +} diff --git a/src/ctx/find.c b/src/ctx/find.c new file mode 100644 index 0000000..f705931 --- /dev/null +++ b/src/ctx/find.c @@ -0,0 +1,22 @@ +#include "../../include/error.h" +#include "../../include/pool.h" +#include "../../include/ctx.h" + +lm_pkg_t *lm_ctx_find(lm_ctx_t *ctx, char *name, char *version){ + if(NULL == ctx || (NULL == name && NULL == version)){ + lm_error_set(LM_ERR_ArgNULL); + return NULL; + } + + lm_pool_t *cur = ctx->pools; + lm_pkg_t *found = NULL; + while(cur != NULL){ + if((found = lm_pool_package_find(cur, name, version)) != NULL) + break; + cur = cur->next; + } + + if(NULL == found) + lm_error_set(LM_ERR_PkgNotFound); + return found; +} diff --git a/src/ctx/install.c b/src/ctx/install.c new file mode 100644 index 0000000..e7b84d0 --- /dev/null +++ b/src/ctx/install.c @@ -0,0 +1,88 @@ +#include "../../include/package.h" +#include "../../include/error.h" +#include "../../include/pool.h" +#include "../../include/util.h" +#include "../../include/ctx.h" + +#include +#include + +typedef struct install_list { + lm_pkg_t *packages; + lm_pkg_t *resolving; + size_t count; +} install_list_t; + +bool install_resolve(lm_ctx_t *ctx, install_list_t *list, lm_pkg_t *pkg){ + if(pkglist_contains(list->packages, pkg)) + return true; + + if(NULL == pkg->depends) + goto end; + + list->resolving = pkglist_add(list->resolving, pkg); + + for(int i = 0; pkg->depends[i] != NULL; i++){ + lm_pkg_t *depend = lm_ctx_find(ctx, pkg->depends[i], NULL); + if(NULL == depend){ + lm_error_set(LM_ERR_DependNotFound, pkg->depends[i], pkg->name); + return false; + } + + if(lm_ctx_database_is_installed(ctx, depend, true)) + continue; + + if(pkglist_contains(list->resolving, depend)){ + lm_error_set(LM_ERR_DependNotFound, pkg->depends[i], pkg->name); + return false; + } + + if(!install_resolve(ctx, list, pkg)) + return false; + } + + list->resolving = pkglist_del(list->resolving, pkg); +end: + list->packages = pkglist_add(list->packages, pkg); + list->count++; + return true; +} + +bool lm_ctx_install(lm_ctx_t *ctx, char *package){ + lm_pkg_t *pkg = lm_ctx_find(ctx, package, NULL); + install_list_t list = { + .packages = NULL, + .resolving = NULL, + .count = 0, + }; + bool ret = false; + + if(NULL == pkg) + return ret; + + if(!install_resolve(ctx, &list, pkg)) + goto end; + + pkg = list.packages; + + while(pkg != NULL){ + if(lm_package_downloaded(pkg) && lm_package_verify(pkg)) + continue; + + if(!lm_pool_package_download(pkg->pool, pkg)){ + char *suberror = strdup(lm_strerror()); + lm_error_set(LM_ERR_InstallDownloadFail, pkg->name, suberror); + free(suberror); + return false; + } + + pkg = pkg->next; + } + + // actually install packages + +end: + pkglist_free(list.packages); + pkglist_free(list.resolving); + return true; +} diff --git a/src/ctx/pakcage.c b/src/ctx/pakcage.c index 909f210..e372f91 100644 --- a/src/ctx/pakcage.c +++ b/src/ctx/pakcage.c @@ -1,62 +1,18 @@ -#include "../../include/ctx.h" #include "../../include/pool.h" #include "../../include/package.h" #include "../../include/database.h" #include "../../include/util.h" #include "../../include/error.h" +#include "../../include/ctx.h" -lm_pkg_t *lm_ctx_package_get(lm_ctx_t *ctx, char *name, char *version) { - lm_pool_t *pool = ctx->pools; - lm_pkg_t *pkg = NULL; - - while (NULL != pool) { - if((pkg = lm_pool_package_find(pool, name, version)) != NULL) - break; - pool = pool->next; - } - - if(NULL == pool && NULL == pkg){ - lm_error_set(LM_ERR_PkgNotFound); - return NULL; - } - - if(!lm_pool_package_get(pool, pkg)) - return NULL; - - return pkg; +bool lm_ctx_package_install(lm_ctx_t *ctx, lm_pkg_t *pkg){ + return true; } -bool lm_ctx_package_verify(lm_ctx_t *ctx, char *name, char *version) { - lm_pool_t *pool = ctx->pools; - lm_pkg_t *pkg = NULL; - - while (NULL != pool) { - if((pkg = lm_pool_package_find(pool, name, version)) != NULL) - break; - pool = pool->next; - } - - if(NULL == pool && NULL == pkg){ - lm_error_set(LM_ERR_PkgNotFound); - return NULL; - } - - return lm_package_verify(pkg); +bool lm_ctx_package_remove(lm_ctx_t *ctx, lm_pkg_t *pkg){ + return true; } -bool lm_ctx_package_is_installed(lm_ctx_t *ctx, char *name, char *version) { - lm_database_t *db = lm_ctx_database_new(ctx); - - if(NULL == db) - return false; - - bool ret = lm_database_find(db, NULL, name); - lm_database_free(db); - - return ret; -} - -lm_pkg_t *lm_ctx_package_install(lm_ctx_t *ctx, char *name, char *version){ - - return NULL; +bool lm_ctx_package_verify(lm_ctx_t *ctx, lm_pkg_t *pkg){ + return true; } diff --git a/src/ctx/pool.c b/src/ctx/pool.c index 5d60118..eca11ee 100644 --- a/src/ctx/pool.c +++ b/src/ctx/pool.c @@ -43,25 +43,11 @@ lm_pool_t *lm_ctx_pool_add(lm_ctx_t *ctx, char *name, char *url) { } } - if (NULL == ctx->pools) { - ctx->pools = pool; - return pool; - } + // add to the start + pool->next = ctx->pools; + ctx->pools = pool; - lm_pool_t *cur = ctx->pools; - while (NULL != cur) { - if (NULL == cur->next) { - cur->next = pool; - return pool; - } - cur = cur->next; - } - - // if we somehow get here, something very wrong has happend - assert(true); - - lm_pool_free(pool); - return NULL; + return pool; } void lm_ctx_pool_clear(lm_ctx_t *ctx) { @@ -134,7 +120,7 @@ void lm_ctx_pool_get_info(lm_ctx_t *ctx, bool allow_update, bool force_update, l goto success; update: - if(!lm_pool_info_get(cur)){ + if(!lm_pool_info_download(cur)){ pdebug(__func__, "(%s) failed to update info: %s", cur->name, lm_strerror()); goto next; } @@ -174,7 +160,7 @@ void lm_ctx_pool_get_list(lm_ctx_t *ctx, bool allow_update, bool force_update, l goto success; update: - if(!lm_pool_list_get(cur)){ + if(!lm_pool_list_download(cur)){ pdebug(__func__, "(%s) failed to update list: %s", cur->name, lm_strerror()); goto next; } @@ -244,7 +230,7 @@ bool lm_ctx_pool_serve(lm_ctx_t *ctx, char *addr, uint8_t threads) { lm_pool_t *pool = lm_ctx_pool_by_url(ctx, hostname, ppath); if (NULL == pool) { - pdebug(__func__, "unknown pool (%s) closing connection", hostname); + pdebug(__func__, "unknown pool (%s), closing connection", hostname); lm_mptp_init(&packet, false, MPTP_S2C_BRUH, true); lm_mptp_server_send(sock, &packet, &saddr); continue; diff --git a/src/database/database.c b/src/database/database.c index a087c15..e5feb58 100644 --- a/src/database/database.c +++ b/src/database/database.c @@ -18,6 +18,7 @@ char *queries[] = { "INSERT INTO packages VALUES (?, ?, ?, ?, ?)", "SELECT * FROM packages WHERE name = '?'", "DELETE from packages WHERE name = '?'", + "SELECT * FROM packages", }; lm_database_t *lm_database_new(char *path){ @@ -50,6 +51,9 @@ lm_database_t *lm_database_new(char *path){ } void lm_database_free(lm_database_t *db){ + if(NULL != db->st) + sqlite3_finalize(db->st); + sqlite3_close(db->sql); free(db->dir); diff --git a/src/database/package.c b/src/database/package.c index 13fd013..ed0da9b 100644 --- a/src/database/package.c +++ b/src/database/package.c @@ -15,27 +15,26 @@ bool lm_database_add(lm_database_t *db, lm_pkg_t *pkg){ } char depends[lm_package_depend_strlen(pkg)]; - sqlite3_stmt *st = NULL; bool ret = false; - if(sqlite3_prepare(db->sql, queries[QUERY_INSERT_PACKAGE], strlen(queries[QUERY_INSERT_PACKAGE]), &st, NULL) != SQLITE_OK){ + if(sqlite3_prepare(db->sql, queries[QUERY_INSERT_PACKAGE], strlen(queries[QUERY_INSERT_PACKAGE]), &db->st, NULL) != SQLITE_OK){ pdebug(__func__, "failed to prepare statement for inserting %s: %s", pkg->name, sqlite3_errmsg(db->sql)); lm_error_set(LM_ERR_DbSqlPrepareFail); goto end; } - sqlite3_bind_text(st, 1, pkg->name, strlen(pkg->name), SQLITE_STATIC); - sqlite3_bind_text(st, 2, pkg->desc, strlen(pkg->desc), SQLITE_STATIC); - sqlite3_bind_text(st, 3, pkg->version, strlen(pkg->version), SQLITE_STATIC); - sqlite3_bind_int64(st, 4, pkg->size); + sqlite3_bind_text(db->st, 1, pkg->name, strlen(pkg->name), SQLITE_STATIC); + sqlite3_bind_text(db->st, 2, pkg->desc, strlen(pkg->desc), SQLITE_STATIC); + sqlite3_bind_text(db->st, 3, pkg->version, strlen(pkg->version), SQLITE_STATIC); + sqlite3_bind_int64(db->st, 4, pkg->size); if(!lm_package_depend_tostr(pkg, depends)){ pdebug(__func__, "failed to convert depends to string for inserting %s: %s", pkg->name, lm_strerror()); goto end; } - sqlite3_bind_text(st, 5, depends, strlen(depends), SQLITE_STATIC); + sqlite3_bind_text(db->st, 5, depends, strlen(depends), SQLITE_STATIC); - if(sqlite3_step(st) != SQLITE_DONE){ + if(sqlite3_step(db->st) != SQLITE_DONE){ pdebug(__func__, "failed to execute insert statement for inserting %s: %s", pkg->name, sqlite3_errmsg(db->sql)); lm_error_set(LM_ERR_DbSqlInsertFail); goto end; @@ -43,8 +42,10 @@ bool lm_database_add(lm_database_t *db, lm_pkg_t *pkg){ ret = true; end: - if(NULL != st) - sqlite3_finalize(st); + if(NULL != db->st){ + sqlite3_finalize(db->st); + db->st = NULL; + } return ret; } @@ -54,18 +55,17 @@ bool lm_database_find(lm_database_t *db, lm_pkg_t *pkg, char *name){ return false; } - sqlite3_stmt *st; bool ret = false; - if(sqlite3_prepare(db->sql, queries[QUERY_SELECT_PACKAGE], strlen(queries[QUERY_SELECT_PACKAGE]), &st, NULL) != SQLITE_OK){ + if(sqlite3_prepare(db->sql, queries[QUERY_SELECT_PACKAGE], strlen(queries[QUERY_SELECT_PACKAGE]), &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(st, 1, name, strlen(name), SQLITE_STATIC); + sqlite3_bind_text(db->st, 1, name, strlen(name), SQLITE_STATIC); - if(sqlite3_step(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; @@ -80,12 +80,12 @@ bool lm_database_find(lm_database_t *db, lm_pkg_t *pkg, char *name){ // we are initing it just in case the caller didn't lm_package_init(pkg); - pkg->name = strdup((char*)sqlite3_column_text(st, 0)); - pkg->desc = strdup((char*)sqlite3_column_text(st, 1)); - pkg->version = strdup((char*)sqlite3_column_text(st, 2)); - pkg->size = sqlite3_column_int64(st, 3); + pkg->name = strdup((char*)sqlite3_column_text(db->st, 0)); + pkg->desc = strdup((char*)sqlite3_column_text(db->st, 1)); + pkg->version = strdup((char*)sqlite3_column_text(db->st, 2)); + pkg->size = sqlite3_column_int64(db->st, 3); - char *depends = (char*)sqlite3_column_text(st, 3); + char *depends = (char*)sqlite3_column_text(db->st, 3); if(!lm_package_depend_fromstr(pkg, depends)){ pdebug(__func__, "failed to load depends for finding %s: %s", pkg->name, lm_strerror()); // error is set by the function @@ -94,8 +94,10 @@ bool lm_database_find(lm_database_t *db, lm_pkg_t *pkg, char *name){ ret = true; end: - if(NULL != st) - sqlite3_finalize(st); + if(NULL != db->st){ + sqlite3_finalize(db->st); + db->st = NULL; + } return ret; } @@ -105,18 +107,17 @@ bool lm_database_del(lm_database_t *db, lm_pkg_t *pkg){ return false; } - sqlite3_stmt *st; bool ret = false; - if(sqlite3_prepare(db->sql, queries[QUERY_DELETE_PACKAGE], strlen(queries[QUERY_DELETE_PACKAGE]), &st, NULL) != SQLITE_OK){ + if(sqlite3_prepare(db->sql, queries[QUERY_DELETE_PACKAGE], strlen(queries[QUERY_DELETE_PACKAGE]), &db->st, NULL) != SQLITE_OK){ pdebug(__func__, "failed to prepare statement for deleting %s: %s", pkg->name, sqlite3_errmsg(db->sql)); lm_error_set(LM_ERR_DbSqlPrepareFail); goto end; } - sqlite3_bind_text(st, 1, pkg->name, strlen(pkg->name), SQLITE_STATIC); + sqlite3_bind_text(db->st, 1, pkg->name, strlen(pkg->name), SQLITE_STATIC); - if(sqlite3_step(st) != SQLITE_DONE){ + if(sqlite3_step(db->st) != SQLITE_DONE){ pdebug(__func__, "failed to execute delete statement for deleting %s: %s", pkg->name, sqlite3_errmsg(db->sql)); lm_error_set(LM_ERR_DbSqlInsertFail); goto end; @@ -124,7 +125,50 @@ bool lm_database_del(lm_database_t *db, lm_pkg_t *pkg){ ret = true; end: - if(NULL != st) - sqlite3_finalize(st); + if(NULL != db->st){ + sqlite3_finalize(db->st); + db->st = NULL; + } return ret; } + +bool lm_database_next(lm_database_t *db, lm_pkg_t *pkg){ + if(NULL == db || NULL == pkg){ + lm_error_set(LM_ERR_ArgNULL); + return false; + } + + if(NULL == db->st){ + if(sqlite3_prepare(db->sql, queries[QUERY_ALL_PACKAGE], strlen(queries[QUERY_ALL_PACKAGE]), &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; + } + } + + else + lm_package_free(pkg); + + if(sqlite3_step(db->st) != SQLITE_ROW){ + sqlite3_finalize(db->st); + db->st = NULL; + return false; + } + + lm_package_init(pkg); + + pkg->name = strdup((char*)sqlite3_column_text(db->st, 0)); + pkg->desc = strdup((char*)sqlite3_column_text(db->st, 1)); + pkg->version = strdup((char*)sqlite3_column_text(db->st, 2)); + pkg->size = sqlite3_column_int64(db->st, 3); + + char *depends = (char*)sqlite3_column_text(db->st, 3); + if(!lm_package_depend_fromstr(pkg, depends)){ + pdebug(__func__, "failed to load depends for finding %s: %s", pkg->name, lm_strerror()); + sqlite3_finalize(db->st); + return false; + } + + return true; +} + diff --git a/src/error.c b/src/error.c index 44fcd16..d5633df 100644 --- a/src/error.c +++ b/src/error.c @@ -1,14 +1,20 @@ #include "../include/error.h" #include "../include/util.h" + +#include +#include #include -lm_error_t error = LM_ERR_NoError; +lm_error_t error = LM_ERR_NoError; +char *error_str = NULL; -void lm_error_set(lm_error_t code) { - error = code; +void lm_error_clear() { + free(error_str); + error = LM_ERR_NoError; + error_str = NULL; } -char *lm_strerror() { +void lm_error_set(lm_error_t code, ...) { lm_error_desc_t errors[] = { {.code = LM_ERR_NoError, .desc = _("no error") }, {.code = LM_ERR_URLBadChar, .desc = _("URL contains an invalid character") }, @@ -100,13 +106,44 @@ char *lm_strerror() { {.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") }, {.code = LM_ERR_DbKeepsUnlinkFail, .desc = _("failed to remove package keep list from the database") }, + {.code = LM_ERR_DependNotFound, .desc = _("failed to find %s (dependency of %s)") }, + {.code = LM_ERR_InstallDownloadFail, .desc = _("failed to download %s for installation: %s") }, + {.code = LM_ERR_PkgNotDownloaded, .desc = _("package is not downloaded") }, + {.code = LM_ERR_PkgRemoveDownloadFail, .desc = _("failed to remove downloaded package") }, }; - for (int i = 0; i < sizeof(errors) / sizeof(lm_error_desc_t); i++) { - if (errors[i].code == error) - return errors[i].desc; + char *fmt = NULL; + error = code; + + if (NULL != error_str) { + free(error_str); + error_str = NULL; } - return NULL; + + for (int i = 0; i < sizeof(errors) / sizeof(lm_error_desc_t); i++) { + if (errors[i].code == error) { + fmt = errors[i].desc; + break; + } + } + + if (NULL == fmt) + return; + + va_list args, argscp; + va_start(args, code); + va_copy(argscp, args); + + int size = vsnprintf(NULL, 0, fmt, args); + error_str = malloc(size + 1); + vsnprintf(error_str, size, fmt, args); + + va_end(args); + va_end(argscp); +} + +char *lm_strerror() { + return error_str; } lm_error_t lm_error() { diff --git a/src/package/package.c b/src/package/package.c index e08cc6c..41bbc14 100644 --- a/src/package/package.c +++ b/src/package/package.c @@ -2,9 +2,12 @@ #include "../../include/error.h" #include "../../include/types.h" #include "../../include/mptp.h" +#include "../../include/util.h" +#include #include #include +#include lm_pkg_t *lm_package_new(){ lm_pkg_t *pkg = malloc(sizeof(lm_pkg_t)); @@ -16,6 +19,34 @@ void lm_package_init(lm_pkg_t *pkg){ bzero(pkg, sizeof(lm_pkg_t)); } +bool lm_package_downloaded(lm_pkg_t *pkg){ + if(lm_package_path_is_empty(pkg)){ + lm_error_set(LM_ERR_PkgPathsEmpty); + return false; + } + + if(!exists(pkg->paths.archive) || !exists(pkg->paths.signature)){ + lm_error_set(LM_ERR_PkgNotDownloaded); + return false; + } + + return true; +} + +bool lm_package_remove_download(lm_pkg_t *pkg){ + if(unlink(pkg->paths.archive) < 0 && errno != ENOENT){ + lm_error_set(LM_ERR_PkgRemoveDownloadFail); + return false; + } + + if(unlink(pkg->paths.signature) < 0 && errno != ENOENT){ + lm_error_set(LM_ERR_PkgRemoveDownloadFail); + return false; + } + + return true; +} + void lm_package_free(lm_pkg_t *pkg){ lm_package_data_free(pkg); bzero(pkg, sizeof(lm_pkg_t)); diff --git a/src/package/verify.c b/src/package/verify.c index 6a60760..2a7613c 100644 --- a/src/package/verify.c +++ b/src/package/verify.c @@ -11,10 +11,9 @@ bool lm_package_verify(lm_pkg_t *pkg){ return false; } - if(lm_package_path_is_empty(pkg)){ - lm_error_set(LM_ERR_PkgPathsEmpty); + // error set by function + if(!lm_package_downloaded(pkg)) return false; - } gpgme_data_t sig = NULL, text = NULL; gpgme_ctx_t ctx = NULL; diff --git a/src/pool/info.c b/src/pool/info.c index edfa5c5..f3b7edc 100644 --- a/src/pool/info.c +++ b/src/pool/info.c @@ -60,7 +60,7 @@ bool lm_pool_info_load(lm_pool_t *pool) { return true; } -bool lm_pool_info_get(lm_pool_t *pool) { +bool lm_pool_info_download(lm_pool_t *pool) { if(NULL == pool){ lm_error_set(LM_ERR_ArgNULL); return false; diff --git a/src/pool/list.c b/src/pool/list.c index dd3f0b0..75db3c8 100644 --- a/src/pool/list.c +++ b/src/pool/list.c @@ -85,7 +85,7 @@ end: return ret; } -bool lm_pool_list_get(lm_pool_t *pool) { +bool lm_pool_list_download(lm_pool_t *pool) { if(NULL == pool){ lm_error_set(LM_ERR_ArgNULL); return false; diff --git a/src/pool/package.c b/src/pool/package.c index 27a63b4..07be3e3 100644 --- a/src/pool/package.c +++ b/src/pool/package.c @@ -35,6 +35,8 @@ bool lm_pool_package_add(lm_pool_t *pool, lm_pkg_t *pkg){ return false; } + pkg->pool = pool; + if(!lm_pool_path_is_empty(pool)){ size_t path_size = strlen(pool->paths.dir)+strlen(pkg->name)+strlen(pkg->version); size_t name_size = path_size - strlen(pool->paths.dir); @@ -52,24 +54,13 @@ bool lm_pool_package_add(lm_pool_t *pool, lm_pkg_t *pkg){ lm_package_path_set_signature(pkg, sig_path); } - if(NULL == pool->pkg){ - pool->pkg = pkg; - return true; - } - - lm_pkg_t *cur = pool->pkg; - while(NULL != cur){ - if(NULL == cur->next){ - cur->next = pkg; - return true; - } - cur = cur->next; - } - - return false; + // add to the start + pkg->next = pool->pkg; + pool->pkg = pkg; + return true; } -bool lm_pool_package_get(lm_pool_t *pool, lm_pkg_t *pkg){ +bool lm_pool_package_download(lm_pool_t *pool, lm_pkg_t *pkg){ if(NULL == pool || NULL == pkg){ lm_error_set(LM_ERR_ArgNULL); return false; diff --git a/src/pool/pool.c b/src/pool/pool.c index ca71d1e..d937231 100644 --- a/src/pool/pool.c +++ b/src/pool/pool.c @@ -10,7 +10,7 @@ lm_pool_t *lm_pool_new(char *name, char *url) { lm_pool_t *pool = malloc(sizeof(lm_pool_t)); bzero(pool, sizeof(lm_pool_t)); - pool->available = true; + pool->available = false; pool->name = name; if (NULL != url && !lm_url_init(&pool->url, url)) { diff --git a/src/util.c b/src/util.c index c2209be..f3d72ec 100644 --- a/src/util.c +++ b/src/util.c @@ -325,3 +325,67 @@ char *join_alloc(const char *base, const char *pth) { join(path, base, pth); return path; } + +bool pkglist_contains(lm_pkg_t *list, lm_pkg_t *pkg) { + lm_pkg_t *cur = list; + while (cur) { + if (eq(pkg->name, cur->name)) + return true; + cur = cur->next; + } + return false; +} + +lm_pkg_t *pkglist_del(lm_pkg_t *list, lm_pkg_t *pkg) { + if (NULL == list) + return list; + + lm_pkg_t *cur = list; + lm_pkg_t *target = NULL; + int indx = 0; + + while (cur) { + if (eq(cur->name, pkg->name)) { + target = cur; + break; + } + cur = cur->next; + indx++; + } + + if (NULL == target) + return list; + + cur = list; + for (int i = 0; i < indx; i++) { + if (cur->next != NULL) + cur = cur->next; + } + + if (NULL == cur->next) + list = NULL; + else + cur->next = cur->next->next; + + free(target); + return list; +} + +lm_pkg_t *pkglist_add(lm_pkg_t *list, lm_pkg_t *pkg) { + lm_pkg_t *new = malloc(sizeof(lm_pkg_t)); + memcpy(new, pkg, sizeof(lm_pkg_t)); + new->next = NULL; + + new->next = list; + list = new; + return list; +} + +void pkglist_free(lm_pkg_t *list) { + lm_pkg_t *cur = list; + while (cur) { + lm_pkg_t *old = cur; + cur = cur->next; + free(old); + } +}