Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3590)

Unified Diff: runtime/bin/directory_fuchsia.cc

Issue 2579483002: Fuchsia: Directory listing (Closed)
Patch Set: Format Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | runtime/tests/vm/dart/hello_fuchsia_test.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/bin/directory_fuchsia.cc
diff --git a/runtime/bin/directory_fuchsia.cc b/runtime/bin/directory_fuchsia.cc
index 24ecd27240ed4f2f95814d459680c2f884a56586..94a86d1618f342a1a47472557b90fe0c1cfcf1a6 100644
--- a/runtime/bin/directory_fuchsia.cc
+++ b/runtime/bin/directory_fuchsia.cc
@@ -7,9 +7,11 @@
#include "bin/directory.h"
+#include <dirent.h> // NOLINT
#include <errno.h> // NOLINT
#include <stdlib.h> // NOLINT
#include <string.h> // NOLINT
+#include <sys/param.h> // NOLINT
#include <sys/stat.h> // NOLINT
#include <unistd.h> // NOLINT
@@ -79,19 +81,164 @@ void PathBuffer::Reset(intptr_t new_length) {
}
+// 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;
+ ino64_t ino;
+ LinkList* next;
+};
+
+
ListType DirectoryListingEntry::Next(DirectoryListing* listing) {
- UNIMPLEMENTED();
- return kListError;
+ if (done_) {
+ return kListDone;
+ }
+
+ if (lister_ == 0) {
+ lister_ =
+ reinterpret_cast<intptr_t>(opendir(listing->path_buffer().AsString()));
+ if (lister_ == 0) {
+ perror("opendir failed: ");
+ done_ = true;
+ return kListError;
+ }
+ if (parent_ != NULL) {
+ if (!listing->path_buffer().Add(File::PathSeparator())) {
+ return kListError;
+ }
+ }
+ path_length_ = listing->path_buffer().length();
+ }
+ // Reset.
+ listing->path_buffer().Reset(path_length_);
+ ResetLink();
+
+ // Iterate the directory and post the directories and files to the
+ // ports.
+ errno = 0;
+ dirent* entry = readdir(reinterpret_cast<DIR*>(lister_));
+ if (entry == NULL) {
+ perror("readdir failed: ");
+ }
+ if (entry != NULL) {
+ if (!listing->path_buffer().Add(entry->d_name)) {
+ done_ = true;
+ return kListError;
+ }
+ switch (entry->d_type) {
+ case DT_DIR:
+ if ((strcmp(entry->d_name, ".") == 0) ||
+ (strcmp(entry->d_name, "..") == 0)) {
+ return Next(listing);
+ }
+ return kListDirectory;
+ case DT_BLK:
+ case DT_CHR:
+ case DT_FIFO:
+ case DT_SOCK:
+ case DT_REG:
+ return kListFile;
+ case DT_LNK:
+ if (!listing->follow_links()) {
+ return kListLink;
+ }
+ // Else fall through to next case.
+ // Fall through.
+ case DT_UNKNOWN: {
+ // On some file systems the entry type is not determined by
+ // readdir. For those and for links we use stat to determine
+ // the actual entry type. Notice that stat returns the type of
+ // the file pointed to.
+ struct stat64 entry_info;
+ int stat_success;
+ stat_success = NO_RETRY_EXPECTED(
+ lstat64(listing->path_buffer().AsString(), &entry_info));
+ if (stat_success == -1) {
+ perror("lstat64 failed: ");
+ return kListError;
+ }
+ if (listing->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, link_};
+ LinkList* previous = link_;
+ 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.
+ return kListLink;
+ }
+ previous = previous->next;
+ }
+ stat_success = NO_RETRY_EXPECTED(
+ stat64(listing->path_buffer().AsString(), &entry_info));
+ if (stat_success == -1) {
+ perror("lstat64 failed");
+ // Report a broken link as a link, even if follow_links is true.
+ return kListLink;
+ }
+ if (S_ISDIR(entry_info.st_mode)) {
+ // Recurse into the subdirectory with current_link added to the
+ // linked list of seen file system links.
+ link_ = new LinkList(current_link);
+ if ((strcmp(entry->d_name, ".") == 0) ||
+ (strcmp(entry->d_name, "..") == 0)) {
+ return Next(listing);
+ }
+ return kListDirectory;
+ }
+ }
+ if (S_ISDIR(entry_info.st_mode)) {
+ if ((strcmp(entry->d_name, ".") == 0) ||
+ (strcmp(entry->d_name, "..") == 0)) {
+ return Next(listing);
+ }
+ return kListDirectory;
+ } else if (S_ISREG(entry_info.st_mode) || S_ISCHR(entry_info.st_mode) ||
+ S_ISBLK(entry_info.st_mode) ||
+ S_ISFIFO(entry_info.st_mode) ||
+ S_ISSOCK(entry_info.st_mode)) {
+ return kListFile;
+ } else if (S_ISLNK(entry_info.st_mode)) {
+ return kListLink;
+ } else {
+ FATAL1("Unexpected st_mode: %d\n", entry_info.st_mode);
+ return kListError;
+ }
+ }
+
+ default:
+ // We should have covered all the bases. If not, let's get an error.
+ FATAL1("Unexpected d_type: %d\n", entry->d_type);
+ return kListError;
+ }
+ }
+ done_ = true;
+
+ if (errno != 0) {
+ return kListError;
+ }
+
+ return kListDone;
}
DirectoryListingEntry::~DirectoryListingEntry() {
- UNIMPLEMENTED();
+ ResetLink();
+ if (lister_ != 0) {
+ VOID_NO_RETRY_EXPECTED(closedir(reinterpret_cast<DIR*>(lister_)));
+ }
}
void DirectoryListingEntry::ResetLink() {
- UNIMPLEMENTED();
+ if ((link_ != NULL) && ((parent_ == NULL) || (parent_->link_ != link_))) {
+ delete link_;
+ link_ = NULL;
+ }
+ if (parent_ != NULL) {
+ link_ = parent_->link_;
+ }
}
« no previous file with comments | « no previous file | runtime/tests/vm/dart/hello_fuchsia_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698