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

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

Issue 12217086: Change Directory.list to use the input path, and not resolve it to a full path. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Add the path separator at the top of the recursive function. Created 7 years, 10 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
« no previous file with comments | « no previous file | runtime/bin/directory_linux.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 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 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "bin/directory.h" 5 #include "bin/directory.h"
6 6
7 #include <dirent.h> 7 #include <dirent.h>
8 #include <errno.h> 8 #include <errno.h>
9 #include <string.h> 9 #include <string.h>
10 #include <sys/param.h> 10 #include <sys/param.h>
11 #include <sys/stat.h> 11 #include <sys/stat.h>
12 #include <unistd.h> 12 #include <unistd.h>
13 13
14 #include "bin/file.h" 14 #include "bin/file.h"
15 #include "bin/platform.h" 15 #include "bin/platform.h"
16 16
17 class PathBuffer { 17 class PathBuffer {
18 public: 18 public:
19 PathBuffer() : length(0) { } 19 PathBuffer() : length(0) {
20 data = new char[PATH_MAX + 1];
21 }
20 22
23 ~PathBuffer() {
24 delete[] data;
25 }
21 26
22 27 char* data;
23 char data[PATH_MAX + 1];
24 int length; 28 int length;
25 29
26 bool Add(const char* name) { 30 bool Add(const char* name) {
27 size_t written = snprintf(data + length, 31 size_t written = snprintf(data + length,
28 PATH_MAX - length, 32 PATH_MAX - length,
29 "%s", 33 "%s",
30 name); 34 name);
31 data[PATH_MAX] = '\0'; 35 data[PATH_MAX] = '\0';
32 if (written == strnlen(name, PATH_MAX + 1)) { 36 if (written == strnlen(name, PATH_MAX + 1)) {
33 length += written; 37 length += written;
34 return true; 38 return true;
35 } else { 39 } else {
36 errno = ENAMETOOLONG; 40 errno = ENAMETOOLONG;
37 return false; 41 return false;
38 } 42 }
39 } 43 }
40 44
41 void Reset(int new_length) { 45 void Reset(int new_length) {
42 length = new_length; 46 length = new_length;
43 data[length] = '\0'; 47 data[length] = '\0';
44 } 48 }
45 }; 49 };
46 50
47 51
48
49 // Forward declarations. 52 // Forward declarations.
50 static bool ListRecursively(const char* dir_name, 53 static bool ListRecursively(PathBuffer* path,
51 bool recursive, 54 bool recursive,
52 DirectoryListing* listing); 55 DirectoryListing* listing);
53 static bool DeleteRecursively(const char* dir_name); 56 static bool DeleteRecursively(PathBuffer* path);
54 57
55 58
56 static void PostError(DirectoryListing *listing, 59 static void PostError(DirectoryListing *listing,
57 const char* dir_name) { 60 const char* dir_name) {
58 listing->HandleError(dir_name); 61 listing->HandleError(dir_name);
59 } 62 }
60 63
61 64
62 static PathBuffer* ComputeFullPath(const char* dir_name) {
63 PathBuffer* path = new PathBuffer();
64 char* abs_path;
65 do {
66 abs_path = realpath(dir_name, path->data);
67 } while (abs_path == NULL && errno == EINTR);
68 if (abs_path == NULL) {
69 delete path;
70 return NULL;
71 }
72 path->length = strnlen(path->data, PATH_MAX);
73 if (path->Add(File::PathSeparator())) {
74 return path;
75 } else {
76 delete path;
77 return NULL;
78 }
79 }
80
81 static bool HandleDir(char* dir_name, 65 static bool HandleDir(char* dir_name,
82 PathBuffer* path, 66 PathBuffer* path,
83 bool recursive, 67 bool recursive,
84 DirectoryListing *listing) { 68 DirectoryListing *listing) {
85 if (strcmp(dir_name, ".") == 0) return true; 69 if (strcmp(dir_name, ".") == 0) return true;
86 if (strcmp(dir_name, "..") == 0) return true; 70 if (strcmp(dir_name, "..") == 0) return true;
87 if (!path->Add(dir_name)) { 71 if (!path->Add(dir_name)) {
88 PostError(listing, path->data); 72 PostError(listing, path->data);
89 return false; 73 return false;
90 }
91 return listing->HandleDirectory(path->data) && 74 return listing->HandleDirectory(path->data) &&
92 (!recursive || ListRecursively(path->data, recursive, listing)); 75 (!recursive || ListRecursively(path, recursive, listing));
93 } 76 }
94 77
78
95 static bool HandleFile(char* file_name, 79 static bool HandleFile(char* file_name,
96 PathBuffer* path, 80 PathBuffer* path,
97 DirectoryListing *listing) { 81 DirectoryListing *listing) {
98 if (!path->Add(file_name)) { 82 if (!path->Add(file_name)) {
99 PostError(listing, path->data); 83 PostError(listing, path->data);
100 return false; 84 return false;
101 } 85 }
102 return listing->HandleFile(path->data); 86 return listing->HandleFile(path->data);
103 } 87 }
104 88
105 89
106 static bool ListRecursively(const char* dir_name, 90 static bool ListRecursively(PathBuffer* path,
107 bool recursive, 91 bool recursive,
108 DirectoryListing *listing) { 92 DirectoryListing *listing) {
93 if (!path->Add(File::PathSeparator())) {
94 PostError(listing, path->data);
95 return false;
96 }
109 DIR* dir_pointer; 97 DIR* dir_pointer;
110 do { 98 do {
111 dir_pointer = opendir(dir_name); 99 dir_pointer = opendir(path->data);
112 } while (dir_pointer == NULL && errno == EINTR); 100 } while (dir_pointer == NULL && errno == EINTR);
113 if (dir_pointer == NULL) { 101 if (dir_pointer == NULL) {
114 PostError(listing, dir_name); 102 PostError(listing, path->data);
115 return false; 103 return false;
116 } 104 }
117 105
118 // Compute full path for the directory currently being listed. The
119 // path buffer will be used to construct the current path in the
120 // recursive traversal. path_length does not always equal
121 // strlen(path) but indicates the current prefix of path that is the
122 // path of the current directory in the traversal.
123 PathBuffer* path = ComputeFullPath(dir_name);
124 if (path == NULL) {
125 PostError(listing, dir_name);
126 return false;
127 }
128 // Iterate the directory and post the directories and files to the 106 // Iterate the directory and post the directories and files to the
129 // ports. 107 // ports.
130 int path_length = path->length; 108 int path_length = path->length;
131 int status = 0; 109 int status = 0;
132 bool success = true; 110 bool success = true;
133 dirent entry; 111 dirent entry;
134 dirent* result; 112 dirent* result;
135 while ((status = TEMP_FAILURE_RETRY(readdir_r(dir_pointer, 113 while ((status = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
136 &entry, 114 &entry,
137 &result))) == 0 && 115 &result))) == 0 &&
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
181 } 159 }
182 default: 160 default:
183 break; 161 break;
184 } 162 }
185 path->Reset(path_length); 163 path->Reset(path_length);
186 } 164 }
187 165
188 if (status != 0) { 166 if (status != 0) {
189 errno = status; 167 errno = status;
190 success = false; 168 success = false;
191 PostError(listing, dir_name); 169 PostError(listing, path->data);
192 } 170 }
193 171
194 if (closedir(dir_pointer) == -1) { 172 if (closedir(dir_pointer) == -1) {
195 success = false; 173 success = false;
196 PostError(listing, dir_name); 174 PostError(listing, path->data);
197 } 175 }
198 delete path;
199 176
200 return success; 177 return success;
201 } 178 }
202 179
203 180
204 static bool DeleteFile(char* file_name, 181 static bool DeleteFile(char* file_name,
205 PathBuffer* path) { 182 PathBuffer* path) {
206 return path->Add(file_name) && remove(path->data) == 0; 183 return path->Add(file_name) && remove(path->data) == 0;
207 } 184 }
208 185
209 186
210 static bool DeleteDir(char* dir_name, 187 static bool DeleteDir(char* dir_name,
211 PathBuffer* path) { 188 PathBuffer* path) {
212 if (strcmp(dir_name, ".") == 0) return true; 189 if (strcmp(dir_name, ".") == 0) return true;
213 if (strcmp(dir_name, "..") == 0) return true; 190 if (strcmp(dir_name, "..") == 0) return true;
214 return path->Add(dir_name) && DeleteRecursively(path->data); 191 return path->Add(dir_name) && DeleteRecursively(path);
215 } 192 }
216 193
217 194
218 static bool DeleteRecursively(const char* dir_name) { 195 static bool DeleteRecursively(PathBuffer* path) {
196 if (!path->Add(File::PathSeparator())) return false;
219 // Do not recurse into links for deletion. Instead delete the link. 197 // Do not recurse into links for deletion. Instead delete the link.
220 struct stat st; 198 struct stat st;
221 if (TEMP_FAILURE_RETRY(lstat(dir_name, &st)) == -1) { 199 if (TEMP_FAILURE_RETRY(lstat(path->data, &st)) == -1) {
222 return false; 200 return false;
223 } else if (S_ISLNK(st.st_mode)) { 201 } else if (S_ISLNK(st.st_mode)) {
224 return (remove(dir_name) == 0); 202 return (remove(path->data) == 0);
225 } 203 }
226 204
227 // Not a link. Attempt to open as a directory and recurse into the 205 // Not a link. Attempt to open as a directory and recurse into the
228 // directory. 206 // directory.
229 DIR* dir_pointer; 207 DIR* dir_pointer;
230 do { 208 do {
231 dir_pointer = opendir(dir_name); 209 dir_pointer = opendir(path->data);
232 } while (dir_pointer == NULL && errno == EINTR); 210 } while (dir_pointer == NULL && errno == EINTR);
233 211
234 if (dir_pointer == NULL) { 212 if (dir_pointer == NULL) {
235 return false; 213 return false;
236 } 214 }
237 215
238 // Compute full path for the directory currently being deleted. The
239 // path buffer will be used to construct the current path in the
240 // recursive traversal.
241 PathBuffer* path = ComputeFullPath(dir_name);
242 if (path == NULL) return false;
243
244 // Iterate the directory and delete all files and directories. 216 // Iterate the directory and delete all files and directories.
245 int path_length = path->length; 217 int path_length = path->length;
246 int read = 0; 218 int read = 0;
247 bool success = true; 219 bool success = true;
248 dirent entry; 220 dirent entry;
249 dirent* result; 221 dirent* result;
250 while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer, 222 while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
251 &entry, 223 &entry,
252 &result))) == 0 && 224 &result))) == 0 &&
253 result != NULL && 225 result != NULL &&
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
286 // directory. 258 // directory.
287 success = success && DeleteFile(entry.d_name, path); 259 success = success && DeleteFile(entry.d_name, path);
288 } 260 }
289 break; 261 break;
290 } 262 }
291 default: 263 default:
292 break; 264 break;
293 } 265 }
294 path->Reset(path_length); 266 path->Reset(path_length);
295 } 267 }
296 delete path;
297 268
298 if ((read != 0) || 269 if ((read != 0) ||
299 (closedir(dir_pointer) == -1) || 270 (closedir(dir_pointer) == -1) ||
300 (remove(dir_name) == -1)) { 271 (remove(path->data) == -1)) {
301 return false; 272 return false;
302 } 273 }
303
304 return success; 274 return success;
305 } 275 }
306 276
307 277
308 bool Directory::List(const char* dir_name, 278 bool Directory::List(const char* dir_name,
309 bool recursive, 279 bool recursive,
310 DirectoryListing *listing) { 280 DirectoryListing *listing) {
311 bool completed = ListRecursively(dir_name, recursive, listing); 281 PathBuffer path;
312 return completed; 282 if (!path.Add(dir_name)) {
283 PostError(listing, dir_name);
284 return false;
285 }
286 return ListRecursively(&path, recursive, listing);
313 } 287 }
314 288
315 289
316 Directory::ExistsResult Directory::Exists(const char* dir_name) { 290 Directory::ExistsResult Directory::Exists(const char* dir_name) {
317 struct stat entry_info; 291 struct stat entry_info;
318 int success = TEMP_FAILURE_RETRY(stat(dir_name, &entry_info)); 292 int success = TEMP_FAILURE_RETRY(stat(dir_name, &entry_info));
319 if (success == 0) { 293 if (success == 0) {
320 if (S_ISDIR(entry_info.st_mode)) { 294 if (S_ISDIR(entry_info.st_mode)) {
321 return EXISTS; 295 return EXISTS;
322 } else { 296 } else {
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
378 } 352 }
379 return path_template; 353 return path_template;
380 } 354 }
381 355
382 356
383 char* Directory::CreateTemp(const char* const_template) { 357 char* Directory::CreateTemp(const char* const_template) {
384 // Returns a new, unused directory name, modifying the contents of 358 // Returns a new, unused directory name, modifying the contents of
385 // dir_template. Creates the directory with the permissions specified 359 // dir_template. Creates the directory with the permissions specified
386 // by the process umask. 360 // by the process umask.
387 // The return value must be freed by the caller. 361 // The return value must be freed by the caller.
388 PathBuffer* path = new PathBuffer(); 362 PathBuffer path;
389 path->Add(const_template); 363 path.Add(const_template);
390 if (path->length == 0) { 364 if (path.length == 0) {
391 // Android does not have a /tmp directory. A partial substitute, 365 // Android does not have a /tmp directory. A partial substitute,
392 // suitable for bring-up work and tests, is to create a tmp 366 // suitable for bring-up work and tests, is to create a tmp
393 // directory in /data/local/tmp. 367 // directory in /data/local/tmp.
394 // 368 //
395 // TODO(4413): In the long run, when running in an application we should 369 // TODO(4413): In the long run, when running in an application we should
396 // probably use android.content.Context.getCacheDir(). 370 // probably use android.content.Context.getCacheDir().
397 #define ANDROID_TEMP_DIR "/data/local/tmp" 371 #define ANDROID_TEMP_DIR "/data/local/tmp"
398 struct stat st; 372 struct stat st;
399 if (stat(ANDROID_TEMP_DIR, &st) != 0) { 373 if (stat(ANDROID_TEMP_DIR, &st) != 0) {
400 mkdir(ANDROID_TEMP_DIR, 0777); 374 mkdir(ANDROID_TEMP_DIR, 0777);
401 } 375 }
402 path->Add(ANDROID_TEMP_DIR "/tmp/temp_dir1_"); 376 path->Add(ANDROID_TEMP_DIR "/tmp/temp_dir1_");
403 } else if ((path->data)[path->length - 1] == '/') { 377 } else if ((path.data)[path.length - 1] == '/') {
404 path->Add("temp_dir_"); 378 path.Add("temp_dir_");
405 } 379 }
406 if (!path->Add("XXXXXX")) { 380 if (!path.Add("XXXXXX")) {
407 // Pattern has overflowed. 381 // Pattern has overflowed.
408 delete path;
409 return NULL; 382 return NULL;
410 } 383 }
411 char* result; 384 char* result;
412 do { 385 do {
413 result = MakeTempDirectory(path->data); 386 result = MakeTempDirectory(path->data);
414 } while (result == NULL && errno == EINTR); 387 } while (result == NULL && errno == EINTR);
415 if (result == NULL) { 388 if (result == NULL) {
416 delete path;
417 return NULL; 389 return NULL;
418 } 390 }
419 int length = strnlen(path->data, PATH_MAX); 391 int length = strnlen(path.data, PATH_MAX);
420 result = static_cast<char*>(malloc(length + 1)); 392 result = static_cast<char*>(malloc(length + 1));
421 strncpy(result, path->data, length); 393 strncpy(result, path.data, length);
422 result[length] = '\0'; 394 result[length] = '\0';
423 delete path;
424 return result; 395 return result;
425 } 396 }
426 397
427 398
428 bool Directory::Delete(const char* dir_name, bool recursive) { 399 bool Directory::Delete(const char* dir_name, bool recursive) {
429 if (!recursive) { 400 if (!recursive) {
430 return (TEMP_FAILURE_RETRY(remove(dir_name)) == 0); 401 return (TEMP_FAILURE_RETRY(remove(dir_name)) == 0);
431 } else { 402 } else {
432 return DeleteRecursively(dir_name); 403 PathBuffer path;
404 if (!path.Add(dir_name)) {
405 return false;
406 }
407 return DeleteRecursively(&path);
433 } 408 }
434 } 409 }
435 410
436 411
437 bool Directory::Rename(const char* path, const char* new_path) { 412 bool Directory::Rename(const char* path, const char* new_path) {
438 ExistsResult exists = Exists(path); 413 ExistsResult exists = Exists(path);
439 if (exists != EXISTS) return false; 414 if (exists != EXISTS) return false;
440 return (TEMP_FAILURE_RETRY(rename(path, new_path)) == 0); 415 return (TEMP_FAILURE_RETRY(rename(path, new_path)) == 0);
441 } 416 }
OLDNEW
« no previous file with comments | « no previous file | runtime/bin/directory_linux.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698