Chromium Code Reviews| 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 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 47 } | 47 } |
| 48 } | 48 } |
| 49 | 49 |
| 50 void Reset(int new_length) { | 50 void Reset(int new_length) { |
| 51 length = new_length; | 51 length = new_length; |
| 52 data[length] = '\0'; | 52 data[length] = '\0'; |
| 53 } | 53 } |
| 54 }; | 54 }; |
| 55 | 55 |
| 56 | 56 |
| 57 // A linked list of symbolic links, with their unique file system identifiers. | |
| 58 // These are scanned to detect loops while doing a recursive directory listing. | |
| 59 struct LinkList { | |
| 60 dev_t dev; | |
| 61 ino_t ino; | |
| 62 LinkList* next; | |
| 63 }; | |
| 64 | |
| 65 | |
| 57 // Forward declarations. | 66 // Forward declarations. |
| 58 static bool ListRecursively(PathBuffer* path, | 67 static bool ListRecursively(PathBuffer* path, |
| 59 bool recursive, | 68 bool recursive, |
| 60 bool follow_links, | 69 bool follow_links, |
| 70 LinkList* seen, | |
| 61 DirectoryListing* listing); | 71 DirectoryListing* listing); |
| 62 static bool DeleteRecursively(PathBuffer* path); | 72 static bool DeleteRecursively(PathBuffer* path); |
| 63 | 73 |
| 64 | 74 |
| 65 static void PostError(DirectoryListing *listing, | 75 static void PostError(DirectoryListing *listing, |
| 66 const char* dir_name) { | 76 const char* dir_name) { |
| 67 listing->HandleError(dir_name); | 77 listing->HandleError(dir_name); |
| 68 } | 78 } |
| 69 | 79 |
| 70 | 80 |
| 71 static bool HandleDir(char* dir_name, | 81 static bool HandleDir(char* dir_name, |
| 72 PathBuffer* path, | 82 PathBuffer* path, |
| 73 bool recursive, | 83 bool recursive, |
| 74 bool follow_links, | 84 bool follow_links, |
| 85 LinkList* seen, | |
| 75 DirectoryListing *listing) { | 86 DirectoryListing *listing) { |
| 76 if (strcmp(dir_name, ".") == 0) return true; | 87 if (strcmp(dir_name, ".") == 0) return true; |
| 77 if (strcmp(dir_name, "..") == 0) return true; | 88 if (strcmp(dir_name, "..") == 0) return true; |
| 78 if (!path->Add(dir_name)) { | 89 if (!path->Add(dir_name)) { |
| 79 PostError(listing, path->data); | 90 PostError(listing, path->data); |
| 80 return false; | 91 return false; |
| 81 } | 92 } |
| 82 return listing->HandleDirectory(path->data) && | 93 return listing->HandleDirectory(path->data) && |
| 83 (!recursive || ListRecursively(path, recursive, follow_links, listing)); | 94 (!recursive || |
| 95 ListRecursively(path, recursive, follow_links, seen, listing)); | |
| 84 } | 96 } |
| 85 | 97 |
| 86 | 98 |
| 87 static bool HandleFile(char* file_name, | 99 static bool HandleFile(char* file_name, |
| 88 PathBuffer* path, | 100 PathBuffer* path, |
| 89 DirectoryListing *listing) { | 101 DirectoryListing *listing) { |
| 90 if (!path->Add(file_name)) { | 102 if (!path->Add(file_name)) { |
| 91 PostError(listing, path->data); | 103 PostError(listing, path->data); |
| 92 return false; | 104 return false; |
| 93 } | 105 } |
| 94 return listing->HandleFile(path->data); | 106 return listing->HandleFile(path->data); |
| 95 } | 107 } |
| 96 | 108 |
| 97 | 109 |
| 98 static bool HandleLink(char* link_name, | 110 static bool HandleLink(char* link_name, |
| 99 PathBuffer* path, | 111 PathBuffer* path, |
| 100 DirectoryListing *listing) { | 112 DirectoryListing *listing) { |
| 101 if (!path->Add(link_name)) { | 113 if (!path->Add(link_name)) { |
| 102 PostError(listing, path->data); | 114 PostError(listing, path->data); |
| 103 return false; | 115 return false; |
| 104 } | 116 } |
| 105 return listing->HandleLink(path->data); | 117 return listing->HandleLink(path->data); |
| 106 } | 118 } |
| 107 | 119 |
| 108 | 120 |
| 109 static bool ListRecursively(PathBuffer* path, | 121 static bool ListRecursively(PathBuffer* path, |
| 110 bool recursive, | 122 bool recursive, |
| 111 bool follow_links, | 123 bool follow_links, |
| 124 LinkList* seen, | |
| 112 DirectoryListing *listing) { | 125 DirectoryListing *listing) { |
| 113 if (!path->Add(File::PathSeparator())) { | 126 if (!path->Add(File::PathSeparator())) { |
| 114 PostError(listing, path->data); | 127 PostError(listing, path->data); |
| 115 return false; | 128 return false; |
| 116 } | 129 } |
| 117 DIR* dir_pointer; | 130 DIR* dir_pointer; |
| 118 do { | 131 do { |
| 119 dir_pointer = opendir(path->data); | 132 dir_pointer = opendir(path->data); |
| 120 } while (dir_pointer == NULL && errno == EINTR); | 133 } while (dir_pointer == NULL && errno == EINTR); |
| 121 if (dir_pointer == NULL) { | 134 if (dir_pointer == NULL) { |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 133 while ((status = TEMP_FAILURE_RETRY(readdir_r(dir_pointer, | 146 while ((status = TEMP_FAILURE_RETRY(readdir_r(dir_pointer, |
| 134 &entry, | 147 &entry, |
| 135 &result))) == 0 && | 148 &result))) == 0 && |
| 136 result != NULL) { | 149 result != NULL) { |
| 137 switch (entry.d_type) { | 150 switch (entry.d_type) { |
| 138 case DT_DIR: | 151 case DT_DIR: |
| 139 success = HandleDir(entry.d_name, | 152 success = HandleDir(entry.d_name, |
| 140 path, | 153 path, |
| 141 recursive, | 154 recursive, |
| 142 follow_links, | 155 follow_links, |
| 156 seen, | |
| 143 listing) && success; | 157 listing) && success; |
| 144 break; | 158 break; |
| 145 case DT_REG: | 159 case DT_REG: |
| 146 success = HandleFile(entry.d_name, | 160 success = HandleFile(entry.d_name, |
| 147 path, | 161 path, |
| 148 listing) && success; | 162 listing) && success; |
| 149 break; | 163 break; |
| 150 case DT_LNK: | 164 case DT_LNK: |
| 151 if (!follow_links) { | 165 if (!follow_links) { |
| 152 success = HandleLink(entry.d_name, | 166 success = HandleLink(entry.d_name, |
| 153 path, | 167 path, |
| 154 listing) && success; | 168 listing) && success; |
| 155 break; | 169 break; |
| 156 } | 170 } |
| 157 // Else fall through to next case. | 171 // Else fall through to next case. |
| 158 // Fall through. | 172 // Fall through. |
| 159 case DT_UNKNOWN: { | 173 case DT_UNKNOWN: { |
| 160 // On some file systems the entry type is not determined by | 174 // On some file systems the entry type is not determined by |
| 161 // readdir_r. For those and for links we use stat to determine | 175 // readdir_r. For those and for links we use stat to determine |
| 162 // the actual entry type. Notice that stat returns the type of | 176 // the actual entry type. Notice that stat returns the type of |
| 163 // the file pointed to. | 177 // the file pointed to. |
| 164 struct stat entry_info; | 178 struct stat entry_info; |
| 165 if (!path->Add(entry.d_name)) { | 179 if (!path->Add(entry.d_name)) { |
| 166 success = false; | 180 success = false; |
| 167 break; | 181 break; |
| 168 } | 182 } |
| 169 int stat_success; | 183 int stat_success; |
| 170 if (follow_links) { | 184 stat_success = TEMP_FAILURE_RETRY(lstat(path->data, &entry_info)); |
| 171 stat_success = TEMP_FAILURE_RETRY(stat(path->data, &entry_info)); | |
| 172 if (stat_success == -1) { | |
| 173 stat_success = TEMP_FAILURE_RETRY(lstat(path->data, &entry_info)); | |
| 174 } | |
| 175 } else { | |
| 176 stat_success = TEMP_FAILURE_RETRY(lstat(path->data, &entry_info)); | |
| 177 } | |
| 178 if (stat_success == -1) { | 185 if (stat_success == -1) { |
| 179 success = false; | 186 success = false; |
| 180 PostError(listing, path->data); | 187 PostError(listing, path->data); |
| 181 break; | 188 break; |
| 182 } | 189 } |
| 190 if (follow_links && S_ISLNK(entry_info.st_mode)) { | |
| 191 // Check to see if we are in a loop created by a symbolic link. | |
| 192 LinkList current_link = { entry_info.st_dev, | |
| 193 entry_info.st_ino, | |
| 194 seen }; | |
| 195 LinkList* previous = seen; | |
| 196 bool looping_link = false; | |
| 197 while (previous != NULL) { | |
| 198 if (previous->dev == current_link.dev && | |
| 199 previous->ino == current_link.ino) { | |
|
Søren Gjesse
2013/04/10 11:33:23
How about adding a compare method (or operator==)
Bill Hesse
2013/04/10 12:49:47
I would do that if we had another use. But that t
| |
| 200 // Report the looping link as a link, rather than following it. | |
| 201 path->Reset(path_length); | |
| 202 success = HandleLink(entry.d_name, | |
| 203 path, | |
| 204 listing) && success; | |
| 205 looping_link = true; | |
| 206 break; | |
| 207 } | |
| 208 previous = previous->next; | |
| 209 } | |
| 210 if (looping_link) break; | |
| 211 stat_success = TEMP_FAILURE_RETRY(stat(path->data, &entry_info)); | |
| 212 if (stat_success == -1) { | |
| 213 // Report a broken link as a link, even if follow_links is true. | |
| 214 path->Reset(path_length); | |
| 215 success = HandleLink(entry.d_name, | |
| 216 path, | |
| 217 listing) && success; | |
| 218 break; | |
| 219 } | |
| 220 if (S_ISDIR(entry_info.st_mode)) { | |
| 221 // Recurse into the subdirectory with current_link added to the | |
| 222 // linked list of seen file system links. | |
| 223 path->Reset(path_length); | |
| 224 success = HandleDir(entry.d_name, | |
| 225 path, | |
| 226 recursive, | |
| 227 follow_links, | |
| 228 ¤t_link, | |
| 229 listing) && success; | |
| 230 break; | |
| 231 } | |
| 232 } | |
| 183 path->Reset(path_length); | 233 path->Reset(path_length); |
| 184 if (S_ISDIR(entry_info.st_mode)) { | 234 if (S_ISDIR(entry_info.st_mode)) { |
| 185 success = HandleDir(entry.d_name, | 235 success = HandleDir(entry.d_name, |
| 186 path, | 236 path, |
| 187 recursive, | 237 recursive, |
| 188 follow_links, | 238 follow_links, |
| 239 seen, | |
| 189 listing) && success; | 240 listing) && success; |
| 190 } else if (S_ISREG(entry_info.st_mode)) { | 241 } else if (S_ISREG(entry_info.st_mode)) { |
| 191 success = HandleFile(entry.d_name, | 242 success = HandleFile(entry.d_name, |
| 192 path, | 243 path, |
| 193 listing) && success; | 244 listing) && success; |
| 194 } else if (S_ISLNK(entry_info.st_mode)) { | 245 } else if (S_ISLNK(entry_info.st_mode)) { |
| 195 success = HandleLink(entry.d_name, | 246 success = HandleLink(entry.d_name, |
| 196 path, | 247 path, |
| 197 listing) && success; | 248 listing) && success; |
| 198 } | 249 } |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 320 | 371 |
| 321 bool Directory::List(const char* dir_name, | 372 bool Directory::List(const char* dir_name, |
| 322 bool recursive, | 373 bool recursive, |
| 323 bool follow_links, | 374 bool follow_links, |
| 324 DirectoryListing *listing) { | 375 DirectoryListing *listing) { |
| 325 PathBuffer path; | 376 PathBuffer path; |
| 326 if (!path.Add(dir_name)) { | 377 if (!path.Add(dir_name)) { |
| 327 PostError(listing, dir_name); | 378 PostError(listing, dir_name); |
| 328 return false; | 379 return false; |
| 329 } | 380 } |
| 330 return ListRecursively(&path, recursive, follow_links, listing); | 381 return ListRecursively(&path, recursive, follow_links, NULL, listing); |
| 331 } | 382 } |
| 332 | 383 |
| 333 | 384 |
| 334 Directory::ExistsResult Directory::Exists(const char* dir_name) { | 385 Directory::ExistsResult Directory::Exists(const char* dir_name) { |
| 335 struct stat entry_info; | 386 struct stat entry_info; |
| 336 int success = TEMP_FAILURE_RETRY(stat(dir_name, &entry_info)); | 387 int success = TEMP_FAILURE_RETRY(stat(dir_name, &entry_info)); |
| 337 if (success == 0) { | 388 if (success == 0) { |
| 338 if (S_ISDIR(entry_info.st_mode)) { | 389 if (S_ISDIR(entry_info.st_mode)) { |
| 339 return EXISTS; | 390 return EXISTS; |
| 340 } else { | 391 } else { |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 425 } | 476 } |
| 426 | 477 |
| 427 | 478 |
| 428 bool Directory::Rename(const char* path, const char* new_path) { | 479 bool Directory::Rename(const char* path, const char* new_path) { |
| 429 ExistsResult exists = Exists(path); | 480 ExistsResult exists = Exists(path); |
| 430 if (exists != EXISTS) return false; | 481 if (exists != EXISTS) return false; |
| 431 return (TEMP_FAILURE_RETRY(rename(path, new_path)) == 0); | 482 return (TEMP_FAILURE_RETRY(rename(path, new_path)) == 0); |
| 432 } | 483 } |
| 433 | 484 |
| 434 #endif // defined(TARGET_OS_LINUX) | 485 #endif // defined(TARGET_OS_LINUX) |
| OLD | NEW |