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 }