summaryrefslogtreecommitdiffstats
path: root/base/file_util_posix.cc
diff options
context:
space:
mode:
Diffstat (limited to 'base/file_util_posix.cc')
-rw-r--r--base/file_util_posix.cc219
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