Home | History | Annotate | Download | only in atree
      1 #include "fs.h"
      2 #include "files.h"
      3 #include <unistd.h>
      4 #include <stdlib.h>
      5 #include <sys/types.h>
      6 #include <sys/wait.h>
      7 #include <dirent.h>
      8 #include <string>
      9 #include <vector>
     10 #include <stdio.h>
     11 #include <string.h>
     12 #include <errno.h>
     13 #include <sys/stat.h>
     14 #include <unistd.h>
     15 #include <string.h>
     16 #include <host/CopyFile.h>
     17 
     18 using namespace std;
     19 
     20 static bool
     21 is_dir(const string& path)
     22 {
     23     int err;
     24     struct stat st;
     25     err = stat(path.c_str(), &st);
     26     return err != 0 || S_ISDIR(st.st_mode);
     27 }
     28 
     29 static int
     30 remove_file(const string& path)
     31 {
     32     int err = unlink(path.c_str());
     33     if (err != 0) {
     34         fprintf(stderr, "error deleting file %s (%s)\n", path.c_str(),
     35                 strerror(errno));
     36         return errno;
     37     }
     38     return 0;
     39 }
     40 
     41 int
     42 remove_recursively(const string& path)
     43 {
     44     int err;
     45 
     46     if (is_dir(path)) {
     47         DIR *d = opendir(path.c_str());
     48         if (d == NULL) {
     49             fprintf(stderr, "error getting directory contents %s (%s)\n",
     50                     path.c_str(), strerror(errno));
     51             return errno;
     52         }
     53 
     54         vector<string> files;
     55         vector<string> dirs;
     56 
     57         struct dirent *ent;
     58         while (NULL != (ent = readdir(d))) {
     59             if (0 == strcmp(".", ent->d_name)
     60                     || 0 == strcmp("..", ent->d_name)) {
     61                 continue;
     62             }
     63             string full = path;
     64             full += '/';
     65             full += ent->d_name;
     66 #ifdef HAVE_DIRENT_D_TYPE
     67             bool is_directory = (ent->d_type == DT_DIR);
     68 #else
     69             // If dirent.d_type is missing, then use stat instead
     70             struct stat stat_buf;
     71             stat(full.c_str(), &stat_buf);
     72             bool is_directory = S_ISDIR(stat_buf.st_mode);
     73 #endif
     74             if (is_directory) {
     75                 dirs.push_back(full);
     76             } else {
     77                 files.push_back(full);
     78             }
     79         }
     80         closedir(d);
     81 
     82         for (vector<string>::iterator it=files.begin(); it!=files.end(); it++) {
     83             err = remove_file(*it);
     84             if (err != 0) {
     85                 return err;
     86             }
     87         }
     88 
     89         for (vector<string>::iterator it=dirs.begin(); it!=dirs.end(); it++) {
     90             err = remove_recursively(*it);
     91             if (err != 0) {
     92                 return err;
     93             }
     94         }
     95 
     96         err = rmdir(path.c_str());
     97         if (err != 0) {
     98             fprintf(stderr, "error deleting directory %s (%s)\n", path.c_str(),
     99                     strerror(errno));
    100             return errno;
    101         }
    102         return 0;
    103     } else {
    104         return remove_file(path);
    105     }
    106 }
    107 
    108 int
    109 mkdir_recursively(const string& path)
    110 {
    111     int err;
    112     size_t pos = 0;
    113     // For absolute pathnames, that starts with leading '/'
    114     // use appropriate initial value.
    115     if (path.length() != 0 and path[0] == '/') pos++;
    116 
    117     while (true) {
    118         pos = path.find('/', pos);
    119         string p = path.substr(0, pos);
    120         struct stat st;
    121         err = stat(p.c_str(), &st);
    122         if (err != 0) {
    123             err = mkdir(p.c_str(), 0770);
    124             if (err != 0) {
    125                 fprintf(stderr, "can't create directory %s (%s)\n",
    126                         path.c_str(), strerror(errno));
    127                 return errno;
    128             }
    129         }
    130         else if (!S_ISDIR(st.st_mode)) {
    131             fprintf(stderr, "can't create directory %s because %s is a file.\n",
    132                         path.c_str(), p.c_str());
    133             return 1;
    134         }
    135         pos++;
    136         if (p == path) {
    137             return 0;
    138         }
    139     }
    140 }
    141 
    142 int
    143 copy_file(const string& src, const string& dst)
    144 {
    145     int err;
    146 
    147     err = copyFile(src.c_str(), dst.c_str(),
    148                     COPY_NO_DEREFERENCE | COPY_FORCE | COPY_PERMISSIONS);
    149     return err;
    150 }
    151 
    152 int
    153 strip_file(const string& path)
    154 {
    155     // Default strip command to run is "strip" unless overridden by the ATREE_STRIP env var.
    156     const char* strip_cmd = getenv("ATREE_STRIP");
    157     if (!strip_cmd || !strip_cmd[0]) {
    158         strip_cmd = "strip";
    159     }
    160     pid_t pid = fork();
    161     if (pid == -1) {
    162         // Fork failed. errno should be set.
    163         return -1;
    164     } else if (pid == 0) {
    165         // Exec in the child. Only returns if execve failed.
    166 
    167         int num_args = 0;
    168         const char *s = strip_cmd;
    169         while (*s) {
    170             while (*s == ' ') ++s;
    171             if (*s && *s != ' ') {
    172                 ++num_args;
    173                 while (*s && *s != ' ') ++s;
    174             }
    175         }
    176 
    177         if (num_args <= 0) {
    178             fprintf(stderr, "Invalid ATREE_STRIP command '%s'\n", strip_cmd);
    179             return 1;
    180 
    181         } else if (num_args == 1) {
    182             return execlp(strip_cmd, strip_cmd, path.c_str(), (char *)NULL);
    183 
    184         } else {
    185             // Split the arguments if more than 1
    186             char* cmd = strdup(strip_cmd);
    187             const char** args = (const char**) malloc(sizeof(const char*) * (num_args + 2));
    188 
    189             const char** curr = args;
    190             char* s = cmd;
    191             while (*s) {
    192                 while (*s == ' ') ++s;
    193                 if (*s && *s != ' ') {
    194                     *curr = s;
    195                     ++curr;
    196                     while (*s && *s != ' ') ++s;
    197                     if (*s) {
    198                         *s = '\0';
    199                         ++s;
    200                     }
    201                 }
    202             }
    203 
    204             args[num_args] = path.c_str();
    205             args[num_args + 1] = NULL;
    206 
    207             int ret = execvp(args[0], (char* const*)args);
    208             free(args);
    209             free(cmd);
    210             return ret;
    211         }
    212     } else {
    213         // Wait for child pid and return its exit code.
    214         int status;
    215         waitpid(pid, &status, 0);
    216         return status;
    217     }
    218 }
    219 
    220