diff options
author | randomdan <randomdan@localhost> | 2009-10-17 17:26:04 +0000 |
---|---|---|
committer | randomdan <randomdan@localhost> | 2009-10-17 17:26:04 +0000 |
commit | 90a05228972cd8d180c2723f71ba94e94d1133b3 (patch) | |
tree | 27ab7a2609bf5e6bb1ff4206348a648f3f1b3efc | |
parent | Imported sources (diff) | |
download | netfs-90a05228972cd8d180c2723f71ba94e94d1133b3.tar.bz2 netfs-90a05228972cd8d180c2723f71ba94e94d1133b3.tar.xz netfs-90a05228972cd8d180c2723f71ba94e94d1133b3.zip |
*** empty log message ***
-rw-r--r-- | netfs/comms.cpp | 90 | ||||
-rw-r--r-- | netfs/comms.h | 60 | ||||
-rwxr-xr-x | netfs/configure | 1 | ||||
-rw-r--r-- | netfs/daemon.cpp | 223 | ||||
-rw-r--r-- | netfs/daemon.xml | 10 | ||||
-rw-r--r-- | netfs/daemonConfig.cpp | 27 | ||||
-rw-r--r-- | netfs/daemonConfig.h | 31 | ||||
-rw-r--r-- | netfs/fuse.cpp | 283 | ||||
-rw-r--r-- | netfs/fuseapp.cpp | 154 | ||||
-rw-r--r-- | netfs/fuseapp.h | 50 | ||||
-rw-r--r-- | netfs/fusecallers.h | 4 | ||||
-rw-r--r-- | netfs/makefile.in | 63 | ||||
-rw-r--r-- | netfs/msgtypes.cpp | 152 | ||||
-rw-r--r-- | netfs/msgtypes.h | 212 | ||||
-rw-r--r-- | netfs/xfers.h | 53 |
15 files changed, 1413 insertions, 0 deletions
diff --git a/netfs/comms.cpp b/netfs/comms.cpp new file mode 100644 index 0000000..86a7313 --- /dev/null +++ b/netfs/comms.cpp @@ -0,0 +1,90 @@ +#include <queue> +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <sys/types.h> +#include <sys/socket.h> +#include "threads.h" +#include "comms.h" +#include "msgtypes.h" + +Semaphore outQueueSl(0); +Semaphore outQueueSu(30); +Semaphore inQueueS(0); +Mutex outQueueM; +Mutex inQueueM; +std::queue<PacketPtr> outQueue; +std::queue<PacketPtr> inQueue; + +Packet::Packet(uint8_t i, DataPayloadPtr p) : + index(i), + data(p) +{ +} +void +sendPacket(PacketPtr p) +{ + outQueueSu.wait(); + outQueueSl.post(); + AutoMutex am(outQueueM); + outQueue.push(p); +} + +void +packetSender(FILE * host) +{ + while (1) { + outQueueSl.wait(); + AutoMutex am(outQueueM); + // We can indicate an exit request by posting the semaphore without putting + // anything in the queue + if (outQueue.size() == 0) { + break; + } + outQueue.front()->write(host); + outQueueSu.post(); + } +} + +Packet::Packet(FILE * host) +{ + if (fread(&index, sizeof(index), 1, host) != 1) { + // error + } + DataPayload::TypeID t = 0; + if (fread(&t, sizeof(t), 1, host) != 1) { + // error + } + data = MsgFacs()[t](); + data->Read(host); +} +void +Packet::write(FILE * host) const +{ + if (fwrite(&index, sizeof(index), 1, host) != 1) { + // error + } + DataPayload::TypeID t = data->dataTypeID(); + if (fwrite(&t, sizeof(t), 1, host) != 1) { + // error + } + data->Send(host); + if (fflush(host) != 0) { + // + } +} + +PacketPtr +recvPacket() +{ + inQueueS.wait(); + AutoMutex am(inQueueM); + PacketPtr rtn = inQueue.front(); + inQueue.pop(); + return rtn; +} + +ContentBase::~ContentBase() +{ +} + diff --git a/netfs/comms.h b/netfs/comms.h new file mode 100644 index 0000000..54681b5 --- /dev/null +++ b/netfs/comms.h @@ -0,0 +1,60 @@ +#ifndef COMMS_H +#define COMMS_H + +#include <stdio.h> +#include <stdint.h> +#include <fuse/fuse.h> +#include "smartpointer.h" + +class DataPayload : public IsRefCounted { + public: + typedef uint16_t TypeID; + + virtual TypeID dataTypeID() const = 0; + virtual void Send(FILE *) const = 0; + virtual void Read(FILE *) = 0; +}; +class NetFS; +template <class Type> +class TypedPayload : public DataPayload { + public: + typedef SmartPointer<TypedPayload<Type> > Ptr; + Type data; + TypeID dataTypeID() const { return Type::TypeID; } + void Send(FILE * h) const { data.Send(h); } + void Read(FILE * h) { data.Read(h); } +}; +template <class Type> +class TypedPayloadReq : public TypedPayload<Type> { + public: + typedef typename Type::Reply Reply; + typedef SmartPointer<TypedPayloadReq<Type> > Ptr; + typedef SmartPointer<TypedPayload<Reply> > ReplyPtr; + TypedPayloadReq(fuse_context * fc) + { + TypedPayload<Type>::data.uid = fc->uid; + TypedPayload<Type>::data.gid = fc->gid; + } + ReplyPtr exchange(NetFS *); +}; + +typedef SmartPointer<DataPayload> DataPayloadPtr; +typedef SmartPointer<const DataPayload> DataPayloadCPtr; + +class Packet : public IsRefCounted { + public: + Packet(FILE *); + Packet(uint8_t i, DataPayloadPtr p); + + void write(FILE *) const; + + uint8_t index; + DataPayloadPtr data; +}; +typedef SmartPointer<Packet> PacketPtr; + +void +sendPacket(PacketPtr p); + +#endif + diff --git a/netfs/configure b/netfs/configure new file mode 100755 index 0000000..4d06840 --- /dev/null +++ b/netfs/configure @@ -0,0 +1 @@ +cp makefile.in makefile diff --git a/netfs/daemon.cpp b/netfs/daemon.cpp new file mode 100644 index 0000000..1cbb5bc --- /dev/null +++ b/netfs/daemon.cpp @@ -0,0 +1,223 @@ +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> +#include <dirent.h> +#include <errno.h> +#include <string.h> +#include <set> +#include "daemonConfig.h" +#include "comms.h" +#include "msgtypes.h" +#include "misc.h" + +class DaemonGlobalState : public IsRefCounted { +}; +typedef SmartPointer<DaemonGlobalState> DaemonGlobalStatePtr; +class Sender { + public: + Sender(int i, FILE * f) + { + idx = i; + host = f; + } + void Send(DataPayloadPtr p) + { + PacketPtr r = new Packet(idx, p); + r->write(host); + } + private: + int idx; + FILE * host; +}; +#define handler(type) void handle(SmartPointer<TypedPayload<type> > req, Sender & s) +handler(AccessRequest) +{ + TypedPayload<AccessRequest::Reply> * r = new TypedPayload<AccessRequest::Reply>(); + r->data.value = access(req->data.path.c_str(), req->data.access); + s.Send(r); +} +handler(GetAttrRequest) +{ + TypedPayload<GetAttrRequest::Reply> * r = new TypedPayload<GetAttrRequest::Reply>(); + r->data.res = stat(req->data.path.c_str(), &r->data.val); + s.Send(r); +} +int dirNo = 0; +std::map<int, DIR*> dirs; +handler(OpenDirRequest) +{ + TypedPayload<OpenDirRequest::Reply> * r = new TypedPayload<OpenDirRequest::Reply>(); + errno = 0; + DIR * od = opendir(req->data.path.c_str()); + if (od) { + dirs[++dirNo] = od; + r->data.handle = dirNo; + } + r->data.error = errno; + s.Send(r); +} +handler(CloseDirRequest) +{ + TypedPayload<CloseDirRequest::Reply> * r = new TypedPayload<CloseDirRequest::Reply>(); + if (dirs.find(req->data.handle) != dirs.end()) { + errno = 0; + if (closedir(dirs[req->data.handle]) != 0) { + r->data.error = errno; + } + else { + dirs.erase(req->data.handle); + } + } + else { + r->data.error = EBADF; + } + s.Send(r); +} +typedef TypedPayload<ReadDirContent>::Ptr DirContPLPtr; +typedef TypedPayload<ReadDirContent> DirContPL; +typedef std::set<DirContPLPtr> DirContPLs; +handler(ReadDirRequest) +{ + TypedPayload<ReadDirRequest::Reply> * r = new TypedPayload<ReadDirRequest::Reply>(); + if (dirs.find(req->data.handle) != dirs.end()) { + errno = 0; + dirent * d; + DirContPLs ds; + while ((d = readdir(dirs[req->data.handle])) && errno == 0) { + DirContPLPtr dc = new DirContPL(); + dc->data.path = d->d_name; + ds.insert(dc); + } + r->data.error = errno; + r->data.count = ds.size(); + s.Send(r); + foreach(DirContPLs::const_iterator, ds, dir) { + s.Send(*dir); + } + } + else { + r->data.error = EBADF; + s.Send(r); + } +} +int fileNo = 0; +std::map<int, int> files; +handler(OpenRequest) +{ + TypedPayload<OpenRequest::Reply> * r = new TypedPayload<OpenRequest::Reply>(); + errno = 0; + int fd = open(req->data.path.c_str(), 0); + if (fd != -1) { + files[++fileNo] = fd; + r->data.handle = fileNo; + } + r->data.error = errno; + s.Send(r); +} +handler(CloseRequest) +{ + TypedPayload<CloseRequest::Reply> * r = new TypedPayload<CloseRequest::Reply>(); + if (files.find(req->data.handle) != files.end()) { + errno = 0; + if (close(files[req->data.handle]) != 0) { + r->data.error = errno; + } + else { + files.erase(req->data.handle); + } + } + else { + r->data.error = EBADF; + } + s.Send(r); +} +handler(ReadRequest) +{ + TypedPayload<ReadRequest::Reply> * r = new TypedPayload<ReadRequest::Reply>(); + if (files.find(req->data.handle) != files.end()) { + char * tmpdata = new char[req->data.size](); + errno = 0; + if (pread(files[req->data.handle], tmpdata, req->data.size, req->data.offset) != -1) { + r->data.data = tmpdata; + r->data.size = req->data.size; + } + else { + r->data.size = 0; + r->data.data = NULL; + } + r->data.error = errno; + } + else { + r->data.error = EBADF; + } + s.Send(r); +} +handler(WriteRequest) +{ + TypedPayload<WriteRequest::Reply> * r = new TypedPayload<WriteRequest::Reply>(); + if (files.find(req->data.handle) != files.end()) { + errno = 0; + if (pwrite(files[req->data.handle], req->data.data, req->data.size, req->data.offset) != -1) { + } + r->data.error = errno; + } + else { + r->data.error = EBADF; + } + s.Send(r); +} +#define TRYCLASS(cls) \ + if (type == cls::TypeID) { handle(p->data.as<TypedPayload<cls> >(), s); } + +void +runDaemonOn(FILE * f, DaemonConfigPtr, DaemonGlobalStatePtr) +{ + while (true) { + PacketPtr p = new Packet(f); + Sender s(p->index, f); + uint16_t type (p->data->dataTypeID()); + TRYCLASS(AccessRequest); + TRYCLASS(GetAttrRequest); + TRYCLASS(OpenDirRequest); + TRYCLASS(CloseDirRequest); + TRYCLASS(ReadDirRequest); + TRYCLASS(OpenRequest); + TRYCLASS(CloseRequest); + TRYCLASS(ReadRequest); + TRYCLASS(WriteRequest); + } + fclose(f); +} + +int main(int, char* []) +{ + DaemonConfigPtr dc = DaemonConfig::Load("daemon.xml"); + struct addrinfo hints; + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + struct addrinfo *result, *rp; + int s = getaddrinfo(NULL, dc->tcpPort.c_str(), &hints, &result); + if (s) { + // Error + } + for (rp = result; rp != NULL; rp = rp->ai_next) { + int sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (sfd == -1) + continue; + if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0) { + if (listen(sfd, 5)) { + // Error + } + DaemonGlobalStatePtr dgs = new DaemonGlobalState(); + for (int newfd; (newfd = accept(sfd, NULL, NULL)) > 0; ) { + runDaemonOn(fdopen(newfd, "a+"), dc, dgs); + } + break; + } + close(sfd); + } + return 0; +} + diff --git a/netfs/daemon.xml b/netfs/daemon.xml new file mode 100644 index 0000000..2454ff6 --- /dev/null +++ b/netfs/daemon.xml @@ -0,0 +1,10 @@ +<config> + <tcpPort>4000</tcpPort> + <exports> + <export> + <name>tmp</name> + <root>/tmp</root> + </export> + </exports> +</config> + diff --git a/netfs/daemonConfig.cpp b/netfs/daemonConfig.cpp new file mode 100644 index 0000000..520cec1 --- /dev/null +++ b/netfs/daemonConfig.cpp @@ -0,0 +1,27 @@ +#include "daemonConfig.h" +#include <string.h> + +DaemonConfigPtr +DaemonConfig::Load(const char * path) +{ + xmlDoc * doc = xmlReadFile(path, NULL, 0); + DaemonConfigPtr dc = new DaemonConfig(doc->children); + xmlFreeDoc(doc); + return dc; +} + +DaemonConfig::DaemonConfig(xmlNodePtr conf) : + tcpPort(xmlGetNodeValue(conf, "tcpPort")) +{ + foreachxml(exp, xmlGetNode(conf, "exports"), "export") { + ExportPtr e = new Export(exp); + exports[e->name] = e; + } +} + +DaemonConfig::Export::Export(xmlNodePtr exp) : + root(xmlGetNodeValue(exp, "root")), + name(xmlGetNodeValue(exp, "name")) +{ +} + diff --git a/netfs/daemonConfig.h b/netfs/daemonConfig.h new file mode 100644 index 0000000..d15fade --- /dev/null +++ b/netfs/daemonConfig.h @@ -0,0 +1,31 @@ +#ifndef DAEMONCONFIG_H +#define DAEMONCONFIG_H + +#include <string> +#include <map> +#include "smartpointer.h" +#include "xml.h" + +class DaemonConfig : public virtual IsRefCounted { + public: + class Export : public virtual IsRefCounted { + public: + Export(xmlNodePtr); + + std::string root; + std::string name; + }; + typedef SmartPointer<Export> ExportPtr; + typedef std::map<std::string, ExportPtr> ExportMap; + + DaemonConfig(xmlNodePtr); + static SmartPointer<DaemonConfig> Load(const char * path); + + + std::string tcpPort; + ExportMap exports; +}; +typedef SmartPointer<DaemonConfig> DaemonConfigPtr; + +#endif + diff --git a/netfs/fuse.cpp b/netfs/fuse.cpp new file mode 100644 index 0000000..610605d --- /dev/null +++ b/netfs/fuse.cpp @@ -0,0 +1,283 @@ +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> +#include "fuseapp.h" +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include "comms.h" +#include "msgtypes.h" + +static FuseAppBase * fuseApp; + +template <class A, int (FuseAppBase::*f)(A)> +static int fuseCall(A a) +{ + try { + return (fuseApp->*f)(a); + } + catch (...) { + return -ENOSYS; + } +} +template <class A, class B, int (FuseAppBase::*f)(A, B)> +static int fuseCall(A a, B b) +{ + try { + return (fuseApp->*f)(a, b); + } + catch (...) { + return -ENOSYS; + } +} +template <class A, class B, class C, int (FuseAppBase::*f)(A, B, C)> +static int fuseCall(A a, B b, C c) +{ + try { + return (fuseApp->*f)(a, b, c); + } + catch (...) { + return -ENOSYS; + } +} +template <class A, class B, class C, class D, int (FuseAppBase::*f)(A, B, C, D)> +static int fuseCall(A a, B b, C c, D d) +{ + try { + return (fuseApp->*f)(a, b, c, d); + } + catch (...) { + return -ENOSYS; + } +} +template <class A, class B, class C, class D, class E, int (FuseAppBase::*f)(A, B, C, D, E)> +static int fuseCall(A a, B b, C c, D d, E e) +{ + try { + return (fuseApp->*f)(a, b, c, d, e); + } + catch (...) { + return -ENOSYS; + } +} +static void * fuseInit (struct fuse_conn_info *conn) +{ + return fuseApp->init(conn); +} +template <class App> +static void fuseDestroy(void * x) +{ + delete (App*)x; +} + +class NetFS : public FuseAppBase +{ + int access(const char * p, int a) + { + TypedPayloadReq<AccessRequest>::Ptr msg = new TypedPayloadReq<AccessRequest>(fuse_get_context()); + msg->data.access = a; + msg->data.path = p; + return -msg->exchange(this)->data.value; + } + int getattr(const char * p, struct stat * s) + { + TypedPayloadReq<GetAttrRequest>::Ptr msg = new TypedPayloadReq<GetAttrRequest>(fuse_get_context()); + msg->data.path = p; + TypedPayload<GetAttrReply>::Ptr rep = msg->exchange(this); + *s = rep->data.val; + return -rep->data.res; + } + int opendir(const char * p, struct fuse_file_info * fi) + { + TypedPayloadReq<OpenDirRequest>::Ptr msg = new TypedPayloadReq<OpenDirRequest>(fuse_get_context()); + msg->data.path = p; + TypedPayload<OpenDirReply>::Ptr rep = msg->exchange(this); + fi->fh = rep->data.handle; + return -rep->data.error; + } + int releasedir(const char *, struct fuse_file_info * fi) + { + TypedPayloadReq<CloseDirRequest>::Ptr msg = new TypedPayloadReq<CloseDirRequest>(fuse_get_context()); + msg->data.handle = fi->fh; + TypedPayload<CloseDirReply>::Ptr rep = msg->exchange(this); + return -rep->data.error; + } + int readdir(const char *, void * buf, fuse_fill_dir_t filler, off_t, struct fuse_file_info * fi) + { + TypedPayloadReq<ReadDirRequest>::Ptr msg = new TypedPayloadReq<ReadDirRequest>(fuse_get_context()); + msg->data.handle = fi->fh; + TypedPayload<ReadDirReply>::Ptr rep = msg->exchange(this); + size_t cnt = rep->data.count; + while (cnt--) { + TypedPayload<ReadDirContent>::Ptr dir = recvType<ReadDirContent>(); + filler(buf, dir->data.path.c_str(), &dir->data.val, 0); + } + return -rep->data.error; + } + int open(const char * p, struct fuse_file_info * fi) + { + TypedPayloadReq<OpenRequest>::Ptr msg = new TypedPayloadReq<OpenRequest>(fuse_get_context()); + msg->data.path = p; + TypedPayload<OpenReply>::Ptr rep = msg->exchange(this); + fi->fh = rep->data.handle; + return -rep->data.error; + } + int release(const char *, struct fuse_file_info * fi) + { + TypedPayloadReq<CloseRequest>::Ptr msg = new TypedPayloadReq<CloseRequest>(fuse_get_context()); + msg->data.handle = fi->fh; + TypedPayload<CloseReply>::Ptr rep = msg->exchange(this); + return -rep->data.error; + } + int read(const char *, char * buf, size_t s, off_t o, struct fuse_file_info * fi) + { + TypedPayloadReq<ReadRequest>::Ptr msg = new TypedPayloadReq<ReadRequest>(fuse_get_context()); + msg->data.handle = fi->fh; + msg->data.offset = o; + msg->data.size = s; + TypedPayload<ReadReply>::Ptr rep = msg->exchange(this); + if (rep->data.size) { + memcpy(buf, rep->data.data, std::min(s, rep->data.size)); + return rep->data.size; + } + else { + return -rep->data.error; + } + } + int write(const char *, const char * buf, size_t s, off_t o, struct fuse_file_info * fi) + { + TypedPayloadReq<WriteRequest>::Ptr msg = new TypedPayloadReq<WriteRequest>(fuse_get_context()); + msg->data.handle = fi->fh; + msg->data.offset = o; + msg->data.size = s; + msg->data.data = new char[s](); + memcpy(msg->data.data, buf, s); + TypedPayload<WriteReply>::Ptr rep = msg->exchange(this); + return -rep->data.error; + } + public: + NetFS() : + f(NULL) + { + struct addrinfo hints; + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + struct addrinfo *result, *rp; + int s = getaddrinfo("localhost", "4000", &hints, &result); + if (s) { + // Error + } + for (rp = result; rp != NULL; rp = rp->ai_next) { + int sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (sfd == -1) + // Error + continue; + if (connect(sfd, rp->ai_addr, rp->ai_addrlen)) { + // Error + continue; + } + f = fdopen(sfd, "a+"); + break; + } + } + ~NetFS() + { + if (f) { + fclose(f); + } + } + DataPayloadPtr exchange(DataPayloadPtr dp) + { + send(dp); + return recv(); + } + void send(DataPayloadPtr dp) + { + PacketPtr sendme = new Packet(0, dp); + sendme->write(f); + } + DataPayloadPtr recv() + { + PacketPtr recvd = new Packet(f); + return recvd->data; + } + template <typename Type> + SmartPointer<TypedPayload<Type> > recvType() + { + DataPayloadPtr p = this->recv(); + return p.as<TypedPayload<Type> >(); + } + private: + FILE * f; +}; +template <typename Type> +SmartPointer<TypedPayload<typename Type::Reply> > TypedPayloadReq<Type>::exchange(NetFS * net) +{ + DataPayloadPtr p = net->exchange(this); + return p.as<TypedPayload<typename Type::Reply> >(); +} + +template <class FuseApp> +int runFuseApp(int argc, char* argv[]) +{ + struct fuse_opt fuse_opts[] = { + { NULL, 0, 0 } + }; + + fuseApp = new FuseApp(); + struct fuse_operations operations = { + fuseCall<const char *, struct stat *, &FuseAppBase::getattr>, + fuseCall<const char *, char *, size_t, &FuseAppBase::readlink>, + NULL, // getdir deprecated + fuseCall<const char *, mode_t, dev_t, &FuseAppBase::mknod>, + fuseCall<const char *, mode_t, &FuseAppBase::mkdir>, + fuseCall<const char *, &FuseAppBase::unlink>, + fuseCall<const char *, &FuseAppBase::rmdir>, + fuseCall<const char *, const char *, &FuseAppBase::symlink>, + fuseCall<const char *, const char *, &FuseAppBase::rename>, + fuseCall<const char *, const char *, &FuseAppBase::link>, + fuseCall<const char *, mode_t, &FuseAppBase::chmod>, + fuseCall<const char *, uid_t, gid_t, &FuseAppBase::chown>, + fuseCall<const char *, off_t, &FuseAppBase::truncate>, + NULL, // utime deprecated + fuseCall<const char *, struct fuse_file_info *, &FuseAppBase::open>, + fuseCall<const char *, char *, size_t, off_t, struct fuse_file_info *, &FuseAppBase::read>, + fuseCall<const char *, const char *, size_t, off_t, struct fuse_file_info *, &FuseAppBase::write>, + fuseCall<const char *, struct statvfs *, &FuseAppBase::statfs>, + fuseCall<const char *, struct fuse_file_info *, &FuseAppBase::flush>, + fuseCall<const char *, struct fuse_file_info *, &FuseAppBase::release>, + fuseCall<const char *, int, struct fuse_file_info *, &FuseAppBase::fsync>, + fuseCall<const char *, const char *, const char *, size_t, int, &FuseAppBase::setxattr>, + fuseCall<const char *, const char *, char *, size_t, &FuseAppBase::getxattr>, + fuseCall<const char *, char *, size_t, &FuseAppBase::listxattr>, + fuseCall<const char *, const char *, &FuseAppBase::removexattr>, + fuseCall<const char *, struct fuse_file_info *, &FuseAppBase::opendir>, + fuseCall<const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *, &FuseAppBase::readdir>, + fuseCall<const char *, struct fuse_file_info *, &FuseAppBase::releasedir>, + fuseCall<const char *, int, struct fuse_file_info *, &FuseAppBase::fsyncdir>, + fuseInit, + fuseDestroy<FuseApp>, + fuseCall<const char *, int, &FuseAppBase::access>, + fuseCall<const char *, mode_t, struct fuse_file_info *, &FuseAppBase::create>, + fuseCall<const char *, off_t, struct fuse_file_info *, &FuseAppBase::ftruncate>, + fuseCall<const char *, struct stat *, struct fuse_file_info *, &FuseAppBase::fgetattr>, + fuseCall<const char *, struct fuse_file_info *, int, struct flock *, &FuseAppBase::lock>, + fuseCall<const char *, const struct timespec [2], &FuseAppBase::utimens>, + fuseCall<const char *, size_t, uint64_t *, &FuseAppBase::bmap> + }; + struct fuse_args args = FUSE_ARGS_INIT(argc, argv); + if (fuse_opt_parse(&args, fuseApp, fuse_opts, + fuseCall<void *, const char *, int, struct fuse_args *, &FuseAppBase::opt_parse>) == -1) { + exit(1); + } + return fuse_main(args.argc, args.argv, &operations, NULL); +} + +int +main(int argc, char* argv[]) +{ + return runFuseApp<NetFS>(argc, argv); +} + diff --git a/netfs/fuseapp.cpp b/netfs/fuseapp.cpp new file mode 100644 index 0000000..b46d3ad --- /dev/null +++ b/netfs/fuseapp.cpp @@ -0,0 +1,154 @@ +#include "fuseapp.h" +#include <errno.h> + +FuseAppBase::FuseAppBase() +{ +} +FuseAppBase::~FuseAppBase() +{ +} +void * FuseAppBase::init(fuse_conn_info*) +{ + return NULL; +} +int FuseAppBase::opt_parse(void*, const char *, int, fuse_args*) +{ + return 1; +} +int FuseAppBase::access(const char *, int) +{ + return -ENOSYS; +} +int FuseAppBase::chmod(const char *, mode_t) +{ + return -ENOSYS; +} +int FuseAppBase::chown(const char *, uid_t, gid_t) +{ + return -ENOSYS; +} +int FuseAppBase::create(const char *, mode_t, struct fuse_file_info *) +{ + return -ENOSYS; +} +int FuseAppBase::fgetattr(const char *, struct stat *, struct fuse_file_info *) +{ + return -ENOSYS; +} +int FuseAppBase::flush(const char *, struct fuse_file_info *) +{ + return -ENOSYS; +} +int FuseAppBase::fsync(const char *, int, struct fuse_file_info *) +{ + return -ENOSYS; +} +int FuseAppBase::fsyncdir(const char *, int, struct fuse_file_info *) +{ + return -ENOSYS; +} +int FuseAppBase::ftruncate(const char *, off_t, struct fuse_file_info *) +{ + return -ENOSYS; +} +int FuseAppBase::getattr(const char *, struct stat *) +{ + return -ENOSYS; +} +int FuseAppBase::getxattr(const char *, const char *, char *, size_t) +{ + return -ENOSYS; +} +int FuseAppBase::link(const char *, const char *) +{ + return -ENOSYS; +} +int FuseAppBase::listxattr(const char *, char *, size_t) +{ + return -ENOSYS; +} +int FuseAppBase::mkdir(const char *, mode_t) +{ + return -ENOSYS; +} +int FuseAppBase::mknod(const char *, mode_t, dev_t) +{ + return -ENOSYS; +} +int FuseAppBase::open(const char *, struct fuse_file_info *) +{ + return -ENOSYS; +} +int FuseAppBase::opendir(const char *, struct fuse_file_info *) +{ + return -ENOSYS; +} +int FuseAppBase::read(const char *, char *, size_t, off_t, struct fuse_file_info *) +{ + return -ENOSYS; +} +int FuseAppBase::readdir(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *) +{ + return -ENOSYS; +} +int FuseAppBase::readlink(const char *, char *, size_t) +{ + return -ENOSYS; +} +int FuseAppBase::release(const char *, struct fuse_file_info *) +{ + return -ENOSYS; +} +int FuseAppBase::releasedir(const char *, struct fuse_file_info *) +{ + return -ENOSYS; +} +int FuseAppBase::removexattr(const char *, const char *) +{ + return -ENOSYS; +} +int FuseAppBase::rename(const char *, const char *) +{ + return -ENOSYS; +} +int FuseAppBase::rmdir(const char *) +{ + return -ENOSYS; +} +int FuseAppBase::setxattr(const char *, const char *, const char *, size_t, int) +{ + return -ENOSYS; +} +int FuseAppBase::statfs(const char *, struct statvfs *) +{ + return -ENOSYS; +} +int FuseAppBase::symlink(const char *, const char *) +{ + return -ENOSYS; +} +int FuseAppBase::truncate(const char *, off_t) +{ + return -ENOSYS; +} +int FuseAppBase::unlink(const char *) +{ + return -ENOSYS; +} +int FuseAppBase::write(const char *, const char *, size_t, off_t, struct fuse_file_info *) +{ + return -ENOSYS; +} +int FuseAppBase::lock(const char *, struct fuse_file_info *, int, struct flock *) +{ + return -ENOSYS; +} +int FuseAppBase::utimens(const char *, const struct timespec[2]) +{ + return -ENOSYS; +} +int FuseAppBase::bmap(const char *, size_t, uint64_t *) +{ + return -ENOSYS; +} + diff --git a/netfs/fuseapp.h b/netfs/fuseapp.h new file mode 100644 index 0000000..965ef0d --- /dev/null +++ b/netfs/fuseapp.h @@ -0,0 +1,50 @@ +#ifndef FUSEAPP_H +#define FUSEAPP_H + +#define FUSE_USE_VERSION 26 +#include <fuse.h> + +class FuseAppBase { + public: + FuseAppBase(); + virtual ~FuseAppBase() = 0; + virtual void * init (struct fuse_conn_info * info); + virtual int opt_parse(void *, const char * arg, int key, struct fuse_args *); + virtual int access(const char *, int); + virtual int chmod(const char *, mode_t); + virtual int chown(const char *, uid_t, gid_t); + virtual int create(const char *, mode_t, struct fuse_file_info *); + virtual int fgetattr(const char *, struct stat *, struct fuse_file_info *); + virtual int flush(const char *, struct fuse_file_info *); + virtual int fsync(const char *, int, struct fuse_file_info *); + virtual int fsyncdir(const char *, int, struct fuse_file_info *); + virtual int ftruncate(const char *, off_t, struct fuse_file_info *); + virtual int getattr(const char *, struct stat *); + virtual int getxattr(const char *, const char *, char *, size_t); + virtual int link(const char *, const char *); + virtual int listxattr(const char *, char *, size_t); + virtual int mkdir(const char *, mode_t); + virtual int mknod(const char *, mode_t, dev_t); + virtual int open(const char *, struct fuse_file_info *); + virtual int opendir(const char *, struct fuse_file_info *); + virtual int read(const char *, char *, size_t, off_t, struct fuse_file_info *); + virtual int readdir(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *); + virtual int readlink(const char *, char *, size_t); + virtual int release(const char *, struct fuse_file_info *); + virtual int releasedir(const char *, struct fuse_file_info *); + virtual int removexattr(const char *, const char *); + virtual int rename(const char *, const char *); + virtual int rmdir(const char *); + virtual int setxattr(const char *, const char *, const char *, size_t, int); + virtual int statfs(const char *, struct statvfs *); + virtual int symlink(const char *, const char *); + virtual int truncate(const char *, off_t); + virtual int unlink(const char *); + virtual int write(const char *, const char *, size_t, off_t, struct fuse_file_info *); + virtual int lock(const char *, struct fuse_file_info *, int cmd, struct flock *); + virtual int utimens(const char *, const struct timespec tv[2]); + virtual int bmap(const char *, size_t blocksize, uint64_t *idx); +}; + +#endif + diff --git a/netfs/fusecallers.h b/netfs/fusecallers.h new file mode 100644 index 0000000..cb521df --- /dev/null +++ b/netfs/fusecallers.h @@ -0,0 +1,4 @@ +#ifndef FUSECALLERS_H +#define FUSECALLERS_H +#endif + diff --git a/netfs/makefile.in b/netfs/makefile.in new file mode 100644 index 0000000..f7901ba --- /dev/null +++ b/netfs/makefile.in @@ -0,0 +1,63 @@ +FUSEFLAGS=-D_FILE_OFFSET_BITS=64 +COMPFLAGS=-DTHREADSAFE -I ../libmisc -I /usr/include/libxml2 +myCXXFLAGS=${CXXFLAGS} ${COMPFLAGS} ${FUSEFLAGS} +LDFLAGS=-lfuse -Xlinker --warn-once -L ../libmisc -l misc -l xml2 +CXX=g++ +CC=${CXX} +default : makefile all + +-include makedeps.mk + +all : makedeps.mk tags netfs netfsd +makefile : makefile.in + @echo "Makefile out of date. Please re-run configure." + @false + +makedeps.mk : $(patsubst %.cpp, %.d, $(wildcard *.cpp)) $(wildcard *.h) + cat *.d > $@ + +%.o : %.d + +%.o : %.cpp + g++ -c ${myCXXFLAGS} $< -o $@ +%.d : %.cpp $(wildcard *.h) + g++ -M ${myCXXFLAGS} $< -o $@ + +tags : $(wildcard *.c*) $(wildcard *.h) + @exuberant-ctags -R + +NETFSOBJS= \ + comms.o \ + fuse.o \ + fuseapp.o \ + msgtypes.o \ + +NETFSDOBJS= \ + comms.o \ + daemon.o \ + daemonConfig.o \ + msgtypes.o \ + +netfs : ${NETFSOBJS} + g++ -o $@ ${NETFSOBJS} ${LDFLAGS} + +netfsd : ${NETFSDOBJS} + g++ -o $@ ${NETFSDOBJS} ${LDFLAGS} + +.SUFFIXES: .cpp .o +.PHONY: clean test mount umount install uninstall + +clean : + rm -f *.o *.d + rm -f netfsd netfs + rm -f makedeps.mk + +install : netfs netfsd + cp -f netfs /usr/bin/netfs + ln -sf /usr/bin/netfs /sbin/mount.netfs + cp -f netfsd /sbin/netfsd + +uninstall : + rm -f /usr/bin/netfs + rm -f /sbin/mount.netfs + rm -f /sbin/netfsd diff --git a/netfs/msgtypes.cpp b/netfs/msgtypes.cpp new file mode 100644 index 0000000..e7a814e --- /dev/null +++ b/netfs/msgtypes.cpp @@ -0,0 +1,152 @@ +#include "msgtypes.h" +#include "xfers.h" + +MessageFactories & MsgFacs() +{ + static MessageFactories m; + return m; +} + +MSGTYPE(0, SimpleInt) +MSGTYPE(1, AccessRequest) +MSGTYPE(2, GetAttrRequest) +MSGTYPE(3, GetAttrReply) +MSGTYPE(4, OpenDirRequest) +MSGTYPE(5, OpenDirReply) +MSGTYPE(6, CloseDirRequest) +MSGTYPE(7, CloseDirReply) +MSGTYPE(8, ReadDirRequest) +MSGTYPE(9, ReadDirReply) +MSGTYPE(10, ReadDirContent) +MSGTYPE(11, OpenRequest) +MSGTYPE(12, OpenReply) +MSGTYPE(13, CloseRequest) +MSGTYPE(14, CloseReply) +MSGTYPE(15, ReadRequest) +MSGTYPE(16, ReadReply) +MSGTYPE(17, WriteRequest) +MSGTYPE(18, WriteReply) + +template<class Type> void operator<<(FILE &, const Type & t); +template<class Type> void operator>>(FILE &, Type & t); + +template<> void operator<<(FILE & f, const std::string & t) +{ + std::string::size_type len = t.length(); + f << len; + if (fwrite(t.data(), len, 1, &f) < len) { + } +} +template<> void operator>>(FILE & f, std::string & t) +{ + std::string::size_type len; + f >> len; + t.clear(); + t.reserve(len); + while (len --) { + t.push_back(fgetc(&f)); + } +} +template<class Type> void operator<<(FILE & f, const Type & t) +{ + if (fwrite(&t, sizeof(t), 1, &f) < sizeof(t)) { + } +} +template<class Type> void operator>>(FILE & f, Type & t) +{ + if (fread(&t, sizeof(t), 1, &f) < sizeof(t)) { + } +} + +void +ContentBase::Send(FILE*) const +{ +} +void +ContentBase::Read(FILE*) +{ +} +Xfer2(RequestBase, ContentBase, uid, gid) +Xfer1(OpenDirRequest, RequestBase, path) +Xfer2(OpenDirReply, ContentBase, error, handle) +Xfer2(ReadDirReply, ContentBase, error, count) +Xfer1(ReadDirRequest, RequestBase, handle) +Xfer2(AccessRequest, RequestBase, path, access) +Xfer1(SimpleInt, ContentBase, value) +Xfer1(GetAttrRequest, RequestBase, path) +Xfer2(GetAttrReply, ContentBase, res, val) +Xfer1(CloseDirRequest, RequestBase, handle) +Xfer1(CloseDirReply, ContentBase, error) +Xfer2(ReadDirContent, ContentBase, path, val) +Xfer1(OpenRequest, RequestBase, path) +Xfer2(OpenReply, ContentBase, error, handle) +Xfer1(CloseRequest, RequestBase, handle) +Xfer1(CloseReply, ContentBase, error) +Xfer3(ReadRequest, RequestBase, handle, offset, size) +Xfer1(WriteReply, ContentBase, error) + +ReadReply::~ReadReply() +{ + if (data) { + delete[] data; + } +} +void +ReadReply::Send(FILE*f) const +{ + ContentBase::Send(f); + *f << error; + *f << size; + if (size) { + if (fwrite(data, size, 1, f) < size) { + } + } +} +void +ReadReply::Read(FILE*f) +{ + ContentBase::Read(f); + *f >> error; + *f >> size; + if (size) { + data = new char[size](); + if (fread(data, size, 1, f) < size) { + } + } + else { + data = NULL; + } +} + +WriteRequest::~WriteRequest() +{ + if (data) { + delete[] data; + } +} +void +WriteRequest::Send(FILE*f) const +{ + RequestBase::Send(f); + *f << handle; + *f << size; + *f << offset; + if (fwrite(data, size, 1, f) < size) { + } +} +void +WriteRequest::Read(FILE*f) +{ + RequestBase::Read(f); + *f >> handle; + *f >> size; + *f >> offset; + if (size) { + data = new char[size](); + if (fread(data, size, 1, f) < size) { + } + } + else { + data = NULL; + } +} diff --git a/netfs/msgtypes.h b/netfs/msgtypes.h new file mode 100644 index 0000000..c29dc93 --- /dev/null +++ b/netfs/msgtypes.h @@ -0,0 +1,212 @@ +#ifndef MSGTYPES_H +#define MSGTYPES_H + +#include "smartpointer.h" +#include "comms.h" +#include <map> +#include <string> +#include <sys/stat.h> +#include <stdint.h> + +typedef DataPayloadPtr (*MessageFactory)(); +typedef std::map<uint16_t, MessageFactory> MessageFactories; +MessageFactories & MsgFacs(); + +template <class Cls> +class Factory { + public: + Factory() { MsgFacs()[Cls::TypeID] = &create; } + static DataPayloadPtr create() { + return new TypedPayload<Cls>(); + } +}; + +class ContentBase : public IsRefCounted { + public: + ~ContentBase() = 0; + virtual void Send(FILE*) const; + virtual void Read(FILE*); +}; + +class RequestBase : public ContentBase { + public: + uid_t uid; + gid_t gid; + virtual void Send(FILE*) const; + virtual void Read(FILE*); +}; + +class SimpleInt : public ContentBase { + public: + int value; + const static uint16_t TypeID; + virtual void Send(FILE*) const; + virtual void Read(FILE*); +}; + +class AccessRequest : public RequestBase { + public: + std::string path; + int access; + const static uint16_t TypeID; + typedef SimpleInt Reply; + virtual void Send(FILE*) const; + virtual void Read(FILE*); +}; + +class GetAttrReply : public ContentBase { + public: + int res; + struct stat val; + const static uint16_t TypeID; + virtual void Send(FILE*) const; + virtual void Read(FILE*); +}; + +class GetAttrRequest : public RequestBase { + public: + std::string path; + const static uint16_t TypeID; + typedef GetAttrReply Reply; + virtual void Send(FILE*) const; + virtual void Read(FILE*); +}; + +class OpenDirReply : public ContentBase { + public: + int handle; + int error; + const static uint16_t TypeID; + virtual void Send(FILE*) const; + virtual void Read(FILE*); +}; + +class OpenDirRequest : public RequestBase { + public: + std::string path; + const static uint16_t TypeID; + typedef OpenDirReply Reply; + virtual void Send(FILE*) const; + virtual void Read(FILE*); +}; + +class CloseDirReply : public ContentBase { + public: + int error; + const static uint16_t TypeID; + virtual void Send(FILE*) const; + virtual void Read(FILE*); +}; + +class CloseDirRequest : public RequestBase { + public: + int handle; + const static uint16_t TypeID; + typedef CloseDirReply Reply; + virtual void Send(FILE*) const; + virtual void Read(FILE*); +}; + +class ReadDirReply : public ContentBase { + public: + int error; + size_t count; + const static uint16_t TypeID; + virtual void Send(FILE*) const; + virtual void Read(FILE*); +}; + +class ReadDirRequest : public RequestBase { + public: + int handle; + const static uint16_t TypeID; + typedef ReadDirReply Reply; + virtual void Send(FILE*) const; + virtual void Read(FILE*); +}; + +class ReadDirContent : public ContentBase { + public: + std::string path; + struct stat val; + const static uint16_t TypeID; + virtual void Send(FILE*) const; + virtual void Read(FILE*); +}; + +class OpenReply : public ContentBase { + public: + int error; + int handle; + const static uint16_t TypeID; + virtual void Send(FILE*) const; + virtual void Read(FILE*); +}; +class OpenRequest : public RequestBase { + public: + std::string path; + const static uint16_t TypeID; + typedef OpenReply Reply; + virtual void Send(FILE*) const; + virtual void Read(FILE*); +}; +class CloseReply : public ContentBase { + public: + int error; + const static uint16_t TypeID; + virtual void Send(FILE*) const; + virtual void Read(FILE*); +}; +class CloseRequest : public RequestBase { + public: + int handle; + const static uint16_t TypeID; + typedef CloseReply Reply; + virtual void Send(FILE*) const; + virtual void Read(FILE*); +}; +class ReadReply : public ContentBase { + public: + ~ReadReply(); + int error; + char * data; + size_t size; + const static uint16_t TypeID; + virtual void Send(FILE*) const; + virtual void Read(FILE*); +}; +class ReadRequest : public RequestBase { + public: + int handle; + size_t size; + off_t offset; + const static uint16_t TypeID; + typedef ReadReply Reply; + virtual void Send(FILE*) const; + virtual void Read(FILE*); +}; +class WriteReply : public ContentBase { + public: + int error; + const static uint16_t TypeID; + virtual void Send(FILE*) const; + virtual void Read(FILE*); +}; +class WriteRequest : public RequestBase { + public: + ~WriteRequest(); + int handle; + size_t size; + char * data; + off_t offset; + const static uint16_t TypeID; + typedef WriteReply Reply; + virtual void Send(FILE*) const; + virtual void Read(FILE*); +}; + +#define MSGTYPE(id, cls) \ + const uint16_t cls::TypeID = id; \ + namespace FactoryFor##cls { Factory<cls> fac; } +#endif + diff --git a/netfs/xfers.h b/netfs/xfers.h new file mode 100644 index 0000000..c1369eb --- /dev/null +++ b/netfs/xfers.h @@ -0,0 +1,53 @@ +#ifndef XFERS_H +#define XFERS_H + +#define Xfer1(Ptype, Pbase, v1) \ +void \ +Ptype::Send(FILE*f) const \ +{ \ + Pbase::Send(f); \ + *f << v1; \ +} \ +void \ +Ptype::Read(FILE*f) \ +{ \ + Pbase::Read(f); \ + *f >> v1; \ +} + +#define Xfer2(Ptype, Pbase, v1, v2) \ +void \ +Ptype::Send(FILE*f) const \ +{ \ + Pbase::Send(f); \ + *f << v1; \ + *f << v2; \ +} \ +void \ +Ptype::Read(FILE*f) \ +{ \ + Pbase::Read(f); \ + *f >> v1; \ + *f >> v2; \ +} + +#define Xfer3(Ptype, Pbase, v1, v2, v3) \ +void \ +Ptype::Send(FILE*f) const \ +{ \ + Pbase::Send(f); \ + *f << v1; \ + *f << v2; \ + *f << v3; \ +} \ +void \ +Ptype::Read(FILE*f) \ +{ \ + Pbase::Read(f); \ + *f >> v1; \ + *f >> v2; \ + *f >> v3; \ +} + +#endif + |