| OLD | NEW |
| 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 "bin/dartutils.h" | 18 #include "bin/dartutils.h" |
| 19 #include "bin/file.h" | 19 #include "bin/file.h" |
| 20 #include "bin/platform.h" | 20 #include "bin/platform.h" |
| 21 #include "platform/signal_blocker.h" | 21 #include "platform/signal_blocker.h" |
| 22 | 22 |
| 23 namespace dart { | 23 namespace dart { |
| 24 namespace bin { | 24 namespace bin { |
| 25 | 25 |
| 26 PathBuffer::PathBuffer() : length_(0) { | 26 PathBuffer::PathBuffer() : length_(0) { |
| (...skipping 23 matching lines...) Expand all Loading... |
| 50 } | 50 } |
| 51 | 51 |
| 52 | 52 |
| 53 const char* PathBuffer::AsScopedString() const { | 53 const char* PathBuffer::AsScopedString() const { |
| 54 return DartUtils::ScopedCopyCString(AsString()); | 54 return DartUtils::ScopedCopyCString(AsString()); |
| 55 } | 55 } |
| 56 | 56 |
| 57 | 57 |
| 58 bool PathBuffer::Add(const char* name) { | 58 bool PathBuffer::Add(const char* name) { |
| 59 char* data = AsString(); | 59 char* data = AsString(); |
| 60 int written = snprintf(data + length_, | 60 int written = snprintf(data + length_, PATH_MAX - length_, "%s", name); |
| 61 PATH_MAX - length_, | |
| 62 "%s", | |
| 63 name); | |
| 64 data[PATH_MAX] = '\0'; | 61 data[PATH_MAX] = '\0'; |
| 65 if ((written <= PATH_MAX - length_) && | 62 if ((written <= PATH_MAX - length_) && (written >= 0) && |
| 66 (written >= 0) && | |
| 67 (static_cast<size_t>(written) == strnlen(name, PATH_MAX + 1))) { | 63 (static_cast<size_t>(written) == strnlen(name, PATH_MAX + 1))) { |
| 68 length_ += written; | 64 length_ += written; |
| 69 return true; | 65 return true; |
| 70 } else { | 66 } else { |
| 71 errno = ENAMETOOLONG; | 67 errno = ENAMETOOLONG; |
| 72 return false; | 68 return false; |
| 73 } | 69 } |
| 74 } | 70 } |
| 75 | 71 |
| 76 | 72 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 130 (strcmp(entry->d_name, "..") == 0)) { | 126 (strcmp(entry->d_name, "..") == 0)) { |
| 131 return Next(listing); | 127 return Next(listing); |
| 132 } | 128 } |
| 133 return kListDirectory; | 129 return kListDirectory; |
| 134 case DT_REG: | 130 case DT_REG: |
| 135 return kListFile; | 131 return kListFile; |
| 136 case DT_LNK: | 132 case DT_LNK: |
| 137 if (!listing->follow_links()) { | 133 if (!listing->follow_links()) { |
| 138 return kListLink; | 134 return kListLink; |
| 139 } | 135 } |
| 140 // Else fall through to next case. | 136 // Else fall through to next case. |
| 141 // Fall through. | 137 // Fall through. |
| 142 case DT_UNKNOWN: { | 138 case DT_UNKNOWN: { |
| 143 // On some file systems the entry type is not determined by | 139 // On some file systems the entry type is not determined by |
| 144 // readdir. For those and for links we use stat to determine | 140 // readdir. For those and for links we use stat to determine |
| 145 // the actual entry type. Notice that stat returns the type of | 141 // the actual entry type. Notice that stat returns the type of |
| 146 // the file pointed to. | 142 // the file pointed to. |
| 147 struct stat64 entry_info; | 143 struct stat64 entry_info; |
| 148 int stat_success; | 144 int stat_success; |
| 149 stat_success = TEMP_FAILURE_RETRY( | 145 stat_success = TEMP_FAILURE_RETRY( |
| 150 lstat64(listing->path_buffer().AsString(), &entry_info)); | 146 lstat64(listing->path_buffer().AsString(), &entry_info)); |
| 151 if (stat_success == -1) { | 147 if (stat_success == -1) { |
| 152 return kListError; | 148 return kListError; |
| 153 } | 149 } |
| 154 if (listing->follow_links() && S_ISLNK(entry_info.st_mode)) { | 150 if (listing->follow_links() && S_ISLNK(entry_info.st_mode)) { |
| 155 // Check to see if we are in a loop created by a symbolic link. | 151 // Check to see if we are in a loop created by a symbolic link. |
| 156 LinkList current_link = { entry_info.st_dev, | 152 LinkList current_link = {entry_info.st_dev, entry_info.st_ino, link_}; |
| 157 entry_info.st_ino, | |
| 158 link_ }; | |
| 159 LinkList* previous = link_; | 153 LinkList* previous = link_; |
| 160 while (previous != NULL) { | 154 while (previous != NULL) { |
| 161 if ((previous->dev == current_link.dev) && | 155 if ((previous->dev == current_link.dev) && |
| 162 (previous->ino == current_link.ino)) { | 156 (previous->ino == current_link.ino)) { |
| 163 // Report the looping link as a link, rather than following it. | 157 // Report the looping link as a link, rather than following it. |
| 164 return kListLink; | 158 return kListLink; |
| 165 } | 159 } |
| 166 previous = previous->next; | 160 previous = previous->next; |
| 167 } | 161 } |
| 168 stat_success = TEMP_FAILURE_RETRY( | 162 stat_success = TEMP_FAILURE_RETRY( |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 224 } | 218 } |
| 225 if (parent_ != NULL) { | 219 if (parent_ != NULL) { |
| 226 link_ = parent_->link_; | 220 link_ = parent_->link_; |
| 227 } | 221 } |
| 228 } | 222 } |
| 229 | 223 |
| 230 | 224 |
| 231 static bool DeleteRecursively(PathBuffer* path); | 225 static bool DeleteRecursively(PathBuffer* path); |
| 232 | 226 |
| 233 | 227 |
| 234 static bool DeleteFile(char* file_name, | 228 static bool DeleteFile(char* file_name, PathBuffer* path) { |
| 235 PathBuffer* path) { | |
| 236 return path->Add(file_name) && | 229 return path->Add(file_name) && |
| 237 (NO_RETRY_EXPECTED(unlink(path->AsString())) == 0); | 230 (NO_RETRY_EXPECTED(unlink(path->AsString())) == 0); |
| 238 } | 231 } |
| 239 | 232 |
| 240 | 233 |
| 241 static bool DeleteDir(char* dir_name, | 234 static bool DeleteDir(char* dir_name, PathBuffer* path) { |
| 242 PathBuffer* path) { | |
| 243 if ((strcmp(dir_name, ".") == 0) || (strcmp(dir_name, "..") == 0)) { | 235 if ((strcmp(dir_name, ".") == 0) || (strcmp(dir_name, "..") == 0)) { |
| 244 return true; | 236 return true; |
| 245 } | 237 } |
| 246 return path->Add(dir_name) && DeleteRecursively(path); | 238 return path->Add(dir_name) && DeleteRecursively(path); |
| 247 } | 239 } |
| 248 | 240 |
| 249 | 241 |
| 250 static bool DeleteRecursively(PathBuffer* path) { | 242 static bool DeleteRecursively(PathBuffer* path) { |
| 251 // Do not recurse into links for deletion. Instead delete the link. | 243 // Do not recurse into links for deletion. Instead delete the link. |
| 252 // If it's a file, delete it. | 244 // If it's a file, delete it. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 266 DIR* dir_pointer; | 258 DIR* dir_pointer; |
| 267 do { | 259 do { |
| 268 dir_pointer = opendir(path->AsString()); | 260 dir_pointer = opendir(path->AsString()); |
| 269 } while ((dir_pointer == NULL) && (errno == EINTR)); | 261 } while ((dir_pointer == NULL) && (errno == EINTR)); |
| 270 if (dir_pointer == NULL) { | 262 if (dir_pointer == NULL) { |
| 271 return false; | 263 return false; |
| 272 } | 264 } |
| 273 | 265 |
| 274 // Iterate the directory and delete all files and directories. | 266 // Iterate the directory and delete all files and directories. |
| 275 int path_length = path->length(); | 267 int path_length = path->length(); |
| 276 while (true){ | 268 while (true) { |
| 277 // In case `readdir()` returns `NULL` we distinguish between end-of-stream a
nd error | 269 // In case `readdir()` returns `NULL` we distinguish between end-of-stream |
| 278 // by looking if `errno` was updated. | 270 // and error by looking if `errno` was updated. |
| 279 errno = 0; | 271 errno = 0; |
| 280 // In glibc 2.24+, readdir_r is deprecated. | 272 // In glibc 2.24+, readdir_r is deprecated. |
| 281 // According to the man page for readdir: | 273 // According to the man page for readdir: |
| 282 // "readdir(3) is not required to be thread-safe. However, in modern | 274 // "readdir(3) is not required to be thread-safe. However, in modern |
| 283 // implementations (including the glibc implementation), concurrent calls to | 275 // implementations (including the glibc implementation), concurrent calls to |
| 284 // readdir(3) that specify different directory streams are thread-safe. | 276 // readdir(3) that specify different directory streams are thread-safe." |
| 285 // Therefore, the use of readdir_r() is generally unnecessary in multithread
ed | |
| 286 // programs. In cases where multiple threads must read from the same directo
ry | |
| 287 // stream, using readdir(3) with external synchronization is still preferabl
e | |
| 288 // to the use of readdir_r(), for the reasons given in the points above." | |
| 289 dirent* entry = readdir(dir_pointer); | 277 dirent* entry = readdir(dir_pointer); |
| 290 if (entry == NULL) { | 278 if (entry == NULL) { |
| 291 // Failed to read next directory entry. | 279 // Failed to read next directory entry. |
| 292 if (errno != 0) { | 280 if (errno != 0) { |
| 293 break; | 281 break; |
| 294 } | 282 } |
| 295 // End of directory. | 283 // End of directory. |
| 296 return (NO_RETRY_EXPECTED(closedir(dir_pointer)) == 0) && | 284 return (NO_RETRY_EXPECTED(closedir(dir_pointer)) == 0) && |
| 297 (NO_RETRY_EXPECTED(remove(path->AsString())) == 0); | 285 (NO_RETRY_EXPECTED(remove(path->AsString())) == 0); |
| 298 } | 286 } |
| 299 bool ok = false; | 287 bool ok = false; |
| 300 switch (entry->d_type) { | 288 switch (entry->d_type) { |
| 301 case DT_DIR: | 289 case DT_DIR: |
| 302 ok = DeleteDir(entry->d_name, path); | 290 ok = DeleteDir(entry->d_name, path); |
| 303 break; | 291 break; |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 350 Directory::ExistsResult Directory::Exists(const char* dir_name) { | 338 Directory::ExistsResult Directory::Exists(const char* dir_name) { |
| 351 struct stat64 entry_info; | 339 struct stat64 entry_info; |
| 352 int success = TEMP_FAILURE_RETRY(stat64(dir_name, &entry_info)); | 340 int success = TEMP_FAILURE_RETRY(stat64(dir_name, &entry_info)); |
| 353 if (success == 0) { | 341 if (success == 0) { |
| 354 if (S_ISDIR(entry_info.st_mode)) { | 342 if (S_ISDIR(entry_info.st_mode)) { |
| 355 return EXISTS; | 343 return EXISTS; |
| 356 } else { | 344 } else { |
| 357 return DOES_NOT_EXIST; | 345 return DOES_NOT_EXIST; |
| 358 } | 346 } |
| 359 } else { | 347 } else { |
| 360 if ((errno == EACCES) || | 348 if ((errno == EACCES) || (errno == EBADF) || (errno == EFAULT) || |
| 361 (errno == EBADF) || | 349 (errno == ENOMEM) || (errno == EOVERFLOW)) { |
| 362 (errno == EFAULT) || | |
| 363 (errno == ENOMEM) || | |
| 364 (errno == EOVERFLOW)) { | |
| 365 // Search permissions denied for one of the directories in the | 350 // Search permissions denied for one of the directories in the |
| 366 // path or a low level error occured. We do not know if the | 351 // path or a low level error occured. We do not know if the |
| 367 // directory exists. | 352 // directory exists. |
| 368 return UNKNOWN; | 353 return UNKNOWN; |
| 369 } | 354 } |
| 370 ASSERT((errno == ELOOP) || | 355 ASSERT((errno == ELOOP) || (errno == ENAMETOOLONG) || (errno == ENOENT) || |
| 371 (errno == ENAMETOOLONG) || | |
| 372 (errno == ENOENT) || | |
| 373 (errno == ENOTDIR)); | 356 (errno == ENOTDIR)); |
| 374 return DOES_NOT_EXIST; | 357 return DOES_NOT_EXIST; |
| 375 } | 358 } |
| 376 } | 359 } |
| 377 | 360 |
| 378 | 361 |
| 379 char* Directory::CurrentNoScope() { | 362 char* Directory::CurrentNoScope() { |
| 380 return getcwd(NULL, 0); | 363 return getcwd(NULL, 0); |
| 381 } | 364 } |
| 382 | 365 |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 476 if (exists != EXISTS) { | 459 if (exists != EXISTS) { |
| 477 return false; | 460 return false; |
| 478 } | 461 } |
| 479 return (NO_RETRY_EXPECTED(rename(path, new_path)) == 0); | 462 return (NO_RETRY_EXPECTED(rename(path, new_path)) == 0); |
| 480 } | 463 } |
| 481 | 464 |
| 482 } // namespace bin | 465 } // namespace bin |
| 483 } // namespace dart | 466 } // namespace dart |
| 484 | 467 |
| 485 #endif // defined(TARGET_OS_LINUX) | 468 #endif // defined(TARGET_OS_LINUX) |
| OLD | NEW |