| Index: runtime/bin/directory_android.cc
|
| diff --git a/runtime/bin/directory_android.cc b/runtime/bin/directory_android.cc
|
| index 3e2559add638ecc0812051f338d5660e6c3c6ecc..95709da45e9cc4e89f359941e0b56215ea1230bd 100644
|
| --- a/runtime/bin/directory_android.cc
|
| +++ b/runtime/bin/directory_android.cc
|
| @@ -54,10 +54,20 @@ class PathBuffer {
|
| };
|
|
|
|
|
| +// A linked list of symbolic links, with their unique file system identifiers.
|
| +// These are scanned to detect loops while doing a recursive directory listing.
|
| +struct LinkList {
|
| + dev_t dev;
|
| + ino_t ino;
|
| + LinkList* next;
|
| +};
|
| +
|
| +
|
| // Forward declarations.
|
| static bool ListRecursively(PathBuffer* path,
|
| bool recursive,
|
| bool follow_links,
|
| + LinkList* seen,
|
| DirectoryListing* listing);
|
| static bool DeleteRecursively(PathBuffer* path);
|
|
|
| @@ -72,6 +82,7 @@ static bool HandleDir(char* dir_name,
|
| PathBuffer* path,
|
| bool recursive,
|
| bool follow_links,
|
| + LinkList* seen,
|
| DirectoryListing *listing) {
|
| if (strcmp(dir_name, ".") == 0) return true;
|
| if (strcmp(dir_name, "..") == 0) return true;
|
| @@ -80,7 +91,8 @@ static bool HandleDir(char* dir_name,
|
| return false;
|
| }
|
| return listing->HandleDirectory(path->data) &&
|
| - (!recursive || ListRecursively(path, recursive, follow_links, listing));
|
| + (!recursive ||
|
| + ListRecursively(path, recursive, follow_links, seen, listing));
|
| }
|
|
|
|
|
| @@ -109,6 +121,7 @@ static bool HandleLink(char* link_name,
|
| static bool ListRecursively(PathBuffer* path,
|
| bool recursive,
|
| bool follow_links,
|
| + LinkList* seen,
|
| DirectoryListing *listing) {
|
| if (!path->Add(File::PathSeparator())) {
|
| PostError(listing, path->data);
|
| @@ -167,19 +180,56 @@ static bool ListRecursively(PathBuffer* path,
|
| break;
|
| }
|
| int stat_success;
|
| - if (follow_links) {
|
| - stat_success = TEMP_FAILURE_RETRY(stat(path->data, &entry_info));
|
| - if (stat_success == -1) {
|
| - stat_success = TEMP_FAILURE_RETRY(lstat(path->data, &entry_info));
|
| - }
|
| - } else {
|
| - stat_success = TEMP_FAILURE_RETRY(lstat(path->data, &entry_info));
|
| - }
|
| + stat_success = TEMP_FAILURE_RETRY(lstat(path->data, &entry_info));
|
| if (stat_success == -1) {
|
| success = false;
|
| PostError(listing, path->data);
|
| break;
|
| }
|
| + if (follow_links && S_ISLNK(entry_info.st_mode)) {
|
| + // Check to see if we are in a loop created by a symbolic link.
|
| + LinkList current_link = { entry_info.st_dev,
|
| + entry_info.st_ino,
|
| + seen };
|
| + LinkList* previous = seen;
|
| + bool looping_link = false;
|
| + while (previous != NULL) {
|
| + if (previous->dev == current_link.dev &&
|
| + previous->ino == current_link.ino) {
|
| + // Report the looping link as a link, rather than following it.
|
| + path->Reset(path_length);
|
| + success = HandleLink(entry.d_name,
|
| + path,
|
| + listing) && success;
|
| + looping_link = true;
|
| + break;
|
| + }
|
| + previous = previous->next;
|
| + }
|
| + if (looping_link) break;
|
| + stat_success = TEMP_FAILURE_RETRY(stat(path->data, &entry_info));
|
| + if (stat_success == -1) {
|
| + // Report a broken link as a link, even if follow_links is true.
|
| + path->Reset(path_length);
|
| + success = HandleLink(entry.d_name,
|
| + path,
|
| + listing) && success;
|
| + break;
|
| + }
|
| + if (S_ISDIR(entry_info.st_mode)) {
|
| + // Recurse into the subdirectory with current_link added to the
|
| + // linked list of seen file system links.
|
| + path->Reset(path_length);
|
| + success = HandleDir(entry.d_name,
|
| + path,
|
| + recursive,
|
| + follow_links,
|
| + seen,
|
| + ¤t_link,
|
| + listing) && success;
|
| + break;
|
| + }
|
| + }
|
| path->Reset(path_length);
|
| if (S_ISDIR(entry_info.st_mode)) {
|
| success = HandleDir(entry.d_name,
|
| @@ -327,7 +377,7 @@ bool Directory::List(const char* dir_name,
|
| PostError(listing, dir_name);
|
| return false;
|
| }
|
| - return ListRecursively(&path, recursive, follow_links, listing);
|
| + return ListRecursively(&path, recursive, follow_links, NULL, listing);
|
| }
|
|
|
|
|
|
|