diff options
Diffstat (limited to 'base/file_util_posix.cc')
-rw-r--r-- | base/file_util_posix.cc | 219 |
1 files changed, 138 insertions, 81 deletions
diff --git a/base/file_util_posix.cc b/base/file_util_posix.cc index 4f77e94..4f75c8a 100644 --- a/base/file_util_posix.cc +++ b/base/file_util_posix.cc @@ -29,10 +29,13 @@ #include "base/file_util.h" -#include <sys/stat.h> -#include <sys/syslimits.h> #include <fcntl.h> +#include <fnmatch.h> +#include <fts.h> #include <libgen.h> +#include <sys/errno.h> +#include <sys/stat.h> +#include <sys/syslimits.h> #include <time.h> #include <fstream> @@ -44,28 +47,79 @@ namespace file_util { std::wstring GetDirectoryFromPath(const std::wstring& path) { - char full_path[PATH_MAX]; - base::strlcpy(full_path, WideToUTF8(path).c_str(), arraysize(full_path)); - return UTF8ToWide(dirname(full_path)); + if (EndsWithSeparator(path)) { + std::wstring dir = path; + TrimTrailingSeparator(&dir); + return dir; + } else { + char full_path[PATH_MAX]; + base::strlcpy(full_path, WideToUTF8(path).c_str(), arraysize(full_path)); + return UTF8ToWide(dirname(full_path)); + } } bool AbsolutePath(std::wstring* path) { - return ResolveShortcut(path); + char full_path[PATH_MAX]; + if (realpath(WideToUTF8(*path).c_str(), full_path) == NULL) + return false; + *path = UTF8ToWide(full_path); + return true; } +// TODO(erikkay): The Windows version of this accepts paths like "foo/bar/*" +// which works both with and without the recursive flag. I'm not sure we need +// that functionality. If not, remove from file_util_win.cc, otherwise add it +// here. bool Delete(const std::wstring& path, bool recursive) { - std::string utf8_path = WideToUTF8(path); + const char* utf8_path = WideToUTF8(path).c_str(); struct stat64 file_info; - if (stat64(utf8_path.c_str(), &file_info) != 0); - return false; + int test = stat64(utf8_path, &file_info); + if (test != 0) { + // The Windows version defines this condition as success. + bool ret = (errno == ENOENT || errno == ENOTDIR); + return ret; + } if (!S_ISDIR(file_info.st_mode)) - return (unlink(utf8_path.c_str()) == 0); + return (unlink(utf8_path) == 0); if (!recursive) - return (rmdir(utf8_path.c_str()) == 0); + return (rmdir(utf8_path) == 0); - // TODO(erikkay): delete directories - DCHECK(recursive); - return false; + bool success = true; + int ftsflags = FTS_PHYSICAL | FTS_NOSTAT; + char top_dir[PATH_MAX]; + base::strlcpy(top_dir, utf8_path, sizeof(top_dir)); + 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: + rmdir(fts_ent->fts_accpath); + break; + case FTS_D: + break; + case FTS_NSOK: + case FTS_F: + case FTS_SL: + case FTS_SLNONE: + unlink(fts_ent->fts_accpath); + break; + default: + DCHECK(false); + break; + } + fts_ent = fts_read(fts); + } + fts_close(fts); + } + return success; } bool Move(const std::wstring& from_path, const std::wstring& to_path) { @@ -111,30 +165,18 @@ bool GetFileCreationLocalTime(const std::string& filename, } #endif -bool ResolveShortcut(std::wstring* path) { - char full_path[PATH_MAX]; - if (!realpath(WideToUTF8(*path).c_str(), full_path)) - return false; - *path = UTF8ToWide(full_path); - return true; -} - -bool CreateShortcutLink(const char *source, const char *destination, - const char *working_dir, const char *arguments, - const char *description, const char *icon, - int icon_index) { - // TODO(erikkay): implement - return false; -} - bool CreateTemporaryFileName(std::wstring* temp_file) { std::wstring tmpdir; if (!GetTempDir(&tmpdir)) return false; - tmpdir.append(L"/com.google.chrome.XXXXXX"); + tmpdir.append(L"com.google.chrome.XXXXXX"); // this should be OK since mktemp just replaces characters in place char* buffer = const_cast<char*>(WideToUTF8(tmpdir).c_str()); *temp_file = UTF8ToWide(mktemp(buffer)); + int fd = open(buffer, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (fd < 0) + return false; + close(fd); return true; } @@ -154,7 +196,21 @@ bool CreateNewTempDirectory(const std::wstring& prefix, } bool CreateDirectory(const std::wstring& full_path) { - return (mkdir(WideToUTF8(full_path).c_str(), 0777) == 0); + std::vector<std::wstring> components; + PathComponents(full_path, &components); + std::wstring path; + std::vector<std::wstring>::iterator i = components.begin(); + for (; i != components.end(); ++i) { + if (path.length() == 0) + path = *i; + else + AppendToPath(&path, *i); + if (!PathExists(path)) { + if (mkdir(WideToUTF8(path).c_str(), 0777) != 0) + return false; + } + } + return true; } bool GetFileSize(const std::wstring& file_path, int64* file_size) { @@ -200,96 +256,97 @@ bool SetCurrentDirectory(const std::wstring& current_directory) { return (ret == 0); } -// TODO(erikkay): implement -#if 0 -FileEnumerator::FileEnumerator(const std::string& root_path, +FileEnumerator::FileEnumerator(const std::wstring& root_path, bool recursive, FileEnumerator::FILE_TYPE file_type) : recursive_(recursive), file_type_(file_type), is_in_find_op_(false), - find_handle_(INVALID_HANDLE_VALUE) { + fts_(NULL) { pending_paths_.push(root_path); } -FileEnumerator::FileEnumerator(const std::string& root_path, +FileEnumerator::FileEnumerator(const std::wstring& root_path, bool recursive, FileEnumerator::FILE_TYPE file_type, - const std::string& pattern) + const std::wstring& pattern) : recursive_(recursive), file_type_(file_type), + pattern_(root_path), is_in_find_op_(false), - pattern_(pattern), - find_handle_(INVALID_HANDLE_VALUE) { + fts_(NULL) { + // 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. + AppendToPath(&pattern_, pattern); pending_paths_.push(root_path); } - + FileEnumerator::~FileEnumerator() { - if (find_handle_ != INVALID_HANDLE_VALUE) - FindClose(find_handle_); + if (fts_) + fts_close(fts_); } +// 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 std::wstring FileEnumerator::Next() { if (!is_in_find_op_) { if (pending_paths_.empty()) return std::wstring(); // The last find FindFirstFile operation is done, prepare a new one. - // root_path_ must have the trailing directory character. root_path_ = pending_paths_.top(); - file_util::AppendToPath(&root_path_, std::wstring()); + TrimTrailingSeparator(&root_path_); pending_paths_.pop(); // Start a new find operation. - std::wstring src(root_path_); - - if (pattern_.empty()) - file_util::AppendToPath(&src, "*"); // No pattern = match everything. - else - file_util::AppendToPath(&src, pattern_); - - find_handle_ = FindFirstFile(src.c_str(), &find_data_); + int ftsflags = FTS_LOGICAL; + char top_dir[PATH_MAX]; + base::strlcpy(top_dir, WideToUTF8(root_path_).c_str(), sizeof(top_dir)); + char* dir_list[2] = { top_dir, NULL }; + fts_ = fts_open(dir_list, ftsflags, NULL); + if (!fts_) + return Next(); is_in_find_op_ = true; - - } else { - // Search for the next file/directory. - if (!FindNextFile(find_handle_, &find_data_)) { - FindClose(find_handle_); - find_handle_ = INVALID_HANDLE_VALUE; - } } - if (INVALID_HANDLE_VALUE == find_handle_) { + FTSENT* fts_ent = fts_read(fts_); + if (fts_ent == NULL) { + fts_close(fts_); + fts_ = NULL; is_in_find_op_ = false; - - // This is reached when we have finished a directory and are advancing to - // the next one in the queue. We applied the pattern (if any) to the files - // in the root search directory, but for those directories which were - // matched, we want to enumerate all files inside them. This will happen - // when the handle is empty. - pattern_.clear(); - return Next(); } - std::wstring cur_file(find_data_.cFileName); - // Skip over . and .. - if (L"." == cur_file || L".." == cur_file) + // Level 0 is the top, which is always skipped. + if (fts_ent->fts_level == 0) return Next(); - // Construct the absolute filename. - cur_file.insert(0, root_path_); + // Patterns are only matched on the items in the top-most directory. + // (see Windows implementation) + if (fts_ent->fts_level == 1 && pattern_.length() > 0) { + const char* utf8_pattern = WideToUTF8(pattern_).c_str(); + if (fnmatch(utf8_pattern, fts_ent->fts_path, 0) != 0) { + if (fts_ent->fts_info == FTS_D) + fts_set(fts_, fts_ent, FTS_SKIP); + return Next(); + } + } - if (recursive_ && find_data_.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - // If |cur_file| is a directory, and we are doing recursive searching, add - // it to pending_paths_ so we scan it after we finish scanning this - // directory. - pending_paths_.push(cur_file); + std::wstring cur_file(UTF8ToWide(fts_ent->fts_path)); + 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(); } - return (file_type_ & FileEnumerator::FILES) ? cur_file : Next(); + // TODO(erikkay) - verify that the other fts_info types aren't interesting + return Next(); } -#endif } // namespace file_util |