mirror of
https://github.com/facebook/sapling.git
synced 2024-10-07 15:27:13 +03:00
a001da77ea
Summary: We want to load the children overlay, not its parent. In the case where only materialized files were requested, the code would infinitively recurse onto non-loaded but materialized inodes. Reviewed By: chadaustin Differential Revision: D34775507 fbshipit-source-id: ed5f4a2cba5fb3cfd03990b6b8696d65e84dde72
100 lines
2.6 KiB
C++
100 lines
2.6 KiB
C++
/*
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This software may be used and distributed according to the terms of the
|
|
* GNU General Public License version 2.
|
|
*/
|
|
|
|
#include "eden/fs/inodes/Traverse.h"
|
|
|
|
#include <folly/logging/xlog.h>
|
|
#include "eden/fs/inodes/EdenMount.h"
|
|
#include "eden/fs/inodes/FileInode.h"
|
|
#include "eden/fs/inodes/TreeInode.h"
|
|
|
|
namespace facebook::eden {
|
|
|
|
namespace {
|
|
|
|
std::vector<ChildEntry> parseDirContents(const DirContents& contents) {
|
|
std::vector<ChildEntry> results;
|
|
results.reserve(contents.size());
|
|
for (const auto& [name, entry] : contents) {
|
|
results.push_back(ChildEntry{
|
|
name,
|
|
entry.getDtype(),
|
|
entry.getInodeNumber(),
|
|
entry.getOptionalHash(),
|
|
entry.getInodePtr()});
|
|
}
|
|
return results;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
void traverseTreeInodeChildren(
|
|
Overlay* overlay,
|
|
const std::vector<ChildEntry>& children,
|
|
RelativePathPiece rootPath,
|
|
InodeNumber ino,
|
|
const std::optional<ObjectId>& hash,
|
|
uint64_t fsRefcount,
|
|
TraversalCallbacks& callbacks) {
|
|
XLOG(DBG7) << "Traversing: " << rootPath;
|
|
callbacks.visitTreeInode(rootPath, ino, hash, fsRefcount, children);
|
|
for (auto& entry : children) {
|
|
auto childPath = rootPath + entry.name;
|
|
if (auto child = entry.loadedChild) {
|
|
if (auto* loadedTreeInode = child.asTreeOrNull()) {
|
|
if (callbacks.shouldRecurse(entry)) {
|
|
traverseObservedInodes(*loadedTreeInode, childPath, callbacks);
|
|
}
|
|
}
|
|
} else {
|
|
if (dtype_t::Dir == entry.dtype) {
|
|
if (callbacks.shouldRecurse(entry)) {
|
|
// If we are able to load a child directory from the overlay, then
|
|
// this child entry has been allocated, and can be traversed.
|
|
auto contents = overlay->loadOverlayDir(entry.ino);
|
|
if (!contents.empty()) {
|
|
traverseTreeInodeChildren(
|
|
overlay,
|
|
parseDirContents(contents),
|
|
childPath,
|
|
entry.ino,
|
|
entry.hash,
|
|
0,
|
|
callbacks);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void traverseObservedInodes(
|
|
const TreeInode& root,
|
|
RelativePathPiece rootPath,
|
|
TraversalCallbacks& callbacks) {
|
|
auto* overlay = root.getMount()->getOverlay();
|
|
|
|
std::vector<ChildEntry> children;
|
|
std::optional<ObjectId> hash;
|
|
{
|
|
auto contents = root.getContents().rlock();
|
|
children = parseDirContents(contents->entries);
|
|
hash = contents->treeHash;
|
|
}
|
|
|
|
traverseTreeInodeChildren(
|
|
overlay,
|
|
children,
|
|
rootPath,
|
|
root.getNodeId(),
|
|
hash,
|
|
root.debugGetFsRefcount(),
|
|
callbacks);
|
|
}
|
|
|
|
} // namespace facebook::eden
|