mirror of
https://github.com/facebook/sapling.git
synced 2024-10-05 06:18:07 +03:00
to satisfy secfs validation suite, limit path components to 255 bytes
Summary: Most filesystems limit path components to 255. To remain consistent, let's have Eden do the same, at least for write operations. Reviewed By: simpkins Differential Revision: D8151020 fbshipit-source-id: 251da94a076f5765111c8e3d9d8a25c37682e2e3
This commit is contained in:
parent
b9e09a508f
commit
0797ee3a35
@ -288,6 +288,8 @@ folly::Future<fuse_entry_out> EdenDispatcher::link(
|
||||
newParent,
|
||||
newName);
|
||||
|
||||
validatePathComponentLength(newName);
|
||||
|
||||
// We intentionally do not support hard links.
|
||||
// These generally cannot be tracked in source control (git or mercurial)
|
||||
// and are not portable to non-Unix platforms.
|
||||
|
@ -978,6 +978,7 @@ TreeInode::create(PathComponentPiece name, mode_t mode, int /*flags*/) {
|
||||
std::shared_ptr<EdenFileHandle> handle;
|
||||
FileInodePtr inode;
|
||||
|
||||
validatePathComponentLength(name);
|
||||
materialize();
|
||||
|
||||
// We need to scope the write lock as the getattr call below implicitly
|
||||
@ -1014,6 +1015,7 @@ TreeInode::create(PathComponentPiece name, mode_t mode, int /*flags*/) {
|
||||
FileInodePtr TreeInode::symlink(
|
||||
PathComponentPiece name,
|
||||
folly::StringPiece symlinkTarget) {
|
||||
validatePathComponentLength(name);
|
||||
materialize();
|
||||
|
||||
{
|
||||
@ -1026,6 +1028,8 @@ FileInodePtr TreeInode::symlink(
|
||||
}
|
||||
|
||||
FileInodePtr TreeInode::mknod(PathComponentPiece name, mode_t mode, dev_t dev) {
|
||||
validatePathComponentLength(name);
|
||||
|
||||
// Compute the effective name of the node they want to create.
|
||||
RelativePath targetName;
|
||||
std::shared_ptr<EdenFileHandle> handle;
|
||||
@ -1058,6 +1062,7 @@ TreeInodePtr TreeInode::mkdir(PathComponentPiece name, mode_t mode) {
|
||||
if (getNodeId() == getMount()->getDotEdenInodeNumber()) {
|
||||
throw InodeError(EPERM, inodePtrFromThis(), name);
|
||||
}
|
||||
validatePathComponentLength(name);
|
||||
|
||||
RelativePath targetName;
|
||||
// Compute the effective name of the node they want to create.
|
||||
@ -1433,6 +1438,7 @@ Future<Unit> TreeInode::rename(
|
||||
if (destParent->getNodeId() == getMount()->getDotEdenInodeNumber()) {
|
||||
return makeFuture<Unit>(InodeError(EPERM, destParent, destName));
|
||||
}
|
||||
validatePathComponentLength(destName);
|
||||
|
||||
bool needSrc = false;
|
||||
bool needDest = false;
|
||||
|
101
eden/fs/inodes/test/EdenDispatcherTest.cpp
Normal file
101
eden/fs/inodes/test/EdenDispatcherTest.cpp
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (c) 2004-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
*/
|
||||
#include "eden/fs/inodes/EdenDispatcher.h"
|
||||
|
||||
#include <folly/experimental/TestUtil.h>
|
||||
#include <folly/test/TestUtils.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include "eden/fs/testharness/FakeTreeBuilder.h"
|
||||
#include "eden/fs/testharness/TestMount.h"
|
||||
|
||||
using namespace facebook::eden;
|
||||
using namespace std::chrono_literals;
|
||||
using namespace folly::string_piece_literals;
|
||||
|
||||
namespace {
|
||||
struct EdenDispatcherTest : ::testing::Test {
|
||||
EdenDispatcherTest() : mount{builder} {}
|
||||
FakeTreeBuilder builder;
|
||||
TestMount mount;
|
||||
};
|
||||
|
||||
constexpr auto kTooLongPiece = folly::StringPiece{
|
||||
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
||||
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
||||
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
||||
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"};
|
||||
static_assert(256 == kTooLongPiece.size(), "256 is one larger than the max!");
|
||||
|
||||
static const auto kTooLong = PathComponentPiece{kTooLongPiece};
|
||||
} // namespace
|
||||
|
||||
TEST_F(EdenDispatcherTest, mknodReturnsNameTooLong) {
|
||||
try {
|
||||
mount.getDispatcher()
|
||||
->mknod(kRootNodeId, kTooLong, S_IFREG | 0644, 0)
|
||||
.get(0ms);
|
||||
FAIL() << "should throw";
|
||||
} catch (std::system_error& e) {
|
||||
EXPECT_EQ(ENAMETOOLONG, e.code().value());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(EdenDispatcherTest, mkdirReturnsNameTooLong) {
|
||||
try {
|
||||
mount.getDispatcher()
|
||||
->mkdir(kRootNodeId, kTooLong, S_IFDIR | 0755)
|
||||
.get(0ms);
|
||||
FAIL() << "should throw";
|
||||
} catch (std::system_error& e) {
|
||||
EXPECT_EQ(ENAMETOOLONG, e.code().value());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(EdenDispatcherTest, symlinkReturnsNameTooLong) {
|
||||
try {
|
||||
mount.getDispatcher()->symlink(kRootNodeId, kTooLong, "aoeu"_sp).get(0ms);
|
||||
FAIL() << "should throw";
|
||||
} catch (std::system_error& e) {
|
||||
EXPECT_EQ(ENAMETOOLONG, e.code().value());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(EdenDispatcherTest, renameReturnsNameTooLong) {
|
||||
try {
|
||||
mount.getDispatcher()
|
||||
->rename(kRootNodeId, "oldname"_pc, kRootNodeId, kTooLong)
|
||||
.get(0ms);
|
||||
FAIL() << "should throw";
|
||||
} catch (std::system_error& e) {
|
||||
EXPECT_EQ(ENAMETOOLONG, e.code().value());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(EdenDispatcherTest, linkReturnsNameTooLong) {
|
||||
try {
|
||||
// Eden doesn't support hard links yet and this link call could never work
|
||||
// in the first place, but at least validate the target name length.
|
||||
mount.getDispatcher()->link(kRootNodeId, kRootNodeId, kTooLong).get(0ms);
|
||||
FAIL() << "should throw";
|
||||
} catch (std::system_error& e) {
|
||||
EXPECT_EQ(ENAMETOOLONG, e.code().value());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(EdenDispatcherTest, createReturnsNameTooLong) {
|
||||
try {
|
||||
mount.getDispatcher()
|
||||
->create(kRootNodeId, kTooLong, S_IFREG | 0644, 0)
|
||||
.get(0ms);
|
||||
FAIL() << "should throw";
|
||||
} catch (std::system_error& e) {
|
||||
EXPECT_EQ(ENAMETOOLONG, e.code().value());
|
||||
}
|
||||
}
|
@ -189,6 +189,10 @@ void TestMount::initTestDirectory() {
|
||||
backingStore_ = make_shared<FakeBackingStore>(localStore_);
|
||||
}
|
||||
|
||||
Dispatcher* TestMount::getDispatcher() const {
|
||||
return edenMount_->getDispatcher();
|
||||
}
|
||||
|
||||
void TestMount::remount() {
|
||||
// Create a new copy of the ClientConfig
|
||||
auto config = make_unique<ClientConfig>(*edenMount_->getConfig());
|
||||
|
@ -160,6 +160,8 @@ class TestMount {
|
||||
return backingStore_;
|
||||
}
|
||||
|
||||
Dispatcher* getDispatcher() const;
|
||||
|
||||
/**
|
||||
* Access to the TestMount's FakeClock which is referenced by the underlying
|
||||
* EdenMount (and thus inodes).
|
||||
|
@ -239,5 +239,12 @@ AbsolutePath normalizeBestEffort(folly::StringPiece path) {
|
||||
return normalizeBestEffort(path.str().c_str());
|
||||
}
|
||||
|
||||
void validatePathComponentLength(PathComponentPiece name) {
|
||||
if (name.value().size() > kMaxPathComponentLength) {
|
||||
folly::throwSystemErrorExplicit(
|
||||
ENAMETOOLONG, "path component too long: ", name);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace eden
|
||||
} // namespace facebook
|
||||
|
@ -36,6 +36,13 @@ folly::StringPiece dirname(folly::StringPiece path);
|
||||
enum : char { kDirSeparator = '/' };
|
||||
constexpr folly::StringPiece kDirSeparatorStr{"/"};
|
||||
|
||||
/**
|
||||
* FUSE supports components up to 1024 (FUSE_NAME_MAX) by default. For
|
||||
* compatibility with other filesystems, Eden will limit to 255.
|
||||
* https://en.wikipedia.org/wiki/Comparison_of_file_systems
|
||||
*/
|
||||
enum : size_t { kMaxPathComponentLength = 255 };
|
||||
|
||||
/* Some helpers for working with path composition.
|
||||
* Goals:
|
||||
*
|
||||
@ -1636,6 +1643,12 @@ normalizeBestEffort(const T& path) {
|
||||
return normalizeBestEffort(path.c_str());
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws std::system_error with ENAMETOOLONG if the given PathComponent is
|
||||
* longer than kMaxPathComponentLength.
|
||||
*/
|
||||
void validatePathComponentLength(PathComponentPiece name);
|
||||
|
||||
/**
|
||||
* Convenient literals for constructing path types.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user