summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorthestig@chromium.org <thestig@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-06 21:23:07 +0000
committerthestig@chromium.org <thestig@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-06 21:23:07 +0000
commit49930c3ae4d0bb40b94cfde0425e8c825a526144 (patch)
tree010ee4721b79bdfd7a22ef0ff7efe56630582b39
parent6ae23b8bfb3ee39e3a158b4b83a2230dcfe06c45 (diff)
downloadchromium_src-49930c3ae4d0bb40b94cfde0425e8c825a526144.zip
chromium_src-49930c3ae4d0bb40b94cfde0425e8c825a526144.tar.gz
chromium_src-49930c3ae4d0bb40b94cfde0425e8c825a526144.tar.bz2
Define _FILE_OFFSET_BITS=64 in order to support large files (>2GB).
_FILE_OFFSET_BITS=64 is incompatible with fts (issue 17492), so file_util::Delete, file_util::CopyDirectory file_util::FileEnumerator are reimplemented without fts. Delete and CopyDirectory are now implemented using FileEnumerator. Patch from vandebo@google.com, original review: http://codereview.chromium.org/160479 BUG=13718,17492 TEST=none Review URL: http://codereview.chromium.org/165085 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@22670 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--base/file_util.h26
-rw-r--r--base/file_util_posix.cc382
-rw-r--r--base/test_file_util_posix.cc126
-rw-r--r--build/common.gypi1
4 files changed, 253 insertions, 282 deletions
diff --git a/base/file_util.h b/base/file_util.h
index 9e2636e7..71780f8 100644
--- a/base/file_util.h
+++ b/base/file_util.h
@@ -13,10 +13,7 @@
#if defined(OS_WIN)
#include <windows.h>
#elif defined(OS_POSIX)
-// Keep the order as in fts(3): fts.h requires types defined in sys/types.h
-#include <sys/types.h>
#include <sys/stat.h>
-#include <fts.h>
#endif
#include <stdio.h>
@@ -421,6 +418,9 @@ class FileEnumerator {
FILES = 1 << 0,
DIRECTORIES = 1 << 1,
INCLUDE_DOT_DOT = 1 << 2,
+#if defined(OS_POSIX)
+ SHOW_SYM_LINKS = 1 << 4,
+#endif
};
// |root_path| is the starting directory to search for. It may or may not end
@@ -485,8 +485,24 @@ class FileEnumerator {
WIN32_FIND_DATA find_data_;
HANDLE find_handle_;
#elif defined(OS_POSIX)
- FTS* fts_;
- FTSENT* fts_ent_;
+ typedef struct {
+ FilePath filename;
+ struct stat stat;
+ } DirectoryEntryInfo;
+
+ // Read the filenames in source into the vector of DirectoryEntryInfo's
+ static bool ReadDirectory(std::vector<DirectoryEntryInfo>* entries,
+ const FilePath& source, bool show_links);
+
+ // Comparison function to neatly sort directory entries
+ static bool CompareFiles(const DirectoryEntryInfo& a,
+ const DirectoryEntryInfo& b);
+
+ // The files in the current directory
+ std::vector<DirectoryEntryInfo> directory_entries_;
+
+ // The next entry to use from the directory_entries_ vector
+ size_t current_directory_entry_;
#endif
DISALLOW_EVIL_CONSTRUCTORS(FileEnumerator);
diff --git a/base/file_util_posix.cc b/base/file_util_posix.cc
index 6642eaa..fb5a7c4 100644
--- a/base/file_util_posix.cc
+++ b/base/file_util_posix.cc
@@ -8,7 +8,6 @@
#include <errno.h>
#include <fcntl.h>
#include <fnmatch.h>
-#include <fts.h>
#include <libgen.h>
#include <stdio.h>
#include <string.h>
@@ -35,19 +34,6 @@
namespace {
-bool IsDirectory(const FTSENT* file) {
- switch (file->fts_info) {
- case FTS_D:
- case FTS_DC:
- case FTS_DNR:
- case FTS_DOT:
- case FTS_DP:
- return true;
- default:
- return false;
- }
-}
-
class LocaleAwareComparator {
public:
LocaleAwareComparator() {
@@ -92,24 +78,6 @@ class LocaleAwareComparator {
DISALLOW_COPY_AND_ASSIGN(LocaleAwareComparator);
};
-int CompareFiles(const FTSENT** a, const FTSENT** b) {
- // Order lexicographically with directories before other files.
- const bool a_is_dir = IsDirectory(*a);
- const bool b_is_dir = IsDirectory(*b);
- if (a_is_dir != b_is_dir)
- return a_is_dir ? -1 : 1;
-
- // On linux, the file system encoding is not defined. We assume
- // SysNativeMBToWide takes care of it.
- //
- // ICU's collator can take strings in OS native encoding. But we convert the
- // strings to UTF-16 ourselves to ensure conversion consistency.
- // TODO(yuzo): Perhaps we should define SysNativeMBToUTF16?
- return Singleton<LocaleAwareComparator>()->Compare(
- WideToUTF16(base::SysNativeMBToWide((*a)->fts_name)),
- WideToUTF16(base::SysNativeMBToWide((*b)->fts_name)));
-}
-
} // namespace
namespace file_util {
@@ -146,6 +114,10 @@ int CountFilesCreatedAfter(const FilePath& path,
DIR* dir = opendir(path.value().c_str());
if (dir) {
+#if !defined(OS_LINUX) && !defined(OS_MACOSX)
+ #error Depending on the definition of struct dirent, additional space for \
+ pathname may be needed
+#endif
struct dirent ent_buf;
struct dirent* ent;
while (readdir_r(dir, &ent_buf, &ent) == 0 && ent) {
@@ -201,43 +173,28 @@ bool Delete(const FilePath& path, bool recursive) {
return (rmdir(path_str) == 0);
bool success = true;
- int ftsflags = FTS_PHYSICAL | FTS_NOSTAT;
- char top_dir[PATH_MAX];
- if (base::strlcpy(top_dir, path_str,
- arraysize(top_dir)) >= arraysize(top_dir)) {
- return false;
+ std::stack<std::string> directories;
+ directories.push(path.value());
+ FileEnumerator traversal(path, true, static_cast<FileEnumerator::FILE_TYPE>(
+ FileEnumerator::FILES | FileEnumerator::DIRECTORIES |
+ FileEnumerator::SHOW_SYM_LINKS));
+ for (FilePath current = traversal.Next(); success && !current.empty();
+ current = traversal.Next()) {
+ FileEnumerator::FindInfo info;
+ traversal.GetFindInfo(&info);
+
+ if (S_ISDIR(info.stat.st_mode))
+ directories.push(current.value());
+ else
+ success = (unlink(current.value().c_str()) == 0);
}
- char* dir_list[2] = { top_dir, NULL };
- FTS* fts = fts_open(dir_list, ftsflags, NULL);
- if (fts) {
- FTSENT* fts_ent = fts_read(fts);
- while (success && fts_ent != NULL) {
- switch (fts_ent->fts_info) {
- case FTS_DNR:
- case FTS_ERR:
- // log error
- success = false;
- continue;
- break;
- case FTS_DP:
- success = (rmdir(fts_ent->fts_accpath) == 0);
- break;
- case FTS_D:
- break;
- case FTS_NSOK:
- case FTS_F:
- case FTS_SL:
- case FTS_SLNONE:
- success = (unlink(fts_ent->fts_accpath) == 0);
- break;
- default:
- DCHECK(false);
- break;
- }
- fts_ent = fts_read(fts);
- }
- fts_close(fts);
+
+ while (success && !directories.empty()) {
+ FilePath dir = FilePath(directories.top());
+ directories.pop();
+ success = (rmdir(dir.value().c_str()) == 0);
}
+
return success;
}
@@ -272,92 +229,76 @@ bool CopyDirectory(const FilePath& from_path,
return false;
}
- char* dir_list[] = { top_dir, NULL };
- FTS* fts = fts_open(dir_list, FTS_PHYSICAL | FTS_NOSTAT, NULL);
- if (!fts) {
- LOG(ERROR) << "fts_open failed: " << strerror(errno);
+ // This function does not properly handle destinations within the source
+ FilePath real_to_path = to_path;
+ if (PathExists(real_to_path)) {
+ if (!AbsolutePath(&real_to_path))
+ return false;
+ } else {
+ real_to_path = real_to_path.DirName();
+ if (!AbsolutePath(&real_to_path))
+ return false;
+ }
+ FilePath real_from_path = from_path;
+ if (!AbsolutePath(&real_from_path))
+ return false;
+ if (real_to_path.value().size() >= real_from_path.value().size() &&
+ real_to_path.value().compare(0, real_from_path.value().size(),
+ real_from_path.value()) == 0)
return false;
+
+ bool success = true;
+ FileEnumerator::FILE_TYPE traverse_type =
+ static_cast<FileEnumerator::FILE_TYPE>(FileEnumerator::FILES |
+ FileEnumerator::SHOW_SYM_LINKS);
+ if (recursive)
+ traverse_type = static_cast<FileEnumerator::FILE_TYPE>(
+ traverse_type | FileEnumerator::DIRECTORIES);
+ FileEnumerator traversal(from_path, recursive, traverse_type);
+
+ // to_path may not exist yet, start the loop with to_path
+ FileEnumerator::FindInfo info;
+ FilePath current = from_path;
+ if (stat(from_path.value().c_str(), &info.stat) < 0) {
+ LOG(ERROR) << "CopyDirectory() couldn't stat source directory: " <<
+ from_path.value() << " errno = " << errno;
+ success = false;
}
- int error = 0;
- FTSENT* ent;
- while (!error && (ent = fts_read(fts)) != NULL) {
- // ent->fts_path is the source path, including from_path, so paste
+ while (success && !current.empty()) {
+ // current is the source path, including from_path, so paste
// the suffix after from_path onto to_path to create the target_path.
- std::string suffix(&ent->fts_path[from_path.value().size()]);
+ std::string suffix(&current.value().c_str()[from_path.value().size()]);
// Strip the leading '/' (if any).
if (!suffix.empty()) {
DCHECK_EQ('/', suffix[0]);
suffix.erase(0, 1);
}
const FilePath target_path = to_path.Append(suffix);
- switch (ent->fts_info) {
- case FTS_D: // Preorder directory.
- // If we encounter a subdirectory in a non-recursive copy, prune it
- // from the traversal.
- if (!recursive && ent->fts_level > 0) {
- if (fts_set(fts, ent, FTS_SKIP) != 0)
- error = errno;
- continue;
- }
-
- // Try creating the target dir, continuing on it if it exists already.
- if (mkdir(target_path.value().c_str(), 0700) != 0) {
- if (errno != EEXIST)
- error = errno;
- }
- break;
- case FTS_F: // Regular file.
- case FTS_NSOK: // File, no stat info requested.
- errno = 0;
- if (!CopyFile(FilePath(ent->fts_path), target_path))
- error = errno ? errno : EINVAL;
- break;
- case FTS_DP: // Postorder directory.
- case FTS_DOT: // "." or ".."
- // Skip it.
- continue;
- case FTS_DC: // Directory causing a cycle.
- // Skip this branch.
- if (fts_set(fts, ent, FTS_SKIP) != 0)
- error = errno;
- break;
- case FTS_DNR: // Directory cannot be read.
- case FTS_ERR: // Error.
- case FTS_NS: // Stat failed.
- // Abort with the error.
- error = ent->fts_errno;
- break;
- case FTS_SL: // Symlink.
- case FTS_SLNONE: // Symlink with broken target.
- LOG(WARNING) << "CopyDirectory() skipping symbolic link: " <<
- ent->fts_path;
- continue;
- case FTS_DEFAULT: // Some other sort of file.
- LOG(WARNING) << "CopyDirectory() skipping file of unknown type: " <<
- ent->fts_path;
- continue;
- default:
- NOTREACHED();
- continue; // Hope for the best!
+
+ if (S_ISDIR(info.stat.st_mode)) {
+ if (mkdir(target_path.value().c_str(), info.stat.st_mode & 01777) != 0 &&
+ errno != EEXIST) {
+ LOG(ERROR) << "CopyDirectory() couldn't create directory: " <<
+ target_path.value() << " errno = " << errno;
+ success = false;
+ }
+ } else if (S_ISREG(info.stat.st_mode)) {
+ if (!CopyFile(current, target_path)) {
+ LOG(ERROR) << "CopyDirectory() couldn't create file: " <<
+ target_path.value();
+ success = false;
+ }
+ } else {
+ LOG(WARNING) << "CopyDirectory() skipping non-regular file: " <<
+ current.value();
}
- }
- // fts_read may have returned NULL and set errno to indicate an error.
- if (!error && errno != 0)
- error = errno;
-
- if (!fts_close(fts)) {
- // If we already have an error, let's use that error instead of the error
- // fts_close set.
- if (!error)
- error = errno;
- }
- if (error) {
- LOG(ERROR) << "CopyDirectory(): " << strerror(error);
- return false;
+ current = traversal.Next();
+ traversal.GetFindInfo(&info);
}
- return true;
+
+ return success;
}
bool PathExists(const FilePath& path) {
@@ -602,10 +543,11 @@ bool SetCurrentDirectory(const FilePath& path) {
FileEnumerator::FileEnumerator(const FilePath& root_path,
bool recursive,
FileEnumerator::FILE_TYPE file_type)
- : recursive_(recursive),
+ : root_path_(root_path),
+ recursive_(recursive),
file_type_(file_type),
is_in_find_op_(false),
- fts_(NULL) {
+ current_directory_entry_(0) {
// INCLUDE_DOT_DOT must not be specified if recursive.
DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_)));
pending_paths_.push(root_path);
@@ -615,101 +557,131 @@ FileEnumerator::FileEnumerator(const FilePath& root_path,
bool recursive,
FileEnumerator::FILE_TYPE file_type,
const FilePath::StringType& pattern)
- : recursive_(recursive),
+ : root_path_(root_path),
+ recursive_(recursive),
file_type_(file_type),
- pattern_(root_path.value()),
+ pattern_(root_path.Append(pattern)),
is_in_find_op_(false),
- fts_(NULL) {
+ current_directory_entry_(0) {
// INCLUDE_DOT_DOT must not be specified if recursive.
DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_)));
- // The Windows version of this code only matches against items in the top-most
- // directory, and we're comparing fnmatch against full paths, so this is the
- // easiest way to get the right pattern.
- pattern_ = pattern_.Append(pattern);
+ // The Windows version of this code appends the pattern to the root_path,
+ // potentially only matching against items in the top-most directory.
+ // Do the same here.
+ if (pattern.size() == 0)
+ pattern_ = FilePath();
pending_paths_.push(root_path);
}
FileEnumerator::~FileEnumerator() {
- if (fts_)
- fts_close(fts_);
}
void FileEnumerator::GetFindInfo(FindInfo* info) {
DCHECK(info);
- if (!is_in_find_op_)
+ if (current_directory_entry_ >= directory_entries_.size())
return;
- memcpy(&(info->stat), fts_ent_->fts_statp, sizeof(info->stat));
- info->filename.assign(fts_ent_->fts_name);
+ DirectoryEntryInfo* cur_entry = &directory_entries_[current_directory_entry_];
+ memcpy(&(info->stat), &(cur_entry->stat), sizeof(info->stat));
+ info->filename.assign(cur_entry->filename.value());
}
-// As it stands, this method calls itself recursively when the next item of
-// the fts enumeration doesn't match (type, pattern, etc.). In the case of
-// large directories with many files this can be quite deep.
-// TODO(erikkay) - get rid of this recursive pattern
FilePath FileEnumerator::Next() {
- if (!is_in_find_op_) {
+ ++current_directory_entry_;
+
+ // While we've exhausted the entries in the current directory, do the next
+ while (current_directory_entry_ >= directory_entries_.size()) {
if (pending_paths_.empty())
return FilePath();
- // The last find FindFirstFile operation is done, prepare a new one.
root_path_ = pending_paths_.top();
root_path_ = root_path_.StripTrailingSeparators();
pending_paths_.pop();
- // Start a new find operation.
- int ftsflags = FTS_LOGICAL | FTS_SEEDOT;
- char top_dir[PATH_MAX];
- base::strlcpy(top_dir, root_path_.value().c_str(), arraysize(top_dir));
- char* dir_list[2] = { top_dir, NULL };
- fts_ = fts_open(dir_list, ftsflags, CompareFiles);
- if (!fts_)
- return Next();
- is_in_find_op_ = true;
- }
+ std::vector<DirectoryEntryInfo> entries;
+ if (!ReadDirectory(&entries, root_path_, file_type_ & SHOW_SYM_LINKS))
+ continue;
- fts_ent_ = fts_read(fts_);
- if (fts_ent_ == NULL) {
- fts_close(fts_);
- fts_ = NULL;
- is_in_find_op_ = false;
- return Next();
- }
+ // The API says that order is not guaranteed, but order affects UX
+ std::sort(entries.begin(), entries.end(), CompareFiles);
+
+ directory_entries_.clear();
+ current_directory_entry_ = 0;
+ for (std::vector<DirectoryEntryInfo>::const_iterator
+ i = entries.begin(); i != entries.end(); ++i) {
+ FilePath full_path = root_path_.Append(i->filename);
+ if (ShouldSkip(full_path))
+ continue;
- // Level 0 is the top, which is always skipped.
- if (fts_ent_->fts_level == 0)
- return Next();
-
- // Patterns are only matched on the items in the top-most directory.
- // (see Windows implementation)
- if (fts_ent_->fts_level == 1 && pattern_.value().length() > 0) {
- if (fnmatch(pattern_.value().c_str(), fts_ent_->fts_path, 0) != 0) {
- if (fts_ent_->fts_info == FTS_D)
- fts_set(fts_, fts_ent_, FTS_SKIP);
- return Next();
+ if (pattern_.value().size() &&
+ fnmatch(pattern_.value().c_str(), full_path.value().c_str(),
+ FNM_NOESCAPE))
+ continue;
+
+ if (recursive_ && S_ISDIR(i->stat.st_mode))
+ pending_paths_.push(full_path);
+
+ if ((S_ISDIR(i->stat.st_mode) && (file_type_ & DIRECTORIES)) ||
+ (!S_ISDIR(i->stat.st_mode) && (file_type_ & FILES)))
+ directory_entries_.push_back(*i);
}
}
- FilePath cur_file(fts_ent_->fts_path);
- if (ShouldSkip(cur_file))
- return Next();
-
- if (fts_ent_->fts_info == FTS_D) {
- // If not recursive, then prune children.
- if (!recursive_)
- fts_set(fts_, fts_ent_, FTS_SKIP);
- return (file_type_ & FileEnumerator::DIRECTORIES) ? cur_file : Next();
- } else if (fts_ent_->fts_info == FTS_F) {
- return (file_type_ & FileEnumerator::FILES) ? cur_file : Next();
- } else if (fts_ent_->fts_info == FTS_DOT) {
- if ((file_type_ & FileEnumerator::DIRECTORIES) && IsDotDot(cur_file)) {
- return cur_file;
+ return root_path_.Append(directory_entries_[current_directory_entry_
+ ].filename);
+}
+
+bool FileEnumerator::ReadDirectory(std::vector<DirectoryEntryInfo>* entries,
+ const FilePath& source, bool show_links) {
+ DIR* dir = opendir(source.value().c_str());
+ if (!dir)
+ return false;
+
+#if !defined(OS_LINUX) && !defined(OS_MACOSX)
+ #error Depending on the definition of struct dirent, additional space for \
+ pathname may be needed
+#endif
+ struct dirent dent_buf;
+ struct dirent* dent;
+ while (readdir_r(dir, &dent_buf, &dent) == 0 && dent) {
+ DirectoryEntryInfo info;
+ FilePath full_name;
+ int stat_value;
+
+ info.filename = FilePath(dent->d_name);
+ full_name = source.Append(dent->d_name);
+ if (show_links)
+ stat_value = lstat(full_name.value().c_str(), &info.stat);
+ else
+ stat_value = stat(full_name.value().c_str(), &info.stat);
+ if (stat_value < 0) {
+ LOG(ERROR) << "Couldn't stat file: " <<
+ source.Append(dent->d_name).value().c_str() << " errno = " << errno;
+ memset(&info.stat, 0, sizeof(info.stat));
}
- return Next();
+ entries->push_back(info);
}
- // TODO(erikkay) - verify that the other fts_info types aren't interesting
- return Next();
+
+ closedir(dir);
+ return true;
+}
+
+bool FileEnumerator::CompareFiles(const DirectoryEntryInfo& a,
+ const DirectoryEntryInfo& b) {
+ // Order lexicographically with directories before other files.
+ if (S_ISDIR(a.stat.st_mode) != S_ISDIR(b.stat.st_mode))
+ return S_ISDIR(a.stat.st_mode);
+
+ // On linux, the file system encoding is not defined. We assume
+ // SysNativeMBToWide takes care of it.
+ //
+ // ICU's collator can take strings in OS native encoding. But we convert the
+ // strings to UTF-16 ourselves to ensure conversion consistency.
+ // TODO(yuzo): Perhaps we should define SysNativeMBToUTF16?
+ return Singleton<LocaleAwareComparator>()->Compare(
+ WideToUTF16(base::SysNativeMBToWide(a.filename.value().c_str())),
+ WideToUTF16(base::SysNativeMBToWide(b.filename.value().c_str()))) < 0;
}
///////////////////////////////////////////////
diff --git a/base/test_file_util_posix.cc b/base/test_file_util_posix.cc
index 66eb8a3..122dd04 100644
--- a/base/test_file_util_posix.cc
+++ b/base/test_file_util_posix.cc
@@ -5,7 +5,6 @@
#include "base/test_file_util.h"
#include <errno.h>
-#include <fts.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -24,6 +23,7 @@ bool DieFileDie(const FilePath& file, bool recurse) {
return file_util::Delete(file, recurse);
}
+// Mostly a verbatim copy of CopyDirectory
bool CopyRecursiveDirNoCache(const std::wstring& source_dir,
const std::wstring& dest_dir) {
const FilePath from_path(FilePath::FromWStringHack(source_dir));
@@ -35,90 +35,72 @@ bool CopyRecursiveDirNoCache(const std::wstring& source_dir,
return false;
}
- char* dir_list[] = { top_dir, NULL };
- FTS* fts = fts_open(dir_list, FTS_PHYSICAL | FTS_NOSTAT, NULL);
- if (!fts) {
- LOG(ERROR) << "fts_open failed: " << strerror(errno);
+ // This function does not properly handle destinations within the source
+ FilePath real_to_path = to_path;
+ if (PathExists(real_to_path)) {
+ if (!AbsolutePath(&real_to_path))
+ return false;
+ } else {
+ real_to_path = real_to_path.DirName();
+ if (!AbsolutePath(&real_to_path))
+ return false;
+ }
+ if (real_to_path.value().compare(0, from_path.value().size(),
+ from_path.value()) == 0)
return false;
+
+ bool success = true;
+ FileEnumerator::FILE_TYPE traverse_type =
+ static_cast<FileEnumerator::FILE_TYPE>(FileEnumerator::FILES |
+ FileEnumerator::SHOW_SYM_LINKS | FileEnumerator::DIRECTORIES);
+ FileEnumerator traversal(from_path, true, traverse_type);
+
+ // to_path may not exist yet, start the loop with to_path
+ FileEnumerator::FindInfo info;
+ FilePath current = from_path;
+ if (stat(from_path.value().c_str(), &info.stat) < 0) {
+ LOG(ERROR) << "CopyRecursiveDirNoCache() couldn't stat source directory: "
+ << from_path.value() << " errno = " << errno;
+ success = false;
}
- int error = 0;
- FTSENT* ent;
- while (!error && (ent = fts_read(fts)) != NULL) {
- // ent->fts_path is the source path, including from_path, so paste
+ while (success && !current.empty()) {
+ // current is the source path, including from_path, so paste
// the suffix after from_path onto to_path to create the target_path.
- std::string suffix(&ent->fts_path[from_path.value().size()]);
+ std::string suffix(&current.value().c_str()[from_path.value().size()]);
// Strip the leading '/' (if any).
if (!suffix.empty()) {
DCHECK_EQ('/', suffix[0]);
suffix.erase(0, 1);
}
const FilePath target_path = to_path.Append(suffix);
- switch (ent->fts_info) {
- case FTS_D: // Preorder directory.
- // Try creating the target dir, continuing on it if it exists already.
- // Rely on the user's umask to produce correct permissions.
- if (mkdir(target_path.value().c_str(), 0777) != 0) {
- if (errno != EEXIST)
- error = errno;
- }
- break;
- case FTS_F: // Regular file.
- case FTS_NSOK: // File, no stat info requested.
- {
- errno = 0;
- FilePath source_path(ent->fts_path);
- if (CopyFile(source_path, target_path)) {
- bool success = EvictFileFromSystemCache(target_path);
- DCHECK(success);
- } else {
- error = errno ? errno : EINVAL;
- }
- }
- break;
- case FTS_DP: // Postorder directory.
- case FTS_DOT: // "." or ".."
- // Skip it.
- continue;
- case FTS_DC: // Directory causing a cycle.
- // Skip this branch.
- if (fts_set(fts, ent, FTS_SKIP) != 0)
- error = errno;
- break;
- case FTS_DNR: // Directory cannot be read.
- case FTS_ERR: // Error.
- case FTS_NS: // Stat failed.
- // Abort with the error.
- error = ent->fts_errno;
- break;
- case FTS_SL: // Symlink.
- case FTS_SLNONE: // Symlink with broken target.
- LOG(WARNING) << "skipping symbolic link: " << ent->fts_path;
- continue;
- case FTS_DEFAULT: // Some other sort of file.
- LOG(WARNING) << "skipping file of unknown type: " << ent->fts_path;
- continue;
- default:
- NOTREACHED();
- continue; // Hope for the best!
+
+ if (S_ISDIR(info.stat.st_mode)) {
+ if (mkdir(target_path.value().c_str(), info.stat.st_mode & 01777) != 0 &&
+ errno != EEXIST) {
+ LOG(ERROR) << "CopyRecursiveDirNoCache() couldn't create directory: " <<
+ target_path.value() << " errno = " << errno;
+ success = false;
+ }
+ } else if (S_ISREG(info.stat.st_mode)) {
+ if (CopyFile(current, target_path)) {
+ success = EvictFileFromSystemCache(target_path);
+ DCHECK(success);
+ } else {
+ LOG(ERROR) << "CopyRecursiveDirNoCache() couldn't create file: " <<
+ target_path.value();
+ success = false;
+ }
+ } else {
+ LOG(WARNING) << "CopyRecursiveDirNoCache() skipping non-regular file: " <<
+ current.value();
}
- }
- // fts_read may have returned NULL and set errno to indicate an error.
- if (!error && errno != 0)
- error = errno;
-
- if (!fts_close(fts)) {
- // If we already have an error, let's use that error instead of the error
- // fts_close set.
- if (!error)
- error = errno;
- }
- if (error) {
- LOG(ERROR) << strerror(error);
- return false;
+ current = traversal.Next();
+ traversal.GetFindInfo(&info);
}
- return true;
+
+ return success;
}
} // namespace file_util
diff --git a/build/common.gypi b/build/common.gypi
index 13178ba..9212844 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -342,6 +342,7 @@
'-pthread',
'-fno-exceptions',
'-Wall',
+ '-D_FILE_OFFSET_BITS=64',
],
'cflags_cc': [
'-fno-threadsafe-statics',