2016-05-12 23:43:17 +03:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2016, 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 "TreeEntryFileInode.h"
|
|
|
|
|
2016-05-17 00:48:25 +03:00
|
|
|
#include "FileData.h"
|
2016-05-12 23:43:17 +03:00
|
|
|
#include "TreeEntryFileHandle.h"
|
|
|
|
#include "eden/fs/store/LocalStore.h"
|
|
|
|
|
|
|
|
using folly::Future;
|
|
|
|
using folly::StringPiece;
|
|
|
|
using std::string;
|
|
|
|
using std::vector;
|
|
|
|
|
|
|
|
const string kXattrSha1 = "user.sha1";
|
|
|
|
|
|
|
|
namespace facebook {
|
|
|
|
namespace eden {
|
|
|
|
|
|
|
|
TreeEntryFileInode::TreeEntryFileInode(
|
|
|
|
fuse_ino_t ino,
|
|
|
|
std::shared_ptr<TreeInode> parentInode,
|
|
|
|
const TreeEntry* entry)
|
|
|
|
: fusell::FileInode(ino), parentInode_(parentInode), entry_(entry) {}
|
|
|
|
|
|
|
|
folly::Future<fusell::Dispatcher::Attr> TreeEntryFileInode::getattr() {
|
|
|
|
fusell::Dispatcher::Attr attr;
|
|
|
|
CHECK_NOTNULL(entry_);
|
|
|
|
|
|
|
|
attr.st.st_ino = ino_;
|
|
|
|
switch (entry_->getFileType()) {
|
|
|
|
case FileType::SYMLINK:
|
|
|
|
attr.st.st_mode = S_IFLNK;
|
|
|
|
break;
|
|
|
|
case FileType::REGULAR_FILE:
|
|
|
|
attr.st.st_mode = S_IFREG;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
folly::throwSystemErrorExplicit(
|
|
|
|
EINVAL,
|
|
|
|
"TreeEntry has an invalid file type: ",
|
|
|
|
entry_->getFileType());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Bit 1 is the executable flag. Flesh out all the permission bits based on
|
|
|
|
// the executable bit being set or not.
|
|
|
|
if (entry_->getOwnerPermissions() & 1) {
|
|
|
|
attr.st.st_mode |= 0755;
|
|
|
|
} else {
|
|
|
|
attr.st.st_mode |= 0644;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We don't know the size unless we fetch the data :-/
|
|
|
|
auto blob = parentInode_->getStore()->getBlob(entry_->getHash());
|
|
|
|
auto buf = blob->getContents();
|
|
|
|
attr.st.st_size = buf.computeChainDataLength();
|
|
|
|
|
|
|
|
return attr;
|
|
|
|
}
|
|
|
|
|
|
|
|
folly::Future<std::string> TreeEntryFileInode::readlink() {
|
|
|
|
CHECK_NOTNULL(entry_);
|
|
|
|
switch (entry_->getFileType()) {
|
|
|
|
case FileType::SYMLINK: {
|
|
|
|
auto blob = parentInode_->getStore()->getBlob(entry_->getHash());
|
|
|
|
auto buf = blob->getContents();
|
|
|
|
return buf.moveToFbString().toStdString();
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
// man 2 readlink says: EINVAL The named file is not a symbolic link.
|
|
|
|
folly::throwSystemErrorExplicit(EINVAL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-17 00:48:25 +03:00
|
|
|
std::shared_ptr<FileData> TreeEntryFileInode::getOrLoadData() {
|
2016-05-12 23:43:17 +03:00
|
|
|
std::unique_lock<std::mutex> lock(mutex_);
|
2016-05-17 00:48:25 +03:00
|
|
|
if (!data_) {
|
|
|
|
data_ =
|
|
|
|
std::make_shared<FileData>(mutex_, parentInode_->getStore(), entry_);
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
2016-05-17 00:48:25 +03:00
|
|
|
return data_;
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void TreeEntryFileInode::fileHandleDidClose() {
|
|
|
|
std::unique_lock<std::mutex> lock(mutex_);
|
2016-05-17 00:48:25 +03:00
|
|
|
if (data_.unique()) {
|
|
|
|
// We're the only remaining user, no need to keep it around
|
|
|
|
data_.reset();
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
folly::Future<fusell::FileHandle*> TreeEntryFileInode::open(
|
|
|
|
const struct fuse_file_info& fi) {
|
|
|
|
CHECK_NOTNULL(entry_);
|
|
|
|
switch (entry_->getFileType()) {
|
|
|
|
case FileType::REGULAR_FILE: {
|
|
|
|
if ((fi.flags & (O_RDWR | O_WRONLY)) != 0) {
|
|
|
|
// Don't allow writes.
|
|
|
|
folly::throwSystemErrorExplicit(EROFS);
|
|
|
|
}
|
|
|
|
|
2016-05-17 00:48:25 +03:00
|
|
|
auto data = getOrLoadData();
|
|
|
|
SCOPE_EXIT {
|
|
|
|
data.reset();
|
2016-05-12 23:43:17 +03:00
|
|
|
fileHandleDidClose();
|
|
|
|
};
|
|
|
|
|
|
|
|
return new TreeEntryFileHandle(
|
2016-05-17 00:48:25 +03:00
|
|
|
std::static_pointer_cast<TreeEntryFileInode>(shared_from_this()),
|
|
|
|
data);
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
case FileType::SYMLINK:
|
|
|
|
// man 2 open says: ELOOP ... or O_NOFOLLOW was specified but pathname
|
|
|
|
// was a symbolic link.
|
|
|
|
// We shouldn't really be able to get here in any case.
|
|
|
|
folly::throwSystemErrorExplicit(ELOOP);
|
|
|
|
default:
|
|
|
|
// We really really should never be able to get here.
|
|
|
|
folly::throwSystemErrorExplicit(
|
|
|
|
EIO, "impossible filetype ", entry_->getFileType());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<vector<string>> TreeEntryFileInode::listxattr() {
|
|
|
|
// Currently, we only return a non-empty vector for regular files, and we
|
|
|
|
// assume that the SHA-1 is present without checking the ObjectStore.
|
|
|
|
vector<string> attributes;
|
|
|
|
if (!entry_ || entry_->getFileType() != FileType::REGULAR_FILE) {
|
|
|
|
return attributes;
|
|
|
|
}
|
|
|
|
|
|
|
|
attributes.emplace_back(kXattrSha1);
|
|
|
|
return attributes;
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<string> TreeEntryFileInode::getxattr(StringPiece name) {
|
|
|
|
// Currently, we only support the xattr for the SHA-1 of a regular file.
|
|
|
|
if (!entry_ || name != kXattrSha1 ||
|
|
|
|
entry_->getFileType() != FileType::REGULAR_FILE) {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(mbolin): Make this more fault-tolerant. Currently, there is no logic
|
|
|
|
// to account for the case where we don't have the SHA-1 for the blob, the
|
|
|
|
// hash doesn't correspond to a blob, etc.
|
|
|
|
auto sha1 = parentInode_->getStore()->getSha1ForBlob(entry_->getHash());
|
|
|
|
return sha1->toString();
|
|
|
|
}
|
|
|
|
|
|
|
|
const TreeEntry* TreeEntryFileInode::getEntry() const {
|
|
|
|
return entry_;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|