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_ANDROID) | 6 #if defined(TARGET_OS_ANDROID) |
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 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
160 // On some file systems the entry type is not determined by | 173 // On some file systems the entry type is not determined by |
161 // readdir_r. For those and for links we use stat to determine | 174 // readdir_r. For those and for links we use stat to determine |
162 // the actual entry type. Notice that stat returns the type of | 175 // the actual entry type. Notice that stat returns the type of |
163 // the file pointed to. | 176 // the file pointed to. |
164 struct stat entry_info; | 177 struct stat entry_info; |
165 if (!path->Add(entry.d_name)) { | 178 if (!path->Add(entry.d_name)) { |
166 success = false; | 179 success = false; |
167 break; | 180 break; |
168 } | 181 } |
169 int stat_success; | 182 int stat_success; |
170 if (follow_links) { | 183 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) { | 184 if (stat_success == -1) { |
179 success = false; | 185 success = false; |
180 PostError(listing, path->data); | 186 PostError(listing, path->data); |
181 break; | 187 break; |
182 } | 188 } |
| 189 if (follow_links && S_ISLNK(entry_info.st_mode)) { |
| 190 // Check to see if we are in a loop created by a symbolic link. |
| 191 LinkList current_link = { entry_info.st_dev, |
| 192 entry_info.st_ino, |
| 193 seen }; |
| 194 LinkList* previous = seen; |
| 195 bool looping_link = false; |
| 196 while (previous != NULL) { |
| 197 if (previous->dev == current_link.dev && |
| 198 previous->ino == current_link.ino) { |
| 199 // Report the looping link as a link, rather than following it. |
| 200 path->Reset(path_length); |
| 201 success = HandleLink(entry.d_name, |
| 202 path, |
| 203 listing) && success; |
| 204 looping_link = true; |
| 205 break; |
| 206 } |
| 207 previous = previous->next; |
| 208 } |
| 209 if (looping_link) break; |
| 210 stat_success = TEMP_FAILURE_RETRY(stat(path->data, &entry_info)); |
| 211 if (stat_success == -1) { |
| 212 // Report a broken link as a link, even if follow_links is true. |
| 213 path->Reset(path_length); |
| 214 success = HandleLink(entry.d_name, |
| 215 path, |
| 216 listing) && success; |
| 217 break; |
| 218 } |
| 219 if (S_ISDIR(entry_info.st_mode)) { |
| 220 // Recurse into the subdirectory with current_link added to the |
| 221 // linked list of seen file system links. |
| 222 path->Reset(path_length); |
| 223 success = HandleDir(entry.d_name, |
| 224 path, |
| 225 recursive, |
| 226 follow_links, |
| 227 seen, |
| 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, |
189 listing) && success; | 239 listing) && success; |
190 } else if (S_ISREG(entry_info.st_mode)) { | 240 } else if (S_ISREG(entry_info.st_mode)) { |
191 success = HandleFile(entry.d_name, | 241 success = HandleFile(entry.d_name, |
192 path, | 242 path, |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
320 | 370 |
321 bool Directory::List(const char* dir_name, | 371 bool Directory::List(const char* dir_name, |
322 bool recursive, | 372 bool recursive, |
323 bool follow_links, | 373 bool follow_links, |
324 DirectoryListing *listing) { | 374 DirectoryListing *listing) { |
325 PathBuffer path; | 375 PathBuffer path; |
326 if (!path.Add(dir_name)) { | 376 if (!path.Add(dir_name)) { |
327 PostError(listing, dir_name); | 377 PostError(listing, dir_name); |
328 return false; | 378 return false; |
329 } | 379 } |
330 return ListRecursively(&path, recursive, follow_links, listing); | 380 return ListRecursively(&path, recursive, follow_links, NULL, listing); |
331 } | 381 } |
332 | 382 |
333 | 383 |
334 Directory::ExistsResult Directory::Exists(const char* dir_name) { | 384 Directory::ExistsResult Directory::Exists(const char* dir_name) { |
335 struct stat entry_info; | 385 struct stat entry_info; |
336 int success = TEMP_FAILURE_RETRY(stat(dir_name, &entry_info)); | 386 int success = TEMP_FAILURE_RETRY(stat(dir_name, &entry_info)); |
337 if (success == 0) { | 387 if (success == 0) { |
338 if (S_ISDIR(entry_info.st_mode)) { | 388 if (S_ISDIR(entry_info.st_mode)) { |
339 return EXISTS; | 389 return EXISTS; |
340 } else { | 390 } else { |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
457 } | 507 } |
458 | 508 |
459 | 509 |
460 bool Directory::Rename(const char* path, const char* new_path) { | 510 bool Directory::Rename(const char* path, const char* new_path) { |
461 ExistsResult exists = Exists(path); | 511 ExistsResult exists = Exists(path); |
462 if (exists != EXISTS) return false; | 512 if (exists != EXISTS) return false; |
463 return (TEMP_FAILURE_RETRY(rename(path, new_path)) == 0); | 513 return (TEMP_FAILURE_RETRY(rename(path, new_path)) == 0); |
464 } | 514 } |
465 | 515 |
466 #endif // defined(TARGET_OS_ANDROID) | 516 #endif // defined(TARGET_OS_ANDROID) |
OLD | NEW |