mirror of
https://github.com/chromium/crashpad.git
synced 2024-12-27 15:32:10 +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/sys/types.h',
|
||||||
'win/time.cc',
|
'win/time.cc',
|
||||||
'win/time.h',
|
'win/time.h',
|
||||||
|
'win/winbase.h',
|
||||||
'win/winnt.h',
|
'win/winnt.h',
|
||||||
'win/winternl.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 ] %s\n",
|
||||||
disabled_test.c_str());
|
disabled_test.c_str());
|
||||||
|
|
||||||
disabled_tests_.insert(disabled_test);
|
disabled_tests_.push_back(disabled_test);
|
||||||
}
|
}
|
||||||
|
|
||||||
DisabledTestGtestEnvironment::DisabledTestGtestEnvironment()
|
DisabledTestGtestEnvironment::DisabledTestGtestEnvironment()
|
||||||
|
@ -15,8 +15,8 @@
|
|||||||
#ifndef CRASHPAD_TEST_GTEST_DISABLED_H_
|
#ifndef CRASHPAD_TEST_GTEST_DISABLED_H_
|
||||||
#define CRASHPAD_TEST_GTEST_DISABLED_H_
|
#define CRASHPAD_TEST_GTEST_DISABLED_H_
|
||||||
|
|
||||||
#include <set>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "base/macros.h"
|
#include "base/macros.h"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
@ -54,7 +54,7 @@ class DisabledTestGtestEnvironment final : public testing::Environment {
|
|||||||
// testing::Environment:
|
// testing::Environment:
|
||||||
void TearDown() override;
|
void TearDown() override;
|
||||||
|
|
||||||
std::set<std::string> disabled_tests_;
|
std::vector<std::string> disabled_tests_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(DisabledTestGtestEnvironment);
|
DISALLOW_COPY_AND_ASSIGN(DisabledTestGtestEnvironment);
|
||||||
};
|
};
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "base/strings/stringprintf.h"
|
#include "base/strings/stringprintf.h"
|
||||||
#include "base/strings/utf_string_conversions.h"
|
#include "base/strings/utf_string_conversions.h"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
#include "test/gtest_disabled.h"
|
||||||
#include "test/scoped_temp_dir.h"
|
#include "test/scoped_temp_dir.h"
|
||||||
#include "util/file/file_io.h"
|
#include "util/file/file_io.h"
|
||||||
#include "util/file/filesystem.h"
|
#include "util/file/filesystem.h"
|
||||||
@ -30,6 +31,51 @@ namespace crashpad {
|
|||||||
namespace test {
|
namespace test {
|
||||||
namespace {
|
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,
|
void ExpectFiles(const std::set<base::FilePath>& files,
|
||||||
const std::set<base::FilePath>& expected) {
|
const std::set<base::FilePath>& expected) {
|
||||||
EXPECT_EQ(files.size(), expected.size());
|
EXPECT_EQ(files.size(), expected.size());
|
||||||
@ -41,36 +87,7 @@ void ExpectFiles(const std::set<base::FilePath>& files,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(DirectoryReader, BadPaths) {
|
void TestFilesAndDirectories(bool symbolic_links) {
|
||||||
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) {
|
|
||||||
ScopedTempDir temp_dir;
|
ScopedTempDir temp_dir;
|
||||||
std::set<base::FilePath> expected_files;
|
std::set<base::FilePath> expected_files;
|
||||||
|
|
||||||
@ -78,17 +95,6 @@ TEST(DirectoryReader, FilesAndDirectories) {
|
|||||||
ASSERT_TRUE(CreateFile(temp_dir.path().Append(file)));
|
ASSERT_TRUE(CreateFile(temp_dir.path().Append(file)));
|
||||||
EXPECT_TRUE(expected_files.insert(file).second);
|
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"));
|
base::FilePath directory(FILE_PATH_LITERAL("directory"));
|
||||||
ASSERT_TRUE(LoggingCreateDirectory(temp_dir.path().Append(directory),
|
ASSERT_TRUE(LoggingCreateDirectory(temp_dir.path().Append(directory),
|
||||||
FilePermissions::kWorldReadable,
|
FilePermissions::kWorldReadable,
|
||||||
@ -99,6 +105,23 @@ TEST(DirectoryReader, FilesAndDirectories) {
|
|||||||
ASSERT_TRUE(
|
ASSERT_TRUE(
|
||||||
CreateFile(temp_dir.path().Append(directory).Append(nested_file)));
|
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;
|
std::set<base::FilePath> files;
|
||||||
DirectoryReader reader;
|
DirectoryReader reader;
|
||||||
ASSERT_TRUE(reader.Open(temp_dir.path()));
|
ASSERT_TRUE(reader.Open(temp_dir.path()));
|
||||||
@ -113,6 +136,22 @@ TEST(DirectoryReader, FilesAndDirectories) {
|
|||||||
ExpectFiles(files, expected_files);
|
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
|
||||||
} // namespace test
|
} // namespace test
|
||||||
} // namespace crashpad
|
} // namespace crashpad
|
||||||
|
@ -56,7 +56,7 @@ bool MoveFileOrDirectory(const base::FilePath& source,
|
|||||||
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) {
|
||||||
PLOG_IF(ERROR, errno != ENOENT) << "stat " << path.value();
|
PLOG(ERROR) << "stat " << path.value();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return S_ISREG(st.st_mode);
|
return S_ISREG(st.st_mode);
|
||||||
@ -69,11 +69,9 @@ bool IsDirectory(const base::FilePath& path, bool allow_symlinks) {
|
|||||||
PLOG(ERROR) << "stat " << path.value();
|
PLOG(ERROR) << "stat " << path.value();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (lstat(path.value().c_str(), &st) != 0) {
|
||||||
if (lstat(path.value().c_str(), &st) != 0) {
|
PLOG(ERROR) << "lstat " << path.value();
|
||||||
PLOG(ERROR) << "lstat " << path.value();
|
return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return S_ISDIR(st.st_mode);
|
return S_ISDIR(st.st_mode);
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include "base/logging.h"
|
#include "base/logging.h"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
#include "test/gtest_disabled.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"
|
||||||
|
|
||||||
@ -60,16 +61,16 @@ TEST(Filesystem, MoveFileOrDirectory) {
|
|||||||
base::FilePath file2(temp_dir.path().Append(FILE_PATH_LITERAL("file2")));
|
base::FilePath file2(temp_dir.path().Append(FILE_PATH_LITERAL("file2")));
|
||||||
EXPECT_TRUE(MoveFileOrDirectory(file, file2));
|
EXPECT_TRUE(MoveFileOrDirectory(file, file2));
|
||||||
EXPECT_TRUE(IsRegularFile(file2));
|
EXPECT_TRUE(IsRegularFile(file2));
|
||||||
EXPECT_FALSE(IsRegularFile(file));
|
EXPECT_FALSE(PathExists(file));
|
||||||
|
|
||||||
EXPECT_FALSE(MoveFileOrDirectory(file, file2));
|
EXPECT_FALSE(MoveFileOrDirectory(file, file2));
|
||||||
EXPECT_TRUE(IsRegularFile(file2));
|
EXPECT_TRUE(IsRegularFile(file2));
|
||||||
EXPECT_FALSE(IsRegularFile(file));
|
EXPECT_FALSE(PathExists(file));
|
||||||
|
|
||||||
ASSERT_TRUE(CreateFile(file));
|
ASSERT_TRUE(CreateFile(file));
|
||||||
EXPECT_TRUE(MoveFileOrDirectory(file2, file));
|
EXPECT_TRUE(MoveFileOrDirectory(file2, file));
|
||||||
EXPECT_TRUE(IsRegularFile(file));
|
EXPECT_TRUE(IsRegularFile(file));
|
||||||
EXPECT_FALSE(IsRegularFile(file2));
|
EXPECT_FALSE(PathExists(file2));
|
||||||
|
|
||||||
// directories
|
// directories
|
||||||
base::FilePath dir(temp_dir.path().Append(FILE_PATH_LITERAL("dir")));
|
base::FilePath dir(temp_dir.path().Append(FILE_PATH_LITERAL("dir")));
|
||||||
@ -100,6 +101,19 @@ TEST(Filesystem, MoveFileOrDirectory) {
|
|||||||
EXPECT_FALSE(MoveFileOrDirectory(dir2, file));
|
EXPECT_FALSE(MoveFileOrDirectory(dir2, file));
|
||||||
EXPECT_TRUE(IsDirectory(dir2, false));
|
EXPECT_TRUE(IsDirectory(dir2, false));
|
||||||
EXPECT_TRUE(IsRegularFile(file));
|
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
|
// file links
|
||||||
base::FilePath link(temp_dir.path().Append(FILE_PATH_LITERAL("link")));
|
base::FilePath link(temp_dir.path().Append(FILE_PATH_LITERAL("link")));
|
||||||
@ -135,6 +149,10 @@ TEST(Filesystem, MoveFileOrDirectory) {
|
|||||||
EXPECT_FALSE(PathExists(link));
|
EXPECT_FALSE(PathExists(link));
|
||||||
|
|
||||||
// directory links
|
// 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));
|
ASSERT_TRUE(CreateSymbolicLink(dir, link));
|
||||||
|
|
||||||
EXPECT_TRUE(MoveFileOrDirectory(link, link2));
|
EXPECT_TRUE(MoveFileOrDirectory(link, link2));
|
||||||
@ -148,6 +166,8 @@ TEST(Filesystem, MoveFileOrDirectory) {
|
|||||||
EXPECT_FALSE(PathExists(link2));
|
EXPECT_FALSE(PathExists(link2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // !OS_FUCHSIA
|
||||||
|
|
||||||
TEST(Filesystem, IsRegularFile) {
|
TEST(Filesystem, IsRegularFile) {
|
||||||
EXPECT_FALSE(IsRegularFile(base::FilePath()));
|
EXPECT_FALSE(IsRegularFile(base::FilePath()));
|
||||||
|
|
||||||
@ -159,6 +179,18 @@ TEST(Filesystem, IsRegularFile) {
|
|||||||
|
|
||||||
ASSERT_TRUE(CreateFile(file));
|
ASSERT_TRUE(CreateFile(file));
|
||||||
EXPECT_TRUE(IsRegularFile(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")));
|
base::FilePath link(temp_dir.path().Append(FILE_PATH_LITERAL("link")));
|
||||||
ASSERT_TRUE(CreateSymbolicLink(file, link));
|
ASSERT_TRUE(CreateSymbolicLink(file, link));
|
||||||
@ -173,6 +205,8 @@ TEST(Filesystem, IsRegularFile) {
|
|||||||
EXPECT_FALSE(IsRegularFile(dir_link));
|
EXPECT_FALSE(IsRegularFile(dir_link));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // !OS_FUCHSIA
|
||||||
|
|
||||||
TEST(Filesystem, IsDirectory) {
|
TEST(Filesystem, IsDirectory) {
|
||||||
EXPECT_FALSE(IsDirectory(base::FilePath(), false));
|
EXPECT_FALSE(IsDirectory(base::FilePath(), false));
|
||||||
EXPECT_FALSE(IsDirectory(base::FilePath(), true));
|
EXPECT_FALSE(IsDirectory(base::FilePath(), true));
|
||||||
@ -187,6 +221,18 @@ TEST(Filesystem, IsDirectory) {
|
|||||||
ASSERT_TRUE(CreateFile(file));
|
ASSERT_TRUE(CreateFile(file));
|
||||||
EXPECT_FALSE(IsDirectory(file, false));
|
EXPECT_FALSE(IsDirectory(file, false));
|
||||||
EXPECT_FALSE(IsDirectory(file, true));
|
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")));
|
base::FilePath link(temp_dir.path().Append(FILE_PATH_LITERAL("link")));
|
||||||
ASSERT_TRUE(CreateSymbolicLink(file, link));
|
ASSERT_TRUE(CreateSymbolicLink(file, link));
|
||||||
@ -204,6 +250,8 @@ TEST(Filesystem, IsDirectory) {
|
|||||||
EXPECT_TRUE(IsDirectory(dir_link, true));
|
EXPECT_TRUE(IsDirectory(dir_link, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // !OS_FUCHSIA
|
||||||
|
|
||||||
TEST(Filesystem, RemoveFile) {
|
TEST(Filesystem, RemoveFile) {
|
||||||
EXPECT_FALSE(LoggingRemoveFile(base::FilePath()));
|
EXPECT_FALSE(LoggingRemoveFile(base::FilePath()));
|
||||||
|
|
||||||
@ -216,27 +264,45 @@ TEST(Filesystem, RemoveFile) {
|
|||||||
ASSERT_TRUE(CreateFile(file));
|
ASSERT_TRUE(CreateFile(file));
|
||||||
EXPECT_TRUE(IsRegularFile(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")));
|
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(PathExists(link));
|
EXPECT_FALSE(PathExists(link));
|
||||||
EXPECT_TRUE(PathExists(file));
|
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));
|
ASSERT_TRUE(CreateSymbolicLink(dir, link));
|
||||||
EXPECT_TRUE(LoggingRemoveFile(link));
|
EXPECT_TRUE(LoggingRemoveFile(link));
|
||||||
EXPECT_FALSE(PathExists(link));
|
EXPECT_FALSE(PathExists(link));
|
||||||
EXPECT_TRUE(PathExists(dir));
|
EXPECT_TRUE(PathExists(dir));
|
||||||
|
|
||||||
EXPECT_TRUE(LoggingRemoveFile(file));
|
|
||||||
EXPECT_FALSE(IsRegularFile(file));
|
|
||||||
EXPECT_FALSE(LoggingRemoveFile(file));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // !OS_FUCHSIA
|
||||||
|
|
||||||
TEST(Filesystem, RemoveDirectory) {
|
TEST(Filesystem, RemoveDirectory) {
|
||||||
EXPECT_FALSE(LoggingRemoveDirectory(base::FilePath()));
|
EXPECT_FALSE(LoggingRemoveDirectory(base::FilePath()));
|
||||||
|
|
||||||
@ -253,6 +319,25 @@ TEST(Filesystem, RemoveDirectory) {
|
|||||||
EXPECT_FALSE(LoggingRemoveDirectory(file));
|
EXPECT_FALSE(LoggingRemoveDirectory(file));
|
||||||
EXPECT_FALSE(LoggingRemoveDirectory(dir));
|
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")));
|
base::FilePath link(temp_dir.path().Append(FILE_PATH_LITERAL("link")));
|
||||||
ASSERT_TRUE(CreateSymbolicLink(file, link));
|
ASSERT_TRUE(CreateSymbolicLink(file, link));
|
||||||
EXPECT_FALSE(LoggingRemoveDirectory(link));
|
EXPECT_FALSE(LoggingRemoveDirectory(link));
|
||||||
@ -261,11 +346,10 @@ TEST(Filesystem, RemoveDirectory) {
|
|||||||
ASSERT_TRUE(CreateSymbolicLink(dir, link));
|
ASSERT_TRUE(CreateSymbolicLink(dir, link));
|
||||||
EXPECT_FALSE(LoggingRemoveDirectory(link));
|
EXPECT_FALSE(LoggingRemoveDirectory(link));
|
||||||
EXPECT_TRUE(LoggingRemoveFile(link));
|
EXPECT_TRUE(LoggingRemoveFile(link));
|
||||||
|
|
||||||
ASSERT_TRUE(LoggingRemoveFile(file));
|
|
||||||
EXPECT_TRUE(LoggingRemoveDirectory(dir));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // !OS_FUCHSIA
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace test
|
} // namespace test
|
||||||
} // namespace crashpad
|
} // namespace crashpad
|
||||||
|
@ -20,9 +20,9 @@
|
|||||||
|
|
||||||
#include "base/logging.h"
|
#include "base/logging.h"
|
||||||
#include "base/strings/utf_string_conversions.h"
|
#include "base/strings/utf_string_conversions.h"
|
||||||
#include "build/build_config.h"
|
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
#include "test/errors.h"
|
#include "test/errors.h"
|
||||||
|
#include "test/scoped_temp_dir.h"
|
||||||
#include "util/file/file_io.h"
|
#include "util/file/file_io.h"
|
||||||
#include "util/file/filesystem.h"
|
#include "util/file/filesystem.h"
|
||||||
|
|
||||||
@ -37,6 +37,60 @@
|
|||||||
namespace crashpad {
|
namespace crashpad {
|
||||||
namespace test {
|
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) {
|
bool CreateFile(const base::FilePath& file) {
|
||||||
ScopedFileHandle fd(LoggingOpenFileForWrite(
|
ScopedFileHandle fd(LoggingOpenFileForWrite(
|
||||||
file, FileWriteMode::kCreateOrFail, FilePermissions::kOwnerOnly));
|
file, FileWriteMode::kCreateOrFail, FilePermissions::kOwnerOnly));
|
||||||
@ -44,6 +98,35 @@ bool CreateFile(const base::FilePath& file) {
|
|||||||
return fd.is_valid();
|
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,
|
bool CreateSymbolicLink(const base::FilePath& target_path,
|
||||||
const base::FilePath& symlink_path) {
|
const base::FilePath& symlink_path) {
|
||||||
#if defined(OS_POSIX)
|
#if defined(OS_POSIX)
|
||||||
@ -53,35 +136,24 @@ bool CreateSymbolicLink(const base::FilePath& target_path,
|
|||||||
PLOG(ERROR) << "symlink";
|
PLOG(ERROR) << "symlink";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
#elif defined(OS_WIN)
|
#elif defined(OS_WIN)
|
||||||
|
DWORD symbolic_link_flags = 0;
|
||||||
|
SymbolicLinkFlags(&symbolic_link_flags);
|
||||||
if (!::CreateSymbolicLink(
|
if (!::CreateSymbolicLink(
|
||||||
symlink_path.value().c_str(),
|
symlink_path.value().c_str(),
|
||||||
target_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";
|
PLOG(ERROR) << "CreateSymbolicLink";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif // OS_POSIX
|
|
||||||
return true;
|
return true;
|
||||||
|
#endif // OS_POSIX
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PathExists(const base::FilePath& path) {
|
#endif // !OS_FUCHSIA
|
||||||
#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
|
||||||
|
@ -17,15 +17,41 @@
|
|||||||
|
|
||||||
#include "base/files/file_path.h"
|
#include "base/files/file_path.h"
|
||||||
|
|
||||||
|
#include "build/build_config.h"
|
||||||
|
|
||||||
namespace crashpad {
|
namespace crashpad {
|
||||||
namespace test {
|
namespace test {
|
||||||
|
|
||||||
bool CreateFile(const base::FilePath& file);
|
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,
|
bool CreateSymbolicLink(const base::FilePath& target_path,
|
||||||
const base::FilePath& symlink_path);
|
const base::FilePath& symlink_path);
|
||||||
|
|
||||||
bool PathExists(const base::FilePath& path);
|
#endif // !OS_FUCHSIA || DOXYGEN
|
||||||
|
|
||||||
} // namespace test
|
} // namespace test
|
||||||
} // namespace crashpad
|
} // namespace crashpad
|
||||||
|
@ -82,8 +82,7 @@ bool MoveFileOrDirectory(const base::FilePath& source,
|
|||||||
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) {
|
||||||
PLOG_IF(ERROR, GetLastError() != ERROR_FILE_NOT_FOUND)
|
PLOG(ERROR) << "GetFileAttributes " << base::UTF16ToUTF8(path.value());
|
||||||
<< "GetFileAttributes " << base::UTF16ToUTF8(path.value());
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ((fileattr & FILE_ATTRIBUTE_DIRECTORY) != 0 ||
|
if ((fileattr & FILE_ATTRIBUTE_DIRECTORY) != 0 ||
|
||||||
|
Loading…
x
Reference in New Issue
Block a user