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

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

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

Powered by Google App Engine
This is Rietveld 408576698