blob: 9468cfd9bf6c3d6330b9f3cc3e9dbcd3bade6b66 [file] [log] [blame]
The Android Open Source Projectb6c1cf62008-10-21 07:00:00 -07001#include "fs.h"
2#include "files.h"
3#include <unistd.h>
Raphael0b3ec5d2011-09-14 15:07:05 -07004#include <stdlib.h>
The Android Open Source Projectb6c1cf62008-10-21 07:00:00 -07005#include <sys/types.h>
Raphael0b3ec5d2011-09-14 15:07:05 -07006#include <sys/wait.h>
The Android Open Source Projectb6c1cf62008-10-21 07:00:00 -07007#include <dirent.h>
8#include <string>
9#include <vector>
10#include <stdio.h>
The Android Open Source Project4f85cc52009-01-09 17:50:54 -080011#include <string.h>
The Android Open Source Projectb6c1cf62008-10-21 07:00:00 -070012#include <errno.h>
13#include <sys/stat.h>
14#include <unistd.h>
Alexey Zaytsev8ae3ad52008-10-22 02:02:30 +040015#include <string.h>
The Android Open Source Projectb6c1cf62008-10-21 07:00:00 -070016#include <host/CopyFile.h>
17
18using namespace std;
19
20static bool
21is_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
29static int
30remove_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
41int
42remove_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
Raphael0b3ec5d2011-09-14 15:07:05 -070069 // 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);
The Android Open Source Projectb6c1cf62008-10-21 07:00:00 -070073#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
108int
109mkdir_recursively(const string& path)
110{
111 int err;
112 size_t pos = 0;
Jey9af5fc42008-12-10 09:07:28 -0800113 // For absolute pathnames, that starts with leading '/'
114 // use appropriate initial value.
115 if (path.length() != 0 and path[0] == '/') pos++;
116
The Android Open Source Projectb6c1cf62008-10-21 07:00:00 -0700117 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
142int
143copy_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}
Raphael0b3ec5d2011-09-14 15:07:05 -0700151
152int
153strip_file(const string& path)
154{
Raphael Mollec5fe912012-06-06 19:33:31 -0700155 // Default strip command to run is "strip" unless overridden by the ATREE_STRIP env var.
156 const char* strip_cmd = getenv("ATREE_STRIP");
Raphael0b3ec5d2011-09-14 15:07:05 -0700157 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.
Raphael Mollec5fe912012-06-06 19:33:31 -0700166
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 }
Raphael0b3ec5d2011-09-14 15:07:05 -0700212 } 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