Commit 5514ae72 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

Go style receivers for unionfs/ and zipfs/

parent 7fc85869
...@@ -76,31 +76,31 @@ func NewAutoUnionFs(directory string, options AutoUnionFsOptions) *AutoUnionFs { ...@@ -76,31 +76,31 @@ func NewAutoUnionFs(directory string, options AutoUnionFsOptions) *AutoUnionFs {
return a return a
} }
func (me *AutoUnionFs) String() string { func (fs *AutoUnionFs) String() string {
return fmt.Sprintf("AutoUnionFs(%s)", me.root) return fmt.Sprintf("AutoUnionFs(%s)", fs.root)
} }
func (me *AutoUnionFs) OnMount(nodeFs *fuse.PathNodeFs) { func (fs *AutoUnionFs) OnMount(nodeFs *fuse.PathNodeFs) {
me.nodeFs = nodeFs fs.nodeFs = nodeFs
if me.options.UpdateOnMount { if fs.options.UpdateOnMount {
time.AfterFunc(100*time.Millisecond, func() { me.updateKnownFses() }) time.AfterFunc(100*time.Millisecond, func() { fs.updateKnownFses() })
} }
} }
func (me *AutoUnionFs) addAutomaticFs(roots []string) { func (fs *AutoUnionFs) addAutomaticFs(roots []string) {
relative := strings.TrimLeft(strings.Replace(roots[0], me.root, "", -1), "/") relative := strings.TrimLeft(strings.Replace(roots[0], fs.root, "", -1), "/")
name := strings.Replace(relative, "/", "-", -1) name := strings.Replace(relative, "/", "-", -1)
if me.getUnionFs(name) == nil { if fs.getUnionFs(name) == nil {
me.addFs(name, roots) fs.addFs(name, roots)
} }
} }
func (me *AutoUnionFs) createFs(name string, roots []string) fuse.Status { func (fs *AutoUnionFs) createFs(name string, roots []string) fuse.Status {
me.lock.Lock() fs.lock.Lock()
defer me.lock.Unlock() defer fs.lock.Unlock()
for workspace, root := range me.nameRootMap { for workspace, root := range fs.nameRootMap {
if root == roots[0] && workspace != name { if root == roots[0] && workspace != name {
log.Printf("Already have a union FS for directory %s in workspace %s", log.Printf("Already have a union FS for directory %s in workspace %s",
roots[0], workspace) roots[0], workspace)
...@@ -108,44 +108,44 @@ func (me *AutoUnionFs) createFs(name string, roots []string) fuse.Status { ...@@ -108,44 +108,44 @@ func (me *AutoUnionFs) createFs(name string, roots []string) fuse.Status {
} }
} }
known := me.knownFileSystems[name] known := fs.knownFileSystems[name]
if known.UnionFs != nil { if known.UnionFs != nil {
log.Println("Already have a workspace:", name) log.Println("Already have a workspace:", name)
return fuse.EBUSY return fuse.EBUSY
} }
ufs, err := NewUnionFsFromRoots(roots, &me.options.UnionFsOptions, true) ufs, err := NewUnionFsFromRoots(roots, &fs.options.UnionFsOptions, true)
if err != nil { if err != nil {
log.Println("Could not create UnionFs:", err) log.Println("Could not create UnionFs:", err)
return fuse.EPERM return fuse.EPERM
} }
log.Printf("Adding workspace %v for roots %v", name, ufs.String()) log.Printf("Adding workspace %v for roots %v", name, ufs.String())
nfs := fuse.NewPathNodeFs(ufs, &me.options.PathNodeFsOptions) nfs := fuse.NewPathNodeFs(ufs, &fs.options.PathNodeFsOptions)
code := me.nodeFs.Mount(name, nfs, &me.options.FileSystemOptions) code := fs.nodeFs.Mount(name, nfs, &fs.options.FileSystemOptions)
if code.Ok() { if code.Ok() {
me.knownFileSystems[name] = knownFs{ fs.knownFileSystems[name] = knownFs{
ufs, ufs,
nfs, nfs,
} }
me.nameRootMap[name] = roots[0] fs.nameRootMap[name] = roots[0]
} }
return code return code
} }
func (me *AutoUnionFs) rmFs(name string) (code fuse.Status) { func (fs *AutoUnionFs) rmFs(name string) (code fuse.Status) {
me.lock.Lock() fs.lock.Lock()
defer me.lock.Unlock() defer fs.lock.Unlock()
known := me.knownFileSystems[name] known := fs.knownFileSystems[name]
if known.UnionFs == nil { if known.UnionFs == nil {
return fuse.ENOENT return fuse.ENOENT
} }
code = me.nodeFs.Unmount(name) code = fs.nodeFs.Unmount(name)
if code.Ok() { if code.Ok() {
delete(me.knownFileSystems, name) delete(fs.knownFileSystems, name)
delete(me.nameRootMap, name) delete(fs.nameRootMap, name)
} else { } else {
log.Printf("Unmount failed for %s. Code %v", name, code) log.Printf("Unmount failed for %s. Code %v", name, code)
} }
...@@ -153,15 +153,15 @@ func (me *AutoUnionFs) rmFs(name string) (code fuse.Status) { ...@@ -153,15 +153,15 @@ func (me *AutoUnionFs) rmFs(name string) (code fuse.Status) {
return code return code
} }
func (me *AutoUnionFs) addFs(name string, roots []string) (code fuse.Status) { func (fs *AutoUnionFs) addFs(name string, roots []string) (code fuse.Status) {
if name == _CONFIG || name == _STATUS || name == _SCAN_CONFIG { if name == _CONFIG || name == _STATUS || name == _SCAN_CONFIG {
log.Println("Illegal name for overlay", roots) log.Println("Illegal name for overlay", roots)
return fuse.EINVAL return fuse.EINVAL
} }
return me.createFs(name, roots) return fs.createFs(name, roots)
} }
func (me *AutoUnionFs) getRoots(path string) []string { func (fs *AutoUnionFs) getRoots(path string) []string {
ro := filepath.Join(path, _READONLY) ro := filepath.Join(path, _READONLY)
fi, err := os.Lstat(ro) fi, err := os.Lstat(ro)
fiDir, errDir := os.Stat(ro) fiDir, errDir := os.Stat(ro)
...@@ -177,30 +177,30 @@ func (me *AutoUnionFs) getRoots(path string) []string { ...@@ -177,30 +177,30 @@ func (me *AutoUnionFs) getRoots(path string) []string {
return nil return nil
} }
func (me *AutoUnionFs) visit(path string, fi os.FileInfo, err error) error { func (fs *AutoUnionFs) visit(path string, fi os.FileInfo, err error) error {
if fi != nil && fi.IsDir() { if fi != nil && fi.IsDir() {
roots := me.getRoots(path) roots := fs.getRoots(path)
if roots != nil { if roots != nil {
me.addAutomaticFs(roots) fs.addAutomaticFs(roots)
} }
} }
return nil return nil
} }
func (me *AutoUnionFs) updateKnownFses() { func (fs *AutoUnionFs) updateKnownFses() {
log.Println("Looking for new filesystems") log.Println("Looking for new filesystems")
// We unroll the first level of entries in the root manually in order // We unroll the first level of entries in the root manually in order
// to allow symbolic links on that level. // to allow symbolic links on that level.
directoryEntries, err := ioutil.ReadDir(me.root) directoryEntries, err := ioutil.ReadDir(fs.root)
if err == nil { if err == nil {
for _, dir := range directoryEntries { for _, dir := range directoryEntries {
if dir.IsDir() || dir.Mode()&os.ModeSymlink != 0 { if dir.IsDir() || dir.Mode()&os.ModeSymlink != 0 {
path := filepath.Join(me.root, dir.Name()) path := filepath.Join(fs.root, dir.Name())
dir, _ = os.Stat(path) dir, _ = os.Stat(path)
me.visit(path, dir, nil) fs.visit(path, dir, nil)
filepath.Walk(path, filepath.Walk(path,
func(path string, fi os.FileInfo, err error) error { func(path string, fi os.FileInfo, err error) error {
return me.visit(path, fi, err) return fs.visit(path, fi, err)
}) })
} }
} }
...@@ -208,58 +208,58 @@ func (me *AutoUnionFs) updateKnownFses() { ...@@ -208,58 +208,58 @@ func (me *AutoUnionFs) updateKnownFses() {
log.Println("Done looking") log.Println("Done looking")
} }
func (me *AutoUnionFs) Readlink(path string, context *fuse.Context) (out string, code fuse.Status) { func (fs *AutoUnionFs) Readlink(path string, context *fuse.Context) (out string, code fuse.Status) {
comps := strings.Split(path, string(filepath.Separator)) comps := strings.Split(path, string(filepath.Separator))
if comps[0] == _STATUS && comps[1] == _ROOT { if comps[0] == _STATUS && comps[1] == _ROOT {
return me.root, fuse.OK return fs.root, fuse.OK
} }
if comps[0] != _CONFIG { if comps[0] != _CONFIG {
return "", fuse.ENOENT return "", fuse.ENOENT
} }
name := comps[1] name := comps[1]
me.lock.RLock() fs.lock.RLock()
defer me.lock.RUnlock() defer fs.lock.RUnlock()
root, ok := me.nameRootMap[name] root, ok := fs.nameRootMap[name]
if ok { if ok {
return root, fuse.OK return root, fuse.OK
} }
return "", fuse.ENOENT return "", fuse.ENOENT
} }
func (me *AutoUnionFs) getUnionFs(name string) *UnionFs { func (fs *AutoUnionFs) getUnionFs(name string) *UnionFs {
me.lock.RLock() fs.lock.RLock()
defer me.lock.RUnlock() defer fs.lock.RUnlock()
return me.knownFileSystems[name].UnionFs return fs.knownFileSystems[name].UnionFs
} }
func (me *AutoUnionFs) Symlink(pointedTo string, linkName string, context *fuse.Context) (code fuse.Status) { func (fs *AutoUnionFs) Symlink(pointedTo string, linkName string, context *fuse.Context) (code fuse.Status) {
comps := strings.Split(linkName, "/") comps := strings.Split(linkName, "/")
if len(comps) != 2 { if len(comps) != 2 {
return fuse.EPERM return fuse.EPERM
} }
if comps[0] == _CONFIG { if comps[0] == _CONFIG {
roots := me.getRoots(pointedTo) roots := fs.getRoots(pointedTo)
if roots == nil { if roots == nil {
return fuse.Status(syscall.ENOTDIR) return fuse.Status(syscall.ENOTDIR)
} }
name := comps[1] name := comps[1]
return me.addFs(name, roots) return fs.addFs(name, roots)
} }
return fuse.EPERM return fuse.EPERM
} }
func (me *AutoUnionFs) Unlink(path string, context *fuse.Context) (code fuse.Status) { func (fs *AutoUnionFs) Unlink(path string, context *fuse.Context) (code fuse.Status) {
comps := strings.Split(path, "/") comps := strings.Split(path, "/")
if len(comps) != 2 { if len(comps) != 2 {
return fuse.EPERM return fuse.EPERM
} }
if comps[0] == _CONFIG && comps[1] != _SCAN_CONFIG { if comps[0] == _CONFIG && comps[1] != _SCAN_CONFIG {
code = me.rmFs(comps[1]) code = fs.rmFs(comps[1])
} else { } else {
code = fuse.ENOENT code = fuse.ENOENT
} }
...@@ -267,11 +267,11 @@ func (me *AutoUnionFs) Unlink(path string, context *fuse.Context) (code fuse.Sta ...@@ -267,11 +267,11 @@ func (me *AutoUnionFs) Unlink(path string, context *fuse.Context) (code fuse.Sta
} }
// Must define this, because ENOSYS will suspend all GetXAttr calls. // Must define this, because ENOSYS will suspend all GetXAttr calls.
func (me *AutoUnionFs) GetXAttr(name string, attr string, context *fuse.Context) ([]byte, fuse.Status) { func (fs *AutoUnionFs) GetXAttr(name string, attr string, context *fuse.Context) ([]byte, fuse.Status) {
return nil, fuse.ENODATA return nil, fuse.ENODATA
} }
func (me *AutoUnionFs) GetAttr(path string, context *fuse.Context) (*fuse.Attr, fuse.Status) { func (fs *AutoUnionFs) GetAttr(path string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
if path == "" || path == _CONFIG || path == _STATUS { if path == "" || path == _CONFIG || path == _STATUS {
a := &fuse.Attr{ a := &fuse.Attr{
Mode: fuse.S_IFDIR | 0755, Mode: fuse.S_IFDIR | 0755,
...@@ -290,7 +290,7 @@ func (me *AutoUnionFs) GetAttr(path string, context *fuse.Context) (*fuse.Attr, ...@@ -290,7 +290,7 @@ func (me *AutoUnionFs) GetAttr(path string, context *fuse.Context) (*fuse.Attr,
if path == filepath.Join(_STATUS, _DEBUG) { if path == filepath.Join(_STATUS, _DEBUG) {
a := &fuse.Attr{ a := &fuse.Attr{
Mode: fuse.S_IFREG | 0644, Mode: fuse.S_IFREG | 0644,
Size: uint64(len(me.DebugData())), Size: uint64(len(fs.DebugData())),
} }
return a, fuse.OK return a, fuse.OK
} }
...@@ -311,7 +311,7 @@ func (me *AutoUnionFs) GetAttr(path string, context *fuse.Context) (*fuse.Attr, ...@@ -311,7 +311,7 @@ func (me *AutoUnionFs) GetAttr(path string, context *fuse.Context) (*fuse.Attr,
comps := strings.Split(path, string(filepath.Separator)) comps := strings.Split(path, string(filepath.Separator))
if len(comps) > 1 && comps[0] == _CONFIG { if len(comps) > 1 && comps[0] == _CONFIG {
fs := me.getUnionFs(comps[1]) fs := fs.getUnionFs(comps[1])
if fs == nil { if fs == nil {
return nil, fuse.ENOENT return nil, fuse.ENOENT
...@@ -326,7 +326,7 @@ func (me *AutoUnionFs) GetAttr(path string, context *fuse.Context) (*fuse.Attr, ...@@ -326,7 +326,7 @@ func (me *AutoUnionFs) GetAttr(path string, context *fuse.Context) (*fuse.Attr,
return nil, fuse.ENOENT return nil, fuse.ENOENT
} }
func (me *AutoUnionFs) StatusDir() (stream chan fuse.DirEntry, status fuse.Status) { func (fs *AutoUnionFs) StatusDir() (stream chan fuse.DirEntry, status fuse.Status) {
stream = make(chan fuse.DirEntry, 10) stream = make(chan fuse.DirEntry, 10)
stream <- fuse.DirEntry{ stream <- fuse.DirEntry{
Name: _VERSION, Name: _VERSION,
...@@ -347,51 +347,51 @@ func (me *AutoUnionFs) StatusDir() (stream chan fuse.DirEntry, status fuse.Statu ...@@ -347,51 +347,51 @@ func (me *AutoUnionFs) StatusDir() (stream chan fuse.DirEntry, status fuse.Statu
// SetMountState stores the MountState, which is necessary for // SetMountState stores the MountState, which is necessary for
// retrieving debug data. // retrieving debug data.
func (me *AutoUnionFs) SetMountState(state *fuse.MountState) { func (fs *AutoUnionFs) SetMountState(state *fuse.MountState) {
me.mountState = state fs.mountState = state
} }
func (me *AutoUnionFs) SetFileSystemConnector(conn *fuse.FileSystemConnector) { func (fs *AutoUnionFs) SetFileSystemConnector(conn *fuse.FileSystemConnector) {
me.connector = conn fs.connector = conn
} }
func (me *AutoUnionFs) DebugData() string { func (fs *AutoUnionFs) DebugData() string {
if me.mountState == nil { if fs.mountState == nil {
return "AutoUnionFs.mountState not set" return "AutoUnionFs.mountState not set"
} }
setting := me.mountState.KernelSettings() setting := fs.mountState.KernelSettings()
msg := fmt.Sprintf( msg := fmt.Sprintf(
"Version: %v\n"+ "Version: %v\n"+
"Bufferpool: %v\n"+ "Bufferpool: %v\n"+
"Kernel: %v\n", "Kernel: %v\n",
fuse.Version(), fuse.Version(),
me.mountState.BufferPoolStats(), fs.mountState.BufferPoolStats(),
&setting) &setting)
lat := me.mountState.Latencies() lat := fs.mountState.Latencies()
if len(lat) > 0 { if len(lat) > 0 {
msg += fmt.Sprintf("Latencies: %v\n", lat) msg += fmt.Sprintf("Latencies: %v\n", lat)
} }
counts := me.mountState.OperationCounts() counts := fs.mountState.OperationCounts()
if len(counts) > 0 { if len(counts) > 0 {
msg += fmt.Sprintf("Op counts: %v\n", counts) msg += fmt.Sprintf("Op counts: %v\n", counts)
} }
if me.connector != nil { if fs.connector != nil {
msg += fmt.Sprintf("Live inodes: %d\n", me.connector.InodeHandleCount()) msg += fmt.Sprintf("Live inodes: %d\n", fs.connector.InodeHandleCount())
} }
return msg return msg
} }
func (me *AutoUnionFs) Open(path string, flags uint32, context *fuse.Context) (fuse.File, fuse.Status) { func (fs *AutoUnionFs) Open(path string, flags uint32, context *fuse.Context) (fuse.File, fuse.Status) {
if path == filepath.Join(_STATUS, _DEBUG) { if path == filepath.Join(_STATUS, _DEBUG) {
if flags&fuse.O_ANYWRITE != 0 { if flags&fuse.O_ANYWRITE != 0 {
return nil, fuse.EPERM return nil, fuse.EPERM
} }
return fuse.NewDataFile([]byte(me.DebugData())), fuse.OK return fuse.NewDataFile([]byte(fs.DebugData())), fuse.OK
} }
if path == filepath.Join(_STATUS, _VERSION) { if path == filepath.Join(_STATUS, _VERSION) {
if flags&fuse.O_ANYWRITE != 0 { if flags&fuse.O_ANYWRITE != 0 {
...@@ -401,14 +401,14 @@ func (me *AutoUnionFs) Open(path string, flags uint32, context *fuse.Context) (f ...@@ -401,14 +401,14 @@ func (me *AutoUnionFs) Open(path string, flags uint32, context *fuse.Context) (f
} }
if path == filepath.Join(_CONFIG, _SCAN_CONFIG) { if path == filepath.Join(_CONFIG, _SCAN_CONFIG) {
if flags&fuse.O_ANYWRITE != 0 { if flags&fuse.O_ANYWRITE != 0 {
me.updateKnownFses() fs.updateKnownFses()
} }
return fuse.NewDevNullFile(), fuse.OK return fuse.NewDevNullFile(), fuse.OK
} }
return nil, fuse.ENOENT return nil, fuse.ENOENT
} }
func (me *AutoUnionFs) Truncate(name string, offset uint64, context *fuse.Context) (code fuse.Status) { func (fs *AutoUnionFs) Truncate(name string, offset uint64, context *fuse.Context) (code fuse.Status) {
if name != filepath.Join(_CONFIG, _SCAN_CONFIG) { if name != filepath.Join(_CONFIG, _SCAN_CONFIG) {
log.Println("Huh? Truncating unsupported write file", name) log.Println("Huh? Truncating unsupported write file", name)
return fuse.EPERM return fuse.EPERM
...@@ -416,10 +416,10 @@ func (me *AutoUnionFs) Truncate(name string, offset uint64, context *fuse.Contex ...@@ -416,10 +416,10 @@ func (me *AutoUnionFs) Truncate(name string, offset uint64, context *fuse.Contex
return fuse.OK return fuse.OK
} }
func (me *AutoUnionFs) OpenDir(name string, context *fuse.Context) (stream chan fuse.DirEntry, status fuse.Status) { func (fs *AutoUnionFs) OpenDir(name string, context *fuse.Context) (stream chan fuse.DirEntry, status fuse.Status) {
switch name { switch name {
case _STATUS: case _STATUS:
return me.StatusDir() return fs.StatusDir()
case _CONFIG: case _CONFIG:
case "/": case "/":
name = "" name = ""
...@@ -429,12 +429,12 @@ func (me *AutoUnionFs) OpenDir(name string, context *fuse.Context) (stream chan ...@@ -429,12 +429,12 @@ func (me *AutoUnionFs) OpenDir(name string, context *fuse.Context) (stream chan
return nil, fuse.ENOSYS return nil, fuse.ENOSYS
} }
me.lock.RLock() fs.lock.RLock()
defer me.lock.RUnlock() defer fs.lock.RUnlock()
stream = make(chan fuse.DirEntry, len(me.knownFileSystems)+5) stream = make(chan fuse.DirEntry, len(fs.knownFileSystems)+5)
if name == _CONFIG { if name == _CONFIG {
for k := range me.knownFileSystems { for k := range fs.knownFileSystems {
stream <- fuse.DirEntry{ stream <- fuse.DirEntry{
Name: k, Name: k,
Mode: syscall.S_IFLNK | 0644, Mode: syscall.S_IFLNK | 0644,
...@@ -456,6 +456,6 @@ func (me *AutoUnionFs) OpenDir(name string, context *fuse.Context) (stream chan ...@@ -456,6 +456,6 @@ func (me *AutoUnionFs) OpenDir(name string, context *fuse.Context) (stream chan
return stream, status return stream, status
} }
func (me *AutoUnionFs) StatFs(name string) *fuse.StatfsOut { func (fs *AutoUnionFs) StatFs(name string) *fuse.StatfsOut {
return &fuse.StatfsOut{} return &fuse.StatfsOut{}
} }
...@@ -107,36 +107,36 @@ func NewCachingFileSystem(fs fuse.FileSystem, ttl time.Duration) *CachingFileSys ...@@ -107,36 +107,36 @@ func NewCachingFileSystem(fs fuse.FileSystem, ttl time.Duration) *CachingFileSys
return c return c
} }
func (me *CachingFileSystem) DropCache() { func (fs *CachingFileSystem) DropCache() {
for _, c := range []*TimedCache{me.attributes, me.dirs, me.links, me.xattr} { for _, c := range []*TimedCache{fs.attributes, fs.dirs, fs.links, fs.xattr} {
c.DropAll(nil) c.DropAll(nil)
} }
} }
func (me *CachingFileSystem) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) { func (fs *CachingFileSystem) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
if name == _DROP_CACHE { if name == _DROP_CACHE {
return &fuse.Attr{ return &fuse.Attr{
Mode: fuse.S_IFREG | 0777, Mode: fuse.S_IFREG | 0777,
}, fuse.OK }, fuse.OK
} }
r := me.attributes.Get(name).(*attrResponse) r := fs.attributes.Get(name).(*attrResponse)
return r.Attr, r.Status return r.Attr, r.Status
} }
func (me *CachingFileSystem) GetXAttr(name string, attr string, context *fuse.Context) ([]byte, fuse.Status) { func (fs *CachingFileSystem) GetXAttr(name string, attr string, context *fuse.Context) ([]byte, fuse.Status) {
key := name + _XATTRSEP + attr key := name + _XATTRSEP + attr
r := me.xattr.Get(key).(*xattrResponse) r := fs.xattr.Get(key).(*xattrResponse)
return r.data, r.Status return r.data, r.Status
} }
func (me *CachingFileSystem) Readlink(name string, context *fuse.Context) (string, fuse.Status) { func (fs *CachingFileSystem) Readlink(name string, context *fuse.Context) (string, fuse.Status) {
r := me.links.Get(name).(*linkResponse) r := fs.links.Get(name).(*linkResponse)
return r.linkContent, r.Status return r.linkContent, r.Status
} }
func (me *CachingFileSystem) OpenDir(name string, context *fuse.Context) (stream chan fuse.DirEntry, status fuse.Status) { func (fs *CachingFileSystem) OpenDir(name string, context *fuse.Context) (stream chan fuse.DirEntry, status fuse.Status) {
r := me.dirs.Get(name).(*dirResponse) r := fs.dirs.Get(name).(*dirResponse)
if r.Status.Ok() { if r.Status.Ok() {
stream = make(chan fuse.DirEntry, len(r.entries)) stream = make(chan fuse.DirEntry, len(r.entries))
for _, d := range r.entries { for _, d := range r.entries {
...@@ -149,14 +149,14 @@ func (me *CachingFileSystem) OpenDir(name string, context *fuse.Context) (stream ...@@ -149,14 +149,14 @@ func (me *CachingFileSystem) OpenDir(name string, context *fuse.Context) (stream
return nil, r.Status return nil, r.Status
} }
func (me *CachingFileSystem) String() string { func (fs *CachingFileSystem) String() string {
return fmt.Sprintf("CachingFileSystem(%v)", me.FileSystem) return fmt.Sprintf("CachingFileSystem(%v)", fs.FileSystem)
} }
func (me *CachingFileSystem) Open(name string, flags uint32, context *fuse.Context) (f fuse.File, status fuse.Status) { func (fs *CachingFileSystem) Open(name string, flags uint32, context *fuse.Context) (f fuse.File, status fuse.Status) {
if flags&fuse.O_ANYWRITE != 0 && name == _DROP_CACHE { if flags&fuse.O_ANYWRITE != 0 && name == _DROP_CACHE {
log.Println("Dropping cache for", me) log.Println("Dropping cache for", fs)
me.DropCache() fs.DropCache()
} }
return me.FileSystem.Open(name, flags, context) return fs.FileSystem.Open(name, flags, context)
} }
...@@ -42,57 +42,57 @@ type DirCache struct { ...@@ -42,57 +42,57 @@ type DirCache struct {
updateRunning bool updateRunning bool
} }
func (me *DirCache) setMap(newMap map[string]bool) { func (c *DirCache) setMap(newMap map[string]bool) {
me.lock.Lock() c.lock.Lock()
defer me.lock.Unlock() defer c.lock.Unlock()
me.names = newMap c.names = newMap
me.updateRunning = false c.updateRunning = false
_ = time.AfterFunc(me.ttl, _ = time.AfterFunc(c.ttl,
func() { me.DropCache() }) func() { c.DropCache() })
} }
func (me *DirCache) DropCache() { func (c *DirCache) DropCache() {
me.lock.Lock() c.lock.Lock()
defer me.lock.Unlock() defer c.lock.Unlock()
me.names = nil c.names = nil
} }
// Try to refresh: if another update is already running, do nothing, // Try to refresh: if another update is already running, do nothing,
// otherwise, read the directory and set it. // otherwise, read the directory and set it.
func (me *DirCache) maybeRefresh() { func (c *DirCache) maybeRefresh() {
me.lock.Lock() c.lock.Lock()
defer me.lock.Unlock() defer c.lock.Unlock()
if me.updateRunning { if c.updateRunning {
return return
} }
me.updateRunning = true c.updateRunning = true
go func() { go func() {
newmap := newDirnameMap(me.fs, me.dir) newmap := newDirnameMap(c.fs, c.dir)
me.setMap(newmap) c.setMap(newmap)
}() }()
} }
func (me *DirCache) RemoveEntry(name string) { func (c *DirCache) RemoveEntry(name string) {
me.lock.Lock() c.lock.Lock()
defer me.lock.Unlock() defer c.lock.Unlock()
if me.names == nil { if c.names == nil {
go me.maybeRefresh() go c.maybeRefresh()
return return
} }
delete(me.names, name) delete(c.names, name)
} }
func (me *DirCache) AddEntry(name string) { func (c *DirCache) AddEntry(name string) {
me.lock.Lock() c.lock.Lock()
defer me.lock.Unlock() defer c.lock.Unlock()
if me.names == nil { if c.names == nil {
go me.maybeRefresh() go c.maybeRefresh()
return return
} }
me.names[name] = true c.names[name] = true
} }
func NewDirCache(fs fuse.FileSystem, dir string, ttl time.Duration) *DirCache { func NewDirCache(fs fuse.FileSystem, dir string, ttl time.Duration) *DirCache {
...@@ -103,14 +103,14 @@ func NewDirCache(fs fuse.FileSystem, dir string, ttl time.Duration) *DirCache { ...@@ -103,14 +103,14 @@ func NewDirCache(fs fuse.FileSystem, dir string, ttl time.Duration) *DirCache {
return dc return dc
} }
func (me *DirCache) HasEntry(name string) (mapPresent bool, found bool) { func (c *DirCache) HasEntry(name string) (mapPresent bool, found bool) {
me.lock.RLock() c.lock.RLock()
defer me.lock.RUnlock() defer c.lock.RUnlock()
if me.names == nil { if c.names == nil {
go me.maybeRefresh() go c.maybeRefresh()
return false, false return false, false
} }
return true, me.names[name] return true, c.names[name]
} }
...@@ -42,79 +42,79 @@ func NewTimedCache(fetcher TimedCacheFetcher, ttl time.Duration) *TimedCache { ...@@ -42,79 +42,79 @@ func NewTimedCache(fetcher TimedCacheFetcher, ttl time.Duration) *TimedCache {
return l return l
} }
func (me *TimedCache) Get(name string) interface{} { func (c *TimedCache) Get(name string) interface{} {
me.cacheMapMutex.RLock() c.cacheMapMutex.RLock()
info, ok := me.cacheMap[name] info, ok := c.cacheMap[name]
me.cacheMapMutex.RUnlock() c.cacheMapMutex.RUnlock()
valid := ok && (me.ttl <= 0 || info.expiry.After(time.Now())) valid := ok && (c.ttl <= 0 || info.expiry.After(time.Now()))
if valid { if valid {
return info.data return info.data
} }
return me.GetFresh(name) return c.GetFresh(name)
} }
func (me *TimedCache) Set(name string, val interface{}) { func (c *TimedCache) Set(name string, val interface{}) {
me.cacheMapMutex.Lock() c.cacheMapMutex.Lock()
defer me.cacheMapMutex.Unlock() defer c.cacheMapMutex.Unlock()
me.cacheMap[name] = &cacheEntry{ c.cacheMap[name] = &cacheEntry{
data: val, data: val,
expiry: time.Now().Add(me.ttl), expiry: time.Now().Add(c.ttl),
} }
} }
func (me *TimedCache) DropEntry(name string) { func (c *TimedCache) DropEntry(name string) {
me.cacheMapMutex.Lock() c.cacheMapMutex.Lock()
defer me.cacheMapMutex.Unlock() defer c.cacheMapMutex.Unlock()
delete(me.cacheMap, name) delete(c.cacheMap, name)
} }
func (me *TimedCache) GetFresh(name string) interface{} { func (c *TimedCache) GetFresh(name string) interface{} {
data, ok := me.fetch(name) data, ok := c.fetch(name)
if ok { if ok {
me.Set(name, data) c.Set(name, data)
} }
return data return data
} }
// Drop all expired entries. // Drop all expired entries.
func (me *TimedCache) Purge() { func (c *TimedCache) Purge() {
keys := make([]string, 0, len(me.cacheMap)) keys := make([]string, 0, len(c.cacheMap))
now := time.Now() now := time.Now()
me.cacheMapMutex.Lock() c.cacheMapMutex.Lock()
defer me.cacheMapMutex.Unlock() defer c.cacheMapMutex.Unlock()
for k, v := range me.cacheMap { for k, v := range c.cacheMap {
if now.After(v.expiry) { if now.After(v.expiry) {
keys = append(keys, k) keys = append(keys, k)
} }
} }
for _, k := range keys { for _, k := range keys {
delete(me.cacheMap, k) delete(c.cacheMap, k)
} }
} }
func (me *TimedCache) RecurringPurge() { func (c *TimedCache) RecurringPurge() {
if me.ttl <= 0 { if c.ttl <= 0 {
return return
} }
me.Purge() c.Purge()
me.PurgeTimer = time.AfterFunc(me.ttl*5, c.PurgeTimer = time.AfterFunc(c.ttl*5,
func() { me.RecurringPurge() }) func() { c.RecurringPurge() })
} }
func (me *TimedCache) DropAll(names []string) { func (c *TimedCache) DropAll(names []string) {
me.cacheMapMutex.Lock() c.cacheMapMutex.Lock()
defer me.cacheMapMutex.Unlock() defer c.cacheMapMutex.Unlock()
if names == nil { if names == nil {
me.cacheMap = make(map[string]*cacheEntry, len(me.cacheMap)) c.cacheMap = make(map[string]*cacheEntry, len(c.cacheMap))
} else { } else {
for _, nm := range names { for _, nm := range names {
delete(me.cacheMap, nm) delete(c.cacheMap, nm)
} }
} }
} }
...@@ -110,8 +110,8 @@ func NewUnionFs(fileSystems []fuse.FileSystem, options UnionFsOptions) *UnionFs ...@@ -110,8 +110,8 @@ func NewUnionFs(fileSystems []fuse.FileSystem, options UnionFsOptions) *UnionFs
return g return g
} }
func (me *UnionFs) OnMount(nodeFs *fuse.PathNodeFs) { func (fs *UnionFs) OnMount(nodeFs *fuse.PathNodeFs) {
me.nodeFs = nodeFs fs.nodeFs = nodeFs
} }
//////////////// ////////////////
...@@ -119,14 +119,14 @@ func (me *UnionFs) OnMount(nodeFs *fuse.PathNodeFs) { ...@@ -119,14 +119,14 @@ func (me *UnionFs) OnMount(nodeFs *fuse.PathNodeFs) {
// The isDeleted() method tells us if a path has a marker in the deletion store. // The isDeleted() method tells us if a path has a marker in the deletion store.
// It may return an error code if the store could not be accessed. // It may return an error code if the store could not be accessed.
func (me *UnionFs) isDeleted(name string) (deleted bool, code fuse.Status) { func (fs *UnionFs) isDeleted(name string) (deleted bool, code fuse.Status) {
marker := me.deletionPath(name) marker := fs.deletionPath(name)
haveCache, found := me.deletionCache.HasEntry(filepath.Base(marker)) haveCache, found := fs.deletionCache.HasEntry(filepath.Base(marker))
if haveCache { if haveCache {
return found, fuse.OK return found, fuse.OK
} }
_, code = me.fileSystems[0].GetAttr(marker, nil) _, code = fs.fileSystems[0].GetAttr(marker, nil)
if code == fuse.OK { if code == fuse.OK {
return true, code return true, code
...@@ -139,13 +139,13 @@ func (me *UnionFs) isDeleted(name string) (deleted bool, code fuse.Status) { ...@@ -139,13 +139,13 @@ func (me *UnionFs) isDeleted(name string) (deleted bool, code fuse.Status) {
return false, fuse.Status(syscall.EROFS) return false, fuse.Status(syscall.EROFS)
} }
func (me *UnionFs) createDeletionStore() (code fuse.Status) { func (fs *UnionFs) createDeletionStore() (code fuse.Status) {
writable := me.fileSystems[0] writable := fs.fileSystems[0]
fi, code := writable.GetAttr(me.options.DeletionDirName, nil) fi, code := writable.GetAttr(fs.options.DeletionDirName, nil)
if code == fuse.ENOENT { if code == fuse.ENOENT {
code = writable.Mkdir(me.options.DeletionDirName, 0755, nil) code = writable.Mkdir(fs.options.DeletionDirName, 0755, nil)
if code.Ok() { if code.Ok() {
fi, code = writable.GetAttr(me.options.DeletionDirName, nil) fi, code = writable.GetAttr(fs.options.DeletionDirName, nil)
} }
} }
...@@ -156,9 +156,9 @@ func (me *UnionFs) createDeletionStore() (code fuse.Status) { ...@@ -156,9 +156,9 @@ func (me *UnionFs) createDeletionStore() (code fuse.Status) {
return code return code
} }
func (me *UnionFs) getBranch(name string) branchResult { func (fs *UnionFs) getBranch(name string) branchResult {
name = stripSlash(name) name = stripSlash(name)
r := me.branchCache.Get(name) r := fs.branchCache.Get(name)
return r.(branchResult) return r.(branchResult)
} }
...@@ -168,11 +168,11 @@ type branchResult struct { ...@@ -168,11 +168,11 @@ type branchResult struct {
branch int branch int
} }
func (me branchResult) String() string { func (fs branchResult) String() string {
return fmt.Sprintf("{%v %v branch %d}", me.attr, me.code, me.branch) return fmt.Sprintf("{%v %v branch %d}", fs.attr, fs.code, fs.branch)
} }
func (me *UnionFs) getBranchAttrNoCache(name string) branchResult { func (fs *UnionFs) getBranchAttrNoCache(name string) branchResult {
name = stripSlash(name) name = stripSlash(name)
parent, base := path.Split(name) parent, base := path.Split(name)
...@@ -180,9 +180,9 @@ func (me *UnionFs) getBranchAttrNoCache(name string) branchResult { ...@@ -180,9 +180,9 @@ func (me *UnionFs) getBranchAttrNoCache(name string) branchResult {
parentBranch := 0 parentBranch := 0
if base != "" { if base != "" {
parentBranch = me.getBranch(parent).branch parentBranch = fs.getBranch(parent).branch
} }
for i, fs := range me.fileSystems { for i, fs := range fs.fileSystems {
if i < parentBranch { if i < parentBranch {
continue continue
} }
...@@ -210,35 +210,35 @@ func (me *UnionFs) getBranchAttrNoCache(name string) branchResult { ...@@ -210,35 +210,35 @@ func (me *UnionFs) getBranchAttrNoCache(name string) branchResult {
//////////////// ////////////////
// Deletion. // Deletion.
func (me *UnionFs) deletionPath(name string) string { func (fs *UnionFs) deletionPath(name string) string {
return filepath.Join(me.options.DeletionDirName, filePathHash(name)) return filepath.Join(fs.options.DeletionDirName, filePathHash(name))
} }
func (me *UnionFs) removeDeletion(name string) { func (fs *UnionFs) removeDeletion(name string) {
marker := me.deletionPath(name) marker := fs.deletionPath(name)
me.deletionCache.RemoveEntry(path.Base(marker)) fs.deletionCache.RemoveEntry(path.Base(marker))
// os.Remove tries to be smart and issues a Remove() and // os.Remove tries to be smart and issues a Remove() and
// Rmdir() sequentially. We want to skip the 2nd system call, // Rmdir() sequentially. We want to skip the 2nd system call,
// so use syscall.Unlink() directly. // so use syscall.Unlink() directly.
code := me.fileSystems[0].Unlink(marker, nil) code := fs.fileSystems[0].Unlink(marker, nil)
if !code.Ok() && code != fuse.ENOENT { if !code.Ok() && code != fuse.ENOENT {
log.Printf("error unlinking %s: %v", marker, code) log.Printf("error unlinking %s: %v", marker, code)
} }
} }
func (me *UnionFs) putDeletion(name string) (code fuse.Status) { func (fs *UnionFs) putDeletion(name string) (code fuse.Status) {
code = me.createDeletionStore() code = fs.createDeletionStore()
if !code.Ok() { if !code.Ok() {
return code return code
} }
marker := me.deletionPath(name) marker := fs.deletionPath(name)
me.deletionCache.AddEntry(path.Base(marker)) fs.deletionCache.AddEntry(path.Base(marker))
// Is there a WriteStringToFileOrDie ? // Is there a WriteStringToFileOrDie ?
writable := me.fileSystems[0] writable := fs.fileSystems[0]
fi, code := writable.GetAttr(marker, nil) fi, code := writable.GetAttr(marker, nil)
if code.Ok() && fi.Size == uint64(len(name)) { if code.Ok() && fi.Size == uint64(len(name)) {
return fuse.OK return fuse.OK
...@@ -268,12 +268,12 @@ func (me *UnionFs) putDeletion(name string) (code fuse.Status) { ...@@ -268,12 +268,12 @@ func (me *UnionFs) putDeletion(name string) (code fuse.Status) {
//////////////// ////////////////
// Promotion. // Promotion.
func (me *UnionFs) Promote(name string, srcResult branchResult, context *fuse.Context) (code fuse.Status) { func (fs *UnionFs) Promote(name string, srcResult branchResult, context *fuse.Context) (code fuse.Status) {
writable := me.fileSystems[0] writable := fs.fileSystems[0]
sourceFs := me.fileSystems[srcResult.branch] sourceFs := fs.fileSystems[srcResult.branch]
// Promote directories. // Promote directories.
me.promoteDirsTo(name) fs.promoteDirsTo(name)
if srcResult.attr.IsRegular() { if srcResult.attr.IsRegular() {
code = fuse.CopyFile(sourceFs, writable, name, name, context) code = fuse.CopyFile(sourceFs, writable, name, name, context)
...@@ -286,7 +286,7 @@ func (me *UnionFs) Promote(name string, srcResult branchResult, context *fuse.Co ...@@ -286,7 +286,7 @@ func (me *UnionFs) Promote(name string, srcResult branchResult, context *fuse.Co
srcResult.attr.Mtimens(), context) srcResult.attr.Mtimens(), context)
} }
files := me.nodeFs.AllFiles(name, 0) files := fs.nodeFs.AllFiles(name, 0)
for _, fileWrapper := range files { for _, fileWrapper := range files {
if !code.Ok() { if !code.Ok() {
break break
...@@ -308,7 +308,7 @@ func (me *UnionFs) Promote(name string, srcResult branchResult, context *fuse.Co ...@@ -308,7 +308,7 @@ func (me *UnionFs) Promote(name string, srcResult branchResult, context *fuse.Co
if uf.layer > 0 { if uf.layer > 0 {
uf.layer = 0 uf.layer = 0
f := uf.File f := uf.File
uf.File, code = me.fileSystems[0].Open(name, fileWrapper.OpenFlags, context) uf.File, code = fs.fileSystems[0].Open(name, fileWrapper.OpenFlags, context)
f.Flush() f.Flush()
f.Release() f.Release()
} }
...@@ -329,12 +329,12 @@ func (me *UnionFs) Promote(name string, srcResult branchResult, context *fuse.Co ...@@ -329,12 +329,12 @@ func (me *UnionFs) Promote(name string, srcResult branchResult, context *fuse.Co
} }
if !code.Ok() { if !code.Ok() {
me.branchCache.GetFresh(name) fs.branchCache.GetFresh(name)
return code return code
} else { } else {
r := me.getBranch(name) r := fs.getBranch(name)
r.branch = 0 r.branch = 0
me.branchCache.Set(name, r) fs.branchCache.Set(name, r)
} }
return fuse.OK return fuse.OK
...@@ -343,11 +343,11 @@ func (me *UnionFs) Promote(name string, srcResult branchResult, context *fuse.Co ...@@ -343,11 +343,11 @@ func (me *UnionFs) Promote(name string, srcResult branchResult, context *fuse.Co
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
// Below: implement interface for a FileSystem. // Below: implement interface for a FileSystem.
func (me *UnionFs) Link(orig string, newName string, context *fuse.Context) (code fuse.Status) { func (fs *UnionFs) Link(orig string, newName string, context *fuse.Context) (code fuse.Status) {
origResult := me.getBranch(orig) origResult := fs.getBranch(orig)
code = origResult.code code = origResult.code
if code.Ok() && origResult.branch > 0 { if code.Ok() && origResult.branch > 0 {
code = me.Promote(orig, origResult, context) code = fs.Promote(orig, origResult, context)
} }
if code.Ok() && origResult.branch > 0 { if code.Ok() && origResult.branch > 0 {
// Hairy: for the link to be hooked up to the existing // Hairy: for the link to be hooked up to the existing
...@@ -355,25 +355,25 @@ func (me *UnionFs) Link(orig string, newName string, context *fuse.Context) (cod ...@@ -355,25 +355,25 @@ func (me *UnionFs) Link(orig string, newName string, context *fuse.Context) (cod
// original. We force a refresh of the attribute (so // original. We force a refresh of the attribute (so
// the Ino is filled in.), and then force PathNodeFs // the Ino is filled in.), and then force PathNodeFs
// to see the Inode number. // to see the Inode number.
me.branchCache.GetFresh(orig) fs.branchCache.GetFresh(orig)
inode := me.nodeFs.Node(orig) inode := fs.nodeFs.Node(orig)
inode.FsNode().GetAttr(nil, nil) inode.FsNode().GetAttr(nil, nil)
} }
if code.Ok() { if code.Ok() {
code = me.promoteDirsTo(newName) code = fs.promoteDirsTo(newName)
} }
if code.Ok() { if code.Ok() {
code = me.fileSystems[0].Link(orig, newName, context) code = fs.fileSystems[0].Link(orig, newName, context)
} }
if code.Ok() { if code.Ok() {
me.removeDeletion(newName) fs.removeDeletion(newName)
me.branchCache.GetFresh(newName) fs.branchCache.GetFresh(newName)
} }
return code return code
} }
func (me *UnionFs) Rmdir(path string, context *fuse.Context) (code fuse.Status) { func (fs *UnionFs) Rmdir(path string, context *fuse.Context) (code fuse.Status) {
r := me.getBranch(path) r := fs.getBranch(path)
if r.code != fuse.OK { if r.code != fuse.OK {
return r.code return r.code
} }
...@@ -381,7 +381,7 @@ func (me *UnionFs) Rmdir(path string, context *fuse.Context) (code fuse.Status) ...@@ -381,7 +381,7 @@ func (me *UnionFs) Rmdir(path string, context *fuse.Context) (code fuse.Status)
return fuse.Status(syscall.ENOTDIR) return fuse.Status(syscall.ENOTDIR)
} }
stream, code := me.OpenDir(path, context) stream, code := fs.OpenDir(path, context)
found := false found := false
for _ = range stream { for _ = range stream {
found = true found = true
...@@ -391,115 +391,115 @@ func (me *UnionFs) Rmdir(path string, context *fuse.Context) (code fuse.Status) ...@@ -391,115 +391,115 @@ func (me *UnionFs) Rmdir(path string, context *fuse.Context) (code fuse.Status)
} }
if r.branch > 0 { if r.branch > 0 {
code = me.putDeletion(path) code = fs.putDeletion(path)
return code return code
} }
code = me.fileSystems[0].Rmdir(path, context) code = fs.fileSystems[0].Rmdir(path, context)
if code != fuse.OK { if code != fuse.OK {
return code return code
} }
r = me.branchCache.GetFresh(path).(branchResult) r = fs.branchCache.GetFresh(path).(branchResult)
if r.branch > 0 { if r.branch > 0 {
code = me.putDeletion(path) code = fs.putDeletion(path)
} }
return code return code
} }
func (me *UnionFs) Mkdir(path string, mode uint32, context *fuse.Context) (code fuse.Status) { func (fs *UnionFs) Mkdir(path string, mode uint32, context *fuse.Context) (code fuse.Status) {
deleted, code := me.isDeleted(path) deleted, code := fs.isDeleted(path)
if !code.Ok() { if !code.Ok() {
return code return code
} }
if !deleted { if !deleted {
r := me.getBranch(path) r := fs.getBranch(path)
if r.code != fuse.ENOENT { if r.code != fuse.ENOENT {
return fuse.Status(syscall.EEXIST) return fuse.Status(syscall.EEXIST)
} }
} }
code = me.promoteDirsTo(path) code = fs.promoteDirsTo(path)
if code.Ok() { if code.Ok() {
code = me.fileSystems[0].Mkdir(path, mode, context) code = fs.fileSystems[0].Mkdir(path, mode, context)
} }
if code.Ok() { if code.Ok() {
me.removeDeletion(path) fs.removeDeletion(path)
attr := &fuse.Attr{ attr := &fuse.Attr{
Mode: fuse.S_IFDIR | mode, Mode: fuse.S_IFDIR | mode,
} }
me.branchCache.Set(path, branchResult{attr, fuse.OK, 0}) fs.branchCache.Set(path, branchResult{attr, fuse.OK, 0})
} }
var stream chan fuse.DirEntry var stream chan fuse.DirEntry
stream, code = me.OpenDir(path, context) stream, code = fs.OpenDir(path, context)
if code.Ok() { if code.Ok() {
// This shouldn't happen, but let's be safe. // This shouldn't happen, but let's be safe.
for entry := range stream { for entry := range stream {
me.putDeletion(filepath.Join(path, entry.Name)) fs.putDeletion(filepath.Join(path, entry.Name))
} }
} }
return code return code
} }
func (me *UnionFs) Symlink(pointedTo string, linkName string, context *fuse.Context) (code fuse.Status) { func (fs *UnionFs) Symlink(pointedTo string, linkName string, context *fuse.Context) (code fuse.Status) {
code = me.promoteDirsTo(linkName) code = fs.promoteDirsTo(linkName)
if code.Ok() { if code.Ok() {
code = me.fileSystems[0].Symlink(pointedTo, linkName, context) code = fs.fileSystems[0].Symlink(pointedTo, linkName, context)
} }
if code.Ok() { if code.Ok() {
me.removeDeletion(linkName) fs.removeDeletion(linkName)
me.branchCache.GetFresh(linkName) fs.branchCache.GetFresh(linkName)
} }
return code return code
} }
func (me *UnionFs) Truncate(path string, size uint64, context *fuse.Context) (code fuse.Status) { func (fs *UnionFs) Truncate(path string, size uint64, context *fuse.Context) (code fuse.Status) {
if path == _DROP_CACHE { if path == _DROP_CACHE {
return fuse.OK return fuse.OK
} }
r := me.getBranch(path) r := fs.getBranch(path)
if r.branch > 0 { if r.branch > 0 {
code = me.Promote(path, r, context) code = fs.Promote(path, r, context)
r.branch = 0 r.branch = 0
} }
if code.Ok() { if code.Ok() {
code = me.fileSystems[0].Truncate(path, size, context) code = fs.fileSystems[0].Truncate(path, size, context)
} }
if code.Ok() { if code.Ok() {
r.attr.Size = size r.attr.Size = size
now := time.Now() now := time.Now()
r.attr.SetTimes(nil, &now, &now) r.attr.SetTimes(nil, &now, &now)
me.branchCache.Set(path, r) fs.branchCache.Set(path, r)
} }
return code return code
} }
func (me *UnionFs) Utimens(name string, atime int64, mtime int64, context *fuse.Context) (code fuse.Status) { func (fs *UnionFs) Utimens(name string, atime int64, mtime int64, context *fuse.Context) (code fuse.Status) {
name = stripSlash(name) name = stripSlash(name)
r := me.getBranch(name) r := fs.getBranch(name)
code = r.code code = r.code
if code.Ok() && r.branch > 0 { if code.Ok() && r.branch > 0 {
code = me.Promote(name, r, context) code = fs.Promote(name, r, context)
r.branch = 0 r.branch = 0
} }
if code.Ok() { if code.Ok() {
code = me.fileSystems[0].Utimens(name, atime, mtime, context) code = fs.fileSystems[0].Utimens(name, atime, mtime, context)
} }
if code.Ok() { if code.Ok() {
r.attr.SetNs(atime, mtime, time.Now().UnixNano()) r.attr.SetNs(atime, mtime, time.Now().UnixNano())
me.branchCache.Set(name, r) fs.branchCache.Set(name, r)
} }
return code return code
} }
func (me *UnionFs) Chown(name string, uid uint32, gid uint32, context *fuse.Context) (code fuse.Status) { func (fs *UnionFs) Chown(name string, uid uint32, gid uint32, context *fuse.Context) (code fuse.Status) {
name = stripSlash(name) name = stripSlash(name)
r := me.getBranch(name) r := fs.getBranch(name)
if r.attr == nil || r.code != fuse.OK { if r.attr == nil || r.code != fuse.OK {
return r.code return r.code
} }
...@@ -510,25 +510,25 @@ func (me *UnionFs) Chown(name string, uid uint32, gid uint32, context *fuse.Cont ...@@ -510,25 +510,25 @@ func (me *UnionFs) Chown(name string, uid uint32, gid uint32, context *fuse.Cont
if r.attr.Uid != uid || r.attr.Gid != gid { if r.attr.Uid != uid || r.attr.Gid != gid {
if r.branch > 0 { if r.branch > 0 {
code := me.Promote(name, r, context) code := fs.Promote(name, r, context)
if code != fuse.OK { if code != fuse.OK {
return code return code
} }
r.branch = 0 r.branch = 0
} }
me.fileSystems[0].Chown(name, uid, gid, context) fs.fileSystems[0].Chown(name, uid, gid, context)
} }
r.attr.Uid = uid r.attr.Uid = uid
r.attr.Gid = gid r.attr.Gid = gid
now := time.Now() now := time.Now()
r.attr.SetTimes(nil, nil, &now) r.attr.SetTimes(nil, nil, &now)
me.branchCache.Set(name, r) fs.branchCache.Set(name, r)
return fuse.OK return fuse.OK
} }
func (me *UnionFs) Chmod(name string, mode uint32, context *fuse.Context) (code fuse.Status) { func (fs *UnionFs) Chmod(name string, mode uint32, context *fuse.Context) (code fuse.Status) {
name = stripSlash(name) name = stripSlash(name)
r := me.getBranch(name) r := fs.getBranch(name)
if r.attr == nil { if r.attr == nil {
return r.code return r.code
} }
...@@ -543,55 +543,55 @@ func (me *UnionFs) Chmod(name string, mode uint32, context *fuse.Context) (code ...@@ -543,55 +543,55 @@ func (me *UnionFs) Chmod(name string, mode uint32, context *fuse.Context) (code
if oldMode != mode { if oldMode != mode {
if r.branch > 0 { if r.branch > 0 {
code := me.Promote(name, r, context) code := fs.Promote(name, r, context)
if code != fuse.OK { if code != fuse.OK {
return code return code
} }
r.branch = 0 r.branch = 0
} }
me.fileSystems[0].Chmod(name, mode, context) fs.fileSystems[0].Chmod(name, mode, context)
} }
r.attr.Mode = (r.attr.Mode &^ permMask) | mode r.attr.Mode = (r.attr.Mode &^ permMask) | mode
now := time.Now() now := time.Now()
r.attr.SetTimes(nil, nil, &now) r.attr.SetTimes(nil, nil, &now)
me.branchCache.Set(name, r) fs.branchCache.Set(name, r)
return fuse.OK return fuse.OK
} }
func (me *UnionFs) Access(name string, mode uint32, context *fuse.Context) (code fuse.Status) { func (fs *UnionFs) Access(name string, mode uint32, context *fuse.Context) (code fuse.Status) {
// We always allow writing. // We always allow writing.
mode = mode &^ raw.W_OK mode = mode &^ raw.W_OK
if name == "" { if name == "" {
return fuse.OK return fuse.OK
} }
r := me.getBranch(name) r := fs.getBranch(name)
if r.branch >= 0 { if r.branch >= 0 {
return me.fileSystems[r.branch].Access(name, mode, context) return fs.fileSystems[r.branch].Access(name, mode, context)
} }
return fuse.ENOENT return fuse.ENOENT
} }
func (me *UnionFs) Unlink(name string, context *fuse.Context) (code fuse.Status) { func (fs *UnionFs) Unlink(name string, context *fuse.Context) (code fuse.Status) {
r := me.getBranch(name) r := fs.getBranch(name)
if r.branch == 0 { if r.branch == 0 {
code = me.fileSystems[0].Unlink(name, context) code = fs.fileSystems[0].Unlink(name, context)
if code != fuse.OK { if code != fuse.OK {
return code return code
} }
r = me.branchCache.GetFresh(name).(branchResult) r = fs.branchCache.GetFresh(name).(branchResult)
} }
if r.branch > 0 { if r.branch > 0 {
// It would be nice to do the putDeletion async. // It would be nice to do the putDeletion async.
code = me.putDeletion(name) code = fs.putDeletion(name)
} }
return code return code
} }
func (me *UnionFs) Readlink(name string, context *fuse.Context) (out string, code fuse.Status) { func (fs *UnionFs) Readlink(name string, context *fuse.Context) (out string, code fuse.Status) {
r := me.getBranch(name) r := fs.getBranch(name)
if r.branch >= 0 { if r.branch >= 0 {
return me.fileSystems[r.branch].Readlink(name, context) return fs.fileSystems[r.branch].Readlink(name, context)
} }
return "", fuse.ENOENT return "", fuse.ENOENT
} }
...@@ -605,14 +605,14 @@ func stripSlash(fn string) string { ...@@ -605,14 +605,14 @@ func stripSlash(fn string) string {
return strings.TrimRight(fn, string(filepath.Separator)) return strings.TrimRight(fn, string(filepath.Separator))
} }
func (me *UnionFs) promoteDirsTo(filename string) fuse.Status { func (fs *UnionFs) promoteDirsTo(filename string) fuse.Status {
dirName, _ := filepath.Split(filename) dirName, _ := filepath.Split(filename)
dirName = stripSlash(dirName) dirName = stripSlash(dirName)
var todo []string var todo []string
var results []branchResult var results []branchResult
for dirName != "" { for dirName != "" {
r := me.getBranch(dirName) r := fs.getBranch(dirName)
if !r.code.Ok() { if !r.code.Ok() {
log.Println("path component does not exist", filename, dirName) log.Println("path component does not exist", filename, dirName)
...@@ -634,43 +634,43 @@ func (me *UnionFs) promoteDirsTo(filename string) fuse.Status { ...@@ -634,43 +634,43 @@ func (me *UnionFs) promoteDirsTo(filename string) fuse.Status {
j := len(todo) - i - 1 j := len(todo) - i - 1
d := todo[j] d := todo[j]
r := results[j] r := results[j]
code := me.fileSystems[0].Mkdir(d, r.attr.Mode&07777|0200, nil) code := fs.fileSystems[0].Mkdir(d, r.attr.Mode&07777|0200, nil)
if code != fuse.OK { if code != fuse.OK {
log.Println("Error creating dir leading to path", d, code, me.fileSystems[0]) log.Println("Error creating dir leading to path", d, code, fs.fileSystems[0])
return fuse.EPERM return fuse.EPERM
} }
me.fileSystems[0].Utimens(d, r.attr.Atimens(), r.attr.Mtimens(), nil) fs.fileSystems[0].Utimens(d, r.attr.Atimens(), r.attr.Mtimens(), nil)
r.branch = 0 r.branch = 0
me.branchCache.Set(d, r) fs.branchCache.Set(d, r)
} }
return fuse.OK return fuse.OK
} }
func (me *UnionFs) Create(name string, flags uint32, mode uint32, context *fuse.Context) (fuseFile fuse.File, code fuse.Status) { func (fs *UnionFs) Create(name string, flags uint32, mode uint32, context *fuse.Context) (fuseFile fuse.File, code fuse.Status) {
writable := me.fileSystems[0] writable := fs.fileSystems[0]
code = me.promoteDirsTo(name) code = fs.promoteDirsTo(name)
if code != fuse.OK { if code != fuse.OK {
return nil, code return nil, code
} }
fuseFile, code = writable.Create(name, flags, mode, context) fuseFile, code = writable.Create(name, flags, mode, context)
if code.Ok() { if code.Ok() {
fuseFile = me.newUnionFsFile(fuseFile, 0) fuseFile = fs.newUnionFsFile(fuseFile, 0)
me.removeDeletion(name) fs.removeDeletion(name)
now := time.Now() now := time.Now()
a := fuse.Attr{ a := fuse.Attr{
Mode: fuse.S_IFREG | mode, Mode: fuse.S_IFREG | mode,
} }
a.SetTimes(nil, &now, &now) a.SetTimes(nil, &now, &now)
me.branchCache.Set(name, branchResult{&a, fuse.OK, 0}) fs.branchCache.Set(name, branchResult{&a, fuse.OK, 0})
} }
return fuseFile, code return fuseFile, code
} }
func (me *UnionFs) GetAttr(name string, context *fuse.Context) (a *fuse.Attr, s fuse.Status) { func (fs *UnionFs) GetAttr(name string, context *fuse.Context) (a *fuse.Attr, s fuse.Status) {
_, hidden := me.hiddenFiles[name] _, hidden := fs.hiddenFiles[name]
if hidden { if hidden {
return nil, fuse.ENOENT return nil, fuse.ENOENT
} }
...@@ -679,10 +679,10 @@ func (me *UnionFs) GetAttr(name string, context *fuse.Context) (a *fuse.Attr, s ...@@ -679,10 +679,10 @@ func (me *UnionFs) GetAttr(name string, context *fuse.Context) (a *fuse.Attr, s
Mode: fuse.S_IFREG | 0777, Mode: fuse.S_IFREG | 0777,
}, fuse.OK }, fuse.OK
} }
if name == me.options.DeletionDirName { if name == fs.options.DeletionDirName {
return nil, fuse.ENOENT return nil, fuse.ENOENT
} }
isDel, s := me.isDeleted(name) isDel, s := fs.isDeleted(name)
if !s.Ok() { if !s.Ok() {
return nil, s return nil, s
} }
...@@ -690,7 +690,7 @@ func (me *UnionFs) GetAttr(name string, context *fuse.Context) (a *fuse.Attr, s ...@@ -690,7 +690,7 @@ func (me *UnionFs) GetAttr(name string, context *fuse.Context) (a *fuse.Attr, s
if isDel { if isDel {
return nil, fuse.ENOENT return nil, fuse.ENOENT
} }
r := me.getBranch(name) r := fs.getBranch(name)
if r.branch < 0 { if r.branch < 0 {
return nil, fuse.ENOENT return nil, fuse.ENOENT
} }
...@@ -700,20 +700,20 @@ func (me *UnionFs) GetAttr(name string, context *fuse.Context) (a *fuse.Attr, s ...@@ -700,20 +700,20 @@ func (me *UnionFs) GetAttr(name string, context *fuse.Context) (a *fuse.Attr, s
return &fi, r.code return &fi, r.code
} }
func (me *UnionFs) GetXAttr(name string, attr string, context *fuse.Context) ([]byte, fuse.Status) { func (fs *UnionFs) GetXAttr(name string, attr string, context *fuse.Context) ([]byte, fuse.Status) {
if name == _DROP_CACHE { if name == _DROP_CACHE {
return nil, fuse.ENODATA return nil, fuse.ENODATA
} }
r := me.getBranch(name) r := fs.getBranch(name)
if r.branch >= 0 { if r.branch >= 0 {
return me.fileSystems[r.branch].GetXAttr(name, attr, context) return fs.fileSystems[r.branch].GetXAttr(name, attr, context)
} }
return nil, fuse.ENOENT return nil, fuse.ENOENT
} }
func (me *UnionFs) OpenDir(directory string, context *fuse.Context) (stream chan fuse.DirEntry, status fuse.Status) { func (fs *UnionFs) OpenDir(directory string, context *fuse.Context) (stream chan fuse.DirEntry, status fuse.Status) {
dirBranch := me.getBranch(directory) dirBranch := fs.getBranch(directory)
if dirBranch.branch < 0 { if dirBranch.branch < 0 {
return nil, fuse.ENOENT return nil, fuse.ENOENT
} }
...@@ -725,17 +725,17 @@ func (me *UnionFs) OpenDir(directory string, context *fuse.Context) (stream chan ...@@ -725,17 +725,17 @@ func (me *UnionFs) OpenDir(directory string, context *fuse.Context) (stream chan
wg.Add(1) wg.Add(1)
go func() { go func() {
deletions = newDirnameMap(me.fileSystems[0], me.options.DeletionDirName) deletions = newDirnameMap(fs.fileSystems[0], fs.options.DeletionDirName)
wg.Done() wg.Done()
}() }()
entries := make([]map[string]uint32, len(me.fileSystems)) entries := make([]map[string]uint32, len(fs.fileSystems))
for i := range me.fileSystems { for i := range fs.fileSystems {
entries[i] = make(map[string]uint32) entries[i] = make(map[string]uint32)
} }
statuses := make([]fuse.Status, len(me.fileSystems)) statuses := make([]fuse.Status, len(fs.fileSystems))
for i, l := range me.fileSystems { for i, l := range fs.fileSystems {
if i >= dirBranch.branch { if i >= dirBranch.branch {
wg.Add(1) wg.Add(1)
go func(j int, pfs fuse.FileSystem) { go func(j int, pfs fuse.FileSystem) {
...@@ -755,7 +755,7 @@ func (me *UnionFs) OpenDir(directory string, context *fuse.Context) (stream chan ...@@ -755,7 +755,7 @@ func (me *UnionFs) OpenDir(directory string, context *fuse.Context) (stream chan
wg.Wait() wg.Wait()
if deletions == nil { if deletions == nil {
_, code := me.fileSystems[0].GetAttr(me.options.DeletionDirName, context) _, code := fs.fileSystems[0].GetAttr(fs.options.DeletionDirName, context)
if code == fuse.ENOENT { if code == fuse.ENOENT {
deletions = map[string]bool{} deletions = map[string]bool{}
} else { } else {
...@@ -789,8 +789,8 @@ func (me *UnionFs) OpenDir(directory string, context *fuse.Context) (stream chan ...@@ -789,8 +789,8 @@ func (me *UnionFs) OpenDir(directory string, context *fuse.Context) (stream chan
} }
} }
if directory == "" { if directory == "" {
delete(results, me.options.DeletionDirName) delete(results, fs.options.DeletionDirName)
for name, _ := range me.hiddenFiles { for name, _ := range fs.hiddenFiles {
delete(results, name) delete(results, name)
} }
} }
...@@ -809,10 +809,10 @@ func (me *UnionFs) OpenDir(directory string, context *fuse.Context) (stream chan ...@@ -809,10 +809,10 @@ func (me *UnionFs) OpenDir(directory string, context *fuse.Context) (stream chan
// recursivePromote promotes path, and if a directory, everything // recursivePromote promotes path, and if a directory, everything
// below that directory. It returns a list of all promoted paths, in // below that directory. It returns a list of all promoted paths, in
// full, including the path itself. // full, including the path itself.
func (me *UnionFs) recursivePromote(path string, pathResult branchResult, context *fuse.Context) (names []string, code fuse.Status) { func (fs *UnionFs) recursivePromote(path string, pathResult branchResult, context *fuse.Context) (names []string, code fuse.Status) {
names = []string{} names = []string{}
if pathResult.branch > 0 { if pathResult.branch > 0 {
code = me.Promote(path, pathResult, context) code = fs.Promote(path, pathResult, context)
} }
if code.Ok() { if code.Ok() {
...@@ -821,15 +821,15 @@ func (me *UnionFs) recursivePromote(path string, pathResult branchResult, contex ...@@ -821,15 +821,15 @@ func (me *UnionFs) recursivePromote(path string, pathResult branchResult, contex
if code.Ok() && pathResult.attr != nil && pathResult.attr.IsDir() { if code.Ok() && pathResult.attr != nil && pathResult.attr.IsDir() {
var stream chan fuse.DirEntry var stream chan fuse.DirEntry
stream, code = me.OpenDir(path, context) stream, code = fs.OpenDir(path, context)
for e := range stream { for e := range stream {
if !code.Ok() { if !code.Ok() {
break break
} }
subnames := []string{} subnames := []string{}
p := filepath.Join(path, e.Name) p := filepath.Join(path, e.Name)
r := me.getBranch(p) r := fs.getBranch(p)
subnames, code = me.recursivePromote(p, r, context) subnames, code = fs.recursivePromote(p, r, context)
names = append(names, subnames...) names = append(names, subnames...)
} }
} }
...@@ -840,17 +840,17 @@ func (me *UnionFs) recursivePromote(path string, pathResult branchResult, contex ...@@ -840,17 +840,17 @@ func (me *UnionFs) recursivePromote(path string, pathResult branchResult, contex
return names, code return names, code
} }
func (me *UnionFs) renameDirectory(srcResult branchResult, srcDir string, dstDir string, context *fuse.Context) (code fuse.Status) { func (fs *UnionFs) renameDirectory(srcResult branchResult, srcDir string, dstDir string, context *fuse.Context) (code fuse.Status) {
names := []string{} names := []string{}
if code.Ok() { if code.Ok() {
names, code = me.recursivePromote(srcDir, srcResult, context) names, code = fs.recursivePromote(srcDir, srcResult, context)
} }
if code.Ok() { if code.Ok() {
code = me.promoteDirsTo(dstDir) code = fs.promoteDirsTo(dstDir)
} }
if code.Ok() { if code.Ok() {
writable := me.fileSystems[0] writable := fs.fileSystems[0]
code = writable.Rename(srcDir, dstDir, context) code = writable.Rename(srcDir, dstDir, context)
} }
...@@ -858,65 +858,65 @@ func (me *UnionFs) renameDirectory(srcResult branchResult, srcDir string, dstDir ...@@ -858,65 +858,65 @@ func (me *UnionFs) renameDirectory(srcResult branchResult, srcDir string, dstDir
for _, srcName := range names { for _, srcName := range names {
relative := strings.TrimLeft(srcName[len(srcDir):], string(filepath.Separator)) relative := strings.TrimLeft(srcName[len(srcDir):], string(filepath.Separator))
dst := filepath.Join(dstDir, relative) dst := filepath.Join(dstDir, relative)
me.removeDeletion(dst) fs.removeDeletion(dst)
srcResult := me.getBranch(srcName) srcResult := fs.getBranch(srcName)
srcResult.branch = 0 srcResult.branch = 0
me.branchCache.Set(dst, srcResult) fs.branchCache.Set(dst, srcResult)
srcResult = me.branchCache.GetFresh(srcName).(branchResult) srcResult = fs.branchCache.GetFresh(srcName).(branchResult)
if srcResult.branch > 0 { if srcResult.branch > 0 {
code = me.putDeletion(srcName) code = fs.putDeletion(srcName)
} }
} }
} }
return code return code
} }
func (me *UnionFs) Rename(src string, dst string, context *fuse.Context) (code fuse.Status) { func (fs *UnionFs) Rename(src string, dst string, context *fuse.Context) (code fuse.Status) {
srcResult := me.getBranch(src) srcResult := fs.getBranch(src)
code = srcResult.code code = srcResult.code
if code.Ok() { if code.Ok() {
code = srcResult.code code = srcResult.code
} }
if srcResult.attr.IsDir() { if srcResult.attr.IsDir() {
return me.renameDirectory(srcResult, src, dst, context) return fs.renameDirectory(srcResult, src, dst, context)
} }
if code.Ok() && srcResult.branch > 0 { if code.Ok() && srcResult.branch > 0 {
code = me.Promote(src, srcResult, context) code = fs.Promote(src, srcResult, context)
} }
if code.Ok() { if code.Ok() {
code = me.promoteDirsTo(dst) code = fs.promoteDirsTo(dst)
} }
if code.Ok() { if code.Ok() {
code = me.fileSystems[0].Rename(src, dst, context) code = fs.fileSystems[0].Rename(src, dst, context)
} }
if code.Ok() { if code.Ok() {
me.removeDeletion(dst) fs.removeDeletion(dst)
// Rename is racy; avoid racing with unionFsFile.Release(). // Rename is racy; avoid racing with unionFsFile.Release().
me.branchCache.DropEntry(dst) fs.branchCache.DropEntry(dst)
srcResult := me.branchCache.GetFresh(src) srcResult := fs.branchCache.GetFresh(src)
if srcResult.(branchResult).branch > 0 { if srcResult.(branchResult).branch > 0 {
code = me.putDeletion(src) code = fs.putDeletion(src)
} }
} }
return code return code
} }
func (me *UnionFs) DropBranchCache(names []string) { func (fs *UnionFs) DropBranchCache(names []string) {
me.branchCache.DropAll(names) fs.branchCache.DropAll(names)
} }
func (me *UnionFs) DropDeletionCache() { func (fs *UnionFs) DropDeletionCache() {
me.deletionCache.DropCache() fs.deletionCache.DropCache()
} }
func (me *UnionFs) DropSubFsCaches() { func (fs *UnionFs) DropSubFsCaches() {
for _, fs := range me.fileSystems { for _, fs := range fs.fileSystems {
a, code := fs.GetAttr(_DROP_CACHE, nil) a, code := fs.GetAttr(_DROP_CACHE, nil)
if code.Ok() && a.IsRegular() { if code.Ok() && a.IsRegular() {
f, _ := fs.Open(_DROP_CACHE, uint32(os.O_WRONLY), nil) f, _ := fs.Open(_DROP_CACHE, uint32(os.O_WRONLY), nil)
...@@ -928,18 +928,18 @@ func (me *UnionFs) DropSubFsCaches() { ...@@ -928,18 +928,18 @@ func (me *UnionFs) DropSubFsCaches() {
} }
} }
func (me *UnionFs) Open(name string, flags uint32, context *fuse.Context) (fuseFile fuse.File, status fuse.Status) { func (fs *UnionFs) Open(name string, flags uint32, context *fuse.Context) (fuseFile fuse.File, status fuse.Status) {
if name == _DROP_CACHE { if name == _DROP_CACHE {
if flags&fuse.O_ANYWRITE != 0 { if flags&fuse.O_ANYWRITE != 0 {
log.Println("Forced cache drop on", me) log.Println("Forced cache drop on", fs)
me.DropBranchCache(nil) fs.DropBranchCache(nil)
me.DropDeletionCache() fs.DropDeletionCache()
me.DropSubFsCaches() fs.DropSubFsCaches()
me.nodeFs.ForgetClientInodes() fs.nodeFs.ForgetClientInodes()
} }
return fuse.NewDevNullFile(), fuse.OK return fuse.NewDevNullFile(), fuse.OK
} }
r := me.getBranch(name) r := fs.getBranch(name)
if r.branch < 0 { if r.branch < 0 {
// This should not happen, as a GetAttr() should have // This should not happen, as a GetAttr() should have
// already verified existence. // already verified existence.
...@@ -947,32 +947,32 @@ func (me *UnionFs) Open(name string, flags uint32, context *fuse.Context) (fuseF ...@@ -947,32 +947,32 @@ func (me *UnionFs) Open(name string, flags uint32, context *fuse.Context) (fuseF
return nil, fuse.ENOENT return nil, fuse.ENOENT
} }
if flags&fuse.O_ANYWRITE != 0 && r.branch > 0 { if flags&fuse.O_ANYWRITE != 0 && r.branch > 0 {
code := me.Promote(name, r, context) code := fs.Promote(name, r, context)
if code != fuse.OK { if code != fuse.OK {
return nil, code return nil, code
} }
r.branch = 0 r.branch = 0
now := time.Now() now := time.Now()
r.attr.SetTimes(nil, &now, nil) r.attr.SetTimes(nil, &now, nil)
me.branchCache.Set(name, r) fs.branchCache.Set(name, r)
} }
fuseFile, status = me.fileSystems[r.branch].Open(name, uint32(flags), context) fuseFile, status = fs.fileSystems[r.branch].Open(name, uint32(flags), context)
if fuseFile != nil { if fuseFile != nil {
fuseFile = me.newUnionFsFile(fuseFile, r.branch) fuseFile = fs.newUnionFsFile(fuseFile, r.branch)
} }
return fuseFile, status return fuseFile, status
} }
func (me *UnionFs) String() string { func (fs *UnionFs) String() string {
names := []string{} names := []string{}
for _, fs := range me.fileSystems { for _, fs := range fs.fileSystems {
names = append(names, fs.String()) names = append(names, fs.String())
} }
return fmt.Sprintf("UnionFs(%v)", names) return fmt.Sprintf("UnionFs(%v)", names)
} }
func (me *UnionFs) StatFs(name string) *fuse.StatfsOut { func (fs *UnionFs) StatFs(name string) *fuse.StatfsOut {
return me.fileSystems[0].StatFs("") return fs.fileSystems[0].StatFs("")
} }
type unionFsFile struct { type unionFsFile struct {
...@@ -982,37 +982,37 @@ type unionFsFile struct { ...@@ -982,37 +982,37 @@ type unionFsFile struct {
layer int layer int
} }
func (me *unionFsFile) String() string { func (fs *unionFsFile) String() string {
return fmt.Sprintf("unionFsFile(%s)", me.File.String()) return fmt.Sprintf("unionFsFile(%s)", fs.File.String())
} }
func (me *UnionFs) newUnionFsFile(f fuse.File, branch int) *unionFsFile { func (fs *UnionFs) newUnionFsFile(f fuse.File, branch int) *unionFsFile {
return &unionFsFile{ return &unionFsFile{
File: f, File: f,
ufs: me, ufs: fs,
layer: branch, layer: branch,
} }
} }
func (me *unionFsFile) InnerFile() (file fuse.File) { func (fs *unionFsFile) InnerFile() (file fuse.File) {
return me.File return fs.File
} }
// We can't hook on Release. Release has no response, so it is not // We can't hook on Release. Release has no response, so it is not
// ordered wrt any following calls. // ordered wrt any following calls.
func (me *unionFsFile) Flush() (code fuse.Status) { func (fs *unionFsFile) Flush() (code fuse.Status) {
code = me.File.Flush() code = fs.File.Flush()
path := me.ufs.nodeFs.Path(me.node) path := fs.ufs.nodeFs.Path(fs.node)
me.ufs.branchCache.GetFresh(path) fs.ufs.branchCache.GetFresh(path)
return code return code
} }
func (me *unionFsFile) SetInode(node *fuse.Inode) { func (fs *unionFsFile) SetInode(node *fuse.Inode) {
me.node = node fs.node = node
} }
func (me *unionFsFile) GetAttr() (*fuse.Attr, fuse.Status) { func (fs *unionFsFile) GetAttr() (*fuse.Attr, fuse.Status) {
fi, code := me.File.GetAttr() fi, code := fs.File.GetAttr()
if fi != nil { if fi != nil {
f := *fi f := *fi
fi = &f fi = &f
......
...@@ -30,24 +30,24 @@ func NewMemTreeFs() *MemTreeFs { ...@@ -30,24 +30,24 @@ func NewMemTreeFs() *MemTreeFs {
return d return d
} }
func (me *MemTreeFs) OnMount(conn *fuse.FileSystemConnector) { func (fs *MemTreeFs) OnMount(conn *fuse.FileSystemConnector) {
for k, v := range me.files { for k, v := range fs.files {
me.addFile(k, v) fs.addFile(k, v)
} }
me.files = nil fs.files = nil
} }
func (me *MemTreeFs) Root() fuse.FsNode { func (fs *MemTreeFs) Root() fuse.FsNode {
return &me.root return &fs.root
} }
func (me *memNode) Print(indent int) { func (n *memNode) Print(indent int) {
s := "" s := ""
for i := 0; i < indent; i++ { for i := 0; i < indent; i++ {
s = s + " " s = s + " "
} }
children := me.Inode().Children() children := n.Inode().Children()
for k, v := range children { for k, v := range children {
if v.IsDir() { if v.IsDir() {
fmt.Println(s + k + ":") fmt.Println(s + k + ":")
...@@ -62,12 +62,12 @@ func (me *memNode) Print(indent int) { ...@@ -62,12 +62,12 @@ func (me *memNode) Print(indent int) {
} }
// We construct the tree at mount, so we never need to look anything up. // We construct the tree at mount, so we never need to look anything up.
func (me *memNode) Lookup(name string, c *fuse.Context) (fi *fuse.Attr, node fuse.FsNode, code fuse.Status) { func (n *memNode) Lookup(name string, c *fuse.Context) (fi *fuse.Attr, node fuse.FsNode, code fuse.Status) {
return nil, nil, fuse.ENOENT return nil, nil, fuse.ENOENT
} }
func (me *memNode) OpenDir(context *fuse.Context) (stream chan fuse.DirEntry, code fuse.Status) { func (n *memNode) OpenDir(context *fuse.Context) (stream chan fuse.DirEntry, code fuse.Status) {
children := me.Inode().Children() children := n.Inode().Children()
stream = make(chan fuse.DirEntry, len(children)) stream = make(chan fuse.DirEntry, len(children))
for k, v := range children { for k, v := range children {
mode := fuse.S_IFREG | 0666 mode := fuse.S_IFREG | 0666
...@@ -83,32 +83,32 @@ func (me *memNode) OpenDir(context *fuse.Context) (stream chan fuse.DirEntry, co ...@@ -83,32 +83,32 @@ func (me *memNode) OpenDir(context *fuse.Context) (stream chan fuse.DirEntry, co
return stream, fuse.OK return stream, fuse.OK
} }
func (me *memNode) Open(flags uint32, context *fuse.Context) (fuseFile fuse.File, code fuse.Status) { func (n *memNode) Open(flags uint32, context *fuse.Context) (fuseFile fuse.File, code fuse.Status) {
if flags&fuse.O_ANYWRITE != 0 { if flags&fuse.O_ANYWRITE != 0 {
return nil, fuse.EPERM return nil, fuse.EPERM
} }
return fuse.NewDataFile(me.file.Data()), fuse.OK return fuse.NewDataFile(n.file.Data()), fuse.OK
} }
func (me *memNode) Deletable() bool { func (n *memNode) Deletable() bool {
return false return false
} }
func (me *memNode) GetAttr(file fuse.File, context *fuse.Context) (*fuse.Attr, fuse.Status) { func (n *memNode) GetAttr(file fuse.File, context *fuse.Context) (*fuse.Attr, fuse.Status) {
if me.Inode().IsDir() { if n.Inode().IsDir() {
return &fuse.Attr{ return &fuse.Attr{
Mode: fuse.S_IFDIR | 0777, Mode: fuse.S_IFDIR | 0777,
}, fuse.OK }, fuse.OK
} }
return me.file.Stat(), fuse.OK return n.file.Stat(), fuse.OK
} }
func (me *MemTreeFs) addFile(name string, f MemFile) { func (n *MemTreeFs) addFile(name string, f MemFile) {
comps := strings.Split(name, "/") comps := strings.Split(name, "/")
node := me.root.Inode() node := n.root.Inode()
for i, c := range comps { for i, c := range comps {
child := node.GetChild(c) child := node.GetChild(c)
if child == nil { if child == nil {
......
...@@ -42,19 +42,19 @@ func NewMultiZipFs() *MultiZipFs { ...@@ -42,19 +42,19 @@ func NewMultiZipFs() *MultiZipFs {
return m return m
} }
func (me *MultiZipFs) String() string { func (fs *MultiZipFs) String() string {
return "MultiZipFs" return "MultiZipFs"
} }
func (me *MultiZipFs) OnMount(nodeFs *fuse.PathNodeFs) { func (fs *MultiZipFs) OnMount(nodeFs *fuse.PathNodeFs) {
me.nodeFs = nodeFs fs.nodeFs = nodeFs
} }
func (me *MultiZipFs) OpenDir(name string, context *fuse.Context) (stream chan fuse.DirEntry, code fuse.Status) { func (fs *MultiZipFs) OpenDir(name string, context *fuse.Context) (stream chan fuse.DirEntry, code fuse.Status) {
me.lock.RLock() fs.lock.RLock()
defer me.lock.RUnlock() defer fs.lock.RUnlock()
stream = make(chan fuse.DirEntry, len(me.zips)+2) stream = make(chan fuse.DirEntry, len(fs.zips)+2)
if name == "" { if name == "" {
var d fuse.DirEntry var d fuse.DirEntry
d.Name = "config" d.Name = "config"
...@@ -63,7 +63,7 @@ func (me *MultiZipFs) OpenDir(name string, context *fuse.Context) (stream chan f ...@@ -63,7 +63,7 @@ func (me *MultiZipFs) OpenDir(name string, context *fuse.Context) (stream chan f
} }
if name == "config" { if name == "config" {
for k := range me.zips { for k := range fs.zips {
var d fuse.DirEntry var d fuse.DirEntry
d.Name = k d.Name = k
d.Mode = fuse.S_IFLNK d.Mode = fuse.S_IFLNK
...@@ -75,7 +75,7 @@ func (me *MultiZipFs) OpenDir(name string, context *fuse.Context) (stream chan f ...@@ -75,7 +75,7 @@ func (me *MultiZipFs) OpenDir(name string, context *fuse.Context) (stream chan f
return stream, fuse.OK return stream, fuse.OK
} }
func (me *MultiZipFs) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) { func (fs *MultiZipFs) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
a := &fuse.Attr{} a := &fuse.Attr{}
if name == "" { if name == "" {
// Should not write in top dir. // Should not write in top dir.
...@@ -97,11 +97,11 @@ func (me *MultiZipFs) GetAttr(name string, context *fuse.Context) (*fuse.Attr, f ...@@ -97,11 +97,11 @@ func (me *MultiZipFs) GetAttr(name string, context *fuse.Context) (*fuse.Attr, f
submode = fuse.S_IFLNK | 0600 submode = fuse.S_IFLNK | 0600
} }
me.lock.RLock() fs.lock.RLock()
defer me.lock.RUnlock() defer fs.lock.RUnlock()
a.Mode = submode a.Mode = submode
_, hasDir := me.zips[base] _, hasDir := fs.zips[base]
if hasDir { if hasDir {
return a, fuse.OK return a, fuse.OK
} }
...@@ -109,20 +109,20 @@ func (me *MultiZipFs) GetAttr(name string, context *fuse.Context) (*fuse.Attr, f ...@@ -109,20 +109,20 @@ func (me *MultiZipFs) GetAttr(name string, context *fuse.Context) (*fuse.Attr, f
return nil, fuse.ENOENT return nil, fuse.ENOENT
} }
func (me *MultiZipFs) Unlink(name string, context *fuse.Context) (code fuse.Status) { func (fs *MultiZipFs) Unlink(name string, context *fuse.Context) (code fuse.Status) {
dir, basename := filepath.Split(name) dir, basename := filepath.Split(name)
if dir == CONFIG_PREFIX { if dir == CONFIG_PREFIX {
me.lock.Lock() fs.lock.Lock()
defer me.lock.Unlock() defer fs.lock.Unlock()
zfs, ok := me.zips[basename] zfs, ok := fs.zips[basename]
if ok { if ok {
code = me.nodeFs.UnmountNode(zfs.Root().Inode()) code = fs.nodeFs.UnmountNode(zfs.Root().Inode())
if !code.Ok() { if !code.Ok() {
return code return code
} }
delete(me.zips, basename) delete(fs.zips, basename)
delete(me.dirZipFileMap, basename) delete(fs.dirZipFileMap, basename)
return fuse.OK return fuse.OK
} else { } else {
return fuse.ENOENT return fuse.ENOENT
...@@ -131,48 +131,48 @@ func (me *MultiZipFs) Unlink(name string, context *fuse.Context) (code fuse.Stat ...@@ -131,48 +131,48 @@ func (me *MultiZipFs) Unlink(name string, context *fuse.Context) (code fuse.Stat
return fuse.EPERM return fuse.EPERM
} }
func (me *MultiZipFs) Readlink(path string, context *fuse.Context) (val string, code fuse.Status) { func (fs *MultiZipFs) Readlink(path string, context *fuse.Context) (val string, code fuse.Status) {
dir, base := filepath.Split(path) dir, base := filepath.Split(path)
if dir != CONFIG_PREFIX { if dir != CONFIG_PREFIX {
return "", fuse.ENOENT return "", fuse.ENOENT
} }
me.lock.Lock() fs.lock.Lock()
defer me.lock.Unlock() defer fs.lock.Unlock()
zipfile, ok := me.dirZipFileMap[base] zipfile, ok := fs.dirZipFileMap[base]
if !ok { if !ok {
return "", fuse.ENOENT return "", fuse.ENOENT
} }
return zipfile, fuse.OK return zipfile, fuse.OK
} }
func (me *MultiZipFs) Symlink(value string, linkName string, context *fuse.Context) (code fuse.Status) { func (fs *MultiZipFs) Symlink(value string, linkName string, context *fuse.Context) (code fuse.Status) {
dir, base := filepath.Split(linkName) dir, base := filepath.Split(linkName)
if dir != CONFIG_PREFIX { if dir != CONFIG_PREFIX {
return fuse.EPERM return fuse.EPERM
} }
me.lock.Lock() fs.lock.Lock()
defer me.lock.Unlock() defer fs.lock.Unlock()
_, ok := me.dirZipFileMap[base] _, ok := fs.dirZipFileMap[base]
if ok { if ok {
return fuse.EBUSY return fuse.EBUSY
} }
fs, err := NewArchiveFileSystem(value) afs, err := NewArchiveFileSystem(value)
if err != nil { if err != nil {
log.Println("NewZipArchiveFileSystem failed.", err) log.Println("NewZipArchiveFileSystem failed.", err)
return fuse.EINVAL return fuse.EINVAL
} }
code = me.nodeFs.Mount(base, fs, nil) code = fs.nodeFs.Mount(base, afs, nil)
if !code.Ok() { if !code.Ok() {
return code return code
} }
me.dirZipFileMap[base] = value fs.dirZipFileMap[base] = value
me.zips[base] = fs fs.zips[base] = afs
return fuse.OK return fuse.OK
} }
...@@ -33,14 +33,14 @@ type TarFile struct { ...@@ -33,14 +33,14 @@ type TarFile struct {
tar.Header tar.Header
} }
func (me *TarFile) Stat() *fuse.Attr { func (f *TarFile) Stat() *fuse.Attr {
fi, _ := HeaderToFileInfo(&me.Header) fi, _ := HeaderToFileInfo(&f.Header)
fi.Mode |= syscall.S_IFREG fi.Mode |= syscall.S_IFREG
return fi return fi
} }
func (me *TarFile) Data() []byte { func (f *TarFile) Data() []byte {
return me.data return f.data
} }
func NewTarTree(r io.Reader) map[string]MemFile { func NewTarTree(r io.Reader) map[string]MemFile {
......
...@@ -19,23 +19,23 @@ type ZipFile struct { ...@@ -19,23 +19,23 @@ type ZipFile struct {
*zip.File *zip.File
} }
func (me *ZipFile) Stat() *fuse.Attr { func (f *ZipFile) Stat() *fuse.Attr {
// TODO - do something intelligent with timestamps. // TODO - do something intelligent with timestamps.
return &fuse.Attr{ return &fuse.Attr{
Mode: fuse.S_IFREG | 0444, Mode: fuse.S_IFREG | 0444,
Size: uint64(me.File.UncompressedSize), Size: uint64(f.File.UncompressedSize),
} }
} }
func (me *ZipFile) Data() []byte { func (f *ZipFile) Data() []byte {
zf := (*me) zf := (*f)
rc, err := zf.Open() rc, err := zf.Open()
if err != nil { if err != nil {
panic(err) panic(err)
} }
dest := bytes.NewBuffer(make([]byte, 0, me.UncompressedSize)) dest := bytes.NewBuffer(make([]byte, 0, f.UncompressedSize))
_, err = io.CopyN(dest, rc, int64(me.UncompressedSize)) _, err = io.CopyN(dest, rc, int64(f.UncompressedSize))
if err != nil { if err != nil {
panic(err) panic(err)
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment