mirror of
https://github.com/chromium/crashpad.git
synced 2024-12-26 23:01:05 +08:00
Add MoveFileOrDirectory to move files, directories, or symbolic links
Change-Id: I6eaeef0dc3ec4300b361c1a96d14209aec736ff0 Reviewed-on: https://chromium-review.googlesource.com/727567 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org>
This commit is contained in:
parent
419f25eac8
commit
ce084d37c8
@ -35,6 +35,31 @@ bool LoggingCreateDirectory(const base::FilePath& path,
|
||||
FilePermissions permissions,
|
||||
bool may_reuse);
|
||||
|
||||
//! \brief Moves a file, symbolic link, or directory, logging a message on
|
||||
//! failure.
|
||||
//!
|
||||
//! \a source must exist and refer to a file, symbolic link, or directory.
|
||||
//!
|
||||
//! \a source and \a dest must be on the same filesystem.
|
||||
//!
|
||||
//! If \a dest exists, it may be overwritten:
|
||||
//!
|
||||
//! If \a dest exists and refers to a file or to a live or dangling symbolic
|
||||
//! link to a file, it will be overwritten if \a source also refers to a file or
|
||||
//! to a live or dangling symbolic link to a file or directory.
|
||||
//!
|
||||
//! On POSIX, if \a dest refers to a directory, it will be overwritten only if
|
||||
//! it is empty and \a source also refers to a directory.
|
||||
//!
|
||||
//! On Windows, if \a dest refers to a directory or to a live or dangling
|
||||
//! symbolic link to a directory, it will not be overwritten.
|
||||
//!
|
||||
//! \param[in] source The path to the file to be moved.
|
||||
//! \param[in] dest The new path for the file.
|
||||
//! \return `true` on success. `false` on failure with a message logged.
|
||||
bool MoveFileOrDirectory(const base::FilePath& source,
|
||||
const base::FilePath& dest);
|
||||
|
||||
//! \brief Determines if a path refers to a regular file, logging a message on
|
||||
//! failure.
|
||||
//!
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "util/file/filesystem.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
@ -42,6 +43,16 @@ bool LoggingCreateDirectory(const base::FilePath& path,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MoveFileOrDirectory(const base::FilePath& source,
|
||||
const base::FilePath& dest) {
|
||||
if (rename(source.value().c_str(), dest.value().c_str()) != 0) {
|
||||
PLOG(ERROR) << "rename " << source.value().c_str() << ", "
|
||||
<< dest.value().c_str();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsRegularFile(const base::FilePath& path) {
|
||||
struct stat st;
|
||||
if (lstat(path.value().c_str(), &st) != 0) {
|
||||
|
@ -16,7 +16,6 @@
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "test/file.h"
|
||||
#include "test/scoped_temp_dir.h"
|
||||
#include "util/file/filesystem_test_util.h"
|
||||
|
||||
@ -45,6 +44,110 @@ TEST(Filesystem, CreateDirectory) {
|
||||
EXPECT_TRUE(IsRegularFile(file));
|
||||
}
|
||||
|
||||
TEST(Filesystem, MoveFileOrDirectory) {
|
||||
ScopedTempDir temp_dir;
|
||||
|
||||
base::FilePath file(temp_dir.path().Append(FILE_PATH_LITERAL("file")));
|
||||
ASSERT_TRUE(CreateFile(file));
|
||||
|
||||
// empty paths
|
||||
EXPECT_FALSE(MoveFileOrDirectory(base::FilePath(), base::FilePath()));
|
||||
EXPECT_FALSE(MoveFileOrDirectory(base::FilePath(), file));
|
||||
EXPECT_FALSE(MoveFileOrDirectory(file, base::FilePath()));
|
||||
EXPECT_TRUE(IsRegularFile(file));
|
||||
|
||||
// files
|
||||
base::FilePath file2(temp_dir.path().Append(FILE_PATH_LITERAL("file2")));
|
||||
EXPECT_TRUE(MoveFileOrDirectory(file, file2));
|
||||
EXPECT_TRUE(IsRegularFile(file2));
|
||||
EXPECT_FALSE(IsRegularFile(file));
|
||||
|
||||
EXPECT_FALSE(MoveFileOrDirectory(file, file2));
|
||||
EXPECT_TRUE(IsRegularFile(file2));
|
||||
EXPECT_FALSE(IsRegularFile(file));
|
||||
|
||||
ASSERT_TRUE(CreateFile(file));
|
||||
EXPECT_TRUE(MoveFileOrDirectory(file2, file));
|
||||
EXPECT_TRUE(IsRegularFile(file));
|
||||
EXPECT_FALSE(IsRegularFile(file2));
|
||||
|
||||
// directories
|
||||
base::FilePath dir(temp_dir.path().Append(FILE_PATH_LITERAL("dir")));
|
||||
ASSERT_TRUE(
|
||||
LoggingCreateDirectory(dir, FilePermissions::kWorldReadable, false));
|
||||
|
||||
base::FilePath nested(dir.Append(FILE_PATH_LITERAL("nested")));
|
||||
ASSERT_TRUE(CreateFile(nested));
|
||||
|
||||
base::FilePath dir2(temp_dir.path().Append(FILE_PATH_LITERAL("dir2")));
|
||||
EXPECT_TRUE(MoveFileOrDirectory(dir, dir2));
|
||||
EXPECT_FALSE(IsDirectory(dir, true));
|
||||
EXPECT_TRUE(IsDirectory(dir2, false));
|
||||
EXPECT_TRUE(IsRegularFile(dir2.Append(nested.BaseName())));
|
||||
|
||||
ASSERT_TRUE(
|
||||
LoggingCreateDirectory(dir, FilePermissions::kWorldReadable, false));
|
||||
EXPECT_FALSE(MoveFileOrDirectory(dir, dir2));
|
||||
EXPECT_TRUE(IsDirectory(dir, false));
|
||||
EXPECT_TRUE(IsDirectory(dir2, false));
|
||||
EXPECT_TRUE(IsRegularFile(dir2.Append(nested.BaseName())));
|
||||
|
||||
// files <-> directories
|
||||
EXPECT_FALSE(MoveFileOrDirectory(file, dir2));
|
||||
EXPECT_TRUE(IsDirectory(dir2, false));
|
||||
EXPECT_TRUE(IsRegularFile(file));
|
||||
|
||||
EXPECT_FALSE(MoveFileOrDirectory(dir2, file));
|
||||
EXPECT_TRUE(IsDirectory(dir2, false));
|
||||
EXPECT_TRUE(IsRegularFile(file));
|
||||
|
||||
// file links
|
||||
base::FilePath link(temp_dir.path().Append(FILE_PATH_LITERAL("link")));
|
||||
ASSERT_TRUE(CreateSymbolicLink(file, link));
|
||||
|
||||
base::FilePath link2(temp_dir.path().Append(FILE_PATH_LITERAL("link2")));
|
||||
EXPECT_TRUE(MoveFileOrDirectory(link, link2));
|
||||
EXPECT_TRUE(PathExists(link2));
|
||||
EXPECT_FALSE(PathExists(link));
|
||||
|
||||
ASSERT_TRUE(CreateSymbolicLink(file, link));
|
||||
EXPECT_TRUE(MoveFileOrDirectory(link, link2));
|
||||
EXPECT_TRUE(PathExists(link2));
|
||||
EXPECT_FALSE(PathExists(link));
|
||||
|
||||
// file links <-> files
|
||||
EXPECT_TRUE(MoveFileOrDirectory(file, link2));
|
||||
EXPECT_TRUE(IsRegularFile(link2));
|
||||
EXPECT_FALSE(PathExists(file));
|
||||
|
||||
ASSERT_TRUE(MoveFileOrDirectory(link2, file));
|
||||
ASSERT_TRUE(CreateSymbolicLink(file, link));
|
||||
EXPECT_TRUE(MoveFileOrDirectory(link, file));
|
||||
EXPECT_TRUE(PathExists(file));
|
||||
EXPECT_FALSE(IsRegularFile(file));
|
||||
EXPECT_FALSE(PathExists(link));
|
||||
EXPECT_TRUE(LoggingRemoveFile(file));
|
||||
|
||||
// dangling file links
|
||||
ASSERT_TRUE(CreateSymbolicLink(file, link));
|
||||
EXPECT_TRUE(MoveFileOrDirectory(link, link2));
|
||||
EXPECT_TRUE(PathExists(link2));
|
||||
EXPECT_FALSE(PathExists(link));
|
||||
|
||||
// directory links
|
||||
ASSERT_TRUE(CreateSymbolicLink(dir, link));
|
||||
|
||||
EXPECT_TRUE(MoveFileOrDirectory(link, link2));
|
||||
EXPECT_TRUE(PathExists(link2));
|
||||
EXPECT_FALSE(PathExists(link));
|
||||
|
||||
// dangling directory links
|
||||
ASSERT_TRUE(LoggingRemoveDirectory(dir));
|
||||
EXPECT_TRUE(MoveFileOrDirectory(link2, link));
|
||||
EXPECT_TRUE(PathExists(link));
|
||||
EXPECT_FALSE(PathExists(link2));
|
||||
}
|
||||
|
||||
TEST(Filesystem, IsRegularFile) {
|
||||
EXPECT_FALSE(IsRegularFile(base::FilePath()));
|
||||
|
||||
@ -116,8 +219,8 @@ TEST(Filesystem, RemoveFile) {
|
||||
base::FilePath link(temp_dir.path().Append(FILE_PATH_LITERAL("link")));
|
||||
ASSERT_TRUE(CreateSymbolicLink(file, link));
|
||||
EXPECT_TRUE(LoggingRemoveFile(link));
|
||||
EXPECT_FALSE(FileExists(link));
|
||||
EXPECT_TRUE(FileExists(file));
|
||||
EXPECT_FALSE(PathExists(link));
|
||||
EXPECT_TRUE(PathExists(file));
|
||||
|
||||
base::FilePath dir(temp_dir.path().Append(FILE_PATH_LITERAL("dir")));
|
||||
ASSERT_TRUE(
|
||||
@ -126,8 +229,8 @@ TEST(Filesystem, RemoveFile) {
|
||||
|
||||
ASSERT_TRUE(CreateSymbolicLink(dir, link));
|
||||
EXPECT_TRUE(LoggingRemoveFile(link));
|
||||
EXPECT_FALSE(FileExists(link));
|
||||
EXPECT_TRUE(FileExists(dir));
|
||||
EXPECT_FALSE(PathExists(link));
|
||||
EXPECT_TRUE(PathExists(dir));
|
||||
|
||||
EXPECT_TRUE(LoggingRemoveFile(file));
|
||||
EXPECT_FALSE(IsRegularFile(file));
|
||||
|
@ -14,9 +14,15 @@
|
||||
|
||||
#include "util/file/filesystem_test_util.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "build/build_config.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "test/errors.h"
|
||||
#include "util/file/file_io.h"
|
||||
#include "util/file/filesystem.h"
|
||||
|
||||
@ -59,5 +65,23 @@ bool CreateSymbolicLink(const base::FilePath& target_path,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PathExists(const base::FilePath& path) {
|
||||
#if defined(OS_POSIX)
|
||||
struct stat st;
|
||||
if (lstat(path.value().c_str(), &st) != 0) {
|
||||
EXPECT_EQ(errno, ENOENT) << ErrnoMessage("lstat ") << path.value();
|
||||
return false;
|
||||
}
|
||||
#elif defined(OS_WIN)
|
||||
if (GetFileAttributes(path.value().c_str()) == INVALID_FILE_ATTRIBUTES) {
|
||||
EXPECT_EQ(GetLastError(), ERROR_FILE_NOT_FOUND)
|
||||
<< ErrorMessage("GetFileAttributes ")
|
||||
<< base::UTF16ToUTF8(path.value());
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace crashpad
|
||||
|
@ -25,6 +25,8 @@ bool CreateFile(const base::FilePath& file);
|
||||
bool CreateSymbolicLink(const base::FilePath& target_path,
|
||||
const base::FilePath& symlink_path);
|
||||
|
||||
bool PathExists(const base::FilePath& path);
|
||||
|
||||
} // namespace test
|
||||
} // namespace crashpad
|
||||
|
||||
|
@ -67,6 +67,18 @@ bool LoggingCreateDirectory(const base::FilePath& path,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MoveFileOrDirectory(const base::FilePath& source,
|
||||
const base::FilePath& dest) {
|
||||
if (!MoveFileEx(source.value().c_str(),
|
||||
dest.value().c_str(),
|
||||
IsDirectory(source, false) ? 0 : MOVEFILE_REPLACE_EXISTING)) {
|
||||
PLOG(ERROR) << "MoveFileEx" << base::UTF16ToUTF8(source.value()) << ", "
|
||||
<< base::UTF16ToUTF8(dest.value());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsRegularFile(const base::FilePath& path) {
|
||||
DWORD fileattr = GetFileAttributes(path.value().c_str());
|
||||
if (fileattr == INVALID_FILE_ATTRIBUTES) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user