302 lines
6.2 KiB
Go
302 lines
6.2 KiB
Go
package kubelwagen
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/hanwen/go-fuse/fuse"
|
|
"github.com/hanwen/go-fuse/fuse/nodefs"
|
|
"github.com/hanwen/go-fuse/fuse/pathfs"
|
|
"github.com/hanwen/go-fuse/unionfs"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
type WsFs struct {
|
|
pathfs.FileSystem
|
|
req chan RequestCallback
|
|
}
|
|
|
|
type WsFsOpts struct {
|
|
ReadOnly bool
|
|
NonEmpty bool
|
|
}
|
|
|
|
func NewWsFs(opts WsFsOpts, req chan RequestCallback, closer chan bool) *pathfs.PathNodeFs {
|
|
var fs pathfs.FileSystem
|
|
wfs := &WsFs{
|
|
FileSystem: pathfs.NewDefaultFileSystem(),
|
|
req: req,
|
|
}
|
|
|
|
// TODO(barakmich): spin up a goroutine to handle notify requests
|
|
fs = wfs
|
|
if opts.ReadOnly {
|
|
fs = pathfs.NewReadonlyFileSystem(fs)
|
|
}
|
|
fs = unionfs.NewCachingFileSystem(fs, 1*time.Second)
|
|
return pathfs.NewPathNodeFs(fs, nil)
|
|
}
|
|
|
|
func getChannel() chan Response {
|
|
return make(chan Response)
|
|
}
|
|
|
|
func (fs *WsFs) String() string {
|
|
return "kubelwagen"
|
|
}
|
|
|
|
func (fs *WsFs) getResponse(r *Request) (Response, bool) {
|
|
c := getChannel()
|
|
fs.req <- RequestCallback{
|
|
message: *r,
|
|
response: c,
|
|
}
|
|
resp, ok := <-c
|
|
if !ok {
|
|
logrus.Errorln("Response to request channel closed")
|
|
}
|
|
return resp, ok
|
|
}
|
|
|
|
func (fs *WsFs) OpenDir(name string, context *fuse.Context) ([]fuse.DirEntry, fuse.Status) {
|
|
r := Request{
|
|
Method: MethodOpenDir,
|
|
Path: name,
|
|
}
|
|
resp, ok := fs.getResponse(&r)
|
|
if !ok {
|
|
return fs.FileSystem.OpenDir(name, context)
|
|
}
|
|
return resp.Dirents, resp.Code
|
|
}
|
|
|
|
func (fs *WsFs) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
|
|
r := Request{
|
|
Method: MethodGetAttr,
|
|
Path: name,
|
|
}
|
|
resp, ok := fs.getResponse(&r)
|
|
if !ok {
|
|
return fs.FileSystem.GetAttr(name, context)
|
|
}
|
|
return resp.Stat, resp.Code
|
|
}
|
|
|
|
func (fs *WsFs) StatFs(name string) *fuse.StatfsOut {
|
|
r := Request{
|
|
Method: MethodStatFs,
|
|
Path: name,
|
|
}
|
|
resp, ok := fs.getResponse(&r)
|
|
if !ok {
|
|
return fs.FileSystem.StatFs(name)
|
|
}
|
|
return resp.Statfs
|
|
}
|
|
|
|
func (fs *WsFs) GetXAttr(name string, attr string, context *fuse.Context) ([]byte, fuse.Status) {
|
|
return nil, fuse.ENOATTR
|
|
}
|
|
|
|
func (fs *WsFs) SetXAttr(name string, attr string, data []byte, flags int, context *fuse.Context) fuse.Status {
|
|
return fuse.ENOSYS
|
|
}
|
|
|
|
func (fs *WsFs) ListXAttr(name string, context *fuse.Context) ([]string, fuse.Status) {
|
|
return nil, fuse.ENOSYS
|
|
}
|
|
|
|
func (fs *WsFs) RemoveXAttr(name string, attr string, context *fuse.Context) fuse.Status {
|
|
return fuse.ENOSYS
|
|
}
|
|
|
|
func (fs *WsFs) Readlink(name string, context *fuse.Context) (string, fuse.Status) {
|
|
r := Request{
|
|
Method: MethodReadLink,
|
|
Path: name,
|
|
}
|
|
resp, ok := fs.getResponse(&r)
|
|
if !ok {
|
|
return "", fuse.ENOSYS
|
|
}
|
|
return resp.LinkStr, resp.Code
|
|
}
|
|
|
|
func (fs *WsFs) Mknod(name string, mode uint32, dev uint32, context *fuse.Context) fuse.Status {
|
|
r := Request{
|
|
Method: MethodMknod,
|
|
Path: name,
|
|
Mode: mode,
|
|
Dev: int32(dev),
|
|
}
|
|
resp, ok := fs.getResponse(&r)
|
|
if !ok {
|
|
return fuse.ENOSYS
|
|
}
|
|
return resp.Code
|
|
}
|
|
|
|
func (fs *WsFs) Mkdir(name string, mode uint32, context *fuse.Context) fuse.Status {
|
|
r := Request{
|
|
Method: MethodMkdir,
|
|
Path: name,
|
|
Mode: mode,
|
|
}
|
|
resp, ok := fs.getResponse(&r)
|
|
if !ok {
|
|
return fuse.ENOSYS
|
|
}
|
|
return resp.Code
|
|
}
|
|
|
|
func (fs *WsFs) Unlink(name string, context *fuse.Context) (code fuse.Status) {
|
|
r := Request{
|
|
Method: MethodUnlink,
|
|
Path: name,
|
|
}
|
|
resp, ok := fs.getResponse(&r)
|
|
if !ok {
|
|
return fuse.ENOSYS
|
|
}
|
|
return resp.Code
|
|
}
|
|
|
|
func (fs *WsFs) Rmdir(name string, context *fuse.Context) (code fuse.Status) {
|
|
r := Request{
|
|
Method: MethodRmdir,
|
|
Path: name,
|
|
}
|
|
resp, ok := fs.getResponse(&r)
|
|
if !ok {
|
|
return fuse.ENOSYS
|
|
}
|
|
return resp.Code
|
|
}
|
|
|
|
func (fs *WsFs) Symlink(value string, linkName string, context *fuse.Context) (code fuse.Status) {
|
|
r := Request{
|
|
Method: MethodSymlink,
|
|
Path: linkName,
|
|
NewPath: value,
|
|
}
|
|
resp, ok := fs.getResponse(&r)
|
|
if !ok {
|
|
return fuse.ENOSYS
|
|
}
|
|
return resp.Code
|
|
}
|
|
|
|
func (fs *WsFs) Rename(oldName string, newName string, context *fuse.Context) (code fuse.Status) {
|
|
r := Request{
|
|
Method: MethodRename,
|
|
Path: oldName,
|
|
NewPath: newName,
|
|
}
|
|
resp, ok := fs.getResponse(&r)
|
|
if !ok {
|
|
return fuse.ENOSYS
|
|
}
|
|
return resp.Code
|
|
}
|
|
|
|
func (fs *WsFs) Link(oldName string, newName string, context *fuse.Context) (code fuse.Status) {
|
|
r := Request{
|
|
Method: MethodLink,
|
|
Path: oldName,
|
|
NewPath: newName,
|
|
}
|
|
resp, ok := fs.getResponse(&r)
|
|
if !ok {
|
|
return fuse.ENOSYS
|
|
}
|
|
return resp.Code
|
|
}
|
|
|
|
func (fs *WsFs) Chmod(name string, mode uint32, context *fuse.Context) (code fuse.Status) {
|
|
r := Request{
|
|
Method: MethodChmod,
|
|
Path: name,
|
|
Mode: mode,
|
|
}
|
|
resp, ok := fs.getResponse(&r)
|
|
if !ok {
|
|
return fuse.ENOSYS
|
|
}
|
|
return resp.Code
|
|
}
|
|
|
|
func (fs *WsFs) Chown(name string, uid uint32, gid uint32, context *fuse.Context) (code fuse.Status) {
|
|
r := Request{
|
|
Method: MethodChown,
|
|
Path: name,
|
|
UID: uid,
|
|
GID: gid,
|
|
}
|
|
resp, ok := fs.getResponse(&r)
|
|
if !ok {
|
|
return fuse.ENOSYS
|
|
}
|
|
return resp.Code
|
|
}
|
|
|
|
func (fs *WsFs) Truncate(name string, offset uint64, context *fuse.Context) (code fuse.Status) {
|
|
r := Request{
|
|
Method: MethodChown,
|
|
Path: name,
|
|
Offset: int64(offset),
|
|
}
|
|
resp, ok := fs.getResponse(&r)
|
|
if !ok {
|
|
return fuse.ENOSYS
|
|
}
|
|
return resp.Code
|
|
}
|
|
|
|
func (fs *WsFs) Access(name string, mode uint32, context *fuse.Context) (code fuse.Status) {
|
|
r := Request{
|
|
Method: MethodAccess,
|
|
Path: name,
|
|
Mode: mode,
|
|
}
|
|
resp, ok := fs.getResponse(&r)
|
|
if !ok {
|
|
return fuse.ENOSYS
|
|
}
|
|
return resp.Code
|
|
}
|
|
|
|
func (fs *WsFs) Utimens(name string, Atime *time.Time, Mtime *time.Time, context *fuse.Context) (code fuse.Status) {
|
|
return fuse.ENOSYS
|
|
}
|
|
|
|
func (fs *WsFs) Open(name string, flags uint32, context *fuse.Context) (file nodefs.File, code fuse.Status) {
|
|
r := Request{
|
|
Method: MethodOpen,
|
|
Flags: flags,
|
|
Path: name,
|
|
}
|
|
resp, ok := fs.getResponse(&r)
|
|
if !ok {
|
|
return nil, fuse.ENOSYS
|
|
}
|
|
if resp.Code != fuse.OK {
|
|
return nil, resp.Code
|
|
}
|
|
return newWsFsFile(resp.FileHandle, fs), resp.Code
|
|
}
|
|
|
|
func (fs *WsFs) Create(name string, flags uint32, mode uint32, context *fuse.Context) (file nodefs.File, code fuse.Status) {
|
|
r := Request{
|
|
Method: MethodCreate,
|
|
Flags: flags,
|
|
Mode: mode,
|
|
Path: name,
|
|
}
|
|
resp, ok := fs.getResponse(&r)
|
|
if !ok {
|
|
return nil, fuse.ENOSYS
|
|
}
|
|
if resp.Code != fuse.OK {
|
|
return nil, resp.Code
|
|
}
|
|
return newWsFsFile(resp.FileHandle, fs), resp.Code
|
|
}
|