Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(155)

Side by Side Diff: runtime/bin/directory_posix.cc

Issue 10823209: Add support for building the Dart VM for Android OS. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 #include "bin/directory.h"
6
7 #include <dirent.h>
8 #include <errno.h>
9 #include <sys/param.h>
10 #include <sys/stat.h>
11 #include <unistd.h>
12
13 #include "bin/file.h"
14 #include "bin/platform.h"
15
16
17 static char* SafeStrNCpy(char* dest, const char* src, size_t n) {
18 strncpy(dest, src, n);
19 dest[n - 1] = '\0';
20 return dest;
21 }
22
23
24 // Forward declarations.
25 static bool ListRecursively(const char* dir_name,
26 bool recursive,
27 DirectoryListing* listing);
28 static bool DeleteRecursively(const char* dir_name);
29
30
31 static bool ComputeFullPath(const char* dir_name,
32 char* path,
33 int* path_length) {
34 char* abs_path;
35 do {
36 abs_path = realpath(dir_name, path);
37 } while (abs_path == NULL && errno == EINTR);
38 if (abs_path == NULL) {
39 return false;
40 }
41 *path_length = strlen(path);
42 size_t written = snprintf(path + *path_length,
43 PATH_MAX - *path_length,
44 "%s",
45 File::PathSeparator());
46 if (written != strlen(File::PathSeparator())) {
47 return false;
48 }
49 *path_length += written;
50 return true;
51 }
52
53
54 static bool HandleDir(char* dir_name,
55 char* path,
56 int path_length,
57 bool recursive,
58 DirectoryListing *listing) {
59 if (strcmp(dir_name, ".") != 0 &&
60 strcmp(dir_name, "..") != 0) {
61 size_t written = snprintf(path + path_length,
62 PATH_MAX - path_length,
63 "%s",
64 dir_name);
65 if (written != strlen(dir_name)) {
66 return false;
67 }
68 bool ok = listing->HandleDirectory(path);
69 if (!ok) return ok;
70 if (recursive) {
71 return ListRecursively(path, recursive, listing);
72 }
73 }
74 return true;
75 }
76
77
78 static bool HandleFile(char* file_name,
79 char* path,
80 int path_length,
81 DirectoryListing *listing) {
82 // TODO(sgjesse): Pass flags to indicate whether file responses are
83 // needed.
84 size_t written = snprintf(path + path_length,
85 PATH_MAX - path_length,
86 "%s",
87 file_name);
88 if (written != strlen(file_name)) {
89 return false;
90 }
91 return listing->HandleFile(path);
92 }
93
94
95 static void PostError(DirectoryListing *listing,
96 const char* dir_name) {
97 listing->HandleError(dir_name);
98 }
99
100
101 static bool ListRecursively(const char* dir_name,
102 bool recursive,
103 DirectoryListing *listing) {
104 DIR* dir_pointer;
105 do {
106 dir_pointer = opendir(dir_name);
107 } while (dir_pointer == NULL && errno == EINTR);
108 if (dir_pointer == NULL) {
109 PostError(listing, dir_name);
110 return false;
111 }
112
113 // Compute full path for the directory currently being listed. The
114 // path buffer will be used to construct the current path in the
115 // recursive traversal. path_length does not always equal
116 // strlen(path) but indicates the current prefix of path that is the
117 // path of the current directory in the traversal.
118 char *path = static_cast<char*>(malloc(PATH_MAX));
119 ASSERT(path != NULL);
120 int path_length = 0;
121 bool valid = ComputeFullPath(dir_name, path, &path_length);
122 if (!valid) {
123 free(path);
124 PostError(listing, dir_name);
125 return false;
126 }
127
128 // Iterated the directory and post the directories and files to the
129 // ports.
130 int read = 0;
131 bool success = true;
132 dirent entry;
133 dirent* result;
134 while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
135 &entry,
136 &result))) == 0 &&
137 result != NULL) {
138 switch (entry.d_type) {
139 case DT_DIR:
140 success = HandleDir(entry.d_name,
141 path,
142 path_length,
143 recursive,
144 listing) && success;
145 break;
146 case DT_REG:
147 success = HandleFile(entry.d_name,
148 path,
149 path_length,
150 listing) && success;
151 break;
152 case DT_LNK:
153 case DT_UNKNOWN: {
154 // On some file systems the entry type is not determined by
155 // readdir_r. For those and for links we use stat to determine
156 // the actual entry type. Notice that stat returns the type of
157 // the file pointed to.
158 struct stat entry_info;
159 size_t written = snprintf(path + path_length,
160 PATH_MAX - path_length,
161 "%s",
162 entry.d_name);
163 if (written != strlen(entry.d_name)) {
164 success = false;
165 break;
166 }
167 int stat_success = TEMP_FAILURE_RETRY(stat(path, &entry_info));
168 if (stat_success == -1) {
169 success = false;
170 PostError(listing, path);
171 break;
172 }
173 if (S_ISDIR(entry_info.st_mode)) {
174 success = HandleDir(entry.d_name,
175 path,
176 path_length,
177 recursive,
178 listing) && success;
179 } else if (S_ISREG(entry_info.st_mode)) {
180 success = HandleFile(entry.d_name,
181 path,
182 path_length,
183 listing) && success;
184 }
185 ASSERT(!S_ISLNK(entry_info.st_mode));
186 break;
187 }
188 default:
189 break;
190 }
191 }
192
193 if (read != 0) {
194 errno = read;
195 success = false;
196 PostError(listing, dir_name);
197 }
198
199 if (closedir(dir_pointer) == -1) {
200 success = false;
201 PostError(listing, dir_name);
202 }
203 free(path);
204
205 return success;
206 }
207
208
209 static bool DeleteFile(char* file_name,
210 char* path,
211 int path_length) {
212 size_t written = snprintf(path + path_length,
213 PATH_MAX - path_length,
214 "%s",
215 file_name);
216 if (written != strlen(file_name)) {
217 return false;
218 }
219 return (remove(path) == 0);
220 }
221
222
223 static bool DeleteDir(char* dir_name,
224 char* path,
225 int path_length) {
226 if (strcmp(dir_name, ".") != 0 &&
227 strcmp(dir_name, "..") != 0) {
228 size_t written = snprintf(path + path_length,
229 PATH_MAX - path_length,
230 "%s",
231 dir_name);
232 if (written != strlen(dir_name)) {
233 return false;
234 }
235 return DeleteRecursively(path);
236 }
237 return true;
238 }
239
240
241 static bool DeleteRecursively(const char* dir_name) {
242 // Do not recurse into links for deletion. Instead delete the link.
243 struct stat st;
244 if (TEMP_FAILURE_RETRY(lstat(dir_name, &st)) == -1) {
245 return false;
246 } else if (S_ISLNK(st.st_mode)) {
247 return (remove(dir_name) == 0);
248 }
249
250 // Not a link. Attempt to open as a directory and recurse into the
251 // directory.
252 DIR* dir_pointer;
253 do {
254 dir_pointer = opendir(dir_name);
255 } while (dir_pointer == NULL && errno == EINTR);
256
257 if (dir_pointer == NULL) {
258 return false;
259 }
260
261 // Compute full path for the directory currently being deleted. The
262 // path buffer will be used to construct the current path in the
263 // recursive traversal. path_length does not always equal
264 // strlen(path) but indicates the current prefix of path that is the
265 // path of the current directory in the traversal.
266 char *path = static_cast<char*>(malloc(PATH_MAX));
267 ASSERT(path != NULL);
268 int path_length = 0;
269 bool valid = ComputeFullPath(dir_name, path, &path_length);
270 if (!valid) {
271 free(path);
272 return false;
273 }
274
275 // Iterate the directory and delete all files and directories.
276 int read = 0;
277 bool success = true;
278 dirent entry;
279 dirent* result;
280 while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
281 &entry,
282 &result))) == 0 &&
283 result != NULL &&
284 success) {
285 switch (entry.d_type) {
286 case DT_DIR:
287 success = success && DeleteDir(entry.d_name, path, path_length);
288 break;
289 case DT_REG:
290 case DT_LNK:
291 // Treat all links as files. This will delete the link which
292 // is what we want no matter if the link target is a file or a
293 // directory.
294 success = success && DeleteFile(entry.d_name, path, path_length);
295 break;
296 case DT_UNKNOWN: {
297 // On some file systems the entry type is not determined by
298 // readdir_r. For those we use lstat to determine the entry
299 // type.
300 struct stat entry_info;
301 size_t written = snprintf(path + path_length,
302 PATH_MAX - path_length,
303 "%s",
304 entry.d_name);
305 if (written != strlen(entry.d_name)) {
306 success = false;
307 break;
308 }
309 int lstat_success = TEMP_FAILURE_RETRY(lstat(path, &entry_info));
310 if (lstat_success == -1) {
311 success = false;
312 break;
313 }
314 if (S_ISDIR(entry_info.st_mode)) {
315 success = success && DeleteDir(entry.d_name, path, path_length);
316 } else if (S_ISREG(entry_info.st_mode) || S_ISLNK(entry_info.st_mode)) {
317 // Treat links as files. This will delete the link which is
318 // what we want no matter if the link target is a file or a
319 // directory.
320 success = success && DeleteFile(entry.d_name, path, path_length);
321 }
322 break;
323 }
324 default:
325 break;
326 }
327 }
328
329 free(path);
330
331 if ((read != 0) ||
332 (closedir(dir_pointer) == -1) ||
333 (remove(dir_name) == -1)) {
334 return false;
335 }
336
337 return success;
338 }
339
340
341 bool Directory::List(const char* dir_name,
342 bool recursive,
343 DirectoryListing *listing) {
344 bool completed = ListRecursively(dir_name, recursive, listing);
345 return completed;
346 }
347
348
349 Directory::ExistsResult Directory::Exists(const char* dir_name) {
350 struct stat entry_info;
351 int success = TEMP_FAILURE_RETRY(stat(dir_name, &entry_info));
352 if (success == 0) {
353 if (S_ISDIR(entry_info.st_mode)) {
354 return EXISTS;
355 } else {
356 return DOES_NOT_EXIST;
357 }
358 } else {
359 if (errno == EACCES ||
360 errno == EBADF ||
361 errno == EFAULT ||
362 errno == ENOMEM ||
363 errno == EOVERFLOW) {
364 // Search permissions denied for one of the directories in the
365 // path or a low level error occured. We do not know if the
366 // directory exists.
367 return UNKNOWN;
368 }
369 ASSERT(errno == ELOOP ||
370 errno == ENAMETOOLONG ||
371 errno == ENOENT ||
372 errno == ENOTDIR);
373 return DOES_NOT_EXIST;
374 }
375 }
376
377
378 char* Directory::Current() {
379 return getcwd(NULL, 0);
380 }
381
382
383 bool Directory::Create(const char* dir_name) {
384 // Create the directory with the permissions specified by the
385 // process umask.
386 return (TEMP_FAILURE_RETRY(mkdir(dir_name, 0777)) == 0);
387 }
388
389
390 char* Directory::CreateTemp(const char* const_template) {
391 // Returns a new, unused directory name, modifying the contents of
392 // dir_template. Creates the directory with the permissions specified
393 // by the process umask.
394 // The return value must be freed by the caller.
395 char* path = static_cast<char*>(malloc(PATH_MAX + 1));
396 SafeStrNCpy(path, const_template, PATH_MAX + 1);
397 int path_length = strlen(path);
398 if (path_length > 0) {
399 if ((path)[path_length - 1] == '/') {
400 snprintf(path + path_length, PATH_MAX - path_length, "temp_dir_XXXXXX");
401 } else {
402 snprintf(path + path_length, PATH_MAX - path_length, "XXXXXX");
403 }
404 } else {
405 snprintf(path, PATH_MAX, "/tmp/temp_dir1_XXXXXX");
406 }
407 char* result;
408 do {
409 result = mkdtemp(path);
410 } while (result == NULL && errno == EINTR);
411 if (result == NULL) {
412 free(path);
413 return NULL;
414 }
415 return path;
416 }
417
418
419 bool Directory::Delete(const char* dir_name, bool recursive) {
420 if (!recursive) {
421 return (TEMP_FAILURE_RETRY(remove(dir_name)) == 0);
422 } else {
423 return DeleteRecursively(dir_name);
424 }
425 }
426
427
428 bool Directory::Rename(const char* path, const char* new_path) {
429 ExistsResult exists = Exists(path);
430 if (exists != EXISTS) return false;
431 return (TEMP_FAILURE_RETRY(rename(path, new_path)) == 0);
432 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698