+char *file_sha256sum_alloc(const char *file_name)
+{
+ static const int sha256sum_bin_len = 32;
+ static const int sha256sum_hex_len = 64;
+
+ static const unsigned char bin2hex[16] = {
+ '0', '1', '2', '3',
+ '4', '5', '6', '7',
+ '8', '9', 'a', 'b',
+ 'c', 'd', 'e', 'f'
+ };
+
+ int i, err;
+ FILE *file;
+ char *sha256sum_hex;
+ unsigned char sha256sum_bin[sha256sum_bin_len];
+
+ sha256sum_hex = xcalloc(1, sha256sum_hex_len + 1);
+
+ file = fopen(file_name, "r");
+ if (file == NULL) {
+ opkg_perror(ERROR, "Failed to open file %s", file_name);
+ free(sha256sum_hex);
+ return NULL;
+ }
+
+ err = sha256_stream(file, sha256sum_bin);
+ if (err) {
+ opkg_msg(ERROR, "Could't compute sha256sum for %s.\n",
+ file_name);
+ fclose(file);
+ free(sha256sum_hex);
+ return NULL;
+ }
+
+ fclose(file);
+
+ for (i = 0; i < sha256sum_bin_len; i++) {
+ sha256sum_hex[i * 2] = bin2hex[sha256sum_bin[i] >> 4];
+ sha256sum_hex[i * 2 + 1] = bin2hex[sha256sum_bin[i] & 0xf];
+ }
+
+ sha256sum_hex[sha256sum_hex_len] = '\0';
+
+ return sha256sum_hex;
+}
+
+char *checksum_bin2hex(const char *src, size_t len)
+{
+ unsigned char *p;
+ static unsigned char buf[65];
+ const unsigned char *s = (unsigned char *)src;
+ static const unsigned char bin2hex[16] = {
+ '0', '1', '2', '3',
+ '4', '5', '6', '7',
+ '8', '9', 'a', 'b',
+ 'c', 'd', 'e', 'f'
+ };
+
+ if (!s || len > 32)
+ return NULL;
+
+ for (p = buf; len > 0; s++, len--) {
+ *p++ = bin2hex[*s / 16];
+ *p++ = bin2hex[*s % 16];
+ }
+
+ *p = 0;
+
+ return (char *)buf;
+}
+
+char *checksum_hex2bin(const char *src, size_t *len)
+{
+ size_t slen;
+ unsigned char *p;
+ const unsigned char *s = (unsigned char *)src;
+ static unsigned char buf[32];
+
+ if (!src) {
+ *len = 0;
+ return NULL;
+ }
+
+ while (isspace(*src))
+ src++;
+
+ slen = strlen(src);
+
+ if (slen > 64) {
+ *len = 0;
+ return NULL;
+ }
+
+#define hex(c) \
+ (c >= 'a' ? (c - 'a') : (c >= 'A' ? (c - 'A') : (c - '0')))
+
+ for (p = buf, *len = 0;
+ slen > 0 && isxdigit(s[0]) && isxdigit(s[1]);
+ slen--, s += 2, (*len)++)
+ *p++ = hex(s[0]) * 16 + hex(s[1]);
+
+ return (char *)buf;
+}
+
+int rm_r(const char *path)
+{
+ int ret = 0;
+ DIR *dir;
+ struct dirent *dent;
+
+ if (path == NULL) {
+ opkg_perror(ERROR, "Missing directory parameter");
+ return -1;
+ }
+
+ dir = opendir(path);
+ if (dir == NULL) {
+ opkg_perror(ERROR, "Failed to open dir %s", path);
+ return -1;
+ }
+
+ if (fchdir(dirfd(dir)) == -1) {
+ opkg_perror(ERROR, "Failed to change to dir %s", path);
+ closedir(dir);
+ return -1;
+ }
+
+ while (1) {
+ errno = 0;
+ if ((dent = readdir(dir)) == NULL) {
+ if (errno) {
+ opkg_perror(ERROR, "Failed to read dir %s",
+ path);
+ ret = -1;
+ }
+ break;
+ }
+
+ if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
+ continue;
+
+#ifdef _BSD_SOURCE
+ if (dent->d_type == DT_DIR) {
+ if ((ret = rm_r(dent->d_name)) == -1)
+ break;
+ continue;
+ } else if (dent->d_type == DT_UNKNOWN)
+#endif
+ {
+ struct stat st;
+ if ((ret = lstat(dent->d_name, &st)) == -1) {
+ opkg_perror(ERROR, "Failed to lstat %s",
+ dent->d_name);
+ break;
+ }
+ if (S_ISDIR(st.st_mode)) {
+ if ((ret = rm_r(dent->d_name)) == -1)
+ break;
+ continue;
+ }
+ }
+
+ if ((ret = unlink(dent->d_name)) == -1) {
+ opkg_perror(ERROR, "Failed to unlink %s", dent->d_name);
+ break;
+ }
+ }
+
+ if (chdir("..") == -1) {
+ ret = -1;
+ opkg_perror(ERROR, "Failed to change to dir %s/..", path);
+ }
+
+ if (rmdir(path) == -1) {
+ ret = -1;
+ opkg_perror(ERROR, "Failed to remove dir %s", path);
+ }
+
+ if (closedir(dir) == -1) {
+ ret = -1;
+ opkg_perror(ERROR, "Failed to close dir %s", path);
+ }
+
+ return ret;
+}
+
+static int urlencode_is_specialchar(char c)
+{
+ switch (c) {
+ case ':':
+ case '?':
+ case '#':
+ case '[':
+ case ']':
+ case '@':
+ case '!':
+ case '$':
+ case '&':
+ case '\'':
+ case '(':
+ case ')':
+ case '*':
+ case '+':
+ case ',':
+ case ';':
+ case '=':
+ case '%':
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+char *urlencode_path(const char *filename)
+{
+ static const char bin2hex[16] = {
+ '0', '1', '2', '3',
+ '4', '5', '6', '7',
+ '8', '9', 'a', 'b',
+ 'c', 'd', 'e', 'f'
+ };
+
+ size_t len = 0;
+ const char *in;
+ char *copy, *out;
+
+ for (in = filename; *in != 0; in++)
+ len += urlencode_is_specialchar(*in) ? 3 : 1;
+
+ copy = xcalloc(1, len + 1);
+
+ for (in = filename, out = copy; *in != 0; in++) {
+ if (urlencode_is_specialchar(*in)) {
+ *out++ = '%';
+ *out++ = bin2hex[*in / 16];
+ *out++ = bin2hex[*in % 16];
+ }
+ else {
+ *out++ = *in;
+ }
+ }
+
+ return copy;
+}