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
is_dir(const string & path)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
remove_file(const string & path)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
remove_recursively(const string & path)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             bool is_directory = (ent->d_type == DT_DIR);
67             if (is_directory) {
68                 dirs.push_back(full);
69             } else {
70                 files.push_back(full);
71             }
72         }
73         closedir(d);
74 
75         for (vector<string>::iterator it=files.begin(); it!=files.end(); it++) {
76             err = remove_file(*it);
77             if (err != 0) {
78                 return err;
79             }
80         }
81 
82         for (vector<string>::iterator it=dirs.begin(); it!=dirs.end(); it++) {
83             err = remove_recursively(*it);
84             if (err != 0) {
85                 return err;
86             }
87         }
88 
89         err = rmdir(path.c_str());
90         if (err != 0) {
91             fprintf(stderr, "error deleting directory %s (%s)\n", path.c_str(),
92                     strerror(errno));
93             return errno;
94         }
95         return 0;
96     } else {
97         return remove_file(path);
98     }
99 }
100 
101 int
mkdir_recursively(const string & path)102 mkdir_recursively(const string& path)
103 {
104     int err;
105     size_t pos = 0;
106     // For absolute pathnames, that starts with leading '/'
107     // use appropriate initial value.
108     if (path.length() != 0 and path[0] == '/') pos++;
109 
110     while (true) {
111         pos = path.find('/', pos);
112         string p = path.substr(0, pos);
113         struct stat st;
114         err = stat(p.c_str(), &st);
115         if (err != 0) {
116             err = mkdir(p.c_str(), 0770);
117             if (err != 0) {
118                 fprintf(stderr, "can't create directory %s (%s)\n",
119                         path.c_str(), strerror(errno));
120                 return errno;
121             }
122         }
123         else if (!S_ISDIR(st.st_mode)) {
124             fprintf(stderr, "can't create directory %s because %s is a file.\n",
125                         path.c_str(), p.c_str());
126             return 1;
127         }
128         pos++;
129         if (p == path) {
130             return 0;
131         }
132     }
133 }
134 
135 int
copy_file(const string & src,const string & dst)136 copy_file(const string& src, const string& dst)
137 {
138     int err;
139 
140     err = copyFile(src.c_str(), dst.c_str(),
141                     COPY_NO_DEREFERENCE | COPY_FORCE | COPY_PERMISSIONS);
142     return err;
143 }
144 
145 int
strip_file(const string & path)146 strip_file(const string& path)
147 {
148     // Default strip command to run is "strip" unless overridden by the ATREE_STRIP env var.
149     const char* strip_cmd = getenv("ATREE_STRIP");
150     if (!strip_cmd || !strip_cmd[0]) {
151         strip_cmd = "strip";
152     }
153     pid_t pid = fork();
154     if (pid == -1) {
155         // Fork failed. errno should be set.
156         return -1;
157     } else if (pid == 0) {
158         // Exec in the child. Only returns if execve failed.
159 
160         int num_args = 0;
161         const char *s = strip_cmd;
162         while (*s) {
163             while (*s == ' ') ++s;
164             if (*s && *s != ' ') {
165                 ++num_args;
166                 while (*s && *s != ' ') ++s;
167             }
168         }
169 
170         if (num_args <= 0) {
171             fprintf(stderr, "Invalid ATREE_STRIP command '%s'\n", strip_cmd);
172             return 1;
173 
174         } else if (num_args == 1) {
175             return execlp(strip_cmd, strip_cmd, path.c_str(), (char *)NULL);
176 
177         } else {
178             // Split the arguments if more than 1
179             char* cmd = strdup(strip_cmd);
180             const char** args = (const char**) malloc(sizeof(const char*) * (num_args + 2));
181 
182             const char** curr = args;
183             char* s = cmd;
184             while (*s) {
185                 while (*s == ' ') ++s;
186                 if (*s && *s != ' ') {
187                     *curr = s;
188                     ++curr;
189                     while (*s && *s != ' ') ++s;
190                     if (*s) {
191                         *s = '\0';
192                         ++s;
193                     }
194                 }
195             }
196 
197             args[num_args] = path.c_str();
198             args[num_args + 1] = NULL;
199 
200             int ret = execvp(args[0], (char* const*)args);
201             free(args);
202             free(cmd);
203             return ret;
204         }
205     } else {
206         // Wait for child pid and return its exit code.
207         int status;
208         waitpid(pid, &status, 0);
209         return status;
210     }
211 }
212 
213