diff --git a/Makefile b/Makefile index 039c680..bd3578a 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,9 @@ dist/libmp.so: $(OBJS) $(CC) -shared -o $@ $^ $(LIBS) $(CFLAGS) dist/%.o: src/%.c - mkdir -p dist + mkdir -p dist/pkg + mkdir -p dist/mptp + mkdir -p dist/pool $(CC) -c -Wall -fPIC -o $@ $^ $(LIBS) $(CFLAGS) -DVERSION=\"${VERSION}\" locale/%.mo: locale/%.po diff --git a/include/error.h b/include/error.h index 596a006..cbb81fb 100644 --- a/include/error.h +++ b/include/error.h @@ -34,6 +34,14 @@ typedef enum lm_error { LM_ERR_MPTPNotLast = 30, LM_ERR_NoPort = 31, LM_ERR_PoolInfoBad = 32, + LM_ERR_ArcWBlockFail = 33, + LM_ERR_ArcRBlockFail = 34, + LM_ERR_ArcOpenFail = 35, + LM_ERR_ArcWHeaderFail = 36, + LM_ERR_ArcWEntryFail = 37, + LM_ERR_GetCwdFail = 38, + LM_ERR_PoolListDirFail = 39, + } lm_error_t; typedef struct lm_error_desc { diff --git a/include/mptp.h b/include/mptp.h index f51b165..535a108 100644 --- a/include/mptp.h +++ b/include/mptp.h @@ -127,7 +127,6 @@ bool lm_mptp_set_data(lm_mptp_t *packet, char *data, size_t size); bool lm_mptp_set_host(lm_mptp_t *packet, char *host); bool lm_mptp_get_host(lm_mptp_t *packet, char *host); bool lm_mptp_get_data(lm_mptp_t *packet, char *data); - int lm_mptp_socket(char *addr, uint16_t port, struct sockaddr *saddr); void lm_mptp_copy(lm_mptp_t *dst, lm_mptp_t *src); bool lm_mptp_verify(lm_mptp_t *packet); diff --git a/include/pkg.h b/include/pkg.h new file mode 100644 index 0000000..3bac697 --- /dev/null +++ b/include/pkg.h @@ -0,0 +1,8 @@ +#pragma once +#include "types.h" +#include + +lm_pkg_t *lm_pkg_new(); +void lm_pkg_free(lm_pkg_t *pkg); + +bool lm_pkg_data_load(lm_pkg_t *pkg, char *file); diff --git a/include/pool.h b/include/pool.h index cb57589..e052a7d 100644 --- a/include/pool.h +++ b/include/pool.h @@ -1,6 +1,7 @@ #pragma once #include "mptp.h" #include "types.h" + #include #include @@ -13,8 +14,12 @@ typedef struct lm_pool_thread_arg { lm_pool_t *lm_pool_new(char *name, char *url); void lm_pool_test(lm_pool_t *pool); -bool lm_pool_info_load(lm_pool_t *pool, char *file); -void lm_pool_info_free(lm_pool_t *pool); void lm_pool_free(lm_pool_t *pool); -void lm_pool_serve_thread(void *arg); -void lm_pool_serve(lm_pool_t *pool, lm_mptp_t *packet, int sock, struct sockaddr *addr); +bool lm_pool_add(lm_pool_t *pool, lm_pkg_t *pkg); + +bool lm_pool_info_load(lm_pool_t *pool, char *file); +bool lm_pool_info_get(lm_pool_t *pool, char *file); +void lm_pool_info_free(lm_pool_t *pool); + +void lm_pool_serve(lm_pool_t *pool, lm_mptp_t *packet, int sock, struct sockaddr *addr); +void lm_pool_serve_thread(void *arg); diff --git a/include/types.h b/include/types.h index 7104aba..0e6e2a5 100644 --- a/include/types.h +++ b/include/types.h @@ -3,6 +3,15 @@ #include #include +typedef struct lm_pkg { + struct lm_pkg *next; + char *name; + char *desc; + char **depends; + char *version; + size_t size; +} lm_pkg_t; + typedef struct lm_pool_info { char *maintainer; char *pubkey; @@ -14,6 +23,7 @@ typedef struct lm_pool { struct lm_pool *next; lm_pool_info_t info; lm_url_t url; + lm_pkg_t *pkg; bool available; char *name; } lm_pool_t; diff --git a/include/util.h b/include/util.h index 6dcee32..f92bc7a 100644 --- a/include/util.h +++ b/include/util.h @@ -14,3 +14,4 @@ bool is_letter(char c); bool is_digit(char c); bool copy_to_buffer(void *buffer, void *src, size_t size, ssize_t *total, ssize_t *used); bool copy_from_buffer(void *dst, void *buffer, size_t size, ssize_t *total, ssize_t *used); +bool extract_archive(char *dst, char *src); diff --git a/locale/tr/LC_MESSAGES/libmp.po b/locale/tr/LC_MESSAGES/libmp.po index f5a1412..8847f1f 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-06-25 20:58+0300\n" +"POT-Creation-Date: 2024-06-26 22:32+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -154,3 +154,31 @@ msgstr "" #: src/error.c:45 msgid "failed to parse pool info" msgstr "" + +#: src/error.c:46 +msgid "failed to write block from archive" +msgstr "" + +#: src/error.c:47 +msgid "failed to read block from archive" +msgstr "" + +#: src/error.c:48 +msgid "failed to open archive" +msgstr "" + +#: src/error.c:49 +msgid "failed to write archive header" +msgstr "" + +#: src/error.c:50 +msgid "failed to finish writing the archive entry" +msgstr "" + +#: src/error.c:51 +msgid "failed to obtain current working directory" +msgstr "" + +#: src/error.c:52 +msgid "failed to open extracted pool list directory" +msgstr "" diff --git a/src/error.c b/src/error.c index e24b960..4cf0ad6 100644 --- a/src/error.c +++ b/src/error.c @@ -43,6 +43,13 @@ char *lm_strerror() { {.code = LM_ERR_MPTPNotLast, .desc = _("MPTP request last flag is not set") }, {.code = LM_ERR_NoPort, .desc = _("host port not specified") }, {.code = LM_ERR_PoolInfoBad, .desc = _("failed to parse pool info") }, + {.code = LM_ERR_ArcWBlockFail, .desc = _("failed to write block from archive") }, + {.code = LM_ERR_ArcRBlockFail, .desc = _("failed to read block from archive") }, + {.code = LM_ERR_ArcOpenFail, .desc = _("failed to open archive") }, + {.code = LM_ERR_ArcWHeaderFail, .desc = _("failed to write archive header") }, + {.code = LM_ERR_ArcWEntryFail, .desc = _("failed to finish writing the archive entry") }, + {.code = LM_ERR_GetCwdFail, .desc = _("failed to obtain current working directory") }, + {.code = LM_ERR_PoolListDirFail, .desc = _("failed to open extracted pool list directory") }, }; for (int i = 0; i < sizeof(errors) / sizeof(lm_error_desc_t); i++) { diff --git a/src/libmp.c b/src/libmp.c index b8d59b4..8cfc8f1 100644 --- a/src/libmp.c +++ b/src/libmp.c @@ -28,6 +28,7 @@ #include "../include/pool.h" #include "../include/thpool.h" #include "../include/util.h" + #include #include #include diff --git a/src/mptp.c b/src/mptp.c deleted file mode 100644 index 0a872b8..0000000 --- a/src/mptp.c +++ /dev/null @@ -1,413 +0,0 @@ -#include "../include/mptp.h" -#include "../include/error.h" -#include "../include/url.h" -#include "../include/util.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -bool lm_mptp_init(lm_mptp_t *packet, bool is_request, uint8_t code, bool is_last) { - packet->header.flags = 0; - packet->header.data_size = 0; - packet->header.host_size = 0; - - bzero(packet->data, MPTP_DATA_MAX); - bzero(packet->host, MPTP_HOST_MAX); - - if (code > MPTP_CODE_MAX) { - lm_error_set(LM_ERR_MPTPBadCode); - return false; - } - - packet->header.flags |= (MPTP_VERSION_SUPPORTED << 8); - - if (is_request) - packet->header.flags |= (MPTP_REQUEST << 7); - else - packet->header.flags |= (MPTP_RESPONSE << 7); - - packet->header.flags |= (code << 4); - - if (is_last || is_request) - packet->header.flags |= (1 << 3); - else - packet->header.flags |= (0 << 3); - - return true; -} - -bool lm_mptp_set_host(lm_mptp_t *packet, char *host) { - size_t size = strlen(host); - if (size > MPTP_HOST_MAX || size < 0) { - lm_error_set(LM_ERR_MPTPBadHost); - return false; - } - - // do NOT copy the NULL terminator - packet->header.host_size = size; - memcpy(packet->host, host, size); - return true; -} - -bool lm_mptp_get_host(lm_mptp_t *packet, char *host) { - if (packet->header.host_size > MPTP_HOST_MAX || packet->header.host_size < 0) { - host = NULL; - lm_error_set(LM_ERR_BadHost); - return false; - } - - memcpy(host, packet->host, packet->header.host_size); - host[packet->header.host_size] = 0; - return true; -} - -bool lm_mptp_set_data(lm_mptp_t *packet, char *data, size_t size) { - if (size > MPTP_DATA_MAX || size < 0) { - lm_error_set(LM_ERR_MPTPBadData); - return false; - } - - packet->header.data_size = size; - mempcpy(packet->data, data, size); - return true; -} - -bool lm_mptp_get_data(lm_mptp_t *packet, char *data) { - if (packet->header.data_size > MPTP_DATA_MAX || packet->header.data_size < 0) { - data = NULL; - lm_error_set(LM_ERR_BadHost); - return false; - } - - memcpy(data, packet->data, packet->header.data_size); - data[packet->header.data_size] = 0; - return true; -} - -bool lm_mptp_verify(lm_mptp_t *packet) { - if (NULL == packet) { - lm_error_set(LM_ERR_ArgNULL); - return false; - } - - if (MPTP_FLAGS_VERSION(packet) != MPTP_VERSION_SUPPORTED) { - lm_error_set(LM_ERR_MPTPBadVersion); - return false; - } - - if (packet->header.data_size > MPTP_DATA_MAX || packet->header.data_size < 0) { - lm_error_set(LM_ERR_MPTPBadData); - return false; - } - - if (MPTP_FLAGS_CODE(packet) > MPTP_CODE_MAX || MPTP_FLAGS_CODE(packet) < 0) { - lm_error_set(LM_ERR_MPTPBadCode); - return false; - } - - return true; -} - -int lm_mptp_socket(char *addr, uint16_t port, struct sockaddr *saddr) { - if (NULL == addr || NULL == saddr) { - lm_error_set(LM_ERR_ArgNULL); - return -1; - } - - struct addrinfo hints, *res, *cur; - int sock = 0, status = 0, family = -1; - - bzero(&hints, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_DGRAM; - - if ((status = getaddrinfo(addr, NULL, &hints, &res)) < 0) { - lm_error_set(LM_ERR_MPTPHostFail); - return -1; - } - - for (cur = res; cur != NULL; cur = cur->ai_next) { - switch (cur->ai_family) { - case AF_INET: - family = cur->ai_family; - struct sockaddr_in *ipv4 = (struct sockaddr_in *)cur->ai_addr; - ipv4->sin_port = htons(port); - - memcpy(saddr, cur->ai_addr, sizeof(struct sockaddr)); - break; - - case AF_INET6: - family = cur->ai_family; - struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)cur->ai_addr; - ipv6->sin6_port = htons(port); - - memcpy(saddr, cur->ai_addr, sizeof(struct sockaddr)); - break; - } - - if (family != -1) - break; - } - - freeaddrinfo(res); - - if (family == -1) { - lm_error_set(LM_ERR_MPTPHostFail); - return -1; - } - - if ((sock = socket(family, SOCK_DGRAM, IPPROTO_UDP)) < 0) { - lm_error_set(LM_ERR_MPTPSocketFail); - return -1; - } - - return sock; -} - -void lm_mptp_close(int sock) { - close(sock); -} - -int lm_mptp_client_connect(char *addr, uint16_t port) { - struct sockaddr saddr; - int sock; - - bzero(&saddr, sizeof(saddr)); - - if ((sock = lm_mptp_socket(addr, port, &saddr)) < 0) - return -1; - - struct timeval timeout; - bzero(&timeout, sizeof(timeout)); - - timeout.tv_sec = MPTP_TIMEOUT; - timeout.tv_usec = 0; - - if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) < 0) { - lm_error_set(LM_ERR_MPTPSetsockopt); - lm_mptp_close(sock); - return -1; - } - - if (connect(sock, &saddr, sizeof(saddr)) < 0) { - lm_mptp_close(sock); - lm_error_set(LM_ERR_MPTPConnectFail); - return -1; - } - - return sock; -} - -bool lm_mptp_client_verify(lm_mptp_t *packet) { - if (!lm_mptp_verify(packet)) - return false; - - if (MPTP_IS_REQUEST(packet)) { - lm_error_set(LM_ERR_MPTPNotResponse); - return false; - } - - if (packet->header.host_size != 0) { - lm_error_set(LM_ERR_MPTPBadHost); - return false; - } - - return true; -} - -bool lm_mptp_client_send(int sock, lm_mptp_t *packet) { - if (NULL == packet) { - lm_error_set(LM_ERR_ArgNULL); - return false; - } - - if (MPTP_FLAGS_VERSION(packet) != MPTP_VERSION_SUPPORTED) { - lm_error_set(LM_ERR_MPTPBadVersion); - return false; - } - - if (packet->header.data_size > MPTP_DATA_MAX) { - lm_error_set(LM_ERR_MPTPBadData); - return false; - } - - if (packet->header.host_size > MPTP_HOST_MAX || packet->header.host_size <= 0) { - lm_error_set(LM_ERR_MPTPBadHost); - return false; - } - - char buffer[sizeof(packet->header) + packet->header.host_size + packet->header.data_size]; - ssize_t total = sizeof(buffer), used = 0; - - packet->header.flags = htons(packet->header.flags); - - copy_to_buffer(buffer, &packet->header, sizeof(packet->header), &total, &used); - copy_to_buffer(buffer, packet->host, packet->header.host_size, &total, &used); - copy_to_buffer(buffer, packet->data, packet->header.data_size, &total, &used); - - if (send(sock, buffer, sizeof(buffer), 0) < 0) { - lm_error_set(LM_ERR_MPTPSendFail); - return false; - } - - return true; -} - -bool lm_mptp_client_recv(int sock, lm_mptp_t *packet) { - if (NULL == packet) { - lm_error_set(LM_ERR_ArgNULL); - return false; - } - - char buffer[sizeof(packet->header) + MPTP_HOST_MAX + MPTP_DATA_MAX]; - ssize_t total = sizeof(buffer), used = 0; - - bzero(buffer, sizeof(buffer)); - bzero(packet, sizeof(lm_mptp_t)); - - if (recv(sock, buffer, sizeof(buffer), 0) < 0) { - if (ETIMEDOUT == errno || EAGAIN == errno) { - lm_error_set(LM_ERR_MPTPTimeout); - return false; - } - lm_error_set(LM_ERR_MPTPRecvFail); - return false; - } - - copy_from_buffer(&packet->header, buffer, sizeof(packet->header), &total, &used); - packet->header.flags = ntohs(packet->header.flags); - // packet->header.host_size = ntohs(packet->header.host_size); - // packet->header.data_size = ntohs(packet->header.data_size); - - if (packet->header.host_size <= MPTP_HOST_MAX) - copy_from_buffer(&packet->host, buffer, packet->header.host_size, &total, &used); - - if (packet->header.data_size <= MPTP_DATA_MAX) - copy_from_buffer(&packet->data, buffer, packet->header.data_size, &total, &used); - - return true; -} - -int lm_mptp_server_listen(char *addr, uint16_t port) { - struct sockaddr saddr; - int sock; - - bzero(&saddr, sizeof(saddr)); - - if ((sock = lm_mptp_socket(addr, port, &saddr)) < 0) - return -1; - - if (bind(sock, &saddr, sizeof(struct sockaddr)) < 0) { - lm_mptp_close(sock); - lm_error_set(LM_ERR_MPTPBindFail); - return -1; - } - - return sock; -} - -bool lm_mptp_server_verify(lm_mptp_t *packet) { - if (!lm_mptp_verify(packet)) - return false; - - if (!MPTP_IS_REQUEST(packet)) { - lm_error_set(LM_ERR_MPTPNotRequest); - return false; - } - - if (packet->header.host_size > MPTP_HOST_MAX || packet->header.host_size <= 0) { - lm_error_set(LM_ERR_MPTPBadHost); - return false; - } - - if (!MPTP_IS_LAST(packet)) { - lm_error_set(LM_ERR_MPTPNotLast); - return false; - } - - return true; -} - -bool lm_mptp_server_recv(int sock, lm_mptp_t *packet, struct sockaddr *addr) { - if (NULL == packet || NULL == addr) { - lm_error_set(LM_ERR_ArgNULL); - return false; - } - - char buffer[sizeof(packet->header) + MPTP_HOST_MAX + MPTP_DATA_MAX]; - socklen_t socklen = sizeof(struct sockaddr); - ssize_t total = sizeof(buffer), used = 0; - - bzero(buffer, sizeof(buffer)); - bzero(packet, sizeof(lm_mptp_t)); - - if (recvfrom(sock, buffer, sizeof(buffer), 0, addr, &socklen) <= 0) { - lm_error_set(LM_ERR_MPTPRecvFail); - return false; - } - - copy_from_buffer(&packet->header, buffer, sizeof(packet->header), &total, &used); - packet->header.flags = ntohs(packet->header.flags); - // packet->header.host_size = ntohs(packet->header.host_size); - // packet->header.data_size = ntohs(packet->header.data_size); - - if (packet->header.host_size <= MPTP_HOST_MAX) - copy_from_buffer(&packet->host, buffer, packet->header.host_size, &total, &used); - - if (packet->header.data_size <= MPTP_DATA_MAX) - copy_from_buffer(&packet->data, buffer, packet->header.data_size, &total, &used); - - return true; -} - -bool lm_mptp_server_send(int sock, lm_mptp_t *packet, struct sockaddr *addr) { - if (NULL == packet) { - lm_error_set(LM_ERR_ArgNULL); - return false; - } - - if (MPTP_FLAGS_VERSION(packet) != MPTP_VERSION_SUPPORTED) { - lm_error_set(LM_ERR_MPTPBadVersion); - return false; - } - - if (packet->header.data_size > MPTP_DATA_MAX) { - lm_error_set(LM_ERR_MPTPBadData); - return false; - } - - if (packet->header.host_size != 0) { - lm_error_set(LM_ERR_MPTPBadHost); - return false; - } - - socklen_t addrlen = sizeof(struct sockaddr); - char buffer[sizeof(packet->header) + packet->header.host_size + packet->header.data_size]; - ssize_t total = sizeof(buffer), used = 0; - - packet->header.flags = htons(packet->header.flags); - - copy_to_buffer(buffer, &packet->header, sizeof(packet->header), &total, &used); - copy_to_buffer(buffer, packet->host, packet->header.host_size, &total, &used); - copy_to_buffer(buffer, packet->data, packet->header.data_size, &total, &used); - - if (sendto(sock, buffer, sizeof(buffer), 0, addr, addrlen) < 0) { - lm_error_set(LM_ERR_MPTPSendFail); - return false; - } - - return true; -} - -void lm_mptp_copy(lm_mptp_t *dst, lm_mptp_t *src) { - memcpy(&dst->header, &src->header, sizeof(dst->header)); - memcpy(&dst->host, &src->data, sizeof(src->host)); - memcpy(&dst->data, &src->data, sizeof(src->data)); -} diff --git a/src/mptp/client.c b/src/mptp/client.c new file mode 100644 index 0000000..833d2e3 --- /dev/null +++ b/src/mptp/client.c @@ -0,0 +1,128 @@ +#include "../../include/error.h" +#include "../../include/mptp.h" +#include "../../include/util.h" + +#include +#include +#include +#include + +int lm_mptp_client_connect(char *addr, uint16_t port) { + struct sockaddr saddr; + int sock; + + bzero(&saddr, sizeof(saddr)); + + if ((sock = lm_mptp_socket(addr, port, &saddr)) < 0) + return -1; + + struct timeval timeout; + bzero(&timeout, sizeof(timeout)); + + timeout.tv_sec = MPTP_TIMEOUT; + timeout.tv_usec = 0; + + if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) < 0) { + lm_error_set(LM_ERR_MPTPSetsockopt); + lm_mptp_close(sock); + return -1; + } + + if (connect(sock, &saddr, sizeof(saddr)) < 0) { + lm_mptp_close(sock); + lm_error_set(LM_ERR_MPTPConnectFail); + return -1; + } + + return sock; +} + +bool lm_mptp_client_verify(lm_mptp_t *packet) { + if (!lm_mptp_verify(packet)) + return false; + + if (MPTP_IS_REQUEST(packet)) { + lm_error_set(LM_ERR_MPTPNotResponse); + return false; + } + + if (packet->header.host_size != 0) { + lm_error_set(LM_ERR_MPTPBadHost); + return false; + } + + return true; +} + +bool lm_mptp_client_send(int sock, lm_mptp_t *packet) { + if (NULL == packet) { + lm_error_set(LM_ERR_ArgNULL); + return false; + } + + if (MPTP_FLAGS_VERSION(packet) != MPTP_VERSION_SUPPORTED) { + lm_error_set(LM_ERR_MPTPBadVersion); + return false; + } + + if (packet->header.data_size > MPTP_DATA_MAX) { + lm_error_set(LM_ERR_MPTPBadData); + return false; + } + + if (packet->header.host_size > MPTP_HOST_MAX || packet->header.host_size <= 0) { + lm_error_set(LM_ERR_MPTPBadHost); + return false; + } + + char buffer[sizeof(packet->header) + packet->header.host_size + packet->header.data_size]; + ssize_t total = sizeof(buffer), used = 0; + + packet->header.flags = htons(packet->header.flags); + + copy_to_buffer(buffer, &packet->header, sizeof(packet->header), &total, &used); + copy_to_buffer(buffer, packet->host, packet->header.host_size, &total, &used); + copy_to_buffer(buffer, packet->data, packet->header.data_size, &total, &used); + + if (send(sock, buffer, sizeof(buffer), 0) < 0) { + lm_error_set(LM_ERR_MPTPSendFail); + return false; + } + + return true; +} + +bool lm_mptp_client_recv(int sock, lm_mptp_t *packet) { + if (NULL == packet) { + lm_error_set(LM_ERR_ArgNULL); + return false; + } + + char buffer[sizeof(packet->header) + MPTP_HOST_MAX + MPTP_DATA_MAX]; + ssize_t total = sizeof(buffer), used = 0; + + bzero(buffer, sizeof(buffer)); + bzero(packet, sizeof(lm_mptp_t)); + + if (recv(sock, buffer, sizeof(buffer), 0) < 0) { + if (ETIMEDOUT == errno || EAGAIN == errno) { + lm_error_set(LM_ERR_MPTPTimeout); + return false; + } + lm_error_set(LM_ERR_MPTPRecvFail); + return false; + } + + copy_from_buffer(&packet->header, buffer, sizeof(packet->header), &total, &used); + packet->header.flags = ntohs(packet->header.flags); + // packet->header.host_size = ntohs(packet->header.host_size); + // packet->header.data_size = ntohs(packet->header.data_size); + + if (packet->header.host_size <= MPTP_HOST_MAX) + copy_from_buffer(&packet->host, buffer, packet->header.host_size, &total, &used); + + if (packet->header.data_size <= MPTP_DATA_MAX) + copy_from_buffer(&packet->data, buffer, packet->header.data_size, &total, &used); + + return true; +} diff --git a/src/mptp/mptp.c b/src/mptp/mptp.c new file mode 100644 index 0000000..d1f9680 --- /dev/null +++ b/src/mptp/mptp.c @@ -0,0 +1,175 @@ +#include "../../include/error.h" +#include "../../include/mptp.h" +#include "../../include/url.h" + +#include +#include +#include + +bool lm_mptp_init(lm_mptp_t *packet, bool is_request, uint8_t code, bool is_last) { + packet->header.flags = 0; + packet->header.data_size = 0; + packet->header.host_size = 0; + + bzero(packet->data, MPTP_DATA_MAX); + bzero(packet->host, MPTP_HOST_MAX); + + if (code > MPTP_CODE_MAX) { + lm_error_set(LM_ERR_MPTPBadCode); + return false; + } + + packet->header.flags |= (MPTP_VERSION_SUPPORTED << 8); + + if (is_request) + packet->header.flags |= (MPTP_REQUEST << 7); + else + packet->header.flags |= (MPTP_RESPONSE << 7); + + packet->header.flags |= (code << 4); + + if (is_last || is_request) + packet->header.flags |= (1 << 3); + else + packet->header.flags |= (0 << 3); + + return true; +} + +bool lm_mptp_verify(lm_mptp_t *packet) { + if (NULL == packet) { + lm_error_set(LM_ERR_ArgNULL); + return false; + } + + if (MPTP_FLAGS_VERSION(packet) != MPTP_VERSION_SUPPORTED) { + lm_error_set(LM_ERR_MPTPBadVersion); + return false; + } + + if (packet->header.data_size > MPTP_DATA_MAX || packet->header.data_size < 0) { + lm_error_set(LM_ERR_MPTPBadData); + return false; + } + + if (MPTP_FLAGS_CODE(packet) > MPTP_CODE_MAX || MPTP_FLAGS_CODE(packet) < 0) { + lm_error_set(LM_ERR_MPTPBadCode); + return false; + } + + return true; +} + +int lm_mptp_socket(char *addr, uint16_t port, struct sockaddr *saddr) { + if (NULL == addr || NULL == saddr) { + lm_error_set(LM_ERR_ArgNULL); + return -1; + } + + struct addrinfo hints, *res, *cur; + int sock = 0, status = 0, family = -1; + + bzero(&hints, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + + if ((status = getaddrinfo(addr, NULL, &hints, &res)) < 0) { + lm_error_set(LM_ERR_MPTPHostFail); + return -1; + } + + for (cur = res; cur != NULL; cur = cur->ai_next) { + switch (cur->ai_family) { + case AF_INET: + family = cur->ai_family; + struct sockaddr_in *ipv4 = (struct sockaddr_in *)cur->ai_addr; + ipv4->sin_port = htons(port); + + memcpy(saddr, cur->ai_addr, sizeof(struct sockaddr)); + break; + + case AF_INET6: + family = cur->ai_family; + struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)cur->ai_addr; + ipv6->sin6_port = htons(port); + + memcpy(saddr, cur->ai_addr, sizeof(struct sockaddr)); + break; + } + + if (family != -1) + break; + } + + freeaddrinfo(res); + + if (family == -1) { + lm_error_set(LM_ERR_MPTPHostFail); + return -1; + } + + if ((sock = socket(family, SOCK_DGRAM, IPPROTO_UDP)) < 0) { + lm_error_set(LM_ERR_MPTPSocketFail); + return -1; + } + + return sock; +} + +void lm_mptp_close(int sock) { + close(sock); +} + +bool lm_mptp_set_host(lm_mptp_t *packet, char *host) { + size_t size = strlen(host); + if (size > MPTP_HOST_MAX || size < 0) { + lm_error_set(LM_ERR_MPTPBadHost); + return false; + } + + // do NOT copy the NULL terminator + packet->header.host_size = size; + memcpy(packet->host, host, size); + return true; +} + +bool lm_mptp_get_host(lm_mptp_t *packet, char *host) { + if (packet->header.host_size > MPTP_HOST_MAX || packet->header.host_size < 0) { + host = NULL; + lm_error_set(LM_ERR_BadHost); + return false; + } + + memcpy(host, packet->host, packet->header.host_size); + host[packet->header.host_size] = 0; + return true; +} + +bool lm_mptp_set_data(lm_mptp_t *packet, char *data, size_t size) { + if (size > MPTP_DATA_MAX || size < 0) { + lm_error_set(LM_ERR_MPTPBadData); + return false; + } + + packet->header.data_size = size; + mempcpy(packet->data, data, size); + return true; +} + +bool lm_mptp_get_data(lm_mptp_t *packet, char *data) { + if (packet->header.data_size > MPTP_DATA_MAX || packet->header.data_size < 0) { + data = NULL; + lm_error_set(LM_ERR_BadHost); + return false; + } + + memcpy(data, packet->data, packet->header.data_size); + data[packet->header.data_size] = 0; + return true; +} + +void lm_mptp_copy(lm_mptp_t *dst, lm_mptp_t *src) { + memcpy(&dst->header, &src->header, sizeof(dst->header)); + memcpy(&dst->host, &src->data, sizeof(src->host)); + memcpy(&dst->data, &src->data, sizeof(src->data)); +} diff --git a/src/mptp/server.c b/src/mptp/server.c new file mode 100644 index 0000000..6c3d384 --- /dev/null +++ b/src/mptp/server.c @@ -0,0 +1,118 @@ +#include "../../include/error.h" +#include "../../include/mptp.h" +#include "../../include/util.h" + +#include +#include +#include + +int lm_mptp_server_listen(char *addr, uint16_t port) { + struct sockaddr saddr; + int sock; + + bzero(&saddr, sizeof(saddr)); + + if ((sock = lm_mptp_socket(addr, port, &saddr)) < 0) + return -1; + + if (bind(sock, &saddr, sizeof(struct sockaddr)) < 0) { + lm_mptp_close(sock); + lm_error_set(LM_ERR_MPTPBindFail); + return -1; + } + + return sock; +} + +bool lm_mptp_server_verify(lm_mptp_t *packet) { + if (!lm_mptp_verify(packet)) + return false; + + if (!MPTP_IS_REQUEST(packet)) { + lm_error_set(LM_ERR_MPTPNotRequest); + return false; + } + + if (packet->header.host_size > MPTP_HOST_MAX || packet->header.host_size <= 0) { + lm_error_set(LM_ERR_MPTPBadHost); + return false; + } + + if (!MPTP_IS_LAST(packet)) { + lm_error_set(LM_ERR_MPTPNotLast); + return false; + } + + return true; +} + +bool lm_mptp_server_recv(int sock, lm_mptp_t *packet, struct sockaddr *addr) { + if (NULL == packet || NULL == addr) { + lm_error_set(LM_ERR_ArgNULL); + return false; + } + + char buffer[sizeof(packet->header) + MPTP_HOST_MAX + MPTP_DATA_MAX]; + socklen_t socklen = sizeof(struct sockaddr); + ssize_t total = sizeof(buffer), used = 0; + + bzero(buffer, sizeof(buffer)); + bzero(packet, sizeof(lm_mptp_t)); + + if (recvfrom(sock, buffer, sizeof(buffer), 0, addr, &socklen) <= 0) { + lm_error_set(LM_ERR_MPTPRecvFail); + return false; + } + + copy_from_buffer(&packet->header, buffer, sizeof(packet->header), &total, &used); + packet->header.flags = ntohs(packet->header.flags); + // packet->header.host_size = ntohs(packet->header.host_size); + // packet->header.data_size = ntohs(packet->header.data_size); + + if (packet->header.host_size <= MPTP_HOST_MAX) + copy_from_buffer(&packet->host, buffer, packet->header.host_size, &total, &used); + + if (packet->header.data_size <= MPTP_DATA_MAX) + copy_from_buffer(&packet->data, buffer, packet->header.data_size, &total, &used); + + return true; +} + +bool lm_mptp_server_send(int sock, lm_mptp_t *packet, struct sockaddr *addr) { + if (NULL == packet) { + lm_error_set(LM_ERR_ArgNULL); + return false; + } + + if (MPTP_FLAGS_VERSION(packet) != MPTP_VERSION_SUPPORTED) { + lm_error_set(LM_ERR_MPTPBadVersion); + return false; + } + + if (packet->header.data_size > MPTP_DATA_MAX) { + lm_error_set(LM_ERR_MPTPBadData); + return false; + } + + if (packet->header.host_size != 0) { + lm_error_set(LM_ERR_MPTPBadHost); + return false; + } + + socklen_t addrlen = sizeof(struct sockaddr); + char buffer[sizeof(packet->header) + packet->header.host_size + packet->header.data_size]; + ssize_t total = sizeof(buffer), used = 0; + + packet->header.flags = htons(packet->header.flags); + + copy_to_buffer(buffer, &packet->header, sizeof(packet->header), &total, &used); + copy_to_buffer(buffer, packet->host, packet->header.host_size, &total, &used); + copy_to_buffer(buffer, packet->data, packet->header.data_size, &total, &used); + + if (sendto(sock, buffer, sizeof(buffer), 0, addr, addrlen) < 0) { + lm_error_set(LM_ERR_MPTPSendFail); + return false; + } + + return true; +} diff --git a/src/pkg/data.c b/src/pkg/data.c new file mode 100644 index 0000000..09109f1 --- /dev/null +++ b/src/pkg/data.c @@ -0,0 +1,7 @@ +#include "../../include/pkg.h" +#include + +bool lm_pkg_data_load(lm_pkg_t *pkg, char *file){ + // TODO: implement lol + return true; +} diff --git a/src/pkg/pkg.c b/src/pkg/pkg.c new file mode 100644 index 0000000..3baff82 --- /dev/null +++ b/src/pkg/pkg.c @@ -0,0 +1,20 @@ +#include "../../include/types.h" +#include "../../include/error.h" +#include "../../include/pkg.h" + +#include +#include + +lm_pkg_t *lm_pkg_new(){ + lm_pkg_t *pkg = malloc(sizeof(lm_pkg_t)); + bzero(pkg, sizeof(lm_pkg_t)); + return pkg; +} + +void lm_pkg_free(lm_pkg_t *pkg){ + free(pkg->desc); + free(pkg->name); + free(pkg->version); + for(int i = 0; pkg->depends[i] != NULL; i++) + free(pkg->depends[i]); +} diff --git a/src/pool.c b/src/pool.c deleted file mode 100644 index 40305a4..0000000 --- a/src/pool.c +++ /dev/null @@ -1,143 +0,0 @@ -#include "../include/pool.h" -#include "../include/error.h" -#include "../include/mptp.h" -#include "../include/util.h" - -#include -#include -#include -#include - -lm_pool_t *lm_pool_new(char *name, char *url) { - lm_pool_t *pool = malloc(sizeof(lm_pool_t)); - pool->available = true; - pool->name = name; - - bzero(&pool->info, sizeof(pool->info)); - bzero(&pool->url, sizeof(pool->url)); - - if (!lm_url_init(&pool->url, url)) { - free(pool); - return NULL; - } - - if (!eq(pool->url.protocol, "mptp")) { - lm_error_set(LM_ERR_PoolNoSupport); - lm_pool_free(pool); - return NULL; - } - - return pool; -} - -void lm_pool_test(lm_pool_t *pool) { - lm_mptp_t packet; - lm_mptp_init(&packet, true, MPTP_C2S_PING, true); - - lm_mptp_set_host(&packet, pool->url.host); - lm_mptp_set_data(&packet, pool->url.path, strlen(pool->url.path)); - - int sock = lm_mptp_client_connect(pool->url.host, pool->url.port); - if (sock == -1) { - pool->available = false; - return; - } - - if (!lm_mptp_client_send(sock, &packet)) { - pool->available = false; - goto end; - } - - if (!lm_mptp_client_recv(sock, &packet)) { - pool->available = false; - goto end; - } - - if (!lm_mptp_client_verify(&packet)) { - pool->available = false; - goto end; - } - - pool->available = MPTP_FLAGS_CODE(&packet) == MPTP_S2C_PONG; -end: - lm_mptp_close(sock); - return; -} - -int lm_pool_info_handler(void *data, const char *_section, const char *_key, const char *_value) { - char *section = (char *)_section, *value = (char *)_value, *key = (char *)_key; - lm_pool_t *pool = data; - - if (!eq(pool->name, section)) - return 0; - - if (eq(key, "size")) - pool->info.size = atol(value); - else if (eq(key, "maintainer")) - pool->info.maintainer = strdup(value); - else if (eq(key, "pubkey")) - pool->info.pubkey = strdup(value); - else - return 0; - - return 1; -} - -bool lm_pool_info_load(lm_pool_t *pool, char *file) { - lm_pool_info_free(pool); - - if (ini_parse(file, lm_pool_info_handler, pool) < 0) { - lm_error_set(LM_ERR_PoolInfoBad); - return false; - } - - pool->info.file = strdup(file); - return true; -} - -void lm_pool_info_free(lm_pool_t *pool) { - free(pool->info.file); - free(pool->info.pubkey); - free(pool->info.maintainer); - bzero(&pool->info, sizeof(pool->info)); -} - -void lm_pool_free(lm_pool_t *pool) { - lm_url_free(&pool->url); - lm_pool_info_free(pool); - free(pool); -} - -void lm_pool_serve(lm_pool_t *pool, lm_mptp_t *packet, int sock, struct sockaddr *addr) { - switch (MPTP_FLAGS_CODE(packet)) { - case MPTP_C2S_PING: - lm_mptp_init(packet, false, MPTP_S2C_PONG, true); - goto end; - - case MPTP_C2S_INFO: - if (NULL == pool->info.file) { - lm_mptp_init(packet, false, MPTP_S2C_BRUH, true); - goto end; - } - - FILE *info = fopen(pool->info.file, "r"); - size_t read = 0; - - while ((read = fread(packet->data, 1, MPTP_DATA_MAX, info)) > 0) { - lm_mptp_server_send(sock, packet, addr); - lm_mptp_init(packet, false, MPTP_S2C_COOL, false); - } - - fclose(info); - lm_mptp_init(packet, false, MPTP_S2C_COOL, true); - } - -end: - lm_mptp_server_send(sock, packet, addr); -} - -void lm_pool_serve_thread(void *_arg) { - lm_pool_thread_arg_t *arg = _arg; - lm_pool_serve(arg->pool, &arg->packet, arg->sock, &arg->addr); - free(arg); -} diff --git a/src/pool/info.c b/src/pool/info.c new file mode 100644 index 0000000..903160b --- /dev/null +++ b/src/pool/info.c @@ -0,0 +1,95 @@ +#include "../../include/error.h" +#include "../../include/pool.h" +#include "../../include/mptp.h" +#include "../../include/util.h" + +#include +#include +#include +#include +#include + +int lm_pool_info_handler(void *data, const char *_section, const char *_key, const char *_value) { + char *section = (char *)_section, *value = (char *)_value, *key = (char *)_key; + lm_pool_t *pool = data; + + if (!eq(pool->name, section)) + return 0; + + if (eq(key, "size")) + pool->info.size = atol(value); + else if (eq(key, "maintainer")) + pool->info.maintainer = strdup(value); + else if (eq(key, "pubkey")) + pool->info.pubkey = strdup(value); + else + return 0; + + return 1; +} + +bool lm_pool_info_load(lm_pool_t *pool, char *file) { + lm_pool_info_free(pool); + + if (ini_parse(file, lm_pool_info_handler, pool) < 0) { + lm_error_set(LM_ERR_PoolInfoBad); + return false; + } + + pool->info.file = strdup(file); + return true; +} + +bool lm_pool_info_get(lm_pool_t *pool, char *file) { + if(!pool->available) + return false; + + if(NULL == pool->url.host) + return false; + + if(NULL == pool->url.path) + return false; + + FILE *info = fopen(file, "a"); + int sock = lm_mptp_client_connect(pool->url.host, pool->url.port); + lm_mptp_t packet; + bool ret = false; + + if(NULL == info) + goto end; + + lm_mptp_init(&packet, true, MPTP_C2S_INFO, true); + lm_mptp_set_host(&packet, pool->url.host); + lm_mptp_set_data(&packet, pool->url.path, strlen(pool->url.path)); + + if(!lm_mptp_client_send(sock, &packet)) + goto end; + + if(!lm_mptp_client_recv(sock, &packet)) + goto end; + + while(lm_mptp_client_recv(sock, &packet)){ + if(!lm_mptp_client_verify(&packet)) + goto end; + + if(fwrite(packet.data, 1, packet.header.data_size, info)==0) + goto end; + + if(MPTP_IS_LAST(&packet)) + break; + } + + ret = true; +end: + fclose(info); + if(ret) + ret = lm_pool_info_load(pool, file); + return ret; +} + +void lm_pool_info_free(lm_pool_t *pool) { + free(pool->info.file); + free(pool->info.pubkey); + free(pool->info.maintainer); + bzero(&pool->info, sizeof(pool->info)); +} diff --git a/src/pool/list.c b/src/pool/list.c new file mode 100644 index 0000000..ac60fd8 --- /dev/null +++ b/src/pool/list.c @@ -0,0 +1,100 @@ +#include "../../include/error.h" +#include "../../include/pool.h" +#include "../../include/mptp.h" +#include "../../include/util.h" +#include "../../include/pkg.h" + +#include +#include +#include +#include + +bool lm_pool_list_load(lm_pool_t *pool, char *file){ + size_t file_len = strlen(file), ent_len = 0; + char filecp[file_len+1], *dir = NULL; + struct dirent *ent = NULL; + DIR *dirfd = NULL; + bool ret = false; + + memcpy(filecp, file, file_len+1); + dir = dirname(filecp); + + if(!extract_archive(dir, file)) + goto end; + + if((dirfd = opendir(dir)) == NULL){ + lm_error_set(LM_ERR_PoolListDirFail); + goto end; + } + + while((ent = readdir(dirfd)) != NULL){ + ent_len = strlen(ent->d_name); + + char datap[ent_len+file_len+10]; + snprintf(datap, sizeof(datap), "%s/%s/DATA", dir, ent->d_name); + + lm_pkg_t *pkg = lm_pkg_new(); + + if(!lm_pkg_data_load(pkg, datap)){ + lm_pkg_free(pkg); + continue; + } + + if(!lm_pool_add(pool, pkg)){ + lm_pkg_free(pkg); + continue; + } + } + +end: + if(NULL != dirfd) + closedir(dirfd); + return ret; +} + +bool lm_pool_list_get(lm_pool_t *pool, char *file) { + if(!pool->available) + return false; + + if(NULL == pool->url.host) + return false; + + if(NULL == pool->url.path) + return false; + + FILE *info = fopen(file, "a"); + int sock = lm_mptp_client_connect(pool->url.host, pool->url.port); + lm_mptp_t packet; + bool ret = false; + + if(NULL == info) + goto end; + + lm_mptp_init(&packet, true, MPTP_C2S_LIST, true); + lm_mptp_set_host(&packet, pool->url.host); + lm_mptp_set_data(&packet, pool->url.path, strlen(pool->url.path)); + + if(!lm_mptp_client_send(sock, &packet)) + goto end; + + if(!lm_mptp_client_recv(sock, &packet)) + goto end; + + while(lm_mptp_client_recv(sock, &packet)){ + if(!lm_mptp_client_verify(&packet)) + goto end; + + if(fwrite(packet.data, 1, packet.header.data_size, info)==0) + goto end; + + if(MPTP_IS_LAST(&packet)) + break; + } + + ret = true; +end: + fclose(info); + if(ret) + ret = lm_pool_list_load(pool, file); + return ret; +} diff --git a/src/pool/pool.c b/src/pool/pool.c new file mode 100644 index 0000000..1a41d2e --- /dev/null +++ b/src/pool/pool.c @@ -0,0 +1,93 @@ +#include "../../include/error.h" +#include "../../include/util.h" +#include "../../include/pool.h" + +#include +#include + +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)); + bzero(&pool->info, sizeof(pool->info)); + bzero(&pool->url, sizeof(pool->url)); + + pool->available = true; + pool->name = name; + + if (!lm_url_init(&pool->url, url)) { + free(pool); + return NULL; + } + + if (!eq(pool->url.protocol, "mptp")) { + lm_error_set(LM_ERR_PoolNoSupport); + lm_pool_free(pool); + return NULL; + } + + return pool; +} + +void lm_pool_test(lm_pool_t *pool) { + lm_mptp_t packet; + lm_mptp_init(&packet, true, MPTP_C2S_PING, true); + + lm_mptp_set_host(&packet, pool->url.host); + lm_mptp_set_data(&packet, pool->url.path, strlen(pool->url.path)); + + int sock = lm_mptp_client_connect(pool->url.host, pool->url.port); + if (sock == -1) { + pool->available = false; + return; + } + + if (!lm_mptp_client_send(sock, &packet)) { + pool->available = false; + goto end; + } + + if (!lm_mptp_client_recv(sock, &packet)) { + pool->available = false; + goto end; + } + + if (!lm_mptp_client_verify(&packet)) { + pool->available = false; + goto end; + } + + pool->available = MPTP_FLAGS_CODE(&packet) == MPTP_S2C_PONG; +end: + lm_mptp_close(sock); + return; +} + +bool lm_pool_add(lm_pool_t *pool, lm_pkg_t *pkg){ + if(NULL == pool || NULL == pkg){ + lm_error_set(LM_ERR_ArgNULL); + return false; + } + + 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; +} + +void lm_pool_free(lm_pool_t *pool) { + lm_url_free(&pool->url); + lm_pool_info_free(pool); + free(pool); +} diff --git a/src/pool/serve.c b/src/pool/serve.c new file mode 100644 index 0000000..b8361e1 --- /dev/null +++ b/src/pool/serve.c @@ -0,0 +1,39 @@ +#include "../../include/error.h" +#include "../../include/util.h" +#include "../../include/pool.h" + +#include + +void lm_pool_serve(lm_pool_t *pool, lm_mptp_t *packet, int sock, struct sockaddr *addr) { + switch (MPTP_FLAGS_CODE(packet)) { + case MPTP_C2S_PING: + lm_mptp_init(packet, false, MPTP_S2C_PONG, true); + goto end; + + case MPTP_C2S_INFO: + if (NULL == pool->info.file) { + lm_mptp_init(packet, false, MPTP_S2C_BRUH, true); + goto end; + } + + FILE *info = fopen(pool->info.file, "r"); + size_t read = 0; + + while ((read = fread(packet->data, 1, MPTP_DATA_MAX, info)) > 0) { + lm_mptp_server_send(sock, packet, addr); + lm_mptp_init(packet, false, MPTP_S2C_COOL, false); + } + + fclose(info); + lm_mptp_init(packet, false, MPTP_S2C_COOL, true); + } + +end: + lm_mptp_server_send(sock, packet, addr); +} + +void lm_pool_serve_thread(void *_arg) { + lm_pool_thread_arg_t *arg = _arg; + lm_pool_serve(arg->pool, &arg->packet, arg->sock, &arg->addr); + free(arg); +} diff --git a/src/util.c b/src/util.c index c0a85d4..8c7c677 100644 --- a/src/util.c +++ b/src/util.c @@ -1,11 +1,15 @@ #include "../include/util.h" #include "../include/error.h" #include "../include/types.h" + +#include #include +#include #include #include #include #include +#include void pdebug(lm_ctx_t *ctx, const char *func, const char *fmt, ...) { if (!ctx->debug) @@ -93,3 +97,95 @@ bool copy_from_buffer(void *dst, void *buffer, size_t size, ssize_t *total, ssiz *used += size; return true; } + +bool copy_blocks(struct archive *w, struct archive *r) { + int64_t offset = 0; + const void *buffer; + size_t size = 0; + int rc = 0; + + while ((rc = archive_read_data_block(r, &buffer, &size, &offset)) == ARCHIVE_OK) { + rc = archive_write_data_block(w, buffer, size, offset); + if (rc != ARCHIVE_OK) { + lm_error_set(LM_ERR_ArcWBlockFail); + return false; + } + } + + if (rc != ARCHIVE_EOF) { + lm_error_set(LM_ERR_ArcRBlockFail); + return false; + } + + return true; +} + +bool extract_archive(char *dst, char *src) { + struct archive *reader = NULL, *writer = NULL; + struct archive_entry *entry = NULL; + int flags = 0, rc = 0; + char *oldpwd = NULL; + bool ret = false; + + oldpwd = getcwd(NULL, 0); + if (NULL == oldpwd) { + lm_error_set(LM_ERR_GetCwdFail); + goto end; + } + + chdir(dst); + + flags = ARCHIVE_EXTRACT_PERM; + flags |= ARCHIVE_EXTRACT_UNLINK; + + reader = archive_read_new(); + writer = archive_write_new(); + + archive_write_disk_set_options(writer, flags); + archive_write_disk_set_standard_lookup(writer); + + archive_read_support_format_tar(reader); + archive_read_support_filter_gzip(reader); + + if (archive_read_open_filename(reader, src, 1024 * 10) != ARCHIVE_OK) { + lm_error_set(LM_ERR_ArcOpenFail); + goto end; + } + + while ((rc = archive_read_next_header(reader, &entry)) == ARCHIVE_OK) { + rc = archive_write_header(writer, entry); + if (rc != ARCHIVE_OK) { + lm_error_set(LM_ERR_ArcWHeaderFail); + goto end; + } + + if (!copy_blocks(writer, reader)) + goto end; + + rc = archive_write_finish_entry(writer); + if (rc != ARCHIVE_OK) { + lm_error_set(LM_ERR_ArcWEntryFail); + goto end; + } + } + + ret = true; + +end: + if (NULL != reader) { + archive_read_close(reader); + archive_read_free(reader); + } + + if (NULL != writer) { + archive_write_close(reader); + archive_write_free(reader); + } + + if (NULL != oldpwd) { + chdir(oldpwd); + free(oldpwd); + } + + return ret; +}