X-Git-Url: https://git.librecmc.org/?p=oweals%2Fopkg-lede.git;a=blobdiff_plain;f=libopkg%2Ffile_util.c;h=759c21b3ae76d206f717022c38dc8538fecf0d52;hp=902b8c935477d35e7da8a26434f2d087cfa4eae4;hb=d1fe095d2c1463ca1e945028b15f57a256070a06;hpb=480538737a8a9be074a1848f2e52cf2d1ff4709f diff --git a/libopkg/file_util.c b/libopkg/file_util.c index 902b8c9..759c21b 100644 --- a/libopkg/file_util.c +++ b/libopkg/file_util.c @@ -1,7 +1,8 @@ /* file_util.c - convenience routines for common stat operations - Carl D. Worth + Copyright (C) 2009 Ubiq Technologies + Carl D. Worth Copyright (C) 2001 University of Southern California This program is free software; you can redistribute it and/or @@ -15,44 +16,38 @@ General Public License for more details. */ -#include "includes.h" +#include #include #include +#include +#include +#include #include "sprintf_alloc.h" #include "file_util.h" -#include "md5.h" +#include #include "libbb/libbb.h" -#undef strlen -#if defined HAVE_SHA256 #include "sha256.h" -#endif int file_exists(const char *file_name) { - int err; - struct stat stat_buf; + struct stat st; + + if (stat(file_name, &st) == -1) + return 0; - err = stat(file_name, &stat_buf); - if (err == 0) { return 1; - } else { - return 0; - } } int file_is_dir(const char *file_name) { - int err; - struct stat stat_buf; + struct stat st; - err = stat(file_name, &stat_buf); - if (err) { - return 0; - } + if (stat(file_name, &st) == -1) + return 0; - return S_ISDIR(stat_buf.st_mode); + return S_ISDIR(st.st_mode); } /* read a single line from a file, stopping at a newline or EOF. @@ -62,165 +57,341 @@ int file_is_dir(const char *file_name) Return value is NULL if the file is at EOF when called. */ -#define FILE_READ_LINE_BUF_SIZE 1024 -char *file_read_line_alloc(FILE *file) +char *file_read_line_alloc(FILE * fp) { - char buf[FILE_READ_LINE_BUF_SIZE]; - int buf_len; - char *line = NULL; - int line_size = 0; - - memset(buf, 0, FILE_READ_LINE_BUF_SIZE); - while (fgets(buf, FILE_READ_LINE_BUF_SIZE, file)) { - buf_len = strlen(buf); - if (line) { - line_size += buf_len; - line = xrealloc(line, line_size); - strcat(line, buf); - } else { - line_size = buf_len + 1; - line = xstrdup(buf); - } - if (buf[buf_len - 1] == '\n') { - break; - } - } - - return line; + char buf[BUFSIZ]; + unsigned int buf_len; + char *line = NULL; + unsigned int line_size = 0; + int got_nl = 0; + + buf[0] = '\0'; + + while (fgets(buf, BUFSIZ, fp)) { + buf_len = strlen(buf); + if (buf[buf_len - 1] == '\n') { + buf_len--; + buf[buf_len] = '\0'; + got_nl = 1; + } + if (line) { + line_size += buf_len; + line = xrealloc(line, line_size + 1); + strncat(line, buf, line_size); + } else { + line_size = buf_len + 1; + line = xstrdup(buf); + } + if (got_nl) + break; + } + + return line; } int file_move(const char *src, const char *dest) { - int err; - - err = rename(src, dest); - - if (err && errno == EXDEV) { - err = file_copy(src, dest); - unlink(src); - } else if (err) { - fprintf(stderr, "%s: ERROR: failed to rename %s to %s: %s\n", - __FUNCTION__, src, dest, strerror(errno)); - } + int err; + + err = rename(src, dest); + if (err == -1) { + if (errno == EXDEV) { + /* src & dest live on different file systems */ + err = file_copy(src, dest); + if (err == 0) + unlink(src); + } else { + opkg_perror(ERROR, "Failed to rename %s to %s", + src, dest); + } + } - return err; + return err; } -/* I put these here to keep libbb dependencies from creeping all over - the opkg code */ int file_copy(const char *src, const char *dest) { - int err; + int err; - err = copy_file(src, dest, FILEUTILS_FORCE | FILEUTILS_PRESERVE_STATUS); - if (err) { - fprintf(stderr, "%s: ERROR: failed to copy %s to %s\n", - __FUNCTION__, src, dest); - } + err = copy_file(src, dest, FILEUTILS_FORCE | FILEUTILS_PRESERVE_STATUS); + if (err) + opkg_msg(ERROR, "Failed to copy file %s to %s.\n", src, dest); - return err; + return err; } int file_mkdir_hier(const char *path, long mode) { - return make_directory(path, mode, FILEUTILS_RECUR); + return make_directory(path, mode, FILEUTILS_RECUR); } -char *file_md5sum_alloc(const char *file_name) + +static int hex2bin(unsigned char x) { - static const int md5sum_bin_len = 16; - static const int md5sum_hex_len = 32; + if (x >= 'a' && x <= 'f') + return x - 'a' + 10; + else if (x >= 'A' && x <= 'F') + return x - 'A' + 10; + else if (x >= '0' && x <= '9') + return x - '0'; + else + return 0; +} - static const unsigned char bin2hex[16] = { +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 *md5sum_hex; - unsigned char md5sum_bin[md5sum_bin_len]; - - md5sum_hex = xcalloc(1, md5sum_hex_len + 1); - - file = fopen(file_name, "r"); - if (file == NULL) { - fprintf(stderr, "%s: Failed to open file %s: %s\n", - __FUNCTION__, file_name, strerror(errno)); - free(md5sum_hex); - return NULL; - } - - err = md5_stream(file, md5sum_bin); - if (err) { - fprintf(stderr, "%s: ERROR computing md5sum for %s: %s\n", - __FUNCTION__, file_name, strerror(err)); - fclose(file); - free(md5sum_hex); - return NULL; - } - - fclose(file); - - for (i=0; i < md5sum_bin_len; i++) { - md5sum_hex[i*2] = bin2hex[md5sum_bin[i] >> 4]; - md5sum_hex[i*2+1] = bin2hex[md5sum_bin[i] & 0xf]; - } - - md5sum_hex[md5sum_hex_len] = '\0'; - - return md5sum_hex; +}; + +char *file_md5sum_alloc(const char *file_name) +{ + static const int md5sum_bin_len = 16; + static const int md5sum_hex_len = 32; + + int i, len; + char *md5sum_hex; + unsigned char md5sum_bin[md5sum_bin_len]; + + len = md5sum(file_name, md5sum_bin); + + if (len) { + opkg_msg(ERROR, "Could't compute md5sum for %s.\n", file_name); + return NULL; + } + + md5sum_hex = xcalloc(1, md5sum_hex_len + 1); + + for (i = 0; i < md5sum_bin_len; i++) { + md5sum_hex[i * 2] = bin2hex[md5sum_bin[i] >> 4]; + md5sum_hex[i * 2 + 1] = bin2hex[md5sum_bin[i] & 0xf]; + } + + md5sum_hex[md5sum_hex_len] = '\0'; + + return md5sum_hex; } -#ifdef HAVE_SHA256 char *file_sha256sum_alloc(const char *file_name) { - static const int sha256sum_bin_len = 32; - static const int sha256sum_hex_len = 64; + static const int sha256sum_bin_len = 32; + static const int sha256sum_hex_len = 64; + + 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; + } - 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) { - fprintf(stderr, "%s: Failed to open file %s: %s\n", - __FUNCTION__, file_name, strerror(errno)); - free(sha256sum_hex); - return NULL; - } - - err = sha256_stream(file, sha256sum_bin); - if (err) { - fprintf(stderr, "%s: ERROR computing sha256sum for %s: %s\n", - __FUNCTION__, file_name, strerror(err)); 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; + + 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; + 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; + } + + for (p = buf, *len = 0; + slen > 0 && isxdigit(s[0]) && isxdigit(s[1]); + slen--, s += 2, (*len)++) + *p++ = hex2bin(s[0]) * 16 + hex2bin(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) +{ + size_t len = 0; + const unsigned char *in; + unsigned char *copy, *out; + + for (in = (unsigned char *)filename; *in != 0; in++) + len += urlencode_is_specialchar(*in) ? 3 : 1; + + copy = xcalloc(1, len + 1); + + for (in = (unsigned char *)filename, out = copy; *in != 0; in++) { + if (urlencode_is_specialchar(*in)) { + *out++ = '%'; + *out++ = bin2hex[*in / 16]; + *out++ = bin2hex[*in % 16]; + } + else { + *out++ = *in; + } + } + + return (char *)copy; +}