From 67684b3a9a7205cef15f5978b5adc4df632f5af5 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 21 Jul 2019 13:54:41 +0100 Subject: Basically all the core functionality --- src/Jamfile.jam | 2 +- src/blob.cpp | 35 +++++++++++++++++++++++++++++--- src/blob.h | 7 ++++++- src/dir.cpp | 55 +++++++++++++++++++++++++++++++++++++++++++++----- src/dir.h | 9 +++++++-- src/git.cpp | 41 +++++++++++++++++++++++++++++++++++++ src/git.h | 9 +++++++++ src/repo.cpp | 61 +++++++++++++++++++++++++++++++++++++++++++------------- src/repo.h | 2 ++ src/repoList.cpp | 3 +-- 10 files changed, 196 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/Jamfile.jam b/src/Jamfile.jam index 4cf083d..d342134 100644 --- a/src/Jamfile.jam +++ b/src/Jamfile.jam @@ -1,7 +1,7 @@ # Testing path-constant gitdir : ../.git ; -lib gitfs : +lib gitfs++11 : [ glob *.cpp ] : ..//adhocutil diff --git a/src/blob.cpp b/src/blob.cpp index 8fb0509..4bd8b15 100644 --- a/src/blob.cpp +++ b/src/blob.cpp @@ -1,13 +1,39 @@ #include +#include #include "blob.h" +#include "repo.h" -GitFS::Blob::Blob(const GitFS::Git::RepositoryPtr & r, const GitFS::Git::TreeEntryPtr & te) : - blob(Git::BlobLookup(r, *git_tree_entry_id(te.get()))), +GitFS::Blob::Blob(const Repo * r, const std::string & path) : + repo(r), + entry(getTreeEntry(path)), + blob(getBlob()), blobSize(git_blob_rawsize(blob.get())), blobContent(static_cast(git_blob_rawcontent(blob.get()))) { } +GitFS::Git::TreeEntryPtr +GitFS::Blob::getTreeEntry(const std::string & path) const +{ + try { + return Git::TreeEntryByPath(repo->tree, path); + } + catch (const Git::Error & e) { + Git::ErrorToSystemError(e); + } +} + +GitFS::Git::BlobPtr +GitFS::Blob::getBlob() const +{ + const auto mode = git_tree_entry_filemode(entry.get()); + + if (S_ISDIR(mode)) throw NetFS::SystemError(EISDIR); + if (S_ISLNK(mode)) throw NetFS::SystemError(ELOOP); + + return Git::BlobLookup(repo->repo, *git_tree_entry_id(entry.get())); +} + void GitFS::Blob::close(const ::Ice::Current& current) { @@ -18,7 +44,10 @@ GitFS::Blob::close(const ::Ice::Current& current) NetFS::Attr GitFS::Blob::fgetattr(ReqEnv, const ::Ice::Current&) { - return {}; + NetFS::Attr a; + a << *blob << *entry << *repo->commit; + a.gid = a.uid = "root"; + return a; } diff --git a/src/blob.h b/src/blob.h index 0a2a77d..64f41ac 100644 --- a/src/blob.h +++ b/src/blob.h @@ -6,9 +6,10 @@ namespace GitFS { using namespace NetFS; + class Repo; class Blob : public File { public: - Blob(const GitFS::Git::RepositoryPtr & r, const Git::TreeEntryPtr &); + Blob(const Repo * r, const std::string &); void close(const ::Ice::Current& current) override; Attr fgetattr(ReqEnv env, const ::Ice::Current& current) override; @@ -17,6 +18,10 @@ namespace GitFS { void write(long long int offset, long long int size, Buffer data, const ::Ice::Current& current) override; private: + Git::TreeEntryPtr getTreeEntry(const std::string & path) const; + Git::BlobPtr getBlob() const; + const Repo * repo; + Git::TreeEntryPtr entry; Git::BlobPtr blob; const decltype(git_blob_rawsize({})) blobSize; const char * const blobContent; diff --git a/src/dir.cpp b/src/dir.cpp index 8a9fd86..cee26f0 100644 --- a/src/dir.cpp +++ b/src/dir.cpp @@ -1,10 +1,36 @@ #include +#include +#include "repo.h" #include "dir.h" -GitFS::Directory::Directory(const GitFS::Git::TreePtr & t, const std::string & p) : - tree(t), - path(p) +GitFS::Directory::Directory(const Repo * r, const std::string & p) : + repo(r), + path(p), + subTreeCacheRootId({}) { + getSubtree(); +} + +GitFS::Git::TreePtr +GitFS::Directory::getSubtree() const +{ + if (!git_oid_equal(&subTreeCacheRootId, git_tree_id(repo->tree.get()))) { + if (path == "/") { + subTreeCache = repo->tree; + } + else { + try { + auto e = Git::TreeEntryByPath(repo->tree, path); + if (!S_ISDIR(git_tree_entry_filemode(e.get()))) throw NetFS::SystemError(ENOTDIR); + subTreeCache = Git::TreeLookup(repo->repo, *git_tree_entry_id(e.get())); + } + catch (const Git::Error & e) { + Git::ErrorToSystemError(e); + } + } + subTreeCacheRootId = *git_tree_id(repo->tree.get()); + } + return subTreeCache; } void @@ -17,14 +43,33 @@ GitFS::Directory::close(const ::Ice::Current& current) NetFS::NameList GitFS::Directory::readdir(const ::Ice::Current&) { - return {}; + const auto subTree = getSubtree(); + NetFS::NameList list; + for (int idx = git_tree_entrycount(subTree.get()); idx--;) { + const auto entry = git_tree_entry_byindex(subTree.get(), idx); + list.push_back(git_tree_entry_name(entry)); + } + return list; } NetFS::DirectoryContents GitFS::Directory::listdir(const ::Ice::Current&) { - return {}; + const auto subTree = getSubtree(); + NetFS::DirectoryContents list; + for (int idx = git_tree_entrycount(subTree.get()); idx--;) { + const auto entry = git_tree_entry_byindex(subTree.get(), idx); + NetFS::Attr a {}; + a << *entry << *repo->commit; + if (S_ISREG(git_tree_entry_filemode(entry))) { + auto blob = Git::BlobLookup(repo->repo, *git_tree_entry_id(entry)); + a << *blob; + } + a.gid = a.uid = "root"; + list.emplace(git_tree_entry_name(entry), a); + } + return list; } diff --git a/src/dir.h b/src/dir.h index 74afde3..7174976 100644 --- a/src/dir.h +++ b/src/dir.h @@ -6,17 +6,22 @@ namespace GitFS { using namespace NetFS; + class Repo; class Directory : public DirectoryV2 { public: - Directory(const GitFS::Git::TreePtr & r, const std::string &); + Directory(const Repo * r, const std::string &); void close(const ::Ice::Current& current) override; NameList readdir(const ::Ice::Current& current) override; DirectoryContents listdir(const ::Ice::Current& current) override; private: - Git::TreePtr tree; + Git::TreePtr getSubtree() const; + const Repo * repo; const std::string path; + + mutable Git::TreePtr subTreeCache; + mutable git_oid subTreeCacheRootId; }; } diff --git a/src/git.cpp b/src/git.cpp index 084e6ca..850b8b3 100644 --- a/src/git.cpp +++ b/src/git.cpp @@ -1,6 +1,8 @@ #include "git.h" #include #include +#include +#include namespace GitFS { namespace Git { @@ -14,6 +16,45 @@ namespace GitFS { #endif throw Error { err, e->klass, e->message }; } + + [[noreturn]] void ErrorToSystemError(const Error & e) + { + if (e.err == GIT_ENOTFOUND) { + throw NetFS::SystemError(ENOENT); + } + throw NetFS::SystemError(EIO); + } + + } +} + +namespace NetFS { + Attr & operator<<(Attr & a, const git_tree_entry & e) + { + a.mode = git_tree_entry_filemode(&e); + if (S_ISDIR(a.mode)) { + a.mode |= S_IXUSR | S_IXGRP | S_IXOTH | S_IRUSR | S_IRGRP | S_IROTH; + } + else if (S_ISLNK(a.mode)) { + a.mode |= S_IRUSR | S_IRGRP | S_IROTH; + } + else { + a.mode ^= S_IWUSR; + } + return a; + } + + Attr & operator<<(Attr & a, const git_commit & c) + { + a.ctime = a.atime = a.mtime = git_commit_time(&c); + return a; + } + + Attr & operator<<(Attr & a, const git_blob & b) + { + a.blockSize = 1; + a.blocks = a.size = git_blob_rawsize(&b); + return a; } } diff --git a/src/git.h b/src/git.h index c0ae4e3..9107f8b 100644 --- a/src/git.h +++ b/src/git.h @@ -23,6 +23,8 @@ namespace GitFS { } } + [[noreturn]] void ErrorToSystemError(const Error & e); + template using TPtr = std::shared_ptr; @@ -83,6 +85,13 @@ namespace GitFS { } } +namespace NetFS { + struct Attr; + Attr & operator<<(Attr &, const git_tree_entry &); + Attr & operator<<(Attr &, const git_commit &); + Attr & operator<<(Attr &, const git_blob &); +} + namespace std { std::ostream & operator<<(std::ostream &, const git_oid &); } diff --git a/src/repo.cpp b/src/repo.cpp index 4c2a13f..0db5b23 100644 --- a/src/repo.cpp +++ b/src/repo.cpp @@ -9,7 +9,7 @@ GitFS::Repo::Repo() : repo(Git::RepositoryOpenBare(rootDir)), - commit(Git::CommitLookup(repo, Git::OidParse("9197cb3c6e58e6f24deb0af326f695aac87bc36d"))), + commit(Git::CommitLookup(repo, Git::OidParse("7a0ccb40084c3ab31d9856e7f689c0514c28c930"))), tree(Git::TreeLookup(repo, *git_commit_tree_id(commit.get()))) { } @@ -24,14 +24,18 @@ GitFS::Repo::disconnect(const ::Ice::Current& current) 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(tree, path))); + std::make_shared(this, path))); } NetFS::VFS -GitFS::Repo::statfs(ReqEnv, ::std::string, const ::Ice::Current&) +GitFS::Repo::statfs(ReqEnv, ::std::string path, const ::Ice::Current&) { + if (path.empty()) throw NetFS::SystemError(EINVAL); + return {}; } @@ -48,6 +52,7 @@ GitFS::Repo::access(ReqEnv, ::std::string path, int mode, const ::Ice::Current&) const auto emode = git_tree_entry_filemode(e.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; @@ -57,7 +62,7 @@ GitFS::Repo::access(ReqEnv, ::std::string path, int mode, const ::Ice::Current&) if (e.err == GIT_ENOTFOUND) { return ENOENT; } - throw NetFS::SystemError(EIO); + Git::ErrorToSystemError(e); } } @@ -65,29 +70,57 @@ GitFS::Repo::access(ReqEnv, ::std::string path, int mode, const ::Ice::Current&) NetFS::Attr GitFS::Repo::getattr(ReqEnv, ::std::string path, const ::Ice::Current&) { - NetFS::Attr a {}; - (void)path; - a.ctime = a.atime = a.mtime = git_commit_time(commit.get()); - return a; + if (path.empty()) throw NetFS::SystemError(EINVAL); + + try { + NetFS::Attr a {}; + if (path == "/") { + a.mode = S_IFDIR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; + } + else { + auto entry = Git::TreeEntryByPath(tree, path); + a << *entry; + if (S_ISREG(git_tree_entry_filemode(entry.get()))) { + auto blob = Git::BlobLookup(repo, *git_tree_entry_id(entry.get())); + a << *blob; + } + } + a << *commit; + a.gid = a.uid = "root"; + return a; + } + catch (const Git::Error & e) { + Git::ErrorToSystemError(e); + } } ::std::string GitFS::Repo::readlink(ReqEnv, ::std::string path, const ::Ice::Current&) { - auto e = Git::TreeEntryByPath(tree, path); - if (!e) throw NetFS::SystemError(ENOENT); - const auto emode = git_tree_entry_filemode(e.get()); - if (!S_ISLNK(emode)) throw NetFS::SystemError(EINVAL); - return {}; + if (path.empty() || path == "/") throw NetFS::SystemError(EINVAL); + + try { + auto e = Git::TreeEntryByPath(tree, path); + if (!S_ISLNK(git_tree_entry_filemode(e.get()))) throw NetFS::SystemError(EINVAL); + auto blob = Git::BlobLookup(repo, *git_tree_entry_id(e.get())); + auto n = static_cast(git_blob_rawcontent(blob.get())); + return { n, n + git_blob_rawsize(blob.get()) }; + } + catch (const Git::Error & e) { + Git::ErrorToSystemError(e); + } } 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); + return Ice::uncheckedCast(ice.adapter->addWithUUID( - std::make_shared(repo, Git::TreeEntryByPath(tree, path)))); + std::make_shared(this, path))); } diff --git a/src/repo.h b/src/repo.h index e6f7d94..0b8cc56 100644 --- a/src/repo.h +++ b/src/repo.h @@ -31,6 +31,8 @@ namespace GitFS { void utimens(ReqEnv env, ::std::string path, long long int atime, long long int atimens, long long int mtime, long long int mtimens, const ::Ice::Current& current) override; private: + friend class Directory; + friend class Blob; Git::RepositoryPtr repo; Git::CommitPtr commit; Git::TreePtr tree; diff --git a/src/repoList.cpp b/src/repoList.cpp index 0ee92c5..51eb6b2 100644 --- a/src/repoList.cpp +++ b/src/repoList.cpp @@ -4,10 +4,9 @@ GitFS::RepoList::RepoList(const Ice::PropertiesPtr &) { - } -NetFS::VolumePrxPtr +NetFS::VolumePrxPtr GitFS::RepoList::connect(const ::std::string, const ::std::string, const ::Ice::Current & ice) { -- cgit v1.2.3