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

Side by Side Diff: runtime/bin/directory_linux.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 | « runtime/bin/directory_android.cc ('k') | runtime/bin/directory_macos.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 // Forward declarations. 52 // Forward declarations.
49 static bool ListRecursively(const char* dir_name, 53 static bool ListRecursively(PathBuffer* path,
50 bool recursive, 54 bool recursive,
51 DirectoryListing* listing); 55 DirectoryListing* listing);
52 static bool DeleteRecursively(const char* dir_name); 56 static bool DeleteRecursively(PathBuffer* path);
53 57
54 58
55 static void PostError(DirectoryListing *listing, 59 static void PostError(DirectoryListing *listing,
56 const char* dir_name) { 60 const char* dir_name) {
57 listing->HandleError(dir_name); 61 listing->HandleError(dir_name);
58 } 62 }
59 63
60 64
61 static PathBuffer* ComputeFullPath(const char* dir_name) {
62 PathBuffer* path = new PathBuffer();
63 char* abs_path;
64 do {
65 abs_path = realpath(dir_name, path->data);
66 } while (abs_path == NULL && errno == EINTR);
67 if (abs_path == NULL) {
68 delete path;
69 return NULL;
70 }
71 path->length = strnlen(path->data, PATH_MAX);
72 if (path->Add(File::PathSeparator())) {
73 return path;
74 } else {
75 delete path;
76 return NULL;
77 }
78 }
79
80 static bool HandleDir(char* dir_name, 65 static bool HandleDir(char* dir_name,
81 PathBuffer* path, 66 PathBuffer* path,
82 bool recursive, 67 bool recursive,
83 DirectoryListing *listing) { 68 DirectoryListing *listing) {
84 if (strcmp(dir_name, ".") == 0) return true; 69 if (strcmp(dir_name, ".") == 0) return true;
85 if (strcmp(dir_name, "..") == 0) return true; 70 if (strcmp(dir_name, "..") == 0) return true;
86 if (!path->Add(dir_name)) { 71 if (!path->Add(dir_name)) {
87 PostError(listing, path->data); 72 PostError(listing, path->data);
88 return false; 73 return false;
89 } 74 }
90 return listing->HandleDirectory(path->data) && 75 if (!listing->HandleDirectory(path->data)) {
91 (!recursive || ListRecursively(path->data, recursive, listing)); 76 return false;
77 }
Bill Hesse 2013/02/13 19:28:51 I just realized I should remove Add(path separator
78 if (!path->Add(File::PathSeparator())) {
79 PostError(listing, path->data);
80 return false;
81 }
82 return !recursive || ListRecursively(path, recursive, listing);
92 } 83 }
93 84
85
94 static bool HandleFile(char* file_name, 86 static bool HandleFile(char* file_name,
95 PathBuffer* path, 87 PathBuffer* path,
96 DirectoryListing *listing) { 88 DirectoryListing *listing) {
97 if (!path->Add(file_name)) { 89 if (!path->Add(file_name)) {
98 PostError(listing, path->data); 90 PostError(listing, path->data);
99 return false; 91 return false;
100 } 92 }
101 return listing->HandleFile(path->data); 93 return listing->HandleFile(path->data);
102 } 94 }
103 95
104 96
105 static bool ListRecursively(const char* dir_name, 97 static bool ListRecursively(PathBuffer* path,
106 bool recursive, 98 bool recursive,
107 DirectoryListing *listing) { 99 DirectoryListing *listing) {
108 DIR* dir_pointer; 100 DIR* dir_pointer;
109 do { 101 do {
110 dir_pointer = opendir(dir_name); 102 dir_pointer = opendir(path->data);
111 } while (dir_pointer == NULL && errno == EINTR); 103 } while (dir_pointer == NULL && errno == EINTR);
112 if (dir_pointer == NULL) { 104 if (dir_pointer == NULL) {
113 PostError(listing, dir_name); 105 PostError(listing, path->data);
114 return false; 106 return false;
115 } 107 }
116 108
117 // Compute full path for the directory currently being listed. The
118 // path buffer will be used to construct the current path in the
119 // recursive traversal. path_length does not always equal
120 // strlen(path) but indicates the current prefix of path that is the
121 // path of the current directory in the traversal.
122 PathBuffer* path = ComputeFullPath(dir_name);
123 if (path == NULL) {
124 PostError(listing, dir_name);
125 return false;
126 }
127 // Iterate the directory and post the directories and files to the 109 // Iterate the directory and post the directories and files to the
128 // ports. 110 // ports.
129 int path_length = path->length; 111 int path_length = path->length;
130 int status = 0; 112 int status = 0;
131 bool success = true; 113 bool success = true;
132 dirent entry; 114 dirent entry;
133 dirent* result; 115 dirent* result;
134 while ((status = TEMP_FAILURE_RETRY(readdir_r(dir_pointer, 116 while ((status = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
135 &entry, 117 &entry,
136 &result))) == 0 && 118 &result))) == 0 &&
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
180 } 162 }
181 default: 163 default:
182 break; 164 break;
183 } 165 }
184 path->Reset(path_length); 166 path->Reset(path_length);
185 } 167 }
186 168
187 if (status != 0) { 169 if (status != 0) {
188 errno = status; 170 errno = status;
189 success = false; 171 success = false;
190 PostError(listing, dir_name); 172 PostError(listing, path->data);
191 } 173 }
192 174
193 if (closedir(dir_pointer) == -1) { 175 if (closedir(dir_pointer) == -1) {
194 success = false; 176 success = false;
195 PostError(listing, dir_name); 177 PostError(listing, path->data);
196 } 178 }
197 delete path;
198 179
199 return success; 180 return success;
200 } 181 }
201 182
202 183
203 static bool DeleteFile(char* file_name, 184 static bool DeleteFile(char* file_name,
204 PathBuffer* path) { 185 PathBuffer* path) {
205 return path->Add(file_name) && remove(path->data) == 0; 186 return path->Add(file_name) && remove(path->data) == 0;
206 } 187 }
207 188
208 189
209 static bool DeleteDir(char* dir_name, 190 static bool DeleteDir(char* dir_name,
210 PathBuffer* path) { 191 PathBuffer* path) {
211 if (strcmp(dir_name, ".") == 0) return true; 192 if (strcmp(dir_name, ".") == 0) return true;
212 if (strcmp(dir_name, "..") == 0) return true; 193 if (strcmp(dir_name, "..") == 0) return true;
213 return path->Add(dir_name) && DeleteRecursively(path->data); 194 return path->Add(dir_name) &&
195 path->Add(File::PathSeparator()) &&
196 DeleteRecursively(path);
214 } 197 }
215 198
216 199
217 static bool DeleteRecursively(const char* dir_name) { 200 static bool DeleteRecursively(PathBuffer* path) {
218 // Do not recurse into links for deletion. Instead delete the link. 201 // Do not recurse into links for deletion. Instead delete the link.
219 struct stat st; 202 struct stat st;
220 if (TEMP_FAILURE_RETRY(lstat(dir_name, &st)) == -1) { 203 if (TEMP_FAILURE_RETRY(lstat(path->data, &st)) == -1) {
221 return false; 204 return false;
222 } else if (S_ISLNK(st.st_mode)) { 205 } else if (S_ISLNK(st.st_mode)) {
223 return (remove(dir_name) == 0); 206 return (remove(path->data) == 0);
224 } 207 }
225 208
226 // 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
227 // directory. 210 // directory.
228 DIR* dir_pointer; 211 DIR* dir_pointer;
229 do { 212 do {
230 dir_pointer = opendir(dir_name); 213 dir_pointer = opendir(path->data);
231 } while (dir_pointer == NULL && errno == EINTR); 214 } while (dir_pointer == NULL && errno == EINTR);
232 215
233 if (dir_pointer == NULL) { 216 if (dir_pointer == NULL) {
234 return false; 217 return false;
235 } 218 }
236 219
237 // Compute full path for the directory currently being deleted. The
238 // path buffer will be used to construct the current path in the
239 // recursive traversal.
240 PathBuffer* path = ComputeFullPath(dir_name);
241 if (path == NULL) return false;
242
243 // Iterate the directory and delete all files and directories. 220 // Iterate the directory and delete all files and directories.
244 int path_length = path->length; 221 int path_length = path->length;
245 int read = 0; 222 int read = 0;
246 bool success = true; 223 bool success = true;
247 dirent entry; 224 dirent entry;
248 dirent* result; 225 dirent* result;
249 while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer, 226 while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
250 &entry, 227 &entry,
251 &result))) == 0 && 228 &result))) == 0 &&
252 result != NULL && 229 result != NULL &&
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
285 // directory. 262 // directory.
286 success = success && DeleteFile(entry.d_name, path); 263 success = success && DeleteFile(entry.d_name, path);
287 } 264 }
288 break; 265 break;
289 } 266 }
290 default: 267 default:
291 break; 268 break;
292 } 269 }
293 path->Reset(path_length); 270 path->Reset(path_length);
294 } 271 }
295 delete path;
296 272
297 if ((read != 0) || 273 if ((read != 0) ||
298 (closedir(dir_pointer) == -1) || 274 (closedir(dir_pointer) == -1) ||
299 (remove(dir_name) == -1)) { 275 (remove(path->data) == -1)) {
300 return false; 276 return false;
301 } 277 }
302
303 return success; 278 return success;
304 } 279 }
305 280
306 281
307 bool Directory::List(const char* dir_name, 282 bool Directory::List(const char* dir_name,
308 bool recursive, 283 bool recursive,
309 DirectoryListing *listing) { 284 DirectoryListing *listing) {
310 bool completed = ListRecursively(dir_name, recursive, listing); 285 PathBuffer path;
311 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);
312 } 291 }
313 292
314 293
315 Directory::ExistsResult Directory::Exists(const char* dir_name) { 294 Directory::ExistsResult Directory::Exists(const char* dir_name) {
316 struct stat entry_info; 295 struct stat entry_info;
317 int success = TEMP_FAILURE_RETRY(stat(dir_name, &entry_info)); 296 int success = TEMP_FAILURE_RETRY(stat(dir_name, &entry_info));
318 if (success == 0) { 297 if (success == 0) {
319 if (S_ISDIR(entry_info.st_mode)) { 298 if (S_ISDIR(entry_info.st_mode)) {
320 return EXISTS; 299 return EXISTS;
321 } else { 300 } else {
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
356 } 335 }
357 return (result == 0); 336 return (result == 0);
358 } 337 }
359 338
360 339
361 char* Directory::CreateTemp(const char* const_template) { 340 char* Directory::CreateTemp(const char* const_template) {
362 // Returns a new, unused directory name, modifying the contents of 341 // Returns a new, unused directory name, modifying the contents of
363 // dir_template. Creates the directory with the permissions specified 342 // dir_template. Creates the directory with the permissions specified
364 // by the process umask. 343 // by the process umask.
365 // The return value must be freed by the caller. 344 // The return value must be freed by the caller.
366 PathBuffer* path = new PathBuffer(); 345 PathBuffer path;
367 path->Add(const_template); 346 path.Add(const_template);
368 if (path->length == 0) { 347 if (path.length == 0) {
369 path->Add("/tmp/temp_dir1_"); 348 path.Add("/tmp/temp_dir1_");
370 } else if ((path->data)[path->length - 1] == '/') { 349 } else if ((path.data)[path.length - 1] == '/') {
371 path->Add("temp_dir_"); 350 path.Add("temp_dir_");
372 } 351 }
373 if (!path->Add("XXXXXX")) { 352 if (!path.Add("XXXXXX")) {
374 // Pattern has overflowed. 353 // Pattern has overflowed.
375 delete path;
376 return NULL; 354 return NULL;
377 } 355 }
378 char* result; 356 char* result;
379 do { 357 do {
380 result = mkdtemp(path->data); 358 result = mkdtemp(path.data);
381 } while (result == NULL && errno == EINTR); 359 } while (result == NULL && errno == EINTR);
382 if (result == NULL) { 360 if (result == NULL) {
383 delete path;
384 return NULL; 361 return NULL;
385 } 362 }
386 int length = strnlen(path->data, PATH_MAX); 363 int length = strnlen(path.data, PATH_MAX);
387 result = static_cast<char*>(malloc(length + 1)); 364 result = static_cast<char*>(malloc(length + 1));
388 strncpy(result, path->data, length); 365 strncpy(result, path.data, length);
389 result[length] = '\0'; 366 result[length] = '\0';
390 delete path;
391 return result; 367 return result;
392 } 368 }
393 369
394 370
395 bool Directory::Delete(const char* dir_name, bool recursive) { 371 bool Directory::Delete(const char* dir_name, bool recursive) {
396 if (!recursive) { 372 if (!recursive) {
397 return (TEMP_FAILURE_RETRY(remove(dir_name)) == 0); 373 return (TEMP_FAILURE_RETRY(remove(dir_name)) == 0);
398 } else { 374 } else {
399 return DeleteRecursively(dir_name); 375 PathBuffer path;
376 if (!path.Add(dir_name) || !path.Add(File::PathSeparator())) {
377 return false;
378 }
379 return DeleteRecursively(&path);
400 } 380 }
401 } 381 }
402 382
403 383
404 bool Directory::Rename(const char* path, const char* new_path) { 384 bool Directory::Rename(const char* path, const char* new_path) {
405 ExistsResult exists = Exists(path); 385 ExistsResult exists = Exists(path);
406 if (exists != EXISTS) return false; 386 if (exists != EXISTS) return false;
407 return (TEMP_FAILURE_RETRY(rename(path, new_path)) == 0); 387 return (TEMP_FAILURE_RETRY(rename(path, new_path)) == 0);
408 } 388 }
OLDNEW
« no previous file with comments | « runtime/bin/directory_android.cc ('k') | runtime/bin/directory_macos.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698