mirror of
https://github.com/chromium/crashpad.git
synced 2024-12-26 23:01:05 +08:00
win: Expect uneven symbolic link support
As mentioned at https://chromium-review.googlesource.com/c/chromium/src/+/735820#message-e8b199498d8b850f2612c46648069d819dd47517, the typical Windows behavior for symbolic links requires administrative privileges. Symbolic links are available to non-administrators in Windows 10.0.15063 and later (1703, Creators Update), provided that developer mode has been enabled and SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE is passed to CreateSymbolicLink(). See https://blogs.windows.com/buildingapps/2016/12/02/symlinks-windows-10/. This adds SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE to uses of CreateSymbolicLink(), and creates test::CanCreateSymbolicLinks() to determine whether symbolic link creation is possible. Tests that exercise symbolic links are adapted to gate all symbolic link operations on this test. Test: crashpad_util_test DirectoryReader.*:Filesystem.* Change-Id: I8250cadd974ffcc7abe32701a0d5bc487061baf0 Bug: crashpad: Reviewed-on: https://chromium-review.googlesource.com/739472 Commit-Queue: Mark Mentovai <mark@chromium.org> Reviewed-by: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Scott Graham <scottmg@chromium.org>
This commit is contained in:
parent
cb3aa9c4d8
commit
c49da9caef
@ -54,6 +54,7 @@
|
||||
'win/sys/types.h',
|
||||
'win/time.cc',
|
||||
'win/time.h',
|
||||
'win/winbase.h',
|
||||
'win/winnt.h',
|
||||
'win/winternl.h',
|
||||
],
|
||||
|
27
compat/win/winbase.h
Normal file
27
compat/win/winbase.h
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright 2017 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef CRASHPAD_COMPAT_WIN_WINBASE_H_
|
||||
#define CRASHPAD_COMPAT_WIN_WINBASE_H_
|
||||
|
||||
// include_next <winbase.h>
|
||||
#include <../um/winbase.h>
|
||||
|
||||
// 10.0.15063.0 SDK
|
||||
|
||||
#ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
|
||||
#define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE (0x2)
|
||||
#endif
|
||||
|
||||
#endif // CRASHPAD_COMPAT_WIN_WINBASE_H_
|
@ -51,7 +51,7 @@ void DisabledTestGtestEnvironment::DisabledTest() {
|
||||
"[ DISABLED ] %s\n",
|
||||
disabled_test.c_str());
|
||||
|
||||
disabled_tests_.insert(disabled_test);
|
||||
disabled_tests_.push_back(disabled_test);
|
||||
}
|
||||
|
||||
DisabledTestGtestEnvironment::DisabledTestGtestEnvironment()
|
||||
|
@ -15,8 +15,8 @@
|
||||
#ifndef CRASHPAD_TEST_GTEST_DISABLED_H_
|
||||
#define CRASHPAD_TEST_GTEST_DISABLED_H_
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "gtest/gtest.h"
|
||||
@ -54,7 +54,7 @@ class DisabledTestGtestEnvironment final : public testing::Environment {
|
||||
// testing::Environment:
|
||||
void TearDown() override;
|
||||
|
||||
std::set<std::string> disabled_tests_;
|
||||
std::vector<std::string> disabled_tests_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(DisabledTestGtestEnvironment);
|
||||
};
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "test/gtest_disabled.h"
|
||||
#include "test/scoped_temp_dir.h"
|
||||
#include "util/file/file_io.h"
|
||||
#include "util/file/filesystem.h"
|
||||
@ -30,6 +31,51 @@ namespace crashpad {
|
||||
namespace test {
|
||||
namespace {
|
||||
|
||||
TEST(DirectoryReader, BadPaths) {
|
||||
DirectoryReader reader;
|
||||
EXPECT_FALSE(reader.Open(base::FilePath()));
|
||||
|
||||
ScopedTempDir temp_dir;
|
||||
base::FilePath file(temp_dir.path().Append(FILE_PATH_LITERAL("file")));
|
||||
ASSERT_TRUE(CreateFile(file));
|
||||
EXPECT_FALSE(reader.Open(file));
|
||||
|
||||
EXPECT_FALSE(
|
||||
reader.Open(temp_dir.path().Append(FILE_PATH_LITERAL("doesntexist"))));
|
||||
}
|
||||
|
||||
#if !defined(OS_FUCHSIA)
|
||||
|
||||
TEST(DirectoryReader, BadPaths_SymbolicLinks) {
|
||||
if (!CanCreateSymbolicLinks()) {
|
||||
DISABLED_TEST();
|
||||
}
|
||||
|
||||
ScopedTempDir temp_dir;
|
||||
base::FilePath file(temp_dir.path().Append(FILE_PATH_LITERAL("file")));
|
||||
ASSERT_TRUE(CreateFile(file));
|
||||
|
||||
base::FilePath link(temp_dir.path().Append(FILE_PATH_LITERAL("link")));
|
||||
ASSERT_TRUE(CreateSymbolicLink(file, link));
|
||||
|
||||
DirectoryReader reader;
|
||||
EXPECT_FALSE(reader.Open(link));
|
||||
|
||||
ASSERT_TRUE(LoggingRemoveFile(file));
|
||||
EXPECT_FALSE(reader.Open(link));
|
||||
}
|
||||
|
||||
#endif // !OS_FUCHSIA
|
||||
|
||||
TEST(DirectoryReader, EmptyDirectory) {
|
||||
ScopedTempDir temp_dir;
|
||||
DirectoryReader reader;
|
||||
|
||||
ASSERT_TRUE(reader.Open(temp_dir.path()));
|
||||
base::FilePath filename;
|
||||
EXPECT_EQ(reader.NextFile(&filename), DirectoryReader::Result::kNoMoreFiles);
|
||||
}
|
||||
|
||||
void ExpectFiles(const std::set<base::FilePath>& files,
|
||||
const std::set<base::FilePath>& expected) {
|
||||
EXPECT_EQ(files.size(), expected.size());
|
||||
@ -41,36 +87,7 @@ void ExpectFiles(const std::set<base::FilePath>& files,
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DirectoryReader, BadPaths) {
|
||||
DirectoryReader reader;
|
||||
EXPECT_FALSE(reader.Open(base::FilePath()));
|
||||
|
||||
ScopedTempDir temp_dir;
|
||||
base::FilePath file(temp_dir.path().Append(FILE_PATH_LITERAL("file")));
|
||||
ASSERT_TRUE(CreateFile(file));
|
||||
EXPECT_FALSE(reader.Open(file));
|
||||
|
||||
base::FilePath link(temp_dir.path().Append(FILE_PATH_LITERAL("link")));
|
||||
ASSERT_TRUE(CreateSymbolicLink(file, link));
|
||||
EXPECT_FALSE(reader.Open(link));
|
||||
|
||||
ASSERT_TRUE(LoggingRemoveFile(file));
|
||||
EXPECT_FALSE(reader.Open(link));
|
||||
|
||||
EXPECT_FALSE(
|
||||
reader.Open(temp_dir.path().Append(FILE_PATH_LITERAL("doesntexist"))));
|
||||
}
|
||||
|
||||
TEST(DirectoryReader, EmptyDirectory) {
|
||||
ScopedTempDir temp_dir;
|
||||
DirectoryReader reader;
|
||||
|
||||
ASSERT_TRUE(reader.Open(temp_dir.path()));
|
||||
base::FilePath filename;
|
||||
EXPECT_EQ(reader.NextFile(&filename), DirectoryReader::Result::kNoMoreFiles);
|
||||
}
|
||||
|
||||
TEST(DirectoryReader, FilesAndDirectories) {
|
||||
void TestFilesAndDirectories(bool symbolic_links) {
|
||||
ScopedTempDir temp_dir;
|
||||
std::set<base::FilePath> expected_files;
|
||||
|
||||
@ -78,17 +95,6 @@ TEST(DirectoryReader, FilesAndDirectories) {
|
||||
ASSERT_TRUE(CreateFile(temp_dir.path().Append(file)));
|
||||
EXPECT_TRUE(expected_files.insert(file).second);
|
||||
|
||||
base::FilePath link(FILE_PATH_LITERAL("link"));
|
||||
ASSERT_TRUE(CreateSymbolicLink(temp_dir.path().Append(file),
|
||||
temp_dir.path().Append(link)));
|
||||
EXPECT_TRUE(expected_files.insert(link).second);
|
||||
|
||||
base::FilePath dangling(FILE_PATH_LITERAL("dangling"));
|
||||
ASSERT_TRUE(
|
||||
CreateSymbolicLink(base::FilePath(FILE_PATH_LITERAL("not_a_file")),
|
||||
temp_dir.path().Append(dangling)));
|
||||
EXPECT_TRUE(expected_files.insert(dangling).second);
|
||||
|
||||
base::FilePath directory(FILE_PATH_LITERAL("directory"));
|
||||
ASSERT_TRUE(LoggingCreateDirectory(temp_dir.path().Append(directory),
|
||||
FilePermissions::kWorldReadable,
|
||||
@ -99,6 +105,23 @@ TEST(DirectoryReader, FilesAndDirectories) {
|
||||
ASSERT_TRUE(
|
||||
CreateFile(temp_dir.path().Append(directory).Append(nested_file)));
|
||||
|
||||
#if !defined(OS_FUCHSIA)
|
||||
|
||||
if (symbolic_links) {
|
||||
base::FilePath link(FILE_PATH_LITERAL("link"));
|
||||
ASSERT_TRUE(CreateSymbolicLink(temp_dir.path().Append(file),
|
||||
temp_dir.path().Append(link)));
|
||||
EXPECT_TRUE(expected_files.insert(link).second);
|
||||
|
||||
base::FilePath dangling(FILE_PATH_LITERAL("dangling"));
|
||||
ASSERT_TRUE(
|
||||
CreateSymbolicLink(base::FilePath(FILE_PATH_LITERAL("not_a_file")),
|
||||
temp_dir.path().Append(dangling)));
|
||||
EXPECT_TRUE(expected_files.insert(dangling).second);
|
||||
}
|
||||
|
||||
#endif // !OS_FUCHSIA
|
||||
|
||||
std::set<base::FilePath> files;
|
||||
DirectoryReader reader;
|
||||
ASSERT_TRUE(reader.Open(temp_dir.path()));
|
||||
@ -113,6 +136,22 @@ TEST(DirectoryReader, FilesAndDirectories) {
|
||||
ExpectFiles(files, expected_files);
|
||||
}
|
||||
|
||||
TEST(DirectoryReader, FilesAndDirectories) {
|
||||
TestFilesAndDirectories(false);
|
||||
}
|
||||
|
||||
#if !defined(OS_FUCHSIA)
|
||||
|
||||
TEST(DirectoryReader, FilesAndDirectories_SymbolicLinks) {
|
||||
if (!CanCreateSymbolicLinks()) {
|
||||
DISABLED_TEST();
|
||||
}
|
||||
|
||||
TestFilesAndDirectories(true);
|
||||
}
|
||||
|
||||
#endif // !OS_FUCHSIA
|
||||
|
||||
} // namespace
|
||||
} // namespace test
|
||||
} // namespace crashpad
|
||||
|
@ -56,7 +56,7 @@ bool MoveFileOrDirectory(const base::FilePath& source,
|
||||
bool IsRegularFile(const base::FilePath& path) {
|
||||
struct stat st;
|
||||
if (lstat(path.value().c_str(), &st) != 0) {
|
||||
PLOG_IF(ERROR, errno != ENOENT) << "stat " << path.value();
|
||||
PLOG(ERROR) << "stat " << path.value();
|
||||
return false;
|
||||
}
|
||||
return S_ISREG(st.st_mode);
|
||||
@ -69,11 +69,9 @@ bool IsDirectory(const base::FilePath& path, bool allow_symlinks) {
|
||||
PLOG(ERROR) << "stat " << path.value();
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (lstat(path.value().c_str(), &st) != 0) {
|
||||
PLOG(ERROR) << "lstat " << path.value();
|
||||
return false;
|
||||
}
|
||||
} else if (lstat(path.value().c_str(), &st) != 0) {
|
||||
PLOG(ERROR) << "lstat " << path.value();
|
||||
return false;
|
||||
}
|
||||
return S_ISDIR(st.st_mode);
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "test/gtest_disabled.h"
|
||||
#include "test/scoped_temp_dir.h"
|
||||
#include "util/file/filesystem_test_util.h"
|
||||
|
||||
@ -60,16 +61,16 @@ TEST(Filesystem, MoveFileOrDirectory) {
|
||||
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(PathExists(file));
|
||||
|
||||
EXPECT_FALSE(MoveFileOrDirectory(file, file2));
|
||||
EXPECT_TRUE(IsRegularFile(file2));
|
||||
EXPECT_FALSE(IsRegularFile(file));
|
||||
EXPECT_FALSE(PathExists(file));
|
||||
|
||||
ASSERT_TRUE(CreateFile(file));
|
||||
EXPECT_TRUE(MoveFileOrDirectory(file2, file));
|
||||
EXPECT_TRUE(IsRegularFile(file));
|
||||
EXPECT_FALSE(IsRegularFile(file2));
|
||||
EXPECT_FALSE(PathExists(file2));
|
||||
|
||||
// directories
|
||||
base::FilePath dir(temp_dir.path().Append(FILE_PATH_LITERAL("dir")));
|
||||
@ -100,6 +101,19 @@ TEST(Filesystem, MoveFileOrDirectory) {
|
||||
EXPECT_FALSE(MoveFileOrDirectory(dir2, file));
|
||||
EXPECT_TRUE(IsDirectory(dir2, false));
|
||||
EXPECT_TRUE(IsRegularFile(file));
|
||||
}
|
||||
|
||||
#if !defined(OS_FUCHSIA)
|
||||
|
||||
TEST(Filesystem, MoveFileOrDirectory_SymbolicLinks) {
|
||||
if (!CanCreateSymbolicLinks()) {
|
||||
DISABLED_TEST();
|
||||
}
|
||||
|
||||
ScopedTempDir temp_dir;
|
||||
|
||||
base::FilePath file(temp_dir.path().Append(FILE_PATH_LITERAL("file")));
|
||||
ASSERT_TRUE(CreateFile(file));
|
||||
|
||||
// file links
|
||||
base::FilePath link(temp_dir.path().Append(FILE_PATH_LITERAL("link")));
|
||||
@ -135,6 +149,10 @@ TEST(Filesystem, MoveFileOrDirectory) {
|
||||
EXPECT_FALSE(PathExists(link));
|
||||
|
||||
// directory links
|
||||
base::FilePath dir(temp_dir.path().Append(FILE_PATH_LITERAL("dir")));
|
||||
ASSERT_TRUE(
|
||||
LoggingCreateDirectory(dir, FilePermissions::kWorldReadable, false));
|
||||
|
||||
ASSERT_TRUE(CreateSymbolicLink(dir, link));
|
||||
|
||||
EXPECT_TRUE(MoveFileOrDirectory(link, link2));
|
||||
@ -148,6 +166,8 @@ TEST(Filesystem, MoveFileOrDirectory) {
|
||||
EXPECT_FALSE(PathExists(link2));
|
||||
}
|
||||
|
||||
#endif // !OS_FUCHSIA
|
||||
|
||||
TEST(Filesystem, IsRegularFile) {
|
||||
EXPECT_FALSE(IsRegularFile(base::FilePath()));
|
||||
|
||||
@ -159,6 +179,18 @@ TEST(Filesystem, IsRegularFile) {
|
||||
|
||||
ASSERT_TRUE(CreateFile(file));
|
||||
EXPECT_TRUE(IsRegularFile(file));
|
||||
}
|
||||
|
||||
#if !defined(OS_FUCHSIA)
|
||||
|
||||
TEST(Filesystem, IsRegularFile_SymbolicLinks) {
|
||||
if (!CanCreateSymbolicLinks()) {
|
||||
DISABLED_TEST();
|
||||
}
|
||||
|
||||
ScopedTempDir temp_dir;
|
||||
base::FilePath file(temp_dir.path().Append(FILE_PATH_LITERAL("file")));
|
||||
ASSERT_TRUE(CreateFile(file));
|
||||
|
||||
base::FilePath link(temp_dir.path().Append(FILE_PATH_LITERAL("link")));
|
||||
ASSERT_TRUE(CreateSymbolicLink(file, link));
|
||||
@ -173,6 +205,8 @@ TEST(Filesystem, IsRegularFile) {
|
||||
EXPECT_FALSE(IsRegularFile(dir_link));
|
||||
}
|
||||
|
||||
#endif // !OS_FUCHSIA
|
||||
|
||||
TEST(Filesystem, IsDirectory) {
|
||||
EXPECT_FALSE(IsDirectory(base::FilePath(), false));
|
||||
EXPECT_FALSE(IsDirectory(base::FilePath(), true));
|
||||
@ -187,6 +221,18 @@ TEST(Filesystem, IsDirectory) {
|
||||
ASSERT_TRUE(CreateFile(file));
|
||||
EXPECT_FALSE(IsDirectory(file, false));
|
||||
EXPECT_FALSE(IsDirectory(file, true));
|
||||
}
|
||||
|
||||
#if !defined(OS_FUCHSIA)
|
||||
|
||||
TEST(Filesystem, IsDirectory_SymbolicLinks) {
|
||||
if (!CanCreateSymbolicLinks()) {
|
||||
DISABLED_TEST();
|
||||
}
|
||||
|
||||
ScopedTempDir temp_dir;
|
||||
base::FilePath file(temp_dir.path().Append(FILE_PATH_LITERAL("file")));
|
||||
ASSERT_TRUE(CreateFile(file));
|
||||
|
||||
base::FilePath link(temp_dir.path().Append(FILE_PATH_LITERAL("link")));
|
||||
ASSERT_TRUE(CreateSymbolicLink(file, link));
|
||||
@ -204,6 +250,8 @@ TEST(Filesystem, IsDirectory) {
|
||||
EXPECT_TRUE(IsDirectory(dir_link, true));
|
||||
}
|
||||
|
||||
#endif // !OS_FUCHSIA
|
||||
|
||||
TEST(Filesystem, RemoveFile) {
|
||||
EXPECT_FALSE(LoggingRemoveFile(base::FilePath()));
|
||||
|
||||
@ -216,27 +264,45 @@ TEST(Filesystem, RemoveFile) {
|
||||
ASSERT_TRUE(CreateFile(file));
|
||||
EXPECT_TRUE(IsRegularFile(file));
|
||||
|
||||
base::FilePath dir(temp_dir.path().Append(FILE_PATH_LITERAL("dir")));
|
||||
ASSERT_TRUE(
|
||||
LoggingCreateDirectory(dir, FilePermissions::kWorldReadable, false));
|
||||
EXPECT_FALSE(LoggingRemoveFile(dir));
|
||||
|
||||
EXPECT_TRUE(LoggingRemoveFile(file));
|
||||
EXPECT_FALSE(PathExists(file));
|
||||
EXPECT_FALSE(LoggingRemoveFile(file));
|
||||
}
|
||||
|
||||
#if !defined(OS_FUCHSIA)
|
||||
|
||||
TEST(Filesystem, RemoveFile_SymbolicLinks) {
|
||||
if (!CanCreateSymbolicLinks()) {
|
||||
DISABLED_TEST();
|
||||
}
|
||||
|
||||
ScopedTempDir temp_dir;
|
||||
base::FilePath file(temp_dir.path().Append(FILE_PATH_LITERAL("file")));
|
||||
ASSERT_TRUE(CreateFile(file));
|
||||
|
||||
base::FilePath dir(temp_dir.path().Append(FILE_PATH_LITERAL("dir")));
|
||||
ASSERT_TRUE(
|
||||
LoggingCreateDirectory(dir, FilePermissions::kWorldReadable, false));
|
||||
|
||||
base::FilePath link(temp_dir.path().Append(FILE_PATH_LITERAL("link")));
|
||||
ASSERT_TRUE(CreateSymbolicLink(file, link));
|
||||
EXPECT_TRUE(LoggingRemoveFile(link));
|
||||
EXPECT_FALSE(PathExists(link));
|
||||
EXPECT_TRUE(PathExists(file));
|
||||
|
||||
base::FilePath dir(temp_dir.path().Append(FILE_PATH_LITERAL("dir")));
|
||||
ASSERT_TRUE(
|
||||
LoggingCreateDirectory(dir, FilePermissions::kWorldReadable, false));
|
||||
EXPECT_FALSE(LoggingRemoveFile(dir));
|
||||
|
||||
ASSERT_TRUE(CreateSymbolicLink(dir, link));
|
||||
EXPECT_TRUE(LoggingRemoveFile(link));
|
||||
EXPECT_FALSE(PathExists(link));
|
||||
EXPECT_TRUE(PathExists(dir));
|
||||
|
||||
EXPECT_TRUE(LoggingRemoveFile(file));
|
||||
EXPECT_FALSE(IsRegularFile(file));
|
||||
EXPECT_FALSE(LoggingRemoveFile(file));
|
||||
}
|
||||
|
||||
#endif // !OS_FUCHSIA
|
||||
|
||||
TEST(Filesystem, RemoveDirectory) {
|
||||
EXPECT_FALSE(LoggingRemoveDirectory(base::FilePath()));
|
||||
|
||||
@ -253,6 +319,25 @@ TEST(Filesystem, RemoveDirectory) {
|
||||
EXPECT_FALSE(LoggingRemoveDirectory(file));
|
||||
EXPECT_FALSE(LoggingRemoveDirectory(dir));
|
||||
|
||||
ASSERT_TRUE(LoggingRemoveFile(file));
|
||||
EXPECT_TRUE(LoggingRemoveDirectory(dir));
|
||||
}
|
||||
|
||||
#if !defined(OS_FUCHSIA)
|
||||
|
||||
TEST(Filesystem, RemoveDirectory_SymbolicLinks) {
|
||||
if (!CanCreateSymbolicLinks()) {
|
||||
DISABLED_TEST();
|
||||
}
|
||||
|
||||
ScopedTempDir temp_dir;
|
||||
base::FilePath dir(temp_dir.path().Append(FILE_PATH_LITERAL("dir")));
|
||||
ASSERT_TRUE(
|
||||
LoggingCreateDirectory(dir, FilePermissions::kWorldReadable, false));
|
||||
|
||||
base::FilePath file(dir.Append(FILE_PATH_LITERAL("file")));
|
||||
EXPECT_FALSE(LoggingRemoveDirectory(file));
|
||||
|
||||
base::FilePath link(temp_dir.path().Append(FILE_PATH_LITERAL("link")));
|
||||
ASSERT_TRUE(CreateSymbolicLink(file, link));
|
||||
EXPECT_FALSE(LoggingRemoveDirectory(link));
|
||||
@ -261,11 +346,10 @@ TEST(Filesystem, RemoveDirectory) {
|
||||
ASSERT_TRUE(CreateSymbolicLink(dir, link));
|
||||
EXPECT_FALSE(LoggingRemoveDirectory(link));
|
||||
EXPECT_TRUE(LoggingRemoveFile(link));
|
||||
|
||||
ASSERT_TRUE(LoggingRemoveFile(file));
|
||||
EXPECT_TRUE(LoggingRemoveDirectory(dir));
|
||||
}
|
||||
|
||||
#endif // !OS_FUCHSIA
|
||||
|
||||
} // namespace
|
||||
} // namespace test
|
||||
} // namespace crashpad
|
||||
|
@ -20,9 +20,9 @@
|
||||
|
||||
#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 "test/scoped_temp_dir.h"
|
||||
#include "util/file/file_io.h"
|
||||
#include "util/file/filesystem.h"
|
||||
|
||||
@ -37,6 +37,60 @@
|
||||
namespace crashpad {
|
||||
namespace test {
|
||||
|
||||
namespace {
|
||||
|
||||
#if defined(OS_WIN)
|
||||
|
||||
// Detects the flags necessary to create symbolic links and stores them in
|
||||
// |flags| if non-nullptr, and returns true on success. If symbolic links can’t
|
||||
// be created, returns false.
|
||||
bool SymbolicLinkFlags(DWORD* flags) {
|
||||
static DWORD symbolic_link_flags = []() {
|
||||
ScopedTempDir temp_dir_;
|
||||
|
||||
base::FilePath target_path = temp_dir_.path().Append(L"target");
|
||||
base::FilePath symlink_path = temp_dir_.path().Append(L"symlink");
|
||||
if (::CreateSymbolicLink(
|
||||
symlink_path.value().c_str(), target_path.value().c_str(), 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD error = GetLastError();
|
||||
if (error == ERROR_PRIVILEGE_NOT_HELD) {
|
||||
if (::CreateSymbolicLink(symlink_path.value().c_str(),
|
||||
target_path.value().c_str(),
|
||||
SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE)) {
|
||||
return SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
|
||||
}
|
||||
|
||||
// This may fail with ERROR_INVALID_PARAMETER if the OS is too old to
|
||||
// understand SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE, so keep
|
||||
// ERROR_PRIVILEGE_NOT_HELD for |error|.
|
||||
}
|
||||
|
||||
// Don’t use ErrorMessage() here because the second CreateSymbolicLink() may
|
||||
// have scrambled it. Use the saved |error| value instead.
|
||||
EXPECT_EQ(error, ERROR_PRIVILEGE_NOT_HELD)
|
||||
<< "CreateSymbolicLink: "
|
||||
<< logging::SystemErrorCodeToString(GetLastError());
|
||||
return -1;
|
||||
}();
|
||||
|
||||
if (symbolic_link_flags == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (flags) {
|
||||
*flags = symbolic_link_flags;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // OS_WIN
|
||||
|
||||
} // namespace
|
||||
|
||||
bool CreateFile(const base::FilePath& file) {
|
||||
ScopedFileHandle fd(LoggingOpenFileForWrite(
|
||||
file, FileWriteMode::kCreateOrFail, FilePermissions::kOwnerOnly));
|
||||
@ -44,6 +98,35 @@ bool CreateFile(const base::FilePath& file) {
|
||||
return fd.is_valid();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
return true;
|
||||
#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;
|
||||
}
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(OS_FUCHSIA)
|
||||
|
||||
bool CanCreateSymbolicLinks() {
|
||||
#if defined(OS_POSIX)
|
||||
return true;
|
||||
#elif defined(OS_WIN)
|
||||
return SymbolicLinkFlags(nullptr);
|
||||
#endif // OS_POSIX
|
||||
}
|
||||
|
||||
bool CreateSymbolicLink(const base::FilePath& target_path,
|
||||
const base::FilePath& symlink_path) {
|
||||
#if defined(OS_POSIX)
|
||||
@ -53,35 +136,24 @@ bool CreateSymbolicLink(const base::FilePath& target_path,
|
||||
PLOG(ERROR) << "symlink";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
#elif defined(OS_WIN)
|
||||
DWORD symbolic_link_flags = 0;
|
||||
SymbolicLinkFlags(&symbolic_link_flags);
|
||||
if (!::CreateSymbolicLink(
|
||||
symlink_path.value().c_str(),
|
||||
target_path.value().c_str(),
|
||||
IsDirectory(target_path, true) ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0)) {
|
||||
symbolic_link_flags |
|
||||
(IsDirectory(target_path, true) ? SYMBOLIC_LINK_FLAG_DIRECTORY
|
||||
: 0))) {
|
||||
PLOG(ERROR) << "CreateSymbolicLink";
|
||||
return false;
|
||||
}
|
||||
#endif // OS_POSIX
|
||||
return true;
|
||||
#endif // OS_POSIX
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
#endif // !OS_FUCHSIA
|
||||
|
||||
} // namespace test
|
||||
} // namespace crashpad
|
||||
|
@ -17,15 +17,41 @@
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
|
||||
#include "build/build_config.h"
|
||||
|
||||
namespace crashpad {
|
||||
namespace test {
|
||||
|
||||
bool CreateFile(const base::FilePath& file);
|
||||
|
||||
bool PathExists(const base::FilePath& path);
|
||||
|
||||
#if !defined(OS_FUCHSIA) || DOXYGEN
|
||||
// There are no symbolic links on Fuchsia. Don’t bother declaring or defining
|
||||
// symbolic link-related functions at all, because it’s an error to even pretend
|
||||
// that symbolic links might be available on Fuchsia.
|
||||
|
||||
//! \brief Determines whether it should be possible to create symbolic links.
|
||||
//!
|
||||
//! It is always possible to create symbolic links on POSIX.
|
||||
//!
|
||||
//! On Windows, it is only possible to create symbolic links when running as an
|
||||
//! administrator, or as a non-administrator when running Windows 10 build 15063
|
||||
//! (1703, Creators Update) or later, provided that developer mode is enabled
|
||||
//! and `SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE` is used. This function
|
||||
//! tests the creation of a symbolic link and returns true on success, and false
|
||||
//! on failure. If the symbolic link could not be created for a reason other
|
||||
//! than the expected lack of privilege, a message is logged.
|
||||
//!
|
||||
//! Additional background: <a
|
||||
//! href="https://blogs.windows.com/buildingapps/2016/12/02/symlinks-windows-10/">Symlinks
|
||||
//! in Windows 10!</a>
|
||||
bool CanCreateSymbolicLinks();
|
||||
|
||||
bool CreateSymbolicLink(const base::FilePath& target_path,
|
||||
const base::FilePath& symlink_path);
|
||||
|
||||
bool PathExists(const base::FilePath& path);
|
||||
#endif // !OS_FUCHSIA || DOXYGEN
|
||||
|
||||
} // namespace test
|
||||
} // namespace crashpad
|
||||
|
@ -82,8 +82,7 @@ bool MoveFileOrDirectory(const base::FilePath& source,
|
||||
bool IsRegularFile(const base::FilePath& path) {
|
||||
DWORD fileattr = GetFileAttributes(path.value().c_str());
|
||||
if (fileattr == INVALID_FILE_ATTRIBUTES) {
|
||||
PLOG_IF(ERROR, GetLastError() != ERROR_FILE_NOT_FOUND)
|
||||
<< "GetFileAttributes " << base::UTF16ToUTF8(path.value());
|
||||
PLOG(ERROR) << "GetFileAttributes " << base::UTF16ToUTF8(path.value());
|
||||
return false;
|
||||
}
|
||||
if ((fileattr & FILE_ATTRIBUTE_DIRECTORY) != 0 ||
|
||||
|
Loading…
x
Reference in New Issue
Block a user