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

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: 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 | « 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 return listing->HandleDirectory(path->data) &&
91 (!recursive || ListRecursively(path->data, recursive, listing)); 76 (!recursive || ListRecursively(path, recursive, listing));
92 } 77 }
93 78
79
94 static bool HandleFile(char* file_name, 80 static bool HandleFile(char* file_name,
95 PathBuffer* path, 81 PathBuffer* path,
96 DirectoryListing *listing) { 82 DirectoryListing *listing) {
97 if (!path->Add(file_name)) { 83 if (!path->Add(file_name)) {
98 PostError(listing, path->data); 84 PostError(listing, path->data);
99 return false; 85 return false;
100 } 86 }
101 return listing->HandleFile(path->data); 87 return listing->HandleFile(path->data);
102 } 88 }
103 89
104 90
105 static bool ListRecursively(const char* dir_name, 91 static bool ListRecursively(PathBuffer* path,
106 bool recursive, 92 bool recursive,
107 DirectoryListing *listing) { 93 DirectoryListing *listing) {
94 if (!path->Add(File::PathSeparator())) {
95 PostError(listing, path->data);
96 return false;
97 }
108 DIR* dir_pointer; 98 DIR* dir_pointer;
109 do { 99 do {
110 dir_pointer = opendir(dir_name); 100 dir_pointer = opendir(path->data);
111 } while (dir_pointer == NULL && errno == EINTR); 101 } while (dir_pointer == NULL && errno == EINTR);
112 if (dir_pointer == NULL) { 102 if (dir_pointer == NULL) {
113 PostError(listing, dir_name); 103 PostError(listing, path->data);
114 return false; 104 return false;
115 } 105 }
116 106
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 107 // Iterate the directory and post the directories and files to the
128 // ports. 108 // ports.
129 int path_length = path->length; 109 int path_length = path->length;
130 int status = 0; 110 int status = 0;
131 bool success = true; 111 bool success = true;
132 dirent entry; 112 dirent entry;
133 dirent* result; 113 dirent* result;
134 while ((status = TEMP_FAILURE_RETRY(readdir_r(dir_pointer, 114 while ((status = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
135 &entry, 115 &entry,
136 &result))) == 0 && 116 &result))) == 0 &&
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
180 } 160 }
181 default: 161 default:
182 break; 162 break;
183 } 163 }
184 path->Reset(path_length); 164 path->Reset(path_length);
185 } 165 }
186 166
187 if (status != 0) { 167 if (status != 0) {
188 errno = status; 168 errno = status;
189 success = false; 169 success = false;
190 PostError(listing, dir_name); 170 PostError(listing, path->data);
191 } 171 }
192 172
193 if (closedir(dir_pointer) == -1) { 173 if (closedir(dir_pointer) == -1) {
194 success = false; 174 success = false;
195 PostError(listing, dir_name); 175 PostError(listing, path->data);
196 } 176 }
197 delete path;
198 177
199 return success; 178 return success;
200 } 179 }
201 180
202 181
203 static bool DeleteFile(char* file_name, 182 static bool DeleteFile(char* file_name,
204 PathBuffer* path) { 183 PathBuffer* path) {
205 return path->Add(file_name) && remove(path->data) == 0; 184 return path->Add(file_name) && remove(path->data) == 0;
206 } 185 }
207 186
208 187
209 static bool DeleteDir(char* dir_name, 188 static bool DeleteDir(char* dir_name,
210 PathBuffer* path) { 189 PathBuffer* path) {
211 if (strcmp(dir_name, ".") == 0) return true; 190 if (strcmp(dir_name, ".") == 0) return true;
212 if (strcmp(dir_name, "..") == 0) return true; 191 if (strcmp(dir_name, "..") == 0) return true;
213 return path->Add(dir_name) && DeleteRecursively(path->data); 192 return path->Add(dir_name) && DeleteRecursively(path);
214 } 193 }
215 194
216 195
217 static bool DeleteRecursively(const char* dir_name) { 196 static bool DeleteRecursively(PathBuffer* path) {
197 if (!path->Add(File::PathSeparator())) return false;
218 // Do not recurse into links for deletion. Instead delete the link. 198 // Do not recurse into links for deletion. Instead delete the link.
219 struct stat st; 199 struct stat st;
220 if (TEMP_FAILURE_RETRY(lstat(dir_name, &st)) == -1) { 200 if (TEMP_FAILURE_RETRY(lstat(path->data, &st)) == -1) {
221 return false; 201 return false;
222 } else if (S_ISLNK(st.st_mode)) { 202 } else if (S_ISLNK(st.st_mode)) {
223 return (remove(dir_name) == 0); 203 return (remove(path->data) == 0);
224 } 204 }
225 205
226 // Not a link. Attempt to open as a directory and recurse into the 206 // Not a link. Attempt to open as a directory and recurse into the
227 // directory. 207 // directory.
228 DIR* dir_pointer; 208 DIR* dir_pointer;
229 do { 209 do {
230 dir_pointer = opendir(dir_name); 210 dir_pointer = opendir(path->data);
231 } while (dir_pointer == NULL && errno == EINTR); 211 } while (dir_pointer == NULL && errno == EINTR);
232 212
233 if (dir_pointer == NULL) { 213 if (dir_pointer == NULL) {
234 return false; 214 return false;
235 } 215 }
236 216
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. 217 // Iterate the directory and delete all files and directories.
244 int path_length = path->length; 218 int path_length = path->length;
245 int read = 0; 219 int read = 0;
246 bool success = true; 220 bool success = true;
247 dirent entry; 221 dirent entry;
248 dirent* result; 222 dirent* result;
249 while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer, 223 while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
250 &entry, 224 &entry,
251 &result))) == 0 && 225 &result))) == 0 &&
252 result != NULL && 226 result != NULL &&
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
285 // directory. 259 // directory.
286 success = success && DeleteFile(entry.d_name, path); 260 success = success && DeleteFile(entry.d_name, path);
287 } 261 }
288 break; 262 break;
289 } 263 }
290 default: 264 default:
291 break; 265 break;
292 } 266 }
293 path->Reset(path_length); 267 path->Reset(path_length);
294 } 268 }
295 delete path;
296 269
297 if ((read != 0) || 270 if ((read != 0) ||
298 (closedir(dir_pointer) == -1) || 271 (closedir(dir_pointer) == -1) ||
299 (remove(dir_name) == -1)) { 272 (remove(path->data) == -1)) {
300 return false; 273 return false;
301 } 274 }
302
303 return success; 275 return success;
304 } 276 }
305 277
306 278
307 bool Directory::List(const char* dir_name, 279 bool Directory::List(const char* dir_name,
308 bool recursive, 280 bool recursive,
309 DirectoryListing *listing) { 281 DirectoryListing *listing) {
310 bool completed = ListRecursively(dir_name, recursive, listing); 282 PathBuffer path;
311 return completed; 283 if (!path.Add(dir_name)) {
284 PostError(listing, dir_name);
285 return false;
286 }
287 return ListRecursively(&path, recursive, listing);
312 } 288 }
313 289
314 290
315 Directory::ExistsResult Directory::Exists(const char* dir_name) { 291 Directory::ExistsResult Directory::Exists(const char* dir_name) {
316 struct stat entry_info; 292 struct stat entry_info;
317 int success = TEMP_FAILURE_RETRY(stat(dir_name, &entry_info)); 293 int success = TEMP_FAILURE_RETRY(stat(dir_name, &entry_info));
318 if (success == 0) { 294 if (success == 0) {
319 if (S_ISDIR(entry_info.st_mode)) { 295 if (S_ISDIR(entry_info.st_mode)) {
320 return EXISTS; 296 return EXISTS;
321 } else { 297 } else {
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
356 } 332 }
357 return (result == 0); 333 return (result == 0);
358 } 334 }
359 335
360 336
361 char* Directory::CreateTemp(const char* const_template) { 337 char* Directory::CreateTemp(const char* const_template) {
362 // Returns a new, unused directory name, modifying the contents of 338 // Returns a new, unused directory name, modifying the contents of
363 // dir_template. Creates the directory with the permissions specified 339 // dir_template. Creates the directory with the permissions specified
364 // by the process umask. 340 // by the process umask.
365 // The return value must be freed by the caller. 341 // The return value must be freed by the caller.
366 PathBuffer* path = new PathBuffer(); 342 PathBuffer path;
367 path->Add(const_template); 343 path.Add(const_template);
368 if (path->length == 0) { 344 if (path.length == 0) {
369 path->Add("/tmp/temp_dir1_"); 345 path.Add("/tmp/temp_dir1_");
370 } else if ((path->data)[path->length - 1] == '/') { 346 } else if ((path.data)[path.length - 1] == '/') {
371 path->Add("temp_dir_"); 347 path.Add("temp_dir_");
372 } 348 }
373 if (!path->Add("XXXXXX")) { 349 if (!path.Add("XXXXXX")) {
374 // Pattern has overflowed. 350 // Pattern has overflowed.
375 delete path;
376 return NULL; 351 return NULL;
377 } 352 }
378 char* result; 353 char* result;
379 do { 354 do {
380 result = mkdtemp(path->data); 355 result = mkdtemp(path.data);
381 } while (result == NULL && errno == EINTR); 356 } while (result == NULL && errno == EINTR);
382 if (result == NULL) { 357 if (result == NULL) {
383 delete path;
384 return NULL; 358 return NULL;
385 } 359 }
386 int length = strnlen(path->data, PATH_MAX); 360 int length = strnlen(path.data, PATH_MAX);
387 result = static_cast<char*>(malloc(length + 1)); 361 result = static_cast<char*>(malloc(length + 1));
388 strncpy(result, path->data, length); 362 strncpy(result, path.data, length);
389 result[length] = '\0'; 363 result[length] = '\0';
390 delete path;
391 return result; 364 return result;
392 } 365 }
393 366
394 367
395 bool Directory::Delete(const char* dir_name, bool recursive) { 368 bool Directory::Delete(const char* dir_name, bool recursive) {
396 if (!recursive) { 369 if (!recursive) {
397 return (TEMP_FAILURE_RETRY(remove(dir_name)) == 0); 370 return (TEMP_FAILURE_RETRY(remove(dir_name)) == 0);
398 } else { 371 } else {
399 return DeleteRecursively(dir_name); 372 PathBuffer path;
373 if (!path.Add(dir_name)) {
374 return false;
375 }
376 return DeleteRecursively(&path);
400 } 377 }
401 } 378 }
402 379
403 380
404 bool Directory::Rename(const char* path, const char* new_path) { 381 bool Directory::Rename(const char* path, const char* new_path) {
405 ExistsResult exists = Exists(path); 382 ExistsResult exists = Exists(path);
406 if (exists != EXISTS) return false; 383 if (exists != EXISTS) return false;
407 return (TEMP_FAILURE_RETRY(rename(path, new_path)) == 0); 384 return (TEMP_FAILURE_RETRY(rename(path, new_path)) == 0);
408 } 385 }
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