mirror of
https://github.com/chromium/crashpad.git
synced 2024-12-27 15:32:10 +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,
|
FilePermissions permissions,
|
||||||
bool may_reuse);
|
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
|
//! \brief Determines if a path refers to a regular file, logging a message on
|
||||||
//! failure.
|
//! failure.
|
||||||
//!
|
//!
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include "util/file/filesystem.h"
|
#include "util/file/filesystem.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -42,6 +43,16 @@ bool LoggingCreateDirectory(const base::FilePath& path,
|
|||||||
return false;
|
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) {
|
bool IsRegularFile(const base::FilePath& path) {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (lstat(path.value().c_str(), &st) != 0) {
|
if (lstat(path.value().c_str(), &st) != 0) {
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
#include "base/logging.h"
|
#include "base/logging.h"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
#include "test/file.h"
|
|
||||||
#include "test/scoped_temp_dir.h"
|
#include "test/scoped_temp_dir.h"
|
||||||
#include "util/file/filesystem_test_util.h"
|
#include "util/file/filesystem_test_util.h"
|
||||||
|
|
||||||
@ -45,6 +44,110 @@ TEST(Filesystem, CreateDirectory) {
|
|||||||
EXPECT_TRUE(IsRegularFile(file));
|
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) {
|
TEST(Filesystem, IsRegularFile) {
|
||||||
EXPECT_FALSE(IsRegularFile(base::FilePath()));
|
EXPECT_FALSE(IsRegularFile(base::FilePath()));
|
||||||
|
|
||||||
@ -116,8 +219,8 @@ TEST(Filesystem, RemoveFile) {
|
|||||||
base::FilePath link(temp_dir.path().Append(FILE_PATH_LITERAL("link")));
|
base::FilePath link(temp_dir.path().Append(FILE_PATH_LITERAL("link")));
|
||||||
ASSERT_TRUE(CreateSymbolicLink(file, link));
|
ASSERT_TRUE(CreateSymbolicLink(file, link));
|
||||||
EXPECT_TRUE(LoggingRemoveFile(link));
|
EXPECT_TRUE(LoggingRemoveFile(link));
|
||||||
EXPECT_FALSE(FileExists(link));
|
EXPECT_FALSE(PathExists(link));
|
||||||
EXPECT_TRUE(FileExists(file));
|
EXPECT_TRUE(PathExists(file));
|
||||||
|
|
||||||
base::FilePath dir(temp_dir.path().Append(FILE_PATH_LITERAL("dir")));
|
base::FilePath dir(temp_dir.path().Append(FILE_PATH_LITERAL("dir")));
|
||||||
ASSERT_TRUE(
|
ASSERT_TRUE(
|
||||||
@ -126,8 +229,8 @@ TEST(Filesystem, RemoveFile) {
|
|||||||
|
|
||||||
ASSERT_TRUE(CreateSymbolicLink(dir, link));
|
ASSERT_TRUE(CreateSymbolicLink(dir, link));
|
||||||
EXPECT_TRUE(LoggingRemoveFile(link));
|
EXPECT_TRUE(LoggingRemoveFile(link));
|
||||||
EXPECT_FALSE(FileExists(link));
|
EXPECT_FALSE(PathExists(link));
|
||||||
EXPECT_TRUE(FileExists(dir));
|
EXPECT_TRUE(PathExists(dir));
|
||||||
|
|
||||||
EXPECT_TRUE(LoggingRemoveFile(file));
|
EXPECT_TRUE(LoggingRemoveFile(file));
|
||||||
EXPECT_FALSE(IsRegularFile(file));
|
EXPECT_FALSE(IsRegularFile(file));
|
||||||
|
@ -14,9 +14,15 @@
|
|||||||
|
|
||||||
#include "util/file/filesystem_test_util.h"
|
#include "util/file/filesystem_test_util.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include "base/logging.h"
|
#include "base/logging.h"
|
||||||
|
#include "base/strings/utf_string_conversions.h"
|
||||||
#include "build/build_config.h"
|
#include "build/build_config.h"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
#include "test/errors.h"
|
||||||
#include "util/file/file_io.h"
|
#include "util/file/file_io.h"
|
||||||
#include "util/file/filesystem.h"
|
#include "util/file/filesystem.h"
|
||||||
|
|
||||||
@ -59,5 +65,23 @@ bool CreateSymbolicLink(const base::FilePath& target_path,
|
|||||||
return true;
|
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 test
|
||||||
} // namespace crashpad
|
} // namespace crashpad
|
||||||
|
@ -25,6 +25,8 @@ bool CreateFile(const base::FilePath& file);
|
|||||||
bool CreateSymbolicLink(const base::FilePath& target_path,
|
bool CreateSymbolicLink(const base::FilePath& target_path,
|
||||||
const base::FilePath& symlink_path);
|
const base::FilePath& symlink_path);
|
||||||
|
|
||||||
|
bool PathExists(const base::FilePath& path);
|
||||||
|
|
||||||
} // namespace test
|
} // namespace test
|
||||||
} // namespace crashpad
|
} // namespace crashpad
|
||||||
|
|
||||||
|
@ -67,6 +67,18 @@ bool LoggingCreateDirectory(const base::FilePath& path,
|
|||||||
return false;
|
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) {
|
bool IsRegularFile(const base::FilePath& path) {
|
||||||
DWORD fileattr = GetFileAttributes(path.value().c_str());
|
DWORD fileattr = GetFileAttributes(path.value().c_str());
|
||||||
if (fileattr == INVALID_FILE_ATTRIBUTES) {
|
if (fileattr == INVALID_FILE_ATTRIBUTES) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user