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

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: Finish the work on linux, macos, android. 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') | runtime/bin/directory_linux.cc » ('J')
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 } 74 }
91 return listing->HandleDirectory(path->data) && 75 if (!listing->HandleDirectory(path->data)) {
92 (!recursive || ListRecursively(path->data, recursive, listing)); 76 return false;
77 }
78 if (!path->Add(File::PathSeparator())) {
79 PostError(listing, path->data);
80 return false;
81 }
82 return !recursive || ListRecursively(path, recursive, listing);
93 } 83 }
94 84
85
95 static bool HandleFile(char* file_name, 86 static bool HandleFile(char* file_name,
96 PathBuffer* path, 87 PathBuffer* path,
97 DirectoryListing *listing) { 88 DirectoryListing *listing) {
98 if (!path->Add(file_name)) { 89 if (!path->Add(file_name)) {
99 PostError(listing, path->data); 90 PostError(listing, path->data);
100 return false; 91 return false;
101 } 92 }
102 return listing->HandleFile(path->data); 93 return listing->HandleFile(path->data);
103 } 94 }
104 95
105 96
106 static bool ListRecursively(const char* dir_name, 97 static bool ListRecursively(PathBuffer* path,
107 bool recursive, 98 bool recursive,
108 DirectoryListing *listing) { 99 DirectoryListing *listing) {
109 DIR* dir_pointer; 100 DIR* dir_pointer;
110 do { 101 do {
111 dir_pointer = opendir(dir_name); 102 dir_pointer = opendir(path->data);
112 } while (dir_pointer == NULL && errno == EINTR); 103 } while (dir_pointer == NULL && errno == EINTR);
113 if (dir_pointer == NULL) { 104 if (dir_pointer == NULL) {
114 PostError(listing, dir_name); 105 PostError(listing, path->data);
115 return false; 106 return false;
116 } 107 }
117 108
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 109 // Iterate the directory and post the directories and files to the
129 // ports. 110 // ports.
130 int path_length = path->length; 111 int path_length = path->length;
131 int status = 0; 112 int status = 0;
132 bool success = true; 113 bool success = true;
133 dirent entry; 114 dirent entry;
134 dirent* result; 115 dirent* result;
135 while ((status = TEMP_FAILURE_RETRY(readdir_r(dir_pointer, 116 while ((status = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
136 &entry, 117 &entry,
137 &result))) == 0 && 118 &result))) == 0 &&
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
181 } 162 }
182 default: 163 default:
183 break; 164 break;
184 } 165 }
185 path->Reset(path_length); 166 path->Reset(path_length);
186 } 167 }
187 168
188 if (status != 0) { 169 if (status != 0) {
189 errno = status; 170 errno = status;
190 success = false; 171 success = false;
191 PostError(listing, dir_name); 172 PostError(listing, path->data);
192 } 173 }
193 174
194 if (closedir(dir_pointer) == -1) { 175 if (closedir(dir_pointer) == -1) {
195 success = false; 176 success = false;
196 PostError(listing, dir_name); 177 PostError(listing, path->data);
197 } 178 }
198 delete path;
199 179
200 return success; 180 return success;
201 } 181 }
202 182
203 183
204 static bool DeleteFile(char* file_name, 184 static bool DeleteFile(char* file_name,
205 PathBuffer* path) { 185 PathBuffer* path) {
206 return path->Add(file_name) && remove(path->data) == 0; 186 return path->Add(file_name) && remove(path->data) == 0;
207 } 187 }
208 188
209 189
210 static bool DeleteDir(char* dir_name, 190 static bool DeleteDir(char* dir_name,
211 PathBuffer* path) { 191 PathBuffer* path) {
212 if (strcmp(dir_name, ".") == 0) return true; 192 if (strcmp(dir_name, ".") == 0) return true;
213 if (strcmp(dir_name, "..") == 0) return true; 193 if (strcmp(dir_name, "..") == 0) return true;
214 return path->Add(dir_name) && DeleteRecursively(path->data); 194 return path->Add(dir_name) &&
195 path->Add(File::PathSeparator()) &&
196 DeleteRecursively(path);
215 } 197 }
216 198
217 199
218 static bool DeleteRecursively(const char* dir_name) { 200 static bool DeleteRecursively(PathBuffer* path) {
219 // Do not recurse into links for deletion. Instead delete the link. 201 // Do not recurse into links for deletion. Instead delete the link.
220 struct stat st; 202 struct stat st;
221 if (TEMP_FAILURE_RETRY(lstat(dir_name, &st)) == -1) { 203 if (TEMP_FAILURE_RETRY(lstat(path->data, &st)) == -1) {
222 return false; 204 return false;
223 } else if (S_ISLNK(st.st_mode)) { 205 } else if (S_ISLNK(st.st_mode)) {
224 return (remove(dir_name) == 0); 206 return (remove(path->data) == 0);
225 } 207 }
226 208
227 // Not a link. Attempt to open as a directory and recurse into the 209 // Not a link. Attempt to open as a directory and recurse into the
228 // directory. 210 // directory.
229 DIR* dir_pointer; 211 DIR* dir_pointer;
230 do { 212 do {
231 dir_pointer = opendir(dir_name); 213 dir_pointer = opendir(path->data);
232 } while (dir_pointer == NULL && errno == EINTR); 214 } while (dir_pointer == NULL && errno == EINTR);
233 215
234 if (dir_pointer == NULL) { 216 if (dir_pointer == NULL) {
235 return false; 217 return false;
236 } 218 }
237 219
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. 220 // Iterate the directory and delete all files and directories.
245 int path_length = path->length; 221 int path_length = path->length;
246 int read = 0; 222 int read = 0;
247 bool success = true; 223 bool success = true;
248 dirent entry; 224 dirent entry;
249 dirent* result; 225 dirent* result;
250 while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer, 226 while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
251 &entry, 227 &entry,
252 &result))) == 0 && 228 &result))) == 0 &&
253 result != NULL && 229 result != NULL &&
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
286 // directory. 262 // directory.
287 success = success && DeleteFile(entry.d_name, path); 263 success = success && DeleteFile(entry.d_name, path);
288 } 264 }
289 break; 265 break;
290 } 266 }
291 default: 267 default:
292 break; 268 break;
293 } 269 }
294 path->Reset(path_length); 270 path->Reset(path_length);
295 } 271 }
296 delete path;
297 272
298 if ((read != 0) || 273 if ((read != 0) ||
299 (closedir(dir_pointer) == -1) || 274 (closedir(dir_pointer) == -1) ||
300 (remove(dir_name) == -1)) { 275 (remove(path->data) == -1)) {
301 return false; 276 return false;
302 } 277 }
303
304 return success; 278 return success;
305 } 279 }
306 280
307 281
308 bool Directory::List(const char* dir_name, 282 bool Directory::List(const char* dir_name,
309 bool recursive, 283 bool recursive,
310 DirectoryListing *listing) { 284 DirectoryListing *listing) {
311 bool completed = ListRecursively(dir_name, recursive, listing); 285 PathBuffer path;
312 return completed; 286 if (!path.Add(dir_name) || !path.Add(File::PathSeparator())) {
287 PostError(listing, dir_name);
288 return false;
289 }
290 return ListRecursively(&path, recursive, listing);
313 } 291 }
314 292
315 293
316 Directory::ExistsResult Directory::Exists(const char* dir_name) { 294 Directory::ExistsResult Directory::Exists(const char* dir_name) {
317 struct stat entry_info; 295 struct stat entry_info;
318 int success = TEMP_FAILURE_RETRY(stat(dir_name, &entry_info)); 296 int success = TEMP_FAILURE_RETRY(stat(dir_name, &entry_info));
319 if (success == 0) { 297 if (success == 0) {
320 if (S_ISDIR(entry_info.st_mode)) { 298 if (S_ISDIR(entry_info.st_mode)) {
321 return EXISTS; 299 return EXISTS;
322 } else { 300 } else {
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
378 } 356 }
379 return path_template; 357 return path_template;
380 } 358 }
381 359
382 360
383 char* Directory::CreateTemp(const char* const_template) { 361 char* Directory::CreateTemp(const char* const_template) {
384 // Returns a new, unused directory name, modifying the contents of 362 // Returns a new, unused directory name, modifying the contents of
385 // dir_template. Creates the directory with the permissions specified 363 // dir_template. Creates the directory with the permissions specified
386 // by the process umask. 364 // by the process umask.
387 // The return value must be freed by the caller. 365 // The return value must be freed by the caller.
388 PathBuffer* path = new PathBuffer(); 366 PathBuffer path;
389 path->Add(const_template); 367 path.Add(const_template);
390 if (path->length == 0) { 368 if (path.length == 0) {
391 // Android does not have a /tmp directory. A partial substitute, 369 // Android does not have a /tmp directory. A partial substitute,
392 // suitable for bring-up work and tests, is to create a tmp 370 // suitable for bring-up work and tests, is to create a tmp
393 // directory in /data/local/tmp. 371 // directory in /data/local/tmp.
394 // 372 //
395 // TODO(4413): In the long run, when running in an application we should 373 // TODO(4413): In the long run, when running in an application we should
396 // probably use android.content.Context.getCacheDir(). 374 // probably use android.content.Context.getCacheDir().
397 #define ANDROID_TEMP_DIR "/data/local/tmp" 375 #define ANDROID_TEMP_DIR "/data/local/tmp"
398 struct stat st; 376 struct stat st;
399 if (stat(ANDROID_TEMP_DIR, &st) != 0) { 377 if (stat(ANDROID_TEMP_DIR, &st) != 0) {
400 mkdir(ANDROID_TEMP_DIR, 0777); 378 mkdir(ANDROID_TEMP_DIR, 0777);
401 } 379 }
402 path->Add(ANDROID_TEMP_DIR "/tmp/temp_dir1_"); 380 path->Add(ANDROID_TEMP_DIR "/tmp/temp_dir1_");
403 } else if ((path->data)[path->length - 1] == '/') { 381 } else if ((path.data)[path.length - 1] == '/') {
404 path->Add("temp_dir_"); 382 path.Add("temp_dir_");
405 } 383 }
406 if (!path->Add("XXXXXX")) { 384 if (!path.Add("XXXXXX")) {
407 // Pattern has overflowed. 385 // Pattern has overflowed.
408 delete path;
409 return NULL; 386 return NULL;
410 } 387 }
411 char* result; 388 char* result;
412 do { 389 do {
413 result = MakeTempDirectory(path->data); 390 result = MakeTempDirectory(path->data);
414 } while (result == NULL && errno == EINTR); 391 } while (result == NULL && errno == EINTR);
415 if (result == NULL) { 392 if (result == NULL) {
416 delete path;
417 return NULL; 393 return NULL;
418 } 394 }
419 int length = strnlen(path->data, PATH_MAX); 395 int length = strnlen(path.data, PATH_MAX);
420 result = static_cast<char*>(malloc(length + 1)); 396 result = static_cast<char*>(malloc(length + 1));
421 strncpy(result, path->data, length); 397 strncpy(result, path.data, length);
422 result[length] = '\0'; 398 result[length] = '\0';
423 delete path;
424 return result; 399 return result;
425 } 400 }
426 401
427 402
428 bool Directory::Delete(const char* dir_name, bool recursive) { 403 bool Directory::Delete(const char* dir_name, bool recursive) {
429 if (!recursive) { 404 if (!recursive) {
430 return (TEMP_FAILURE_RETRY(remove(dir_name)) == 0); 405 return (TEMP_FAILURE_RETRY(remove(dir_name)) == 0);
431 } else { 406 } else {
432 return DeleteRecursively(dir_name); 407 PathBuffer path;
408 if (!path.Add(dir_name) || !path.Add(File::PathSeparator())) {
409 return false;
410 }
411 return DeleteRecursively(&path);
433 } 412 }
434 } 413 }
435 414
436 415
437 bool Directory::Rename(const char* path, const char* new_path) { 416 bool Directory::Rename(const char* path, const char* new_path) {
438 ExistsResult exists = Exists(path); 417 ExistsResult exists = Exists(path);
439 if (exists != EXISTS) return false; 418 if (exists != EXISTS) return false;
440 return (TEMP_FAILURE_RETRY(rename(path, new_path)) == 0); 419 return (TEMP_FAILURE_RETRY(rename(path, new_path)) == 0);
441 } 420 }
OLDNEW
« no previous file with comments | « no previous file | runtime/bin/directory_linux.cc » ('j') | runtime/bin/directory_linux.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698