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

Unified Diff: runtime/bin/directory_fuchsia.cc

Issue 2621093002: Fuchsia: Implement recursive delete (Closed)
Patch Set: Format Created 3 years, 11 months 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 9259bd019164403da02b95544835ac2cd9e01138..c9311712ced530c4dc2fb36186b764dbd91a13e2 100644
--- a/runtime/bin/directory_fuchsia.cc
+++ b/runtime/bin/directory_fuchsia.cc
@@ -126,91 +126,61 @@ ListType DirectoryListingEntry::Next(DirectoryListing* listing) {
done_ = true;
return kListError;
}
- switch (entry->d_type) {
- case DT_DIR:
+ // TODO(MG-450): When entry->d_type is filled out correctly, we can avoid
+ // this call to stat().
+ 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;
- 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;
+ }
+ 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;
}
}
done_ = true;
@@ -336,10 +306,7 @@ const char* Directory::CreateTemp(const char* prefix) {
// Pattern has overflowed.
return NULL;
}
- char* result;
- do {
- result = mkdtemp(path.AsString());
- } while ((result == NULL) && (errno == EINTR));
+ char* result = mkdtemp(path.AsString());
if (result == NULL) {
return NULL;
}
@@ -347,6 +314,98 @@ const char* Directory::CreateTemp(const char* prefix) {
}
+static bool DeleteRecursively(PathBuffer* path);
+
+
+static bool DeleteFile(char* file_name, PathBuffer* path) {
+ return path->Add(file_name) &&
+ (NO_RETRY_EXPECTED(unlink(path->AsString())) == 0);
+}
+
+
+static bool DeleteDir(char* dir_name, PathBuffer* path) {
+ if ((strcmp(dir_name, ".") == 0) || (strcmp(dir_name, "..") == 0)) {
+ return true;
+ }
+ return path->Add(dir_name) && DeleteRecursively(path);
+}
+
+
+static bool DeleteRecursively(PathBuffer* path) {
+ // Do not recurse into links for deletion. Instead delete the link.
+ // If it's a file, delete it.
+ struct stat64 st;
+ if (NO_RETRY_EXPECTED(lstat64(path->AsString(), &st)) == -1) {
+ return false;
+ } else if (!S_ISDIR(st.st_mode)) {
+ return NO_RETRY_EXPECTED(unlink(path->AsString())) == 0;
+ }
+
+ if (!path->Add(File::PathSeparator())) {
+ return false;
+ }
+
+ // Not a link. Attempt to open as a directory and recurse into the
+ // directory.
+ DIR* dir_pointer = opendir(path->AsString());
+ if (dir_pointer == NULL) {
+ return false;
+ }
+
+ // Iterate the directory and delete all files and directories.
+ int path_length = path->length();
+ while (true) {
+ // In case `readdir()` returns `NULL` we distinguish between end-of-stream
+ // and error by looking if `errno` was updated.
+ errno = 0;
+ // In glibc 2.24+, readdir_r is deprecated.
+ // According to the man page for readdir:
+ // "readdir(3) is not required to be thread-safe. However, in modern
+ // implementations (including the glibc implementation), concurrent calls to
+ // readdir(3) that specify different directory streams are thread-safe."
+ dirent* entry = readdir(dir_pointer);
+ if (entry == NULL) {
+ // Failed to read next directory entry.
+ if (errno != 0) {
+ break;
+ }
+ // End of directory.
+ return (NO_RETRY_EXPECTED(closedir(dir_pointer)) == 0) &&
+ (NO_RETRY_EXPECTED(remove(path->AsString())) == 0);
+ }
+ bool ok = false;
+ if (!path->Add(entry->d_name)) {
+ break;
+ }
+ // TODO(MG-450): When entry->d_type is filled out correctly, we can avoid
+ // this call to stat().
+ struct stat64 entry_info;
+ if (NO_RETRY_EXPECTED(lstat64(path->AsString(), &entry_info)) == -1) {
+ break;
+ }
+ path->Reset(path_length);
+ if (S_ISDIR(entry_info.st_mode)) {
+ ok = DeleteDir(entry->d_name, path);
+ } else {
+ // Treat links as files. This will delete the link which is
+ // what we want no matter if the link target is a file or a
+ // directory.
+ ok = DeleteFile(entry->d_name, path);
+ }
+ if (!ok) {
+ break;
+ }
+ path->Reset(path_length);
+ }
+ // Only happens if there was an error.
+ ASSERT(errno != 0);
+ int err = errno;
+ VOID_NO_RETRY_EXPECTED(closedir(dir_pointer));
+ errno = err;
+ return false;
+}
+
+
bool Directory::Delete(const char* dir_name, bool recursive) {
if (!recursive) {
if ((File::GetType(dir_name, false) == File::kIsLink) &&
@@ -355,10 +414,11 @@ bool Directory::Delete(const char* dir_name, bool recursive) {
}
return NO_RETRY_EXPECTED(rmdir(dir_name)) == 0;
} else {
- // TODO(MG-416): After the issue is addressed, this can use the same code
- // as on Linux, etc.
- UNIMPLEMENTED();
- return false;
+ PathBuffer path;
+ if (!path.Add(dir_name)) {
+ return false;
+ }
+ return DeleteRecursively(&path);
}
}
« 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