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

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

Issue 165723007: Move signal_blocker to platform and use it by default in TEMP_FAILURE_RETRY. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Tiny fix. Created 6 years, 9 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 "platform/globals.h" 5 #include "platform/globals.h"
6 #if defined(TARGET_OS_LINUX) 6 #if defined(TARGET_OS_LINUX)
7 7
8 #include "bin/directory.h" 8 #include "bin/directory.h"
9 9
10 #include <dirent.h> // NOLINT 10 #include <dirent.h> // NOLINT
11 #include <errno.h> // NOLINT 11 #include <errno.h> // NOLINT
12 #include <stdlib.h> // NOLINT 12 #include <stdlib.h> // NOLINT
13 #include <string.h> // NOLINT 13 #include <string.h> // NOLINT
14 #include <sys/param.h> // NOLINT 14 #include <sys/param.h> // NOLINT
15 #include <sys/stat.h> // NOLINT 15 #include <sys/stat.h> // NOLINT
16 #include <unistd.h> // NOLINT 16 #include <unistd.h> // NOLINT
17 17
18 #include "platform/signal_blocker.h"
18 #include "bin/file.h" 19 #include "bin/file.h"
19 #include "bin/platform.h" 20 #include "bin/platform.h"
20 21
21 22
22 namespace dart { 23 namespace dart {
23 namespace bin { 24 namespace bin {
24 25
25 26
26 PathBuffer::PathBuffer() : length_(0) { 27 PathBuffer::PathBuffer() : length_(0) {
27 data_ = calloc(PATH_MAX + 1, sizeof(char)); // NOLINT 28 data_ = calloc(PATH_MAX + 1, sizeof(char)); // NOLINT
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
98 } 99 }
99 // Reset. 100 // Reset.
100 listing->path_buffer().Reset(path_length_); 101 listing->path_buffer().Reset(path_length_);
101 ResetLink(); 102 ResetLink();
102 103
103 // Iterate the directory and post the directories and files to the 104 // Iterate the directory and post the directories and files to the
104 // ports. 105 // ports.
105 int status = 0; 106 int status = 0;
106 dirent entry; 107 dirent entry;
107 dirent* result; 108 dirent* result;
108 if ((status = TEMP_FAILURE_RETRY(readdir_r(reinterpret_cast<DIR*>(lister_), 109 if ((status = NO_RETRY_EXPECTED(readdir_r(reinterpret_cast<DIR*>(lister_),
109 &entry, 110 &entry,
110 &result))) == 0 && 111 &result))) == 0 &&
111 result != NULL) { 112 result != NULL) {
112 if (!listing->path_buffer().Add(entry.d_name)) { 113 if (!listing->path_buffer().Add(entry.d_name)) {
113 done_ = true; 114 done_ = true;
114 return kListError; 115 return kListError;
115 } 116 }
116 switch (entry.d_type) { 117 switch (entry.d_type) {
117 case DT_DIR: 118 case DT_DIR:
118 if (strcmp(entry.d_name, ".") == 0) return Next(listing); 119 if (strcmp(entry.d_name, ".") == 0) return Next(listing);
119 if (strcmp(entry.d_name, "..") == 0) return Next(listing); 120 if (strcmp(entry.d_name, "..") == 0) return Next(listing);
120 return kListDirectory; 121 return kListDirectory;
121 case DT_REG: 122 case DT_REG:
122 return kListFile; 123 return kListFile;
123 case DT_LNK: 124 case DT_LNK:
124 if (!listing->follow_links()) { 125 if (!listing->follow_links()) {
125 return kListLink; 126 return kListLink;
126 } 127 }
127 // Else fall through to next case. 128 // Else fall through to next case.
128 // Fall through. 129 // Fall through.
129 case DT_UNKNOWN: { 130 case DT_UNKNOWN: {
130 // On some file systems the entry type is not determined by 131 // On some file systems the entry type is not determined by
131 // readdir_r. For those and for links we use stat to determine 132 // readdir_r. For those and for links we use stat to determine
132 // the actual entry type. Notice that stat returns the type of 133 // the actual entry type. Notice that stat returns the type of
133 // the file pointed to. 134 // the file pointed to.
134 struct stat64 entry_info; 135 struct stat64 entry_info;
135 int stat_success; 136 int stat_success;
136 stat_success = TEMP_FAILURE_RETRY( 137 stat_success = NO_RETRY_EXPECTED(
137 lstat64(listing->path_buffer().AsString(), &entry_info)); 138 lstat64(listing->path_buffer().AsString(), &entry_info));
138 if (stat_success == -1) { 139 if (stat_success == -1) {
139 return kListError; 140 return kListError;
140 } 141 }
141 if (listing->follow_links() && S_ISLNK(entry_info.st_mode)) { 142 if (listing->follow_links() && S_ISLNK(entry_info.st_mode)) {
142 // Check to see if we are in a loop created by a symbolic link. 143 // Check to see if we are in a loop created by a symbolic link.
143 LinkList current_link = { entry_info.st_dev, 144 LinkList current_link = { entry_info.st_dev,
144 entry_info.st_ino, 145 entry_info.st_ino,
145 link_ }; 146 link_ };
146 LinkList* previous = link_; 147 LinkList* previous = link_;
147 while (previous != NULL) { 148 while (previous != NULL) {
148 if (previous->dev == current_link.dev && 149 if (previous->dev == current_link.dev &&
149 previous->ino == current_link.ino) { 150 previous->ino == current_link.ino) {
150 // Report the looping link as a link, rather than following it. 151 // Report the looping link as a link, rather than following it.
151 return kListLink; 152 return kListLink;
152 } 153 }
153 previous = previous->next; 154 previous = previous->next;
154 } 155 }
155 stat_success = TEMP_FAILURE_RETRY( 156 stat_success = NO_RETRY_EXPECTED(
156 stat64(listing->path_buffer().AsString(), &entry_info)); 157 stat64(listing->path_buffer().AsString(), &entry_info));
157 if (stat_success == -1) { 158 if (stat_success == -1) {
158 // Report a broken link as a link, even if follow_links is true. 159 // Report a broken link as a link, even if follow_links is true.
159 return kListLink; 160 return kListLink;
160 } 161 }
161 if (S_ISDIR(entry_info.st_mode)) { 162 if (S_ISDIR(entry_info.st_mode)) {
162 // Recurse into the subdirectory with current_link added to the 163 // Recurse into the subdirectory with current_link added to the
163 // linked list of seen file system links. 164 // linked list of seen file system links.
164 link_ = new LinkList(current_link); 165 link_ = new LinkList(current_link);
165 if (strcmp(entry.d_name, ".") == 0) return Next(listing); 166 if (strcmp(entry.d_name, ".") == 0) return Next(listing);
(...skipping 23 matching lines...) Expand all
189 return kListError; 190 return kListError;
190 } 191 }
191 192
192 return kListDone; 193 return kListDone;
193 } 194 }
194 195
195 196
196 DirectoryListingEntry::~DirectoryListingEntry() { 197 DirectoryListingEntry::~DirectoryListingEntry() {
197 ResetLink(); 198 ResetLink();
198 if (lister_ != 0) { 199 if (lister_ != 0) {
199 closedir(reinterpret_cast<DIR*>(lister_)); 200 VOID_NO_RETRY_EXPECTED(closedir(reinterpret_cast<DIR*>(lister_)));
200 } 201 }
201 } 202 }
202 203
203 204
204 void DirectoryListingEntry::ResetLink() { 205 void DirectoryListingEntry::ResetLink() {
205 if (link_ != NULL && (parent_ == NULL || parent_->link_ != link_)) { 206 if (link_ != NULL && (parent_ == NULL || parent_->link_ != link_)) {
206 delete link_; 207 delete link_;
207 link_ = NULL; 208 link_ = NULL;
208 } 209 }
209 if (parent_ != NULL) { 210 if (parent_ != NULL) {
210 link_ = parent_->link_; 211 link_ = parent_->link_;
211 } 212 }
212 } 213 }
213 214
214 215
215 static bool DeleteRecursively(PathBuffer* path); 216 static bool DeleteRecursively(PathBuffer* path);
216 217
217 218
218 static bool DeleteFile(char* file_name, 219 static bool DeleteFile(char* file_name,
219 PathBuffer* path) { 220 PathBuffer* path) {
220 return path->Add(file_name) && unlink(path->AsString()) == 0; 221 return path->Add(file_name) &&
222 NO_RETRY_EXPECTED(unlink(path->AsString())) == 0;
221 } 223 }
222 224
223 225
224 static bool DeleteDir(char* dir_name, 226 static bool DeleteDir(char* dir_name,
225 PathBuffer* path) { 227 PathBuffer* path) {
226 if (strcmp(dir_name, ".") == 0) return true; 228 if (strcmp(dir_name, ".") == 0) return true;
227 if (strcmp(dir_name, "..") == 0) return true; 229 if (strcmp(dir_name, "..") == 0) return true;
228 return path->Add(dir_name) && DeleteRecursively(path); 230 return path->Add(dir_name) && DeleteRecursively(path);
229 } 231 }
230 232
231 233
232 static bool DeleteRecursively(PathBuffer* path) { 234 static bool DeleteRecursively(PathBuffer* path) {
233 // Do not recurse into links for deletion. Instead delete the link. 235 // Do not recurse into links for deletion. Instead delete the link.
234 // If it's a file, delete it. 236 // If it's a file, delete it.
235 struct stat64 st; 237 struct stat64 st;
236 if (TEMP_FAILURE_RETRY(lstat64(path->AsString(), &st)) == -1) { 238 if (NO_RETRY_EXPECTED(lstat64(path->AsString(), &st)) == -1) {
237 return false; 239 return false;
238 } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) { 240 } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
239 return (unlink(path->AsString()) == 0); 241 return (NO_RETRY_EXPECTED(unlink(path->AsString())) == 0);
240 } 242 }
241 243
242 if (!path->Add(File::PathSeparator())) return false; 244 if (!path->Add(File::PathSeparator())) return false;
243 245
244 // Not a link. Attempt to open as a directory and recurse into the 246 // Not a link. Attempt to open as a directory and recurse into the
245 // directory. 247 // directory.
246 DIR* dir_pointer; 248 DIR* dir_pointer;
247 do { 249 do {
248 dir_pointer = opendir(path->AsString()); 250 dir_pointer = opendir(path->AsString());
249 } while (dir_pointer == NULL && errno == EINTR); 251 } while (dir_pointer == NULL && errno == EINTR);
250 252
251 if (dir_pointer == NULL) { 253 if (dir_pointer == NULL) {
252 return false; 254 return false;
253 } 255 }
254 256
255 // Iterate the directory and delete all files and directories. 257 // Iterate the directory and delete all files and directories.
256 int path_length = path->length(); 258 int path_length = path->length();
257 int read = 0; 259 int read = 0;
258 bool success = true; 260 bool success = true;
259 dirent entry; 261 dirent entry;
260 dirent* result; 262 dirent* result;
261 while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer, 263 while ((read = NO_RETRY_EXPECTED(
262 &entry, 264 readdir_r(dir_pointer, &entry, &result))) == 0 &&
263 &result))) == 0 && 265 result != NULL &&
264 result != NULL && 266 success) {
265 success) {
266 switch (entry.d_type) { 267 switch (entry.d_type) {
267 case DT_DIR: 268 case DT_DIR:
268 success = success && DeleteDir(entry.d_name, path); 269 success = success && DeleteDir(entry.d_name, path);
269 break; 270 break;
270 case DT_REG: 271 case DT_REG:
271 case DT_LNK: 272 case DT_LNK:
272 // Treat all links as files. This will delete the link which 273 // Treat all links as files. This will delete the link which
273 // is what we want no matter if the link target is a file or a 274 // is what we want no matter if the link target is a file or a
274 // directory. 275 // directory.
275 success = success && DeleteFile(entry.d_name, path); 276 success = success && DeleteFile(entry.d_name, path);
276 break; 277 break;
277 case DT_UNKNOWN: { 278 case DT_UNKNOWN: {
278 if (!path->Add(entry.d_name)) { 279 if (!path->Add(entry.d_name)) {
279 success = false; 280 success = false;
280 break; 281 break;
281 } 282 }
282 // On some file systems the entry type is not determined by 283 // On some file systems the entry type is not determined by
283 // readdir_r. For those we use lstat to determine the entry 284 // readdir_r. For those we use lstat to determine the entry
284 // type. 285 // type.
285 struct stat64 entry_info; 286 struct stat64 entry_info;
286 int lstat_success = TEMP_FAILURE_RETRY( 287 int lstat_success = NO_RETRY_EXPECTED(
287 lstat64(path->AsString(), &entry_info)); 288 lstat64(path->AsString(), &entry_info));
288 if (lstat_success == -1) { 289 if (lstat_success == -1) {
289 success = false; 290 success = false;
290 break; 291 break;
291 } 292 }
292 path->Reset(path_length); 293 path->Reset(path_length);
293 if (S_ISDIR(entry_info.st_mode)) { 294 if (S_ISDIR(entry_info.st_mode)) {
294 success = success && DeleteDir(entry.d_name, path); 295 success = success && DeleteDir(entry.d_name, path);
295 } else if (S_ISREG(entry_info.st_mode) || S_ISLNK(entry_info.st_mode)) { 296 } else if (S_ISREG(entry_info.st_mode) || S_ISLNK(entry_info.st_mode)) {
296 // Treat links as files. This will delete the link which is 297 // Treat links as files. This will delete the link which is
297 // what we want no matter if the link target is a file or a 298 // what we want no matter if the link target is a file or a
298 // directory. 299 // directory.
299 success = success && DeleteFile(entry.d_name, path); 300 success = success && DeleteFile(entry.d_name, path);
300 } 301 }
301 break; 302 break;
302 } 303 }
303 default: 304 default:
304 break; 305 break;
305 } 306 }
306 path->Reset(path_length); 307 path->Reset(path_length);
307 } 308 }
308 309
309 if ((read != 0) || 310 if ((read != 0) ||
310 (closedir(dir_pointer) == -1) || 311 (NO_RETRY_EXPECTED(closedir(dir_pointer)) == -1) ||
311 (remove(path->AsString()) == -1)) { 312 (NO_RETRY_EXPECTED(remove(path->AsString())) == -1)) {
312 return false; 313 return false;
313 } 314 }
314 return success; 315 return success;
315 } 316 }
316 317
317 318
318 Directory::ExistsResult Directory::Exists(const char* dir_name) { 319 Directory::ExistsResult Directory::Exists(const char* dir_name) {
319 struct stat64 entry_info; 320 struct stat64 entry_info;
320 int success = TEMP_FAILURE_RETRY(stat64(dir_name, &entry_info)); 321 int success = NO_RETRY_EXPECTED(stat64(dir_name, &entry_info));
321 if (success == 0) { 322 if (success == 0) {
322 if (S_ISDIR(entry_info.st_mode)) { 323 if (S_ISDIR(entry_info.st_mode)) {
323 return EXISTS; 324 return EXISTS;
324 } else { 325 } else {
325 return DOES_NOT_EXIST; 326 return DOES_NOT_EXIST;
326 } 327 }
327 } else { 328 } else {
328 if (errno == EACCES || 329 if (errno == EACCES ||
329 errno == EBADF || 330 errno == EBADF ||
330 errno == EFAULT || 331 errno == EFAULT ||
(...skipping 23 matching lines...) Expand all
354 result = getcwd(buffer, size); 355 result = getcwd(buffer, size);
355 if (result == NULL && errno != ERANGE) { 356 if (result == NULL && errno != ERANGE) {
356 return NULL; 357 return NULL;
357 } 358 }
358 } 359 }
359 return buffer; 360 return buffer;
360 } 361 }
361 362
362 363
363 bool Directory::SetCurrent(const char* path) { 364 bool Directory::SetCurrent(const char* path) {
364 int result = TEMP_FAILURE_RETRY(chdir(path)); 365 return NO_RETRY_EXPECTED(chdir(path)) == 0;
365 return result == 0;
366 } 366 }
367 367
368 368
369 bool Directory::Create(const char* dir_name) { 369 bool Directory::Create(const char* dir_name) {
370 // Create the directory with the permissions specified by the 370 // Create the directory with the permissions specified by the
371 // process umask. 371 // process umask.
372 int result = TEMP_FAILURE_RETRY(mkdir(dir_name, 0777)); 372 int result = NO_RETRY_EXPECTED(mkdir(dir_name, 0777));
373 // If the directory already exists, treat it as a success. 373 // If the directory already exists, treat it as a success.
374 if (result == -1 && errno == EEXIST) { 374 if (result == -1 && errno == EEXIST) {
375 return (Exists(dir_name) == EXISTS); 375 return (Exists(dir_name) == EXISTS);
376 } 376 }
377 return (result == 0); 377 return (result == 0);
378 } 378 }
379 379
380 380
381 char* Directory::SystemTemp() { 381 char* Directory::SystemTemp() {
382 const char* temp_dir = getenv("TMPDIR"); 382 const char* temp_dir = getenv("TMPDIR");
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
415 return NULL; 415 return NULL;
416 } 416 }
417 return strdup(result); 417 return strdup(result);
418 } 418 }
419 419
420 420
421 bool Directory::Delete(const char* dir_name, bool recursive) { 421 bool Directory::Delete(const char* dir_name, bool recursive) {
422 if (!recursive) { 422 if (!recursive) {
423 if (File::GetType(dir_name, false) == File::kIsLink && 423 if (File::GetType(dir_name, false) == File::kIsLink &&
424 File::GetType(dir_name, true) == File::kIsDirectory) { 424 File::GetType(dir_name, true) == File::kIsDirectory) {
425 return (TEMP_FAILURE_RETRY(unlink(dir_name)) == 0); 425 return NO_RETRY_EXPECTED(unlink(dir_name)) == 0;
426 } 426 }
427 return (TEMP_FAILURE_RETRY(rmdir(dir_name)) == 0); 427 return NO_RETRY_EXPECTED(rmdir(dir_name)) == 0;
428 } else { 428 } else {
429 PathBuffer path; 429 PathBuffer path;
430 if (!path.Add(dir_name)) { 430 if (!path.Add(dir_name)) {
431 return false; 431 return false;
432 } 432 }
433 return DeleteRecursively(&path); 433 return DeleteRecursively(&path);
434 } 434 }
435 } 435 }
436 436
437 437
438 bool Directory::Rename(const char* path, const char* new_path) { 438 bool Directory::Rename(const char* path, const char* new_path) {
439 ExistsResult exists = Exists(path); 439 ExistsResult exists = Exists(path);
440 if (exists != EXISTS) return false; 440 if (exists != EXISTS) return false;
441 return (TEMP_FAILURE_RETRY(rename(path, new_path)) == 0); 441 return NO_RETRY_EXPECTED(rename(path, new_path)) == 0;
442 } 442 }
443 443
444 } // namespace bin 444 } // namespace bin
445 } // namespace dart 445 } // namespace dart
446 446
447 #endif // defined(TARGET_OS_LINUX) 447 #endif // defined(TARGET_OS_LINUX)
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