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 #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
mkdir_recursively(const string & path)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
copy_file(const string & src,const string & dst)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
strip_file(const string & path)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