#include "repo.h" #include "blob.h" #include "dir.h" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { std::string operator/(const std::string & value, const std::string & fallback) { return value.empty() ? fallback : value; } } GitFS::Repo::Repo(const PropertyReader & properties) : repo(Git::repositoryOpenBare(properties("gitdir"))), commitish(properties("commitish") / "main"), isBranch(false), resolvedAt(0), gid(properties("gid") / "root"), uid(properties("uid") / "root") { if (commitish.length() == GIT_OID_HEXSZ) { commit = Git::commitLookup(repo, Git::oidParse(commitish)); } else { ref = Git::commitish(repo, commitish); isBranch = git_reference_is_branch(ref.get()); } update(); } void GitFS::Repo::update() { constexpr time_t MIN_CHECK_TIME = 30; if (!commit || (isBranch && ref && resolvedAt < std::time(nullptr) - MIN_CHECK_TIME)) { commit = Git::commitLookup(repo, *git_reference_target(Git::resolve(ref).get())); resolvedAt = std::time(nullptr); } tree = Git::treeLookup(repo, *git_commit_tree_id(commit.get())); } void GitFS::Repo::disconnect(const ::Ice::Current & ice) { ice.adapter->remove(ice.id); } NetFS::DirectoryPrxPtr GitFS::Repo::opendir(ReqEnv, ::std::string path, const ::Ice::Current & ice) { if (path.empty()) { throw NetFS::SystemError(EINVAL); } return Ice::uncheckedCast( ice.adapter->addWithUUID(std::make_shared(this, std::move(path)))); } NetFS::VFS GitFS::Repo::statfs(ReqEnv, ::std::string path, const ::Ice::Current &) { if (path.empty()) { throw NetFS::SystemError(EINVAL); } return {}; } int GitFS::Repo::access(ReqEnv, const ::std::string path, const int mode, const ::Ice::Current &) { if (mode & W_OK) { return EACCES; } if (path.empty()) { return EINVAL; } if (path == "/") { return 0; } try { update(); auto entry = Git::treeEntryByPath(tree, path); const auto emode = git_tree_entry_filemode(entry.get()); if (S_ISDIR(emode)) { return 0; } if (S_ISLNK(emode)) { return 0; } if (mode & R_OK && !(S_IRUSR & emode)) { return EACCES; } if (mode & X_OK && !(S_IXUSR & emode)) { return EACCES; } return 0; } catch (const NetFS::SystemError & e) { return e.syserrno; } } NetFS::Attr GitFS::Repo::getattr(ReqEnv, const ::std::string path, const ::Ice::Current &) { if (path.empty()) { throw NetFS::SystemError(EINVAL); } NetFS::Attr attr {}; if (path == "/") { attr.mode = S_IFDIR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; } else { update(); auto entry = Git::treeEntryByPath(tree, path); attr << *entry; if (S_ISREG(git_tree_entry_filemode(entry.get()))) { auto blob = Git::blobLookup(repo, *git_tree_entry_id(entry.get())); attr << *blob; } } attr << *commit; attr.gid = gid; attr.uid = uid; return attr; } ::std::string GitFS::Repo::readlink(ReqEnv, const ::std::string path, const ::Ice::Current &) { if (path.empty() || path == "/") { throw NetFS::SystemError(EINVAL); } update(); auto entry = Git::treeEntryByPath(tree, path); if (!S_ISLNK(git_tree_entry_filemode(entry.get()))) { throw NetFS::SystemError(EINVAL); } auto blob = Git::blobLookup(repo, *git_tree_entry_id(entry.get())); auto content = static_cast(git_blob_rawcontent(blob.get())); return {content, git_blob_rawsize(blob.get())}; } NetFS::FilePrxPtr GitFS::Repo::open(ReqEnv, ::std::string path, int, const ::Ice::Current & ice) { if (path.empty()) { throw NetFS::SystemError(EINVAL); } if (path == "/") { throw NetFS::SystemError(EISDIR); } update(); return Ice::uncheckedCast(ice.adapter->addWithUUID(std::make_shared(this, std::move(path)))); } NetFS::FilePrxPtr GitFS::Repo::create(ReqEnv, ::std::string, int, int, const ::Ice::Current &) { throw NetFS::SystemError(EROFS); } void GitFS::Repo::truncate(ReqEnv, ::std::string, long long int, const ::Ice::Current &) { throw NetFS::SystemError(EROFS); } void GitFS::Repo::unlink(ReqEnv, ::std::string, const ::Ice::Current &) { throw NetFS::SystemError(EROFS); } void GitFS::Repo::mkdir(ReqEnv, ::std::string, int, const ::Ice::Current &) { throw NetFS::SystemError(EROFS); } void GitFS::Repo::rmdir(ReqEnv, ::std::string, const ::Ice::Current &) { throw NetFS::SystemError(EROFS); } void GitFS::Repo::mknod(ReqEnv, ::std::string, int, int, const ::Ice::Current &) { throw NetFS::SystemError(EROFS); } void GitFS::Repo::symlink(ReqEnv, ::std::string, ::std::string, const ::Ice::Current &) { throw NetFS::SystemError(EROFS); } void GitFS::Repo::link(ReqEnv, ::std::string, ::std::string, const ::Ice::Current &) { throw NetFS::SystemError(EROFS); } void GitFS::Repo::rename(ReqEnv, ::std::string, ::std::string, const Ice::optional, const ::Ice::Current &) { throw NetFS::SystemError(EROFS); } void GitFS::Repo::chmod(ReqEnv, ::std::string, int, const ::Ice::Current &) { throw NetFS::SystemError(EROFS); } void GitFS::Repo::chown(ReqEnv, ::std::string, int, int, const ::Ice::Current &) { throw NetFS::SystemError(EROFS); } void GitFS::Repo::utimens( ReqEnv, ::std::string, long long int, long long int, long long int, long long int, const ::Ice::Current &) { throw NetFS::SystemError(EROFS); }