blob: e4ede8a387a8cb56cc37364d8fcbc7c5873e62f1 [file] [log] [blame]
// Copyright 2019 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "smbfs/inode_map.h"
#include <utility>
#include <base/check.h>
#include <base/check_op.h>
#include <base/containers/contains.h>
#include <base/logging.h>
namespace smbfs {
struct InodeMap::Entry {
Entry(ino_t inode, const base::FilePath& path) : inode(inode), path(path) {}
~Entry() = default;
uint64_t refcount = 0;
const ino_t inode;
base::FilePath path;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(Entry);
};
InodeMap::InodeMap(ino_t root_inode)
: root_inode_(root_inode), seq_num_(root_inode + 1) {
DCHECK(root_inode_);
// Insert an entry for the root inode.
std::unique_ptr<Entry> entry =
std::make_unique<Entry>(root_inode, base::FilePath("/"));
entry->refcount = 1;
files_.emplace("/", entry.get());
inodes_.emplace(root_inode, std::move(entry));
}
InodeMap::~InodeMap() = default;
InodeMap::Entry* InodeMap::GetEntryByPath(const base::FilePath& path) {
CHECK(!path.empty());
CHECK(path.IsAbsolute());
CHECK(!path.ReferencesParent());
const auto it = files_.find(path.value());
if (it != files_.end()) {
return it->second;
}
DCHECK(!base::Contains(inodes_, seq_num_));
ino_t inode = seq_num_++;
CHECK(inode) << "Inode wrap around";
std::unique_ptr<Entry> entry = std::make_unique<Entry>(inode, path);
Entry* raw_entry = entry.get();
files_.emplace(path.value(), raw_entry);
inodes_.emplace(inode, std::move(entry));
return raw_entry;
}
ino_t InodeMap::GetWeakInode(const base::FilePath& path) {
Entry* entry = GetEntryByPath(path);
return entry->inode;
}
ino_t InodeMap::IncInodeRef(const base::FilePath& path) {
Entry* entry = GetEntryByPath(path);
entry->refcount++;
CHECK(entry->refcount) << "Refcount wrap around";
return entry->inode;
}
base::FilePath InodeMap::GetPath(ino_t inode) const {
const auto it = inodes_.find(inode);
if (it == inodes_.end() || it->second->refcount == 0) {
return {};
}
return it->second->path;
}
bool InodeMap::PathExists(const base::FilePath& path) const {
auto it = files_.find(path.value());
return it != files_.end() && it->second->refcount > 0;
}
void InodeMap::UpdatePath(ino_t inode, const base::FilePath& new_path) {
CHECK_NE(inode, root_inode_);
CHECK(!new_path.empty());
CHECK(new_path.IsAbsolute());
CHECK(!new_path.ReferencesParent());
DCHECK(!PathExists(new_path));
const auto it = inodes_.find(inode);
CHECK(it != inodes_.end());
CHECK_GT(it->second->refcount, 0);
const base::FilePath old_path = it->second->path;
it->second->path = new_path;
files_.erase(old_path.value());
files_.emplace(new_path.value(), it->second.get());
}
bool InodeMap::Forget(ino_t inode, uint64_t forget_count) {
if (inode == root_inode_) {
// Ignore the root inode.
return false;
}
const auto it = inodes_.find(inode);
CHECK(it != inodes_.end());
Entry* entry = it->second.get();
CHECK_GE(entry->refcount, forget_count);
entry->refcount -= forget_count;
if (entry->refcount > 0) {
return false;
}
size_t removed = files_.erase(entry->path.value());
DCHECK_EQ(removed, 1);
inodes_.erase(it);
return true;
}
} // namespace smbfs