blob: cbb64c6f0d5efc86df2965940d7c943d9283814d [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_DEVELOPER_FORENSICS_TESTING_SCOPED_MEMFS_MANAGER_H_
#define SRC_DEVELOPER_FORENSICS_TESTING_SCOPED_MEMFS_MANAGER_H_
#include <fcntl.h>
#include <lib/fdio/namespace.h>
#include <lib/syslog/cpp/macros.h>
#include <memory>
#include <string>
#include <unordered_map>
#include <fbl/unique_fd.h>
#include "src/lib/files/scoped_temp_dir.h"
namespace forensics::testing {
// Manages creating and destroying directories in the calling processes namespace.
class ScopedMemFsManager {
public:
ScopedMemFsManager() {
tmp_storage_.reset(open("/tmp", O_RDONLY | O_DIRECTORY));
FX_CHECK(tmp_storage_.is_valid());
FX_CHECK(fdio_ns_get_installed(&ns_) == ZX_OK);
}
~ScopedMemFsManager() {
for (auto& [path, binding] : bindings_) {
FX_CHECK(fdio_ns_unbind(ns_, path.c_str()) == ZX_OK);
binding.reset();
if (path == "/tmp") {
// Rebind the real /tmp if it was unbound.
FX_CHECK(fdio_ns_bind_fd(ns_, "/tmp", tmp_storage_.get()) == ZX_OK);
}
}
}
bool Contains(const std::string& path) const { return bindings_.count(path) != 0; }
// Create a directory at |path| in the component's namespace.
void Create(const std::string& path) {
FX_CHECK(!Contains(path));
if (path == "/tmp") {
// /tmp already exists in the namespace and backs all of the temporary directories. In order
// to provide a scoped /tmp, the main /tmp needs to be unbound from the namespace.
// `tmp_storage_` preserves a handle to the main /tmp and allows it to be bound again in the
// destructor.
FX_CHECK(fdio_ns_unbind(ns_, "/tmp") == ZX_OK);
}
auto temp_dir = std::make_unique<files::ScopedTempDirAt>(tmp_storage_.get());
fbl::unique_fd temp_dir_fd(
openat(temp_dir->root_fd(), temp_dir->path().c_str(), O_RDONLY | O_DIRECTORY));
FX_CHECK(temp_dir_fd.is_valid());
FX_CHECK(fdio_ns_bind_fd(ns_, path.c_str(), temp_dir_fd.get()) == ZX_OK);
bindings_.emplace(path, std::move(temp_dir));
}
private:
fbl::unique_fd tmp_storage_;
fdio_ns_t* ns_;
std::unordered_map<std::string, std::unique_ptr<files::ScopedTempDirAt>> bindings_;
};
} // namespace forensics::testing
#endif // SRC_DEVELOPER_FORENSICS_TESTING_SCOPED_MEMFS_MANAGER_H_