Add a function for recursive directory removal and use that instead of xsystem.
[oweals/opkg-lede.git] / libopkg / file_util.c
index fad4178901f8f9aa47961d2131acfeaa27501830..08c801a1501c261968ba842319aac3fdeeb8cdbe 100644 (file)
@@ -18,6 +18,7 @@
 #include "includes.h"
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <dirent.h>
 
 #include "sprintf_alloc.h"
 #include "file_util.h"
 #include "libbb/libbb.h"
 #undef strlen
 
+#if defined HAVE_SHA256
+#include "sha256.h"
+#endif
+
 int file_exists(const char *file_name)
 {
     int err;
@@ -71,15 +76,11 @@ char *file_read_line_alloc(FILE *file)
        buf_len = strlen(buf);
        if (line) {
            line_size += buf_len;
-           line = realloc(line, line_size);
-           if (line == NULL) {
-               fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-               break;
-           }
+           line = xrealloc(line, line_size);
            strcat(line, buf);
        } else {
            line_size = buf_len + 1;
-           line = strdup(buf);
+           line = xstrdup(buf);
        }
        if (buf[buf_len - 1] == '\n') {
            break;
@@ -143,24 +144,23 @@ char *file_md5sum_alloc(const char *file_name)
     char *md5sum_hex;
     unsigned char md5sum_bin[md5sum_bin_len];
 
-    md5sum_hex = calloc(1, md5sum_hex_len + 1);
-    if (md5sum_hex == NULL) {
-       fprintf(stderr, "%s: out of memory\n", __FUNCTION__);
-       return strdup("");
-    }
+    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));
-       return strdup("");
+       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));
-       return strdup("");
+       fclose(file);
+       free(md5sum_hex);
+       return NULL;
     }
 
     fclose(file);
@@ -175,3 +175,133 @@ char *file_md5sum_alloc(const char *file_name)
     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 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;
+}
+
+#endif
+
+
+int
+rm_r(const char *path)
+{
+       int ret = 0;
+       DIR *dir;
+       struct dirent *dent;
+
+       dir = opendir(path);
+       if (dir == NULL) {
+               perror_msg("%s: opendir(%s)", __FUNCTION__, path);
+               return -1;
+       }
+
+       if (fchdir(dirfd(dir)) == -1) {
+               perror_msg("%s: fchdir(%s)", __FUNCTION__, path);
+               closedir(dir);
+               return -1;
+       }
+
+       while (1) {
+               errno = 0;
+               if ((dent = readdir(dir)) == NULL) {
+                       if (errno) {
+                               perror_msg("%s: readdir(%s)",
+                                               __FUNCTION__, 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) {
+                               perror_msg("%s: lstat(%s)",
+                                               __FUNCTION__, 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) {
+                       perror_msg("%s: unlink(%s)",
+                                       __FUNCTION__, dent->d_name);
+                       break;
+               }
+       }
+
+       if (chdir("..") == -1) {
+               ret = -1;
+               perror_msg("%s: chdir(%s/..)", __FUNCTION__, path);
+       }
+
+       if (rmdir(path) == -1 ) {
+               ret = -1;
+               perror_msg("%s: rmdir(%s)", __FUNCTION__, path);
+       }
+
+       if (closedir(dir) == -1) {
+               ret = -1;
+               perror_msg("%s: closedir(%s)", __FUNCTION__, path);
+       }
+
+       return ret;
+}