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:
Mark Mentovai 2017-10-26 18:37:49 -04:00 committed by Commit Bot
parent cb3aa9c4d8
commit c49da9caef
10 changed files with 334 additions and 88 deletions

View File

@ -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
View 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_

View File

@ -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()

View File

@ -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);
};

View File

@ -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

View File

@ -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,12 +69,10 @@ 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) {
} else if (lstat(path.value().c_str(), &st) != 0) {
PLOG(ERROR) << "lstat " << path.value();
return false;
}
}
return S_ISDIR(st.st_mode);
}

View File

@ -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

View File

@ -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 cant
// 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|.
}
// Dont 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

View File

@ -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. Dont bother declaring or defining
// symbolic link-related functions at all, because its 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

View File

@ -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 ||