#include "fs.h" #include "files.h" #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/wait.h> #include <dirent.h> #include <string> #include <vector> #include <stdio.h> #include <string.h> #include <errno.h> #include <sys/stat.h> #include <unistd.h> #include <string.h> #include <host/CopyFile.h> using namespace std; static bool is_dir(const string& path) { int err; struct stat st; err = stat(path.c_str(), &st); return err != 0 || S_ISDIR(st.st_mode); } static int remove_file(const string& path) { int err = unlink(path.c_str()); if (err != 0) { fprintf(stderr, "error deleting file %s (%s)\n", path.c_str(), strerror(errno)); return errno; } return 0; } int remove_recursively(const string& path) { int err; if (is_dir(path)) { DIR *d = opendir(path.c_str()); if (d == NULL) { fprintf(stderr, "error getting directory contents %s (%s)\n", path.c_str(), strerror(errno)); return errno; } vector<string> files; vector<string> dirs; struct dirent *ent; while (NULL != (ent = readdir(d))) { if (0 == strcmp(".", ent->d_name) || 0 == strcmp("..", ent->d_name)) { continue; } string full = path; full += '/'; full += ent->d_name; #ifdef HAVE_DIRENT_D_TYPE bool is_directory = (ent->d_type == DT_DIR); #else // If dirent.d_type is missing, then use stat instead struct stat stat_buf; stat(full.c_str(), &stat_buf); bool is_directory = S_ISDIR(stat_buf.st_mode); #endif if (is_directory) { dirs.push_back(full); } else { files.push_back(full); } } closedir(d); for (vector<string>::iterator it=files.begin(); it!=files.end(); it++) { err = remove_file(*it); if (err != 0) { return err; } } for (vector<string>::iterator it=dirs.begin(); it!=dirs.end(); it++) { err = remove_recursively(*it); if (err != 0) { return err; } } err = rmdir(path.c_str()); if (err != 0) { fprintf(stderr, "error deleting directory %s (%s)\n", path.c_str(), strerror(errno)); return errno; } return 0; } else { return remove_file(path); } } int mkdir_recursively(const string& path) { int err; size_t pos = 0; // For absolute pathnames, that starts with leading '/' // use appropriate initial value. if (path.length() != 0 and path[0] == '/') pos++; while (true) { pos = path.find('/', pos); string p = path.substr(0, pos); struct stat st; err = stat(p.c_str(), &st); if (err != 0) { err = mkdir(p.c_str(), 0770); if (err != 0) { fprintf(stderr, "can't create directory %s (%s)\n", path.c_str(), strerror(errno)); return errno; } } else if (!S_ISDIR(st.st_mode)) { fprintf(stderr, "can't create directory %s because %s is a file.\n", path.c_str(), p.c_str()); return 1; } pos++; if (p == path) { return 0; } } } int copy_file(const string& src, const string& dst) { int err; err = copyFile(src.c_str(), dst.c_str(), COPY_NO_DEREFERENCE | COPY_FORCE | COPY_PERMISSIONS); return err; } int strip_file(const string& path) { // Default strip command to run is "strip" unless overridden by the ATREE_STRIP env var. const char* strip_cmd = getenv("ATREE_STRIP"); if (!strip_cmd || !strip_cmd[0]) { strip_cmd = "strip"; } pid_t pid = fork(); if (pid == -1) { // Fork failed. errno should be set. return -1; } else if (pid == 0) { // Exec in the child. Only returns if execve failed. int num_args = 0; const char *s = strip_cmd; while (*s) { while (*s == ' ') ++s; if (*s && *s != ' ') { ++num_args; while (*s && *s != ' ') ++s; } } if (num_args <= 0) { fprintf(stderr, "Invalid ATREE_STRIP command '%s'\n", strip_cmd); return 1; } else if (num_args == 1) { return execlp(strip_cmd, strip_cmd, path.c_str(), (char *)NULL); } else { // Split the arguments if more than 1 char* cmd = strdup(strip_cmd); const char** args = (const char**) malloc(sizeof(const char*) * (num_args + 2)); const char** curr = args; char* s = cmd; while (*s) { while (*s == ' ') ++s; if (*s && *s != ' ') { *curr = s; ++curr; while (*s && *s != ' ') ++s; if (*s) { *s = '\0'; ++s; } } } args[num_args] = path.c_str(); args[num_args + 1] = NULL; int ret = execvp(args[0], (char* const*)args); free(args); free(cmd); return ret; } } else { // Wait for child pid and return its exit code. int status; waitpid(pid, &status, 0); return status; } }