summaryrefslogtreecommitdiffstats
path: root/base/file_util_posix.cc
diff options
context:
space:
mode:
authorerikkay@google.com <erikkay@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-08-15 17:32:10 +0000
committererikkay@google.com <erikkay@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-08-15 17:32:10 +0000
commit37088fefa67704ad6f18e1e72e2e6292ba48ee1b (patch)
treeef54e2c068b1a63dfe29b01fb59af6e1148d16d3 /base/file_util_posix.cc
parente87ce0ff4a37f8e5bd0e4d7938bcf93b66d29ec9 (diff)
downloadchromium_src-37088fefa67704ad6f18e1e72e2e6292ba48ee1b.zip
chromium_src-37088fefa67704ad6f18e1e72e2e6292ba48ee1b.tar.gz
chromium_src-37088fefa67704ad6f18e1e72e2e6292ba48ee1b.tar.bz2
Part two of file_util porting. Almost all of the functionality has been ported, including the unit tests now. Some of this API isn't great, and should be cleaned up, but I'd like to hold off and do that in a followup changelist. More general code cleanup is likely needed here as well.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@944 0039d316-1c4b-4281-b951-d872f2087c98
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