diff --git a/.gitignore b/.gitignore
index 0ceafbbf..d10a224b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1213,4 +1213,10 @@ python-sdk/samples/env/*
python-sdk/venv/*
python-cli/venv/*
python-cli/mft_cli/poetry.lock
-plugins/*
\ No newline at end of file
+plugins/*
+
+
+# mft-fs gitignores
+mft-fs/mftfs_data/
+mft-fs/mount
+mft-fs/root
diff --git a/mft-fs/Dockerfile b/mft-fs/Dockerfile
new file mode 100644
index 00000000..4b781d4a
--- /dev/null
+++ b/mft-fs/Dockerfile
@@ -0,0 +1,22 @@
+# Use the latest Ubuntu image
+FROM ubuntu:latest
+
+# Install necessary packages
+RUN apt-get update && apt-get install -y \
+ fuse \
+ kmod \
+ wget \
+ curl \
+ git \
+ build-essential
+
+# Download and install Go v1.22.3
+RUN wget https://go.dev/dl/go1.22.3.linux-amd64.tar.gz && \
+ tar -C /usr/local -xzf go1.22.3.linux-amd64.tar.gz && \
+ rm go1.22.3.linux-amd64.tar.gz
+
+# Set up Go environment
+ENV PATH="/usr/local/go/bin:${PATH}"
+ENV GOPATH="/go"
+ENV PATH="${GOPATH}/bin:${PATH}"
+
diff --git a/mft-fs/README.md b/mft-fs/README.md
new file mode 100644
index 00000000..3dadc180
--- /dev/null
+++ b/mft-fs/README.md
@@ -0,0 +1,187 @@
+
MFT-FS
+
+
+
+MFT-FS is a FUSE-based extension to Airavata MFT. It provides the abstraction that unifies the different file I/O protocols into one filesystem.
+
+The Problem:
+
+
+
+
+The Solution:
+
+
+
+
+Operating System Filesystem (OSFS)
+
+This was more of a learning/testing implementation. It creates a filesystem mount which provides implementations for each fileystem method. However, the implementation has identical behavior to the native filesystem of the computer. It is merely a filesystem that mimics the operating system's filesystem.
+
+
+
+Remote Filesystem (RemoteFS)
+
+
+
+This filesystem uses gRPC to exchange data between a client and a server. In this filesystem, the client has the FUSE mount running. The client's FUSE mount invokes FUSE operations remotely, using gRPC. Thus, all of the operations performed on the client will modify the server's operating system.
+
+Note: RemoteFS is NOT threadsafe. Multiple clients reading and writing concurrently can cause race conditions and inconsistency.
+
+
+
+Safe Remote Filesystem (SafeRemoteFS)
+
+
+
+This filesystem adds the safety layers on top of the remote filesystem. It uses a Concurrent Reads, Exclusive Writes (CREW) model. Prior to reading/writing a file, the client must request to read/write. This is a blocking operation. The server only grants access to the client when there are no writers. If a client is reading/writing, it is guaranteed that no other client can write at the same time. After a client is done reading/writing, it must send an acknowledgement.
+
+
+
+Instructions for RemoteFS
+
+RemoteFS is a Filesystem supported over a gRPC-based TCP connection.
+
+The following instructions assume Go v1.20.x and FUSE are installed on the system.
+
+
+
+
+Code can be installed using
+
+```shell
+git clone https://github.com/RohanPhadnis/airavata-mft.git
+```
+
+Perform all the steps below from the airavata-mft/mft-fs directory.
+
+
+-
+
+To get the go.mod file ready, use the following command:
+
+```shell
+cat gomod.txt > go.mod
+```
+
+
+
+-
+
+To install all dependencies, run the following two commands:
+
+```shell
+go mod tidy
+go install ./...
+```
+
+
+
+-
+
+Before running, ensure you have the mount and test directories in the main directory.
+
+```shell
+mkdir mount
+mkdir root
+```
+
+
+
+-
+
+To run the server, use the command:
+
+```shell
+go run ./remotefs/servermain/server_main.go --rootDirectory ./root
+```
+
+This will run the server locally to interface with the FUSE client.
+
+
+
+
+-
+
+To run the client, allow the server to run in a terminal session. Open a new terminal and type:
+
+```shell
+go run ./remotefs/clientmain/client_main.go --mountDirectory ./mount
+```
+
+
+
+
+Important Final Step: Enjoy and report any bugs!
+
+
+
+
+
+Instructions for OSFS
+
+OSFS is a Filesystem Mount which uses the local operating system to interface with FUSE.
+
+The following instructions assume Go v1.20.x and FUSE are installed on the system.
+
+
+
+
+Code can be installed using
+
+```shell
+git clone https://github.com/RohanPhadnis/airavata-mft.git
+```
+
+Perform all the steps below from the airavata-mft/mft-fs directory.
+
+
+-
+
+To get the go.mod file ready, use the following command:
+
+```shell
+cat gomod.txt > go.mod
+```
+
+
+
+-
+
+To install all dependencies, run the following two commands:
+
+```shell
+go mod tidy
+go install ./...
+```
+
+
+
+-
+
+Before running, ensure you have the mount and test directories in the main directory.
+
+```shell
+mkdir mount
+mkdir root
+```
+
+
+
+-
+
+To run the project, use the command:
+
+```shell
+go run ./main/main.go --mountDirectory ./mount --rootDirectory ./root
+```
+
+This will mount the pass-through functions on the ./mount directory. All operations will be computed and performed on ./root
+
+
+
+
+
+Important Final Step: Enjoy and report any bugs!
+
+
\ No newline at end of file
diff --git a/mft-fs/abstractfs/abstractfs.go b/mft-fs/abstractfs/abstractfs.go
new file mode 100644
index 00000000..bac6526c
--- /dev/null
+++ b/mft-fs/abstractfs/abstractfs.go
@@ -0,0 +1,499 @@
+/*
+Package abstractfs
+abstractfs is a FUSE-based filesystem wrapper
+it defines an interface for a filesystem Manager, which can be implemented by any filesystem
+it implements FUSE operations which calls the respective methods of the filesystems
+*/
+package abstractfs
+
+import (
+ "context"
+ "fmt"
+ "time"
+
+ "github.com/jacobsa/fuse"
+ "github.com/jacobsa/fuse/fuseops"
+ "github.com/jacobsa/fuse/fuseutil"
+)
+
+type NoImplementationError struct{}
+
+func (e NoImplementationError) Error() string {
+ return "No implementation"
+}
+
+/*
+The printer function prints messages to the terminal on behalf of FUSE operations.
+*/
+func printer(message string) {
+ fmt.Println(message)
+
+ /*file, _ := os.OpenFile("log.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
+ defer file.Close()
+ file.WriteString(fmt.Sprintf("%s\n", message))*/
+}
+
+func minimum(a int64, b int64) int64 {
+ if a < b {
+ return a
+ }
+ return b
+}
+
+func expireTime() time.Time {
+ return time.Now().Add(time.Minute)
+}
+
+type AbstractFS struct {
+ // fuseutil.NotImplementedFileSystem
+ Manager FSManager
+ MountDir string
+
+ Cachable bool
+ CacheDir string
+}
+
+func (fs AbstractFS) MkNode(ctx context.Context, op *fuseops.MkNodeOp) error {
+ printer("MkNode")
+ return nil
+}
+
+func (fs AbstractFS) CreateLink(ctx context.Context, op *fuseops.CreateLinkOp) error {
+ printer("MkNode")
+ return nil
+}
+
+func (fs AbstractFS) CreateSymlink(ctx context.Context, op *fuseops.CreateSymlinkOp) error {
+ printer("MkNode")
+ return nil
+}
+
+func (fs AbstractFS) Rename(ctx context.Context, op *fuseops.RenameOp) error {
+ printer("MkNode")
+ return nil
+}
+
+func (fs AbstractFS) Unlink(ctx context.Context, op *fuseops.UnlinkOp) error {
+ printer("MkNode")
+ return nil
+}
+
+func (fs AbstractFS) ReadSymlink(ctx context.Context, op *fuseops.ReadSymlinkOp) error {
+ printer("MkNode")
+ return nil
+}
+
+func (fs AbstractFS) RemoveXattr(ctx context.Context, op *fuseops.RemoveXattrOp) error {
+ printer("MkNode")
+ return nil
+}
+
+func (fs AbstractFS) GetXattr(ctx context.Context, op *fuseops.GetXattrOp) error {
+ printer("MkNode")
+ return nil
+}
+
+func (fs AbstractFS) ListXattr(ctx context.Context, op *fuseops.ListXattrOp) error {
+ printer("MkNode")
+ return nil
+}
+
+func (fs AbstractFS) SetXattr(ctx context.Context, op *fuseops.SetXattrOp) error {
+ printer("MkNode")
+ return nil
+}
+
+func (fs AbstractFS) Fallocate(ctx context.Context, op *fuseops.FallocateOp) error {
+ printer("MkNode")
+ return nil
+}
+
+// private helpers
+
+// fillAttributes
+// todo: update local inode info once fetched from remote
+func (fs AbstractFS) fillAttributes(inode fuseops.InodeID, attributes *fuseops.InodeAttributes) error {
+ info, e := fs.Manager.GetInfo(inode)
+ if e != nil {
+ return fuse.ENOENT
+ }
+
+ attributes.Size = info.Size
+
+ attributes.Nlink = info.Nlink
+
+ attributes.Mode = info.Mode
+
+ attributes.Atime = info.Atime
+ attributes.Mtime = info.Mtime
+ attributes.Ctime = info.Ctime
+ attributes.Crtime = info.Crtime
+
+ attributes.Uid = info.Uid
+ attributes.Gid = info.Gid
+
+ return nil
+}
+
+// public methods
+
+func NewAbstractFS(manager FSManager) (AbstractFS, error) {
+ fs := AbstractFS{
+ Manager: manager,
+ }
+ return fs, nil
+}
+
+// FUSE Operations
+
+// StatFS
+// call Manager's GetSize and GetLength methods to perform operation
+func (fs AbstractFS) StatFS(ctx context.Context, op *fuseops.StatFSOp) error {
+ printer("StatFS")
+
+ op.BlockSize = 4096
+
+ size, e := fs.Manager.GetSize()
+ op.Blocks = 64
+ op.BlocksFree = uint64(64 - uint32(size)/op.BlockSize)
+ op.BlocksAvailable = op.BlocksFree
+
+ op.IoSize = 4096
+
+ op.Inodes = 128
+ length, e := fs.Manager.GetLength()
+ if e != nil {
+ return e
+ }
+ op.InodesFree = op.Inodes - length
+
+ return nil
+}
+
+// LookUpInode
+// call Manager's GetInode to get latest information
+// todo: update local info once fetched from remote
+func (fs AbstractFS) LookUpInode(ctx context.Context, op *fuseops.LookUpInodeOp) error {
+ printer("LookUpInode")
+
+ // does parent exist?
+ parentInfo, e := fs.Manager.GetInfo(op.Parent)
+ if e != nil {
+ return fuse.ENOENT
+ }
+
+ // is parent a directory?
+ if parentInfo.DirentType != fuseutil.DT_Directory {
+ return fuse.ENOTDIR
+ }
+
+ // does child exist in parent?
+ index, ok := parentInfo.ChildrenIndexMap[op.Name]
+ if !ok {
+ return nil // fuse.ENOENT
+ }
+
+ // get child's inode
+ childInode := parentInfo.Children[index]
+
+ // fill information
+ op.Entry.Child = childInode
+ op.Entry.AttributesExpiration = expireTime()
+ op.Entry.EntryExpiration = expireTime()
+
+ return fs.fillAttributes(childInode, &op.Entry.Attributes)
+}
+
+func (fs AbstractFS) GetInodeAttributes(ctx context.Context, op *fuseops.GetInodeAttributesOp) error {
+ printer("GetInodeAttributes")
+
+ op.AttributesExpiration = expireTime()
+ return fs.fillAttributes(op.Inode, &op.Attributes)
+}
+
+// SetInodeAttributes
+// todo: update local information too; possible data race: remote locking?
+func (fs AbstractFS) SetInodeAttributes(ctx context.Context, op *fuseops.SetInodeAttributesOp) error {
+ printer("SetInodeAttributes")
+ op.AttributesExpiration = expireTime()
+ e := fs.Manager.SetInfo(op.Inode, op.Uid, op.Gid, op.Size, op.Mode, op.Atime, op.Mtime)
+ if e != nil {
+ return e
+ }
+ return fs.fillAttributes(op.Inode, &op.Attributes)
+}
+
+// ForgetInode
+// todo account for references and hard links
+func (fs AbstractFS) ForgetInode(ctx context.Context, op *fuseops.ForgetInodeOp) error {
+ printer("ForgetInode")
+ return fs.Manager.Delete(op.Inode)
+}
+
+func (fs AbstractFS) BatchForget(ctx context.Context, op *fuseops.BatchForgetOp) error {
+ printer("BatchForget")
+ var e error
+ for _, entry := range op.Entries {
+ e = fs.Manager.Delete(entry.Inode)
+ if e != nil {
+ return e
+ }
+ }
+ return nil
+}
+
+func (fs AbstractFS) MkDir(ctx context.Context, op *fuseops.MkDirOp) error {
+ printer("MkDir")
+
+ // get parent information
+ info, e := fs.Manager.GetInfo(op.Parent)
+ if e != nil {
+ return e
+ }
+
+ // check if parent is a directory
+ if info.DirentType != fuseutil.DT_Directory {
+ return fuse.ENOTDIR
+ }
+
+ // already exists?
+ _, ok := info.ChildrenIndexMap[op.Name]
+ if ok {
+ return fuse.EEXIST
+ }
+
+ childInode, e := fs.Manager.MkDir(op.Parent, op.Name, op.Mode)
+ if e != nil {
+ return e
+ }
+
+ op.Entry.AttributesExpiration = expireTime()
+ op.Entry.EntryExpiration = expireTime()
+ op.Entry.Child = childInode
+ return fs.fillAttributes(childInode, &op.Entry.Attributes)
+}
+
+func (fs AbstractFS) CreateFile(ctx context.Context, op *fuseops.CreateFileOp) error {
+ printer("CreateFile")
+
+ // get parent information
+ info, e := fs.Manager.GetInfo(op.Parent)
+ if e != nil {
+ return e
+ }
+
+ // check if parent is a directory
+ if info.DirentType != fuseutil.DT_Directory {
+ return fuse.ENOTDIR
+ }
+
+ // already exists?
+ _, ok := info.ChildrenIndexMap[op.Name]
+ if ok {
+ return fuse.EEXIST
+ }
+
+ childInode, e := fs.Manager.CreateFile(op.Parent, op.Name, op.Mode)
+ if e != nil {
+ return e
+ }
+
+ op.Entry.AttributesExpiration = expireTime()
+ op.Entry.EntryExpiration = expireTime()
+ op.Entry.Child = childInode
+ op.Handle = fuseops.HandleID(childInode)
+ if e != nil {
+ return e
+ }
+ return fs.fillAttributes(childInode, &op.Entry.Attributes)
+}
+
+func (fs AbstractFS) RmDir(ctx context.Context, op *fuseops.RmDirOp) error {
+ printer("RmDir")
+
+ info, e := fs.Manager.GetInfo(op.Parent)
+ if e != nil {
+ return e
+ }
+
+ if info.DirentType != fuseutil.DT_Directory {
+ return fuse.ENOTDIR
+ }
+
+ inode := info.Children[info.ChildrenIndexMap[op.Name]]
+ return fs.Manager.RmDir(inode)
+}
+
+func (fs AbstractFS) OpenDir(ctx context.Context, op *fuseops.OpenDirOp) error {
+ printer("OpenDir")
+ op.Handle = fuseops.HandleID(op.Inode)
+ return nil
+}
+
+func (fs AbstractFS) ReadDir(ctx context.Context, op *fuseops.ReadDirOp) error {
+ printer("ReadDir")
+
+ info, e := fs.Manager.GetInfo(op.Inode)
+ if e != nil {
+ return e
+ }
+ if info.DirentType != fuseutil.DT_Directory {
+ return fuse.ENOTDIR
+ }
+ if info.Handle != op.Handle {
+ return fuse.ENOENT
+ }
+
+ printer(fmt.Sprintf("Path: %v\tOffset: %v\n", info.Path, op.Offset))
+
+ //if fuseops.DirOffset(len(data)) < op.Offset {
+ // return nil
+ //}
+
+ op.BytesRead = 0
+ bytesRead := 0
+ currentBytesRead := 0
+ buff := make([]byte, 1024)
+ for _, childInode := range info.Children {
+ dirent := fuseutil.Dirent{}
+ childInfo, e := fs.Manager.GetInfo(childInode)
+ if e != nil {
+ return e
+ }
+ dirent.Inode = childInfo.Inode
+ dirent.Name = childInfo.Name
+ dirent.Type = childInfo.DirentType
+ dirent.Offset = fuseops.DirOffset(bytesRead) // - op.Offset
+ currentBytesRead = fuseutil.WriteDirent(buff, dirent) //op.Dst[bytesRead:], dirent)
+ if bytesRead >= int(op.Offset) {
+ copy(op.Dst[op.BytesRead:], buff)
+ op.BytesRead += currentBytesRead
+ printer(fmt.Sprintf("Inode: %v\tName: %v\tOffset: %v\n", dirent.Inode, dirent.Name, dirent.Offset))
+ }
+ bytesRead += currentBytesRead
+ }
+
+ if int(op.Offset) >= bytesRead {
+ return nil
+ }
+
+ currentBytesRead = fuseutil.WriteDirent(op.Dst[op.BytesRead:], fuseutil.Dirent{
+ Offset: fuseops.DirOffset(bytesRead),
+ Name: ".",
+ Type: fuseutil.DT_Directory,
+ Inode: op.Inode,
+ })
+ bytesRead += currentBytesRead
+ op.BytesRead += currentBytesRead
+
+ // op.Dst = op.Dst[op.Offset:]
+ // op.BytesRead = bytesRead - int(op.Offset)
+
+ printer(fmt.Sprintf("Bytes Read: %v\n", op.BytesRead))
+
+ fmt.Println("done")
+
+ return nil
+}
+
+func (fs AbstractFS) ReleaseDirHandle(ctx context.Context, op *fuseops.ReleaseDirHandleOp) error {
+ printer("ReleaseDirHandle")
+ return nil
+}
+
+func (fs AbstractFS) OpenFile(ctx context.Context, op *fuseops.OpenFileOp) error {
+ printer("OpenFile")
+ op.Handle = fuseops.HandleID(op.Inode)
+ return nil
+}
+
+func (fs AbstractFS) ReadFile(ctx context.Context, op *fuseops.ReadFileOp) error {
+ printer("ReadFile")
+
+ info, e := fs.Manager.GetInfo(op.Inode)
+ if e != nil {
+ return e
+ }
+
+ if op.Handle != info.Handle {
+ return fuse.ENOENT
+ }
+
+ if op.Dst != nil {
+ buff := make([]byte, op.Size)
+ byteCount, _ := fs.Manager.ReadAt(op.Inode, buff, op.Offset)
+ /*if e != nil {
+ return e
+ }*/
+ op.BytesRead = int(minimum(int64(byteCount), op.Size))
+ for i := 0; i < op.BytesRead; i++ {
+ op.Dst[i] = buff[i] //append(op.Dst, buff[i])
+ }
+ printer(string(buff))
+ printer(fmt.Sprintf("read requested at offset: %v\tbytes read: %v", op.Offset, byteCount))
+ return nil
+ }
+
+ // todo implement vector read
+ fmt.Println("vector read requested")
+
+ return NoImplementationError{}
+}
+
+func (fs AbstractFS) WriteFile(ctx context.Context, op *fuseops.WriteFileOp) error {
+ printer("WriteFile")
+
+ info, e := fs.Manager.GetInfo(op.Inode)
+ if e != nil {
+ return e
+ }
+ if info.Handle != op.Handle {
+ return fuse.ENOENT
+ }
+
+ _, e = fs.Manager.WriteAt(op.Inode, op.Data, op.Offset)
+ if e != nil {
+ return e
+ }
+
+ return nil
+}
+
+func (fs AbstractFS) SyncFile(ctx context.Context, op *fuseops.SyncFileOp) error {
+ printer("SyncFile")
+
+ info, e := fs.Manager.GetInfo(op.Inode)
+ if e != nil {
+ return e
+ }
+ if info.Handle != op.Handle {
+ return fuse.ENOENT
+ }
+
+ return fs.Manager.SyncFile(op.Inode)
+}
+
+func (fs AbstractFS) FlushFile(ctx context.Context, op *fuseops.FlushFileOp) error {
+ printer("SyncFile")
+
+ info, e := fs.Manager.GetInfo(op.Inode)
+ if e != nil {
+ return e
+ }
+ if info.Handle != op.Handle {
+ return fuse.ENOENT
+ }
+
+ return fs.Manager.SyncFile(op.Inode)
+}
+
+func (fs AbstractFS) ReleaseFileHandle(ctx context.Context, op *fuseops.ReleaseFileHandleOp) error {
+ printer("ReleaseFileHandle")
+ return nil
+}
+
+func (fs AbstractFS) Destroy() {
+ printer("Destroy")
+ fs.Manager.Teardown()
+ fuse.Unmount("./mount")
+}
diff --git a/mft-fs/abstractfs/abstractfs_utils.go b/mft-fs/abstractfs/abstractfs_utils.go
new file mode 100644
index 00000000..49c0a369
--- /dev/null
+++ b/mft-fs/abstractfs/abstractfs_utils.go
@@ -0,0 +1,292 @@
+package abstractfs
+
+import (
+ "os"
+ "time"
+
+ "github.com/jacobsa/fuse/fuseops"
+ "github.com/jacobsa/fuse/fuseutil"
+
+ "mft-fs/datastructures"
+)
+
+/*
+FSManager Interface
+the FSManager interface can be implemented by any custom filesystem
+its methods are used by the AbstractFS fuse server
+*/
+type FSManager interface {
+ /*
+ Start method to initiate any FS Manager.
+ params: None
+ returns:
+ error: any arror caused by the invocation
+ */
+ Start() error
+
+ /*
+ Teardown method to close any FS Manager.
+ params: None
+ returns:
+ error: any error caused by the invocation
+ */
+ Teardown() error
+
+ /*
+ GetSize method to get the size of the filesystem
+ params: None
+ returns:
+ uint64: the size of the filesystem, in bytes
+ error: any error caused by the invocation
+ */
+ GetSize() (uint64, error)
+
+ /*
+ GetLength method for getting the length of the filesystem
+ params: None
+ returns:
+ uint64: the length of the filesystem (count the number of unique inodes)
+ error: any error caused by the invocation
+ */
+ GetLength() (uint64, error)
+
+ /*
+ GetInfo method for getting stats and metrics of a specific inode
+ params:
+ id fuseops.InodeID: the inode for which the information is required
+ returns:
+ *FileInfo: a reference to the FileInfo object which describes the inode's information
+ error: any error caused by the invocation
+ */
+ GetInfo(id fuseops.InodeID) (*FileInfo, error)
+
+ /*
+ SetInfo method for setting or modifying an inode's attributes
+ params:
+ id fuseops.InodeID: the inode in question
+ uidptr *uint32: a pointer to the new UserID for the inode's ownership; if no change is desired, pass nil
+ gidptr *uint32: a pointer to the new GroupID for the inode's ownership; if no change is desired, pass nil
+ sizeptr *uint64: a pointer to the new size of the inode (in bytes); if no change is desired, pass nil
+ modeptr *os.FileMode: a pointer to the new filemode of the inode; if no change is desired, pass nil
+ atimeptr *time.Time: a pointer to the new access time of the inode; if no change is desired, pass nil
+ mtimeptr *time.Time: a pointer to the new modification time of the inode; if no change is desired, pass nil
+ returns:
+ error: any error caused by the invocation
+ */
+ SetInfo(id fuseops.InodeID, uidptr *uint32, gidptr *uint32, sizeptr *uint64, modeptr *os.FileMode, atimeptr *time.Time, mtimeptr *time.Time) error
+
+ /*
+ Delete method for deleting an inode from the filesystem entirely
+ params:
+ inode fuseops.InodeID: the inode to be deleted
+ returns:
+ error: any error caused by the invocation
+ */
+ Delete(inode fuseops.InodeID) error
+
+ /*
+ MkDir method for creating a directory
+ params:
+ parent fuseops.InodeID: inode of the parent directory
+ name string: name of the directory to be created
+ mode os.FileMode: mode to set permissions for the new directory
+ returns:
+ fuseops.InodeID: the inode of the new directory
+ error: any error caused by the invocation
+ */
+ MkDir(parent fuseops.InodeID, name string, mode os.FileMode) (fuseops.InodeID, error)
+
+ /*
+ CreateFile method to create a new file
+ params:
+ parent fuseops.InodeID: inode of the parent directory
+ name string: name of the file to be created
+ mode os.FileMode: mode to set permissions for the new file
+ returns:
+ fuseops.InodeID: the inode of the newly created file
+ error: any error caused by the invocation
+ */
+ CreateFile(parent fuseops.InodeID, name string, mode os.FileMode) (fuseops.InodeID, error)
+
+ /*
+ RmDir method for removing a directory
+ params:
+ inode fuseops.InodeID: inode of the directory being deleted
+ returns:
+ error: any error caused by the invocation
+ */
+ RmDir(inode fuseops.InodeID) error
+
+ /*
+ SyncFile method for syncing a file
+ params:
+ inode fuseops.InodeID: inode of the file being synced
+ returns:
+ error: any error caused by the invocation
+ */
+ SyncFile(inode fuseops.InodeID) error
+
+ /*
+ WriteAt method for writing data to a file at a specific offset
+ params:
+ inode fuseops.InodeID: the inode of the file being written to
+ data []byte: the bytes being written in
+ off int64: the offset of the location to write to
+ returns:
+ n int: the number of bytes written
+ err error: any error caused by the invocation
+ */
+ WriteAt(inode fuseops.InodeID, data []byte, off int64) (n int, err error)
+
+ /*
+ ReadAt method for reading from a file at a specific offset
+ params:
+ inode fuseops.InodeID: the inode of the file being read from
+ data []byte: the buffer to store all data being read into
+ off int64: the offset of the location to read from
+ returns:
+ n int: the number of bytes read
+ err error: any error caused by the invocation
+ */
+ ReadAt(inode fuseops.InodeID, data []byte, off int64) (n int, err error)
+
+ /*
+ Destroy method for destroying a filesystem
+ params: None
+ returns:
+ error: any error caused by the invocation
+ */
+ // Destroy() error
+}
+
+/*
+FileInfo struct for representing a file's information
+*/
+type FileInfo struct {
+ // name of the file/directory
+ Name string
+
+ // path to the file/directory
+ Path string
+
+ // inode of the file/directory
+ Inode fuseops.InodeID
+
+ // if it is a directory, a slice with inodes of all children
+ Children []fuseops.InodeID
+
+ // if it is a directory, a map: name of child -> index of child in Children slice
+ ChildrenIndexMap map[string]int
+
+ // inode of the parent directory
+ Parent fuseops.InodeID
+
+ // if it is a file, the number of links
+ Nlink uint32
+
+ // size of the file/directory
+ Size uint64
+
+ // the mode of the file/directory
+ Mode os.FileMode
+
+ // access time of the file/directory
+ Atime time.Time
+
+ // modification time of the file/directory
+ Mtime time.Time
+
+ // creation time of the file/directory
+ Ctime time.Time
+
+ // creation time of the file/directory
+ Crtime time.Time
+
+ // user id of the file/directory ownership
+ Uid uint32
+
+ // group id of the file/directory ownership
+ Gid uint32
+
+ // dirent type (file, directory, other)
+ DirentType fuseutil.DirentType
+
+ // handle to the file/directory
+ Handle fuseops.HandleID
+
+ // boolean variable to assess whether file has been cached locally
+ Cache bool
+
+ // time the variable was downloaded to the local cache
+ CacheTime time.Time
+
+ // time the metadata of the file was modified
+ MetadataWriteTime time.Time
+
+ // time the content of the file was modified
+ ContentWriteTime time.Time
+
+ // CREW lock for metadata
+ MetadataLock *datastructures.CREWResource
+
+ // CREW lock for content
+ ContentLock *datastructures.CREWResource
+}
+
+func (info *FileInfo) AddChild(childName string, childInode fuseops.InodeID) {
+ info.Children = append(info.Children, childInode)
+ info.ChildrenIndexMap[childName] = len(info.Children) - 1
+}
+
+/*
+NewFileInfo method to create a new FileInfo
+*/
+func NewFileInfo(name string, path string, inode fuseops.InodeID, parent fuseops.InodeID, direntType fuseutil.DirentType) FileInfo {
+ return FileInfo{
+ Name: name,
+ Children: make([]fuseops.InodeID, 0),
+ ChildrenIndexMap: make(map[string]int),
+ Parent: parent,
+ Inode: inode,
+ Path: path,
+ DirentType: direntType,
+ Cache: false,
+ CacheTime: time.Unix(0, 0),
+ ContentWriteTime: time.Now(),
+ }
+}
+
+/*
+NewSafeFileInfo method to create a new FileInfo
+ - also initializes CREW locks
+*/
+func NewSafeFileInfo(name string, path string, inode fuseops.InodeID, parent fuseops.InodeID, direntType fuseutil.DirentType) FileInfo {
+ return FileInfo{
+ Name: name,
+ Children: make([]fuseops.InodeID, 0),
+ ChildrenIndexMap: make(map[string]int),
+ Parent: parent,
+ Inode: inode,
+ Path: path,
+ DirentType: direntType,
+ Cache: false,
+ CacheTime: time.Unix(0, 0),
+ ContentWriteTime: time.Now(),
+ MetadataWriteTime: time.Now(),
+ ContentLock: datastructures.NewCREWResource(),
+ MetadataLock: datastructures.NewCREWResource(),
+ }
+}
+
+/**
+TODO
+ - implement caching
+ - read/write request
+ - request contains cacheBool and cacheTime
+ - permission granted for read iff cache is invalid
+ - permission granted for write iff cache is valid
+ - read/write ack
+ - send inode in request
+ - return new writecontent time
+ - implement local handles
+*/
diff --git a/mft-fs/archive/abstractfs/abstract_fs_operations.go b/mft-fs/archive/abstractfs/abstract_fs_operations.go
new file mode 100644
index 00000000..689ddb63
--- /dev/null
+++ b/mft-fs/archive/abstractfs/abstract_fs_operations.go
@@ -0,0 +1,440 @@
+/*
+Package abstractfs
+abstractfs is a FUSE-based filesystem wrapper
+it defines an interface for a filesystem manager, which can be implemented by any filesystem
+it implements FUSE operations which calls the respective methods of the filesystems
+*/
+package abstractfs
+
+import (
+ "context"
+ "fmt"
+ "github.com/jacobsa/fuse"
+ "github.com/jacobsa/fuse/fuseops"
+ "github.com/jacobsa/fuse/fuseutil"
+ "time"
+)
+
+type NoImplementationError struct{}
+
+func (e NoImplementationError) Error() string {
+ return "No implementation"
+}
+
+/*
+The printer function prints messages to the terminal on behalf of FUSE operations.
+*/
+func printer(message string) {
+ fmt.Println(message)
+
+ /*file, _ := os.OpenFile("log.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
+ defer file.Close()
+ file.WriteString(fmt.Sprintf("%s\n", message))*/
+}
+
+func minimum(a int64, b int64) int64 {
+ if a < b {
+ return a
+ }
+ return b
+}
+
+func expireTime() time.Time {
+ return time.Now().Add(time.Minute)
+}
+
+type AbstractFS struct {
+ fuseutil.NotImplementedFileSystem
+ Manager FSManager
+}
+
+// private helpers
+
+func (fs AbstractFS) fillAttributes(inode fuseops.InodeID, attributes *fuseops.InodeAttributes) error {
+ info, e := fs.Manager.GetInfo(inode)
+ if e != nil {
+ return fuse.ENOENT
+ }
+
+ attributes.Size = info.Size
+
+ attributes.Nlink = info.Nlink
+
+ attributes.Mode = info.Mode
+
+ attributes.Atime = info.Atime
+ attributes.Mtime = info.Mtime
+ attributes.Ctime = info.Ctime
+ attributes.Crtime = info.Crtime
+
+ attributes.Uid = info.Uid
+ attributes.Gid = info.Gid
+
+ return nil
+}
+
+// public methods
+
+func NewAbstractFS(manager FSManager) (AbstractFS, error) {
+ fs := AbstractFS{
+ Manager: manager,
+ }
+ return fs, nil
+}
+
+// FUSE Operations
+
+func (fs AbstractFS) StatFS(ctx context.Context, op *fuseops.StatFSOp) error {
+ printer("StatFS")
+
+ op.BlockSize = 4096
+
+ size, e := fs.Manager.GetSize()
+ op.Blocks = 64
+ op.BlocksFree = uint64(64 - uint32(size)/op.BlockSize)
+ op.BlocksAvailable = op.BlocksFree
+
+ op.IoSize = 4096
+
+ op.Inodes = 128
+ length, e := fs.Manager.GetLength()
+ if e != nil {
+ return e
+ }
+ op.InodesFree = op.Inodes - length
+
+ return nil
+}
+
+func (fs AbstractFS) LookUpInode(ctx context.Context, op *fuseops.LookUpInodeOp) error {
+ printer("LookUpInode")
+
+ // does parent exist?
+ parentInfo, e := fs.Manager.GetInfo(op.Parent)
+ if e != nil {
+ return fuse.ENOENT
+ }
+
+ // is parent a directory?
+ if parentInfo.DirentType != fuseutil.DT_Directory {
+ return fuse.ENOTDIR
+ }
+
+ // does child exist in parent?
+ index, ok := parentInfo.ChildrenIndexMap[op.Name]
+ if !ok {
+ return nil // fuse.ENOENT
+ }
+
+ // get child's inode
+ childInode := parentInfo.Children[index]
+
+ // fill information
+ op.Entry.Child = childInode
+ op.Entry.AttributesExpiration = expireTime()
+ op.Entry.EntryExpiration = expireTime()
+
+ return fs.fillAttributes(childInode, &op.Entry.Attributes)
+}
+
+func (fs AbstractFS) GetInodeAttributes(ctx context.Context, op *fuseops.GetInodeAttributesOp) error {
+ printer("GetInodeAttributes")
+
+ op.AttributesExpiration = expireTime()
+ return fs.fillAttributes(op.Inode, &op.Attributes)
+}
+
+func (fs AbstractFS) SetInodeAttributes(ctx context.Context, op *fuseops.SetInodeAttributesOp) error {
+ printer("SetInodeAttributes")
+ op.AttributesExpiration = expireTime()
+ e := fs.Manager.SetInfo(op.Inode, op.Uid, op.Gid, op.Size, op.Mode, op.Atime, op.Mtime)
+ if e != nil {
+ return e
+ }
+ return fs.fillAttributes(op.Inode, &op.Attributes)
+}
+
+// ForgetInode
+// todo account for references and hard links
+func (fs AbstractFS) ForgetInode(ctx context.Context, op *fuseops.ForgetInodeOp) error {
+ printer("ForgetInode")
+ return fs.Manager.Delete(op.Inode)
+}
+
+func (fs AbstractFS) BatchForget(ctx context.Context, op *fuseops.BatchForgetOp) error {
+ printer("BatchForget")
+ var e error
+ for _, entry := range op.Entries {
+ e = fs.Manager.Delete(entry.Inode)
+ if e != nil {
+ return e
+ }
+ }
+ return nil
+}
+
+func (fs AbstractFS) MkDir(ctx context.Context, op *fuseops.MkDirOp) error {
+ printer("MkDir")
+
+ // get parent information
+ info, e := fs.Manager.GetInfo(op.Parent)
+ if e != nil {
+ return e
+ }
+
+ // check if parent is a directory
+ if info.DirentType != fuseutil.DT_Directory {
+ return fuse.ENOTDIR
+ }
+
+ // already exists?
+ _, ok := info.ChildrenIndexMap[op.Name]
+ if ok {
+ return fuse.EEXIST
+ }
+
+ childInode, e := fs.Manager.MkDir(op.Parent, op.Name, op.Mode)
+ if e != nil {
+ return e
+ }
+
+ op.Entry.AttributesExpiration = expireTime()
+ op.Entry.EntryExpiration = expireTime()
+ op.Entry.Child = childInode
+ return fs.fillAttributes(childInode, &op.Entry.Attributes)
+}
+
+func (fs AbstractFS) CreateFile(ctx context.Context, op *fuseops.CreateFileOp) error {
+ printer("CreateFile")
+
+ // get parent information
+ info, e := fs.Manager.GetInfo(op.Parent)
+ if e != nil {
+ return e
+ }
+
+ // check if parent is a directory
+ if info.DirentType != fuseutil.DT_Directory {
+ return fuse.ENOTDIR
+ }
+
+ // already exists?
+ _, ok := info.ChildrenIndexMap[op.Name]
+ if ok {
+ return fuse.EEXIST
+ }
+
+ childInode, e := fs.Manager.CreateFile(op.Parent, op.Name, op.Mode)
+ if e != nil {
+ return e
+ }
+
+ op.Entry.AttributesExpiration = expireTime()
+ op.Entry.EntryExpiration = expireTime()
+ op.Entry.Child = childInode
+ op.Handle, e = fs.Manager.GenerateHandle(childInode)
+ if e != nil {
+ return e
+ }
+ return fs.fillAttributes(childInode, &op.Entry.Attributes)
+}
+
+func (fs AbstractFS) RmDir(ctx context.Context, op *fuseops.RmDirOp) error {
+ printer("RmDir")
+
+ info, e := fs.Manager.GetInfo(op.Parent)
+ if e != nil {
+ return e
+ }
+
+ if info.DirentType != fuseutil.DT_Directory {
+ return fuse.ENOTDIR
+ }
+
+ inode := info.Children[info.ChildrenIndexMap[op.Name]]
+ return fs.Manager.RmDir(inode)
+}
+
+func (fs AbstractFS) OpenDir(ctx context.Context, op *fuseops.OpenDirOp) error {
+ printer("OpenDir")
+ handle, e := fs.Manager.GenerateHandle(op.Inode)
+ if e != nil {
+ return e
+ }
+ op.Handle = handle
+ return nil
+}
+
+func (fs AbstractFS) ReadDir(ctx context.Context, op *fuseops.ReadDirOp) error {
+ printer("ReadDir")
+
+ info, e := fs.Manager.GetInfo(op.Inode)
+ if e != nil {
+ return e
+ }
+ if info.DirentType != fuseutil.DT_Directory {
+ return fuse.ENOTDIR
+ }
+ if info.Handle != op.Handle {
+ return fuse.ENOENT
+ }
+
+ printer(fmt.Sprintf("Path: %v\tOffset: %v\n", info.Path, op.Offset))
+
+ //if fuseops.DirOffset(len(data)) < op.Offset {
+ // return nil
+ //}
+
+ op.BytesRead = 0
+ bytesRead := 0
+ currentBytesRead := 0
+ buff := make([]byte, 1024)
+ for _, childInode := range info.Children {
+ dirent := fuseutil.Dirent{}
+ childInfo, e := fs.Manager.GetInfo(childInode)
+ if e != nil {
+ return e
+ }
+ dirent.Inode = childInfo.Inode
+ dirent.Name = childInfo.Name
+ dirent.Type = childInfo.DirentType
+ dirent.Offset = fuseops.DirOffset(bytesRead) // - op.Offset
+ currentBytesRead = fuseutil.WriteDirent(buff, dirent) //op.Dst[bytesRead:], dirent)
+ if bytesRead >= int(op.Offset) {
+ copy(op.Dst[op.BytesRead:], buff)
+ op.BytesRead += currentBytesRead
+ printer(fmt.Sprintf("Inode: %v\tName: %v\tOffset: %v\n", dirent.Inode, dirent.Name, dirent.Offset))
+ }
+ bytesRead += currentBytesRead
+ }
+
+ if int(op.Offset) >= bytesRead {
+ return nil
+ }
+
+ currentBytesRead = fuseutil.WriteDirent(op.Dst[op.BytesRead:], fuseutil.Dirent{
+ Offset: fuseops.DirOffset(bytesRead),
+ Name: ".",
+ Type: fuseutil.DT_Directory,
+ Inode: op.Inode,
+ })
+ bytesRead += currentBytesRead
+ op.BytesRead += currentBytesRead
+
+ // op.Dst = op.Dst[op.Offset:]
+ // op.BytesRead = bytesRead - int(op.Offset)
+
+ printer(fmt.Sprintf("Bytes Read: %v\n", op.BytesRead))
+
+ fmt.Println("done")
+
+ return nil
+}
+
+func (fs AbstractFS) ReleaseDirHandle(ctx context.Context, op *fuseops.ReleaseDirHandleOp) error {
+ printer("ReleaseDirHandle")
+
+ return fs.Manager.DeleteHandle(op.Handle)
+}
+
+func (fs AbstractFS) OpenFile(ctx context.Context, op *fuseops.OpenFileOp) error {
+ printer("OpenFile")
+ handle, e := fs.Manager.GenerateHandle(op.Inode)
+ if e != nil {
+ return e
+ }
+ op.Handle = handle
+ return nil
+}
+
+func (fs AbstractFS) ReadFile(ctx context.Context, op *fuseops.ReadFileOp) error {
+ printer("ReadFile")
+
+ info, e := fs.Manager.GetInfo(op.Inode)
+ if e != nil {
+ return e
+ }
+
+ if op.Handle != info.Handle {
+ return fuse.ENOENT
+ }
+
+ if op.Dst != nil {
+ buff := make([]byte, op.Size)
+ byteCount, _ := fs.Manager.ReadAt(op.Inode, buff, op.Offset)
+ /*if e != nil {
+ return e
+ }*/
+ op.BytesRead = int(minimum(int64(byteCount), op.Size))
+ for i := 0; i < op.BytesRead; i++ {
+ op.Dst[i] = buff[i] //append(op.Dst, buff[i])
+ }
+ printer(string(buff))
+ printer(fmt.Sprintf("read requested at offset: %v\tbytes read: %v", op.Offset, byteCount))
+ return nil
+ }
+
+ // todo implement vector read
+ fmt.Println("vector read requested")
+
+ return NoImplementationError{}
+}
+
+func (fs AbstractFS) WriteFile(ctx context.Context, op *fuseops.WriteFileOp) error {
+ printer("WriteFile")
+
+ info, e := fs.Manager.GetInfo(op.Inode)
+ if e != nil {
+ return e
+ }
+ if info.Handle != op.Handle {
+ return fuse.ENOENT
+ }
+
+ _, e = fs.Manager.WriteAt(op.Inode, op.Data, op.Offset)
+ if e != nil {
+ return e
+ }
+
+ return nil
+}
+
+func (fs AbstractFS) SyncFile(ctx context.Context, op *fuseops.SyncFileOp) error {
+ printer("SyncFile")
+
+ info, e := fs.Manager.GetInfo(op.Inode)
+ if e != nil {
+ return e
+ }
+ if info.Handle != op.Handle {
+ return fuse.ENOENT
+ }
+
+ return fs.Manager.SyncFile(op.Inode)
+}
+
+func (fs AbstractFS) FlushFile(ctx context.Context, op *fuseops.FlushFileOp) error {
+ printer("SyncFile")
+
+ info, e := fs.Manager.GetInfo(op.Inode)
+ if e != nil {
+ return e
+ }
+ if info.Handle != op.Handle {
+ return fuse.ENOENT
+ }
+
+ return fs.Manager.SyncFile(op.Inode)
+}
+
+func (fs AbstractFS) ReleaseFileHandle(ctx context.Context, op *fuseops.ReleaseFileHandleOp) error {
+ printer("ReleaseFileHandle")
+
+ return fs.Manager.DeleteHandle(op.Handle)
+}
+
+func (fs AbstractFS) Destroy() {
+ printer("Destroy")
+ fs.Manager.Destroy()
+ fuse.Unmount("./mount")
+}
diff --git a/mft-fs/archive/abstractfs/fs_manager.go b/mft-fs/archive/abstractfs/fs_manager.go
new file mode 100644
index 00000000..6d49f812
--- /dev/null
+++ b/mft-fs/archive/abstractfs/fs_manager.go
@@ -0,0 +1,298 @@
+/*
+Package abstractfs
+abstractfs is a FUSE-based filesystem wrapper
+it defines an interface for a filesystem manager, which can be implemented by any filesystem
+it implements FUSE operations which calls the respective methods of the filesystems
+*/
+package abstractfs
+
+import (
+ "github.com/jacobsa/fuse/fuseops"
+ "github.com/jacobsa/fuse/fuseutil"
+ "mft-fs/datastructures"
+ "os"
+ "time"
+)
+
+/*
+FSManager Interface
+the FSManager interface can be implemented by any custom filesystem
+its methods are used by the AbstractFS fuse server
+*/
+type FSManager interface {
+ /*
+ GetSize method to get the size of the filesystem
+ params: None
+ returns:
+ uint64: the size of the filesystem, in bytes
+ error: any error caused by the invocation
+ */
+ GetSize() (uint64, error)
+
+ /*
+ GetLength method for getting the length of the filesystem
+ params: None
+ returns:
+ uint64: the length of the filesystem (count the number of unique inodes)
+ error: any error caused by the invocation
+ */
+ GetLength() (uint64, error)
+
+ /*
+ GetInfo method for getting stats and metrics of a specific inode
+ params:
+ id fuseops.InodeID: the inode for which the information is required
+ returns:
+ *FileInfo: a reference to the FileInfo object which describes the inode's information
+ error: any error caused by the invocation
+ */
+ GetInfo(id fuseops.InodeID) (*FileInfo, error)
+
+ /*
+ SetInfo method for setting or modifying an inode's attributes
+ params:
+ id fuseops.InodeID: the inode in question
+ uidptr *uint32: a pointer to the new UserID for the inode's ownership; if no change is desired, pass nil
+ gidptr *uint32: a pointer to the new GroupID for the inode's ownership; if no change is desired, pass nil
+ sizeptr *uint64: a pointer to the new size of the inode (in bytes); if no change is desired, pass nil
+ modeptr *os.FileMode: a pointer to the new filemode of the inode; if no change is desired, pass nil
+ atimeptr *time.Time: a pointer to the new access time of the inode; if no change is desired, pass nil
+ mtimeptr *time.Time: a pointer to the new modification time of the inode; if no change is desired, pass nil
+ returns:
+ error: any error caused by the invocation
+ */
+ SetInfo(id fuseops.InodeID, uidptr *uint32, gidptr *uint32, sizeptr *uint64, modeptr *os.FileMode, atimeptr *time.Time, mtimeptr *time.Time) error
+
+ /*
+ Delete method for deleting an inode from the filesystem entirely
+ params:
+ inode fuseops.InodeID: the inode to be deleted
+ returns:
+ error: any error caused by the invocation
+ */
+ Delete(inode fuseops.InodeID) error
+
+ /*
+ MkDir method for creating a directory
+ params:
+ parent fuseops.InodeID: inode of the parent directory
+ name string: name of the directory to be created
+ mode os.FileMode: mode to set permissions for the new directory
+ returns:
+ fuseops.InodeID: the inode of the new directory
+ error: any error caused by the invocation
+ */
+ MkDir(parent fuseops.InodeID, name string, mode os.FileMode) (fuseops.InodeID, error)
+
+ /*
+ GenerateHandle method for creating a handle for a certain inode
+ params:
+ id fuseops.InodeID: the inode for which the handle is being created
+ returns:
+ fuseops.HandleID: the handle generated
+ error: any error caused by the invocation
+ */
+ GenerateHandle(id fuseops.InodeID) (fuseops.HandleID, error)
+
+ /*
+ CreateFile method to create a new file
+ params:
+ parent fuseops.InodeID: inode of the parent directory
+ name string: name of the file to be created
+ mode os.FileMode: mode to set permissions for the new file
+ returns:
+ fuseops.InodeID: the inode of the newly created file
+ error: any error caused by the invocation
+ */
+ CreateFile(parent fuseops.InodeID, name string, mode os.FileMode) (fuseops.InodeID, error)
+
+ /*
+ RmDir method for removing a directory
+ params:
+ inode fuseops.InodeID: inode of the directory being deleted
+ returns:
+ error: any error caused by the invocation
+ */
+ RmDir(inode fuseops.InodeID) error
+
+ /*
+ DeleteHandle method for deleting a handle which had been created previously
+ params:
+ handle fuseops.HandleID: the handle being deleted
+ return:
+ error: any error caused by the invocation
+ */
+ DeleteHandle(handle fuseops.HandleID) error
+
+ /*
+ SyncFile method for syncing a file
+ params:
+ inode fuseops.InodeID: inode of the file being synced
+ returns:
+ error: any error caused by the invocation
+ */
+ SyncFile(inode fuseops.InodeID) error
+
+ /*
+ WriteAt method for writing data to a file at a specific offset
+ params:
+ inode fuseops.InodeID: the inode of the file being written to
+ data []byte: the bytes being written in
+ off int64: the offset of the location to write to
+ returns:
+ n int: the number of bytes written
+ err error: any error caused by the invocation
+ */
+ WriteAt(inode fuseops.InodeID, data []byte, off int64) (n int, err error)
+
+ /*
+ ReadAt method for reading from a file at a specific offset
+ params:
+ inode fuseops.InodeID: the inode of the file being read from
+ data []byte: the buffer to store all data being read into
+ off int64: the offset of the location to read from
+ returns:
+ n int: the number of bytes read
+ err error: any error caused by the invocation
+ */
+ ReadAt(inode fuseops.InodeID, data []byte, off int64) (n int, err error)
+
+ /*
+ Destroy method for destroying a filesystem
+ params: None
+ returns:
+ error: any error caused by the invocation
+ */
+ Destroy() error
+}
+
+/*
+FileInfo struct for representing a file's information
+*/
+type FileInfo struct {
+ // name of the file/directory
+ Name string
+
+ // path to the file/directory
+ Path string
+
+ // inode of the file/directory
+ Inode fuseops.InodeID
+
+ // if it is a directory, a slice with inodes of all children
+ Children []fuseops.InodeID
+
+ // if it is a directory, a map: name of child -> index of child in Children slice
+ ChildrenIndexMap map[string]int
+
+ // inode of the parent directory
+ Parent fuseops.InodeID
+
+ // if it is a file, the number of links
+ Nlink uint32
+
+ // size of the file/directory
+ Size uint64
+
+ // the mode of the file/directory
+ Mode os.FileMode
+
+ // access time of the file/directory
+ Atime time.Time
+
+ // modification time of the file/directory
+ Mtime time.Time
+
+ // creation time of the file/directory
+ Ctime time.Time
+
+ // creation time of the file/directory
+ Crtime time.Time
+
+ // user id of the file/directory ownership
+ Uid uint32
+
+ // group id of the file/directory ownership
+ Gid uint32
+
+ // dirent type (file, directory, other)
+ DirentType fuseutil.DirentType
+
+ // handle to the file/directory
+ Handle fuseops.HandleID
+
+ // boolean variable to assess whether file has been cached locally
+ Cache bool
+
+ // time the variable was downloaded to the local cache
+ CacheTime time.Time
+
+ // time the metadata of the file was modified
+ MetadataWriteTime time.Time
+
+ // time the content of the file was modified
+ ContentWriteTime time.Time
+
+ // CREW lock for metadata
+ MetadataLock *datastructures.CREWResource
+
+ // CREW lock for content
+ ContentLock *datastructures.CREWResource
+}
+
+/*
+NewFileInfo method to create a new FileInfo
+*/
+func NewFileInfo(name string, path string, inode fuseops.InodeID, parent fuseops.InodeID, direntType fuseutil.DirentType) FileInfo {
+ return FileInfo{
+ Name: name,
+ Children: make([]fuseops.InodeID, 0),
+ ChildrenIndexMap: make(map[string]int),
+ Parent: parent,
+ Inode: inode,
+ Path: path,
+ DirentType: direntType,
+ Cache: false,
+ CacheTime: time.Unix(0, 0),
+ ContentWriteTime: time.Now(),
+ }
+}
+
+/*
+NewSafeFileInfo method to create a new FileInfo
+ - also initializes CREW locks
+*/
+func NewSafeFileInfo(name string, path string, inode fuseops.InodeID, parent fuseops.InodeID, direntType fuseutil.DirentType) FileInfo {
+ return FileInfo{
+ Name: name,
+ Children: make([]fuseops.InodeID, 0),
+ ChildrenIndexMap: make(map[string]int),
+ Parent: parent,
+ Inode: inode,
+ Path: path,
+ DirentType: direntType,
+ Cache: false,
+ CacheTime: time.Unix(0, 0),
+ ContentWriteTime: time.Now(),
+ MetadataWriteTime: time.Now(),
+ ContentLock: datastructures.NewCREWResource(),
+ MetadataLock: datastructures.NewCREWResource(),
+ }
+}
+
+/**
+TODO
+ - implement caching
+ - read/write request
+ - request contains cacheBool and cacheTime
+ - permission granted for read iff cache is invalid
+ - permission granted for write iff cache is valid
+ - read/write ack
+ - send inode in request
+ - return new writecontent time
+ - implement local handles
+ - implement thread safety
+ - metadata updates
+ - content updates
+ - read, write, acks for metadata and content
+*/
diff --git a/mft-fs/archive/basicfs/basic_fs.go b/mft-fs/archive/basicfs/basic_fs.go
new file mode 100644
index 00000000..3733bb6e
--- /dev/null
+++ b/mft-fs/archive/basicfs/basic_fs.go
@@ -0,0 +1,1054 @@
+package basicfs
+
+import (
+ "context"
+ "crypto/rand"
+ "fmt"
+ "golang.org/x/sys/unix"
+ "os"
+ "syscall"
+ "time"
+
+ "mft-fs/datastructures"
+
+ "github.com/jacobsa/fuse"
+ "github.com/jacobsa/fuse/fuseops"
+ "github.com/jacobsa/fuse/fuseutil"
+)
+
+type NoImplementationError struct{}
+
+func (e NoImplementationError) Error() string {
+ return "No implementation"
+}
+
+/*
+The printer function prints messages to the terminal on behalf of FUSE operations.
+*/
+func printer(message string) {
+ fmt.Println(message)
+
+ /*file, _ := os.OpenFile("log.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
+ defer file.Close()
+ file.WriteString(fmt.Sprintf("%s\n", message))*/
+}
+
+func expireTime() time.Time {
+ return time.Now().Add(time.Minute)
+}
+
+func minimum(a int64, b int64) int64 {
+ if a < b {
+ return a
+ }
+ return b
+}
+
+type BasicFS struct {
+ fuseutil.NotImplementedFileSystem
+ root string
+ // pathToInode map[string]fuseops.InodeID
+ inodeToPath map[fuseops.InodeID]string
+ handleToInode map[fuseops.HandleID]fuseops.InodeID
+}
+
+/*
+todo:
+ OS Operations: MkNode, SetINodeAttrs
+ Dir Operations:
+ File Operations: ReadSymLink, CreateSymLink, CreateLink, Unlink
+ Correctness
+ - atomicity checks
+ - sync vs flush
+ - buffer writing
+ Optimizations:
+ - update map when appropriate (mkdir, createfile, rmdir, etc.)
+ - store tree backing
+ - explore caching strategies
+*/
+
+// private helpers
+
+func (fs BasicFS) update() error {
+ q := datastructures.NewQueue()
+ q.Enqueue(fs.root)
+ for !q.IsEmpty() {
+ path := q.Dequeue().(string)
+ fileInfo, e := os.Stat(path)
+ if e != nil {
+ return e
+ }
+ inode := fileInfo.Sys().(*syscall.Stat_t).Ino
+ fs.inodeToPath[fuseops.InodeID(inode)] = path
+ if fileInfo.IsDir() {
+ files, e := os.ReadDir(path)
+ if e != nil {
+ return e
+ }
+ for _, file := range files {
+ q.Enqueue(path + "/" + file.Name())
+ }
+ }
+ }
+ return nil
+}
+
+func (fs BasicFS) fillAttributes(path string, attributes *fuseops.InodeAttributes) error {
+
+ fileInfo, e := os.Stat(path)
+ if e != nil {
+ return e
+ }
+ stats := fileInfo.Sys().(*syscall.Stat_t)
+
+ attributes.Size = uint64(fileInfo.Size())
+
+ attributes.Nlink = 1
+
+ attributes.Mode = fileInfo.Mode()
+
+ var timeStats unix.Stat_t
+ e = unix.Stat(path, &timeStats)
+ if e != nil {
+ return e
+ }
+
+ /*attributes.Atime = time.Unix(stats.Atimespec.Sec, stats.Atimespec.Nsec)
+ attributes.Mtime = time.Unix(stats.Mtimespec.Sec, stats.Mtimespec.Nsec)
+ attributes.Ctime = time.Unix(stats.Ctimespec.Sec, stats.Ctimespec.Nsec)
+ attributes.Crtime = time.Unix(stats.Birthtimespec.Sec, stats.Birthtimespec.Nsec)*/
+ attributes.Atime = time.Unix(timeStats.Atim.Sec, timeStats.Atim.Nsec)
+ attributes.Mtime = time.Unix(timeStats.Mtim.Sec, timeStats.Mtim.Nsec)
+ attributes.Ctime = time.Unix(timeStats.Ctim.Sec, timeStats.Ctim.Nsec)
+ attributes.Crtime = time.Unix(timeStats.Ctim.Sec, timeStats.Ctim.Nsec)
+
+ attributes.Uid = stats.Uid
+ attributes.Gid = stats.Gid
+
+ return nil
+}
+
+func (fs BasicFS) generateHandle(inode fuseops.InodeID) (fuseops.HandleID, error) {
+ var buff [8]byte
+ _, e := rand.Read(buff[:])
+ if e != nil {
+ return 0, e
+ }
+ var output uint64 = 0
+ for i := 0; i < len(buff); i++ {
+ output = output | uint64(buff[i]<<(8*i))
+ }
+ handle := fuseops.HandleID(output)
+ _, ok := fs.handleToInode[handle]
+ if ok {
+ return fs.generateHandle(inode)
+ }
+ fs.handleToInode[handle] = inode
+ return handle, nil
+}
+
+// Public BasicFS specific methods
+
+func NewBasicFS(root string) (BasicFS, error) {
+ fs := BasicFS{
+ root: root,
+ // pathToInode: make(map[string]fuseops.InodeID),
+ inodeToPath: make(map[fuseops.InodeID]string),
+ handleToInode: make(map[fuseops.HandleID]fuseops.InodeID),
+ }
+ fs.inodeToPath[1] = fs.root
+ e := fs.update()
+ return fs, e
+}
+
+// FUSE Operations Implementation
+
+func (fs BasicFS) StatFS(ctx context.Context, op *fuseops.StatFSOp) error {
+ printer("StatFS")
+
+ stat, _ := os.Stat(fs.root)
+
+ op.BlockSize = 4096
+
+ op.Blocks = 64
+ op.BlocksFree = uint64(64 - uint32(stat.Size())/op.BlockSize)
+ op.BlocksAvailable = op.BlocksFree
+
+ op.IoSize = 4096
+
+ op.Inodes = 128
+ op.InodesFree = op.Inodes - uint64(len(fs.inodeToPath))
+
+ return nil
+}
+
+func (fs BasicFS) LookUpInode(ctx context.Context, op *fuseops.LookUpInodeOp) error {
+ printer("LookUpInode")
+ var path string
+ var ok bool
+ // find parent
+ if op.Parent == 1 {
+ path = fs.root
+ } else {
+ path, ok = fs.inodeToPath[op.Parent]
+ if !ok {
+ e := fs.update()
+ if e != nil {
+ return e
+ }
+ path, ok = fs.inodeToPath[op.Parent]
+ // if parent does not exist
+ if !ok {
+ return fuse.ENOENT // FileDoesNotExistError{}
+ }
+ }
+ }
+
+ // get parent information
+ fileInfo, e := os.Stat(path)
+ if e != nil {
+ return e
+ }
+ // if parent is not a directory
+ if !fileInfo.IsDir() {
+ return fuse.ENOTDIR // not a directory error
+ }
+
+ // get child information
+ fileInfo, e = os.Stat(path + "/" + op.Name)
+
+ if e != nil {
+ // if child does not exist, return without updating op contents
+ return nil
+ }
+
+ // if child exists, update op contents
+ stat := fileInfo.Sys().(*syscall.Stat_t)
+
+ op.Entry.EntryExpiration = expireTime()
+ op.Entry.AttributesExpiration = expireTime()
+
+ op.Entry.Child = fuseops.InodeID(stat.Ino)
+
+ return fs.fillAttributes(path+"/"+op.Name, &op.Entry.Attributes)
+}
+
+func (fs BasicFS) GetInodeAttributes(ctx context.Context, op *fuseops.GetInodeAttributesOp) error {
+ printer("GetInodeAttributes")
+ var path string
+ var ok bool
+ if op.Inode == 1 {
+ path = fs.root
+ } else {
+ path, ok = fs.inodeToPath[op.Inode]
+ if !ok {
+ e := fs.update()
+ if e != nil {
+ return e
+ }
+ path, ok = fs.inodeToPath[op.Inode]
+ if !ok {
+ return fuse.ENOENT
+ }
+ }
+ }
+
+ op.AttributesExpiration = expireTime()
+ return fs.fillAttributes(path, &op.Attributes)
+}
+
+func (fs BasicFS) SetInodeAttributes(ctx context.Context, op *fuseops.SetInodeAttributesOp) error {
+ printer("SetInodeAttributes")
+
+ var path string
+ var ok bool
+
+ if op.Inode == 1 {
+ path = fs.root
+ } else {
+ path, ok = fs.inodeToPath[op.Inode]
+ if !ok {
+ e := fs.update()
+ if e != nil {
+ return e
+ }
+ path, ok = fs.inodeToPath[op.Inode]
+ if !ok {
+ return fuse.ENOENT
+ }
+ }
+
+ }
+
+ var e error
+
+ if op.Mode != nil {
+ e = os.Chmod(path, *op.Mode)
+ if e != nil {
+ return e
+ }
+ }
+
+ uid := -1
+ gid := -1
+ if op.Uid != nil {
+ uid = int(*op.Uid)
+ }
+ if op.Gid != nil {
+ gid = int(*op.Gid)
+ }
+ e = os.Chown(path, uid, gid)
+ if e != nil {
+ return e
+ }
+
+ atime := time.Time{}
+ mtime := time.Time{}
+ if op.Atime != nil {
+ atime = *op.Atime
+ }
+ if op.Mtime != nil {
+ mtime = *op.Mtime
+ }
+ e = os.Chtimes(path, atime, mtime)
+ if e != nil {
+ return e
+ }
+
+ e = fs.fillAttributes(path, &op.Attributes)
+ if e != nil {
+ return e
+ }
+
+ op.AttributesExpiration = expireTime()
+
+ return nil
+}
+
+// ForgetInode
+// todo account for references and hard links
+func (fs BasicFS) ForgetInode(ctx context.Context, op *fuseops.ForgetInodeOp) error {
+ printer("ForgetInode")
+ delete(fs.inodeToPath, op.Inode)
+ return nil
+}
+
+func (fs BasicFS) BatchForget(ctx context.Context, op *fuseops.BatchForgetOp) error {
+ printer("BatchForget")
+ for _, entry := range op.Entries {
+ delete(fs.inodeToPath, entry.Inode)
+ }
+ return nil
+}
+
+func (fs BasicFS) MkDir(ctx context.Context, op *fuseops.MkDirOp) error {
+ printer("MkDir")
+
+ var path string
+ var ok bool
+ // find parent
+ if op.Parent == 1 {
+ path = fs.root
+ } else {
+ path, ok = fs.inodeToPath[op.Parent]
+ if !ok {
+ e := fs.update()
+ if e != nil {
+ return e
+ }
+ path, ok = fs.inodeToPath[op.Parent]
+ // if parent does not exist
+ if !ok {
+ return fuse.ENOENT
+ }
+ }
+ }
+
+ // get parent information
+ fileInfo, e := os.Stat(path)
+ if e != nil {
+ return e
+ }
+ // if parent is not a directory
+ if !fileInfo.IsDir() {
+ return fuse.ENOTDIR
+ }
+
+ childPath := path + "/" + op.Name
+ e = os.Mkdir(childPath, op.Mode)
+ switch e.(type) {
+ case nil:
+ break
+ case *os.PathError:
+ return fuse.EEXIST
+ default:
+ return e
+ }
+
+ fileInfo, e = os.Stat(childPath)
+ if e != nil {
+ return e
+ }
+
+ op.Entry.Child = fuseops.InodeID(fileInfo.Sys().(*syscall.Stat_t).Ino)
+ op.Entry.AttributesExpiration = expireTime()
+ op.Entry.EntryExpiration = expireTime()
+
+ return fs.fillAttributes(childPath, &op.Entry.Attributes)
+}
+
+//func (fs BasicFS) MkNode(ctx context.Context, op *fuseops.MkNodeOp) error {
+// printer("MkNode")
+// return NoImplementationError{}
+//}
+
+func (fs BasicFS) CreateFile(ctx context.Context, op *fuseops.CreateFileOp) error {
+ printer("CreateFile")
+
+ var path string
+ var ok bool
+ // find parent
+ if op.Parent == 1 {
+ path = fs.root
+ } else {
+ path, ok = fs.inodeToPath[op.Parent]
+ if !ok {
+ e := fs.update()
+ if e != nil {
+ return e
+ }
+ path, ok = fs.inodeToPath[op.Parent]
+ // if parent does not exist
+ if !ok {
+ return fuse.ENOENT
+ }
+ }
+ }
+
+ // get parent information
+ fileInfo, e := os.Stat(path)
+ if e != nil {
+ return e
+ }
+ // if parent is not a directory
+ if !fileInfo.IsDir() {
+ return fuse.ENOTDIR // not a directory error
+ }
+
+ childPath := path + "/" + op.Name
+ var file *os.File
+ file, e = os.Create(childPath)
+ defer file.Close()
+ switch e.(type) {
+ case nil:
+ break
+ case *os.PathError:
+ return fuse.EEXIST
+ default:
+ return e
+ }
+ e = file.Chmod(op.Mode)
+ if e != nil {
+ return e
+ }
+
+ fileInfo, e = os.Stat(childPath)
+ if e != nil {
+ return e
+ }
+
+ op.Entry.Child = fuseops.InodeID(fileInfo.Sys().(*syscall.Stat_t).Ino)
+ op.Entry.AttributesExpiration = expireTime()
+ op.Entry.EntryExpiration = expireTime()
+
+ var handle fuseops.HandleID
+ handle, e = fs.generateHandle(op.Entry.Child)
+ if e != nil {
+ return e
+ }
+ op.Handle = handle
+
+ return fs.fillAttributes(childPath, &op.Entry.Attributes)
+}
+
+//func (fs BasicFS) CreateLink(ctx context.Context, op *fuseops.CreateLinkOp) error {
+// printer("CreateLink")
+// return NoImplementationError{}
+//}
+//
+//func (fs BasicFS) CreateSymlink(ctx context.Context, op *fuseops.CreateSymlinkOp) error {
+// printer("CreateSymlink")
+// return NoImplementationError{}
+//}
+
+// Rename
+//todo: verify atomicity requirements
+/*
+If the new name is an existing directory, the file system must ensure it is empty before replacing it, returning ENOTEMPTY otherwise. (This is per the posix spec: http://goo.gl/4XtT79)
+
+The rename must be atomic from the point of view of an observer of the new name. That is, if the new name already exists, there must be no point at which it doesn't exist.
+
+It is okay for the new name to be modified before the old name is removed; these need not be atomic. In fact, the Linux man page explicitly says this is likely (cf. https://goo.gl/Y1wVZc).
+
+Linux bends over backwards (https://goo.gl/pLDn3r) to ensure that neither the old nor the new parent can be concurrently modified. But it's not clear whether OS X does this, and in any case it doesn't matter for file systems that may be modified remotely. Therefore a careful file system implementor should probably ensure if possible that the unlink step in the "link new name, unlink old name" process doesn't unlink a different inode than the one that was linked to the new name. Still, posix and the man pages are imprecise about the actual semantics of a rename if it's not atomic, so it is probably not disastrous to be loose about this.
+*/
+func (fs BasicFS) Rename(ctx context.Context, op *fuseops.RenameOp) error {
+ printer("Rename")
+
+ e := fs.update()
+ if e != nil {
+ return e
+ }
+
+ var path string
+ var newPath string
+ var oldPath string
+ var ok bool
+
+ path, ok = fs.inodeToPath[op.OldParent]
+ if !ok {
+ return fuse.ENOENT
+ }
+ oldPath = path + "/" + op.OldName
+
+ path, ok = fs.inodeToPath[op.NewParent]
+ if ok {
+ newPath = path + "/" + op.NewName
+ fileInfo, e := os.Stat(path)
+ if e == nil && fileInfo.IsDir() {
+ files, e := os.ReadDir(newPath)
+ if e != nil {
+ return e
+ }
+ if len(files) > 0 {
+ return fuse.ENOTEMPTY
+ }
+ }
+ }
+
+ return os.Rename(oldPath, newPath)
+}
+
+func (fs BasicFS) RmDir(ctx context.Context, op *fuseops.RmDirOp) error {
+ printer("RmDir")
+
+ var path string
+ var ok bool
+
+ path, ok = fs.inodeToPath[op.Parent]
+ if !ok {
+ e := fs.update()
+ if e != nil {
+ return e
+ }
+ path, ok = fs.inodeToPath[op.Parent]
+ if !ok {
+ return fuse.ENOENT
+ }
+ }
+
+ path = path + "/" + op.Name
+ return os.RemoveAll(path)
+}
+
+//func (fs BasicFS) Unlink(ctx context.Context, op *fuseops.UnlinkOp) error {
+// printer("Unlink")
+// return NoImplementationError{}
+//}
+
+func (fs BasicFS) OpenDir(ctx context.Context, op *fuseops.OpenDirOp) error {
+ printer("OpenDir")
+ var ok bool
+ _, ok = fs.inodeToPath[op.Inode]
+ if !ok && op.Inode != 1 {
+ e := fs.update()
+ if e != nil {
+ return e
+ }
+ _, ok = fs.inodeToPath[op.Inode]
+ if !ok {
+ return fuse.ENOENT
+ }
+ }
+ handle, e := fs.generateHandle(op.Inode)
+ if e != nil {
+ return e
+ }
+ op.Handle = handle
+ return nil
+}
+
+// todo: handle offsets (see ReadDirOp documentation)
+func (fs BasicFS) ReadDir(ctx context.Context, op *fuseops.ReadDirOp) error {
+ printer("ReadDir")
+
+ var path string
+ var ok bool
+ if op.Inode == 1 {
+ path = fs.root
+ } else {
+ path, ok = fs.inodeToPath[op.Inode]
+ if !ok {
+ e := fs.update()
+ if e != nil {
+ return e
+ }
+ path, ok = fs.inodeToPath[op.Inode]
+ if !ok {
+ return fuse.ENOENT
+ }
+ }
+ }
+ var inode fuseops.InodeID
+ inode, ok = fs.handleToInode[op.Handle]
+ if !ok || inode != op.Inode {
+ return fuse.ENOENT
+ }
+
+ fileInfo, e := os.Stat(path)
+ if e != nil {
+ return e
+ }
+ if !fileInfo.IsDir() {
+ return fuse.ENOTDIR
+ }
+
+ data, e := os.ReadDir(path)
+ if e != nil {
+ return e
+ }
+
+ printer(fmt.Sprintf("Path: %v\tOffset: %v\n", path, op.Offset))
+
+ //if fuseops.DirOffset(len(data)) < op.Offset {
+ // return nil
+ //}
+
+ op.BytesRead = 0
+ bytesRead := 0
+ currentBytesRead := 0
+ buff := make([]byte, 1024)
+ for _, d := range data {
+ dirent := fuseutil.Dirent{}
+ fileInfo, e := d.Info()
+ if e != nil {
+ return e
+ }
+ dirent.Inode = fuseops.InodeID(fileInfo.Sys().(*syscall.Stat_t).Ino)
+ dirent.Name = d.Name()
+ if fileInfo.IsDir() {
+ dirent.Type = fuseutil.DT_Directory
+ } else {
+ dirent.Type = fuseutil.DT_File
+ }
+ dirent.Offset = fuseops.DirOffset(bytesRead) // - op.Offset
+ currentBytesRead = fuseutil.WriteDirent(buff, dirent) //op.Dst[bytesRead:], dirent)
+ if bytesRead >= int(op.Offset) {
+ copy(op.Dst[op.BytesRead:], buff)
+ op.BytesRead += currentBytesRead
+ printer(fmt.Sprintf("Inode: %v\tName: %v\tOffset: %v\n", dirent.Inode, dirent.Name, dirent.Offset))
+ }
+ bytesRead += currentBytesRead
+ }
+
+ if int(op.Offset) >= bytesRead {
+ return nil
+ }
+
+ currentBytesRead = fuseutil.WriteDirent(op.Dst[op.BytesRead:], fuseutil.Dirent{
+ Offset: fuseops.DirOffset(bytesRead),
+ Name: ".",
+ Type: fuseutil.DT_Directory,
+ Inode: inode,
+ })
+ bytesRead += currentBytesRead
+ op.BytesRead += currentBytesRead
+
+ // op.Dst = op.Dst[op.Offset:]
+ // op.BytesRead = bytesRead - int(op.Offset)
+
+ printer(fmt.Sprintf("Bytes Read: %v\n", op.BytesRead))
+
+ fmt.Println("done")
+
+ return nil
+}
+
+func (fs BasicFS) ReleaseDirHandle(ctx context.Context, op *fuseops.ReleaseDirHandleOp) error {
+ printer("ReleaseDirHandle")
+
+ delete(fs.handleToInode, op.Handle)
+
+ return nil
+}
+
+func (fs BasicFS) OpenFile(ctx context.Context, op *fuseops.OpenFileOp) error {
+ printer("OpenFile")
+ var ok bool
+ _, ok = fs.inodeToPath[op.Inode]
+ if !ok && op.Inode != 1 {
+ e := fs.update()
+ if e != nil {
+ return e
+ }
+ _, ok = fs.inodeToPath[op.Inode]
+ if !ok {
+ return fuse.ENOENT
+ }
+ }
+ handle, e := fs.generateHandle(op.Inode)
+ if e != nil {
+ return e
+ }
+ op.Handle = handle
+ return nil
+}
+
+func (fs BasicFS) ReadFile(ctx context.Context, op *fuseops.ReadFileOp) error {
+ printer("ReadFile")
+
+ var path string
+ var ok bool
+ path, ok = fs.inodeToPath[op.Inode]
+ if !ok {
+ e := fs.update()
+ if e != nil {
+ return e
+ }
+ path, ok = fs.inodeToPath[op.Inode]
+ if !ok {
+ return fuse.ENOENT
+ }
+ }
+ var inode fuseops.InodeID
+ inode, ok = fs.handleToInode[op.Handle]
+ if !ok || inode != op.Inode {
+ return fuse.ENOENT
+ }
+
+ fileInfo, e := os.Stat(path)
+ if e != nil {
+ return e
+ }
+ var file *os.File
+ file, e = os.OpenFile(path, os.O_RDWR, fileInfo.Mode())
+ defer file.Close()
+ if e != nil {
+ return e
+ }
+
+ if op.Dst != nil {
+ buff := make([]byte, op.Size)
+ byteCount, _ := file.ReadAt(buff, op.Offset)
+ /*if e != nil {
+ fmt.Println("got an error")
+ fmt.Println(fmt.Sprintf("read requested for: %v, at offset: %v", path, op.Offset))
+ return e
+ }*/
+ op.BytesRead = int(minimum(int64(byteCount), op.Size))
+ for i := 0; i < op.BytesRead; i++ {
+ op.Dst[i] = buff[i] //append(op.Dst, buff[i])
+ }
+ printer(string(buff))
+ printer(fmt.Sprintf("read requested at offset: %v\tbytes read: %v", op.Offset, byteCount))
+ return nil
+ }
+
+ fmt.Println("vector read requested")
+
+ return NoImplementationError{}
+}
+
+func (fs BasicFS) WriteFile(ctx context.Context, op *fuseops.WriteFileOp) error {
+ printer("WriteFile")
+
+ var path string
+ var ok bool
+ path, ok = fs.inodeToPath[op.Inode]
+ if !ok {
+ e := fs.update()
+ if e != nil {
+ return e
+ }
+ path, ok = fs.inodeToPath[op.Inode]
+ if !ok {
+ return fuse.ENOENT
+ }
+ }
+ var inode fuseops.InodeID
+ inode, ok = fs.handleToInode[op.Handle]
+ if !ok || inode != op.Inode {
+ return fuse.ENOENT
+ }
+
+ fileInfo, e := os.Stat(path)
+ if e != nil {
+ return e
+ }
+ var file *os.File
+ file, e = os.OpenFile(path, os.O_RDWR, fileInfo.Mode())
+ defer file.Close()
+ if e != nil {
+ return e
+ }
+
+ _, e = file.WriteAt(op.Data, op.Offset)
+ if e != nil {
+ return e
+ }
+
+ return nil
+}
+
+func (fs BasicFS) SyncFile(ctx context.Context, op *fuseops.SyncFileOp) error {
+ printer("SyncFile")
+
+ var path string
+ var ok bool
+
+ if op.Inode == 1 {
+ path = fs.root
+ } else {
+ path, ok = fs.inodeToPath[op.Inode]
+ if !ok {
+ e := fs.update()
+ if e != nil {
+ return e
+ }
+ }
+ path, ok = fs.inodeToPath[op.Inode]
+ if !ok {
+ return fuse.ENOENT
+ }
+ }
+
+ if fs.handleToInode[op.Handle] != op.Inode {
+ return fuse.ENOENT
+ }
+
+ fileInfo, e := os.Stat(path)
+ if e != nil {
+ return e
+ }
+ file, e := os.OpenFile(path, os.O_RDWR, fileInfo.Mode())
+ defer file.Close()
+ if e != nil {
+ return e
+ }
+
+ e = file.Sync()
+ if e != nil {
+ return e
+ }
+
+ return nil
+}
+
+func (fs BasicFS) FlushFile(ctx context.Context, op *fuseops.FlushFileOp) error {
+ printer("FlushFile")
+
+ var path string
+ var ok bool
+
+ if op.Inode == 1 {
+ path = fs.root
+ } else {
+ path, ok = fs.inodeToPath[op.Inode]
+ if !ok {
+ e := fs.update()
+ if e != nil {
+ return e
+ }
+ }
+ path, ok = fs.inodeToPath[op.Inode]
+ if !ok {
+ return fuse.ENOENT
+ }
+ }
+
+ if fs.handleToInode[op.Handle] != op.Inode {
+ return fuse.ENOENT
+ }
+
+ fileInfo, e := os.Stat(path)
+ if e != nil {
+ return e
+ }
+ file, e := os.OpenFile(path, os.O_RDWR, fileInfo.Mode())
+ defer file.Close()
+ if e != nil {
+ return e
+ }
+
+ e = file.Sync()
+ if e != nil {
+ return e
+ }
+
+ return nil
+}
+
+func (fs BasicFS) ReleaseFileHandle(ctx context.Context, op *fuseops.ReleaseFileHandleOp) error {
+ printer("ReleaseFileHandle")
+
+ delete(fs.handleToInode, op.Handle)
+
+ return nil
+}
+
+//func (fs BasicFS) ReadSymlink(ctx context.Context, op *fuseops.ReadSymlinkOp) error {
+// printer("ReadSymLink")
+// return NoImplementationError{}
+//}
+
+/*
+func (fs BasicFS) RemoveXattr(ctx context.Context, op *fuseops.RemoveXattrOp) error {
+ printer("RemoveXattr")
+
+ var path string
+ var ok bool
+
+ if op.Inode == 1 {
+ path = fs.root
+ } else {
+ path, ok = fs.inodeToPath[op.Inode]
+ if !ok {
+ e := fs.update()
+ if e != nil {
+ return e
+ }
+ }
+ path, ok = fs.inodeToPath[op.Inode]
+ if !ok {
+ return fuse.ENOENT
+ }
+ }
+
+ e := xattr.Remove(path, op.Name)
+ if e != nil {
+ return fuse.ENOATTR
+ }
+
+ return nil
+}
+
+func (fs BasicFS) GetXattr(ctx context.Context, op *fuseops.GetXattrOp) error {
+ printer("GetXattr")
+
+ var path string
+ var ok bool
+
+ if op.Inode == 1 {
+ path = fs.root
+ } else {
+ path, ok = fs.inodeToPath[op.Inode]
+ if !ok {
+ e := fs.update()
+ if e != nil {
+ return e
+ }
+ }
+ path, ok = fs.inodeToPath[op.Inode]
+ if !ok {
+ return fuse.ENOENT
+ }
+ }
+
+ val, e := xattr.Get(path, op.Name)
+ if e != nil {
+ return fuse.ENOATTR
+ }
+
+ op.Dst = val
+ op.BytesRead = len(val)
+
+ return nil
+}
+
+func (fs BasicFS) ListXattr(ctx context.Context, op *fuseops.ListXattrOp) error {
+ printer("ListXattr")
+
+ var path string
+ var ok bool
+
+ if op.Inode == 1 {
+ path = fs.root
+ } else {
+ path, ok = fs.inodeToPath[op.Inode]
+ if !ok {
+ e := fs.update()
+ if e != nil {
+ return e
+ }
+ }
+ path, ok = fs.inodeToPath[op.Inode]
+ if !ok {
+ return fuse.ENOENT
+ }
+ }
+
+ val, e := xattr.List(path)
+ if e != nil {
+ return e
+ }
+
+ var output []byte
+ for _, v := range val {
+ output = append(output, []byte(v)...)
+ output = append(output, 0)
+ }
+
+ op.Dst = output
+ op.BytesRead = len(output)
+
+ return nil
+}
+
+func (fs BasicFS) SetXattr(ctx context.Context, op *fuseops.SetXattrOp) error {
+ printer("SetXattr")
+
+ var path string
+ var ok bool
+
+ if op.Inode == 1 {
+ path = fs.root
+ } else {
+ path, ok = fs.inodeToPath[op.Inode]
+ if !ok {
+ e := fs.update()
+ if e != nil {
+ return e
+ }
+ }
+ path, ok = fs.inodeToPath[op.Inode]
+ if !ok {
+ return fuse.ENOENT
+ }
+ }
+
+ _, e := xattr.Get(path, op.Name)
+
+ if op.Flags == 0x1 && e == nil {
+ return fuse.EEXIST
+ } else if op.Flags == 0x2 && e != nil {
+ return fuse.ENOATTR
+ }
+
+ e = xattr.Set(path, op.Name, op.Value)
+ if e != nil {
+ return e
+ }
+
+ return nil
+}
+
+func (fs BasicFS) Fallocate(ctx context.Context, op *fuseops.FallocateOp) error {
+ printer("Fallocate")
+ return NoImplementationError{}
+}
+*/
+
+func (fs BasicFS) Destroy() {
+ printer("Destroy")
+ fuse.Unmount("./mount")
+}
diff --git a/mft-fs/archive/main/main.go b/mft-fs/archive/main/main.go
new file mode 100644
index 00000000..9ed8c081
--- /dev/null
+++ b/mft-fs/archive/main/main.go
@@ -0,0 +1,40 @@
+package main
+
+import (
+ "context"
+ "flag"
+ "github.com/jacobsa/fuse"
+ "github.com/jacobsa/fuse/fuseutil"
+ "log"
+ "mft-fs/archive/abstractfs"
+ "mft-fs/archive/osfsmanager"
+ "os"
+)
+
+func main() {
+
+ // reading commandline args
+ mountDirectory := flag.String("mountDirectory", "", "mount directory")
+ rootDirectory := flag.String("rootDirectory", "", "root directory")
+ flag.Parse()
+
+ manager := osfsmanager.NewOSFSManager(*rootDirectory)
+ fs, _ := abstractfs.NewAbstractFS(manager)
+ server := fuseutil.NewFileSystemServer(&fs)
+
+ // mount the filesystem
+ cfg := &fuse.MountConfig{
+ ReadOnly: false,
+ DebugLogger: log.New(os.Stderr, "fuse: ", 0),
+ ErrorLogger: log.New(os.Stderr, "fuse: ", 0),
+ }
+ mfs, err := fuse.Mount(*mountDirectory, server, cfg)
+ if err != nil {
+ log.Fatalf("Mount: %v", err)
+ }
+
+ // wait for it to be unmounted
+ if err = mfs.Join(context.Background()); err != nil {
+ log.Fatalf("Join: %v", err)
+ }
+}
diff --git a/mft-fs/archive/osfsmanager/os_fs_manager.go b/mft-fs/archive/osfsmanager/os_fs_manager.go
new file mode 100644
index 00000000..0292ef53
--- /dev/null
+++ b/mft-fs/archive/osfsmanager/os_fs_manager.go
@@ -0,0 +1,347 @@
+package osfsmanager
+
+import (
+ "crypto/rand"
+ "fmt"
+ "github.com/jacobsa/fuse"
+ "github.com/jacobsa/fuse/fuseops"
+ "github.com/jacobsa/fuse/fuseutil"
+ "golang.org/x/sys/unix"
+ "mft-fs/archive/abstractfs"
+ "mft-fs/datastructures"
+ "os"
+ "syscall"
+ "time"
+)
+
+type OSFSManager struct {
+ abstractfs.FSManager
+ root string
+ inodeInfo map[fuseops.InodeID]*abstractfs.FileInfo
+ handleToInode map[fuseops.HandleID]fuseops.InodeID
+ inodeCounter fuseops.InodeID
+}
+
+type parentChildPair struct {
+ parent fuseops.InodeID
+ child string
+}
+
+func (manager *OSFSManager) bfs(root string) {
+ q := datastructures.NewQueue()
+ q.Enqueue(&(parentChildPair{
+ parent: 0,
+ child: root,
+ }))
+ for !q.IsEmpty() {
+ current := q.Dequeue().(*parentChildPair)
+ var direntType fuseutil.DirentType
+ stat, e := os.Stat(current.child)
+ if e != nil {
+ fmt.Println("error:")
+ fmt.Println(e.Error())
+ continue
+ }
+ if stat.IsDir() {
+ dir, e := os.ReadDir(current.child)
+ if e != nil {
+ continue
+ }
+ for _, file := range dir {
+ q.Enqueue(&(parentChildPair{
+ parent: manager.inodeCounter,
+ child: fmt.Sprintf("%s/%s", current.child, file.Name()),
+ }))
+ }
+ direntType = fuseutil.DT_Directory
+ } else {
+ direntType = fuseutil.DT_File
+ }
+ info := abstractfs.NewFileInfo(stat.Name(), current.child, manager.inodeCounter, current.parent, direntType)
+ manager.inodeInfo[manager.inodeCounter] = &info
+ parentInfo, ok := manager.inodeInfo[current.parent]
+ if ok {
+ parentInfo.ChildrenIndexMap[info.Name] = len(parentInfo.Children)
+ parentInfo.Children = append(parentInfo.Children, manager.inodeCounter)
+ }
+ manager.updateInfo(manager.inodeInfo[manager.inodeCounter])
+ manager.inodeCounter++
+ }
+}
+
+func NewOSFSManager(root string) *OSFSManager {
+ manager := &OSFSManager{
+ root: root,
+ inodeInfo: make(map[fuseops.InodeID]*abstractfs.FileInfo),
+ handleToInode: make(map[fuseops.HandleID]fuseops.InodeID),
+ inodeCounter: 1,
+ }
+ manager.bfs(root)
+ return manager
+}
+
+func (manager *OSFSManager) GenerateHandle(inode fuseops.InodeID) (fuseops.HandleID, error) {
+ var buff [8]byte
+ _, e := rand.Read(buff[:])
+ if e != nil {
+ return 0, e
+ }
+ var output uint64 = 0
+ for i := 0; i < len(buff); i++ {
+ output = output | uint64(buff[i]<<(8*i))
+ }
+ handle := fuseops.HandleID(output)
+ _, ok := manager.handleToInode[handle]
+ if ok {
+ return manager.GenerateHandle(inode)
+ }
+ info, ok := manager.inodeInfo[inode]
+ if !ok {
+ return 0, fuse.ENOENT
+ }
+ info.Handle = handle
+ manager.handleToInode[handle] = inode
+ return handle, nil
+}
+
+func (manager *OSFSManager) updateInfo(info *abstractfs.FileInfo) error {
+
+ fileInfo, e := os.Stat(info.Path)
+ if e != nil {
+ return e
+ }
+ stats := fileInfo.Sys().(*syscall.Stat_t)
+
+ info.Size = uint64(fileInfo.Size())
+
+ info.Nlink = 1
+
+ info.Mode = fileInfo.Mode()
+
+ /*info.Atime = time.Unix(stats.Atimespec.Sec, stats.Atimespec.Nsec)
+ info.Mtime = time.Unix(stats.Mtimespec.Sec, stats.Mtimespec.Nsec)
+ info.Ctime = time.Unix(stats.Ctimespec.Sec, stats.Ctimespec.Nsec)
+ info.Crtime = time.Unix(stats.Birthtimespec.Sec, stats.Birthtimespec.Nsec)*/
+ var timeStats unix.Stat_t
+ e = unix.Stat(info.Path, &timeStats)
+ if e != nil {
+ return e
+ }
+ info.Atime = time.Unix(timeStats.Atim.Sec, timeStats.Atim.Nsec)
+ info.Mtime = time.Unix(timeStats.Mtim.Sec, timeStats.Mtim.Nsec)
+ info.Ctime = time.Unix(timeStats.Ctim.Sec, timeStats.Ctim.Nsec)
+ info.Crtime = time.Unix(timeStats.Ctim.Sec, timeStats.Ctim.Nsec)
+
+ info.Uid = stats.Uid
+ info.Gid = stats.Gid
+
+ return nil
+}
+
+func (manager *OSFSManager) GetSize() (uint64, error) {
+ stat, _ := os.Stat(manager.root)
+ return uint64(stat.Size()), nil
+}
+
+func (manager *OSFSManager) GetLength() (uint64, error) {
+ return uint64(len(manager.inodeInfo)), nil
+}
+
+func (manager *OSFSManager) GetInfo(inode fuseops.InodeID) (*abstractfs.FileInfo, error) {
+ info, ok := manager.inodeInfo[inode]
+ if !ok {
+ return nil, fuse.ENOENT
+ }
+ return info, nil
+}
+
+func (manager *OSFSManager) SetInfo(inode fuseops.InodeID, uidptr *uint32, gidptr *uint32, sizeptr *uint64, modeptr *os.FileMode, atimeptr *time.Time, mtimeptr *time.Time) error {
+ info, e := manager.GetInfo(inode)
+ if e != nil {
+ return e
+ }
+
+ if modeptr != nil {
+ e = os.Chmod(info.Path, *modeptr)
+ if e != nil {
+ return e
+ }
+ }
+
+ uid := -1
+ gid := -1
+ if uidptr != nil {
+ uid = int(*uidptr)
+ }
+ if gidptr != nil {
+ gid = int(*gidptr)
+ }
+ e = os.Chown(info.Path, uid, gid)
+ if e != nil {
+ return e
+ }
+
+ atime := time.Time{}
+ mtime := time.Time{}
+ if atimeptr != nil {
+ atime = *atimeptr
+ }
+ if mtimeptr != nil {
+ mtime = *mtimeptr
+ }
+ e = os.Chtimes(info.Path, atime, mtime)
+ if e != nil {
+ return e
+ }
+
+ return manager.updateInfo(info)
+}
+
+func (manager *OSFSManager) MkDir(parent fuseops.InodeID, name string, mode os.FileMode) (fuseops.InodeID, error) {
+ parentInfo, e := manager.GetInfo(parent)
+ if e != nil {
+ return 0, e
+ }
+
+ path := parentInfo.Path + "/" + name
+ e = os.Mkdir(path, mode)
+ if e != nil {
+ return 0, e
+ }
+
+ inode := manager.inodeCounter //fuseops.InodeID(osInfo.Sys().(*syscall.Stat_t).Ino)
+ manager.inodeCounter++
+ infoObj := abstractfs.NewFileInfo(name, path, inode, parent, fuseutil.DT_Directory)
+ manager.inodeInfo[inode] = &infoObj
+ e = manager.updateInfo(&infoObj)
+ if e != nil {
+ return 0, e
+ }
+
+ parentInfo.Children = append(parentInfo.Children, inode)
+ parentInfo.ChildrenIndexMap[name] = len(parentInfo.Children) - 1
+
+ return inode, nil
+}
+
+func (manager *OSFSManager) CreateFile(parent fuseops.InodeID, name string, mode os.FileMode) (fuseops.InodeID, error) {
+ parentInfo, e := manager.GetInfo(parent)
+ if e != nil {
+ return 0, e
+ }
+
+ path := parentInfo.Path + "/" + name
+ file, e := os.Create(path)
+ defer file.Close()
+ if e != nil {
+ return 0, e
+ }
+
+ e = file.Chmod(mode)
+ if e != nil {
+ return 0, e
+ }
+
+ inode := manager.inodeCounter //fuseops.InodeID(osInfo.Sys().(*syscall.Stat_t).Ino)
+ manager.inodeCounter++
+ infoObj := abstractfs.NewFileInfo(name, path, inode, parent, fuseutil.DT_File)
+ manager.inodeInfo[inode] = &infoObj
+ e = manager.updateInfo(&infoObj)
+ if e != nil {
+ return 0, e
+ }
+
+ parentInfo.Children = append(parentInfo.Children, inode)
+ parentInfo.ChildrenIndexMap[name] = len(parentInfo.Children) - 1
+
+ return inode, nil
+}
+
+func (manager *OSFSManager) RmDir(inode fuseops.InodeID) error {
+ return nil
+}
+
+func (manager *OSFSManager) Delete(inode fuseops.InodeID) error {
+
+ // first delete any reference in parents
+ // then delete self
+
+ info, e := manager.GetInfo(inode)
+ if e != nil {
+ return e
+ }
+
+ parentInfo, e := manager.GetInfo(info.Parent)
+ if e != nil {
+ return e
+ }
+
+ parentInfo.Children = datastructures.Remove(parentInfo.Children, parentInfo.ChildrenIndexMap[info.Name])
+ target := parentInfo.ChildrenIndexMap[info.Name]
+ for name, index := range parentInfo.ChildrenIndexMap {
+ if index > target {
+ parentInfo.ChildrenIndexMap[name] = index - 1
+ }
+ }
+ delete(parentInfo.ChildrenIndexMap, info.Name)
+
+ delete(manager.inodeInfo, info.Inode)
+
+ return nil
+}
+
+func (manager *OSFSManager) DeleteHandle(handle fuseops.HandleID) error {
+ delete(manager.handleToInode, handle)
+ return nil
+}
+
+func (manager *OSFSManager) SyncFile(inode fuseops.InodeID) error {
+ info, e := manager.GetInfo(inode)
+ if e != nil {
+ return e
+ }
+ file, e := os.OpenFile(info.Path, os.O_RDWR, info.Mode)
+ if e != nil {
+ return e
+ }
+ defer file.Close()
+ e = file.Sync()
+ if e != nil {
+ return e
+ }
+ return nil
+}
+
+func (manager *OSFSManager) ReadAt(inode fuseops.InodeID, data []byte, off int64) (int, error) {
+ info, e := manager.GetInfo(inode)
+ if e != nil {
+ return 0, e
+ }
+
+ file, e := os.OpenFile(info.Path, os.O_RDWR, info.Mode)
+ if e != nil {
+ return 0, e
+ }
+ defer file.Close()
+
+ n, e := file.ReadAt(data, off)
+ return n, e
+}
+
+func (manager *OSFSManager) WriteAt(inode fuseops.InodeID, data []byte, off int64) (int, error) {
+ info, e := manager.GetInfo(inode)
+ if e != nil {
+ return 0, e
+ }
+
+ file, e := os.OpenFile(info.Path, os.O_RDWR, info.Mode)
+ if e != nil {
+ return 0, e
+ }
+ defer file.Close()
+
+ n, e := file.WriteAt(data, off)
+ return n, e
+}
+
+func (manager *OSFSManager) Destroy() error { return nil }
diff --git a/mft-fs/archive/remotefs/client/client_manager.go b/mft-fs/archive/remotefs/client/client_manager.go
new file mode 100644
index 00000000..877ca41e
--- /dev/null
+++ b/mft-fs/archive/remotefs/client/client_manager.go
@@ -0,0 +1,163 @@
+package client
+
+import (
+ "context"
+ "github.com/jacobsa/fuse/fuseops"
+ "google.golang.org/grpc"
+ "google.golang.org/protobuf/types/known/timestamppb"
+ "mft-fs/archive/abstractfs"
+ remotefscomms2 "mft-fs/archive/remotefs/remotefscomms"
+ "os"
+ "time"
+)
+
+type ClientManager struct {
+ abstractfs.FSManager
+ client remotefscomms2.RemoteFSCommsClient
+}
+
+func NewClientManager(conn *grpc.ClientConn) (*ClientManager, error) {
+ output := &ClientManager{}
+ output.client = remotefscomms2.NewRemoteFSCommsClient(conn)
+ return output, nil
+}
+
+func (manager *ClientManager) GetSize() (uint64, error) {
+ resp, e := manager.client.GetSizeComm(context.Background(), &remotefscomms2.Empty{})
+ if e != nil {
+ return 0, e
+ }
+ return resp.Data, nil
+}
+
+func (manager *ClientManager) GetLength() (uint64, error) {
+ resp, e := manager.client.GetLengthComm(context.Background(), &remotefscomms2.Empty{})
+ if e != nil {
+ return 0, e
+ }
+ return resp.Data, nil
+}
+
+func (manager *ClientManager) GetInfo(inode fuseops.InodeID) (*abstractfs.FileInfo, error) {
+ resp, e := manager.client.GetInfoComm(context.Background(), &remotefscomms2.UintMsg{
+ Data: uint64(inode),
+ })
+ if e != nil {
+ return nil, e
+ }
+ output := &abstractfs.FileInfo{
+ ChildrenIndexMap: make(map[string]int),
+ }
+ remotefscomms2.ConvertFromComm(resp, output)
+ return output, nil
+}
+
+func (manager *ClientManager) SetInfo(inode fuseops.InodeID, uidptr *uint32, gidptr *uint32, sizeptr *uint64, modeptr *os.FileMode, atimeptr *time.Time, mtimeptr *time.Time) error {
+ request := &remotefscomms2.SetInfoParamsMsg{
+ Inode: uint64(inode),
+ Uid: -1,
+ Gid: -1,
+ Size: -1,
+ Mode: -1,
+ Atime: timestamppb.New(time.Time{}),
+ Mtime: timestamppb.New(time.Time{}),
+ }
+ if uidptr != nil {
+ request.Uid = int32(*uidptr)
+ }
+ if gidptr != nil {
+ request.Gid = int32(*gidptr)
+ }
+ if sizeptr != nil {
+ request.Size = int64(*sizeptr)
+ }
+ if modeptr != nil {
+ request.Mode = int32(*modeptr)
+ }
+ if atimeptr != nil {
+ request.Atime = timestamppb.New(*atimeptr)
+ }
+ if mtimeptr != nil {
+ request.Mtime = timestamppb.New(*mtimeptr)
+ }
+ _, e := manager.client.SetInfoComm(context.Background(), request)
+ return e
+}
+
+func (manager *ClientManager) Delete(inode fuseops.InodeID) error {
+ _, e := manager.client.DeleteComm(context.Background(), &remotefscomms2.UintMsg{Data: uint64(inode)})
+ return e
+}
+
+func (manager *ClientManager) MkDir(parent fuseops.InodeID, name string, mode os.FileMode) (fuseops.InodeID, error) {
+ resp, e := manager.client.MkDirComm(context.Background(), &remotefscomms2.MkInodeMsg{
+ Parent: uint64(parent),
+ Name: name,
+ Mode: uint32(mode),
+ })
+ if e != nil {
+ return 0, e
+ }
+ return fuseops.InodeID(resp.Data), nil
+}
+
+func (manager *ClientManager) GenerateHandle(inode fuseops.InodeID) (fuseops.HandleID, error) {
+ resp, e := manager.client.GenerateHandleComm(context.Background(), &remotefscomms2.UintMsg{Data: uint64(inode)})
+ if e != nil {
+ return 0, e
+ }
+ return fuseops.HandleID(resp.Data), nil
+}
+func (manager *ClientManager) CreateFile(parent fuseops.InodeID, name string, mode os.FileMode) (fuseops.InodeID, error) {
+ resp, e := manager.client.CreateFileComm(context.Background(), &remotefscomms2.MkInodeMsg{
+ Parent: uint64(parent),
+ Name: name,
+ Mode: uint32(mode),
+ })
+ if e != nil {
+ return 0, e
+ }
+ return fuseops.InodeID(resp.Data), nil
+}
+
+func (manager *ClientManager) RmDir(inode fuseops.InodeID) error {
+ _, e := manager.client.RmDirComm(context.Background(), &remotefscomms2.UintMsg{Data: uint64(inode)})
+ return e
+}
+
+func (manager *ClientManager) DeleteHandle(handle fuseops.HandleID) error {
+ _, e := manager.client.DeleteHandleComm(context.Background(), &remotefscomms2.UintMsg{Data: uint64(handle)})
+ return e
+}
+
+func (manager *ClientManager) SyncFile(inode fuseops.InodeID) error {
+ _, e := manager.client.SyncFileComm(context.Background(), &remotefscomms2.UintMsg{Data: uint64(inode)})
+ return e
+}
+
+func (manager *ClientManager) WriteAt(inode fuseops.InodeID, data []byte, off int64) (n int, err error) {
+ resp, e := manager.client.WriteAtComm(context.Background(), &remotefscomms2.ContentMsg{
+ Inode: uint64(inode),
+ Data: data,
+ Off: off,
+ })
+ if e != nil {
+ return 0, e
+ }
+ return int(resp.Data), nil
+}
+func (manager *ClientManager) ReadAt(inode fuseops.InodeID, data []byte, off int64) (n int, err error) {
+ resp, e := manager.client.ReadAtComm(context.Background(), &remotefscomms2.ContentMsg{
+ Inode: uint64(inode),
+ Data: data,
+ Off: off,
+ })
+ if e != nil {
+ return 0, e
+ }
+ return int(resp.Data), nil
+}
+
+func (manager *ClientManager) Destroy() error {
+ return nil
+}
diff --git a/mft-fs/archive/remotefs/clientmain/client_main.go b/mft-fs/archive/remotefs/clientmain/client_main.go
new file mode 100644
index 00000000..872113ba
--- /dev/null
+++ b/mft-fs/archive/remotefs/clientmain/client_main.go
@@ -0,0 +1,54 @@
+package main
+
+import (
+ "context"
+ "flag"
+ "github.com/jacobsa/fuse"
+ "github.com/jacobsa/fuse/fuseutil"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/credentials/insecure"
+ "log"
+ "mft-fs/archive/abstractfs"
+ "mft-fs/archive/remotefs/client"
+ "os"
+)
+
+func main() {
+
+ // reading commandline args
+ mountDirectory := flag.String("mountDirectory", "", "mount directory")
+ flag.Parse()
+
+ // setting up gRPC communicators
+ var opts []grpc.DialOption
+ opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))
+ conn, e := grpc.NewClient(":8000", opts...)
+ if e != nil {
+ log.Fatalf("Error: %v\n", e)
+ }
+ defer conn.Close()
+
+ // setting up FUSE
+ manager, e := client.NewClientManager(conn)
+ if e != nil {
+ log.Fatalf("Error: %v\n", e)
+ }
+ fs, _ := abstractfs.NewAbstractFS(manager)
+ server := fuseutil.NewFileSystemServer(&fs)
+
+ // mount the filesystem
+ cfg := &fuse.MountConfig{
+ ReadOnly: false,
+ DebugLogger: log.New(os.Stderr, "fuse: ", 0),
+ ErrorLogger: log.New(os.Stderr, "fuse: ", 0),
+ }
+ mfs, err := fuse.Mount(*mountDirectory, server, cfg)
+ if err != nil {
+ log.Fatalf("Mount: %v", err)
+ }
+
+ // wait for it to be unmounted
+ if err = mfs.Join(context.Background()); err != nil {
+ log.Fatalf("Join: %v", err)
+ }
+}
diff --git a/mft-fs/archive/remotefs/comm.proto b/mft-fs/archive/remotefs/comm.proto
new file mode 100644
index 00000000..3660e5bf
--- /dev/null
+++ b/mft-fs/archive/remotefs/comm.proto
@@ -0,0 +1,102 @@
+syntax = "proto3";
+package remotefscomms;
+
+option go_package="./safe-remotefscomms";
+
+import "google/protobuf/timestamp.proto";
+
+/*
+Complete FileInfo struct
+ - GetInfo (response)
+*/
+message FileInfoMsg {
+ string name = 1;
+ string path = 2;
+ uint64 inode = 3;
+ repeated uint64 children = 4;
+ map childrenIndexMap = 5;
+ uint64 parent = 6;
+ uint32 nlink = 7;
+ uint64 size = 8;
+ uint32 mode = 9;
+ google.protobuf.Timestamp atime = 10;
+ google.protobuf.Timestamp mtime = 11;
+ google.protobuf.Timestamp ctime = 12;
+ google.protobuf.Timestamp crtime = 13;
+ uint32 uid = 14;
+ uint32 gid = 15;
+ uint32 direntType = 16;
+ uint64 handle = 17;
+}
+
+/*
+Sending a single uint64
+ - GetSize (response)
+ - GetLength (response)
+ - GetInfo (request)
+ - Delete (request)
+ - MkDir (response)
+ - GenerateHandle (request, response)
+ - CreateFile (response)
+ - RmDir (request)
+ - DeleteHandle (request)
+ - SyncFile (request)
+*/
+message UintMsg {
+ uint64 data = 1;
+}
+
+/*
+Sending file contents
+ - ReadAt
+ - WriteAt
+*/
+message ContentMsg {
+ uint64 inode = 1;
+ bytes data = 2;
+ int64 off = 3;
+}
+
+/*
+SetInfoParamsMsg
+ - SetInfo (request)
+*/
+message SetInfoParamsMsg {
+ uint64 inode = 1;
+ int32 uid = 2;
+ int32 gid = 3;
+ int64 size = 4;
+ int32 mode = 5;
+ google.protobuf.Timestamp atime = 6;
+ google.protobuf.Timestamp mtime = 7;
+}
+
+/*
+MkInodeMsg
+ - MkDir (request)
+ - CreateFile (request)
+*/
+message MkInodeMsg {
+ uint64 parent = 1;
+ string name = 2;
+ uint32 mode = 3;
+}
+
+/*Empty Message*/
+message Empty {}
+
+service RemoteFSComms {
+ rpc GetSizeComm(Empty) returns (UintMsg) {}
+ rpc GetLengthComm(Empty) returns (UintMsg) {}
+ rpc GetInfoComm(UintMsg) returns (FileInfoMsg) {}
+ rpc SetInfoComm(SetInfoParamsMsg) returns (Empty) {}
+ rpc DeleteComm(UintMsg) returns (Empty) {}
+ rpc MkDirComm(MkInodeMsg) returns (UintMsg) {}
+ rpc GenerateHandleComm(UintMsg) returns (UintMsg) {}
+ rpc CreateFileComm(MkInodeMsg) returns (UintMsg) {}
+ rpc RmDirComm(UintMsg) returns (Empty) {}
+ rpc DeleteHandleComm(UintMsg) returns (Empty) {}
+ rpc SyncFileComm(UintMsg) returns (Empty) {}
+ rpc WriteAtComm(ContentMsg) returns (UintMsg) {}
+ rpc ReadAtComm(ContentMsg) returns (UintMsg) {}
+}
diff --git a/mft-fs/archive/remotefs/remotefscomms/comm.pb.go b/mft-fs/archive/remotefs/remotefscomms/comm.pb.go
new file mode 100644
index 00000000..52d7855e
--- /dev/null
+++ b/mft-fs/archive/remotefs/remotefscomms/comm.pb.go
@@ -0,0 +1,821 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.34.2
+// protoc v5.27.1
+// source: comm.proto
+
+package remotefscomms
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ timestamppb "google.golang.org/protobuf/types/known/timestamppb"
+ reflect "reflect"
+ sync "sync"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// Complete FileInfo struct
+// - GetInfo (response)
+type FileInfoMsg struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"`
+ Inode uint64 `protobuf:"varint,3,opt,name=inode,proto3" json:"inode,omitempty"`
+ Children []uint64 `protobuf:"varint,4,rep,packed,name=children,proto3" json:"children,omitempty"`
+ ChildrenIndexMap map[string]uint32 `protobuf:"bytes,5,rep,name=childrenIndexMap,proto3" json:"childrenIndexMap,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"`
+ Parent uint64 `protobuf:"varint,6,opt,name=parent,proto3" json:"parent,omitempty"`
+ Nlink uint32 `protobuf:"varint,7,opt,name=nlink,proto3" json:"nlink,omitempty"`
+ Size uint64 `protobuf:"varint,8,opt,name=size,proto3" json:"size,omitempty"`
+ Mode uint32 `protobuf:"varint,9,opt,name=mode,proto3" json:"mode,omitempty"`
+ Atime *timestamppb.Timestamp `protobuf:"bytes,10,opt,name=atime,proto3" json:"atime,omitempty"`
+ Mtime *timestamppb.Timestamp `protobuf:"bytes,11,opt,name=mtime,proto3" json:"mtime,omitempty"`
+ Ctime *timestamppb.Timestamp `protobuf:"bytes,12,opt,name=ctime,proto3" json:"ctime,omitempty"`
+ Crtime *timestamppb.Timestamp `protobuf:"bytes,13,opt,name=crtime,proto3" json:"crtime,omitempty"`
+ Uid uint32 `protobuf:"varint,14,opt,name=uid,proto3" json:"uid,omitempty"`
+ Gid uint32 `protobuf:"varint,15,opt,name=gid,proto3" json:"gid,omitempty"`
+ DirentType uint32 `protobuf:"varint,16,opt,name=direntType,proto3" json:"direntType,omitempty"`
+ Handle uint64 `protobuf:"varint,17,opt,name=handle,proto3" json:"handle,omitempty"`
+}
+
+func (x *FileInfoMsg) Reset() {
+ *x = FileInfoMsg{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_comm_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *FileInfoMsg) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*FileInfoMsg) ProtoMessage() {}
+
+func (x *FileInfoMsg) ProtoReflect() protoreflect.Message {
+ mi := &file_comm_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use FileInfoMsg.ProtoReflect.Descriptor instead.
+func (*FileInfoMsg) Descriptor() ([]byte, []int) {
+ return file_comm_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *FileInfoMsg) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *FileInfoMsg) GetPath() string {
+ if x != nil {
+ return x.Path
+ }
+ return ""
+}
+
+func (x *FileInfoMsg) GetInode() uint64 {
+ if x != nil {
+ return x.Inode
+ }
+ return 0
+}
+
+func (x *FileInfoMsg) GetChildren() []uint64 {
+ if x != nil {
+ return x.Children
+ }
+ return nil
+}
+
+func (x *FileInfoMsg) GetChildrenIndexMap() map[string]uint32 {
+ if x != nil {
+ return x.ChildrenIndexMap
+ }
+ return nil
+}
+
+func (x *FileInfoMsg) GetParent() uint64 {
+ if x != nil {
+ return x.Parent
+ }
+ return 0
+}
+
+func (x *FileInfoMsg) GetNlink() uint32 {
+ if x != nil {
+ return x.Nlink
+ }
+ return 0
+}
+
+func (x *FileInfoMsg) GetSize() uint64 {
+ if x != nil {
+ return x.Size
+ }
+ return 0
+}
+
+func (x *FileInfoMsg) GetMode() uint32 {
+ if x != nil {
+ return x.Mode
+ }
+ return 0
+}
+
+func (x *FileInfoMsg) GetAtime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.Atime
+ }
+ return nil
+}
+
+func (x *FileInfoMsg) GetMtime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.Mtime
+ }
+ return nil
+}
+
+func (x *FileInfoMsg) GetCtime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.Ctime
+ }
+ return nil
+}
+
+func (x *FileInfoMsg) GetCrtime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.Crtime
+ }
+ return nil
+}
+
+func (x *FileInfoMsg) GetUid() uint32 {
+ if x != nil {
+ return x.Uid
+ }
+ return 0
+}
+
+func (x *FileInfoMsg) GetGid() uint32 {
+ if x != nil {
+ return x.Gid
+ }
+ return 0
+}
+
+func (x *FileInfoMsg) GetDirentType() uint32 {
+ if x != nil {
+ return x.DirentType
+ }
+ return 0
+}
+
+func (x *FileInfoMsg) GetHandle() uint64 {
+ if x != nil {
+ return x.Handle
+ }
+ return 0
+}
+
+// Sending a single uint64
+// - GetSize (response)
+// - GetLength (response)
+// - GetInfo (request)
+// - Delete (request)
+// - MkDir (response)
+// - GenerateHandle (request, response)
+// - CreateFile (response)
+// - RmDir (request)
+// - DeleteHandle (request)
+// - SyncFile (request)
+type UintMsg struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Data uint64 `protobuf:"varint,1,opt,name=data,proto3" json:"data,omitempty"`
+}
+
+func (x *UintMsg) Reset() {
+ *x = UintMsg{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_comm_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *UintMsg) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UintMsg) ProtoMessage() {}
+
+func (x *UintMsg) ProtoReflect() protoreflect.Message {
+ mi := &file_comm_proto_msgTypes[1]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use UintMsg.ProtoReflect.Descriptor instead.
+func (*UintMsg) Descriptor() ([]byte, []int) {
+ return file_comm_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *UintMsg) GetData() uint64 {
+ if x != nil {
+ return x.Data
+ }
+ return 0
+}
+
+// Sending file contents
+// - ReadAt
+// - WriteAt
+type ContentMsg struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Inode uint64 `protobuf:"varint,1,opt,name=inode,proto3" json:"inode,omitempty"`
+ Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
+ Off int64 `protobuf:"varint,3,opt,name=off,proto3" json:"off,omitempty"`
+}
+
+func (x *ContentMsg) Reset() {
+ *x = ContentMsg{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_comm_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ContentMsg) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ContentMsg) ProtoMessage() {}
+
+func (x *ContentMsg) ProtoReflect() protoreflect.Message {
+ mi := &file_comm_proto_msgTypes[2]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ContentMsg.ProtoReflect.Descriptor instead.
+func (*ContentMsg) Descriptor() ([]byte, []int) {
+ return file_comm_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *ContentMsg) GetInode() uint64 {
+ if x != nil {
+ return x.Inode
+ }
+ return 0
+}
+
+func (x *ContentMsg) GetData() []byte {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
+
+func (x *ContentMsg) GetOff() int64 {
+ if x != nil {
+ return x.Off
+ }
+ return 0
+}
+
+// SetInfoParamsMsg
+// - SetInfo (request)
+type SetInfoParamsMsg struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Inode uint64 `protobuf:"varint,1,opt,name=inode,proto3" json:"inode,omitempty"`
+ Uid int32 `protobuf:"varint,2,opt,name=uid,proto3" json:"uid,omitempty"`
+ Gid int32 `protobuf:"varint,3,opt,name=gid,proto3" json:"gid,omitempty"`
+ Size int64 `protobuf:"varint,4,opt,name=size,proto3" json:"size,omitempty"`
+ Mode int32 `protobuf:"varint,5,opt,name=mode,proto3" json:"mode,omitempty"`
+ Atime *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=atime,proto3" json:"atime,omitempty"`
+ Mtime *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=mtime,proto3" json:"mtime,omitempty"`
+}
+
+func (x *SetInfoParamsMsg) Reset() {
+ *x = SetInfoParamsMsg{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_comm_proto_msgTypes[3]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *SetInfoParamsMsg) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SetInfoParamsMsg) ProtoMessage() {}
+
+func (x *SetInfoParamsMsg) ProtoReflect() protoreflect.Message {
+ mi := &file_comm_proto_msgTypes[3]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SetInfoParamsMsg.ProtoReflect.Descriptor instead.
+func (*SetInfoParamsMsg) Descriptor() ([]byte, []int) {
+ return file_comm_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *SetInfoParamsMsg) GetInode() uint64 {
+ if x != nil {
+ return x.Inode
+ }
+ return 0
+}
+
+func (x *SetInfoParamsMsg) GetUid() int32 {
+ if x != nil {
+ return x.Uid
+ }
+ return 0
+}
+
+func (x *SetInfoParamsMsg) GetGid() int32 {
+ if x != nil {
+ return x.Gid
+ }
+ return 0
+}
+
+func (x *SetInfoParamsMsg) GetSize() int64 {
+ if x != nil {
+ return x.Size
+ }
+ return 0
+}
+
+func (x *SetInfoParamsMsg) GetMode() int32 {
+ if x != nil {
+ return x.Mode
+ }
+ return 0
+}
+
+func (x *SetInfoParamsMsg) GetAtime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.Atime
+ }
+ return nil
+}
+
+func (x *SetInfoParamsMsg) GetMtime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.Mtime
+ }
+ return nil
+}
+
+// MkInodeMsg
+// - MkDir (request)
+// - CreateFile (request)
+type MkInodeMsg struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Parent uint64 `protobuf:"varint,1,opt,name=parent,proto3" json:"parent,omitempty"`
+ Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
+ Mode uint32 `protobuf:"varint,3,opt,name=mode,proto3" json:"mode,omitempty"`
+}
+
+func (x *MkInodeMsg) Reset() {
+ *x = MkInodeMsg{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_comm_proto_msgTypes[4]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *MkInodeMsg) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MkInodeMsg) ProtoMessage() {}
+
+func (x *MkInodeMsg) ProtoReflect() protoreflect.Message {
+ mi := &file_comm_proto_msgTypes[4]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use MkInodeMsg.ProtoReflect.Descriptor instead.
+func (*MkInodeMsg) Descriptor() ([]byte, []int) {
+ return file_comm_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *MkInodeMsg) GetParent() uint64 {
+ if x != nil {
+ return x.Parent
+ }
+ return 0
+}
+
+func (x *MkInodeMsg) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *MkInodeMsg) GetMode() uint32 {
+ if x != nil {
+ return x.Mode
+ }
+ return 0
+}
+
+// Empty Message
+type Empty struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+}
+
+func (x *Empty) Reset() {
+ *x = Empty{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_comm_proto_msgTypes[5]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *Empty) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Empty) ProtoMessage() {}
+
+func (x *Empty) ProtoReflect() protoreflect.Message {
+ mi := &file_comm_proto_msgTypes[5]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Empty.ProtoReflect.Descriptor instead.
+func (*Empty) Descriptor() ([]byte, []int) {
+ return file_comm_proto_rawDescGZIP(), []int{5}
+}
+
+var File_comm_proto protoreflect.FileDescriptor
+
+var file_comm_proto_rawDesc = []byte{
+ 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0d, 0x72, 0x65,
+ 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x1a, 0x1f, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d,
+ 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x86, 0x05, 0x0a,
+ 0x0b, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x4d, 0x73, 0x67, 0x12, 0x12, 0x0a, 0x04,
+ 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
+ 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
+ 0x70, 0x61, 0x74, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20,
+ 0x01, 0x28, 0x04, 0x52, 0x05, 0x69, 0x6e, 0x6f, 0x64, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x68,
+ 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x03, 0x28, 0x04, 0x52, 0x08, 0x63, 0x68,
+ 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x12, 0x5c, 0x0a, 0x10, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72,
+ 0x65, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x4d, 0x61, 0x70, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b,
+ 0x32, 0x30, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73,
+ 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x4d, 0x73, 0x67, 0x2e, 0x43, 0x68, 0x69,
+ 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74,
+ 0x72, 0x79, 0x52, 0x10, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x49, 0x6e, 0x64, 0x65,
+ 0x78, 0x4d, 0x61, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x06,
+ 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05,
+ 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x6e, 0x6c, 0x69,
+ 0x6e, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04,
+ 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x09,
+ 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x30, 0x0a, 0x05, 0x61, 0x74,
+ 0x69, 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65,
+ 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x61, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x30, 0x0a, 0x05,
+ 0x6d, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69,
+ 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x6d, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x30,
+ 0x0a, 0x05, 0x63, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
+ 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x63, 0x74, 0x69, 0x6d, 0x65,
+ 0x12, 0x32, 0x0a, 0x06, 0x63, 0x72, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b,
+ 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
+ 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x06, 0x63, 0x72,
+ 0x74, 0x69, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28,
+ 0x0d, 0x52, 0x03, 0x75, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x69, 0x64, 0x18, 0x0f, 0x20,
+ 0x01, 0x28, 0x0d, 0x52, 0x03, 0x67, 0x69, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x69, 0x72, 0x65,
+ 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x64, 0x69,
+ 0x72, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x61, 0x6e, 0x64,
+ 0x6c, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65,
+ 0x1a, 0x43, 0x0a, 0x15, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x49, 0x6e, 0x64, 0x65,
+ 0x78, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79,
+ 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76,
+ 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75,
+ 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x1d, 0x0a, 0x07, 0x55, 0x69, 0x6e, 0x74, 0x4d, 0x73, 0x67,
+ 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04,
+ 0x64, 0x61, 0x74, 0x61, 0x22, 0x48, 0x0a, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x4d,
+ 0x73, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
+ 0x04, 0x52, 0x05, 0x69, 0x6e, 0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x10, 0x0a, 0x03,
+ 0x6f, 0x66, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6f, 0x66, 0x66, 0x22, 0xd8,
+ 0x01, 0x0a, 0x10, 0x53, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73,
+ 0x4d, 0x73, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x04, 0x52, 0x05, 0x69, 0x6e, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x75, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x67,
+ 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x67, 0x69, 0x64, 0x12, 0x12, 0x0a,
+ 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x7a,
+ 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52,
+ 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x30, 0x0a, 0x05, 0x61, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x06,
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
+ 0x52, 0x05, 0x61, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x30, 0x0a, 0x05, 0x6d, 0x74, 0x69, 0x6d, 0x65,
+ 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
+ 0x6d, 0x70, 0x52, 0x05, 0x6d, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x4c, 0x0a, 0x0a, 0x4d, 0x6b, 0x49,
+ 0x6e, 0x6f, 0x64, 0x65, 0x4d, 0x73, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e,
+ 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12,
+ 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e,
+ 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
+ 0x0d, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0x07, 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79,
+ 0x32, 0xf3, 0x06, 0x0a, 0x0d, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x46, 0x53, 0x43, 0x6f, 0x6d,
+ 0x6d, 0x73, 0x12, 0x3d, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x43, 0x6f, 0x6d,
+ 0x6d, 0x12, 0x14, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d,
+ 0x73, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x16, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65,
+ 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x55, 0x69, 0x6e, 0x74, 0x4d, 0x73, 0x67, 0x22,
+ 0x00, 0x12, 0x3f, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x43, 0x6f,
+ 0x6d, 0x6d, 0x12, 0x14, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d,
+ 0x6d, 0x73, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x16, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74,
+ 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x55, 0x69, 0x6e, 0x74, 0x4d, 0x73, 0x67,
+ 0x22, 0x00, 0x12, 0x43, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x43, 0x6f, 0x6d,
+ 0x6d, 0x12, 0x16, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d,
+ 0x73, 0x2e, 0x55, 0x69, 0x6e, 0x74, 0x4d, 0x73, 0x67, 0x1a, 0x1a, 0x2e, 0x72, 0x65, 0x6d, 0x6f,
+ 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e,
+ 0x66, 0x6f, 0x4d, 0x73, 0x67, 0x22, 0x00, 0x12, 0x46, 0x0a, 0x0b, 0x53, 0x65, 0x74, 0x49, 0x6e,
+ 0x66, 0x6f, 0x43, 0x6f, 0x6d, 0x6d, 0x12, 0x1f, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66,
+ 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x53, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x50, 0x61,
+ 0x72, 0x61, 0x6d, 0x73, 0x4d, 0x73, 0x67, 0x1a, 0x14, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65,
+ 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12,
+ 0x3c, 0x0a, 0x0a, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x12, 0x16, 0x2e,
+ 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x55, 0x69,
+ 0x6e, 0x74, 0x4d, 0x73, 0x67, 0x1a, 0x14, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73,
+ 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x40, 0x0a,
+ 0x09, 0x4d, 0x6b, 0x44, 0x69, 0x72, 0x43, 0x6f, 0x6d, 0x6d, 0x12, 0x19, 0x2e, 0x72, 0x65, 0x6d,
+ 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x4d, 0x6b, 0x49, 0x6e, 0x6f,
+ 0x64, 0x65, 0x4d, 0x73, 0x67, 0x1a, 0x16, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73,
+ 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x55, 0x69, 0x6e, 0x74, 0x4d, 0x73, 0x67, 0x22, 0x00, 0x12,
+ 0x46, 0x0a, 0x12, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x48, 0x61, 0x6e, 0x64, 0x6c,
+ 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x12, 0x16, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73,
+ 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x55, 0x69, 0x6e, 0x74, 0x4d, 0x73, 0x67, 0x1a, 0x16, 0x2e,
+ 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x55, 0x69,
+ 0x6e, 0x74, 0x4d, 0x73, 0x67, 0x22, 0x00, 0x12, 0x45, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74,
+ 0x65, 0x46, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x12, 0x19, 0x2e, 0x72, 0x65, 0x6d, 0x6f,
+ 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x4d, 0x6b, 0x49, 0x6e, 0x6f, 0x64,
+ 0x65, 0x4d, 0x73, 0x67, 0x1a, 0x16, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63,
+ 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x55, 0x69, 0x6e, 0x74, 0x4d, 0x73, 0x67, 0x22, 0x00, 0x12, 0x3b,
+ 0x0a, 0x09, 0x52, 0x6d, 0x44, 0x69, 0x72, 0x43, 0x6f, 0x6d, 0x6d, 0x12, 0x16, 0x2e, 0x72, 0x65,
+ 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x55, 0x69, 0x6e, 0x74,
+ 0x4d, 0x73, 0x67, 0x1a, 0x14, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f,
+ 0x6d, 0x6d, 0x73, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x42, 0x0a, 0x10, 0x44,
+ 0x65, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x12,
+ 0x16, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e,
+ 0x55, 0x69, 0x6e, 0x74, 0x4d, 0x73, 0x67, 0x1a, 0x14, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65,
+ 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12,
+ 0x3e, 0x0a, 0x0c, 0x53, 0x79, 0x6e, 0x63, 0x46, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x12,
+ 0x16, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e,
+ 0x55, 0x69, 0x6e, 0x74, 0x4d, 0x73, 0x67, 0x1a, 0x14, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65,
+ 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12,
+ 0x42, 0x0a, 0x0b, 0x57, 0x72, 0x69, 0x74, 0x65, 0x41, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x12, 0x19,
+ 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x43,
+ 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x4d, 0x73, 0x67, 0x1a, 0x16, 0x2e, 0x72, 0x65, 0x6d, 0x6f,
+ 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x55, 0x69, 0x6e, 0x74, 0x4d, 0x73,
+ 0x67, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x0a, 0x52, 0x65, 0x61, 0x64, 0x41, 0x74, 0x43, 0x6f, 0x6d,
+ 0x6d, 0x12, 0x19, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d,
+ 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x4d, 0x73, 0x67, 0x1a, 0x16, 0x2e, 0x72,
+ 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x55, 0x69, 0x6e,
+ 0x74, 0x4d, 0x73, 0x67, 0x22, 0x00, 0x42, 0x11, 0x5a, 0x0f, 0x2e, 0x2f, 0x72, 0x65, 0x6d, 0x6f,
+ 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x33,
+}
+
+var (
+ file_comm_proto_rawDescOnce sync.Once
+ file_comm_proto_rawDescData = file_comm_proto_rawDesc
+)
+
+func file_comm_proto_rawDescGZIP() []byte {
+ file_comm_proto_rawDescOnce.Do(func() {
+ file_comm_proto_rawDescData = protoimpl.X.CompressGZIP(file_comm_proto_rawDescData)
+ })
+ return file_comm_proto_rawDescData
+}
+
+var file_comm_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
+var file_comm_proto_goTypes = []any{
+ (*FileInfoMsg)(nil), // 0: safe-remotefscomms.FileInfoMsg
+ (*UintMsg)(nil), // 1: safe-remotefscomms.UintMsg
+ (*ContentMsg)(nil), // 2: safe-remotefscomms.ContentMsg
+ (*SetInfoParamsMsg)(nil), // 3: safe-remotefscomms.SetInfoParamsMsg
+ (*MkInodeMsg)(nil), // 4: safe-remotefscomms.MkInodeMsg
+ (*Empty)(nil), // 5: safe-remotefscomms.Empty
+ nil, // 6: safe-remotefscomms.FileInfoMsg.ChildrenIndexMapEntry
+ (*timestamppb.Timestamp)(nil), // 7: google.protobuf.Timestamp
+}
+var file_comm_proto_depIdxs = []int32{
+ 6, // 0: safe-remotefscomms.FileInfoMsg.childrenIndexMap:type_name -> safe-remotefscomms.FileInfoMsg.ChildrenIndexMapEntry
+ 7, // 1: safe-remotefscomms.FileInfoMsg.atime:type_name -> google.protobuf.Timestamp
+ 7, // 2: safe-remotefscomms.FileInfoMsg.mtime:type_name -> google.protobuf.Timestamp
+ 7, // 3: safe-remotefscomms.FileInfoMsg.ctime:type_name -> google.protobuf.Timestamp
+ 7, // 4: safe-remotefscomms.FileInfoMsg.crtime:type_name -> google.protobuf.Timestamp
+ 7, // 5: safe-remotefscomms.SetInfoParamsMsg.atime:type_name -> google.protobuf.Timestamp
+ 7, // 6: safe-remotefscomms.SetInfoParamsMsg.mtime:type_name -> google.protobuf.Timestamp
+ 5, // 7: safe-remotefscomms.RemoteFSComms.GetSizeComm:input_type -> safe-remotefscomms.Empty
+ 5, // 8: safe-remotefscomms.RemoteFSComms.GetLengthComm:input_type -> safe-remotefscomms.Empty
+ 1, // 9: safe-remotefscomms.RemoteFSComms.GetInfoComm:input_type -> safe-remotefscomms.UintMsg
+ 3, // 10: safe-remotefscomms.RemoteFSComms.SetInfoComm:input_type -> safe-remotefscomms.SetInfoParamsMsg
+ 1, // 11: safe-remotefscomms.RemoteFSComms.DeleteComm:input_type -> safe-remotefscomms.UintMsg
+ 4, // 12: safe-remotefscomms.RemoteFSComms.MkDirComm:input_type -> safe-remotefscomms.MkInodeMsg
+ 1, // 13: safe-remotefscomms.RemoteFSComms.GenerateHandleComm:input_type -> safe-remotefscomms.UintMsg
+ 4, // 14: safe-remotefscomms.RemoteFSComms.CreateFileComm:input_type -> safe-remotefscomms.MkInodeMsg
+ 1, // 15: safe-remotefscomms.RemoteFSComms.RmDirComm:input_type -> safe-remotefscomms.UintMsg
+ 1, // 16: safe-remotefscomms.RemoteFSComms.DeleteHandleComm:input_type -> safe-remotefscomms.UintMsg
+ 1, // 17: safe-remotefscomms.RemoteFSComms.SyncFileComm:input_type -> safe-remotefscomms.UintMsg
+ 2, // 18: safe-remotefscomms.RemoteFSComms.WriteAtComm:input_type -> safe-remotefscomms.ContentMsg
+ 2, // 19: safe-remotefscomms.RemoteFSComms.ReadAtComm:input_type -> safe-remotefscomms.ContentMsg
+ 1, // 20: safe-remotefscomms.RemoteFSComms.GetSizeComm:output_type -> safe-remotefscomms.UintMsg
+ 1, // 21: safe-remotefscomms.RemoteFSComms.GetLengthComm:output_type -> safe-remotefscomms.UintMsg
+ 0, // 22: safe-remotefscomms.RemoteFSComms.GetInfoComm:output_type -> safe-remotefscomms.FileInfoMsg
+ 5, // 23: safe-remotefscomms.RemoteFSComms.SetInfoComm:output_type -> safe-remotefscomms.Empty
+ 5, // 24: safe-remotefscomms.RemoteFSComms.DeleteComm:output_type -> safe-remotefscomms.Empty
+ 1, // 25: safe-remotefscomms.RemoteFSComms.MkDirComm:output_type -> safe-remotefscomms.UintMsg
+ 1, // 26: safe-remotefscomms.RemoteFSComms.GenerateHandleComm:output_type -> safe-remotefscomms.UintMsg
+ 1, // 27: safe-remotefscomms.RemoteFSComms.CreateFileComm:output_type -> safe-remotefscomms.UintMsg
+ 5, // 28: safe-remotefscomms.RemoteFSComms.RmDirComm:output_type -> safe-remotefscomms.Empty
+ 5, // 29: safe-remotefscomms.RemoteFSComms.DeleteHandleComm:output_type -> safe-remotefscomms.Empty
+ 5, // 30: safe-remotefscomms.RemoteFSComms.SyncFileComm:output_type -> safe-remotefscomms.Empty
+ 1, // 31: safe-remotefscomms.RemoteFSComms.WriteAtComm:output_type -> safe-remotefscomms.UintMsg
+ 1, // 32: safe-remotefscomms.RemoteFSComms.ReadAtComm:output_type -> safe-remotefscomms.UintMsg
+ 20, // [20:33] is the sub-list for method output_type
+ 7, // [7:20] is the sub-list for method input_type
+ 7, // [7:7] is the sub-list for extension type_name
+ 7, // [7:7] is the sub-list for extension extendee
+ 0, // [0:7] is the sub-list for field type_name
+}
+
+func init() { file_comm_proto_init() }
+func file_comm_proto_init() {
+ if File_comm_proto != nil {
+ return
+ }
+ if !protoimpl.UnsafeEnabled {
+ file_comm_proto_msgTypes[0].Exporter = func(v any, i int) any {
+ switch v := v.(*FileInfoMsg); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_comm_proto_msgTypes[1].Exporter = func(v any, i int) any {
+ switch v := v.(*UintMsg); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_comm_proto_msgTypes[2].Exporter = func(v any, i int) any {
+ switch v := v.(*ContentMsg); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_comm_proto_msgTypes[3].Exporter = func(v any, i int) any {
+ switch v := v.(*SetInfoParamsMsg); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_comm_proto_msgTypes[4].Exporter = func(v any, i int) any {
+ switch v := v.(*MkInodeMsg); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_comm_proto_msgTypes[5].Exporter = func(v any, i int) any {
+ switch v := v.(*Empty); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_comm_proto_rawDesc,
+ NumEnums: 0,
+ NumMessages: 7,
+ NumExtensions: 0,
+ NumServices: 1,
+ },
+ GoTypes: file_comm_proto_goTypes,
+ DependencyIndexes: file_comm_proto_depIdxs,
+ MessageInfos: file_comm_proto_msgTypes,
+ }.Build()
+ File_comm_proto = out.File
+ file_comm_proto_rawDesc = nil
+ file_comm_proto_goTypes = nil
+ file_comm_proto_depIdxs = nil
+}
diff --git a/mft-fs/archive/remotefs/remotefscomms/comm_grpc.pb.go b/mft-fs/archive/remotefs/remotefscomms/comm_grpc.pb.go
new file mode 100644
index 00000000..31791914
--- /dev/null
+++ b/mft-fs/archive/remotefs/remotefscomms/comm_grpc.pb.go
@@ -0,0 +1,566 @@
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+// versions:
+// - protoc-gen-go-grpc v1.4.0
+// - protoc v5.27.1
+// source: comm.proto
+
+package remotefscomms
+
+import (
+ context "context"
+ grpc "google.golang.org/grpc"
+ codes "google.golang.org/grpc/codes"
+ status "google.golang.org/grpc/status"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.62.0 or later.
+const _ = grpc.SupportPackageIsVersion8
+
+const (
+ RemoteFSComms_GetSizeComm_FullMethodName = "/safe-remotefscomms.RemoteFSComms/GetSizeComm"
+ RemoteFSComms_GetLengthComm_FullMethodName = "/safe-remotefscomms.RemoteFSComms/GetLengthComm"
+ RemoteFSComms_GetInfoComm_FullMethodName = "/safe-remotefscomms.RemoteFSComms/GetInfoComm"
+ RemoteFSComms_SetInfoComm_FullMethodName = "/safe-remotefscomms.RemoteFSComms/SetInfoComm"
+ RemoteFSComms_DeleteComm_FullMethodName = "/safe-remotefscomms.RemoteFSComms/DeleteComm"
+ RemoteFSComms_MkDirComm_FullMethodName = "/safe-remotefscomms.RemoteFSComms/MkDirComm"
+ RemoteFSComms_GenerateHandleComm_FullMethodName = "/safe-remotefscomms.RemoteFSComms/GenerateHandleComm"
+ RemoteFSComms_CreateFileComm_FullMethodName = "/safe-remotefscomms.RemoteFSComms/CreateFileComm"
+ RemoteFSComms_RmDirComm_FullMethodName = "/safe-remotefscomms.RemoteFSComms/RmDirComm"
+ RemoteFSComms_DeleteHandleComm_FullMethodName = "/safe-remotefscomms.RemoteFSComms/DeleteHandleComm"
+ RemoteFSComms_SyncFileComm_FullMethodName = "/safe-remotefscomms.RemoteFSComms/SyncFileComm"
+ RemoteFSComms_WriteAtComm_FullMethodName = "/safe-remotefscomms.RemoteFSComms/WriteAtComm"
+ RemoteFSComms_ReadAtComm_FullMethodName = "/safe-remotefscomms.RemoteFSComms/ReadAtComm"
+)
+
+// RemoteFSCommsClient is the client API for RemoteFSComms service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type RemoteFSCommsClient interface {
+ GetSizeComm(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*UintMsg, error)
+ GetLengthComm(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*UintMsg, error)
+ GetInfoComm(ctx context.Context, in *UintMsg, opts ...grpc.CallOption) (*FileInfoMsg, error)
+ SetInfoComm(ctx context.Context, in *SetInfoParamsMsg, opts ...grpc.CallOption) (*Empty, error)
+ DeleteComm(ctx context.Context, in *UintMsg, opts ...grpc.CallOption) (*Empty, error)
+ MkDirComm(ctx context.Context, in *MkInodeMsg, opts ...grpc.CallOption) (*UintMsg, error)
+ GenerateHandleComm(ctx context.Context, in *UintMsg, opts ...grpc.CallOption) (*UintMsg, error)
+ CreateFileComm(ctx context.Context, in *MkInodeMsg, opts ...grpc.CallOption) (*UintMsg, error)
+ RmDirComm(ctx context.Context, in *UintMsg, opts ...grpc.CallOption) (*Empty, error)
+ DeleteHandleComm(ctx context.Context, in *UintMsg, opts ...grpc.CallOption) (*Empty, error)
+ SyncFileComm(ctx context.Context, in *UintMsg, opts ...grpc.CallOption) (*Empty, error)
+ WriteAtComm(ctx context.Context, in *ContentMsg, opts ...grpc.CallOption) (*UintMsg, error)
+ ReadAtComm(ctx context.Context, in *ContentMsg, opts ...grpc.CallOption) (*UintMsg, error)
+}
+
+type remoteFSCommsClient struct {
+ cc grpc.ClientConnInterface
+}
+
+func NewRemoteFSCommsClient(cc grpc.ClientConnInterface) RemoteFSCommsClient {
+ return &remoteFSCommsClient{cc}
+}
+
+func (c *remoteFSCommsClient) GetSizeComm(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*UintMsg, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(UintMsg)
+ err := c.cc.Invoke(ctx, RemoteFSComms_GetSizeComm_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *remoteFSCommsClient) GetLengthComm(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*UintMsg, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(UintMsg)
+ err := c.cc.Invoke(ctx, RemoteFSComms_GetLengthComm_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *remoteFSCommsClient) GetInfoComm(ctx context.Context, in *UintMsg, opts ...grpc.CallOption) (*FileInfoMsg, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(FileInfoMsg)
+ err := c.cc.Invoke(ctx, RemoteFSComms_GetInfoComm_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *remoteFSCommsClient) SetInfoComm(ctx context.Context, in *SetInfoParamsMsg, opts ...grpc.CallOption) (*Empty, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(Empty)
+ err := c.cc.Invoke(ctx, RemoteFSComms_SetInfoComm_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *remoteFSCommsClient) DeleteComm(ctx context.Context, in *UintMsg, opts ...grpc.CallOption) (*Empty, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(Empty)
+ err := c.cc.Invoke(ctx, RemoteFSComms_DeleteComm_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *remoteFSCommsClient) MkDirComm(ctx context.Context, in *MkInodeMsg, opts ...grpc.CallOption) (*UintMsg, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(UintMsg)
+ err := c.cc.Invoke(ctx, RemoteFSComms_MkDirComm_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *remoteFSCommsClient) GenerateHandleComm(ctx context.Context, in *UintMsg, opts ...grpc.CallOption) (*UintMsg, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(UintMsg)
+ err := c.cc.Invoke(ctx, RemoteFSComms_GenerateHandleComm_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *remoteFSCommsClient) CreateFileComm(ctx context.Context, in *MkInodeMsg, opts ...grpc.CallOption) (*UintMsg, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(UintMsg)
+ err := c.cc.Invoke(ctx, RemoteFSComms_CreateFileComm_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *remoteFSCommsClient) RmDirComm(ctx context.Context, in *UintMsg, opts ...grpc.CallOption) (*Empty, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(Empty)
+ err := c.cc.Invoke(ctx, RemoteFSComms_RmDirComm_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *remoteFSCommsClient) DeleteHandleComm(ctx context.Context, in *UintMsg, opts ...grpc.CallOption) (*Empty, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(Empty)
+ err := c.cc.Invoke(ctx, RemoteFSComms_DeleteHandleComm_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *remoteFSCommsClient) SyncFileComm(ctx context.Context, in *UintMsg, opts ...grpc.CallOption) (*Empty, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(Empty)
+ err := c.cc.Invoke(ctx, RemoteFSComms_SyncFileComm_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *remoteFSCommsClient) WriteAtComm(ctx context.Context, in *ContentMsg, opts ...grpc.CallOption) (*UintMsg, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(UintMsg)
+ err := c.cc.Invoke(ctx, RemoteFSComms_WriteAtComm_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *remoteFSCommsClient) ReadAtComm(ctx context.Context, in *ContentMsg, opts ...grpc.CallOption) (*UintMsg, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(UintMsg)
+ err := c.cc.Invoke(ctx, RemoteFSComms_ReadAtComm_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+// RemoteFSCommsServer is the server API for RemoteFSComms service.
+// All implementations must embed UnimplementedRemoteFSCommsServer
+// for forward compatibility
+type RemoteFSCommsServer interface {
+ GetSizeComm(context.Context, *Empty) (*UintMsg, error)
+ GetLengthComm(context.Context, *Empty) (*UintMsg, error)
+ GetInfoComm(context.Context, *UintMsg) (*FileInfoMsg, error)
+ SetInfoComm(context.Context, *SetInfoParamsMsg) (*Empty, error)
+ DeleteComm(context.Context, *UintMsg) (*Empty, error)
+ MkDirComm(context.Context, *MkInodeMsg) (*UintMsg, error)
+ GenerateHandleComm(context.Context, *UintMsg) (*UintMsg, error)
+ CreateFileComm(context.Context, *MkInodeMsg) (*UintMsg, error)
+ RmDirComm(context.Context, *UintMsg) (*Empty, error)
+ DeleteHandleComm(context.Context, *UintMsg) (*Empty, error)
+ SyncFileComm(context.Context, *UintMsg) (*Empty, error)
+ WriteAtComm(context.Context, *ContentMsg) (*UintMsg, error)
+ ReadAtComm(context.Context, *ContentMsg) (*UintMsg, error)
+ mustEmbedUnimplementedRemoteFSCommsServer()
+}
+
+// UnimplementedRemoteFSCommsServer must be embedded to have forward compatible implementations.
+type UnimplementedRemoteFSCommsServer struct {
+}
+
+func (UnimplementedRemoteFSCommsServer) GetSizeComm(context.Context, *Empty) (*UintMsg, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method GetSizeComm not implemented")
+}
+func (UnimplementedRemoteFSCommsServer) GetLengthComm(context.Context, *Empty) (*UintMsg, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method GetLengthComm not implemented")
+}
+func (UnimplementedRemoteFSCommsServer) GetInfoComm(context.Context, *UintMsg) (*FileInfoMsg, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method GetInfoComm not implemented")
+}
+func (UnimplementedRemoteFSCommsServer) SetInfoComm(context.Context, *SetInfoParamsMsg) (*Empty, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method SetInfoComm not implemented")
+}
+func (UnimplementedRemoteFSCommsServer) DeleteComm(context.Context, *UintMsg) (*Empty, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method DeleteComm not implemented")
+}
+func (UnimplementedRemoteFSCommsServer) MkDirComm(context.Context, *MkInodeMsg) (*UintMsg, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method MkDirComm not implemented")
+}
+func (UnimplementedRemoteFSCommsServer) GenerateHandleComm(context.Context, *UintMsg) (*UintMsg, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method GenerateHandleComm not implemented")
+}
+func (UnimplementedRemoteFSCommsServer) CreateFileComm(context.Context, *MkInodeMsg) (*UintMsg, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method CreateFileComm not implemented")
+}
+func (UnimplementedRemoteFSCommsServer) RmDirComm(context.Context, *UintMsg) (*Empty, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method RmDirComm not implemented")
+}
+func (UnimplementedRemoteFSCommsServer) DeleteHandleComm(context.Context, *UintMsg) (*Empty, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method DeleteHandleComm not implemented")
+}
+func (UnimplementedRemoteFSCommsServer) SyncFileComm(context.Context, *UintMsg) (*Empty, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method SyncFileComm not implemented")
+}
+func (UnimplementedRemoteFSCommsServer) WriteAtComm(context.Context, *ContentMsg) (*UintMsg, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method WriteAtComm not implemented")
+}
+func (UnimplementedRemoteFSCommsServer) ReadAtComm(context.Context, *ContentMsg) (*UintMsg, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method ReadAtComm not implemented")
+}
+func (UnimplementedRemoteFSCommsServer) mustEmbedUnimplementedRemoteFSCommsServer() {}
+
+// UnsafeRemoteFSCommsServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to RemoteFSCommsServer will
+// result in compilation errors.
+type UnsafeRemoteFSCommsServer interface {
+ mustEmbedUnimplementedRemoteFSCommsServer()
+}
+
+func RegisterRemoteFSCommsServer(s grpc.ServiceRegistrar, srv RemoteFSCommsServer) {
+ s.RegisterService(&RemoteFSComms_ServiceDesc, srv)
+}
+
+func _RemoteFSComms_GetSizeComm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(Empty)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(RemoteFSCommsServer).GetSizeComm(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: RemoteFSComms_GetSizeComm_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(RemoteFSCommsServer).GetSizeComm(ctx, req.(*Empty))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _RemoteFSComms_GetLengthComm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(Empty)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(RemoteFSCommsServer).GetLengthComm(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: RemoteFSComms_GetLengthComm_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(RemoteFSCommsServer).GetLengthComm(ctx, req.(*Empty))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _RemoteFSComms_GetInfoComm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(UintMsg)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(RemoteFSCommsServer).GetInfoComm(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: RemoteFSComms_GetInfoComm_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(RemoteFSCommsServer).GetInfoComm(ctx, req.(*UintMsg))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _RemoteFSComms_SetInfoComm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(SetInfoParamsMsg)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(RemoteFSCommsServer).SetInfoComm(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: RemoteFSComms_SetInfoComm_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(RemoteFSCommsServer).SetInfoComm(ctx, req.(*SetInfoParamsMsg))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _RemoteFSComms_DeleteComm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(UintMsg)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(RemoteFSCommsServer).DeleteComm(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: RemoteFSComms_DeleteComm_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(RemoteFSCommsServer).DeleteComm(ctx, req.(*UintMsg))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _RemoteFSComms_MkDirComm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(MkInodeMsg)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(RemoteFSCommsServer).MkDirComm(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: RemoteFSComms_MkDirComm_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(RemoteFSCommsServer).MkDirComm(ctx, req.(*MkInodeMsg))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _RemoteFSComms_GenerateHandleComm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(UintMsg)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(RemoteFSCommsServer).GenerateHandleComm(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: RemoteFSComms_GenerateHandleComm_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(RemoteFSCommsServer).GenerateHandleComm(ctx, req.(*UintMsg))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _RemoteFSComms_CreateFileComm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(MkInodeMsg)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(RemoteFSCommsServer).CreateFileComm(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: RemoteFSComms_CreateFileComm_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(RemoteFSCommsServer).CreateFileComm(ctx, req.(*MkInodeMsg))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _RemoteFSComms_RmDirComm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(UintMsg)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(RemoteFSCommsServer).RmDirComm(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: RemoteFSComms_RmDirComm_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(RemoteFSCommsServer).RmDirComm(ctx, req.(*UintMsg))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _RemoteFSComms_DeleteHandleComm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(UintMsg)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(RemoteFSCommsServer).DeleteHandleComm(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: RemoteFSComms_DeleteHandleComm_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(RemoteFSCommsServer).DeleteHandleComm(ctx, req.(*UintMsg))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _RemoteFSComms_SyncFileComm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(UintMsg)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(RemoteFSCommsServer).SyncFileComm(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: RemoteFSComms_SyncFileComm_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(RemoteFSCommsServer).SyncFileComm(ctx, req.(*UintMsg))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _RemoteFSComms_WriteAtComm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(ContentMsg)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(RemoteFSCommsServer).WriteAtComm(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: RemoteFSComms_WriteAtComm_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(RemoteFSCommsServer).WriteAtComm(ctx, req.(*ContentMsg))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _RemoteFSComms_ReadAtComm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(ContentMsg)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(RemoteFSCommsServer).ReadAtComm(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: RemoteFSComms_ReadAtComm_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(RemoteFSCommsServer).ReadAtComm(ctx, req.(*ContentMsg))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+// RemoteFSComms_ServiceDesc is the grpc.ServiceDesc for RemoteFSComms service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var RemoteFSComms_ServiceDesc = grpc.ServiceDesc{
+ ServiceName: "safe-remotefscomms.RemoteFSComms",
+ HandlerType: (*RemoteFSCommsServer)(nil),
+ Methods: []grpc.MethodDesc{
+ {
+ MethodName: "GetSizeComm",
+ Handler: _RemoteFSComms_GetSizeComm_Handler,
+ },
+ {
+ MethodName: "GetLengthComm",
+ Handler: _RemoteFSComms_GetLengthComm_Handler,
+ },
+ {
+ MethodName: "GetInfoComm",
+ Handler: _RemoteFSComms_GetInfoComm_Handler,
+ },
+ {
+ MethodName: "SetInfoComm",
+ Handler: _RemoteFSComms_SetInfoComm_Handler,
+ },
+ {
+ MethodName: "DeleteComm",
+ Handler: _RemoteFSComms_DeleteComm_Handler,
+ },
+ {
+ MethodName: "MkDirComm",
+ Handler: _RemoteFSComms_MkDirComm_Handler,
+ },
+ {
+ MethodName: "GenerateHandleComm",
+ Handler: _RemoteFSComms_GenerateHandleComm_Handler,
+ },
+ {
+ MethodName: "CreateFileComm",
+ Handler: _RemoteFSComms_CreateFileComm_Handler,
+ },
+ {
+ MethodName: "RmDirComm",
+ Handler: _RemoteFSComms_RmDirComm_Handler,
+ },
+ {
+ MethodName: "DeleteHandleComm",
+ Handler: _RemoteFSComms_DeleteHandleComm_Handler,
+ },
+ {
+ MethodName: "SyncFileComm",
+ Handler: _RemoteFSComms_SyncFileComm_Handler,
+ },
+ {
+ MethodName: "WriteAtComm",
+ Handler: _RemoteFSComms_WriteAtComm_Handler,
+ },
+ {
+ MethodName: "ReadAtComm",
+ Handler: _RemoteFSComms_ReadAtComm_Handler,
+ },
+ },
+ Streams: []grpc.StreamDesc{},
+ Metadata: "comm.proto",
+}
diff --git a/mft-fs/archive/remotefs/remotefscomms/commutils.go b/mft-fs/archive/remotefs/remotefscomms/commutils.go
new file mode 100644
index 00000000..1c7ea043
--- /dev/null
+++ b/mft-fs/archive/remotefs/remotefscomms/commutils.go
@@ -0,0 +1,57 @@
+package remotefscomms
+
+import (
+ "github.com/jacobsa/fuse/fuseops"
+ "github.com/jacobsa/fuse/fuseutil"
+ "google.golang.org/protobuf/types/known/timestamppb"
+ "mft-fs/archive/abstractfs"
+ "os"
+)
+
+func ConvertFromComm(input *FileInfoMsg, output *abstractfs.FileInfo) {
+ output.Name = input.Name
+ output.Path = input.Path
+ output.Inode = fuseops.InodeID(input.Inode)
+ for _, child := range input.Children {
+ output.Children = append(output.Children, fuseops.InodeID(child))
+ }
+ for name, index := range input.ChildrenIndexMap {
+ output.ChildrenIndexMap[name] = int(index)
+ }
+ output.Parent = fuseops.InodeID(input.Parent)
+ output.Nlink = input.Nlink
+ output.Size = input.Size
+ output.Mode = os.FileMode(input.Mode)
+ output.Atime = input.Atime.AsTime()
+ output.Mtime = input.Mtime.AsTime()
+ output.Ctime = input.Ctime.AsTime()
+ output.Crtime = input.Crtime.AsTime()
+ output.Uid = input.Uid
+ output.Gid = input.Gid
+ output.DirentType = fuseutil.DirentType(input.DirentType)
+ output.Handle = fuseops.HandleID(input.Handle)
+}
+
+func ConvertToComm(input *abstractfs.FileInfo, output *FileInfoMsg) {
+ output.Name = input.Name
+ output.Path = input.Path
+ output.Inode = uint64(input.Inode)
+ for _, child := range input.Children {
+ output.Children = append(output.Children, uint64(child))
+ }
+ for name, index := range input.ChildrenIndexMap {
+ output.ChildrenIndexMap[name] = uint32(index)
+ }
+ output.Parent = uint64(input.Parent)
+ output.Nlink = input.Nlink
+ output.Size = input.Size
+ output.Mode = uint32(input.Mode)
+ output.Atime = timestamppb.New(input.Atime)
+ output.Mtime = timestamppb.New(input.Mtime)
+ output.Ctime = timestamppb.New(input.Ctime)
+ output.Crtime = timestamppb.New(input.Crtime)
+ output.Uid = input.Uid
+ output.Gid = input.Gid
+ output.DirentType = uint32(input.DirentType)
+ output.Handle = uint64(input.Handle)
+}
diff --git a/mft-fs/archive/remotefs/server/server_manager.go b/mft-fs/archive/remotefs/server/server_manager.go
new file mode 100644
index 00000000..6dba102d
--- /dev/null
+++ b/mft-fs/archive/remotefs/server/server_manager.go
@@ -0,0 +1,148 @@
+package server
+
+import (
+ "context"
+ "github.com/jacobsa/fuse/fuseops"
+ "mft-fs/archive/osfsmanager"
+ remotefscomms2 "mft-fs/archive/remotefs/remotefscomms"
+ "os"
+ "time"
+)
+
+type Server struct {
+ remotefscomms2.UnimplementedRemoteFSCommsServer
+ manager *osfsmanager.OSFSManager
+}
+
+func NewServerHandler(root string) *Server {
+ output := &Server{
+ manager: osfsmanager.NewOSFSManager(root),
+ }
+ return output
+}
+
+func (server *Server) GetSizeComm(ctx context.Context, in *remotefscomms2.Empty) (*remotefscomms2.UintMsg, error) {
+ size, e := server.manager.GetSize()
+ if e != nil {
+ return nil, e
+ }
+ return &remotefscomms2.UintMsg{Data: size}, nil
+}
+
+func (server *Server) GetLengthComm(ctx context.Context, in *remotefscomms2.Empty) (*remotefscomms2.UintMsg, error) {
+ length, e := server.manager.GetLength()
+ if e != nil {
+ return nil, e
+ }
+ return &remotefscomms2.UintMsg{Data: length}, nil
+}
+
+func (server *Server) GetInfoComm(ctx context.Context, in *remotefscomms2.UintMsg) (*remotefscomms2.FileInfoMsg, error) {
+ info, e := server.manager.GetInfo(fuseops.InodeID(in.Data))
+ if e != nil {
+ return nil, e
+ }
+ output := &remotefscomms2.FileInfoMsg{
+ ChildrenIndexMap: make(map[string]uint32),
+ }
+ remotefscomms2.ConvertToComm(info, output)
+ return output, nil
+}
+
+func (server *Server) SetInfoComm(ctx context.Context, in *remotefscomms2.SetInfoParamsMsg) (*remotefscomms2.Empty, error) {
+ var uidptr *uint32 = nil
+ var gidptr *uint32 = nil
+ var sizeptr *uint64 = nil
+ var modeptr *os.FileMode = nil
+ var atimeptr *time.Time = nil
+ var mtimeptr *time.Time = nil
+ if in.Uid != -1 {
+ *uidptr = uint32(in.Uid)
+ }
+ if in.Gid != -1 {
+ *gidptr = uint32(in.Gid)
+ }
+ if in.Mode != -1 {
+ *modeptr = os.FileMode(in.Mode)
+ }
+ if in.Size != -1 {
+ *sizeptr = uint64(in.Size)
+ }
+ if !in.Atime.AsTime().Equal(time.Time{}) {
+ *atimeptr = in.Atime.AsTime()
+ }
+ if !in.Mtime.AsTime().Equal(time.Time{}) {
+ *mtimeptr = in.Mtime.AsTime()
+ }
+ e := server.manager.SetInfo(fuseops.InodeID(in.Inode), uidptr, gidptr, sizeptr, modeptr, atimeptr, mtimeptr)
+ if e != nil {
+ return nil, e
+ }
+ return &remotefscomms2.Empty{}, nil
+}
+
+func (server *Server) DeleteComm(ctx context.Context, in *remotefscomms2.UintMsg) (*remotefscomms2.Empty, error) {
+ e := server.manager.Delete(fuseops.InodeID(in.Data))
+ if e != nil {
+ return nil, e
+ }
+ return &remotefscomms2.Empty{}, nil
+}
+
+func (server *Server) MkDirComm(ctx context.Context, in *remotefscomms2.MkInodeMsg) (*remotefscomms2.UintMsg, error) {
+ inode, e := server.manager.MkDir(fuseops.InodeID(in.Parent), in.Name, os.FileMode(in.Mode))
+ if e != nil {
+ return nil, e
+ }
+ return &remotefscomms2.UintMsg{Data: uint64(inode)}, nil
+}
+
+func (server *Server) GenerateHandleComm(ctx context.Context, in *remotefscomms2.UintMsg) (*remotefscomms2.UintMsg, error) {
+ handle, e := server.manager.GenerateHandle(fuseops.InodeID(in.Data))
+ if e != nil {
+ return nil, e
+ }
+ return &remotefscomms2.UintMsg{Data: uint64(handle)}, nil
+}
+
+func (server *Server) CreateFileComm(ctx context.Context, in *remotefscomms2.MkInodeMsg) (*remotefscomms2.UintMsg, error) {
+ inode, e := server.manager.CreateFile(fuseops.InodeID(in.Parent), in.Name, os.FileMode(in.Mode))
+ if e != nil {
+ return nil, e
+ }
+ return &remotefscomms2.UintMsg{Data: uint64(inode)}, nil
+}
+
+func (server *Server) RmDirComm(ctx context.Context, in *remotefscomms2.UintMsg) (*remotefscomms2.Empty, error) {
+ e := server.manager.RmDir(fuseops.InodeID(in.Data))
+ if e != nil {
+ return nil, e
+ }
+ return &remotefscomms2.Empty{}, nil
+}
+
+func (server *Server) DeleteHandleComm(ctx context.Context, in *remotefscomms2.UintMsg) (*remotefscomms2.Empty, error) {
+ e := server.manager.DeleteHandle(fuseops.HandleID(in.Data))
+ if e != nil {
+ return nil, e
+ }
+ return &remotefscomms2.Empty{}, nil
+}
+
+func (server *Server) SyncFileComm(ctx context.Context, in *remotefscomms2.UintMsg) (*remotefscomms2.Empty, error) {
+ e := server.manager.SyncFile(fuseops.InodeID(in.Data))
+ if e != nil {
+ return nil, e
+ }
+ return &remotefscomms2.Empty{}, nil
+}
+
+func (server *Server) WriteAtComm(ctx context.Context, in *remotefscomms2.ContentMsg) (*remotefscomms2.UintMsg, error) {
+ n, _ := server.manager.WriteAt(fuseops.InodeID(in.Inode), in.Data, in.Off)
+ return &remotefscomms2.UintMsg{Data: uint64(n)}, nil
+}
+
+func (server *Server) ReadAtComm(ctx context.Context, in *remotefscomms2.ContentMsg) (*remotefscomms2.UintMsg, error) {
+ n, _ := server.manager.ReadAt(fuseops.InodeID(in.Inode), in.Data, in.Off)
+ return &remotefscomms2.UintMsg{Data: uint64(n)}, nil
+}
diff --git a/mft-fs/archive/remotefs/servermain/server_main.go b/mft-fs/archive/remotefs/servermain/server_main.go
new file mode 100644
index 00000000..aff14736
--- /dev/null
+++ b/mft-fs/archive/remotefs/servermain/server_main.go
@@ -0,0 +1,26 @@
+package main
+
+import (
+ "flag"
+ "google.golang.org/grpc"
+ "log"
+ "mft-fs/archive/remotefs/remotefscomms"
+ "mft-fs/archive/remotefs/server"
+ "net"
+)
+
+func main() {
+
+ rootDirectory := flag.String("rootDirectory", "", "Root Directory")
+ flag.Parse()
+
+ lis, e := net.Listen("tcp", ":8000")
+ if e != nil {
+ log.Fatalf("Error: %v\n", e)
+ }
+ defer lis.Close()
+
+ s := grpc.NewServer()
+ remotefscomms.RegisterRemoteFSCommsServer(s, server.NewServerHandler(*rootDirectory))
+ s.Serve(lis)
+}
diff --git a/mft-fs/archive/safe-remotefs/client/client_manager.go b/mft-fs/archive/safe-remotefs/client/client_manager.go
new file mode 100644
index 00000000..7aca84c0
--- /dev/null
+++ b/mft-fs/archive/safe-remotefs/client/client_manager.go
@@ -0,0 +1,302 @@
+package client
+
+import (
+ "context"
+ "crypto/rand"
+ "errors"
+ "fmt"
+ "github.com/jacobsa/fuse/fuseops"
+ "google.golang.org/grpc"
+ "google.golang.org/protobuf/types/known/timestamppb"
+ "mft-fs/archive/abstractfs"
+ safe_remotefscomms2 "mft-fs/archive/safe-remotefs/safe-remotefscomms"
+ "os"
+ "time"
+)
+
+type cacheInfo struct {
+ cache bool
+ cacheTime time.Time
+ handle fuseops.HandleID
+}
+
+func minimum(a int, b int) int {
+ if a < b {
+ return a
+ }
+ return b
+}
+
+func newCacheInfo() *cacheInfo {
+ return &cacheInfo{
+ cache: false,
+ cacheTime: time.Unix(0, 0),
+ handle: fuseops.HandleID(0),
+ }
+}
+
+type ClientManager struct {
+ abstractfs.FSManager
+ client safe_remotefscomms2.RemoteFSCommsClient
+ cachePath string
+ localInfo map[fuseops.InodeID]*cacheInfo
+ handleToInode map[fuseops.HandleID]fuseops.InodeID
+}
+
+func NewClientManager(conn *grpc.ClientConn, cachePath string) (*ClientManager, error) {
+ output := &ClientManager{
+ cachePath: cachePath,
+ localInfo: make(map[fuseops.InodeID]*cacheInfo),
+ handleToInode: make(map[fuseops.HandleID]fuseops.InodeID),
+ }
+ output.client = safe_remotefscomms2.NewRemoteFSCommsClient(conn)
+ return output, nil
+}
+
+func (manager *ClientManager) GetSize() (uint64, error) {
+ resp, e := manager.client.GetSizeComm(context.Background(), &safe_remotefscomms2.Empty{})
+ if e != nil {
+ return 0, e
+ }
+ return resp.Data, nil
+}
+
+func (manager *ClientManager) GetLength() (uint64, error) {
+ resp, e := manager.client.GetLengthComm(context.Background(), &safe_remotefscomms2.Empty{})
+ if e != nil {
+ return 0, e
+ }
+ return resp.Data, nil
+}
+
+func (manager *ClientManager) GetInfo(inode fuseops.InodeID) (*abstractfs.FileInfo, error) {
+ resp, e := manager.client.GetInfoComm(context.Background(), &safe_remotefscomms2.UintMsg{
+ Data: uint64(inode),
+ })
+ if e != nil {
+ return nil, e
+ }
+ output := &abstractfs.FileInfo{
+ ChildrenIndexMap: make(map[string]int),
+ }
+ safe_remotefscomms2.ConvertFromComm(resp, output)
+ info, ok := manager.localInfo[inode]
+ if ok {
+ output.Handle = info.handle
+ }
+ return output, nil
+}
+
+func (manager *ClientManager) SetInfo(inode fuseops.InodeID, uidptr *uint32, gidptr *uint32, sizeptr *uint64, modeptr *os.FileMode, atimeptr *time.Time, mtimeptr *time.Time) error {
+ request := &safe_remotefscomms2.SetInfoParamsMsg{
+ Inode: uint64(inode),
+ Uid: -1,
+ Gid: -1,
+ Size: -1,
+ Mode: -1,
+ Atime: timestamppb.New(time.Time{}),
+ Mtime: timestamppb.New(time.Time{}),
+ }
+ if uidptr != nil {
+ request.Uid = int32(*uidptr)
+ }
+ if gidptr != nil {
+ request.Gid = int32(*gidptr)
+ }
+ if sizeptr != nil {
+ request.Size = int64(*sizeptr)
+ }
+ if modeptr != nil {
+ request.Mode = int32(*modeptr)
+ }
+ if atimeptr != nil {
+ request.Atime = timestamppb.New(*atimeptr)
+ }
+ if mtimeptr != nil {
+ request.Mtime = timestamppb.New(*mtimeptr)
+ }
+ _, e := manager.client.SetInfoComm(context.Background(), request)
+ return e
+}
+
+func (manager *ClientManager) Delete(inode fuseops.InodeID) error {
+ _, e := manager.client.DeleteComm(context.Background(), &safe_remotefscomms2.UintMsg{Data: uint64(inode)})
+ return e
+}
+
+func (manager *ClientManager) MkDir(parent fuseops.InodeID, name string, mode os.FileMode) (fuseops.InodeID, error) {
+ resp, e := manager.client.MkDirComm(context.Background(), &safe_remotefscomms2.MkInodeMsg{
+ Parent: uint64(parent),
+ Name: name,
+ Mode: uint32(mode),
+ })
+ if e != nil {
+ return 0, e
+ }
+ return fuseops.InodeID(resp.Data), nil
+}
+
+func (manager *ClientManager) GenerateHandle(inode fuseops.InodeID) (fuseops.HandleID, error) {
+ var buff [8]byte
+ _, e := rand.Read(buff[:])
+ if e != nil {
+ return 0, e
+ }
+ var output uint64 = 0
+ for i := 0; i < len(buff); i++ {
+ output = output | uint64(buff[i]<<(8*i))
+ }
+ handle := fuseops.HandleID(output)
+ _, ok := manager.handleToInode[handle]
+ if ok {
+ return manager.GenerateHandle(inode)
+ }
+ info, ok := manager.localInfo[inode]
+ if !ok {
+ manager.localInfo[inode] = newCacheInfo()
+ info = manager.localInfo[inode]
+ }
+ info.handle = handle
+ manager.handleToInode[handle] = inode
+ return handle, nil
+}
+func (manager *ClientManager) CreateFile(parent fuseops.InodeID, name string, mode os.FileMode) (fuseops.InodeID, error) {
+ resp, e := manager.client.CreateFileComm(context.Background(), &safe_remotefscomms2.MkInodeMsg{
+ Parent: uint64(parent),
+ Name: name,
+ Mode: uint32(mode),
+ })
+ if e != nil {
+ return 0, e
+ }
+ return fuseops.InodeID(resp.Data), nil
+}
+
+func (manager *ClientManager) RmDir(inode fuseops.InodeID) error {
+ _, e := manager.client.RmDirComm(context.Background(), &safe_remotefscomms2.UintMsg{Data: uint64(inode)})
+ return e
+}
+
+func (manager *ClientManager) DeleteHandle(handle fuseops.HandleID) error {
+ delete(manager.handleToInode, handle)
+ return nil
+}
+
+func (manager *ClientManager) SyncFile(inode fuseops.InodeID) error {
+ _, e := manager.client.SyncFileComm(context.Background(), &safe_remotefscomms2.UintMsg{Data: uint64(inode)})
+ return e
+}
+
+func (manager *ClientManager) WriteAt(inode fuseops.InodeID, data []byte, off int64) (n int, err error) {
+
+ info, ok := manager.localInfo[inode]
+ if !ok {
+ fmt.Println("cache map issue")
+ return 0, errors.New("local cache not updated")
+ }
+
+ msg := safe_remotefscomms2.RequestResourceMsg{
+ CacheTime: timestamppb.New(info.cacheTime),
+ Inode: uint64(inode),
+ Cache: info.cache,
+ }
+
+ requestResp, e := manager.client.RequestWriteComm(context.Background(), &msg)
+ if e != nil {
+ return 0, e
+ }
+
+ if requestResp.Success {
+ resp, e := manager.client.WriteAtComm(context.Background(), &safe_remotefscomms2.WriteAtMsg{
+ Inode: uint64(inode),
+ Data: data,
+ Off: off,
+ })
+ if e != nil {
+ return 0, e
+ }
+
+ ackResp, e := manager.client.AckWriteComm(context.Background(), &safe_remotefscomms2.UintMsg{Data: uint64(inode)})
+ if e != nil {
+ return 0, e
+ }
+
+ manager.localInfo[inode].cache = true
+ manager.localInfo[inode].cacheTime = ackResp.WriteTime.AsTime()
+
+ file, e := os.OpenFile(fmt.Sprintf("%s/file%d.txt", manager.cachePath, int(inode)), os.O_RDWR|os.O_CREATE, 777)
+ if e != nil {
+ return 0, e
+ }
+ _, e = file.WriteAt(data, off)
+ if e != nil {
+ return 0, e
+ }
+
+ return int(resp.Data), nil
+ }
+
+ fmt.Println("cache timing issue")
+ return 0, errors.New("local cache not updated")
+}
+func (manager *ClientManager) ReadAt(inode fuseops.InodeID, data []byte, off int64) (n int, err error) {
+
+ msg := safe_remotefscomms2.RequestResourceMsg{
+ CacheTime: timestamppb.New(time.Unix(0, 0)),
+ Inode: uint64(inode),
+ Cache: false,
+ }
+
+ info, ok := manager.localInfo[inode]
+ if ok {
+ msg.Cache = info.cache
+ msg.CacheTime = timestamppb.New(info.cacheTime)
+ } else {
+ manager.localInfo[inode] = newCacheInfo()
+ }
+
+ requestResp, e := manager.client.RequestReadComm(context.Background(), &msg)
+ if e != nil {
+ return 0, e
+ }
+
+ if requestResp.Success {
+ resp, e := manager.client.ReadAtComm(context.Background(), &safe_remotefscomms2.ReadAtMsg{
+ Inode: uint64(inode),
+ Size: int64(len(data)),
+ Off: off,
+ })
+ if e != nil {
+ return 0, e
+ }
+ ackResp, e := manager.client.AckReadComm(context.Background(), &safe_remotefscomms2.UintMsg{Data: uint64(inode)})
+ if e != nil {
+ return 0, e
+ }
+ manager.localInfo[inode].cacheTime = ackResp.WriteTime.AsTime()
+ manager.localInfo[inode].cache = true
+ for i := 0; i < minimum(len(data), len(resp.Data)); i++ {
+ data[i] = resp.Data[i]
+ }
+ file, e := os.OpenFile(fmt.Sprintf("%s/file%d.txt", manager.cachePath, int(inode)), os.O_RDWR|os.O_CREATE, 777)
+ if e != nil {
+ return 0, e
+ }
+ _, e = file.WriteAt(data, off)
+ if e != nil {
+ return 0, e
+ }
+ return int(resp.N), nil
+ } else {
+ file, e := os.OpenFile(fmt.Sprintf("%s/file%d.txt", manager.cachePath, int(inode)), os.O_RDWR, 777)
+ if e != nil {
+ return 0, e
+ }
+ n, _ := file.ReadAt(data, off)
+ return n, nil
+ }
+}
+
+func (manager *ClientManager) Destroy() error {
+ return nil
+}
diff --git a/mft-fs/archive/safe-remotefs/clientmain/client_main.go b/mft-fs/archive/safe-remotefs/clientmain/client_main.go
new file mode 100644
index 00000000..813617ad
--- /dev/null
+++ b/mft-fs/archive/safe-remotefs/clientmain/client_main.go
@@ -0,0 +1,55 @@
+package main
+
+import (
+ "context"
+ "flag"
+ "github.com/jacobsa/fuse"
+ "github.com/jacobsa/fuse/fuseutil"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/credentials/insecure"
+ "log"
+ "mft-fs/archive/abstractfs"
+ "mft-fs/archive/safe-remotefs/client"
+ "os"
+)
+
+func main() {
+
+ // reading commandline args
+ mountDirectory := flag.String("mountDirectory", "", "mount directory")
+ cacheDirectory := flag.String("cacheDirectory", "", "cache directory")
+ flag.Parse()
+
+ // setting up gRPC communicators
+ var opts []grpc.DialOption
+ opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))
+ conn, e := grpc.NewClient(":8000", opts...)
+ if e != nil {
+ log.Fatalf("Error: %v\n", e)
+ }
+ defer conn.Close()
+
+ // setting up FUSE
+ manager, e := client.NewClientManager(conn, *cacheDirectory)
+ if e != nil {
+ log.Fatalf("Error: %v\n", e)
+ }
+ fs, _ := abstractfs.NewAbstractFS(manager)
+ server := fuseutil.NewFileSystemServer(&fs)
+
+ // mount the filesystem
+ cfg := &fuse.MountConfig{
+ ReadOnly: false,
+ DebugLogger: log.New(os.Stderr, "fuse: ", 0),
+ ErrorLogger: log.New(os.Stderr, "fuse: ", 0),
+ }
+ mfs, err := fuse.Mount(*mountDirectory, server, cfg)
+ if err != nil {
+ log.Fatalf("Mount: %v", err)
+ }
+
+ // wait for it to be unmounted
+ if err = mfs.Join(context.Background()); err != nil {
+ log.Fatalf("Join: %v", err)
+ }
+}
diff --git a/mft-fs/archive/safe-remotefs/comm.proto b/mft-fs/archive/safe-remotefs/comm.proto
new file mode 100644
index 00000000..35adeb3e
--- /dev/null
+++ b/mft-fs/archive/safe-remotefs/comm.proto
@@ -0,0 +1,143 @@
+syntax = "proto3";
+package safe_remotefscomms;
+
+option go_package="./safe-remotefscomms";
+
+import "google/protobuf/timestamp.proto";
+
+/*
+Complete FileInfo struct
+ - GetInfo (response)
+*/
+message FileInfoMsg {
+ string name = 1;
+ string path = 2;
+ uint64 inode = 3;
+ repeated uint64 children = 4;
+ map childrenIndexMap = 5;
+ uint64 parent = 6;
+ uint32 nlink = 7;
+ uint64 size = 8;
+ uint32 mode = 9;
+ google.protobuf.Timestamp atime = 10;
+ google.protobuf.Timestamp mtime = 11;
+ google.protobuf.Timestamp ctime = 12;
+ google.protobuf.Timestamp crtime = 13;
+ uint32 uid = 14;
+ uint32 gid = 15;
+ uint32 direntType = 16;
+ uint64 handle = 17;
+}
+
+/*
+Sending a single uint64
+ - GetSize (response)
+ - GetLength (response)
+ - GetInfo (request)
+ - Delete (request)
+ - MkDir (response)
+ - GenerateHandle (request, response)
+ - CreateFile (response)
+ - RmDir (request)
+ - DeleteHandle (request)
+ - SyncFile (request)
+*/
+message UintMsg {
+ uint64 data = 1;
+}
+
+/*
+Sending file contents
+ - WriteAt
+*/
+message WriteAtMsg {
+ uint64 inode = 1;
+ bytes data = 2;
+ int64 off = 3;
+}
+
+message ReadAtMsg {
+ uint64 inode = 1;
+ int64 size = 2;
+ int64 off = 3;
+}
+
+message ReadAtResponseMsg {
+ int64 n = 1;
+ bytes data = 2;
+}
+
+/*
+SetInfoParamsMsg
+ - SetInfo (request)
+*/
+message SetInfoParamsMsg {
+ uint64 inode = 1;
+ int32 uid = 2;
+ int32 gid = 3;
+ int64 size = 4;
+ int32 mode = 5;
+ google.protobuf.Timestamp atime = 6;
+ google.protobuf.Timestamp mtime = 7;
+}
+
+/*
+MkInodeMsg
+ - MkDir (request)
+ - CreateFile (request)
+*/
+message MkInodeMsg {
+ uint64 parent = 1;
+ string name = 2;
+ uint32 mode = 3;
+}
+
+/*
+RequestResourceMsg
+ - RequestRead
+ - RequestWrite
+ */
+message RequestResourceMsg {
+ uint64 inode = 1;
+ bool cache = 2;
+ google.protobuf.Timestamp cacheTime = 3;
+}
+
+/*
+RequestResponseMsg
+ - RequestRead
+ - RequestWrite
+ */
+message RequestResponseMsg {
+ bool success = 1;
+}
+
+/*
+AckResponseMsg
+ - AckRead
+ - AckWrite
+ */
+message AckResponseMsg {
+ google.protobuf.Timestamp writeTime = 1;
+}
+
+/*Empty Message*/
+message Empty {}
+
+service RemoteFSComms {
+ rpc GetSizeComm(Empty) returns (UintMsg) {}
+ rpc GetLengthComm(Empty) returns (UintMsg) {}
+ rpc GetInfoComm(UintMsg) returns (FileInfoMsg) {}
+ rpc SetInfoComm(SetInfoParamsMsg) returns (Empty) {}
+ rpc DeleteComm(UintMsg) returns (Empty) {}
+ rpc MkDirComm(MkInodeMsg) returns (UintMsg) {}
+ rpc CreateFileComm(MkInodeMsg) returns (UintMsg) {}
+ rpc RmDirComm(UintMsg) returns (Empty) {}
+ rpc SyncFileComm(UintMsg) returns (Empty) {}
+ rpc WriteAtComm(WriteAtMsg) returns (UintMsg) {}
+ rpc ReadAtComm(ReadAtMsg) returns (ReadAtResponseMsg) {}
+ rpc RequestReadComm(RequestResourceMsg) returns (RequestResponseMsg) {}
+ rpc RequestWriteComm(RequestResourceMsg) returns (RequestResponseMsg) {}
+ rpc AckReadComm(UintMsg) returns (AckResponseMsg) {}
+ rpc AckWriteComm(UintMsg) returns (AckResponseMsg) {}
+}
diff --git a/mft-fs/archive/safe-remotefs/safe-remotefscomms/comm.pb.go b/mft-fs/archive/safe-remotefs/safe-remotefscomms/comm.pb.go
new file mode 100644
index 00000000..69636763
--- /dev/null
+++ b/mft-fs/archive/safe-remotefs/safe-remotefscomms/comm.pb.go
@@ -0,0 +1,1221 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.34.2
+// protoc v5.27.1
+// source: comm.proto
+
+package safe_remotefscomms
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ timestamppb "google.golang.org/protobuf/types/known/timestamppb"
+ reflect "reflect"
+ sync "sync"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// Complete FileInfo struct
+// - GetInfo (response)
+type FileInfoMsg struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"`
+ Inode uint64 `protobuf:"varint,3,opt,name=inode,proto3" json:"inode,omitempty"`
+ Children []uint64 `protobuf:"varint,4,rep,packed,name=children,proto3" json:"children,omitempty"`
+ ChildrenIndexMap map[string]uint32 `protobuf:"bytes,5,rep,name=childrenIndexMap,proto3" json:"childrenIndexMap,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"`
+ Parent uint64 `protobuf:"varint,6,opt,name=parent,proto3" json:"parent,omitempty"`
+ Nlink uint32 `protobuf:"varint,7,opt,name=nlink,proto3" json:"nlink,omitempty"`
+ Size uint64 `protobuf:"varint,8,opt,name=size,proto3" json:"size,omitempty"`
+ Mode uint32 `protobuf:"varint,9,opt,name=mode,proto3" json:"mode,omitempty"`
+ Atime *timestamppb.Timestamp `protobuf:"bytes,10,opt,name=atime,proto3" json:"atime,omitempty"`
+ Mtime *timestamppb.Timestamp `protobuf:"bytes,11,opt,name=mtime,proto3" json:"mtime,omitempty"`
+ Ctime *timestamppb.Timestamp `protobuf:"bytes,12,opt,name=ctime,proto3" json:"ctime,omitempty"`
+ Crtime *timestamppb.Timestamp `protobuf:"bytes,13,opt,name=crtime,proto3" json:"crtime,omitempty"`
+ Uid uint32 `protobuf:"varint,14,opt,name=uid,proto3" json:"uid,omitempty"`
+ Gid uint32 `protobuf:"varint,15,opt,name=gid,proto3" json:"gid,omitempty"`
+ DirentType uint32 `protobuf:"varint,16,opt,name=direntType,proto3" json:"direntType,omitempty"`
+ Handle uint64 `protobuf:"varint,17,opt,name=handle,proto3" json:"handle,omitempty"`
+}
+
+func (x *FileInfoMsg) Reset() {
+ *x = FileInfoMsg{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_comm_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *FileInfoMsg) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*FileInfoMsg) ProtoMessage() {}
+
+func (x *FileInfoMsg) ProtoReflect() protoreflect.Message {
+ mi := &file_comm_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use FileInfoMsg.ProtoReflect.Descriptor instead.
+func (*FileInfoMsg) Descriptor() ([]byte, []int) {
+ return file_comm_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *FileInfoMsg) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *FileInfoMsg) GetPath() string {
+ if x != nil {
+ return x.Path
+ }
+ return ""
+}
+
+func (x *FileInfoMsg) GetInode() uint64 {
+ if x != nil {
+ return x.Inode
+ }
+ return 0
+}
+
+func (x *FileInfoMsg) GetChildren() []uint64 {
+ if x != nil {
+ return x.Children
+ }
+ return nil
+}
+
+func (x *FileInfoMsg) GetChildrenIndexMap() map[string]uint32 {
+ if x != nil {
+ return x.ChildrenIndexMap
+ }
+ return nil
+}
+
+func (x *FileInfoMsg) GetParent() uint64 {
+ if x != nil {
+ return x.Parent
+ }
+ return 0
+}
+
+func (x *FileInfoMsg) GetNlink() uint32 {
+ if x != nil {
+ return x.Nlink
+ }
+ return 0
+}
+
+func (x *FileInfoMsg) GetSize() uint64 {
+ if x != nil {
+ return x.Size
+ }
+ return 0
+}
+
+func (x *FileInfoMsg) GetMode() uint32 {
+ if x != nil {
+ return x.Mode
+ }
+ return 0
+}
+
+func (x *FileInfoMsg) GetAtime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.Atime
+ }
+ return nil
+}
+
+func (x *FileInfoMsg) GetMtime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.Mtime
+ }
+ return nil
+}
+
+func (x *FileInfoMsg) GetCtime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.Ctime
+ }
+ return nil
+}
+
+func (x *FileInfoMsg) GetCrtime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.Crtime
+ }
+ return nil
+}
+
+func (x *FileInfoMsg) GetUid() uint32 {
+ if x != nil {
+ return x.Uid
+ }
+ return 0
+}
+
+func (x *FileInfoMsg) GetGid() uint32 {
+ if x != nil {
+ return x.Gid
+ }
+ return 0
+}
+
+func (x *FileInfoMsg) GetDirentType() uint32 {
+ if x != nil {
+ return x.DirentType
+ }
+ return 0
+}
+
+func (x *FileInfoMsg) GetHandle() uint64 {
+ if x != nil {
+ return x.Handle
+ }
+ return 0
+}
+
+// Sending a single uint64
+// - GetSize (response)
+// - GetLength (response)
+// - GetInfo (request)
+// - Delete (request)
+// - MkDir (response)
+// - GenerateHandle (request, response)
+// - CreateFile (response)
+// - RmDir (request)
+// - DeleteHandle (request)
+// - SyncFile (request)
+type UintMsg struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Data uint64 `protobuf:"varint,1,opt,name=data,proto3" json:"data,omitempty"`
+}
+
+func (x *UintMsg) Reset() {
+ *x = UintMsg{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_comm_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *UintMsg) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UintMsg) ProtoMessage() {}
+
+func (x *UintMsg) ProtoReflect() protoreflect.Message {
+ mi := &file_comm_proto_msgTypes[1]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use UintMsg.ProtoReflect.Descriptor instead.
+func (*UintMsg) Descriptor() ([]byte, []int) {
+ return file_comm_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *UintMsg) GetData() uint64 {
+ if x != nil {
+ return x.Data
+ }
+ return 0
+}
+
+// Sending file contents
+// - WriteAt
+type WriteAtMsg struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Inode uint64 `protobuf:"varint,1,opt,name=inode,proto3" json:"inode,omitempty"`
+ Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
+ Off int64 `protobuf:"varint,3,opt,name=off,proto3" json:"off,omitempty"`
+}
+
+func (x *WriteAtMsg) Reset() {
+ *x = WriteAtMsg{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_comm_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *WriteAtMsg) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*WriteAtMsg) ProtoMessage() {}
+
+func (x *WriteAtMsg) ProtoReflect() protoreflect.Message {
+ mi := &file_comm_proto_msgTypes[2]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use WriteAtMsg.ProtoReflect.Descriptor instead.
+func (*WriteAtMsg) Descriptor() ([]byte, []int) {
+ return file_comm_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *WriteAtMsg) GetInode() uint64 {
+ if x != nil {
+ return x.Inode
+ }
+ return 0
+}
+
+func (x *WriteAtMsg) GetData() []byte {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
+
+func (x *WriteAtMsg) GetOff() int64 {
+ if x != nil {
+ return x.Off
+ }
+ return 0
+}
+
+type ReadAtMsg struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Inode uint64 `protobuf:"varint,1,opt,name=inode,proto3" json:"inode,omitempty"`
+ Size int64 `protobuf:"varint,2,opt,name=size,proto3" json:"size,omitempty"`
+ Off int64 `protobuf:"varint,3,opt,name=off,proto3" json:"off,omitempty"`
+}
+
+func (x *ReadAtMsg) Reset() {
+ *x = ReadAtMsg{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_comm_proto_msgTypes[3]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ReadAtMsg) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReadAtMsg) ProtoMessage() {}
+
+func (x *ReadAtMsg) ProtoReflect() protoreflect.Message {
+ mi := &file_comm_proto_msgTypes[3]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReadAtMsg.ProtoReflect.Descriptor instead.
+func (*ReadAtMsg) Descriptor() ([]byte, []int) {
+ return file_comm_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *ReadAtMsg) GetInode() uint64 {
+ if x != nil {
+ return x.Inode
+ }
+ return 0
+}
+
+func (x *ReadAtMsg) GetSize() int64 {
+ if x != nil {
+ return x.Size
+ }
+ return 0
+}
+
+func (x *ReadAtMsg) GetOff() int64 {
+ if x != nil {
+ return x.Off
+ }
+ return 0
+}
+
+type ReadAtResponseMsg struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ N int64 `protobuf:"varint,1,opt,name=n,proto3" json:"n,omitempty"`
+ Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
+}
+
+func (x *ReadAtResponseMsg) Reset() {
+ *x = ReadAtResponseMsg{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_comm_proto_msgTypes[4]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ReadAtResponseMsg) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReadAtResponseMsg) ProtoMessage() {}
+
+func (x *ReadAtResponseMsg) ProtoReflect() protoreflect.Message {
+ mi := &file_comm_proto_msgTypes[4]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReadAtResponseMsg.ProtoReflect.Descriptor instead.
+func (*ReadAtResponseMsg) Descriptor() ([]byte, []int) {
+ return file_comm_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *ReadAtResponseMsg) GetN() int64 {
+ if x != nil {
+ return x.N
+ }
+ return 0
+}
+
+func (x *ReadAtResponseMsg) GetData() []byte {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
+
+// SetInfoParamsMsg
+// - SetInfo (request)
+type SetInfoParamsMsg struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Inode uint64 `protobuf:"varint,1,opt,name=inode,proto3" json:"inode,omitempty"`
+ Uid int32 `protobuf:"varint,2,opt,name=uid,proto3" json:"uid,omitempty"`
+ Gid int32 `protobuf:"varint,3,opt,name=gid,proto3" json:"gid,omitempty"`
+ Size int64 `protobuf:"varint,4,opt,name=size,proto3" json:"size,omitempty"`
+ Mode int32 `protobuf:"varint,5,opt,name=mode,proto3" json:"mode,omitempty"`
+ Atime *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=atime,proto3" json:"atime,omitempty"`
+ Mtime *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=mtime,proto3" json:"mtime,omitempty"`
+}
+
+func (x *SetInfoParamsMsg) Reset() {
+ *x = SetInfoParamsMsg{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_comm_proto_msgTypes[5]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *SetInfoParamsMsg) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SetInfoParamsMsg) ProtoMessage() {}
+
+func (x *SetInfoParamsMsg) ProtoReflect() protoreflect.Message {
+ mi := &file_comm_proto_msgTypes[5]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use SetInfoParamsMsg.ProtoReflect.Descriptor instead.
+func (*SetInfoParamsMsg) Descriptor() ([]byte, []int) {
+ return file_comm_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *SetInfoParamsMsg) GetInode() uint64 {
+ if x != nil {
+ return x.Inode
+ }
+ return 0
+}
+
+func (x *SetInfoParamsMsg) GetUid() int32 {
+ if x != nil {
+ return x.Uid
+ }
+ return 0
+}
+
+func (x *SetInfoParamsMsg) GetGid() int32 {
+ if x != nil {
+ return x.Gid
+ }
+ return 0
+}
+
+func (x *SetInfoParamsMsg) GetSize() int64 {
+ if x != nil {
+ return x.Size
+ }
+ return 0
+}
+
+func (x *SetInfoParamsMsg) GetMode() int32 {
+ if x != nil {
+ return x.Mode
+ }
+ return 0
+}
+
+func (x *SetInfoParamsMsg) GetAtime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.Atime
+ }
+ return nil
+}
+
+func (x *SetInfoParamsMsg) GetMtime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.Mtime
+ }
+ return nil
+}
+
+// MkInodeMsg
+// - MkDir (request)
+// - CreateFile (request)
+type MkInodeMsg struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Parent uint64 `protobuf:"varint,1,opt,name=parent,proto3" json:"parent,omitempty"`
+ Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
+ Mode uint32 `protobuf:"varint,3,opt,name=mode,proto3" json:"mode,omitempty"`
+}
+
+func (x *MkInodeMsg) Reset() {
+ *x = MkInodeMsg{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_comm_proto_msgTypes[6]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *MkInodeMsg) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MkInodeMsg) ProtoMessage() {}
+
+func (x *MkInodeMsg) ProtoReflect() protoreflect.Message {
+ mi := &file_comm_proto_msgTypes[6]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use MkInodeMsg.ProtoReflect.Descriptor instead.
+func (*MkInodeMsg) Descriptor() ([]byte, []int) {
+ return file_comm_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *MkInodeMsg) GetParent() uint64 {
+ if x != nil {
+ return x.Parent
+ }
+ return 0
+}
+
+func (x *MkInodeMsg) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *MkInodeMsg) GetMode() uint32 {
+ if x != nil {
+ return x.Mode
+ }
+ return 0
+}
+
+// RequestResourceMsg
+// - RequestRead
+// - RequestWrite
+type RequestResourceMsg struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Inode uint64 `protobuf:"varint,1,opt,name=inode,proto3" json:"inode,omitempty"`
+ Cache bool `protobuf:"varint,2,opt,name=cache,proto3" json:"cache,omitempty"`
+ CacheTime *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=cacheTime,proto3" json:"cacheTime,omitempty"`
+}
+
+func (x *RequestResourceMsg) Reset() {
+ *x = RequestResourceMsg{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_comm_proto_msgTypes[7]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *RequestResourceMsg) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RequestResourceMsg) ProtoMessage() {}
+
+func (x *RequestResourceMsg) ProtoReflect() protoreflect.Message {
+ mi := &file_comm_proto_msgTypes[7]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use RequestResourceMsg.ProtoReflect.Descriptor instead.
+func (*RequestResourceMsg) Descriptor() ([]byte, []int) {
+ return file_comm_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *RequestResourceMsg) GetInode() uint64 {
+ if x != nil {
+ return x.Inode
+ }
+ return 0
+}
+
+func (x *RequestResourceMsg) GetCache() bool {
+ if x != nil {
+ return x.Cache
+ }
+ return false
+}
+
+func (x *RequestResourceMsg) GetCacheTime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.CacheTime
+ }
+ return nil
+}
+
+// RequestResponseMsg
+// - RequestRead
+// - RequestWrite
+type RequestResponseMsg struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
+}
+
+func (x *RequestResponseMsg) Reset() {
+ *x = RequestResponseMsg{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_comm_proto_msgTypes[8]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *RequestResponseMsg) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RequestResponseMsg) ProtoMessage() {}
+
+func (x *RequestResponseMsg) ProtoReflect() protoreflect.Message {
+ mi := &file_comm_proto_msgTypes[8]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use RequestResponseMsg.ProtoReflect.Descriptor instead.
+func (*RequestResponseMsg) Descriptor() ([]byte, []int) {
+ return file_comm_proto_rawDescGZIP(), []int{8}
+}
+
+func (x *RequestResponseMsg) GetSuccess() bool {
+ if x != nil {
+ return x.Success
+ }
+ return false
+}
+
+// AckResponseMsg
+// - AckRead
+// - AckWrite
+type AckResponseMsg struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ WriteTime *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=writeTime,proto3" json:"writeTime,omitempty"`
+}
+
+func (x *AckResponseMsg) Reset() {
+ *x = AckResponseMsg{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_comm_proto_msgTypes[9]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *AckResponseMsg) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AckResponseMsg) ProtoMessage() {}
+
+func (x *AckResponseMsg) ProtoReflect() protoreflect.Message {
+ mi := &file_comm_proto_msgTypes[9]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use AckResponseMsg.ProtoReflect.Descriptor instead.
+func (*AckResponseMsg) Descriptor() ([]byte, []int) {
+ return file_comm_proto_rawDescGZIP(), []int{9}
+}
+
+func (x *AckResponseMsg) GetWriteTime() *timestamppb.Timestamp {
+ if x != nil {
+ return x.WriteTime
+ }
+ return nil
+}
+
+// Empty Message
+type Empty struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+}
+
+func (x *Empty) Reset() {
+ *x = Empty{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_comm_proto_msgTypes[10]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *Empty) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Empty) ProtoMessage() {}
+
+func (x *Empty) ProtoReflect() protoreflect.Message {
+ mi := &file_comm_proto_msgTypes[10]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Empty.ProtoReflect.Descriptor instead.
+func (*Empty) Descriptor() ([]byte, []int) {
+ return file_comm_proto_rawDescGZIP(), []int{10}
+}
+
+var File_comm_proto protoreflect.FileDescriptor
+
+var file_comm_proto_rawDesc = []byte{
+ 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x12, 0x73, 0x61,
+ 0x66, 0x65, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73,
+ 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
+ 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x22, 0x8b, 0x05, 0x0a, 0x0b, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x4d, 0x73,
+ 0x67, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x6f,
+ 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x69, 0x6e, 0x6f, 0x64, 0x65, 0x12,
+ 0x1a, 0x0a, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x03, 0x28,
+ 0x04, 0x52, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x12, 0x61, 0x0a, 0x10, 0x63,
+ 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x4d, 0x61, 0x70, 0x18,
+ 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x72, 0x65, 0x6d,
+ 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x49,
+ 0x6e, 0x66, 0x6f, 0x4d, 0x73, 0x67, 0x2e, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x49,
+ 0x6e, 0x64, 0x65, 0x78, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x10, 0x63, 0x68,
+ 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x4d, 0x61, 0x70, 0x12, 0x16,
+ 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06,
+ 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x18,
+ 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x12, 0x0a, 0x04,
+ 0x73, 0x69, 0x7a, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65,
+ 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04,
+ 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x30, 0x0a, 0x05, 0x61, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0a, 0x20,
+ 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52,
+ 0x05, 0x61, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x30, 0x0a, 0x05, 0x6d, 0x74, 0x69, 0x6d, 0x65, 0x18,
+ 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
+ 0x70, 0x52, 0x05, 0x6d, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x30, 0x0a, 0x05, 0x63, 0x74, 0x69, 0x6d,
+ 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74,
+ 0x61, 0x6d, 0x70, 0x52, 0x05, 0x63, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x32, 0x0a, 0x06, 0x63, 0x72,
+ 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d,
+ 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x06, 0x63, 0x72, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x10,
+ 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x75, 0x69, 0x64,
+ 0x12, 0x10, 0x0a, 0x03, 0x67, 0x69, 0x64, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x67,
+ 0x69, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x69, 0x72, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65,
+ 0x18, 0x10, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x64, 0x69, 0x72, 0x65, 0x6e, 0x74, 0x54, 0x79,
+ 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x18, 0x11, 0x20, 0x01,
+ 0x28, 0x04, 0x52, 0x06, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x1a, 0x43, 0x0a, 0x15, 0x43, 0x68,
+ 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x4d, 0x61, 0x70, 0x45, 0x6e,
+ 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22,
+ 0x1d, 0x0a, 0x07, 0x55, 0x69, 0x6e, 0x74, 0x4d, 0x73, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61,
+ 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x48,
+ 0x0a, 0x0a, 0x57, 0x72, 0x69, 0x74, 0x65, 0x41, 0x74, 0x4d, 0x73, 0x67, 0x12, 0x14, 0x0a, 0x05,
+ 0x69, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x69, 0x6e, 0x6f,
+ 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c,
+ 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x10, 0x0a, 0x03, 0x6f, 0x66, 0x66, 0x18, 0x03, 0x20,
+ 0x01, 0x28, 0x03, 0x52, 0x03, 0x6f, 0x66, 0x66, 0x22, 0x47, 0x0a, 0x09, 0x52, 0x65, 0x61, 0x64,
+ 0x41, 0x74, 0x4d, 0x73, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01,
+ 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x69, 0x6e, 0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73,
+ 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12,
+ 0x10, 0x0a, 0x03, 0x6f, 0x66, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6f, 0x66,
+ 0x66, 0x22, 0x35, 0x0a, 0x11, 0x52, 0x65, 0x61, 0x64, 0x41, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f,
+ 0x6e, 0x73, 0x65, 0x4d, 0x73, 0x67, 0x12, 0x0c, 0x0a, 0x01, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28,
+ 0x03, 0x52, 0x01, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01,
+ 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0xd8, 0x01, 0x0a, 0x10, 0x53, 0x65, 0x74,
+ 0x49, 0x6e, 0x66, 0x6f, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x4d, 0x73, 0x67, 0x12, 0x14, 0x0a,
+ 0x05, 0x69, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x69, 0x6e,
+ 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05,
+ 0x52, 0x03, 0x75, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01,
+ 0x28, 0x05, 0x52, 0x03, 0x67, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18,
+ 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6d,
+ 0x6f, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12,
+ 0x30, 0x0a, 0x05, 0x61, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a,
+ 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
+ 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x61, 0x74, 0x69, 0x6d,
+ 0x65, 0x12, 0x30, 0x0a, 0x05, 0x6d, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b,
+ 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
+ 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x6d, 0x74,
+ 0x69, 0x6d, 0x65, 0x22, 0x4c, 0x0a, 0x0a, 0x4d, 0x6b, 0x49, 0x6e, 0x6f, 0x64, 0x65, 0x4d, 0x73,
+ 0x67, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28,
+ 0x04, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d,
+ 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a,
+ 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x6d, 0x6f, 0x64,
+ 0x65, 0x22, 0x7a, 0x0a, 0x12, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f,
+ 0x75, 0x72, 0x63, 0x65, 0x4d, 0x73, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x6f, 0x64, 0x65,
+ 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x69, 0x6e, 0x6f, 0x64, 0x65, 0x12, 0x14, 0x0a,
+ 0x05, 0x63, 0x61, 0x63, 0x68, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x63, 0x61,
+ 0x63, 0x68, 0x65, 0x12, 0x38, 0x0a, 0x09, 0x63, 0x61, 0x63, 0x68, 0x65, 0x54, 0x69, 0x6d, 0x65,
+ 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
+ 0x6d, 0x70, 0x52, 0x09, 0x63, 0x61, 0x63, 0x68, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x2e, 0x0a,
+ 0x12, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+ 0x4d, 0x73, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01,
+ 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x4a, 0x0a,
+ 0x0e, 0x41, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x73, 0x67, 0x12,
+ 0x38, 0x0a, 0x09, 0x77, 0x72, 0x69, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09,
+ 0x77, 0x72, 0x69, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x07, 0x0a, 0x05, 0x45, 0x6d, 0x70,
+ 0x74, 0x79, 0x32, 0xce, 0x09, 0x0a, 0x0d, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x46, 0x53, 0x43,
+ 0x6f, 0x6d, 0x6d, 0x73, 0x12, 0x47, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x43,
+ 0x6f, 0x6d, 0x6d, 0x12, 0x19, 0x2e, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x74,
+ 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1b,
+ 0x2e, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f,
+ 0x6d, 0x6d, 0x73, 0x2e, 0x55, 0x69, 0x6e, 0x74, 0x4d, 0x73, 0x67, 0x22, 0x00, 0x12, 0x49, 0x0a,
+ 0x0d, 0x47, 0x65, 0x74, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x43, 0x6f, 0x6d, 0x6d, 0x12, 0x19,
+ 0x2e, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f,
+ 0x6d, 0x6d, 0x73, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1b, 0x2e, 0x73, 0x61, 0x66, 0x65,
+ 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x55,
+ 0x69, 0x6e, 0x74, 0x4d, 0x73, 0x67, 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x49,
+ 0x6e, 0x66, 0x6f, 0x43, 0x6f, 0x6d, 0x6d, 0x12, 0x1b, 0x2e, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x72,
+ 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x55, 0x69, 0x6e,
+ 0x74, 0x4d, 0x73, 0x67, 0x1a, 0x1f, 0x2e, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x72, 0x65, 0x6d, 0x6f,
+ 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e,
+ 0x66, 0x6f, 0x4d, 0x73, 0x67, 0x22, 0x00, 0x12, 0x50, 0x0a, 0x0b, 0x53, 0x65, 0x74, 0x49, 0x6e,
+ 0x66, 0x6f, 0x43, 0x6f, 0x6d, 0x6d, 0x12, 0x24, 0x2e, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x72, 0x65,
+ 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x53, 0x65, 0x74, 0x49,
+ 0x6e, 0x66, 0x6f, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x4d, 0x73, 0x67, 0x1a, 0x19, 0x2e, 0x73,
+ 0x61, 0x66, 0x65, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d,
+ 0x73, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x46, 0x0a, 0x0a, 0x44, 0x65, 0x6c,
+ 0x65, 0x74, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x12, 0x1b, 0x2e, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x72,
+ 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x55, 0x69, 0x6e,
+ 0x74, 0x4d, 0x73, 0x67, 0x1a, 0x19, 0x2e, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x72, 0x65, 0x6d, 0x6f,
+ 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22,
+ 0x00, 0x12, 0x4a, 0x0a, 0x09, 0x4d, 0x6b, 0x44, 0x69, 0x72, 0x43, 0x6f, 0x6d, 0x6d, 0x12, 0x1e,
+ 0x2e, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f,
+ 0x6d, 0x6d, 0x73, 0x2e, 0x4d, 0x6b, 0x49, 0x6e, 0x6f, 0x64, 0x65, 0x4d, 0x73, 0x67, 0x1a, 0x1b,
+ 0x2e, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f,
+ 0x6d, 0x6d, 0x73, 0x2e, 0x55, 0x69, 0x6e, 0x74, 0x4d, 0x73, 0x67, 0x22, 0x00, 0x12, 0x4f, 0x0a,
+ 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x12,
+ 0x1e, 0x2e, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63,
+ 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x4d, 0x6b, 0x49, 0x6e, 0x6f, 0x64, 0x65, 0x4d, 0x73, 0x67, 0x1a,
+ 0x1b, 0x2e, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63,
+ 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x55, 0x69, 0x6e, 0x74, 0x4d, 0x73, 0x67, 0x22, 0x00, 0x12, 0x45,
+ 0x0a, 0x09, 0x52, 0x6d, 0x44, 0x69, 0x72, 0x43, 0x6f, 0x6d, 0x6d, 0x12, 0x1b, 0x2e, 0x73, 0x61,
+ 0x66, 0x65, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73,
+ 0x2e, 0x55, 0x69, 0x6e, 0x74, 0x4d, 0x73, 0x67, 0x1a, 0x19, 0x2e, 0x73, 0x61, 0x66, 0x65, 0x5f,
+ 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x45, 0x6d,
+ 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x48, 0x0a, 0x0c, 0x53, 0x79, 0x6e, 0x63, 0x46, 0x69, 0x6c,
+ 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x12, 0x1b, 0x2e, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x72, 0x65, 0x6d,
+ 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x55, 0x69, 0x6e, 0x74, 0x4d,
+ 0x73, 0x67, 0x1a, 0x19, 0x2e, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65,
+ 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12,
+ 0x4c, 0x0a, 0x0b, 0x57, 0x72, 0x69, 0x74, 0x65, 0x41, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x12, 0x1e,
+ 0x2e, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f,
+ 0x6d, 0x6d, 0x73, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x41, 0x74, 0x4d, 0x73, 0x67, 0x1a, 0x1b,
+ 0x2e, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f,
+ 0x6d, 0x6d, 0x73, 0x2e, 0x55, 0x69, 0x6e, 0x74, 0x4d, 0x73, 0x67, 0x22, 0x00, 0x12, 0x54, 0x0a,
+ 0x0a, 0x52, 0x65, 0x61, 0x64, 0x41, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x12, 0x1d, 0x2e, 0x73, 0x61,
+ 0x66, 0x65, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73,
+ 0x2e, 0x52, 0x65, 0x61, 0x64, 0x41, 0x74, 0x4d, 0x73, 0x67, 0x1a, 0x25, 0x2e, 0x73, 0x61, 0x66,
+ 0x65, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e,
+ 0x52, 0x65, 0x61, 0x64, 0x41, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x73,
+ 0x67, 0x22, 0x00, 0x12, 0x63, 0x0a, 0x0f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65,
+ 0x61, 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x12, 0x26, 0x2e, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x72, 0x65,
+ 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4d, 0x73, 0x67, 0x1a, 0x26,
+ 0x2e, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f,
+ 0x6d, 0x6d, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f,
+ 0x6e, 0x73, 0x65, 0x4d, 0x73, 0x67, 0x22, 0x00, 0x12, 0x64, 0x0a, 0x10, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x57, 0x72, 0x69, 0x74, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x12, 0x26, 0x2e, 0x73,
+ 0x61, 0x66, 0x65, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d,
+ 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
+ 0x65, 0x4d, 0x73, 0x67, 0x1a, 0x26, 0x2e, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x72, 0x65, 0x6d, 0x6f,
+ 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+ 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x73, 0x67, 0x22, 0x00, 0x12, 0x50,
+ 0x0a, 0x0b, 0x41, 0x63, 0x6b, 0x52, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x12, 0x1b, 0x2e,
+ 0x73, 0x61, 0x66, 0x65, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d,
+ 0x6d, 0x73, 0x2e, 0x55, 0x69, 0x6e, 0x74, 0x4d, 0x73, 0x67, 0x1a, 0x22, 0x2e, 0x73, 0x61, 0x66,
+ 0x65, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e,
+ 0x41, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x73, 0x67, 0x22, 0x00,
+ 0x12, 0x51, 0x0a, 0x0c, 0x41, 0x63, 0x6b, 0x57, 0x72, 0x69, 0x74, 0x65, 0x43, 0x6f, 0x6d, 0x6d,
+ 0x12, 0x1b, 0x2e, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73,
+ 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x2e, 0x55, 0x69, 0x6e, 0x74, 0x4d, 0x73, 0x67, 0x1a, 0x22, 0x2e,
+ 0x73, 0x61, 0x66, 0x65, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d,
+ 0x6d, 0x73, 0x2e, 0x41, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x73,
+ 0x67, 0x22, 0x00, 0x42, 0x16, 0x5a, 0x14, 0x2e, 0x2f, 0x73, 0x61, 0x66, 0x65, 0x2d, 0x72, 0x65,
+ 0x6d, 0x6f, 0x74, 0x65, 0x66, 0x73, 0x63, 0x6f, 0x6d, 0x6d, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x33,
+}
+
+var (
+ file_comm_proto_rawDescOnce sync.Once
+ file_comm_proto_rawDescData = file_comm_proto_rawDesc
+)
+
+func file_comm_proto_rawDescGZIP() []byte {
+ file_comm_proto_rawDescOnce.Do(func() {
+ file_comm_proto_rawDescData = protoimpl.X.CompressGZIP(file_comm_proto_rawDescData)
+ })
+ return file_comm_proto_rawDescData
+}
+
+var file_comm_proto_msgTypes = make([]protoimpl.MessageInfo, 12)
+var file_comm_proto_goTypes = []any{
+ (*FileInfoMsg)(nil), // 0: safe_remotefscomms.FileInfoMsg
+ (*UintMsg)(nil), // 1: safe_remotefscomms.UintMsg
+ (*WriteAtMsg)(nil), // 2: safe_remotefscomms.WriteAtMsg
+ (*ReadAtMsg)(nil), // 3: safe_remotefscomms.ReadAtMsg
+ (*ReadAtResponseMsg)(nil), // 4: safe_remotefscomms.ReadAtResponseMsg
+ (*SetInfoParamsMsg)(nil), // 5: safe_remotefscomms.SetInfoParamsMsg
+ (*MkInodeMsg)(nil), // 6: safe_remotefscomms.MkInodeMsg
+ (*RequestResourceMsg)(nil), // 7: safe_remotefscomms.RequestResourceMsg
+ (*RequestResponseMsg)(nil), // 8: safe_remotefscomms.RequestResponseMsg
+ (*AckResponseMsg)(nil), // 9: safe_remotefscomms.AckResponseMsg
+ (*Empty)(nil), // 10: safe_remotefscomms.Empty
+ nil, // 11: safe_remotefscomms.FileInfoMsg.ChildrenIndexMapEntry
+ (*timestamppb.Timestamp)(nil), // 12: google.protobuf.Timestamp
+}
+var file_comm_proto_depIdxs = []int32{
+ 11, // 0: safe_remotefscomms.FileInfoMsg.childrenIndexMap:type_name -> safe_remotefscomms.FileInfoMsg.ChildrenIndexMapEntry
+ 12, // 1: safe_remotefscomms.FileInfoMsg.atime:type_name -> google.protobuf.Timestamp
+ 12, // 2: safe_remotefscomms.FileInfoMsg.mtime:type_name -> google.protobuf.Timestamp
+ 12, // 3: safe_remotefscomms.FileInfoMsg.ctime:type_name -> google.protobuf.Timestamp
+ 12, // 4: safe_remotefscomms.FileInfoMsg.crtime:type_name -> google.protobuf.Timestamp
+ 12, // 5: safe_remotefscomms.SetInfoParamsMsg.atime:type_name -> google.protobuf.Timestamp
+ 12, // 6: safe_remotefscomms.SetInfoParamsMsg.mtime:type_name -> google.protobuf.Timestamp
+ 12, // 7: safe_remotefscomms.RequestResourceMsg.cacheTime:type_name -> google.protobuf.Timestamp
+ 12, // 8: safe_remotefscomms.AckResponseMsg.writeTime:type_name -> google.protobuf.Timestamp
+ 10, // 9: safe_remotefscomms.RemoteFSComms.GetSizeComm:input_type -> safe_remotefscomms.Empty
+ 10, // 10: safe_remotefscomms.RemoteFSComms.GetLengthComm:input_type -> safe_remotefscomms.Empty
+ 1, // 11: safe_remotefscomms.RemoteFSComms.GetInfoComm:input_type -> safe_remotefscomms.UintMsg
+ 5, // 12: safe_remotefscomms.RemoteFSComms.SetInfoComm:input_type -> safe_remotefscomms.SetInfoParamsMsg
+ 1, // 13: safe_remotefscomms.RemoteFSComms.DeleteComm:input_type -> safe_remotefscomms.UintMsg
+ 6, // 14: safe_remotefscomms.RemoteFSComms.MkDirComm:input_type -> safe_remotefscomms.MkInodeMsg
+ 6, // 15: safe_remotefscomms.RemoteFSComms.CreateFileComm:input_type -> safe_remotefscomms.MkInodeMsg
+ 1, // 16: safe_remotefscomms.RemoteFSComms.RmDirComm:input_type -> safe_remotefscomms.UintMsg
+ 1, // 17: safe_remotefscomms.RemoteFSComms.SyncFileComm:input_type -> safe_remotefscomms.UintMsg
+ 2, // 18: safe_remotefscomms.RemoteFSComms.WriteAtComm:input_type -> safe_remotefscomms.WriteAtMsg
+ 3, // 19: safe_remotefscomms.RemoteFSComms.ReadAtComm:input_type -> safe_remotefscomms.ReadAtMsg
+ 7, // 20: safe_remotefscomms.RemoteFSComms.RequestReadComm:input_type -> safe_remotefscomms.RequestResourceMsg
+ 7, // 21: safe_remotefscomms.RemoteFSComms.RequestWriteComm:input_type -> safe_remotefscomms.RequestResourceMsg
+ 1, // 22: safe_remotefscomms.RemoteFSComms.AckReadComm:input_type -> safe_remotefscomms.UintMsg
+ 1, // 23: safe_remotefscomms.RemoteFSComms.AckWriteComm:input_type -> safe_remotefscomms.UintMsg
+ 1, // 24: safe_remotefscomms.RemoteFSComms.GetSizeComm:output_type -> safe_remotefscomms.UintMsg
+ 1, // 25: safe_remotefscomms.RemoteFSComms.GetLengthComm:output_type -> safe_remotefscomms.UintMsg
+ 0, // 26: safe_remotefscomms.RemoteFSComms.GetInfoComm:output_type -> safe_remotefscomms.FileInfoMsg
+ 10, // 27: safe_remotefscomms.RemoteFSComms.SetInfoComm:output_type -> safe_remotefscomms.Empty
+ 10, // 28: safe_remotefscomms.RemoteFSComms.DeleteComm:output_type -> safe_remotefscomms.Empty
+ 1, // 29: safe_remotefscomms.RemoteFSComms.MkDirComm:output_type -> safe_remotefscomms.UintMsg
+ 1, // 30: safe_remotefscomms.RemoteFSComms.CreateFileComm:output_type -> safe_remotefscomms.UintMsg
+ 10, // 31: safe_remotefscomms.RemoteFSComms.RmDirComm:output_type -> safe_remotefscomms.Empty
+ 10, // 32: safe_remotefscomms.RemoteFSComms.SyncFileComm:output_type -> safe_remotefscomms.Empty
+ 1, // 33: safe_remotefscomms.RemoteFSComms.WriteAtComm:output_type -> safe_remotefscomms.UintMsg
+ 4, // 34: safe_remotefscomms.RemoteFSComms.ReadAtComm:output_type -> safe_remotefscomms.ReadAtResponseMsg
+ 8, // 35: safe_remotefscomms.RemoteFSComms.RequestReadComm:output_type -> safe_remotefscomms.RequestResponseMsg
+ 8, // 36: safe_remotefscomms.RemoteFSComms.RequestWriteComm:output_type -> safe_remotefscomms.RequestResponseMsg
+ 9, // 37: safe_remotefscomms.RemoteFSComms.AckReadComm:output_type -> safe_remotefscomms.AckResponseMsg
+ 9, // 38: safe_remotefscomms.RemoteFSComms.AckWriteComm:output_type -> safe_remotefscomms.AckResponseMsg
+ 24, // [24:39] is the sub-list for method output_type
+ 9, // [9:24] is the sub-list for method input_type
+ 9, // [9:9] is the sub-list for extension type_name
+ 9, // [9:9] is the sub-list for extension extendee
+ 0, // [0:9] is the sub-list for field type_name
+}
+
+func init() { file_comm_proto_init() }
+func file_comm_proto_init() {
+ if File_comm_proto != nil {
+ return
+ }
+ if !protoimpl.UnsafeEnabled {
+ file_comm_proto_msgTypes[0].Exporter = func(v any, i int) any {
+ switch v := v.(*FileInfoMsg); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_comm_proto_msgTypes[1].Exporter = func(v any, i int) any {
+ switch v := v.(*UintMsg); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_comm_proto_msgTypes[2].Exporter = func(v any, i int) any {
+ switch v := v.(*WriteAtMsg); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_comm_proto_msgTypes[3].Exporter = func(v any, i int) any {
+ switch v := v.(*ReadAtMsg); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_comm_proto_msgTypes[4].Exporter = func(v any, i int) any {
+ switch v := v.(*ReadAtResponseMsg); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_comm_proto_msgTypes[5].Exporter = func(v any, i int) any {
+ switch v := v.(*SetInfoParamsMsg); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_comm_proto_msgTypes[6].Exporter = func(v any, i int) any {
+ switch v := v.(*MkInodeMsg); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_comm_proto_msgTypes[7].Exporter = func(v any, i int) any {
+ switch v := v.(*RequestResourceMsg); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_comm_proto_msgTypes[8].Exporter = func(v any, i int) any {
+ switch v := v.(*RequestResponseMsg); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_comm_proto_msgTypes[9].Exporter = func(v any, i int) any {
+ switch v := v.(*AckResponseMsg); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_comm_proto_msgTypes[10].Exporter = func(v any, i int) any {
+ switch v := v.(*Empty); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_comm_proto_rawDesc,
+ NumEnums: 0,
+ NumMessages: 12,
+ NumExtensions: 0,
+ NumServices: 1,
+ },
+ GoTypes: file_comm_proto_goTypes,
+ DependencyIndexes: file_comm_proto_depIdxs,
+ MessageInfos: file_comm_proto_msgTypes,
+ }.Build()
+ File_comm_proto = out.File
+ file_comm_proto_rawDesc = nil
+ file_comm_proto_goTypes = nil
+ file_comm_proto_depIdxs = nil
+}
diff --git a/mft-fs/archive/safe-remotefs/safe-remotefscomms/comm_grpc.pb.go b/mft-fs/archive/safe-remotefs/safe-remotefscomms/comm_grpc.pb.go
new file mode 100644
index 00000000..d9eae90d
--- /dev/null
+++ b/mft-fs/archive/safe-remotefs/safe-remotefscomms/comm_grpc.pb.go
@@ -0,0 +1,642 @@
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+// versions:
+// - protoc-gen-go-grpc v1.4.0
+// - protoc v5.27.1
+// source: comm.proto
+
+package safe_remotefscomms
+
+import (
+ context "context"
+ grpc "google.golang.org/grpc"
+ codes "google.golang.org/grpc/codes"
+ status "google.golang.org/grpc/status"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.62.0 or later.
+const _ = grpc.SupportPackageIsVersion8
+
+const (
+ RemoteFSComms_GetSizeComm_FullMethodName = "/safe_remotefscomms.RemoteFSComms/GetSizeComm"
+ RemoteFSComms_GetLengthComm_FullMethodName = "/safe_remotefscomms.RemoteFSComms/GetLengthComm"
+ RemoteFSComms_GetInfoComm_FullMethodName = "/safe_remotefscomms.RemoteFSComms/GetInfoComm"
+ RemoteFSComms_SetInfoComm_FullMethodName = "/safe_remotefscomms.RemoteFSComms/SetInfoComm"
+ RemoteFSComms_DeleteComm_FullMethodName = "/safe_remotefscomms.RemoteFSComms/DeleteComm"
+ RemoteFSComms_MkDirComm_FullMethodName = "/safe_remotefscomms.RemoteFSComms/MkDirComm"
+ RemoteFSComms_CreateFileComm_FullMethodName = "/safe_remotefscomms.RemoteFSComms/CreateFileComm"
+ RemoteFSComms_RmDirComm_FullMethodName = "/safe_remotefscomms.RemoteFSComms/RmDirComm"
+ RemoteFSComms_SyncFileComm_FullMethodName = "/safe_remotefscomms.RemoteFSComms/SyncFileComm"
+ RemoteFSComms_WriteAtComm_FullMethodName = "/safe_remotefscomms.RemoteFSComms/WriteAtComm"
+ RemoteFSComms_ReadAtComm_FullMethodName = "/safe_remotefscomms.RemoteFSComms/ReadAtComm"
+ RemoteFSComms_RequestReadComm_FullMethodName = "/safe_remotefscomms.RemoteFSComms/RequestReadComm"
+ RemoteFSComms_RequestWriteComm_FullMethodName = "/safe_remotefscomms.RemoteFSComms/RequestWriteComm"
+ RemoteFSComms_AckReadComm_FullMethodName = "/safe_remotefscomms.RemoteFSComms/AckReadComm"
+ RemoteFSComms_AckWriteComm_FullMethodName = "/safe_remotefscomms.RemoteFSComms/AckWriteComm"
+)
+
+// RemoteFSCommsClient is the client API for RemoteFSComms service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type RemoteFSCommsClient interface {
+ GetSizeComm(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*UintMsg, error)
+ GetLengthComm(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*UintMsg, error)
+ GetInfoComm(ctx context.Context, in *UintMsg, opts ...grpc.CallOption) (*FileInfoMsg, error)
+ SetInfoComm(ctx context.Context, in *SetInfoParamsMsg, opts ...grpc.CallOption) (*Empty, error)
+ DeleteComm(ctx context.Context, in *UintMsg, opts ...grpc.CallOption) (*Empty, error)
+ MkDirComm(ctx context.Context, in *MkInodeMsg, opts ...grpc.CallOption) (*UintMsg, error)
+ CreateFileComm(ctx context.Context, in *MkInodeMsg, opts ...grpc.CallOption) (*UintMsg, error)
+ RmDirComm(ctx context.Context, in *UintMsg, opts ...grpc.CallOption) (*Empty, error)
+ SyncFileComm(ctx context.Context, in *UintMsg, opts ...grpc.CallOption) (*Empty, error)
+ WriteAtComm(ctx context.Context, in *WriteAtMsg, opts ...grpc.CallOption) (*UintMsg, error)
+ ReadAtComm(ctx context.Context, in *ReadAtMsg, opts ...grpc.CallOption) (*ReadAtResponseMsg, error)
+ RequestReadComm(ctx context.Context, in *RequestResourceMsg, opts ...grpc.CallOption) (*RequestResponseMsg, error)
+ RequestWriteComm(ctx context.Context, in *RequestResourceMsg, opts ...grpc.CallOption) (*RequestResponseMsg, error)
+ AckReadComm(ctx context.Context, in *UintMsg, opts ...grpc.CallOption) (*AckResponseMsg, error)
+ AckWriteComm(ctx context.Context, in *UintMsg, opts ...grpc.CallOption) (*AckResponseMsg, error)
+}
+
+type remoteFSCommsClient struct {
+ cc grpc.ClientConnInterface
+}
+
+func NewRemoteFSCommsClient(cc grpc.ClientConnInterface) RemoteFSCommsClient {
+ return &remoteFSCommsClient{cc}
+}
+
+func (c *remoteFSCommsClient) GetSizeComm(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*UintMsg, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(UintMsg)
+ err := c.cc.Invoke(ctx, RemoteFSComms_GetSizeComm_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *remoteFSCommsClient) GetLengthComm(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*UintMsg, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(UintMsg)
+ err := c.cc.Invoke(ctx, RemoteFSComms_GetLengthComm_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *remoteFSCommsClient) GetInfoComm(ctx context.Context, in *UintMsg, opts ...grpc.CallOption) (*FileInfoMsg, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(FileInfoMsg)
+ err := c.cc.Invoke(ctx, RemoteFSComms_GetInfoComm_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *remoteFSCommsClient) SetInfoComm(ctx context.Context, in *SetInfoParamsMsg, opts ...grpc.CallOption) (*Empty, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(Empty)
+ err := c.cc.Invoke(ctx, RemoteFSComms_SetInfoComm_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *remoteFSCommsClient) DeleteComm(ctx context.Context, in *UintMsg, opts ...grpc.CallOption) (*Empty, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(Empty)
+ err := c.cc.Invoke(ctx, RemoteFSComms_DeleteComm_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *remoteFSCommsClient) MkDirComm(ctx context.Context, in *MkInodeMsg, opts ...grpc.CallOption) (*UintMsg, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(UintMsg)
+ err := c.cc.Invoke(ctx, RemoteFSComms_MkDirComm_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *remoteFSCommsClient) CreateFileComm(ctx context.Context, in *MkInodeMsg, opts ...grpc.CallOption) (*UintMsg, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(UintMsg)
+ err := c.cc.Invoke(ctx, RemoteFSComms_CreateFileComm_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *remoteFSCommsClient) RmDirComm(ctx context.Context, in *UintMsg, opts ...grpc.CallOption) (*Empty, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(Empty)
+ err := c.cc.Invoke(ctx, RemoteFSComms_RmDirComm_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *remoteFSCommsClient) SyncFileComm(ctx context.Context, in *UintMsg, opts ...grpc.CallOption) (*Empty, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(Empty)
+ err := c.cc.Invoke(ctx, RemoteFSComms_SyncFileComm_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *remoteFSCommsClient) WriteAtComm(ctx context.Context, in *WriteAtMsg, opts ...grpc.CallOption) (*UintMsg, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(UintMsg)
+ err := c.cc.Invoke(ctx, RemoteFSComms_WriteAtComm_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *remoteFSCommsClient) ReadAtComm(ctx context.Context, in *ReadAtMsg, opts ...grpc.CallOption) (*ReadAtResponseMsg, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(ReadAtResponseMsg)
+ err := c.cc.Invoke(ctx, RemoteFSComms_ReadAtComm_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *remoteFSCommsClient) RequestReadComm(ctx context.Context, in *RequestResourceMsg, opts ...grpc.CallOption) (*RequestResponseMsg, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(RequestResponseMsg)
+ err := c.cc.Invoke(ctx, RemoteFSComms_RequestReadComm_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *remoteFSCommsClient) RequestWriteComm(ctx context.Context, in *RequestResourceMsg, opts ...grpc.CallOption) (*RequestResponseMsg, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(RequestResponseMsg)
+ err := c.cc.Invoke(ctx, RemoteFSComms_RequestWriteComm_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *remoteFSCommsClient) AckReadComm(ctx context.Context, in *UintMsg, opts ...grpc.CallOption) (*AckResponseMsg, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(AckResponseMsg)
+ err := c.cc.Invoke(ctx, RemoteFSComms_AckReadComm_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *remoteFSCommsClient) AckWriteComm(ctx context.Context, in *UintMsg, opts ...grpc.CallOption) (*AckResponseMsg, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(AckResponseMsg)
+ err := c.cc.Invoke(ctx, RemoteFSComms_AckWriteComm_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+// RemoteFSCommsServer is the server API for RemoteFSComms service.
+// All implementations must embed UnimplementedRemoteFSCommsServer
+// for forward compatibility
+type RemoteFSCommsServer interface {
+ GetSizeComm(context.Context, *Empty) (*UintMsg, error)
+ GetLengthComm(context.Context, *Empty) (*UintMsg, error)
+ GetInfoComm(context.Context, *UintMsg) (*FileInfoMsg, error)
+ SetInfoComm(context.Context, *SetInfoParamsMsg) (*Empty, error)
+ DeleteComm(context.Context, *UintMsg) (*Empty, error)
+ MkDirComm(context.Context, *MkInodeMsg) (*UintMsg, error)
+ CreateFileComm(context.Context, *MkInodeMsg) (*UintMsg, error)
+ RmDirComm(context.Context, *UintMsg) (*Empty, error)
+ SyncFileComm(context.Context, *UintMsg) (*Empty, error)
+ WriteAtComm(context.Context, *WriteAtMsg) (*UintMsg, error)
+ ReadAtComm(context.Context, *ReadAtMsg) (*ReadAtResponseMsg, error)
+ RequestReadComm(context.Context, *RequestResourceMsg) (*RequestResponseMsg, error)
+ RequestWriteComm(context.Context, *RequestResourceMsg) (*RequestResponseMsg, error)
+ AckReadComm(context.Context, *UintMsg) (*AckResponseMsg, error)
+ AckWriteComm(context.Context, *UintMsg) (*AckResponseMsg, error)
+ mustEmbedUnimplementedRemoteFSCommsServer()
+}
+
+// UnimplementedRemoteFSCommsServer must be embedded to have forward compatible implementations.
+type UnimplementedRemoteFSCommsServer struct {
+}
+
+func (UnimplementedRemoteFSCommsServer) GetSizeComm(context.Context, *Empty) (*UintMsg, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method GetSizeComm not implemented")
+}
+func (UnimplementedRemoteFSCommsServer) GetLengthComm(context.Context, *Empty) (*UintMsg, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method GetLengthComm not implemented")
+}
+func (UnimplementedRemoteFSCommsServer) GetInfoComm(context.Context, *UintMsg) (*FileInfoMsg, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method GetInfoComm not implemented")
+}
+func (UnimplementedRemoteFSCommsServer) SetInfoComm(context.Context, *SetInfoParamsMsg) (*Empty, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method SetInfoComm not implemented")
+}
+func (UnimplementedRemoteFSCommsServer) DeleteComm(context.Context, *UintMsg) (*Empty, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method DeleteComm not implemented")
+}
+func (UnimplementedRemoteFSCommsServer) MkDirComm(context.Context, *MkInodeMsg) (*UintMsg, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method MkDirComm not implemented")
+}
+func (UnimplementedRemoteFSCommsServer) CreateFileComm(context.Context, *MkInodeMsg) (*UintMsg, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method CreateFileComm not implemented")
+}
+func (UnimplementedRemoteFSCommsServer) RmDirComm(context.Context, *UintMsg) (*Empty, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method RmDirComm not implemented")
+}
+func (UnimplementedRemoteFSCommsServer) SyncFileComm(context.Context, *UintMsg) (*Empty, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method SyncFileComm not implemented")
+}
+func (UnimplementedRemoteFSCommsServer) WriteAtComm(context.Context, *WriteAtMsg) (*UintMsg, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method WriteAtComm not implemented")
+}
+func (UnimplementedRemoteFSCommsServer) ReadAtComm(context.Context, *ReadAtMsg) (*ReadAtResponseMsg, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method ReadAtComm not implemented")
+}
+func (UnimplementedRemoteFSCommsServer) RequestReadComm(context.Context, *RequestResourceMsg) (*RequestResponseMsg, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method RequestReadComm not implemented")
+}
+func (UnimplementedRemoteFSCommsServer) RequestWriteComm(context.Context, *RequestResourceMsg) (*RequestResponseMsg, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method RequestWriteComm not implemented")
+}
+func (UnimplementedRemoteFSCommsServer) AckReadComm(context.Context, *UintMsg) (*AckResponseMsg, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method AckReadComm not implemented")
+}
+func (UnimplementedRemoteFSCommsServer) AckWriteComm(context.Context, *UintMsg) (*AckResponseMsg, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method AckWriteComm not implemented")
+}
+func (UnimplementedRemoteFSCommsServer) mustEmbedUnimplementedRemoteFSCommsServer() {}
+
+// UnsafeRemoteFSCommsServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to RemoteFSCommsServer will
+// result in compilation errors.
+type UnsafeRemoteFSCommsServer interface {
+ mustEmbedUnimplementedRemoteFSCommsServer()
+}
+
+func RegisterRemoteFSCommsServer(s grpc.ServiceRegistrar, srv RemoteFSCommsServer) {
+ s.RegisterService(&RemoteFSComms_ServiceDesc, srv)
+}
+
+func _RemoteFSComms_GetSizeComm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(Empty)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(RemoteFSCommsServer).GetSizeComm(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: RemoteFSComms_GetSizeComm_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(RemoteFSCommsServer).GetSizeComm(ctx, req.(*Empty))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _RemoteFSComms_GetLengthComm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(Empty)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(RemoteFSCommsServer).GetLengthComm(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: RemoteFSComms_GetLengthComm_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(RemoteFSCommsServer).GetLengthComm(ctx, req.(*Empty))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _RemoteFSComms_GetInfoComm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(UintMsg)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(RemoteFSCommsServer).GetInfoComm(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: RemoteFSComms_GetInfoComm_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(RemoteFSCommsServer).GetInfoComm(ctx, req.(*UintMsg))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _RemoteFSComms_SetInfoComm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(SetInfoParamsMsg)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(RemoteFSCommsServer).SetInfoComm(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: RemoteFSComms_SetInfoComm_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(RemoteFSCommsServer).SetInfoComm(ctx, req.(*SetInfoParamsMsg))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _RemoteFSComms_DeleteComm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(UintMsg)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(RemoteFSCommsServer).DeleteComm(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: RemoteFSComms_DeleteComm_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(RemoteFSCommsServer).DeleteComm(ctx, req.(*UintMsg))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _RemoteFSComms_MkDirComm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(MkInodeMsg)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(RemoteFSCommsServer).MkDirComm(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: RemoteFSComms_MkDirComm_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(RemoteFSCommsServer).MkDirComm(ctx, req.(*MkInodeMsg))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _RemoteFSComms_CreateFileComm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(MkInodeMsg)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(RemoteFSCommsServer).CreateFileComm(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: RemoteFSComms_CreateFileComm_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(RemoteFSCommsServer).CreateFileComm(ctx, req.(*MkInodeMsg))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _RemoteFSComms_RmDirComm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(UintMsg)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(RemoteFSCommsServer).RmDirComm(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: RemoteFSComms_RmDirComm_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(RemoteFSCommsServer).RmDirComm(ctx, req.(*UintMsg))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _RemoteFSComms_SyncFileComm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(UintMsg)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(RemoteFSCommsServer).SyncFileComm(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: RemoteFSComms_SyncFileComm_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(RemoteFSCommsServer).SyncFileComm(ctx, req.(*UintMsg))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _RemoteFSComms_WriteAtComm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(WriteAtMsg)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(RemoteFSCommsServer).WriteAtComm(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: RemoteFSComms_WriteAtComm_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(RemoteFSCommsServer).WriteAtComm(ctx, req.(*WriteAtMsg))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _RemoteFSComms_ReadAtComm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(ReadAtMsg)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(RemoteFSCommsServer).ReadAtComm(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: RemoteFSComms_ReadAtComm_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(RemoteFSCommsServer).ReadAtComm(ctx, req.(*ReadAtMsg))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _RemoteFSComms_RequestReadComm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(RequestResourceMsg)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(RemoteFSCommsServer).RequestReadComm(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: RemoteFSComms_RequestReadComm_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(RemoteFSCommsServer).RequestReadComm(ctx, req.(*RequestResourceMsg))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _RemoteFSComms_RequestWriteComm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(RequestResourceMsg)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(RemoteFSCommsServer).RequestWriteComm(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: RemoteFSComms_RequestWriteComm_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(RemoteFSCommsServer).RequestWriteComm(ctx, req.(*RequestResourceMsg))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _RemoteFSComms_AckReadComm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(UintMsg)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(RemoteFSCommsServer).AckReadComm(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: RemoteFSComms_AckReadComm_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(RemoteFSCommsServer).AckReadComm(ctx, req.(*UintMsg))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _RemoteFSComms_AckWriteComm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(UintMsg)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(RemoteFSCommsServer).AckWriteComm(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: RemoteFSComms_AckWriteComm_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(RemoteFSCommsServer).AckWriteComm(ctx, req.(*UintMsg))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+// RemoteFSComms_ServiceDesc is the grpc.ServiceDesc for RemoteFSComms service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var RemoteFSComms_ServiceDesc = grpc.ServiceDesc{
+ ServiceName: "safe_remotefscomms.RemoteFSComms",
+ HandlerType: (*RemoteFSCommsServer)(nil),
+ Methods: []grpc.MethodDesc{
+ {
+ MethodName: "GetSizeComm",
+ Handler: _RemoteFSComms_GetSizeComm_Handler,
+ },
+ {
+ MethodName: "GetLengthComm",
+ Handler: _RemoteFSComms_GetLengthComm_Handler,
+ },
+ {
+ MethodName: "GetInfoComm",
+ Handler: _RemoteFSComms_GetInfoComm_Handler,
+ },
+ {
+ MethodName: "SetInfoComm",
+ Handler: _RemoteFSComms_SetInfoComm_Handler,
+ },
+ {
+ MethodName: "DeleteComm",
+ Handler: _RemoteFSComms_DeleteComm_Handler,
+ },
+ {
+ MethodName: "MkDirComm",
+ Handler: _RemoteFSComms_MkDirComm_Handler,
+ },
+ {
+ MethodName: "CreateFileComm",
+ Handler: _RemoteFSComms_CreateFileComm_Handler,
+ },
+ {
+ MethodName: "RmDirComm",
+ Handler: _RemoteFSComms_RmDirComm_Handler,
+ },
+ {
+ MethodName: "SyncFileComm",
+ Handler: _RemoteFSComms_SyncFileComm_Handler,
+ },
+ {
+ MethodName: "WriteAtComm",
+ Handler: _RemoteFSComms_WriteAtComm_Handler,
+ },
+ {
+ MethodName: "ReadAtComm",
+ Handler: _RemoteFSComms_ReadAtComm_Handler,
+ },
+ {
+ MethodName: "RequestReadComm",
+ Handler: _RemoteFSComms_RequestReadComm_Handler,
+ },
+ {
+ MethodName: "RequestWriteComm",
+ Handler: _RemoteFSComms_RequestWriteComm_Handler,
+ },
+ {
+ MethodName: "AckReadComm",
+ Handler: _RemoteFSComms_AckReadComm_Handler,
+ },
+ {
+ MethodName: "AckWriteComm",
+ Handler: _RemoteFSComms_AckWriteComm_Handler,
+ },
+ },
+ Streams: []grpc.StreamDesc{},
+ Metadata: "comm.proto",
+}
diff --git a/mft-fs/archive/safe-remotefs/safe-remotefscomms/commutils.go b/mft-fs/archive/safe-remotefs/safe-remotefscomms/commutils.go
new file mode 100644
index 00000000..bd9ead92
--- /dev/null
+++ b/mft-fs/archive/safe-remotefs/safe-remotefscomms/commutils.go
@@ -0,0 +1,57 @@
+package safe_remotefscomms
+
+import (
+ "github.com/jacobsa/fuse/fuseops"
+ "github.com/jacobsa/fuse/fuseutil"
+ "google.golang.org/protobuf/types/known/timestamppb"
+ "mft-fs/archive/abstractfs"
+ "os"
+)
+
+func ConvertFromComm(input *FileInfoMsg, output *abstractfs.FileInfo) {
+ output.Name = input.Name
+ output.Path = input.Path
+ output.Inode = fuseops.InodeID(input.Inode)
+ for _, child := range input.Children {
+ output.Children = append(output.Children, fuseops.InodeID(child))
+ }
+ for name, index := range input.ChildrenIndexMap {
+ output.ChildrenIndexMap[name] = int(index)
+ }
+ output.Parent = fuseops.InodeID(input.Parent)
+ output.Nlink = input.Nlink
+ output.Size = input.Size
+ output.Mode = os.FileMode(input.Mode)
+ output.Atime = input.Atime.AsTime()
+ output.Mtime = input.Mtime.AsTime()
+ output.Ctime = input.Ctime.AsTime()
+ output.Crtime = input.Crtime.AsTime()
+ output.Uid = input.Uid
+ output.Gid = input.Gid
+ output.DirentType = fuseutil.DirentType(input.DirentType)
+ output.Handle = fuseops.HandleID(input.Handle)
+}
+
+func ConvertToComm(input *abstractfs.FileInfo, output *FileInfoMsg) {
+ output.Name = input.Name
+ output.Path = input.Path
+ output.Inode = uint64(input.Inode)
+ for _, child := range input.Children {
+ output.Children = append(output.Children, uint64(child))
+ }
+ for name, index := range input.ChildrenIndexMap {
+ output.ChildrenIndexMap[name] = uint32(index)
+ }
+ output.Parent = uint64(input.Parent)
+ output.Nlink = input.Nlink
+ output.Size = input.Size
+ output.Mode = uint32(input.Mode)
+ output.Atime = timestamppb.New(input.Atime)
+ output.Mtime = timestamppb.New(input.Mtime)
+ output.Ctime = timestamppb.New(input.Ctime)
+ output.Crtime = timestamppb.New(input.Crtime)
+ output.Uid = input.Uid
+ output.Gid = input.Gid
+ output.DirentType = uint32(input.DirentType)
+ output.Handle = uint64(input.Handle)
+}
diff --git a/mft-fs/archive/safe-remotefs/server/safe_os_fs_manager.go b/mft-fs/archive/safe-remotefs/server/safe_os_fs_manager.go
new file mode 100644
index 00000000..243f4824
--- /dev/null
+++ b/mft-fs/archive/safe-remotefs/server/safe_os_fs_manager.go
@@ -0,0 +1,424 @@
+package server
+
+import (
+ "fmt"
+ "github.com/jacobsa/fuse"
+ "github.com/jacobsa/fuse/fuseops"
+ "github.com/jacobsa/fuse/fuseutil"
+ "golang.org/x/sys/unix"
+ "mft-fs/archive/abstractfs"
+ "mft-fs/datastructures"
+ "os"
+ "syscall"
+ "time"
+)
+
+type SafeOSFSManager struct {
+ abstractfs.FSManager
+ root string
+ lock *datastructures.CREWResource
+ inodeInfo map[fuseops.InodeID]*abstractfs.FileInfo
+ inodeCounter fuseops.InodeID
+}
+
+type parentChildPair struct {
+ parent fuseops.InodeID
+ child string
+}
+
+func (manager *SafeOSFSManager) bfs(root string) {
+ q := datastructures.NewQueue()
+ q.Enqueue(&(parentChildPair{
+ parent: 0,
+ child: root,
+ }))
+ for !q.IsEmpty() {
+ current := q.Dequeue().(*parentChildPair)
+ var direntType fuseutil.DirentType
+ stat, e := os.Stat(current.child)
+ if e != nil {
+ fmt.Println("error:")
+ fmt.Println(e.Error())
+ continue
+ }
+ if stat.IsDir() {
+ dir, e := os.ReadDir(current.child)
+ if e != nil {
+ continue
+ }
+ for _, file := range dir {
+ q.Enqueue(&(parentChildPair{
+ parent: manager.inodeCounter,
+ child: fmt.Sprintf("%s/%s", current.child, file.Name()),
+ }))
+ }
+ direntType = fuseutil.DT_Directory
+ } else {
+ direntType = fuseutil.DT_File
+ }
+ info := abstractfs.NewSafeFileInfo(stat.Name(), current.child, manager.inodeCounter, current.parent, direntType)
+ manager.inodeInfo[manager.inodeCounter] = &info
+ parentInfo, ok := manager.inodeInfo[current.parent]
+ if ok {
+ parentInfo.ChildrenIndexMap[info.Name] = len(parentInfo.Children)
+ parentInfo.Children = append(parentInfo.Children, manager.inodeCounter)
+ }
+ manager.updateInfo(manager.inodeInfo[manager.inodeCounter])
+ manager.inodeCounter++
+ }
+}
+
+func NewSafeOSFSManager(root string) *SafeOSFSManager {
+ manager := &SafeOSFSManager{
+ root: root,
+ lock: datastructures.NewCREWResource(),
+ inodeInfo: make(map[fuseops.InodeID]*abstractfs.FileInfo),
+ inodeCounter: 1,
+ }
+ manager.lock.RequestWrite()
+ defer manager.lock.AckWrite()
+ manager.bfs(root)
+ return manager
+}
+
+func (manager *SafeOSFSManager) GenerateHandle(inode fuseops.InodeID) (fuseops.HandleID, error) {
+ return 0, nil
+}
+
+func (manager *SafeOSFSManager) updateInfo(info *abstractfs.FileInfo) error {
+
+ fileInfo, e := os.Stat(info.Path)
+ if e != nil {
+ return e
+ }
+ stats := fileInfo.Sys().(*syscall.Stat_t)
+
+ info.Size = uint64(fileInfo.Size())
+
+ info.Nlink = 1
+
+ info.Mode = fileInfo.Mode()
+
+ /*info.Atime = time.Unix(stats.Atimespec.Sec, stats.Atimespec.Nsec)
+ info.Mtime = time.Unix(stats.Mtimespec.Sec, stats.Mtimespec.Nsec)
+ info.Ctime = time.Unix(stats.Ctimespec.Sec, stats.Ctimespec.Nsec)
+ info.Crtime = time.Unix(stats.Birthtimespec.Sec, stats.Birthtimespec.Nsec)*/
+ var timeStats unix.Stat_t
+ e = unix.Stat(info.Path, &timeStats)
+ if e != nil {
+ return e
+ }
+ info.Atime = time.Unix(timeStats.Atim.Sec, timeStats.Atim.Nsec)
+ info.Mtime = time.Unix(timeStats.Mtim.Sec, timeStats.Mtim.Nsec)
+ info.Ctime = time.Unix(timeStats.Ctim.Sec, timeStats.Ctim.Nsec)
+ info.Crtime = time.Unix(timeStats.Ctim.Sec, timeStats.Ctim.Nsec)
+
+ info.Uid = stats.Uid
+ info.Gid = stats.Gid
+
+ info.MetadataWriteTime = time.Now()
+
+ return nil
+}
+
+// todo: consider locking mechanisms
+func (manager *SafeOSFSManager) GetSize() (uint64, error) {
+ stat, _ := os.Stat(manager.root)
+ return uint64(stat.Size()), nil
+}
+
+func (manager *SafeOSFSManager) GetLength() (uint64, error) {
+ manager.lock.RequestRead()
+ defer manager.lock.AckRead()
+ output := uint64(len(manager.inodeInfo))
+ return output, nil
+}
+
+func (manager *SafeOSFSManager) GetInfo(inode fuseops.InodeID) (*abstractfs.FileInfo, error) {
+ manager.lock.RequestRead()
+ defer manager.lock.AckRead()
+ info, ok := manager.inodeInfo[inode]
+ if !ok {
+ return nil, fuse.ENOENT
+ }
+ return info, nil
+}
+
+func (manager *SafeOSFSManager) SetInfo(inode fuseops.InodeID, uidptr *uint32, gidptr *uint32, sizeptr *uint64, modeptr *os.FileMode, atimeptr *time.Time, mtimeptr *time.Time) error {
+ info, e := manager.GetInfo(inode)
+
+ // todo consider thread safety options
+
+ if e != nil {
+ return e
+ }
+
+ if modeptr != nil {
+ e = os.Chmod(info.Path, *modeptr)
+ if e != nil {
+ return e
+ }
+ }
+
+ uid := -1
+ gid := -1
+ if uidptr != nil {
+ uid = int(*uidptr)
+ }
+ if gidptr != nil {
+ gid = int(*gidptr)
+ }
+ e = os.Chown(info.Path, uid, gid)
+ if e != nil {
+ return e
+ }
+
+ atime := time.Time{}
+ mtime := time.Time{}
+ if atimeptr != nil {
+ atime = *atimeptr
+ }
+ if mtimeptr != nil {
+ mtime = *mtimeptr
+ }
+ e = os.Chtimes(info.Path, atime, mtime)
+ if e != nil {
+ return e
+ }
+
+ info.MetadataLock.RequestWrite()
+ e = manager.updateInfo(info)
+ info.MetadataLock.AckWrite()
+
+ return e
+}
+
+func (manager *SafeOSFSManager) MkDir(parent fuseops.InodeID, name string, mode os.FileMode) (fuseops.InodeID, error) {
+ parentInfo, e := manager.GetInfo(parent)
+ if e != nil {
+ return 0, e
+ }
+
+ path := parentInfo.Path + "/" + name
+ e = os.Mkdir(path, mode)
+ if e != nil {
+ return 0, e
+ }
+
+ manager.lock.RequestWrite()
+ inode := manager.inodeCounter //fuseops.InodeID(osInfo.Sys().(*syscall.Stat_t).Ino)
+ manager.inodeCounter++
+ infoObj := abstractfs.NewSafeFileInfo(name, path, inode, parent, fuseutil.DT_Directory)
+ manager.inodeInfo[inode] = &infoObj
+ manager.lock.AckWrite()
+
+ infoObj.MetadataLock.RequestWrite()
+ e = manager.updateInfo(&infoObj)
+ infoObj.MetadataLock.AckWrite()
+ if e != nil {
+ return 0, e
+ }
+
+ parentInfo.MetadataLock.RequestWrite()
+ parentInfo.Children = append(parentInfo.Children, inode)
+ parentInfo.ChildrenIndexMap[name] = len(parentInfo.Children) - 1
+ parentInfo.MetadataWriteTime = time.Now()
+ parentInfo.MetadataLock.AckWrite()
+
+ return inode, nil
+}
+
+func (manager *SafeOSFSManager) CreateFile(parent fuseops.InodeID, name string, mode os.FileMode) (fuseops.InodeID, error) {
+ parentInfo, e := manager.GetInfo(parent)
+ if e != nil {
+ return 0, e
+ }
+
+ path := parentInfo.Path + "/" + name
+ file, e := os.Create(path)
+ defer file.Close()
+ if e != nil {
+ return 0, e
+ }
+
+ e = file.Chmod(mode)
+ if e != nil {
+ return 0, e
+ }
+
+ manager.lock.RequestWrite()
+ inode := manager.inodeCounter //fuseops.InodeID(osInfo.Sys().(*syscall.Stat_t).Ino)
+ manager.inodeCounter++
+ infoObj := abstractfs.NewSafeFileInfo(name, path, inode, parent, fuseutil.DT_File)
+ manager.inodeInfo[inode] = &infoObj
+ manager.lock.AckWrite()
+
+ infoObj.MetadataLock.RequestWrite()
+ e = manager.updateInfo(&infoObj)
+ infoObj.MetadataLock.AckWrite()
+ if e != nil {
+ return 0, e
+ }
+
+ parentInfo.MetadataLock.RequestWrite()
+ parentInfo.Children = append(parentInfo.Children, inode)
+ parentInfo.ChildrenIndexMap[name] = len(parentInfo.Children) - 1
+ parentInfo.MetadataWriteTime = time.Now()
+ parentInfo.MetadataLock.AckWrite()
+
+ return inode, nil
+}
+
+func (manager *SafeOSFSManager) RmDir(inode fuseops.InodeID) error {
+ return nil
+}
+
+func (manager *SafeOSFSManager) Delete(inode fuseops.InodeID) error {
+
+ // first delete any reference in parents
+ // then delete self
+
+ info, e := manager.GetInfo(inode)
+ if e != nil {
+ return e
+ }
+
+ parentInfo, e := manager.GetInfo(info.Parent)
+ if e != nil {
+ return e
+ }
+
+ parentInfo.MetadataLock.RequestWrite()
+ parentInfo.Children = datastructures.Remove(parentInfo.Children, parentInfo.ChildrenIndexMap[info.Name])
+ target := parentInfo.ChildrenIndexMap[info.Name]
+ for name, index := range parentInfo.ChildrenIndexMap {
+ if index > target {
+ parentInfo.ChildrenIndexMap[name] = index - 1
+ }
+ }
+ delete(parentInfo.ChildrenIndexMap, info.Name)
+ parentInfo.MetadataWriteTime = time.Now()
+ parentInfo.MetadataLock.AckWrite()
+
+ manager.lock.RequestWrite()
+ delete(manager.inodeInfo, info.Inode)
+ manager.lock.AckWrite()
+
+ return nil
+}
+
+func (manager *SafeOSFSManager) DeleteHandle(handle fuseops.HandleID) error {
+ return nil
+}
+
+func (manager *SafeOSFSManager) SyncFile(inode fuseops.InodeID) error {
+ info, e := manager.GetInfo(inode)
+ if e != nil {
+ return e
+ }
+ file, e := os.OpenFile(info.Path, os.O_RDWR, info.Mode)
+ if e != nil {
+ return e
+ }
+ defer file.Close()
+ e = file.Sync()
+ if e != nil {
+ return e
+ }
+ return nil
+}
+
+func (manager *SafeOSFSManager) ReadAt(inode fuseops.InodeID, data []byte, off int64) (int, error) {
+ info, e := manager.GetInfo(inode)
+ if e != nil {
+ return 0, e
+ }
+
+ file, e := os.OpenFile(info.Path, os.O_RDWR, info.Mode)
+ if e != nil {
+ return 0, e
+ }
+ defer file.Close()
+
+ n, e := file.ReadAt(data, off)
+ return n, e
+}
+
+func (manager *SafeOSFSManager) WriteAt(inode fuseops.InodeID, data []byte, off int64) (int, error) {
+ info, e := manager.GetInfo(inode)
+ if e != nil {
+ return 0, e
+ }
+
+ file, e := os.OpenFile(info.Path, os.O_RDWR, info.Mode)
+ if e != nil {
+ return 0, e
+ }
+ defer file.Close()
+
+ n, e := file.WriteAt(data, off)
+ return n, e
+}
+
+func (manager *SafeOSFSManager) RequestRead(inode fuseops.InodeID, cache bool, cacheTime time.Time) (bool, error) {
+ info, e := manager.GetInfo(inode)
+ if e != nil {
+ return false, e
+ }
+
+ info.ContentLock.RequestRead()
+ // if cache is invalid, return lock success = true
+ if !cache || info.ContentWriteTime.After(cacheTime) {
+ return true, nil
+ }
+ info.ContentLock.AckRead()
+
+ // if cache is valid, no need to lock
+ return false, nil
+}
+
+func (manager *SafeOSFSManager) AckRead(inode fuseops.InodeID) (time.Time, error) {
+ info, e := manager.GetInfo(inode)
+ if e != nil {
+ return time.Time{}, e
+ }
+ info.ContentLock.AckRead()
+ info.MetadataLock.RequestRead()
+ output := info.ContentWriteTime
+ info.MetadataLock.AckRead()
+ return output, nil
+}
+
+func (manager *SafeOSFSManager) RequestWrite(inode fuseops.InodeID, cache bool, cacheTime time.Time) (bool, error) {
+ info, e := manager.GetInfo(inode)
+ if e != nil {
+ return false, e
+ }
+
+ info.ContentLock.RequestWrite()
+
+ // cache is valid so grant permission
+ fmt.Printf("%v\t%v\n", info.ContentWriteTime, cacheTime)
+ if cache && (info.ContentWriteTime.Equal(cacheTime) || info.ContentWriteTime.Before(cacheTime)) {
+ return true, nil
+ }
+ info.ContentLock.AckWrite()
+
+ // cache is not valid, so do not grant permission
+ return false, nil
+}
+
+func (manager *SafeOSFSManager) AckWrite(inode fuseops.InodeID) (time.Time, error) {
+ info, e := manager.GetInfo(inode)
+ if e != nil {
+ return time.Time{}, e
+ }
+ info.MetadataLock.RequestWrite()
+ info.ContentWriteTime = time.Now()
+ output := info.ContentWriteTime
+ info.MetadataLock.AckWrite()
+ info.ContentLock.AckWrite()
+ return output, nil
+}
+
+func (manager *SafeOSFSManager) Destroy() error { return nil }
diff --git a/mft-fs/archive/safe-remotefs/server/server_manager.go b/mft-fs/archive/safe-remotefs/server/server_manager.go
new file mode 100644
index 00000000..1e65d673
--- /dev/null
+++ b/mft-fs/archive/safe-remotefs/server/server_manager.go
@@ -0,0 +1,204 @@
+package server
+
+import (
+ "context"
+ "fmt"
+ "github.com/jacobsa/fuse/fuseops"
+ "google.golang.org/protobuf/types/known/timestamppb"
+ safe_remotefscomms2 "mft-fs/archive/safe-remotefs/safe-remotefscomms"
+ "os"
+ "time"
+)
+
+type Server struct {
+ safe_remotefscomms2.UnimplementedRemoteFSCommsServer
+ manager *SafeOSFSManager
+}
+
+func NewServerHandler(root string) *Server {
+ output := &Server{
+ manager: NewSafeOSFSManager(root),
+ }
+ return output
+}
+
+func (server *Server) GetSizeComm(ctx context.Context, in *safe_remotefscomms2.Empty) (*safe_remotefscomms2.UintMsg, error) {
+ fmt.Println("GetSizeComm")
+ size, e := server.manager.GetSize()
+ if e != nil {
+ return nil, e
+ }
+ return &safe_remotefscomms2.UintMsg{Data: size}, nil
+}
+
+func (server *Server) GetLengthComm(ctx context.Context, in *safe_remotefscomms2.Empty) (*safe_remotefscomms2.UintMsg, error) {
+ fmt.Println("GetLengthComm")
+ length, e := server.manager.GetLength()
+ if e != nil {
+ return nil, e
+ }
+ return &safe_remotefscomms2.UintMsg{Data: length}, nil
+}
+
+func (server *Server) GetInfoComm(ctx context.Context, in *safe_remotefscomms2.UintMsg) (*safe_remotefscomms2.FileInfoMsg, error) {
+ fmt.Println("GetInfoComm")
+ info, e := server.manager.GetInfo(fuseops.InodeID(in.Data))
+ if e != nil {
+ return nil, e
+ }
+ output := &safe_remotefscomms2.FileInfoMsg{
+ ChildrenIndexMap: make(map[string]uint32),
+ }
+ info.MetadataLock.RequestRead()
+ safe_remotefscomms2.ConvertToComm(info, output)
+ info.MetadataLock.AckRead()
+ return output, nil
+}
+
+func (server *Server) SetInfoComm(ctx context.Context, in *safe_remotefscomms2.SetInfoParamsMsg) (*safe_remotefscomms2.Empty, error) {
+ fmt.Println("SetInfoComm")
+ var uidptr *uint32
+ var gidptr *uint32
+ var sizeptr *uint64
+ var modeptr *os.FileMode
+ var atimeptr *time.Time
+ var mtimeptr *time.Time
+ if in.Uid != -1 {
+ var temp uint32 = uint32(in.Uid)
+ uidptr = &temp
+ } else {
+ uidptr = nil
+ }
+ if in.Gid != -1 {
+ var temp uint32 = uint32(in.Uid)
+ gidptr = &temp
+ } else {
+ gidptr = nil
+ }
+ if in.Mode != -1 {
+ var temp os.FileMode = os.FileMode(in.Mode)
+ modeptr = &temp
+ } else {
+ modeptr = nil
+ }
+ if in.Size != -1 {
+ var temp uint64 = uint64(in.Size)
+ sizeptr = &temp
+ } else {
+ sizeptr = nil
+ }
+ if !in.Atime.AsTime().Equal(time.Time{}) {
+ var temp time.Time = in.Atime.AsTime()
+ atimeptr = &temp
+ } else {
+ atimeptr = nil
+ }
+ if !in.Mtime.AsTime().Equal(time.Time{}) {
+ var temp time.Time = in.Mtime.AsTime()
+ mtimeptr = &temp
+ } else {
+ mtimeptr = nil
+ }
+ e := server.manager.SetInfo(fuseops.InodeID(in.Inode), uidptr, gidptr, sizeptr, modeptr, atimeptr, mtimeptr)
+ if e != nil {
+ return nil, e
+ }
+ return &safe_remotefscomms2.Empty{}, nil
+}
+
+func (server *Server) DeleteComm(ctx context.Context, in *safe_remotefscomms2.UintMsg) (*safe_remotefscomms2.Empty, error) {
+ fmt.Println("DeleteComm")
+ e := server.manager.Delete(fuseops.InodeID(in.Data))
+ if e != nil {
+ return nil, e
+ }
+ return &safe_remotefscomms2.Empty{}, nil
+}
+
+func (server *Server) MkDirComm(ctx context.Context, in *safe_remotefscomms2.MkInodeMsg) (*safe_remotefscomms2.UintMsg, error) {
+ fmt.Println("MkDirComm")
+ inode, e := server.manager.MkDir(fuseops.InodeID(in.Parent), in.Name, os.FileMode(in.Mode))
+ if e != nil {
+ return nil, e
+ }
+ return &safe_remotefscomms2.UintMsg{Data: uint64(inode)}, nil
+}
+
+func (server *Server) CreateFileComm(ctx context.Context, in *safe_remotefscomms2.MkInodeMsg) (*safe_remotefscomms2.UintMsg, error) {
+ fmt.Println("CreateFileComm")
+ inode, e := server.manager.CreateFile(fuseops.InodeID(in.Parent), in.Name, os.FileMode(in.Mode))
+ if e != nil {
+ return nil, e
+ }
+ return &safe_remotefscomms2.UintMsg{Data: uint64(inode)}, nil
+}
+
+func (server *Server) RmDirComm(ctx context.Context, in *safe_remotefscomms2.UintMsg) (*safe_remotefscomms2.Empty, error) {
+ fmt.Println("RmDirComm")
+ e := server.manager.RmDir(fuseops.InodeID(in.Data))
+ if e != nil {
+ return nil, e
+ }
+ return &safe_remotefscomms2.Empty{}, nil
+}
+
+func (server *Server) SyncFileComm(ctx context.Context, in *safe_remotefscomms2.UintMsg) (*safe_remotefscomms2.Empty, error) {
+ fmt.Println("SyncFileComm")
+ e := server.manager.SyncFile(fuseops.InodeID(in.Data))
+ if e != nil {
+ return nil, e
+ }
+ return &safe_remotefscomms2.Empty{}, nil
+}
+
+func (server *Server) WriteAtComm(ctx context.Context, in *safe_remotefscomms2.WriteAtMsg) (*safe_remotefscomms2.UintMsg, error) {
+ fmt.Println("WriteAtComm")
+ n, _ := server.manager.WriteAt(fuseops.InodeID(in.Inode), in.Data, in.Off)
+ return &safe_remotefscomms2.UintMsg{Data: uint64(n)}, nil
+}
+
+func (server *Server) ReadAtComm(ctx context.Context, in *safe_remotefscomms2.ReadAtMsg) (*safe_remotefscomms2.ReadAtResponseMsg, error) {
+ fmt.Println("ReadAtComm")
+ data := make([]byte, in.Size)
+ n, _ := server.manager.ReadAt(fuseops.InodeID(in.Inode), data, in.Off)
+ return &safe_remotefscomms2.ReadAtResponseMsg{
+ Data: data,
+ N: int64(n),
+ }, nil
+}
+
+func (server *Server) RequestReadComm(ctx context.Context, in *safe_remotefscomms2.RequestResourceMsg) (*safe_remotefscomms2.RequestResponseMsg, error) {
+ fmt.Println("RequestReadComm")
+ success, e := server.manager.RequestRead(fuseops.InodeID(in.Inode), in.Cache, in.CacheTime.AsTime())
+ if e != nil {
+ return nil, e
+ }
+ return &safe_remotefscomms2.RequestResponseMsg{Success: success}, nil
+}
+
+func (server *Server) RequestWriteComm(ctx context.Context, in *safe_remotefscomms2.RequestResourceMsg) (*safe_remotefscomms2.RequestResponseMsg, error) {
+ fmt.Println("RequestWriteComm")
+ success, e := server.manager.RequestWrite(fuseops.InodeID(in.Inode), in.Cache, in.CacheTime.AsTime())
+ if e != nil {
+ return nil, e
+ }
+ return &safe_remotefscomms2.RequestResponseMsg{Success: success}, nil
+}
+
+func (server *Server) AckReadComm(ctx context.Context, in *safe_remotefscomms2.UintMsg) (*safe_remotefscomms2.AckResponseMsg, error) {
+ fmt.Println("AckReadComm")
+ timestamp, e := server.manager.AckRead(fuseops.InodeID(in.Data))
+ if e != nil {
+ return nil, e
+ }
+ return &safe_remotefscomms2.AckResponseMsg{WriteTime: timestamppb.New(timestamp)}, nil
+}
+
+func (server *Server) AckWriteComm(ctx context.Context, in *safe_remotefscomms2.UintMsg) (*safe_remotefscomms2.AckResponseMsg, error) {
+ fmt.Println("AckWriteComm")
+ timestamp, e := server.manager.AckWrite(fuseops.InodeID(in.Data))
+ if e != nil {
+ return nil, e
+ }
+ return &safe_remotefscomms2.AckResponseMsg{WriteTime: timestamppb.New(timestamp)}, nil
+}
diff --git a/mft-fs/archive/safe-remotefs/servermain/server_main.go b/mft-fs/archive/safe-remotefs/servermain/server_main.go
new file mode 100644
index 00000000..2ad5ed1d
--- /dev/null
+++ b/mft-fs/archive/safe-remotefs/servermain/server_main.go
@@ -0,0 +1,26 @@
+package main
+
+import (
+ "flag"
+ "google.golang.org/grpc"
+ "log"
+ "mft-fs/archive/safe-remotefs/safe-remotefscomms"
+ "mft-fs/archive/safe-remotefs/server"
+ "net"
+)
+
+func main() {
+
+ rootDirectory := flag.String("rootDirectory", "", "Root Directory")
+ flag.Parse()
+
+ lis, e := net.Listen("tcp", ":8000")
+ if e != nil {
+ log.Fatalf("Error: %v\n", e)
+ }
+ defer lis.Close()
+
+ s := grpc.NewServer()
+ safe_remotefscomms.RegisterRemoteFSCommsServer(s, server.NewServerHandler(*rootDirectory))
+ s.Serve(lis)
+}
diff --git a/mft-fs/datastructures/queue.go b/mft-fs/datastructures/queue.go
new file mode 100644
index 00000000..07789ecc
--- /dev/null
+++ b/mft-fs/datastructures/queue.go
@@ -0,0 +1,32 @@
+package datastructures
+
+type Queue struct {
+ backingArray []interface{}
+}
+
+func NewQueue() *Queue {
+ output := new(Queue)
+ output.backingArray = make([]interface{}, 0)
+ return output
+}
+
+func (q *Queue) IsEmpty() bool {
+ return len(q.backingArray) == 0
+}
+
+func (q *Queue) Size() int {
+ return len(q.backingArray)
+}
+
+func (q *Queue) Enqueue(v interface{}) {
+ q.backingArray = append(q.backingArray, v)
+}
+
+func (q *Queue) Dequeue() interface{} {
+ if len(q.backingArray) == 0 {
+ return nil
+ }
+ output := q.backingArray[0]
+ q.backingArray = q.backingArray[1:]
+ return output
+}
diff --git a/mft-fs/datastructures/read_write_lock.go b/mft-fs/datastructures/read_write_lock.go
new file mode 100644
index 00000000..5a899b2b
--- /dev/null
+++ b/mft-fs/datastructures/read_write_lock.go
@@ -0,0 +1,74 @@
+package datastructures
+
+import (
+ "sync"
+)
+
+type CREWResource struct {
+ reads int
+ readsMutex *sync.Mutex
+ doneReads *sync.Cond
+
+ allowRead bool
+ allowReadMutex *sync.Mutex
+ doneWrite *sync.Cond
+}
+
+func NewCREWResource() *CREWResource {
+ mutex1 := &sync.Mutex{}
+ mutex2 := &sync.Mutex{}
+
+ return &CREWResource{
+ reads: 0,
+ readsMutex: mutex1,
+ doneReads: &sync.Cond{L: mutex1},
+
+ allowRead: true,
+ allowReadMutex: mutex2,
+ doneWrite: &sync.Cond{L: mutex2},
+ }
+}
+
+func (resource *CREWResource) RequestRead() {
+ resource.allowReadMutex.Lock()
+ for !resource.allowRead {
+ resource.doneWrite.Wait()
+ }
+ resource.readsMutex.Lock()
+ resource.reads++
+ resource.readsMutex.Unlock()
+ resource.allowReadMutex.Unlock()
+}
+
+func (resource *CREWResource) AckRead() {
+ resource.readsMutex.Lock()
+ resource.reads--
+ if resource.reads == 0 {
+ resource.doneReads.Signal()
+ }
+ resource.readsMutex.Unlock()
+}
+
+func (resource *CREWResource) RequestWrite() {
+ // wait for any writes to finish and set allow reads to false
+ resource.allowReadMutex.Lock()
+ for !resource.allowRead {
+ resource.doneWrite.Wait()
+ }
+ resource.allowRead = false
+ resource.allowReadMutex.Unlock()
+
+ // wait for all reads to finish
+ resource.readsMutex.Lock()
+ for resource.reads > 0 {
+ resource.doneReads.Wait()
+ }
+ resource.readsMutex.Unlock()
+}
+
+func (resource *CREWResource) AckWrite() {
+ resource.allowReadMutex.Lock()
+ resource.allowRead = true
+ resource.doneWrite.Broadcast()
+ resource.allowReadMutex.Unlock()
+}
diff --git a/mft-fs/datastructures/slice_operations.go b/mft-fs/datastructures/slice_operations.go
new file mode 100644
index 00000000..db6fb89f
--- /dev/null
+++ b/mft-fs/datastructures/slice_operations.go
@@ -0,0 +1,8 @@
+package datastructures
+
+func Remove[T any](slice []T, i int) []T {
+ if i+1 < len(slice) {
+ return append(slice[:i], slice[i+1:]...)
+ }
+ return slice[:i]
+}
diff --git a/mft-fs/go.sum b/mft-fs/go.sum
new file mode 100644
index 00000000..d66a41b3
--- /dev/null
+++ b/mft-fs/go.sum
@@ -0,0 +1,95 @@
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/jacobsa/fuse v0.0.0-20240607092844-7285af0d05b0 h1:IWVMQZZvWN+9FeRwWnZAINYNrsr3yyCWI2BcddQBDvk=
+github.com/jacobsa/fuse v0.0.0-20240607092844-7285af0d05b0/go.mod h1:JYi9iIxdYNgxmMgLwtSHO/hmVnP2kfX1oc+mtx+XWLA=
+github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
+github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
+github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
+github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
+github.com/pkg/sftp v1.13.9 h1:4NGkvGudBL7GteO3m6qnaQ4pC0Kvf0onSVc9gR3EWBw=
+github.com/pkg/sftp v1.13.9/go.mod h1:OBN7bVXdstkFFN/gdnHPUb5TE8eb8G1Rp9wCItqjkkA=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
+golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
+golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
+golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
+golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
+golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
+golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
+golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
+golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
+golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
+golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
+golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
+golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
+golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
+golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
+golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
+golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
+golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
+golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 h1:Zy9XzmMEflZ/MAaA7vNcoebnRAld7FsPW1EeBB7V0m8=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
+google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
+google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
+google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
+google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/mft-fs/gomod.txt b/mft-fs/gomod.txt
new file mode 100644
index 00000000..361352ae
--- /dev/null
+++ b/mft-fs/gomod.txt
@@ -0,0 +1,22 @@
+module mft-fs
+
+go 1.21
+
+toolchain go1.22.3
+
+require github.com/jacobsa/fuse v0.0.0-20240607092844-7285af0d05b0
+
+require (
+ golang.org/x/sys v0.28.0
+ google.golang.org/grpc v1.65.0
+)
+
+require (
+ github.com/kr/fs v0.1.0 // indirect
+ github.com/pkg/sftp v1.13.9 // indirect
+ golang.org/x/crypto v0.31.0 // indirect
+ golang.org/x/net v0.25.0 // indirect
+ golang.org/x/text v0.21.0 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect
+ google.golang.org/protobuf v1.34.1 // indirect
+)
diff --git a/mft-fs/grpcfs/grpcfs.go b/mft-fs/grpcfs/grpcfs.go
new file mode 100644
index 00000000..ef8bcbef
--- /dev/null
+++ b/mft-fs/grpcfs/grpcfs.go
@@ -0,0 +1,302 @@
+package grpcfs
+
+import (
+ "context"
+ "crypto/rand"
+ "errors"
+ "fmt"
+ "github.com/jacobsa/fuse/fuseops"
+ "google.golang.org/grpc"
+ "google.golang.org/protobuf/types/known/timestamppb"
+ "mft-fs/archive/abstractfs"
+ safe_remotefscomms2 "mft-fs/archive/safe-remotefs/safe-remotefscomms"
+ "os"
+ "time"
+)
+
+type cacheInfo struct {
+ cache bool
+ cacheTime time.Time
+ handle fuseops.HandleID
+}
+
+func minimum(a int, b int) int {
+ if a < b {
+ return a
+ }
+ return b
+}
+
+func newCacheInfo() *cacheInfo {
+ return &cacheInfo{
+ cache: false,
+ cacheTime: time.Unix(0, 0),
+ handle: fuseops.HandleID(0),
+ }
+}
+
+type ClientManager struct {
+ abstractfs.FSManager
+ client safe_remotefscomms2.RemoteFSCommsClient
+ cachePath string
+ localInfo map[fuseops.InodeID]*cacheInfo
+ handleToInode map[fuseops.HandleID]fuseops.InodeID
+}
+
+func NewClientManager(conn *grpc.ClientConn, cachePath string) (*ClientManager, error) {
+ output := &ClientManager{
+ cachePath: cachePath,
+ localInfo: make(map[fuseops.InodeID]*cacheInfo),
+ handleToInode: make(map[fuseops.HandleID]fuseops.InodeID),
+ }
+ output.client = safe_remotefscomms2.NewRemoteFSCommsClient(conn)
+ return output, nil
+}
+
+func (manager *ClientManager) GetSize() (uint64, error) {
+ resp, e := manager.client.GetSizeComm(context.Background(), &safe_remotefscomms2.Empty{})
+ if e != nil {
+ return 0, e
+ }
+ return resp.Data, nil
+}
+
+func (manager *ClientManager) GetLength() (uint64, error) {
+ resp, e := manager.client.GetLengthComm(context.Background(), &safe_remotefscomms2.Empty{})
+ if e != nil {
+ return 0, e
+ }
+ return resp.Data, nil
+}
+
+func (manager *ClientManager) GetInfo(inode fuseops.InodeID) (*abstractfs.FileInfo, error) {
+ resp, e := manager.client.GetInfoComm(context.Background(), &safe_remotefscomms2.UintMsg{
+ Data: uint64(inode),
+ })
+ if e != nil {
+ return nil, e
+ }
+ output := &abstractfs.FileInfo{
+ ChildrenIndexMap: make(map[string]int),
+ }
+ safe_remotefscomms2.ConvertFromComm(resp, output)
+ info, ok := manager.localInfo[inode]
+ if ok {
+ output.Handle = info.handle
+ }
+ return output, nil
+}
+
+func (manager *ClientManager) SetInfo(inode fuseops.InodeID, uidptr *uint32, gidptr *uint32, sizeptr *uint64, modeptr *os.FileMode, atimeptr *time.Time, mtimeptr *time.Time) error {
+ request := &safe_remotefscomms2.SetInfoParamsMsg{
+ Inode: uint64(inode),
+ Uid: -1,
+ Gid: -1,
+ Size: -1,
+ Mode: -1,
+ Atime: timestamppb.New(time.Time{}),
+ Mtime: timestamppb.New(time.Time{}),
+ }
+ if uidptr != nil {
+ request.Uid = int32(*uidptr)
+ }
+ if gidptr != nil {
+ request.Gid = int32(*gidptr)
+ }
+ if sizeptr != nil {
+ request.Size = int64(*sizeptr)
+ }
+ if modeptr != nil {
+ request.Mode = int32(*modeptr)
+ }
+ if atimeptr != nil {
+ request.Atime = timestamppb.New(*atimeptr)
+ }
+ if mtimeptr != nil {
+ request.Mtime = timestamppb.New(*mtimeptr)
+ }
+ _, e := manager.client.SetInfoComm(context.Background(), request)
+ return e
+}
+
+func (manager *ClientManager) Delete(inode fuseops.InodeID) error {
+ _, e := manager.client.DeleteComm(context.Background(), &safe_remotefscomms2.UintMsg{Data: uint64(inode)})
+ return e
+}
+
+func (manager *ClientManager) MkDir(parent fuseops.InodeID, name string, mode os.FileMode) (fuseops.InodeID, error) {
+ resp, e := manager.client.MkDirComm(context.Background(), &safe_remotefscomms2.MkInodeMsg{
+ Parent: uint64(parent),
+ Name: name,
+ Mode: uint32(mode),
+ })
+ if e != nil {
+ return 0, e
+ }
+ return fuseops.InodeID(resp.Data), nil
+}
+
+func (manager *ClientManager) GenerateHandle(inode fuseops.InodeID) (fuseops.HandleID, error) {
+ var buff [8]byte
+ _, e := rand.Read(buff[:])
+ if e != nil {
+ return 0, e
+ }
+ var output uint64 = 0
+ for i := 0; i < len(buff); i++ {
+ output = output | uint64(buff[i]<<(8*i))
+ }
+ handle := fuseops.HandleID(output)
+ _, ok := manager.handleToInode[handle]
+ if ok {
+ return manager.GenerateHandle(inode)
+ }
+ info, ok := manager.localInfo[inode]
+ if !ok {
+ manager.localInfo[inode] = newCacheInfo()
+ info = manager.localInfo[inode]
+ }
+ info.handle = handle
+ manager.handleToInode[handle] = inode
+ return handle, nil
+}
+func (manager *ClientManager) CreateFile(parent fuseops.InodeID, name string, mode os.FileMode) (fuseops.InodeID, error) {
+ resp, e := manager.client.CreateFileComm(context.Background(), &safe_remotefscomms2.MkInodeMsg{
+ Parent: uint64(parent),
+ Name: name,
+ Mode: uint32(mode),
+ })
+ if e != nil {
+ return 0, e
+ }
+ return fuseops.InodeID(resp.Data), nil
+}
+
+func (manager *ClientManager) RmDir(inode fuseops.InodeID) error {
+ _, e := manager.client.RmDirComm(context.Background(), &safe_remotefscomms2.UintMsg{Data: uint64(inode)})
+ return e
+}
+
+func (manager *ClientManager) DeleteHandle(handle fuseops.HandleID) error {
+ delete(manager.handleToInode, handle)
+ return nil
+}
+
+func (manager *ClientManager) SyncFile(inode fuseops.InodeID) error {
+ _, e := manager.client.SyncFileComm(context.Background(), &safe_remotefscomms2.UintMsg{Data: uint64(inode)})
+ return e
+}
+
+func (manager *ClientManager) WriteAt(inode fuseops.InodeID, data []byte, off int64) (n int, err error) {
+
+ info, ok := manager.localInfo[inode]
+ if !ok {
+ fmt.Println("cache map issue")
+ return 0, errors.New("local cache not updated")
+ }
+
+ msg := safe_remotefscomms2.RequestResourceMsg{
+ CacheTime: timestamppb.New(info.cacheTime),
+ Inode: uint64(inode),
+ Cache: info.cache,
+ }
+
+ requestResp, e := manager.client.RequestWriteComm(context.Background(), &msg)
+ if e != nil {
+ return 0, e
+ }
+
+ if requestResp.Success {
+ resp, e := manager.client.WriteAtComm(context.Background(), &safe_remotefscomms2.WriteAtMsg{
+ Inode: uint64(inode),
+ Data: data,
+ Off: off,
+ })
+ if e != nil {
+ return 0, e
+ }
+
+ ackResp, e := manager.client.AckWriteComm(context.Background(), &safe_remotefscomms2.UintMsg{Data: uint64(inode)})
+ if e != nil {
+ return 0, e
+ }
+
+ manager.localInfo[inode].cache = true
+ manager.localInfo[inode].cacheTime = ackResp.WriteTime.AsTime()
+
+ file, e := os.OpenFile(fmt.Sprintf("%s/file%d.txt", manager.cachePath, int(inode)), os.O_RDWR|os.O_CREATE, 777)
+ if e != nil {
+ return 0, e
+ }
+ _, e = file.WriteAt(data, off)
+ if e != nil {
+ return 0, e
+ }
+
+ return int(resp.Data), nil
+ }
+
+ fmt.Println("cache timing issue")
+ return 0, errors.New("local cache not updated")
+}
+func (manager *ClientManager) ReadAt(inode fuseops.InodeID, data []byte, off int64) (n int, err error) {
+
+ msg := safe_remotefscomms2.RequestResourceMsg{
+ CacheTime: timestamppb.New(time.Unix(0, 0)),
+ Inode: uint64(inode),
+ Cache: false,
+ }
+
+ info, ok := manager.localInfo[inode]
+ if ok {
+ msg.Cache = info.cache
+ msg.CacheTime = timestamppb.New(info.cacheTime)
+ } else {
+ manager.localInfo[inode] = newCacheInfo()
+ }
+
+ requestResp, e := manager.client.RequestReadComm(context.Background(), &msg)
+ if e != nil {
+ return 0, e
+ }
+
+ if requestResp.Success {
+ resp, e := manager.client.ReadAtComm(context.Background(), &safe_remotefscomms2.ReadAtMsg{
+ Inode: uint64(inode),
+ Size: int64(len(data)),
+ Off: off,
+ })
+ if e != nil {
+ return 0, e
+ }
+ ackResp, e := manager.client.AckReadComm(context.Background(), &safe_remotefscomms2.UintMsg{Data: uint64(inode)})
+ if e != nil {
+ return 0, e
+ }
+ manager.localInfo[inode].cacheTime = ackResp.WriteTime.AsTime()
+ manager.localInfo[inode].cache = true
+ for i := 0; i < minimum(len(data), len(resp.Data)); i++ {
+ data[i] = resp.Data[i]
+ }
+ file, e := os.OpenFile(fmt.Sprintf("%s/file%d.txt", manager.cachePath, int(inode)), os.O_RDWR|os.O_CREATE, 777)
+ if e != nil {
+ return 0, e
+ }
+ _, e = file.WriteAt(data, off)
+ if e != nil {
+ return 0, e
+ }
+ return int(resp.N), nil
+ } else {
+ file, e := os.OpenFile(fmt.Sprintf("%s/file%d.txt", manager.cachePath, int(inode)), os.O_RDWR, 777)
+ if e != nil {
+ return 0, e
+ }
+ n, _ := file.ReadAt(data, off)
+ return n, nil
+ }
+}
+
+func (manager *ClientManager) Destroy() error {
+ return nil
+}
diff --git a/mft-fs/images/many_clients.png b/mft-fs/images/many_clients.png
new file mode 100644
index 00000000..1e99c0dc
Binary files /dev/null and b/mft-fs/images/many_clients.png differ
diff --git a/mft-fs/images/problem.png b/mft-fs/images/problem.png
new file mode 100644
index 00000000..2701e6e2
Binary files /dev/null and b/mft-fs/images/problem.png differ
diff --git a/mft-fs/images/single_client.png b/mft-fs/images/single_client.png
new file mode 100644
index 00000000..13be800a
Binary files /dev/null and b/mft-fs/images/single_client.png differ
diff --git a/mft-fs/images/solution.png b/mft-fs/images/solution.png
new file mode 100644
index 00000000..769a93f3
Binary files /dev/null and b/mft-fs/images/solution.png differ
diff --git a/mft-fs/main.go b/mft-fs/main.go
new file mode 100644
index 00000000..48e0b2ff
--- /dev/null
+++ b/mft-fs/main.go
@@ -0,0 +1,424 @@
+package main
+
+import (
+ "bufio"
+ "context"
+ "encoding/json"
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "math/rand"
+ "os"
+ "path/filepath"
+ "strconv"
+ "strings"
+
+ "github.com/jacobsa/fuse"
+ "github.com/jacobsa/fuse/fuseutil"
+
+ "mft-fs/abstractfs"
+ "mft-fs/osfs"
+ "mft-fs/sftpfs"
+)
+
+// --------------- GLOBAL VARIABLES ---------------------
+
+var mftfsDir string = "/Users/rohanphadnis/GeorgiaTech/ArtisanResearch/airavata-mft/mft-fs/mftfs_data"
+var infoData *InfoFile
+
+const IdLength uint8 = 16
+
+// ------------- DATA STRUCTURES -------------------------
+
+// InfoFile represents the structure of the info.json file.
+type InfoFile struct {
+ PathToID map[string]string `json:"path_to_id"`
+ IDToData map[string]FilesystemEntry `json:"id_to_data"`
+}
+
+func (info *InfoFile) generateId() string {
+ output := make([]byte, IdLength)
+ for i := uint8(0); i < IdLength; i++ {
+ output[i] = uint8(rand.Float64()*26 + 65)
+ }
+ _, ok := info.IDToData[string(output)]
+ if ok {
+ return info.generateId()
+ }
+ return string(output)
+}
+
+func (info *InfoFile) AddNewFs(mountDir string, fsType string, fsConfig *Config) {
+ identity := info.generateId()
+ info.IDToData[identity] = FilesystemEntry{
+ ID: identity,
+ Path: mountDir,
+ Type: fsType,
+ Config: fsConfig,
+ }
+ info.PathToID[mountDir] = identity
+
+ err := writeInfo()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error writing info file: %v\n", err)
+ }
+}
+
+type Config struct {
+ SftpConfig *sftpfs.SftpClientConfig
+ OsfsConfig *osfs.Config
+ // add other configuration variables
+}
+
+// FilesystemEntry holds the metadata for a single mounted filesystem.
+type FilesystemEntry struct {
+ ID string `json:"id"`
+ Path string `json:"path"`
+ Type string `json:"type"`
+ Config *Config `json:"config"`
+}
+
+// Command-line flags.
+var (
+ helpFlag bool
+ initFlag string
+ destroyFlag string
+ infoFlag bool
+)
+
+func init() {
+ flag.BoolVar(&helpFlag, "help", false, "Display help information for the program.")
+ flag.StringVar(&initFlag, "init", "", "Initialize and mount a filesystem at the specified directory.")
+ flag.StringVar(&destroyFlag, "destroy", "", "Unmount and destroy the filesystem at the specified directory.")
+ flag.BoolVar(&infoFlag, "info", false, "Display information about the mounted filesystem.")
+}
+
+// --------------- MAIN METHOD ------------------
+
+func main() {
+ flag.Parse()
+
+ // Perform a one-time setup to ensure the metadata directory exists.
+ if err := startup(); err != nil {
+ fmt.Fprintf(os.Stderr, "Startup failed: %v\n", err)
+ os.Exit(1)
+ }
+
+ // Read the info.json file into memory.
+ if err := readInfo(); err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to read info.json: %v\n", err)
+ os.Exit(1)
+ }
+
+ // Handle the command-line flags.
+ switch {
+ case helpFlag:
+ handleHelp()
+ case initFlag != "":
+ handleInit(initFlag)
+ runFilesystem(initFlag)
+ case destroyFlag != "":
+ handleDestroy(destroyFlag)
+ case infoFlag:
+ handleInfo()
+ default:
+ handleHelp()
+ }
+}
+
+func runFilesystem(mountDir string) {
+ fmt.Println("running filesystem!")
+
+ absMountDir, err := filepath.Abs(mountDir)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Invalid mount directory path: %v\n", err)
+ os.Exit(1)
+ }
+
+ id, ok := infoData.PathToID[absMountDir]
+ if !ok {
+ fmt.Fprintf(os.Stderr, "Could not find mount directory %s\n", absMountDir)
+ os.Exit(1)
+ }
+
+ fsInfo, ok := infoData.IDToData[id]
+ if !ok {
+ fmt.Fprintf(os.Stderr, "Could not find file system info for %s\n", id)
+ os.Exit(1)
+ }
+
+ if fsInfo.Config == nil {
+ fmt.Fprintln(os.Stderr, "Null value of configuration")
+ os.Exit(1)
+ }
+
+ var fs *abstractfs.AbstractFS
+
+ switch fsInfo.Type {
+ case "osfs":
+ fs = osfs.NewOSFS(absMountDir, fsInfo.Config.OsfsConfig)
+ case "sftpfs":
+ fs = sftpfs.NewSFTPFS(absMountDir, fsInfo.Config.SftpConfig)
+ default:
+ fmt.Fprintf(os.Stderr, "Filesystem type %s not implemented\n", fsInfo.Type)
+ os.Exit(1)
+ }
+
+ if fs == nil {
+ fmt.Fprintf(os.Stderr, "Could not find mount directory 678 %s\n", absMountDir)
+ os.Exit(1)
+ }
+
+ err = fs.Manager.Start()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Startup failed: %v\n", err)
+ os.Exit(1)
+ }
+ server := fuseutil.NewFileSystemServer(fs)
+
+ // mount the filesystem
+ cfg := &fuse.MountConfig{
+ ReadOnly: false,
+ DebugLogger: log.New(os.Stderr, "fuse: ", 0),
+ ErrorLogger: log.New(os.Stderr, "fuse: ", 0),
+ }
+ mfs, err := fuse.Mount(mountDir, server, cfg)
+ if err != nil {
+ log.Fatalf("Mount: %v", err)
+ }
+
+ // wait for it to be unmounted
+ if err = mfs.Join(context.Background()); err != nil {
+ log.Fatalf("Join: %v", err)
+ }
+}
+
+// startup ensures the .mftfs directory structure exists.
+func startup() error {
+ /*
+ todo: uncomment this for eventual release
+ homeDir, err := os.UserHomeDir()
+ if err != nil {
+ return fmt.Errorf("could not find user home directory: %w", err)
+ }
+
+ mftfsDir = filepath.Join(homeDir, ".mftfs")*/
+
+ infoPath := filepath.Join(mftfsDir, "info.json")
+ cacheDir := filepath.Join(mftfsDir, "cache")
+
+ // Create .mftfs directory if it doesn't exist.
+ if err := os.MkdirAll(mftfsDir, 0755); err != nil {
+ return fmt.Errorf("failed to create .mftfs directory: %w", err)
+ }
+
+ // Create cache directory if it doesn't exist.
+ if err := os.MkdirAll(cacheDir, 0755); err != nil {
+ return fmt.Errorf("failed to create cache directory: %w", err)
+ }
+
+ // Create empty info.json file if it doesn't exist.
+ if _, err := os.Stat(infoPath); os.IsNotExist(err) {
+ initialInfo := InfoFile{
+ PathToID: make(map[string]string),
+ IDToData: make(map[string]FilesystemEntry),
+ }
+ data, err := json.MarshalIndent(initialInfo, "", " ")
+ if err != nil {
+ return fmt.Errorf("failed to marshal initial info.json: %w", err)
+ }
+ if err := ioutil.WriteFile(infoPath, data, 0644); err != nil {
+ return fmt.Errorf("failed to write initial info.json: %w", err)
+ }
+ }
+
+ return nil
+}
+
+// ----------------- INFO FILE UTILITIES -------------------
+
+// readInfo loads the metadata from the info.json file.
+func readInfo() error {
+ infoPath := filepath.Join(mftfsDir, "info.json")
+ data, err := ioutil.ReadFile(infoPath)
+ if err != nil {
+ return fmt.Errorf("failed to read info.json: %w", err)
+ }
+
+ infoData = &InfoFile{}
+ if err := json.Unmarshal(data, infoData); err != nil {
+ return fmt.Errorf("failed to unmarshal info.json: %w", err)
+ }
+
+ // Initialize maps if they were nil after unmarshalling an empty JSON object.
+ if infoData.PathToID == nil {
+ infoData.PathToID = make(map[string]string)
+ }
+ if infoData.IDToData == nil {
+ infoData.IDToData = make(map[string]FilesystemEntry)
+ }
+
+ return nil
+}
+
+// writeInfo saves the current in-memory infoData to info.json.
+func writeInfo() error {
+ data, err := json.MarshalIndent(infoData, "", " ")
+ if err != nil {
+ return fmt.Errorf("failed to marshal infoData: %w", err)
+ }
+ infoPath := filepath.Join(mftfsDir, "info.json")
+ if err := ioutil.WriteFile(infoPath, data, 0644); err != nil {
+ return fmt.Errorf("failed to write info.json: %w", err)
+ }
+ return nil
+}
+
+// ------------------- CLI HANDLERS -----------------
+
+// handleHelp displays the usage information for the CLI tool.
+func handleHelp() {
+ fmt.Println("Usage: mftfs [flags]")
+ fmt.Println("A command-line tool to manage your FUSE filesystems.")
+ fmt.Println("\nFlags:")
+ flag.PrintDefaults()
+}
+
+// handleInit guides the user through the filesystem initialization process.
+func handleInit(mountDir string) {
+ reader := bufio.NewReader(os.Stdin)
+ absMountDir, err := filepath.Abs(mountDir)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Invalid mount directory path: %v\n", err)
+ os.Exit(1)
+ }
+
+ // Check if the mount path exists in the metadata.
+ fsID, ok := infoData.PathToID[absMountDir]
+ if ok {
+ fsEntry, entryExists := infoData.IDToData[fsID]
+ if !entryExists {
+ fmt.Println("Error: Metadata inconsistency detected.")
+ os.Exit(1)
+ }
+
+ fmt.Printf("There was previously a filesystem of type %s on this path. Do you want to relaunch it? [y/n]: ", fsEntry.Type)
+ response := readInput(reader, "")
+
+ if strings.ToLower(response) == "y" {
+ fmt.Printf("Relaunching existing %s filesystem at %s.\n", fsEntry.Type, absMountDir)
+ // TODO: Add logic to use fsEntry.Config to mount the filesystem.
+ return
+ }
+
+ if strings.ToLower(response) == "n" {
+ // User wants a new filesystem, so remove the old metadata.
+ delete(infoData.PathToID, absMountDir)
+ delete(infoData.IDToData, fsID)
+ if err := writeInfo(); err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to update info.json: %v\n", err)
+ os.Exit(1)
+ }
+ fmt.Println("Removed old filesystem metadata. Starting a new initialization.")
+ } else {
+ fmt.Println("Invalid response. Exiting.")
+ os.Exit(1)
+ }
+ }
+
+ // Normal initialization flow if no previous record exists or user wants a new one.
+ fmt.Printf("Initializing a new filesystem at: %s\n", absMountDir)
+ fsType := strings.ToLower(readInput(reader, "Type of filesystem (s3fs, osfs, grpcfs, sftpfs): "))
+
+ config := &Config{}
+
+ switch fsType {
+ case "sftpfs":
+ handleSFTPFSInit(reader, config)
+ case "osfs":
+ handleOsfsInit(reader, config)
+ case "s3fs", "grpcfs":
+ fmt.Printf("Support for %s is not yet implemented.\n", fsType)
+ os.Exit(1)
+ default:
+ fmt.Printf("Unknown filesystem type: %s\n", fsType)
+ os.Exit(1)
+ }
+
+ infoData.AddNewFs(absMountDir, fsType, config)
+
+ fmt.Printf("Filesystem of type '%s' is ready to be mounted at '%s'.\n", fsType, absMountDir)
+ fmt.Println("Add your mounting logic here.")
+}
+
+// handleDestroy is a placeholder for the destroy logic.
+func handleDestroy(mountDir string) {
+ fmt.Printf("Attempting to unmount and destroy filesystem at: %s\n", mountDir)
+ fmt.Println("Add your unmounting logic here.")
+}
+
+// handleInfo displays the contents of the info.json file in a pretty-printed format.
+func handleInfo() {
+ fmt.Println("Displaying metadata from info.json:")
+ data, err := json.MarshalIndent(infoData, "", " ")
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error marshaling info data for display: %v\n", err)
+ return
+ }
+ fmt.Println(string(data))
+}
+
+// -------------- FILESYSTEM SPECIFIC HANDLERS ------------------------
+
+// handleSFTPFSInit prompts for and reads SFTP connection details and returns the config map.
+func handleSFTPFSInit(reader *bufio.Reader, config *Config) {
+ fmt.Println("\n--- SFTP-FS Configuration ---")
+ host := readInput(reader, "Host: ")
+ p, err := strconv.ParseInt(readInput(reader, "Port: "), 10, 16)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Invalid port: %v\n", err)
+ os.Exit(1)
+ }
+ port := uint16(p)
+ username := readInput(reader, "Username: ")
+ password := readInput(reader, "Password: ")
+
+ config.SftpConfig = &sftpfs.SftpClientConfig{
+ Host: host,
+ Port: port,
+ Username: username,
+ Password: password,
+ // PrivateKeyPath: ".",
+ RemoteRoot: ".",
+ }
+}
+
+// handleS3FSInit prompts for and reads S3 connection details and returns the config map.
+func handleOsfsInit(reader *bufio.Reader, config *Config) {
+ fmt.Println("\n--- OS-FS Configuration ---")
+ rootDir := readInput(reader, "Root Absolute Path: ")
+
+ config.OsfsConfig = &osfs.Config{RootDir: rootDir}
+}
+
+// handleS3FSInit prompts for and reads S3 connection details and returns the config map.
+func handleS3FSInit(reader *bufio.Reader) {
+ fmt.Println("\n--- S3-FS Configuration ---")
+ // todo: implement
+ /*
+ bucketName := readInput(reader, "Bucket Name: ")
+ region := readInput(reader, "Region: ")
+ awsKey := readInput(reader, "AWS Key: ")
+ awsSecretKey := readInput(reader, "AWS Secret Key: ")
+ */
+}
+
+// ----------------- INFO FILE UTILS -----------------
+
+// readInput is a helper function to read a line of input from the user.
+func readInput(reader *bufio.Reader, prompt string) string {
+ fmt.Print(prompt)
+ input, _ := reader.ReadString('\n')
+ return strings.TrimSpace(input)
+}
diff --git a/mft-fs/osfs/osfs.go b/mft-fs/osfs/osfs.go
new file mode 100644
index 00000000..3841eab4
--- /dev/null
+++ b/mft-fs/osfs/osfs.go
@@ -0,0 +1,343 @@
+package osfs
+
+import (
+ "fmt"
+ "os"
+ "syscall"
+ "time"
+
+ "github.com/jacobsa/fuse"
+ "github.com/jacobsa/fuse/fuseops"
+ "github.com/jacobsa/fuse/fuseutil"
+
+ "golang.org/x/sys/unix"
+
+ "mft-fs/abstractfs"
+ "mft-fs/datastructures"
+)
+
+type Config struct {
+ RootDir string
+}
+
+func NewOSFS(mountDir string, config *Config) *abstractfs.AbstractFS {
+ if config == nil {
+ fmt.Println("config is nil")
+ return nil
+ }
+ return &abstractfs.AbstractFS{
+ Manager: NewOSFSManager(config.RootDir),
+ MountDir: mountDir,
+ Cachable: false,
+ CacheDir: "",
+ }
+}
+
+type OSFSManager struct {
+ abstractfs.FSManager
+ root string
+ inodeInfo map[fuseops.InodeID]*abstractfs.FileInfo
+ inodeCounter fuseops.InodeID
+}
+
+type parentChildPair struct {
+ parent fuseops.InodeID
+ child string
+}
+
+func (manager *OSFSManager) bfs(root string) {
+ q := datastructures.NewQueue()
+ q.Enqueue(&(parentChildPair{
+ parent: 0,
+ child: root,
+ }))
+ for !q.IsEmpty() {
+ current := q.Dequeue().(*parentChildPair)
+ var direntType fuseutil.DirentType
+ stat, e := os.Stat(current.child)
+ if e != nil {
+ fmt.Println("error:")
+ fmt.Println(e.Error())
+ continue
+ }
+ if stat.IsDir() {
+ dir, e := os.ReadDir(current.child)
+ if e != nil {
+ continue
+ }
+ for _, file := range dir {
+ q.Enqueue(&(parentChildPair{
+ parent: manager.inodeCounter,
+ child: fmt.Sprintf("%s/%s", current.child, file.Name()),
+ }))
+ }
+ direntType = fuseutil.DT_Directory
+ } else {
+ direntType = fuseutil.DT_File
+ }
+ info := abstractfs.NewFileInfo(stat.Name(), current.child, manager.inodeCounter, current.parent, direntType)
+ manager.inodeInfo[manager.inodeCounter] = &info
+ parentInfo, ok := manager.inodeInfo[current.parent]
+ if ok {
+ parentInfo.ChildrenIndexMap[info.Name] = len(parentInfo.Children)
+ parentInfo.Children = append(parentInfo.Children, manager.inodeCounter)
+ }
+ manager.updateInfo(manager.inodeInfo[manager.inodeCounter])
+ manager.inodeCounter++
+ }
+}
+
+func NewOSFSManager(root string) *OSFSManager {
+ manager := &OSFSManager{
+ root: root,
+ inodeInfo: make(map[fuseops.InodeID]*abstractfs.FileInfo),
+ inodeCounter: 1,
+ }
+ manager.bfs(root)
+ return manager
+}
+
+func (manager *OSFSManager) updateInfo(info *abstractfs.FileInfo) error {
+
+ fileInfo, e := os.Stat(info.Path)
+ if e != nil {
+ return e
+ }
+ stats := fileInfo.Sys().(*syscall.Stat_t)
+
+ info.Size = uint64(fileInfo.Size())
+
+ info.Nlink = 1
+
+ info.Mode = fileInfo.Mode()
+
+ /*info.Atime = time.Unix(stats.Atimespec.Sec, stats.Atimespec.Nsec)
+ info.Mtime = time.Unix(stats.Mtimespec.Sec, stats.Mtimespec.Nsec)
+ info.Ctime = time.Unix(stats.Ctimespec.Sec, stats.Ctimespec.Nsec)
+ info.Crtime = time.Unix(stats.Birthtimespec.Sec, stats.Birthtimespec.Nsec)*/
+ var timeStats unix.Stat_t
+ e = unix.Stat(info.Path, &timeStats)
+ if e != nil {
+ return e
+ }
+ info.Atime = time.Unix(timeStats.Atim.Sec, timeStats.Atim.Nsec)
+ info.Mtime = time.Unix(timeStats.Mtim.Sec, timeStats.Mtim.Nsec)
+ info.Ctime = time.Unix(timeStats.Ctim.Sec, timeStats.Ctim.Nsec)
+ info.Crtime = time.Unix(timeStats.Ctim.Sec, timeStats.Ctim.Nsec)
+
+ info.Uid = stats.Uid
+ info.Gid = stats.Gid
+
+ return nil
+}
+
+func (manager *OSFSManager) Start() error {
+ return nil
+}
+
+func (manager *OSFSManager) Teardown() error {
+ return nil
+}
+
+func (manager *OSFSManager) GetSize() (uint64, error) {
+ stat, _ := os.Stat(manager.root)
+ return uint64(stat.Size()), nil
+}
+
+func (manager *OSFSManager) GetLength() (uint64, error) {
+ return uint64(len(manager.inodeInfo)), nil
+}
+
+func (manager *OSFSManager) GetInfo(inode fuseops.InodeID) (*abstractfs.FileInfo, error) {
+ info, ok := manager.inodeInfo[inode]
+ if !ok {
+ return nil, fuse.ENOENT
+ }
+ return info, nil
+}
+
+func (manager *OSFSManager) SetInfo(inode fuseops.InodeID, uidptr *uint32, gidptr *uint32, sizeptr *uint64, modeptr *os.FileMode, atimeptr *time.Time, mtimeptr *time.Time) error {
+ info, e := manager.GetInfo(inode)
+ if e != nil {
+ return e
+ }
+
+ if modeptr != nil {
+ e = os.Chmod(info.Path, *modeptr)
+ if e != nil {
+ return e
+ }
+ }
+
+ uid := -1
+ gid := -1
+ if uidptr != nil {
+ uid = int(*uidptr)
+ }
+ if gidptr != nil {
+ gid = int(*gidptr)
+ }
+ e = os.Chown(info.Path, uid, gid)
+ if e != nil {
+ return e
+ }
+
+ atime := time.Time{}
+ mtime := time.Time{}
+ if atimeptr != nil {
+ atime = *atimeptr
+ }
+ if mtimeptr != nil {
+ mtime = *mtimeptr
+ }
+ e = os.Chtimes(info.Path, atime, mtime)
+ if e != nil {
+ return e
+ }
+
+ return manager.updateInfo(info)
+}
+
+func (manager *OSFSManager) MkDir(parent fuseops.InodeID, name string, mode os.FileMode) (fuseops.InodeID, error) {
+ parentInfo, e := manager.GetInfo(parent)
+ if e != nil {
+ return 0, e
+ }
+
+ path := parentInfo.Path + "/" + name
+ e = os.Mkdir(path, mode)
+ if e != nil {
+ return 0, e
+ }
+
+ inode := manager.inodeCounter //fuseops.InodeID(osInfo.Sys().(*syscall.Stat_t).Ino)
+ manager.inodeCounter++
+ infoObj := abstractfs.NewFileInfo(name, path, inode, parent, fuseutil.DT_Directory)
+ manager.inodeInfo[inode] = &infoObj
+ e = manager.updateInfo(&infoObj)
+ if e != nil {
+ return 0, e
+ }
+
+ parentInfo.Children = append(parentInfo.Children, inode)
+ parentInfo.ChildrenIndexMap[name] = len(parentInfo.Children) - 1
+
+ return inode, nil
+}
+
+func (manager *OSFSManager) CreateFile(parent fuseops.InodeID, name string, mode os.FileMode) (fuseops.InodeID, error) {
+ parentInfo, e := manager.GetInfo(parent)
+ if e != nil {
+ return 0, e
+ }
+
+ path := parentInfo.Path + "/" + name
+ file, e := os.Create(path)
+ defer file.Close()
+ if e != nil {
+ return 0, e
+ }
+
+ e = file.Chmod(mode)
+ if e != nil {
+ return 0, e
+ }
+
+ inode := manager.inodeCounter //fuseops.InodeID(osInfo.Sys().(*syscall.Stat_t).Ino)
+ manager.inodeCounter++
+ infoObj := abstractfs.NewFileInfo(name, path, inode, parent, fuseutil.DT_File)
+ manager.inodeInfo[inode] = &infoObj
+ e = manager.updateInfo(&infoObj)
+ if e != nil {
+ return 0, e
+ }
+
+ parentInfo.Children = append(parentInfo.Children, inode)
+ parentInfo.ChildrenIndexMap[name] = len(parentInfo.Children) - 1
+
+ return inode, nil
+}
+
+func (manager *OSFSManager) RmDir(inode fuseops.InodeID) error {
+ return nil
+}
+
+func (manager *OSFSManager) Delete(inode fuseops.InodeID) error {
+
+ // first delete any reference in parents
+ // then delete self
+
+ info, e := manager.GetInfo(inode)
+ if e != nil {
+ return e
+ }
+
+ parentInfo, e := manager.GetInfo(info.Parent)
+ if e != nil {
+ return e
+ }
+
+ parentInfo.Children = datastructures.Remove(parentInfo.Children, parentInfo.ChildrenIndexMap[info.Name])
+ target := parentInfo.ChildrenIndexMap[info.Name]
+ for name, index := range parentInfo.ChildrenIndexMap {
+ if index > target {
+ parentInfo.ChildrenIndexMap[name] = index - 1
+ }
+ }
+ delete(parentInfo.ChildrenIndexMap, info.Name)
+
+ delete(manager.inodeInfo, info.Inode)
+
+ return nil
+}
+
+func (manager *OSFSManager) SyncFile(inode fuseops.InodeID) error {
+ info, e := manager.GetInfo(inode)
+ if e != nil {
+ return e
+ }
+ file, e := os.OpenFile(info.Path, os.O_RDWR, info.Mode)
+ if e != nil {
+ return e
+ }
+ defer file.Close()
+ e = file.Sync()
+ if e != nil {
+ return e
+ }
+ return nil
+}
+
+func (manager *OSFSManager) ReadAt(inode fuseops.InodeID, data []byte, off int64) (int, error) {
+ info, e := manager.GetInfo(inode)
+ if e != nil {
+ return 0, e
+ }
+
+ file, e := os.OpenFile(info.Path, os.O_RDWR, info.Mode)
+ if e != nil {
+ return 0, e
+ }
+ defer file.Close()
+
+ n, e := file.ReadAt(data, off)
+ return n, e
+}
+
+func (manager *OSFSManager) WriteAt(inode fuseops.InodeID, data []byte, off int64) (int, error) {
+ info, e := manager.GetInfo(inode)
+ if e != nil {
+ return 0, e
+ }
+
+ file, e := os.OpenFile(info.Path, os.O_RDWR, info.Mode)
+ if e != nil {
+ return 0, e
+ }
+ defer file.Close()
+
+ n, e := file.WriteAt(data, off)
+ return n, e
+}
+
+// func (manager *OSFSManager) Destroy() error { return nil }
diff --git a/mft-fs/planning.txt b/mft-fs/planning.txt
new file mode 100644
index 00000000..2c64a212
--- /dev/null
+++ b/mft-fs/planning.txt
@@ -0,0 +1,111 @@
+AbstractFS attributes:
+ - file metadata - a safe, tree-based structure representing metadata of all files in the FS
+ - generic mount metadata
+ - cache - boolean value representing if file information should be cached (disable for osfs, s3fs if relying on external mount)
+ - readonly - boolean value representing if the FS can be written into
+ - specific mount metadata - mount-dependent metadata
+ - region, passwords for s3fs
+ - username, password, key for sftp-fs
+
+
+
+.mftfs
+ cache/
+ fs0/
+ file_.data
+ fs1/
+ ...
+ fsn/
+ info.json
+ path to id mapping
+ id to data
+ id
+ path
+ type (s3fs, osfs, sftpfs, etc)
+ config (type dependent)
+
+
+
+func (fs AbstractFS) StatFS(ctx context.Context, op *fuseops.StatFSOp) error
+ - returns general information about the FS like remaining space, inode capacity, etc
+ - implement GetSize(), GetLength() for each FS
+
+func (fs AbstractFS) LookUpInode(ctx context.Context, op *fuseops.LookUpInodeOp) error
+ - returns information about a certain inode
+ - implement as much in abstract as possible
+
+func (fs AbstractFS) GetInodeAttributes(ctx context.Context, op *fuseops.GetInodeAttributesOp) error
+ - simple metadata; fill it up in abstract
+
+func (fs AbstractFS) SetInodeAttributes(ctx context.Context, op *fuseops.SetInodeAttributesOp) error
+ - sets inode's attributes
+
+func (fs AbstractFS) ForgetInode(ctx context.Context, op *fuseops.ForgetInodeOp) error
+ - delete abstract inode metadata
+
+func (fs AbstractFS) BatchForget(ctx context.Context, op *fuseops.BatchForgetOp) error
+ - delete all abstract inodes
+
+func (fs AbstractFS) MkDir(ctx context.Context, op *fuseops.MkDirOp) error
+ - make a directory; fs specific, need to implement
+
+func (fs AbstractFS) CreateFile(ctx context.Context, op *fuseops.CreateFileOp) error
+ - creates a file; fs specific, need to implement
+
+func (fs AbstractFS) RmDir(ctx context.Context, op *fuseops.RmDirOp) error
+ - removes a directory
+ - fs specific, need to implement
+
+func (fs AbstractFS) OpenDir(ctx context.Context, op *fuseops.OpenDirOp) error
+ - returns a file handle
+
+func (fs AbstractFS) ReadDir(ctx context.Context, op *fuseops.ReadDirOp) error
+ - lists all items in a directory
+ - abstract implementation
+
+func (fs AbstractFS) ReleaseDirHandle(ctx context.Context, op *fuseops.ReleaseDirHandleOp) error
+ - delete handle
+ - abstract implementation
+
+func (fs AbstractFS) OpenFile(ctx context.Context, op *fuseops.OpenFileOp) error
+ - returns file handle
+ - abstract implementation
+
+func (fs AbstractFS) ReadFile(ctx context.Context, op *fuseops.ReadFileOp) error
+ - reads a file
+ - if cachable FS, checks if cache is up to date; if so, pulls from cache;
+ - else, pulls from remote; stores in cache if needed
+ - fs specific method needed
+
+func (fs AbstractFS) WriteFile(ctx context.Context, op *fuseops.WriteFileOp) error
+ - writes into a file. same behavior as readfile
+ - fs specific method needed
+
+func (fs AbstractFS) SyncFile(ctx context.Context, op *fuseops.SyncFileOp) error
+ - fs specific method needed
+
+func (fs AbstractFS) FlushFile(ctx context.Context, op *fuseops.FlushFileOp) error
+ - fs specific method needed
+
+func (fs AbstractFS) ReleaseFileHandle(ctx context.Context, op *fuseops.ReleaseFileHandleOp) error
+ - abstract implementation for deleting file handle
+
+func (fs AbstractFS) Destroy()
+ - abstract implementation for deleting mount
+
+mount generic methods:
+ - future: queue read/write
+
+mount-dependent methods:
+ - Load()
+ - Save()
+ - GetSize()
+ - GetLength()
+ - GetMetadata() -> blocking operations which pulls the lastest file metadata from remote to ensure consistency
+ - SetMetadata() -> blocking operation to update remote metadata
+ - MkDir()
+ - CreateFile()
+ - ReatAt()
+ - WriteAt()
+ - SyncFile()
+ - FlushFile()
diff --git a/mft-fs/sftpfs/sftp_test_server/host_key b/mft-fs/sftpfs/sftp_test_server/host_key
new file mode 100644
index 00000000..e2b0e872
--- /dev/null
+++ b/mft-fs/sftpfs/sftp_test_server/host_key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEApBlB0edbPaslbnaPfNdwy3qWPOBnemLkfw+KWGO3hKPg/Q8z
+J6OmusjSCapjbfMAxhur/XB8pmwbUwE1P3d+6f5hE1DW5qAxc5eU6QPBK4Y/+f6Z
+021W1sKNc2VDy35tTkpJs8qsjgt1EjvOOi6gOM+Pf1e10F+UWpMYjtJo2k4T7gRT
+vBwGikWXo5Pk99Rnyv3H6PxxoXHervkCgHqWAhpxG+yPS/JsShMzURuRcCYUqLi7
+vUMtojy/IRoQEaXwn9WZPM3fCC4NfIpiEM5RQf4Sy6ibfCtXXcdo1J5szF4TuRYA
+of8PoaVmyuwNYUEQAUuNBM7bycBnjB6Bv4xQKwIDAQABAoIBABeLpjWTkDRvh63r
+ZhhAI2eW3dK7Ui2t3eJbXPrkx/LIvuIgmbLw2N4JLZYEdELU8MH8O3fgeYo5jcwh
+qr3CDBxQCybF3Sf3SVEwKUYr6z4vA6P/w5uiHykufjRWDd23dMCciSm6hXrWKwSk
+Pyl7AjNUmN7pO2W8KSG75HStvSzBdy21QV76RcHPt4d3W0H9OsujRyjENqplJsd6
+Wt5lHytz+PrweaQwo4dRqd6P6Cw5pUoJdL9Dv9aoKv9H95FrCh6CczmCNuwopjuu
+fFK0yyMOBbVGOpQJhleHtpM59bdGox6KXdSHyZ5nf4bHNCUycEOy3hwdSJGsZa0F
+UDPBzXECgYEA4CoD7sO5+N9rA55t6qbB0sWtkTlEG4ZMceBx1NTMJjPr2AFM/yMt
+2zjb3RdLFcPiISB503jswqxCKG6lo48htMYqkzWatvBl4aEmUSdpHN4U7tdcV9Vs
+Hmb3Rt4KoEU6/kWw5afkPTxyW5/8I26bk/kX6n3U6AsejIeASB7kqrsCgYEAu2dt
+rsEZ2WUsyP4rJO0iS9G8U0UyRinaIe//Ba9+NTQzIfYCI4EPmnlpEdxHdXLa68uv
+sC4AHX9uo9WBrCKeDf2BpoOg23KLYh5sfeI+8hqsj2Km15slkvcAiK4+EoqVufy5
+8Edx1sloS6PYi1H7dWmzVXT1AYjkp0t7cMSFsVECgYAsoFCuHOsOH7RXQRgSyeX2
+RwJZ0fO8Iw1e8lbXDxIhXN7L3t5sQJ2lcflbV4LML3X6MFPwhLdlvhNhpz10hU8p
+hPX+3oIRf2RY+dL9/wGPDKtQLTGmDsf6eXcq9ZNZ+s5WxpsD7Vuj0T/W+8+fYiq4
+17MqLKjRFT2crnEcaoINdwKBgHGxvglXfac2ioUmLmaotzXoeKjMQkPvADe2srFw
+VtFQafUgmwuPMTg2kFgVnATVOZv0ZxIr1kYPGcCrt5AHMHysYAv1r5FzXLyaWJfG
+uwmGxUn4P+Bub81JrTk+/Mmi6lN70BLGRXpZlrzNGoLrqfMBvZsK6dmUg6Q7VxiD
+IdkBAoGBAKAl81lQTJuzrGoM5a85pehsc8/eUsQ/hqmSefn5hmwjQeTd93AVcLrJ
+g8dcDfWDHSmMhZ4f67LMl3v0aVR9QUbsdexrtlGomZSCLo8fOh+NFim1j0DbQ2DR
+0Ta8DRUSiO8CzYs7Y5zKydwQVhWol6FhCojunc4d09lpZ3i8c36w
+-----END RSA PRIVATE KEY-----
diff --git a/mft-fs/sftpfs/sftp_test_server/main.go b/mft-fs/sftpfs/sftp_test_server/main.go
new file mode 100644
index 00000000..e4d34448
--- /dev/null
+++ b/mft-fs/sftpfs/sftp_test_server/main.go
@@ -0,0 +1,151 @@
+// An example SFTP server implementation using the golang SSH package.
+// Serves the whole filesystem visible to the user, and has a hard-coded username and password,
+// so not for real use!
+package main
+
+import (
+ "fmt"
+ "io"
+ "log"
+ "net"
+ "os"
+
+ "github.com/pkg/sftp"
+ "golang.org/x/crypto/ssh"
+)
+
+// Based on example server code from golang.org/x/crypto/ssh and server_standalone
+func main() {
+ var (
+ readOnly bool
+ debugStderr bool
+ winRoot bool
+ )
+ readOnly = false
+ debugStderr = true
+ winRoot = false
+
+ debugStream := io.Discard
+ if debugStderr {
+ debugStream = os.Stderr
+ }
+
+ // An SSH server is represented by a ServerConfig, which holds
+ // certificate details and handles authentication of ServerConns.
+ config := &ssh.ServerConfig{
+ PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
+ // Should use constant-time compare (or better, salt+hash) in
+ // a production setting.
+ fmt.Fprintf(debugStream, "Login: %s\n", c.User())
+ if c.User() == "testuser" && string(pass) == "tiger" {
+ return nil, nil
+ }
+ return nil, fmt.Errorf("password rejected for %q", c.User())
+ },
+ }
+
+ privateBytes, err := os.ReadFile("./host_key")
+ if err != nil {
+ log.Fatal("Failed to load private key", err)
+ }
+
+ private, err := ssh.ParsePrivateKey(privateBytes)
+ if err != nil {
+ log.Fatal("Failed to parse private key", err)
+ }
+
+ config.AddHostKey(private)
+
+ // Once a ServerConfig has been configured, connections can be
+ // accepted.
+ listener, err := net.Listen("tcp", "localhost:2222")
+ if err != nil {
+ log.Fatal("failed to listen for connection", err)
+ }
+ fmt.Printf("Listening on %v\n", listener.Addr())
+
+ nConn, err := listener.Accept()
+ if err != nil {
+ log.Fatal("failed to accept incoming connection", err)
+ }
+
+ // Before use, a handshake must be performed on the incoming
+ // net.Conn.
+ _, chans, reqs, err := ssh.NewServerConn(nConn, config)
+ if err != nil {
+ log.Fatal("failed to handshake", err)
+ }
+ fmt.Fprintf(debugStream, "SSH server established\n")
+
+ // The incoming Request channel must be serviced.
+ go ssh.DiscardRequests(reqs)
+
+ // Service the incoming Channel channel.
+ for newChannel := range chans {
+ // Channels have a type, depending on the application level
+ // protocol intended. In the case of an SFTP session, this is "subsystem"
+ // with a payload string of "sftp"
+ fmt.Fprintf(debugStream, "Incoming channel: %s\n", newChannel.ChannelType())
+ if newChannel.ChannelType() != "session" {
+ newChannel.Reject(ssh.UnknownChannelType, "unknown channel type")
+ fmt.Fprintf(debugStream, "Unknown channel type: %s\n", newChannel.ChannelType())
+ continue
+ }
+ channel, requests, err := newChannel.Accept()
+ if err != nil {
+ log.Fatal("could not accept channel.", err)
+ }
+ fmt.Fprintf(debugStream, "Channel accepted\n")
+
+ // Sessions have out-of-band requests such as "shell",
+ // "pty-req" and "env". Here we handle only the
+ // "subsystem" request.
+ go func(in <-chan *ssh.Request) {
+ for req := range in {
+ fmt.Fprintf(debugStream, "Request: %v\n", req.Type)
+ ok := false
+ switch req.Type {
+ case "subsystem":
+ fmt.Fprintf(debugStream, "Subsystem: %s\n", req.Payload[4:])
+ if string(req.Payload[4:]) == "sftp" {
+ ok = true
+ }
+ }
+ fmt.Fprintf(debugStream, " - accepted: %v\n", ok)
+ req.Reply(ok, nil)
+ }
+ }(requests)
+
+ serverOptions := []sftp.ServerOption{
+ sftp.WithDebug(debugStream),
+ sftp.WithServerWorkingDirectory("/Users/rohanphadnis/GeorgiaTech/ArtisanResearch/SFTP_Research/go_server/sftp_root"),
+ }
+
+ if readOnly {
+ serverOptions = append(serverOptions, sftp.ReadOnly())
+ fmt.Fprintf(debugStream, "Read-only server\n")
+ } else {
+ fmt.Fprintf(debugStream, "Read write server\n")
+ }
+
+ if winRoot {
+ serverOptions = append(serverOptions, sftp.WindowsRootEnumeratesDrives())
+ fmt.Fprintf(debugStream, "Windows root enabled\n")
+ }
+
+ server, err := sftp.NewServer(
+ channel,
+ serverOptions...,
+ )
+ if err != nil {
+ log.Fatal(err)
+ }
+ if err := server.Serve(); err != nil {
+ if err != io.EOF {
+ log.Fatal("sftp server completed with error:", err)
+ }
+ }
+ server.Close()
+ log.Print("sftp client exited session.")
+ }
+}
diff --git a/mft-fs/sftpfs/sftpfs.go b/mft-fs/sftpfs/sftpfs.go
new file mode 100644
index 00000000..07d3932e
--- /dev/null
+++ b/mft-fs/sftpfs/sftpfs.go
@@ -0,0 +1,557 @@
+package sftpfs
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "path"
+ "sync"
+ "time"
+
+ "github.com/jacobsa/fuse"
+ "github.com/jacobsa/fuse/fuseops"
+ "github.com/jacobsa/fuse/fuseutil"
+
+ "github.com/pkg/sftp"
+
+ "golang.org/x/crypto/ssh"
+
+ "mft-fs/abstractfs"
+ "mft-fs/datastructures"
+)
+
+// todo: make generated inode persistent
+
+type SftpClientConfig struct {
+ Host string
+ Port uint16
+ Username string
+ Password string
+ // PrivateKeyPath string
+ RemoteRoot string
+}
+
+type sftpFSManager struct {
+ abstractfs.FSManager
+
+ client *sftp.Client
+ conn *ssh.Client
+ config *SftpClientConfig
+
+ mutex *sync.Mutex
+ data map[fuseops.InodeID]*abstractfs.FileInfo
+ pathToInode map[string]fuseops.InodeID
+ length uint64
+ inodeCounter fuseops.InodeID
+}
+
+func NewSFTPFS(mountDir string, config *SftpClientConfig) *abstractfs.AbstractFS {
+ return &abstractfs.AbstractFS{
+ Manager: newSftpFsManager(config),
+ MountDir: mountDir,
+ Cachable: true,
+ CacheDir: ".",
+ }
+}
+
+func newSftpFsManager(config *SftpClientConfig) *sftpFSManager {
+ if config == nil {
+ fmt.Println("config is nil")
+ return nil
+ }
+ return &sftpFSManager{
+ config: config,
+ mutex: &sync.Mutex{},
+ data: make(map[fuseops.InodeID]*abstractfs.FileInfo),
+ length: 1,
+ inodeCounter: 1,
+ pathToInode: make(map[string]fuseops.InodeID),
+ }
+}
+
+type parentChildPair struct {
+ parent fuseops.InodeID
+ child string
+}
+
+func writeFileInfo(stat *os.FileInfo, statSys *sftp.FileStat, info *abstractfs.FileInfo) {
+
+ // general metadata
+ info.Size = uint64(statSys.Size)
+ var direntType fuseutil.DirentType
+ if (*stat).IsDir() {
+ direntType = fuseutil.DT_Directory
+ } else {
+ direntType = fuseutil.DT_File
+ }
+ info.DirentType = direntType
+
+ // permissions metadata
+ info.Mode = os.FileMode(statSys.Mode)
+ info.Uid = statSys.UID
+ info.Gid = statSys.GID
+
+ // timing metadata
+ info.Atime = statSys.AccessTime()
+ info.Mtime = statSys.ModTime()
+ // info.Ctime = time.Unix(statSys.Ctimespec.Sec, statSys.Ctimespec.Nsec)
+ // info.Crtime = time.Unix(statSys.Birthtimespec.Sec, statSys.Birthtimespec.Nsec)
+
+}
+
+func (manager *sftpFSManager) generateInode() fuseops.InodeID {
+ output := manager.inodeCounter
+ manager.inodeCounter++
+ return output
+}
+
+func (manager *sftpFSManager) bfs() error {
+ fringe := datastructures.NewQueue()
+
+ fringe.Enqueue(&parentChildPair{
+ parent: 0,
+ child: manager.config.RemoteRoot,
+ })
+ var current *parentChildPair
+ manager.length = 0
+ for !fringe.IsEmpty() {
+ current = fringe.Dequeue().(*parentChildPair)
+ var p string
+ if current.parent == 0 {
+ p = manager.config.RemoteRoot
+ } else {
+ p = path.Join(manager.data[current.parent].Path, current.child)
+ }
+
+ // get the current path
+ stat, e := manager.client.Stat(p)
+ if e != nil {
+ return e
+ }
+ statSys := stat.Sys().(*sftp.FileStat)
+
+ // variable declaration
+ var inode fuseops.InodeID
+ var info *abstractfs.FileInfo
+ var ok bool
+
+ // get the inode
+ inode, ok = manager.pathToInode[p]
+ if !ok {
+ inode = manager.generateInode()
+ }
+
+ // get info object; create if does not exist
+ info, ok = manager.data[inode]
+ if !ok {
+ i := abstractfs.NewFileInfo(current.child, p, inode, current.parent, fuseutil.DT_Unknown)
+ info = &i
+ manager.data[inode] = info
+ manager.pathToInode[p] = inode
+ if current.parent != 0 {
+ manager.data[current.parent].AddChild(current.child, inode)
+ }
+ }
+
+ writeFileInfo(&stat, statSys, info)
+
+ if info.DirentType == fuseutil.DT_Directory {
+ dir, err := manager.client.ReadDir(info.Path)
+ if err != nil {
+ return err
+ }
+ for _, d := range dir {
+ fringe.Enqueue(&parentChildPair{
+ parent: info.Inode,
+ child: d.Name(),
+ })
+ }
+ }
+
+ manager.length++
+ }
+
+ return nil
+}
+
+func (manager *sftpFSManager) Start() error {
+ sshConfig := &ssh.ClientConfig{
+ User: manager.config.Username,
+ Auth: []ssh.AuthMethod{
+ ssh.Password(manager.config.Password),
+ },
+
+ // todo: change in production
+ HostKeyCallback: ssh.InsecureIgnoreHostKey(),
+ Timeout: 10 * time.Second,
+ }
+
+ // Dial the SSH server.
+ conn, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", manager.config.Host, manager.config.Port), sshConfig)
+ if err != nil {
+ return fmt.Errorf("failed to dial SSH server: %w", err)
+ }
+
+ // Create the SFTP client from the SSH connection.
+ client, err := sftp.NewClient(conn)
+ if err != nil {
+ // If SFTP client creation fails, ensure the SSH connection is closed.
+ conn.Close()
+ return fmt.Errorf("failed to create SFTP client: %w", err)
+ }
+
+ // update manager attributes
+ manager.conn = conn
+ manager.client = client
+
+ return manager.bfs()
+}
+
+func (manager *sftpFSManager) Teardown() error {
+ var err error
+
+ if manager.client != nil {
+ err = manager.client.Close()
+ if err != nil {
+ return err
+ }
+ }
+
+ if manager.conn != nil {
+ err = manager.conn.Close()
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (manager *sftpFSManager) GetSize() (uint64, error) {
+ manager.mutex.Lock()
+ defer manager.mutex.Unlock()
+
+ if manager.client == nil {
+ return 0, fmt.Errorf("SFTP client is not initialized")
+ }
+
+ return 0, nil
+ stat, e := manager.client.Stat(manager.config.RemoteRoot)
+ if e != nil {
+ return 0, e
+ }
+ return uint64(stat.Size()), nil
+}
+
+func (manager *sftpFSManager) GetLength() (uint64, error) {
+ manager.mutex.Lock()
+ defer manager.mutex.Unlock()
+
+ if manager.client == nil {
+ return 0, fmt.Errorf("SFTP client is not initialized")
+ }
+
+ return manager.length, nil
+
+}
+
+func (manager *sftpFSManager) GetInfo(id fuseops.InodeID) (*abstractfs.FileInfo, error) {
+ manager.mutex.Lock()
+ defer manager.mutex.Unlock()
+
+ if manager.client == nil {
+ return nil, fmt.Errorf("SFTP client is not initialized")
+ }
+
+ var e error
+
+ // get the inode object
+ info, ok := manager.data[id]
+ if !ok {
+ // if it does not exist, perform a BFS to get it
+ e = manager.bfs()
+ if e != nil {
+ return nil, e
+ }
+
+ // if it still does not exist, throw does not exist error
+ info, ok = manager.data[id]
+ if !ok {
+ return nil, fuse.ENOENT
+ }
+ }
+
+ // fetch its statistics
+ stat, e := manager.client.Stat(info.Path)
+ if e != nil {
+ // if it errors, perform a BFS to get latest info
+ e = manager.bfs()
+ if e != nil {
+ return nil, e
+ }
+
+ info, ok = manager.data[id]
+ // if it still errors, throw the error
+ stat, e = manager.client.Stat(info.Path)
+ if e != nil {
+ return nil, e
+ }
+ }
+
+ writeFileInfo(&stat, stat.Sys().(*sftp.FileStat), info)
+
+ return info, nil
+}
+
+func (manager *sftpFSManager) SetInfo(id fuseops.InodeID, uidptr *uint32, gidptr *uint32, sizeptr *uint64, modeptr *os.FileMode, atimeptr *time.Time, mtimeptr *time.Time) error {
+ manager.mutex.Lock()
+ defer manager.mutex.Unlock()
+
+ if manager.client == nil {
+ return fmt.Errorf("SFTP client is not initialized")
+ }
+
+ var e error
+
+ info, ok := manager.data[id]
+ if !ok {
+ info, e = manager.GetInfo(id)
+ if e != nil {
+ return e
+ }
+ }
+
+ if modeptr != nil {
+ e = manager.client.Chmod(info.Path, *modeptr)
+ if e != nil {
+ return e
+ }
+ }
+
+ uid := -1
+ gid := -1
+ if uidptr != nil {
+ uid = int(*uidptr)
+ }
+ if gidptr != nil {
+ gid = int(*gidptr)
+ }
+ e = manager.client.Chown(info.Path, uid, gid)
+ if e != nil {
+ return e
+ }
+
+ atime := time.Time{}
+ mtime := time.Time{}
+ if atimeptr != nil {
+ atime = *atimeptr
+ }
+ if mtimeptr != nil {
+ mtime = *mtimeptr
+ }
+ e = manager.client.Chtimes(info.Path, atime, mtime)
+ if e != nil {
+ return e
+ }
+
+ return nil
+}
+
+func (manager *sftpFSManager) Delete(id fuseops.InodeID) error {
+ manager.mutex.Lock()
+ defer manager.mutex.Unlock()
+ if manager.client == nil {
+ return fmt.Errorf("SFTP client is not initialized")
+ }
+
+ var e error
+ info, ok := manager.data[id]
+ if !ok {
+ info, e = manager.GetInfo(id)
+ if e != nil {
+ return e
+ }
+ }
+ return manager.client.Remove(info.Path)
+}
+
+func (manager *sftpFSManager) MkDir(parent fuseops.InodeID, name string, mode os.FileMode) (fuseops.InodeID, error) {
+ manager.mutex.Lock()
+ defer manager.mutex.Unlock()
+ if manager.client == nil {
+ return 0, fmt.Errorf("SFTP client is not initialized")
+ }
+ var e error
+ info, ok := manager.data[parent]
+ if !ok {
+ info, e = manager.GetInfo(parent)
+ if e != nil {
+ return 0, e
+ }
+ }
+ p := path.Join(info.Path, name)
+
+ // make the directory
+ e = manager.client.Mkdir(p)
+ if e != nil {
+ return 0, e
+ }
+
+ // set permissions
+ e = manager.client.Chmod(p, mode)
+ if e != nil {
+ return 0, e
+ }
+
+ // create a new inode in local representation
+ stat, e := manager.client.Stat(p)
+ if e != nil {
+ return 0, e
+ }
+ statSys := stat.Sys().(*sftp.FileStat)
+ inode := manager.generateInode()
+ i := abstractfs.NewFileInfo(name, p, inode, parent, fuseutil.DT_Unknown)
+ info = &i
+ manager.data[inode] = info
+ manager.pathToInode[p] = inode
+ manager.data[parent].AddChild(name, inode)
+ writeFileInfo(&stat, statSys, info)
+ return inode, nil
+}
+
+func (manager *sftpFSManager) CreateFile(parent fuseops.InodeID, name string, mode os.FileMode) (fuseops.InodeID, error) {
+ manager.mutex.Lock()
+ defer manager.mutex.Unlock()
+ if manager.client == nil {
+ return 0, fmt.Errorf("SFTP client is not initialized")
+ }
+ var e error
+ info, ok := manager.data[parent]
+ if !ok {
+ info, e = manager.GetInfo(parent)
+ if e != nil {
+ return 0, e
+ }
+ }
+ p := path.Join(info.Path, name)
+
+ // make the directory
+ _, e = manager.client.Create(p)
+ if e != nil {
+ return 0, e
+ }
+
+ // set permissions
+ e = manager.client.Chmod(p, mode)
+ if e != nil {
+ return 0, e
+ }
+
+ // create a new inode in local representation
+ stat, e := manager.client.Stat(p)
+ if e != nil {
+ return 0, e
+ }
+ statSys := stat.Sys().(*sftp.FileStat)
+ inode := manager.generateInode()
+ i := abstractfs.NewFileInfo(name, p, inode, parent, fuseutil.DT_Unknown)
+ info = &i
+ manager.data[inode] = info
+ manager.pathToInode[p] = inode
+ manager.data[parent].AddChild(name, inode)
+ writeFileInfo(&stat, statSys, info)
+ return inode, nil
+}
+
+func (manager *sftpFSManager) RmDir(id fuseops.InodeID) error {
+ manager.mutex.Lock()
+ defer manager.mutex.Unlock()
+ if manager.client == nil {
+ return fmt.Errorf("SFTP client is not initialized")
+ }
+
+ var e error
+ info, ok := manager.data[id]
+ if !ok {
+ info, e = manager.GetInfo(id)
+ if e != nil {
+ return e
+ }
+ }
+ return manager.client.RemoveDirectory(info.Path)
+}
+
+func (manager *sftpFSManager) SyncFile(inode fuseops.InodeID) error {
+ return nil
+}
+
+func (manager *sftpFSManager) WriteAt(inode fuseops.InodeID, data []byte, off int64) (n int, err error) {
+ manager.mutex.Lock()
+ defer manager.mutex.Unlock()
+ if manager.client == nil {
+ return 0, fmt.Errorf("SFTP client is not initialized")
+ }
+
+ var e error
+ info, ok := manager.data[inode]
+ if !ok {
+ info, e = manager.GetInfo(inode)
+ if e != nil {
+ return 0, e
+ }
+ }
+
+ sftpFile, e := manager.client.Open(info.Path)
+ if e != nil {
+ return 0, e
+ }
+
+ _, err = sftpFile.Seek(off, 0)
+ if err != nil {
+ return 0, err
+ }
+
+ n, err = sftpFile.Write(data)
+ if err != nil {
+ return 0, err
+ }
+
+ return n, nil
+}
+
+func (manager *sftpFSManager) ReadAt(inode fuseops.InodeID, data []byte, off int64) (n int, err error) {
+ manager.mutex.Lock()
+ defer manager.mutex.Unlock()
+ if manager.client == nil {
+ return 0, fmt.Errorf("SFTP client is not initialized")
+ }
+ var e error
+ info, ok := manager.data[inode]
+ if !ok {
+ info, e = manager.GetInfo(inode)
+ if e != nil {
+ return 0, e
+ }
+ }
+
+ sftpFile, e := manager.client.Open(info.Path)
+ if e != nil {
+ return 0, e
+ }
+
+ _, err = sftpFile.Seek(off, 0)
+ if err != nil {
+ return 0, err
+ }
+
+ n, err = sftpFile.Read(data)
+ if err != nil && err != io.EOF {
+ return n, err
+ }
+
+ return n, nil
+}
+
+//func (manager *sftpFSManager) Destroy() error {
+// return nil
+//}