# #
#############################################################################*/
+#include <ctype.h>
#include <errno.h>
+#include <fcntl.h>
+#include <ftw.h>
#include <libgen.h>
#include <math.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
+#include <archive.h>
+#include <archive_entry.h>
+#include <json.h>
+#include <solv/pool.h>
+#include <uuid/uuid.h>
+
#include <pakfire/constants.h>
#include <pakfire/logging.h>
-#include <pakfire/private.h>
-#include <pakfire/types.h>
+#include <pakfire/package.h>
+#include <pakfire/util.h>
-void pakfire_oom(size_t num, size_t len) {
- if (num)
- fprintf(stderr, "Out of memory allocating %zu*%zu bytes!\n", num, len);
- else
- fprintf(stderr, "Out of memory allocating %zu bytes!\n", len);
+#define NSEC_PER_SEC 1000000000
- abort();
- exit(1);
-}
+static Id pakfire_parse_namespace(Pool* pool, const char* s) {
+ const char* p = strchr(s, '(');
+ if (!p)
+ return 0;
+
+ // Store the namespace ID
+ Id namespace = pool_strn2id(pool, s, p - s, 1);
-char* pakfire_strdup(const char* s) {
+ // Find the end of the string
+ s = strrchr(p, ')');
if (!s)
return 0;
- char* r = strdup(s);
- if (!r)
- pakfire_oom(0, strlen(s));
+ Id id = pool_strn2id(pool, p + 1, s - p - 1, 1);
- return r;
+ // Bring it all together
+ return pool_rel2id(pool, namespace, id, REL_NAMESPACE, 1);
}
-PAKFIRE_EXPORT int pakfire_string_startswith(const char* s, const char* prefix) {
- return !strncmp(s, prefix, strlen(prefix));
-}
+Id pakfire_parse_dep(struct pakfire* pakfire, const char* s) {
+ Id id;
-char* pakfire_format_size(double size) {
- char string[STRING_SIZE];
- const char* units[] = {" ", "k", "M", "G", "T", NULL};
- const char** unit = units;
-
- while (*(unit + 1) && size >= 1024.0) {
- size /= 1024.0;
- unit++;
+ if (!s) {
+ errno = EINVAL;
+ return 0;
}
- snprintf(string, STRING_SIZE, "%.0f%s", round(size), *unit);
+ // Ignore empty strings
+ if (!*s)
+ return 0;
+
+ Pool* pool = pakfire_get_solv_pool(pakfire);
+
+ // Consume any leading space
+ if (isspace(*s))
+ s++;
+
+ const char* p = s;
+
+ // Find the first part (before =, >= or <=)
+ while (*p && !isspace(*p) && *p != '<' && *p != '=' && *p != '>')
+ p++;
+
+ // The length of the first part
+ size_t l = p - s;
+
+ // Add name to pool
+ if (pakfire_string_startswith(s, "pakfire("))
+ id = pakfire_parse_namespace(pool, s);
+ else
+ id = pool_strn2id(pool, s, l, 1);
+
+ // Consume any more space
+ if (isspace(*p))
+ p++;
+
+ if (*p == '<' || *p == '=' || *p == '>') {
+ int flags = 0;
+
+ while (1) {
+ if (*p == '<')
+ flags |= REL_LT;
+ else if (*p == '=')
+ flags |= REL_EQ;
+ else if (*p == '>')
+ flags |= REL_GT;
+ else
+ break;
+
+ p++;
+ }
+
+ // Consume any more space
+ if (isspace(*p))
+ p++;
+
+ // Add EVR to pool
+ Id evr = pool_str2id(pool, p, 1);
+
+ // Combine everything
+ id = pool_rel2id(pool, id, evr, flags, 1);
+ }
- return pakfire_strdup(string);
+ return id;
}
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wformat-nonliteral"
-static char* pakfire_strftime(const char* format, time_t t) {
- char string[STRING_SIZE];
- struct tm* tm = gmtime(&t);
+void pakfire_parse_deps(struct pakfire* pakfire, struct pakfire_package* pkg,
+ void (*func)(struct pakfire_package* pkg, const char* dep), const char* deps) {
+ char* p = strdupa(deps);
+
+ while (*p) {
+ char* e = strchr(p, '\n');
+
+ // Terminate the string
+ if (e)
+ *e = '\0';
+
+ // Add the dependency
+ func(pkg, p);
- strftime(string, sizeof(string), format, tm);
+ // End loop when we reached the end
+ if (!e)
+ break;
- return pakfire_strdup(string);
+ // Or continue at the next line
+ p = e + 1;
+ }
}
-#pragma GCC diagnostic pop
-char* pakfire_format_date(time_t t) {
- return pakfire_strftime("%Y-%m-%d", t);
+int pakfire_string_startswith(const char* s, const char* prefix) {
+ // Validate input
+ if (!s || !prefix) {
+ errno = EINVAL;
+ return 1;
+ }
+
+ return !strncmp(s, prefix, strlen(prefix));
}
-PAKFIRE_EXPORT char* pakfire_path_join(const char* first, const char* second) {
- char* buffer;
+int pakfire_string_endswith(const char* s, const char* suffix) {
+ // Validate input
+ if (!s || !suffix) {
+ errno = EINVAL;
+ return 1;
+ }
- if (!first)
- return pakfire_strdup(second);
+ return !strcmp(s + strlen(s) - strlen(suffix), suffix);
+}
- if (!second)
- return pakfire_strdup(first);
+int pakfire_string_matches(const char* s, const char* pattern) {
+ return !!strstr(s, pattern);
+}
- if (*second == '/')
- return pakfire_strdup(second);
+char* pakfire_unquote_in_place(char* s) {
+ if (!s || !*s)
+ return s;
- asprintf(&buffer, "%s/%s", first, second);
+ // Is the first character a quote?
+ if (*s != '"')
+ return s;
- return buffer;
-}
+ // Find the end of value
+ size_t l = strlen(s);
+ if (!l)
+ return s;
-PAKFIRE_EXPORT const char* pakfire_path_relpath(const char* root, const char* path) {
- if (pakfire_string_startswith(path, root))
- return path + strlen(root);
+ // Is the last character a quote?
+ if (s[l - 1] != '"')
+ return s;
- return NULL;
+ // The string seems to be in quotes; remove them
+ s[l - 1] = '\0';
+ s++;
+
+ return s;
}
-PAKFIRE_EXPORT int pakfire_path_isdir(const char* path) {
- struct stat s;
+int pakfire_string_partition(const char* s, const char* delim, char** s1, char** s2) {
+ char* p = strstr(s, delim);
- if (stat(path, &s) != 0) {
- // Does not seem to exist
- return 0;
+ // Delim was not found
+ if (!p) {
+ *s1 = NULL;
+ *s2 = NULL;
+ return 1;
}
- if (S_ISDIR(s.st_mode))
- return 1;
+ // Length of string before delim
+ size_t l = p - s;
+
+ char* buffer = malloc(l + 1);
+ if (!buffer)
+ return -ENOMEM;
+
+ // Copy first part
+ *s1 = memcpy(buffer, s, l);
+ buffer[l] = '\0';
+
+ // Copy second part
+ *s2 = strdup(p + strlen(delim));
return 0;
}
-PAKFIRE_EXPORT char* pakfire_basename(const char* path) {
- char* name = pakfire_strdup(path);
+char* pakfire_string_replace(const char* s, const char* pattern, const char* repl) {
+ // Return NULL on no input or no pattern
+ if (!s || !pattern) {
+ errno = EINVAL;
+ return NULL;
+ }
- char* r = basename(name);
- if (r)
- r = pakfire_strdup(r);
+ // Replace with nothing when repl is NULL
+ if (!repl)
+ repl = "";
- free(name);
+ char* result = NULL;
+ const char** cache = NULL;
+ unsigned int count = 0;
- return r;
-}
+ const size_t pattern_length = strlen(pattern);
-PAKFIRE_EXPORT char* pakfire_dirname(const char* path) {
- char* parent = pakfire_strdup(path);
+ // Working pointer
+ const char* p = s;
- char* r = dirname(parent);
- if (r)
- r = pakfire_strdup(r);
+ // Find all occurrences of pattern and store their location
+ while (1) {
+ const char* needle = strstr(p, pattern);
+ if (!needle)
+ break;
- free(parent);
+ // Make space in the cache
+ cache = reallocarray(cache, sizeof(*cache), count + 1);
+ cache[count++] = needle;
- return r;
+ // Move p forward
+ p = needle + pattern_length;
+ }
+
+ // Copy the string if no occurence was found
+ if (count == 0) {
+ result = strdup(s);
+ goto ERROR;
+ }
+
+ // Store the end pointer
+ cache = reallocarray(cache, sizeof(*cache), count + 1);
+ cache[count] = s + strlen(s);
+
+ const size_t repl_length = strlen(repl);
+
+ // Determine the length of the final string
+ const size_t length = strlen(s) + ((repl_length - pattern_length) * count);
+
+ // Allocate enough memory for the result
+ result = malloc(length + 1);
+ if (!result)
+ goto ERROR;
+
+ // Reset p
+ p = s;
+
+ // Working pointer for the result
+ char* r = result;
+
+ // Copy everything up to the first match
+ ssize_t l = cache[0] - s;
+ memcpy(r, p, l);
+ r += l;
+ p += l;
+
+ for (unsigned int i = 0; i < count; i++) {
+ // Put replacement here
+ memcpy(r, repl, repl_length);
+ r += repl_length;
+ p += pattern_length;
+
+ // Determine the length between two matches
+ l = cache[i+1] - (cache[i] + pattern_length);
+
+ memcpy(r, p, l);
+ r += l;
+ p += l;
+ }
+
+ // Terminate the string
+ result[length] = '\0';
+
+ERROR:
+ if (cache)
+ free(cache);
+
+ return result;
}
-PAKFIRE_EXPORT int pakfire_access(Pakfire pakfire, const char* dir, const char* file, int mode) {
- char* path = pakfire_path_join(dir, file);
+static unsigned int pakfire_chrcnt(const char* s, char delim) {
+ size_t length = strlen(s);
- int r = access(path, mode);
+ unsigned int count = 0;
- if (r) {
- if (mode & R_OK)
- DEBUG(pakfire, "%s is not readable\n", path);
+ for (unsigned int i = 0; i < length; i++)
+ if (s[i] == delim)
+ count++;
- if (mode & W_OK)
- DEBUG(pakfire, "%s is not writable\n", path);
+ return count;
+}
- if (mode & X_OK)
- DEBUG(pakfire, "%s is not executable\n", path);
+char** pakfire_split_string(const char* s, char delim) {
+ char** array = NULL;
- if (mode & F_OK)
- DEBUG(pakfire, "%s does not exist\n", path);
+ if (!s) {
+ errno = EINVAL;
+ return NULL;
}
- free(path);
+ // Count how often we need to split
+ unsigned int count = pakfire_chrcnt(s, delim) + 1;
- return r;
+ // Allocate array
+ array = calloc(count + 1, sizeof(*array));
+ if (!array)
+ return NULL;
+
+ // Copy string to stack
+ char* p = strdupa(s);
+ if (!p)
+ return NULL;
+
+ unsigned int i = 0;
+ while (*p) {
+ char* e = strchr(p, delim);
+
+ // Terminate the string
+ if (e)
+ *e = '\0';
+
+ // Add string to the array
+ array[i++] = strdup(p);
+
+ // End loop when we reached the end
+ if (!e)
+ break;
+
+ // Or continue at the next line
+ p = e + 1;
+ }
+
+ return array;
}
-int pakfire_mkdir(Pakfire pakfire, const char* path, mode_t mode) {
- int r = 0;
+char* pakfire_string_join(char** list, const char* delim) {
+ if (!list)
+ return NULL;
- if ((strcmp(path, "/") == 0) || (strcmp(path, ".") == 0))
- return 0;
+ size_t length = 0;
+ unsigned int elements = 0;
- // If parent does not exists, we try to create it.
- char* parent = pakfire_dirname(path);
- r = pakfire_access(pakfire, parent, NULL, F_OK);
- if (r)
- r = pakfire_mkdir(pakfire, parent, 0);
+ // Count the number of elements and the total length
+ for (char** item = list; *item; item++) {
+ length += strlen(*item);
+ elements++;
+ }
- free(parent);
+ // Empty list?
+ if (!elements)
+ return NULL;
- // Exit if parent directory could not be created
- if (r)
- return r;
+ // Add the delimiters
+ length += strlen(delim) * (elements - 1);
- DEBUG(pakfire, "Creating directory %s\n", path);
+ // Allocate the result string
+ char* string = malloc(length + 1);
+ if (!string)
+ return NULL;
- // Finally, create the directory we want.
- r = mkdir(path, mode);
- if (r) {
- switch (errno) {
- // If the directory already exists, this is fine.
- case EEXIST:
- r = 0;
- break;
+ // Pointer to where we are writing
+ char* p = string;
+
+ size_t bytes_left = length;
+ size_t bytes_written;
+
+ for (char** item = list; *item; item++) {
+ bytes_written = snprintf(p, bytes_left, "%s", *item);
+
+ bytes_left -= bytes_written;
+ p += bytes_written;
+
+ // Write the delimiter
+ if (bytes_left) {
+ bytes_written = snprintf(p, bytes_left, "%s", delim);
+
+ bytes_left -= bytes_written;
+ p += bytes_written;
}
}
- return r;
+ return string;
}
-char* pakfire_sgets(char* str, int num, char** input) {
- char* next = *input;
- int numread = 0;
+int pakfire_format_size(char* dst, size_t length, double value) {
+ const char* units[] = {
+ "%.0f ",
+ "%.0fk",
+ "%.1fM",
+ "%.1fG",
+ "%.1fT",
+ NULL
+ };
+ const char** unit = units;
- while (numread + 1 < num && *next) {
- int isnewline = (*next == '\n');
+ while (*(unit + 1) && value >= 1024.0) {
+ value /= 1024.0;
+ unit++;
+ }
- *str++ = *next++;
- numread++;
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+ return snprintf(dst, length, *unit, value);
+#pragma GCC diagnostic pop
+}
- if (isnewline)
- break;
+int pakfire_format_speed(char* dst, size_t length, double value) {
+ const char* units[] = {
+ "%4.0fB/s",
+ "%4.0fkB/s",
+ "%4.1fMB/s",
+ "%4.1fGB/s",
+ "%4.1fTB/s",
+ NULL
+ };
+ const char** unit = units;
+
+ while (*(unit + 1) && value >= 1024.0) {
+ value /= 1024.0;
+ unit++;
}
- // Terminate string
- *str = '\0';
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+ return snprintf(dst, length, *unit, value);
+#pragma GCC diagnostic pop
+}
- *input = next;
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+static char* pakfire_strftime(const char* format, time_t t) {
+ char string[128];
+ struct tm* tm = gmtime(&t);
- return str;
+ strftime(string, sizeof(string) - 1, format, tm);
+
+ return strdup(string);
}
+#pragma GCC diagnostic pop
-char* pakfire_remove_trailing_newline(char* str) {
- ssize_t pos = strlen(str) - 1;
+char* pakfire_format_date(time_t t) {
+ return pakfire_strftime("%Y-%m-%d", t);
+}
- if (str[pos] == '\n')
- str[pos] = '\0';
+int __pakfire_strftime_now(char* dest, size_t length, const char* format) {
+ struct tm tm;
- return str;
+ // Fetch the current time
+ const time_t t = time(NULL);
+ if (t < 0)
+ return 1;
+
+ // Convert to struct tm
+ struct tm* now = gmtime_r(&t, &tm);
+ if (!now)
+ return 1;
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+ strftime(dest, length, format, now);
+#pragma GCC diagnostic pop
+
+ return 0;
}
-PAKFIRE_EXPORT const char* pakfire_action_type_string(pakfire_action_type_t type) {
- switch (type) {
- case PAKFIRE_ACTION_NOOP:
- return "NOOP";
+int __pakfire_path_join(char* dest, size_t length,
+ const char* first, const char* second) {
+ if (!first)
+ return snprintf(dest, length, "%s", second);
- case PAKFIRE_ACTION_VERIFY:
- return "VERIFY";
+ if (!second)
+ return snprintf(dest, length, "%s", first);
- case PAKFIRE_ACTION_EXECUTE:
- return "EXECUTE";
+ // Remove leading slashes from second argument
+ while (*second == '/')
+ second++;
- case PAKFIRE_ACTION_PRETRANS:
- return "PRETRANS";
+ return snprintf(dest, length, "%s/%s", first, second);
+}
- case PAKFIRE_ACTION_POSTTRANS:
- return "POSTTRANS";
- }
+const char* pakfire_path_relpath(const char* root, const char* path) {
+ if (pakfire_string_startswith(path, root))
+ return path + strlen(root);
return NULL;
}
-PAKFIRE_EXPORT int pakfire_read_file_into_buffer(FILE* f, char** buffer, size_t* len) {
+int pakfire_path_exists(const char* path) {
+ return !access(path, F_OK);
+}
+
+time_t pakfire_path_age(const char* path) {
+ struct stat st;
+
+ int r = stat(path, &st);
+ if (r == 0) {
+ // Get current timestamp
+ time_t now = time(NULL);
+
+ // Return the difference since the file has been created and now
+ return now - st.st_ctime;
+ }
+
+ return -1;
+}
+
+char* pakfire_basename(const char* path) {
+ char* name = strdup(path);
+
+ char* r = basename(name);
+ if (r)
+ r = strdup(r);
+
+ free(name);
+
+ return r;
+}
+
+char* pakfire_dirname(const char* path) {
+ char* parent = strdup(path);
+
+ char* r = dirname(parent);
+ if (r)
+ r = strdup(r);
+
+ free(parent);
+
+ return r;
+}
+
+char* pakfire_remove_trailing_newline(char* str) {
+ ssize_t pos = strlen(str) - 1;
+
+ if (str[pos] == '\n')
+ str[pos] = '\0';
+
+ return str;
+}
+
+int pakfire_read_file_into_buffer(FILE* f, char** buffer, size_t* len) {
if (!f)
return -EBADF;
return 0;
}
-PAKFIRE_EXPORT size_t pakfire_string_to_size(const char* s) {
- size_t size;
+char* pakfire_generate_uuid() {
+ uuid_t uuid;
+
+ // Generate a new random value
+ uuid_generate_random(uuid);
- int r = sscanf(s, "%zu", &size);
- if (r == 1)
- return size;
+ char* ret = malloc(UUID_STR_LEN + 1);
+ if (!ret)
+ return NULL;
+
+ // Convert it to string
+ uuid_unparse_lower(uuid, ret);
+
+ // Terminate string
+ ret[UUID_STR_LEN] = '\0';
+
+ return ret;
+}
+
+int pakfire_tty_is_noninteractive(void) {
+ const int fds[] = {
+ STDIN_FILENO,
+ STDOUT_FILENO,
+ STDERR_FILENO,
+ -1,
+ };
+
+ for (const int* fd = fds; *fd >= 0; fd++) {
+ if (!isatty(*fd))
+ return 1;
+ }
return 0;
}
-PAKFIRE_EXPORT char** pakfire_split_string(const char* s, char delim) {
- // Copy string to stack and count spaces
- char buffer[strlen(s) + 2];
+char* __pakfire_hexlify(const unsigned char* digest, const size_t length) {
+ const char* hexdigits = "0123456789abcdef";
- size_t count = 1;
- for (unsigned int i = 0; i < strlen(s) + 1; i++) {
- buffer[i] = s[i];
+ char* s = malloc((length * 2) + 1);
+ if (!s)
+ return NULL;
- if (s[i] == delim) {
- buffer[i] = '\0';
- count++;
+ for (unsigned int i = 0, j = 0; i < length; i++) {
+ char b = digest[i];
+
+ s[j++] = hexdigits[(b >> 4) & 0xf];
+ s[j++] = hexdigits[(b & 0x0f)];
+ }
+
+ // Terminate result
+ s[length * 2] = '\0';
+
+ return s;
+}
+
+static int parse_nibble(char nibble) {
+ // Handle digits
+ if (nibble >= '0' && nibble <= '9')
+ return nibble - '0';
+
+ // Handle lowercase letters
+ if (nibble >= 'a' && nibble <= 'f')
+ return 10 + nibble - 'a';
+
+ // Handle uppercase letters
+ if (nibble >= 'A' && nibble <= 'F')
+ return 10 + nibble - 'A';
+
+ // Error
+ return -1;
+}
+
+int __pakfire_unhexlify(unsigned char* dst, const size_t l, const char* src) {
+ if (!src) {
+ errno = EINVAL;
+ return 1;
+ }
+
+ // Determine input length
+ const size_t length = strlen(src);
+
+ for (unsigned int i = 0, j = 0; i < length && j < l; i += 2, j++) {
+ int h = parse_nibble(src[i]);
+ int l = parse_nibble(src[i+1]);
+
+ // Check for invalid input
+ if (h < 0 || l < 0) {
+ errno = EINVAL;
+ return 1;
}
+
+ // Store result
+ dst[j] = h << 4 | l;
}
- // Allocate an array of sufficient size
- char** ret = malloc(sizeof(*ret) * (count + 1));
+ return 0;
+}
- // Copy strings to heap one by one
- unsigned int i = 0;
- char* p = buffer;
- while (*p) {
- ret[i++] = pakfire_strdup(p);
+int pakfire_mkparentdir(const char* path, mode_t mode) {
+ int r;
+
+ char* dirname = pakfire_dirname(path);
+ if (!dirname)
+ return 1;
+
+ // We have arrived at the top of the tree
+ if (*dirname == '.' || strcmp(dirname, "/") == 0)
+ return 0;
+
+ // Ensure the parent directory exists
+ r = pakfire_mkparentdir(dirname, mode);
+ if (r)
+ goto END;
+
+ // Create this directory
+ r = mkdir(dirname, mode);
+
+ // Ignore when the directory already exists
+ if (r && errno == EEXIST)
+ r = 0;
+
+END:
+ free(dirname);
+
+ return r;
+}
+
+int pakfire_mkdir(const char* path, mode_t mode) {
+ int r = pakfire_mkparentdir(path, mode);
+ if (r)
+ return r;
+
+ // Finally, create the directory we want
+ return mkdir(path, mode);
+}
+
+FILE* pakfire_mktemp(char* path) {
+ int r = pakfire_mkparentdir(path, 0);
+ if (r)
+ return NULL;
+
+ // Create a temporary result file
+ int fd = mkostemp(path, O_CLOEXEC);
+ if (fd < 0)
+ return NULL;
- // Move pointer to the next string
- p += strlen(p) + 1;
+ // Re-open as file handle
+ return fdopen(fd, "w+");
+}
+
+char* pakfire_mkdtemp(char* path) {
+ int r = pakfire_mkparentdir(path, 0);
+ if (r)
+ return NULL;
+
+ return mkdtemp(path);
+}
+
+static int _unlink(const char* path, const struct stat* stat, int typeflag, struct FTW* ftwbuf) {
+ return remove(path);
+}
+
+int pakfire_rmtree(const char* path, int flags) {
+ int r = nftw(path, _unlink, 64, flags|FTW_DEPTH|FTW_PHYS);
+
+ // Ignore if path didn't exist
+ if (r < 0 && errno == ENOENT)
+ r = 0;
+
+ return r;
+}
+
+// Digests
+
+size_t pakfire_digest_length(enum pakfire_digests digest) {
+ switch (digest) {
+ case PAKFIRE_DIGEST_SHA512:
+ return 64;
+
+ case PAKFIRE_DIGEST_SHA256:
+ return 32;
+
+ case PAKFIRE_DIGEST_SHA1:
+ return 20;
+
+ case PAKFIRE_DIGEST_NONE:
+ return 0;
}
- // Terminate array
- ret[count] = NULL;
+ return 0;
+}
- return ret;
+// Archive Stuff
+
+int pakfire_archive_copy_data(struct archive* src, struct archive* dst,
+ struct archive_entry* entry) {
+ const void* buffer;
+ size_t size;
+ off_t offset;
+ int r;
+
+ for (;;) {
+ // Read a block of data
+ r = archive_read_data_block(src, &buffer, &size, &offset);
+ if (r == ARCHIVE_EOF)
+ return ARCHIVE_OK;
+ else if (r)
+ return r;
+
+ // Write the read block of data
+ r = archive_write_data(dst, buffer, size);
+ if (r < 0)
+ return r;
+ }
}
-PAKFIRE_EXPORT void pakfire_partition_string(const char* s, const char* delim, char** s1, char** s2) {
- char* p = strstr(s, delim);
+int pakfire_archive_copy_data_to_buffer(struct pakfire* pakfire, struct archive* a,
+ struct archive_entry* entry, char** data, size_t* data_size) {
+ *data = NULL;
+ *data_size = 0;
- // Delim was not found
- if (!p) {
- *s1 = NULL;
- *s2 = NULL;
- return;
+ size_t required_size = archive_entry_size(entry);
+ if (!required_size)
+ return 0;
+
+ // Allocate a block of the required size
+ *data = calloc(1, required_size + 1);
+ if (!*data)
+ return ENOMEM;
+
+ ssize_t bytes_read = archive_read_data(a, *data, required_size);
+ if (bytes_read < 0) {
+ ERROR(pakfire, "Could not read from archive: %s\n", archive_error_string(a));
+ free(*data);
+ return 1;
}
- // Length of string before delim
- size_t l = p - s;
+ *data_size = bytes_read;
+
+ return 0;
+}
+
+// JSON Stuff
+
+static struct json_object* pakfire_json_parse(struct pakfire* pakfire, FILE* f) {
+ struct json_tokener* tokener = NULL;
+ struct json_object* json = NULL;
+ char* buffer = NULL;
+ size_t length;
+
+ // Read everything into memory
+ int r = pakfire_read_file_into_buffer(f, &buffer, &length);
+ if (r)
+ goto ERROR;
+
+ // Create tokener
+ tokener = json_tokener_new();
+ if (!tokener) {
+ ERROR(pakfire, "Could not allocate JSON tokener: %m\n");
+ goto ERROR;
+ }
+
+ // Parse JSON from path
+ json = json_tokener_parse_ex(tokener, buffer, length);
+ if (!json) {
+ enum json_tokener_error error = json_tokener_get_error(tokener);
- *s1 = malloc(l);
- snprintf(*s1, l, "%s", s);
+ ERROR(pakfire, "JSON parsing error: %s\n", json_tokener_error_desc(error));
+ goto ERROR;
+ }
+
+ // Log what we have parsed
+ DEBUG(pakfire, "Parsed JSON:\n%s\n",
+ json_object_to_json_string_ext(json,
+ JSON_C_TO_STRING_SPACED | JSON_C_TO_STRING_PRETTY)
+ );
+
+ERROR:
+ if (buffer)
+ free(buffer);
+
+ if (tokener)
+ json_tokener_free(tokener);
+
+ return json;
+}
+
+struct json_object* pakfire_json_parse_from_file(struct pakfire* pakfire, const char* path) {
+ FILE* f = fopen(path, "r");
+ if (!f)
+ return NULL;
+
+ struct json_object* json = pakfire_json_parse(pakfire, f);
+ fclose(f);
+
+ return json;
+}
+
+// Time Stuff
+
+static void timespec_normalize(struct timespec* t) {
+ while (t->tv_nsec >= NSEC_PER_SEC) {
+ t->tv_sec++;
+ t->tv_nsec -= NSEC_PER_SEC;
+ }
+
+ while (t->tv_nsec <= -NSEC_PER_SEC) {
+ t->tv_sec--;
+ t->tv_nsec += NSEC_PER_SEC;
+ }
+}
+
+struct timespec timespec_add(const struct timespec* t1, const struct timespec* t2) {
+ struct timespec r = {
+ .tv_sec = t1->tv_sec + t2->tv_sec,
+ .tv_nsec = t2->tv_nsec + t2->tv_nsec,
+ };
+
+ // Correct any negative values
+ timespec_normalize(&r);
+
+ return r;
+}
+
+struct timespec timespec_from_ms(int milliseconds) {
+ struct timespec t = {
+ .tv_sec = (milliseconds / 1000),
+ .tv_nsec = (milliseconds % 1000) * 1000000,
+ };
+
+ return t;
+}
+
+int timespec_lt(struct timespec* t1, struct timespec* t2) {
+ return (
+ t1->tv_sec < t2->tv_sec ||
+ (t1->tv_sec == t2->tv_sec && t1->tv_nsec < t2->tv_nsec)
+ );
+}
+
+// Resource Limits
+
+int pakfire_rlimit_set(struct pakfire* pakfire, int limit) {
+ struct rlimit rl;
+
+ // Sanity check
+ if (limit < 3) {
+ errno = EINVAL;
+ return 1;
+ }
+
+ // Fetch current configuration
+ if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
+ ERROR(pakfire, "Could not read RLIMIT_NOFILE: %m\n");
+ return 1;
+ }
+
+ // Do not attempt to set higher than maximum
+ if ((long unsigned int)limit > rl.rlim_max)
+ limit = rl.rlim_max;
+
+ rl.rlim_cur = limit;
+
+ // Set the new limit
+ if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
+ ERROR(pakfire, "Could not set RLIMIT_NOFILE to %lu: %m\n", rl.rlim_cur);
+ return 1;
+ }
+
+ DEBUG(pakfire, "RLIMIT_NOFILE set to %d\n", limit);
+
+ return 0;
+}
- *s2 = pakfire_strdup(p + strlen(delim));
+/*
+ Resets RLIMIT_NOFILE to FD_SETSIZE (e.g. 1024)
+ for compatibility with software that uses select()
+*/
+int pakfire_rlimit_reset_nofile(struct pakfire* pakfire) {
+ return pakfire_rlimit_set(pakfire, FD_SETSIZE);
}