summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2019-07-21 13:54:41 +0100
committerDan Goodliffe <dan@randomdan.homeip.net>2019-07-21 13:54:41 +0100
commit67684b3a9a7205cef15f5978b5adc4df632f5af5 (patch)
tree630a28d313047bf6440b0c349047c6c8de0cb298 /src
parentAdd a test symlink (diff)
downloadnetfs-gitfs-67684b3a9a7205cef15f5978b5adc4df632f5af5.tar.bz2
netfs-gitfs-67684b3a9a7205cef15f5978b5adc4df632f5af5.tar.xz
netfs-gitfs-67684b3a9a7205cef15f5978b5adc4df632f5af5.zip
Basically all the core functionality
Diffstat (limited to 'src')
-rw-r--r--src/Jamfile.jam2
-rw-r--r--src/blob.cpp35
-rw-r--r--src/blob.h7
-rw-r--r--src/dir.cpp55
-rw-r--r--src/dir.h9
-rw-r--r--src/git.cpp41
-rw-r--r--src/git.h9
-rw-r--r--src/repo.cpp61
-rw-r--r--src/repo.h2
-rw-r--r--src/repoList.cpp3
10 files changed, 196 insertions, 28 deletions
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 ]
:
<library>..//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 <Ice/ObjectAdapter.h>
+#include <sys/stat.h>
#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<const char *>(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 <Ice/ObjectAdapter.h>
+#include <sys/stat.h>
+#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 <execinfo.h>
#include <exceptions.h>
+#include <types.h>
+#include <sys/stat.h>
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<typename T>
using TPtr = std::shared_ptr<T>;
@@ -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<NetFS::DirectoryV2Prx>(ice.adapter->addWithUUID(
- std::make_shared<Directory>(tree, path)));
+ std::make_shared<Directory>(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<const ::std::string::value_type *>(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<NetFS::FilePrx>(ice.adapter->addWithUUID(
- std::make_shared<Blob>(repo, Git::TreeEntryByPath(tree, path))));
+ std::make_shared<Blob>(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)
{