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

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

Powered by Google App Engine
This is Rietveld 408576698