| 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 "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> |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 | 23 |
| 24 static void SetOsErrorMessage(char* os_error_message, | 24 static void SetOsErrorMessage(char* os_error_message, |
| 25 int os_error_message_len) { | 25 int os_error_message_len) { |
| 26 SafeStrNCpy(os_error_message, strerror(errno), os_error_message_len); | 26 SafeStrNCpy(os_error_message, strerror(errno), os_error_message_len); |
| 27 } | 27 } |
| 28 | 28 |
| 29 | 29 |
| 30 // Forward declarations. | 30 // Forward declarations. |
| 31 static bool ListRecursively(const char* dir_name, | 31 static bool ListRecursively(const char* dir_name, |
| 32 bool recursive, | 32 bool recursive, |
| 33 Dart_Port dir_port, | 33 DirectoryListing* listing); |
| 34 Dart_Port file_port, | |
| 35 Dart_Port done_port, | |
| 36 Dart_Port error_port); | |
| 37 static bool DeleteRecursively(const char* dir_name); | 34 static bool DeleteRecursively(const char* dir_name); |
| 38 | 35 |
| 39 | 36 |
| 40 static bool ComputeFullPath(const char* dir_name, | 37 static bool ComputeFullPath(const char* dir_name, |
| 41 char* path, | 38 char* path, |
| 42 int* path_length) { | 39 int* path_length) { |
| 43 char* abs_path; | 40 char* abs_path; |
| 44 do { | 41 do { |
| 45 abs_path = realpath(dir_name, path); | 42 abs_path = realpath(dir_name, path); |
| 46 } while (abs_path == NULL && errno == EINTR); | 43 } while (abs_path == NULL && errno == EINTR); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 57 } | 54 } |
| 58 *path_length += written; | 55 *path_length += written; |
| 59 return true; | 56 return true; |
| 60 } | 57 } |
| 61 | 58 |
| 62 | 59 |
| 63 static bool HandleDir(char* dir_name, | 60 static bool HandleDir(char* dir_name, |
| 64 char* path, | 61 char* path, |
| 65 int path_length, | 62 int path_length, |
| 66 bool recursive, | 63 bool recursive, |
| 67 Dart_Port dir_port, | 64 DirectoryListing *listing) { |
| 68 Dart_Port file_port, | |
| 69 Dart_Port done_port, | |
| 70 Dart_Port error_port) { | |
| 71 if (strcmp(dir_name, ".") != 0 && | 65 if (strcmp(dir_name, ".") != 0 && |
| 72 strcmp(dir_name, "..") != 0) { | 66 strcmp(dir_name, "..") != 0) { |
| 73 size_t written = snprintf(path + path_length, | 67 size_t written = snprintf(path + path_length, |
| 74 PATH_MAX - path_length, | 68 PATH_MAX - path_length, |
| 75 "%s", | 69 "%s", |
| 76 dir_name); | 70 dir_name); |
| 77 if (written != strlen(dir_name)) { | 71 if (written != strlen(dir_name)) { |
| 78 return false; | 72 return false; |
| 79 } | 73 } |
| 80 if (dir_port != 0) { | 74 bool ok = listing->HandleDirectory(dir_name); |
| 81 Dart_Handle name = Dart_NewString(path); | 75 if (!ok) return ok; |
| 82 Dart_Post(dir_port, name); | |
| 83 } | |
| 84 if (recursive) { | 76 if (recursive) { |
| 85 return ListRecursively(path, | 77 return ListRecursively(path, recursive, listing); |
| 86 recursive, | |
| 87 dir_port, | |
| 88 file_port, | |
| 89 done_port, | |
| 90 error_port); | |
| 91 } | 78 } |
| 92 } | 79 } |
| 93 return true; | 80 return true; |
| 94 } | 81 } |
| 95 | 82 |
| 96 | 83 |
| 97 static bool HandleFile(char* file_name, | 84 static bool HandleFile(char* file_name, |
| 98 char* path, | 85 char* path, |
| 99 int path_length, | 86 int path_length, |
| 100 Dart_Port file_port) { | 87 DirectoryListing *listing) { |
| 101 if (file_port != 0) { | 88 // TODO(sgjesse): Pass flags to indicate whether file responses are |
| 102 size_t written = snprintf(path + path_length, | 89 // needed. |
| 103 PATH_MAX - path_length, | 90 size_t written = snprintf(path + path_length, |
| 104 "%s", | 91 PATH_MAX - path_length, |
| 105 file_name); | 92 "%s", |
| 106 if (written != strlen(file_name)) { | 93 file_name); |
| 107 return false; | 94 if (written != strlen(file_name)) { |
| 108 } | 95 return false; |
| 109 Dart_Handle name = Dart_NewString(path); | |
| 110 Dart_Post(file_port, name); | |
| 111 } | 96 } |
| 112 return true; | 97 return listing->HandleFile(path); |
| 113 } | 98 } |
| 114 | 99 |
| 115 | 100 |
| 116 static void PostError(Dart_Port error_port, | 101 static void PostError(DirectoryListing *listing, |
| 117 const char* prefix, | 102 const char* prefix, |
| 118 const char* suffix, | 103 const char* suffix, |
| 119 int error_code) { | 104 int error_code) { |
| 120 if (error_port != 0) { | 105 // TODO(sgjesse): Pass flags to indicate whether error response is |
| 121 char* error_str = Platform::StrError(error_code); | 106 // needed. |
| 122 int error_message_size = | 107 char* error_str = Platform::StrError(error_code); |
| 123 strlen(prefix) + strlen(suffix) + strlen(error_str) + 3; | 108 int error_message_size = |
| 124 char* message = static_cast<char*>(malloc(error_message_size + 1)); | 109 strlen(prefix) + strlen(suffix) + strlen(error_str) + 3; |
| 125 int written = snprintf(message, | 110 char* message = static_cast<char*>(malloc(error_message_size + 1)); |
| 126 error_message_size + 1, | 111 int written = snprintf(message, |
| 127 "%s%s (%s)", | 112 error_message_size + 1, |
| 128 prefix, | 113 "%s%s (%s)", |
| 129 suffix, | 114 prefix, |
| 130 error_str); | 115 suffix, |
| 131 ASSERT(written == error_message_size); | 116 error_str); |
| 132 free(error_str); | 117 ASSERT(written == error_message_size); |
| 133 Dart_Post(error_port, Dart_NewString(message)); | 118 free(error_str); |
| 134 free(message); | 119 listing->HandleError(message); |
| 135 } | 120 free(message); |
| 136 } | 121 } |
| 137 | 122 |
| 138 | 123 |
| 139 static bool ListRecursively(const char* dir_name, | 124 static bool ListRecursively(const char* dir_name, |
| 140 bool recursive, | 125 bool recursive, |
| 141 Dart_Port dir_port, | 126 DirectoryListing *listing) { |
| 142 Dart_Port file_port, | |
| 143 Dart_Port done_port, | |
| 144 Dart_Port error_port) { | |
| 145 DIR* dir_pointer; | 127 DIR* dir_pointer; |
| 146 do { | 128 do { |
| 147 dir_pointer = opendir(dir_name); | 129 dir_pointer = opendir(dir_name); |
| 148 } while (dir_pointer == NULL && errno == EINTR); | 130 } while (dir_pointer == NULL && errno == EINTR); |
| 149 if (dir_pointer == NULL) { | 131 if (dir_pointer == NULL) { |
| 150 PostError(error_port, "Directory listing failed for: ", dir_name, errno); | 132 PostError(listing, "Directory listing failed for: ", dir_name, errno); |
| 151 return false; | 133 return false; |
| 152 } | 134 } |
| 153 | 135 |
| 154 // Compute full path for the directory currently being listed. The | 136 // Compute full path for the directory currently being listed. The |
| 155 // path buffer will be used to construct the current path in the | 137 // path buffer will be used to construct the current path in the |
| 156 // recursive traversal. path_length does not always equal | 138 // recursive traversal. path_length does not always equal |
| 157 // strlen(path) but indicates the current prefix of path that is the | 139 // strlen(path) but indicates the current prefix of path that is the |
| 158 // path of the current directory in the traversal. | 140 // path of the current directory in the traversal. |
| 159 char *path = static_cast<char*>(malloc(PATH_MAX)); | 141 char *path = static_cast<char*>(malloc(PATH_MAX)); |
| 160 ASSERT(path != NULL); | 142 ASSERT(path != NULL); |
| 161 int path_length = 0; | 143 int path_length = 0; |
| 162 bool valid = ComputeFullPath(dir_name, path, &path_length); | 144 bool valid = ComputeFullPath(dir_name, path, &path_length); |
| 163 if (!valid) { | 145 if (!valid) { |
| 164 free(path); | 146 free(path); |
| 165 PostError(error_port, "Directory listing failed for: ", dir_name, errno); | 147 PostError(listing, "Directory listing failed for: ", dir_name, errno); |
| 166 return false; | 148 return false; |
| 167 } | 149 } |
| 168 | 150 |
| 169 // Iterated the directory and post the directories and files to the | 151 // Iterated the directory and post the directories and files to the |
| 170 // ports. | 152 // ports. |
| 171 int read = 0; | 153 int read = 0; |
| 172 bool success = true; | 154 bool success = true; |
| 173 dirent entry; | 155 dirent entry; |
| 174 dirent* result; | 156 dirent* result; |
| 175 while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer, | 157 while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer, |
| 176 &entry, | 158 &entry, |
| 177 &result))) == 0 && | 159 &result))) == 0 && |
| 178 result != NULL && | 160 result != NULL && |
| 179 success) { | 161 success) { |
| 180 switch (entry.d_type) { | 162 switch (entry.d_type) { |
| 181 case DT_DIR: | 163 case DT_DIR: |
| 182 success = success && HandleDir(entry.d_name, | 164 success = success && HandleDir(entry.d_name, |
| 183 path, | 165 path, |
| 184 path_length, | 166 path_length, |
| 185 recursive, | 167 recursive, |
| 186 dir_port, | 168 listing); |
| 187 file_port, | |
| 188 done_port, | |
| 189 error_port); | |
| 190 break; | 169 break; |
| 191 case DT_REG: | 170 case DT_REG: |
| 192 success = success && HandleFile(entry.d_name, | 171 success = success && HandleFile(entry.d_name, |
| 193 path, | 172 path, |
| 194 path_length, | 173 path_length, |
| 195 file_port); | 174 listing); |
| 196 break; | 175 break; |
| 197 case DT_UNKNOWN: { | 176 case DT_UNKNOWN: { |
| 198 // On some file systems the entry type is not determined by | 177 // On some file systems the entry type is not determined by |
| 199 // readdir_r. For those we use lstat to determine the entry | 178 // readdir_r. For those we use lstat to determine the entry |
| 200 // type. | 179 // type. |
| 201 struct stat entry_info; | 180 struct stat entry_info; |
| 202 size_t written = snprintf(path + path_length, | 181 size_t written = snprintf(path + path_length, |
| 203 PATH_MAX - path_length, | 182 PATH_MAX - path_length, |
| 204 "%s", | 183 "%s", |
| 205 entry.d_name); | 184 entry.d_name); |
| 206 if (written != strlen(entry.d_name)) { | 185 if (written != strlen(entry.d_name)) { |
| 207 success = false; | 186 success = false; |
| 208 break; | 187 break; |
| 209 } | 188 } |
| 210 int lstat_success = TEMP_FAILURE_RETRY(lstat(path, &entry_info)); | 189 int lstat_success = TEMP_FAILURE_RETRY(lstat(path, &entry_info)); |
| 211 if (lstat_success == -1) { | 190 if (lstat_success == -1) { |
| 212 success = false; | 191 success = false; |
| 213 PostError(error_port, "Directory listing failed for: ", path, errno); | 192 PostError(listing, "Directory listing failed for: ", path, errno); |
| 214 break; | 193 break; |
| 215 } | 194 } |
| 216 if ((entry_info.st_mode & S_IFMT) == S_IFDIR) { | 195 if ((entry_info.st_mode & S_IFMT) == S_IFDIR) { |
| 217 success = success && HandleDir(entry.d_name, | 196 success = success && HandleDir(entry.d_name, |
| 218 path, | 197 path, |
| 219 path_length, | 198 path_length, |
| 220 recursive, | 199 recursive, |
| 221 dir_port, | 200 listing); |
| 222 file_port, | |
| 223 done_port, | |
| 224 error_port); | |
| 225 } else if ((entry_info.st_mode & S_IFMT) == S_IFREG) { | 201 } else if ((entry_info.st_mode & S_IFMT) == S_IFREG) { |
| 226 success = success && HandleFile(entry.d_name, | 202 success = success && HandleFile(entry.d_name, |
| 227 path, | 203 path, |
| 228 path_length, | 204 path_length, |
| 229 file_port); | 205 listing); |
| 230 } | 206 } |
| 231 break; | 207 break; |
| 232 } | 208 } |
| 233 default: | 209 default: |
| 234 break; | 210 break; |
| 235 } | 211 } |
| 236 } | 212 } |
| 237 | 213 |
| 238 if (read != 0) { | 214 if (read != 0) { |
| 239 success = false; | 215 success = false; |
| 240 PostError(error_port, "Directory listing failed", "", read); | 216 PostError(listing, "Directory listing failed", "", read); |
| 241 } | 217 } |
| 242 | 218 |
| 243 if (closedir(dir_pointer) == -1) { | 219 if (closedir(dir_pointer) == -1) { |
| 244 PostError(error_port, "Failed to close directory", "", errno); | 220 PostError(listing, "Failed to close directory", "", errno); |
| 245 } | 221 } |
| 246 free(path); | 222 free(path); |
| 247 | 223 |
| 248 return success; | 224 return success; |
| 249 } | 225 } |
| 250 | 226 |
| 251 | 227 |
| 252 static bool DeleteFile(char* file_name, | 228 static bool DeleteFile(char* file_name, |
| 253 char* path, | 229 char* path, |
| 254 int path_length) { | 230 int path_length) { |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 357 if ((read != 0) || | 333 if ((read != 0) || |
| 358 (closedir(dir_pointer) == -1) || | 334 (closedir(dir_pointer) == -1) || |
| 359 (remove(dir_name) == -1)) { | 335 (remove(dir_name) == -1)) { |
| 360 return false; | 336 return false; |
| 361 } | 337 } |
| 362 | 338 |
| 363 return success; | 339 return success; |
| 364 } | 340 } |
| 365 | 341 |
| 366 | 342 |
| 367 void Directory::List(const char* dir_name, | 343 bool Directory::List(const char* dir_name, |
| 368 bool recursive, | 344 bool recursive, |
| 369 Dart_Port dir_port, | 345 DirectoryListing *listing) { |
| 370 Dart_Port file_port, | 346 bool completed = ListRecursively(dir_name, recursive, listing); |
| 371 Dart_Port done_port, | 347 return completed; |
| 372 Dart_Port error_port) { | |
| 373 bool completed = ListRecursively(dir_name, | |
| 374 recursive, | |
| 375 dir_port, | |
| 376 file_port, | |
| 377 done_port, | |
| 378 error_port); | |
| 379 if (done_port != 0) { | |
| 380 Dart_Handle value = Dart_NewBoolean(completed); | |
| 381 Dart_Post(done_port, value); | |
| 382 } | |
| 383 } | 348 } |
| 384 | 349 |
| 385 | 350 |
| 386 Directory::ExistsResult Directory::Exists(const char* dir_name) { | 351 Directory::ExistsResult Directory::Exists(const char* dir_name) { |
| 387 struct stat entry_info; | 352 struct stat entry_info; |
| 388 int lstat_success = TEMP_FAILURE_RETRY(lstat(dir_name, &entry_info)); | 353 int lstat_success = TEMP_FAILURE_RETRY(lstat(dir_name, &entry_info)); |
| 389 if (lstat_success == 0) { | 354 if (lstat_success == 0) { |
| 390 if ((entry_info.st_mode & S_IFMT) == S_IFDIR) { | 355 if ((entry_info.st_mode & S_IFMT) == S_IFDIR) { |
| 391 return EXISTS; | 356 return EXISTS; |
| 392 } else { | 357 } else { |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 453 } | 418 } |
| 454 | 419 |
| 455 | 420 |
| 456 bool Directory::Delete(const char* dir_name, bool recursive) { | 421 bool Directory::Delete(const char* dir_name, bool recursive) { |
| 457 if (!recursive) { | 422 if (!recursive) { |
| 458 return (TEMP_FAILURE_RETRY(remove(dir_name)) == 0); | 423 return (TEMP_FAILURE_RETRY(remove(dir_name)) == 0); |
| 459 } else { | 424 } else { |
| 460 return DeleteRecursively(dir_name); | 425 return DeleteRecursively(dir_name); |
| 461 } | 426 } |
| 462 } | 427 } |
| OLD | NEW |