Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
go-fuse
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Levin Zimmermann
go-fuse
Commits
5514ae72
Commit
5514ae72
authored
May 02, 2012
by
Han-Wen Nienhuys
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Go style receivers for unionfs/ and zipfs/
parent
7fc85869
Changes
9
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
415 additions
and
415 deletions
+415
-415
unionfs/autounion.go
unionfs/autounion.go
+80
-80
unionfs/cachingfs.go
unionfs/cachingfs.go
+16
-16
unionfs/dircache.go
unionfs/dircache.go
+37
-37
unionfs/timedcache.go
unionfs/timedcache.go
+34
-34
unionfs/unionfs.go
unionfs/unionfs.go
+188
-188
zipfs/memtree.go
zipfs/memtree.go
+19
-19
zipfs/multizip.go
zipfs/multizip.go
+31
-31
zipfs/tarfs.go
zipfs/tarfs.go
+4
-4
zipfs/zipfs.go
zipfs/zipfs.go
+6
-6
No files found.
unionfs/autounion.go
View file @
5514ae72
...
...
@@ -76,31 +76,31 @@ func NewAutoUnionFs(directory string, options AutoUnionFsOptions) *AutoUnionFs {
return
a
}
func
(
me
*
AutoUnionFs
)
String
()
string
{
return
fmt
.
Sprintf
(
"AutoUnionFs(%s)"
,
me
.
root
)
func
(
fs
*
AutoUnionFs
)
String
()
string
{
return
fmt
.
Sprintf
(
"AutoUnionFs(%s)"
,
fs
.
root
)
}
func
(
me
*
AutoUnionFs
)
OnMount
(
nodeFs
*
fuse
.
PathNodeFs
)
{
me
.
nodeFs
=
nodeFs
if
me
.
options
.
UpdateOnMount
{
time
.
AfterFunc
(
100
*
time
.
Millisecond
,
func
()
{
me
.
updateKnownFses
()
})
func
(
fs
*
AutoUnionFs
)
OnMount
(
nodeFs
*
fuse
.
PathNodeFs
)
{
fs
.
nodeFs
=
nodeFs
if
fs
.
options
.
UpdateOnMount
{
time
.
AfterFunc
(
100
*
time
.
Millisecond
,
func
()
{
fs
.
updateKnownFses
()
})
}
}
func
(
me
*
AutoUnionFs
)
addAutomaticFs
(
roots
[]
string
)
{
relative
:=
strings
.
TrimLeft
(
strings
.
Replace
(
roots
[
0
],
me
.
root
,
""
,
-
1
),
"/"
)
func
(
fs
*
AutoUnionFs
)
addAutomaticFs
(
roots
[]
string
)
{
relative
:=
strings
.
TrimLeft
(
strings
.
Replace
(
roots
[
0
],
fs
.
root
,
""
,
-
1
),
"/"
)
name
:=
strings
.
Replace
(
relative
,
"/"
,
"-"
,
-
1
)
if
me
.
getUnionFs
(
name
)
==
nil
{
me
.
addFs
(
name
,
roots
)
if
fs
.
getUnionFs
(
name
)
==
nil
{
fs
.
addFs
(
name
,
roots
)
}
}
func
(
me
*
AutoUnionFs
)
createFs
(
name
string
,
roots
[]
string
)
fuse
.
Status
{
me
.
lock
.
Lock
()
defer
me
.
lock
.
Unlock
()
func
(
fs
*
AutoUnionFs
)
createFs
(
name
string
,
roots
[]
string
)
fuse
.
Status
{
fs
.
lock
.
Lock
()
defer
fs
.
lock
.
Unlock
()
for
workspace
,
root
:=
range
me
.
nameRootMap
{
for
workspace
,
root
:=
range
fs
.
nameRootMap
{
if
root
==
roots
[
0
]
&&
workspace
!=
name
{
log
.
Printf
(
"Already have a union FS for directory %s in workspace %s"
,
roots
[
0
],
workspace
)
...
...
@@ -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
{
log
.
Println
(
"Already have a workspace:"
,
name
)
return
fuse
.
EBUSY
}
ufs
,
err
:=
NewUnionFsFromRoots
(
roots
,
&
me
.
options
.
UnionFsOptions
,
true
)
ufs
,
err
:=
NewUnionFsFromRoots
(
roots
,
&
fs
.
options
.
UnionFsOptions
,
true
)
if
err
!=
nil
{
log
.
Println
(
"Could not create UnionFs:"
,
err
)
return
fuse
.
EPERM
}
log
.
Printf
(
"Adding workspace %v for roots %v"
,
name
,
ufs
.
String
())
nfs
:=
fuse
.
NewPathNodeFs
(
ufs
,
&
me
.
options
.
PathNodeFsOptions
)
code
:=
me
.
nodeFs
.
Mount
(
name
,
nfs
,
&
me
.
options
.
FileSystemOptions
)
nfs
:=
fuse
.
NewPathNodeFs
(
ufs
,
&
fs
.
options
.
PathNodeFsOptions
)
code
:=
fs
.
nodeFs
.
Mount
(
name
,
nfs
,
&
fs
.
options
.
FileSystemOptions
)
if
code
.
Ok
()
{
me
.
knownFileSystems
[
name
]
=
knownFs
{
fs
.
knownFileSystems
[
name
]
=
knownFs
{
ufs
,
nfs
,
}
me
.
nameRootMap
[
name
]
=
roots
[
0
]
fs
.
nameRootMap
[
name
]
=
roots
[
0
]
}
return
code
}
func
(
me
*
AutoUnionFs
)
rmFs
(
name
string
)
(
code
fuse
.
Status
)
{
me
.
lock
.
Lock
()
defer
me
.
lock
.
Unlock
()
func
(
fs
*
AutoUnionFs
)
rmFs
(
name
string
)
(
code
fuse
.
Status
)
{
fs
.
lock
.
Lock
()
defer
fs
.
lock
.
Unlock
()
known
:=
me
.
knownFileSystems
[
name
]
known
:=
fs
.
knownFileSystems
[
name
]
if
known
.
UnionFs
==
nil
{
return
fuse
.
ENOENT
}
code
=
me
.
nodeFs
.
Unmount
(
name
)
code
=
fs
.
nodeFs
.
Unmount
(
name
)
if
code
.
Ok
()
{
delete
(
me
.
knownFileSystems
,
name
)
delete
(
me
.
nameRootMap
,
name
)
delete
(
fs
.
knownFileSystems
,
name
)
delete
(
fs
.
nameRootMap
,
name
)
}
else
{
log
.
Printf
(
"Unmount failed for %s. Code %v"
,
name
,
code
)
}
...
...
@@ -153,15 +153,15 @@ func (me *AutoUnionFs) rmFs(name string) (code fuse.Status) {
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
{
log
.
Println
(
"Illegal name for overlay"
,
roots
)
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
)
fi
,
err
:=
os
.
Lstat
(
ro
)
fiDir
,
errDir
:=
os
.
Stat
(
ro
)
...
...
@@ -177,30 +177,30 @@ func (me *AutoUnionFs) getRoots(path string) []string {
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
()
{
roots
:=
me
.
getRoots
(
path
)
roots
:=
fs
.
getRoots
(
path
)
if
roots
!=
nil
{
me
.
addAutomaticFs
(
roots
)
fs
.
addAutomaticFs
(
roots
)
}
}
return
nil
}
func
(
me
*
AutoUnionFs
)
updateKnownFses
()
{
func
(
fs
*
AutoUnionFs
)
updateKnownFses
()
{
log
.
Println
(
"Looking for new filesystems"
)
// We unroll the first level of entries in the root manually in order
// to allow symbolic links on that level.
directoryEntries
,
err
:=
ioutil
.
ReadDir
(
me
.
root
)
directoryEntries
,
err
:=
ioutil
.
ReadDir
(
fs
.
root
)
if
err
==
nil
{
for
_
,
dir
:=
range
directoryEntries
{
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
)
me
.
visit
(
path
,
dir
,
nil
)
fs
.
visit
(
path
,
dir
,
nil
)
filepath
.
Walk
(
path
,
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() {
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
))
if
comps
[
0
]
==
_STATUS
&&
comps
[
1
]
==
_ROOT
{
return
me
.
root
,
fuse
.
OK
return
fs
.
root
,
fuse
.
OK
}
if
comps
[
0
]
!=
_CONFIG
{
return
""
,
fuse
.
ENOENT
}
name
:=
comps
[
1
]
me
.
lock
.
RLock
()
defer
me
.
lock
.
RUnlock
()
fs
.
lock
.
RLock
()
defer
fs
.
lock
.
RUnlock
()
root
,
ok
:=
me
.
nameRootMap
[
name
]
root
,
ok
:=
fs
.
nameRootMap
[
name
]
if
ok
{
return
root
,
fuse
.
OK
}
return
""
,
fuse
.
ENOENT
}
func
(
me
*
AutoUnionFs
)
getUnionFs
(
name
string
)
*
UnionFs
{
me
.
lock
.
RLock
()
defer
me
.
lock
.
RUnlock
()
return
me
.
knownFileSystems
[
name
]
.
UnionFs
func
(
fs
*
AutoUnionFs
)
getUnionFs
(
name
string
)
*
UnionFs
{
fs
.
lock
.
RLock
()
defer
fs
.
lock
.
RUnlock
()
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
,
"/"
)
if
len
(
comps
)
!=
2
{
return
fuse
.
EPERM
}
if
comps
[
0
]
==
_CONFIG
{
roots
:=
me
.
getRoots
(
pointedTo
)
roots
:=
fs
.
getRoots
(
pointedTo
)
if
roots
==
nil
{
return
fuse
.
Status
(
syscall
.
ENOTDIR
)
}
name
:=
comps
[
1
]
return
me
.
addFs
(
name
,
roots
)
return
fs
.
addFs
(
name
,
roots
)
}
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
,
"/"
)
if
len
(
comps
)
!=
2
{
return
fuse
.
EPERM
}
if
comps
[
0
]
==
_CONFIG
&&
comps
[
1
]
!=
_SCAN_CONFIG
{
code
=
me
.
rmFs
(
comps
[
1
])
code
=
fs
.
rmFs
(
comps
[
1
])
}
else
{
code
=
fuse
.
ENOENT
}
...
...
@@ -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.
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
}
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
{
a
:=
&
fuse
.
Attr
{
Mode
:
fuse
.
S_IFDIR
|
0755
,
...
...
@@ -290,7 +290,7 @@ func (me *AutoUnionFs) GetAttr(path string, context *fuse.Context) (*fuse.Attr,
if
path
==
filepath
.
Join
(
_STATUS
,
_DEBUG
)
{
a
:=
&
fuse
.
Attr
{
Mode
:
fuse
.
S_IFREG
|
0644
,
Size
:
uint64
(
len
(
me
.
DebugData
())),
Size
:
uint64
(
len
(
fs
.
DebugData
())),
}
return
a
,
fuse
.
OK
}
...
...
@@ -311,7 +311,7 @@ func (me *AutoUnionFs) GetAttr(path string, context *fuse.Context) (*fuse.Attr,
comps
:=
strings
.
Split
(
path
,
string
(
filepath
.
Separator
))
if
len
(
comps
)
>
1
&&
comps
[
0
]
==
_CONFIG
{
fs
:=
me
.
getUnionFs
(
comps
[
1
])
fs
:=
fs
.
getUnionFs
(
comps
[
1
])
if
fs
==
nil
{
return
nil
,
fuse
.
ENOENT
...
...
@@ -326,7 +326,7 @@ func (me *AutoUnionFs) GetAttr(path string, context *fuse.Context) (*fuse.Attr,
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
<-
fuse
.
DirEntry
{
Name
:
_VERSION
,
...
...
@@ -347,51 +347,51 @@ func (me *AutoUnionFs) StatusDir() (stream chan fuse.DirEntry, status fuse.Statu
// SetMountState stores the MountState, which is necessary for
// retrieving debug data.
func
(
me
*
AutoUnionFs
)
SetMountState
(
state
*
fuse
.
MountState
)
{
me
.
mountState
=
state
func
(
fs
*
AutoUnionFs
)
SetMountState
(
state
*
fuse
.
MountState
)
{
fs
.
mountState
=
state
}
func
(
me
*
AutoUnionFs
)
SetFileSystemConnector
(
conn
*
fuse
.
FileSystemConnector
)
{
me
.
connector
=
conn
func
(
fs
*
AutoUnionFs
)
SetFileSystemConnector
(
conn
*
fuse
.
FileSystemConnector
)
{
fs
.
connector
=
conn
}
func
(
me
*
AutoUnionFs
)
DebugData
()
string
{
if
me
.
mountState
==
nil
{
func
(
fs
*
AutoUnionFs
)
DebugData
()
string
{
if
fs
.
mountState
==
nil
{
return
"AutoUnionFs.mountState not set"
}
setting
:=
me
.
mountState
.
KernelSettings
()
setting
:=
fs
.
mountState
.
KernelSettings
()
msg
:=
fmt
.
Sprintf
(
"Version: %v
\n
"
+
"Bufferpool: %v
\n
"
+
"Kernel: %v
\n
"
,
fuse
.
Version
(),
me
.
mountState
.
BufferPoolStats
(),
fs
.
mountState
.
BufferPoolStats
(),
&
setting
)
lat
:=
me
.
mountState
.
Latencies
()
lat
:=
fs
.
mountState
.
Latencies
()
if
len
(
lat
)
>
0
{
msg
+=
fmt
.
Sprintf
(
"Latencies: %v
\n
"
,
lat
)
}
counts
:=
me
.
mountState
.
OperationCounts
()
counts
:=
fs
.
mountState
.
OperationCounts
()
if
len
(
counts
)
>
0
{
msg
+=
fmt
.
Sprintf
(
"Op counts: %v
\n
"
,
counts
)
}
if
me
.
connector
!=
nil
{
msg
+=
fmt
.
Sprintf
(
"Live inodes: %d
\n
"
,
me
.
connector
.
InodeHandleCount
())
if
fs
.
connector
!=
nil
{
msg
+=
fmt
.
Sprintf
(
"Live inodes: %d
\n
"
,
fs
.
connector
.
InodeHandleCount
())
}
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
flags
&
fuse
.
O_ANYWRITE
!=
0
{
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
flags
&
fuse
.
O_ANYWRITE
!=
0
{
...
...
@@ -401,14 +401,14 @@ func (me *AutoUnionFs) Open(path string, flags uint32, context *fuse.Context) (f
}
if
path
==
filepath
.
Join
(
_CONFIG
,
_SCAN_CONFIG
)
{
if
flags
&
fuse
.
O_ANYWRITE
!=
0
{
me
.
updateKnownFses
()
fs
.
updateKnownFses
()
}
return
fuse
.
NewDevNullFile
(),
fuse
.
OK
}
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
)
{
log
.
Println
(
"Huh? Truncating unsupported write file"
,
name
)
return
fuse
.
EPERM
...
...
@@ -416,10 +416,10 @@ func (me *AutoUnionFs) Truncate(name string, offset uint64, context *fuse.Contex
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
{
case
_STATUS
:
return
me
.
StatusDir
()
return
fs
.
StatusDir
()
case
_CONFIG
:
case
"/"
:
name
=
""
...
...
@@ -429,12 +429,12 @@ func (me *AutoUnionFs) OpenDir(name string, context *fuse.Context) (stream chan
return
nil
,
fuse
.
ENOSYS
}
me
.
lock
.
RLock
()
defer
me
.
lock
.
RUnlock
()
fs
.
lock
.
RLock
()
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
{
for
k
:=
range
me
.
knownFileSystems
{
for
k
:=
range
fs
.
knownFileSystems
{
stream
<-
fuse
.
DirEntry
{
Name
:
k
,
Mode
:
syscall
.
S_IFLNK
|
0644
,
...
...
@@ -456,6 +456,6 @@ func (me *AutoUnionFs) OpenDir(name string, context *fuse.Context) (stream chan
return
stream
,
status
}
func
(
me
*
AutoUnionFs
)
StatFs
(
name
string
)
*
fuse
.
StatfsOut
{
func
(
fs
*
AutoUnionFs
)
StatFs
(
name
string
)
*
fuse
.
StatfsOut
{
return
&
fuse
.
StatfsOut
{}
}
unionfs/cachingfs.go
View file @
5514ae72
...
...
@@ -107,36 +107,36 @@ func NewCachingFileSystem(fs fuse.FileSystem, ttl time.Duration) *CachingFileSys
return
c
}
func
(
me
*
CachingFileSystem
)
DropCache
()
{
for
_
,
c
:=
range
[]
*
TimedCache
{
me
.
attributes
,
me
.
dirs
,
me
.
links
,
me
.
xattr
}
{
func
(
fs
*
CachingFileSystem
)
DropCache
()
{
for
_
,
c
:=
range
[]
*
TimedCache
{
fs
.
attributes
,
fs
.
dirs
,
fs
.
links
,
fs
.
xattr
}
{
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
{
return
&
fuse
.
Attr
{
Mode
:
fuse
.
S_IFREG
|
0777
,
},
fuse
.
OK
}
r
:=
me
.
attributes
.
Get
(
name
)
.
(
*
attrResponse
)
r
:=
fs
.
attributes
.
Get
(
name
)
.
(
*
attrResponse
)
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
r
:=
me
.
xattr
.
Get
(
key
)
.
(
*
xattrResponse
)
r
:=
fs
.
xattr
.
Get
(
key
)
.
(
*
xattrResponse
)
return
r
.
data
,
r
.
Status
}
func
(
me
*
CachingFileSystem
)
Readlink
(
name
string
,
context
*
fuse
.
Context
)
(
string
,
fuse
.
Status
)
{
r
:=
me
.
links
.
Get
(
name
)
.
(
*
linkResponse
)
func
(
fs
*
CachingFileSystem
)
Readlink
(
name
string
,
context
*
fuse
.
Context
)
(
string
,
fuse
.
Status
)
{
r
:=
fs
.
links
.
Get
(
name
)
.
(
*
linkResponse
)
return
r
.
linkContent
,
r
.
Status
}
func
(
me
*
CachingFileSystem
)
OpenDir
(
name
string
,
context
*
fuse
.
Context
)
(
stream
chan
fuse
.
DirEntry
,
status
fuse
.
Status
)
{
r
:=
me
.
dirs
.
Get
(
name
)
.
(
*
dirResponse
)
func
(
fs
*
CachingFileSystem
)
OpenDir
(
name
string
,
context
*
fuse
.
Context
)
(
stream
chan
fuse
.
DirEntry
,
status
fuse
.
Status
)
{
r
:=
fs
.
dirs
.
Get
(
name
)
.
(
*
dirResponse
)
if
r
.
Status
.
Ok
()
{
stream
=
make
(
chan
fuse
.
DirEntry
,
len
(
r
.
entries
))
for
_
,
d
:=
range
r
.
entries
{
...
...
@@ -149,14 +149,14 @@ func (me *CachingFileSystem) OpenDir(name string, context *fuse.Context) (stream
return
nil
,
r
.
Status
}
func
(
me
*
CachingFileSystem
)
String
()
string
{
return
fmt
.
Sprintf
(
"CachingFileSystem(%v)"
,
me
.
FileSystem
)
func
(
fs
*
CachingFileSystem
)
String
()
string
{
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
{
log
.
Println
(
"Dropping cache for"
,
me
)
me
.
DropCache
()
log
.
Println
(
"Dropping cache for"
,
fs
)
fs
.
DropCache
()
}
return
me
.
FileSystem
.
Open
(
name
,
flags
,
context
)
return
fs
.
FileSystem
.
Open
(
name
,
flags
,
context
)
}
unionfs/dircache.go
View file @
5514ae72
...
...
@@ -42,57 +42,57 @@ type DirCache struct {
updateRunning
bool
}
func
(
me
*
DirCache
)
setMap
(
newMap
map
[
string
]
bool
)
{
me
.
lock
.
Lock
()
defer
me
.
lock
.
Unlock
()
me
.
names
=
newMap
me
.
updateRunning
=
false
_
=
time
.
AfterFunc
(
me
.
ttl
,
func
()
{
me
.
DropCache
()
})
func
(
c
*
DirCache
)
setMap
(
newMap
map
[
string
]
bool
)
{
c
.
lock
.
Lock
()
defer
c
.
lock
.
Unlock
()
c
.
names
=
newMap
c
.
updateRunning
=
false
_
=
time
.
AfterFunc
(
c
.
ttl
,
func
()
{
c
.
DropCache
()
})
}
func
(
me
*
DirCache
)
DropCache
()
{
me
.
lock
.
Lock
()
defer
me
.
lock
.
Unlock
()
me
.
names
=
nil
func
(
c
*
DirCache
)
DropCache
()
{
c
.
lock
.
Lock
()
defer
c
.
lock
.
Unlock
()
c
.
names
=
nil
}
// Try to refresh: if another update is already running, do nothing,
// otherwise, read the directory and set it.
func
(
me
*
DirCache
)
maybeRefresh
()
{
me
.
lock
.
Lock
()
defer
me
.
lock
.
Unlock
()
if
me
.
updateRunning
{
func
(
c
*
DirCache
)
maybeRefresh
()
{
c
.
lock
.
Lock
()
defer
c
.
lock
.
Unlock
()
if
c
.
updateRunning
{
return
}
me
.
updateRunning
=
true
c
.
updateRunning
=
true
go
func
()
{
newmap
:=
newDirnameMap
(
me
.
fs
,
me
.
dir
)
me
.
setMap
(
newmap
)
newmap
:=
newDirnameMap
(
c
.
fs
,
c
.
dir
)
c
.
setMap
(
newmap
)
}()
}
func
(
me
*
DirCache
)
RemoveEntry
(
name
string
)
{
me
.
lock
.
Lock
()
defer
me
.
lock
.
Unlock
()
if
me
.
names
==
nil
{
go
me
.
maybeRefresh
()
func
(
c
*
DirCache
)
RemoveEntry
(
name
string
)
{
c
.
lock
.
Lock
()
defer
c
.
lock
.
Unlock
()
if
c
.
names
==
nil
{
go
c
.
maybeRefresh
()
return
}
delete
(
me
.
names
,
name
)
delete
(
c
.
names
,
name
)
}
func
(
me
*
DirCache
)
AddEntry
(
name
string
)
{
me
.
lock
.
Lock
()
defer
me
.
lock
.
Unlock
()
if
me
.
names
==
nil
{
go
me
.
maybeRefresh
()
func
(
c
*
DirCache
)
AddEntry
(
name
string
)
{
c
.
lock
.
Lock
()
defer
c
.
lock
.
Unlock
()
if
c
.
names
==
nil
{
go
c
.
maybeRefresh
()
return
}
me
.
names
[
name
]
=
true
c
.
names
[
name
]
=
true
}
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
}
func
(
me
*
DirCache
)
HasEntry
(
name
string
)
(
mapPresent
bool
,
found
bool
)
{
me
.
lock
.
RLock
()
defer
me
.
lock
.
RUnlock
()
func
(
c
*
DirCache
)
HasEntry
(
name
string
)
(
mapPresent
bool
,
found
bool
)
{
c
.
lock
.
RLock
()
defer
c
.
lock
.
RUnlock
()
if
me
.
names
==
nil
{
go
me
.
maybeRefresh
()
if
c
.
names
==
nil
{
go
c
.
maybeRefresh
()
return
false
,
false
}
return
true
,
me
.
names
[
name
]
return
true
,
c
.
names
[
name
]
}
unionfs/timedcache.go
View file @
5514ae72
...
...
@@ -42,79 +42,79 @@ func NewTimedCache(fetcher TimedCacheFetcher, ttl time.Duration) *TimedCache {
return
l
}
func
(
me
*
TimedCache
)
Get
(
name
string
)
interface
{}
{
me
.
cacheMapMutex
.
RLock
()
info
,
ok
:=
me
.
cacheMap
[
name
]
me
.
cacheMapMutex
.
RUnlock
()
func
(
c
*
TimedCache
)
Get
(
name
string
)
interface
{}
{
c
.
cacheMapMutex
.
RLock
()
info
,
ok
:=
c
.
cacheMap
[
name
]
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
{
return
info
.
data
}
return
me
.
GetFresh
(
name
)
return
c
.
GetFresh
(
name
)
}
func
(
me
*
TimedCache
)
Set
(
name
string
,
val
interface
{})
{
me
.
cacheMapMutex
.
Lock
()
defer
me
.
cacheMapMutex
.
Unlock
()
func
(
c
*
TimedCache
)
Set
(
name
string
,
val
interface
{})
{
c
.
cacheMapMutex
.
Lock
()
defer
c
.
cacheMapMutex
.
Unlock
()
me
.
cacheMap
[
name
]
=
&
cacheEntry
{
c
.
cacheMap
[
name
]
=
&
cacheEntry
{
data
:
val
,
expiry
:
time
.
Now
()
.
Add
(
me
.
ttl
),
expiry
:
time
.
Now
()
.
Add
(
c
.
ttl
),
}
}
func
(
me
*
TimedCache
)
DropEntry
(
name
string
)
{
me
.
cacheMapMutex
.
Lock
()
defer
me
.
cacheMapMutex
.
Unlock
()
func
(
c
*
TimedCache
)
DropEntry
(
name
string
)
{
c
.
cacheMapMutex
.
Lock
()
defer
c
.
cacheMapMutex
.
Unlock
()
delete
(
me
.
cacheMap
,
name
)
delete
(
c
.
cacheMap
,
name
)
}
func
(
me
*
TimedCache
)
GetFresh
(
name
string
)
interface
{}
{
data
,
ok
:=
me
.
fetch
(
name
)
func
(
c
*
TimedCache
)
GetFresh
(
name
string
)
interface
{}
{
data
,
ok
:=
c
.
fetch
(
name
)
if
ok
{
me
.
Set
(
name
,
data
)
c
.
Set
(
name
,
data
)
}
return
data
}
// Drop all expired entries.
func
(
me
*
TimedCache
)
Purge
()
{
keys
:=
make
([]
string
,
0
,
len
(
me
.
cacheMap
))
func
(
c
*
TimedCache
)
Purge
()
{
keys
:=
make
([]
string
,
0
,
len
(
c
.
cacheMap
))
now
:=
time
.
Now
()
me
.
cacheMapMutex
.
Lock
()
defer
me
.
cacheMapMutex
.
Unlock
()
for
k
,
v
:=
range
me
.
cacheMap
{
c
.
cacheMapMutex
.
Lock
()
defer
c
.
cacheMapMutex
.
Unlock
()
for
k
,
v
:=
range
c
.
cacheMap
{
if
now
.
After
(
v
.
expiry
)
{
keys
=
append
(
keys
,
k
)
}
}
for
_
,
k
:=
range
keys
{
delete
(
me
.
cacheMap
,
k
)
delete
(
c
.
cacheMap
,
k
)
}
}
func
(
me
*
TimedCache
)
RecurringPurge
()
{
if
me
.
ttl
<=
0
{
func
(
c
*
TimedCache
)
RecurringPurge
()
{
if
c
.
ttl
<=
0
{
return
}
me
.
Purge
()
me
.
PurgeTimer
=
time
.
AfterFunc
(
me
.
ttl
*
5
,
func
()
{
me
.
RecurringPurge
()
})
c
.
Purge
()
c
.
PurgeTimer
=
time
.
AfterFunc
(
c
.
ttl
*
5
,
func
()
{
c
.
RecurringPurge
()
})
}
func
(
me
*
TimedCache
)
DropAll
(
names
[]
string
)
{
me
.
cacheMapMutex
.
Lock
()
defer
me
.
cacheMapMutex
.
Unlock
()
func
(
c
*
TimedCache
)
DropAll
(
names
[]
string
)
{
c
.
cacheMapMutex
.
Lock
()
defer
c
.
cacheMapMutex
.
Unlock
()
if
names
==
nil
{
me
.
cacheMap
=
make
(
map
[
string
]
*
cacheEntry
,
len
(
me
.
cacheMap
))
c
.
cacheMap
=
make
(
map
[
string
]
*
cacheEntry
,
len
(
c
.
cacheMap
))
}
else
{
for
_
,
nm
:=
range
names
{
delete
(
me
.
cacheMap
,
nm
)
delete
(
c
.
cacheMap
,
nm
)
}
}
}
unionfs/unionfs.go
View file @
5514ae72
...
...
@@ -110,8 +110,8 @@ func NewUnionFs(fileSystems []fuse.FileSystem, options UnionFsOptions) *UnionFs
return
g
}
func
(
me
*
UnionFs
)
OnMount
(
nodeFs
*
fuse
.
PathNodeFs
)
{
me
.
nodeFs
=
nodeFs
func
(
fs
*
UnionFs
)
OnMount
(
nodeFs
*
fuse
.
PathNodeFs
)
{
fs
.
nodeFs
=
nodeFs
}
////////////////
...
...
@@ -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.
// It may return an error code if the store could not be accessed.
func
(
me
*
UnionFs
)
isDeleted
(
name
string
)
(
deleted
bool
,
code
fuse
.
Status
)
{
marker
:=
me
.
deletionPath
(
name
)
haveCache
,
found
:=
me
.
deletionCache
.
HasEntry
(
filepath
.
Base
(
marker
))
func
(
fs
*
UnionFs
)
isDeleted
(
name
string
)
(
deleted
bool
,
code
fuse
.
Status
)
{
marker
:=
fs
.
deletionPath
(
name
)
haveCache
,
found
:=
fs
.
deletionCache
.
HasEntry
(
filepath
.
Base
(
marker
))
if
haveCache
{
return
found
,
fuse
.
OK
}
_
,
code
=
me
.
fileSystems
[
0
]
.
GetAttr
(
marker
,
nil
)
_
,
code
=
fs
.
fileSystems
[
0
]
.
GetAttr
(
marker
,
nil
)
if
code
==
fuse
.
OK
{
return
true
,
code
...
...
@@ -139,13 +139,13 @@ func (me *UnionFs) isDeleted(name string) (deleted bool, code fuse.Status) {
return
false
,
fuse
.
Status
(
syscall
.
EROFS
)
}
func
(
me
*
UnionFs
)
createDeletionStore
()
(
code
fuse
.
Status
)
{
writable
:=
me
.
fileSystems
[
0
]
fi
,
code
:=
writable
.
GetAttr
(
me
.
options
.
DeletionDirName
,
nil
)
func
(
fs
*
UnionFs
)
createDeletionStore
()
(
code
fuse
.
Status
)
{
writable
:=
fs
.
fileSystems
[
0
]
fi
,
code
:=
writable
.
GetAttr
(
fs
.
options
.
DeletionDirName
,
nil
)
if
code
==
fuse
.
ENOENT
{
code
=
writable
.
Mkdir
(
me
.
options
.
DeletionDirName
,
0755
,
nil
)
code
=
writable
.
Mkdir
(
fs
.
options
.
DeletionDirName
,
0755
,
nil
)
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) {
return
code
}
func
(
me
*
UnionFs
)
getBranch
(
name
string
)
branchResult
{
func
(
fs
*
UnionFs
)
getBranch
(
name
string
)
branchResult
{
name
=
stripSlash
(
name
)
r
:=
me
.
branchCache
.
Get
(
name
)
r
:=
fs
.
branchCache
.
Get
(
name
)
return
r
.
(
branchResult
)
}
...
...
@@ -168,11 +168,11 @@ type branchResult struct {
branch
int
}
func
(
me
branchResult
)
String
()
string
{
return
fmt
.
Sprintf
(
"{%v %v branch %d}"
,
me
.
attr
,
me
.
code
,
me
.
branch
)
func
(
fs
branchResult
)
String
()
string
{
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
)
parent
,
base
:=
path
.
Split
(
name
)
...
...
@@ -180,9 +180,9 @@ func (me *UnionFs) getBranchAttrNoCache(name string) branchResult {
parentBranch
:=
0
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
{
continue
}
...
...
@@ -210,35 +210,35 @@ func (me *UnionFs) getBranchAttrNoCache(name string) branchResult {
////////////////
// Deletion.
func
(
me
*
UnionFs
)
deletionPath
(
name
string
)
string
{
return
filepath
.
Join
(
me
.
options
.
DeletionDirName
,
filePathHash
(
name
))
func
(
fs
*
UnionFs
)
deletionPath
(
name
string
)
string
{
return
filepath
.
Join
(
fs
.
options
.
DeletionDirName
,
filePathHash
(
name
))
}
func
(
me
*
UnionFs
)
removeDeletion
(
name
string
)
{
marker
:=
me
.
deletionPath
(
name
)
me
.
deletionCache
.
RemoveEntry
(
path
.
Base
(
marker
))
func
(
fs
*
UnionFs
)
removeDeletion
(
name
string
)
{
marker
:=
fs
.
deletionPath
(
name
)
fs
.
deletionCache
.
RemoveEntry
(
path
.
Base
(
marker
))
// os.Remove tries to be smart and issues a Remove() and
// Rmdir() sequentially. We want to skip the 2nd system call,
// 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
{
log
.
Printf
(
"error unlinking %s: %v"
,
marker
,
code
)
}
}
func
(
me
*
UnionFs
)
putDeletion
(
name
string
)
(
code
fuse
.
Status
)
{
code
=
me
.
createDeletionStore
()
func
(
fs
*
UnionFs
)
putDeletion
(
name
string
)
(
code
fuse
.
Status
)
{
code
=
fs
.
createDeletionStore
()
if
!
code
.
Ok
()
{
return
code
}
marker
:=
me
.
deletionPath
(
name
)
me
.
deletionCache
.
AddEntry
(
path
.
Base
(
marker
))
marker
:=
fs
.
deletionPath
(
name
)
fs
.
deletionCache
.
AddEntry
(
path
.
Base
(
marker
))
// Is there a WriteStringToFileOrDie ?
writable
:=
me
.
fileSystems
[
0
]
writable
:=
fs
.
fileSystems
[
0
]
fi
,
code
:=
writable
.
GetAttr
(
marker
,
nil
)
if
code
.
Ok
()
&&
fi
.
Size
==
uint64
(
len
(
name
))
{
return
fuse
.
OK
...
...
@@ -268,12 +268,12 @@ func (me *UnionFs) putDeletion(name string) (code fuse.Status) {
////////////////
// Promotion.
func
(
me
*
UnionFs
)
Promote
(
name
string
,
srcResult
branchResult
,
context
*
fuse
.
Context
)
(
code
fuse
.
Status
)
{
writable
:=
me
.
fileSystems
[
0
]
sourceFs
:=
me
.
fileSystems
[
srcResult
.
branch
]
func
(
fs
*
UnionFs
)
Promote
(
name
string
,
srcResult
branchResult
,
context
*
fuse
.
Context
)
(
code
fuse
.
Status
)
{
writable
:=
fs
.
fileSystems
[
0
]
sourceFs
:=
fs
.
fileSystems
[
srcResult
.
branch
]
// Promote directories.
me
.
promoteDirsTo
(
name
)
fs
.
promoteDirsTo
(
name
)
if
srcResult
.
attr
.
IsRegular
()
{
code
=
fuse
.
CopyFile
(
sourceFs
,
writable
,
name
,
name
,
context
)
...
...
@@ -286,7 +286,7 @@ func (me *UnionFs) Promote(name string, srcResult branchResult, context *fuse.Co
srcResult
.
attr
.
Mtimens
(),
context
)
}
files
:=
me
.
nodeFs
.
AllFiles
(
name
,
0
)
files
:=
fs
.
nodeFs
.
AllFiles
(
name
,
0
)
for
_
,
fileWrapper
:=
range
files
{
if
!
code
.
Ok
()
{
break
...
...
@@ -308,7 +308,7 @@ func (me *UnionFs) Promote(name string, srcResult branchResult, context *fuse.Co
if
uf
.
layer
>
0
{
uf
.
layer
=
0
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
.
Release
()
}
...
...
@@ -329,12 +329,12 @@ func (me *UnionFs) Promote(name string, srcResult branchResult, context *fuse.Co
}
if
!
code
.
Ok
()
{
me
.
branchCache
.
GetFresh
(
name
)
fs
.
branchCache
.
GetFresh
(
name
)
return
code
}
else
{
r
:=
me
.
getBranch
(
name
)
r
:=
fs
.
getBranch
(
name
)
r
.
branch
=
0
me
.
branchCache
.
Set
(
name
,
r
)
fs
.
branchCache
.
Set
(
name
,
r
)
}
return
fuse
.
OK
...
...
@@ -343,11 +343,11 @@ func (me *UnionFs) Promote(name string, srcResult branchResult, context *fuse.Co
////////////////////////////////////////////////////////////////
// Below: implement interface for a FileSystem.
func
(
me
*
UnionFs
)
Link
(
orig
string
,
newName
string
,
context
*
fuse
.
Context
)
(
code
fuse
.
Status
)
{
origResult
:=
me
.
getBranch
(
orig
)
func
(
fs
*
UnionFs
)
Link
(
orig
string
,
newName
string
,
context
*
fuse
.
Context
)
(
code
fuse
.
Status
)
{
origResult
:=
fs
.
getBranch
(
orig
)
code
=
origResult
.
code
if
code
.
Ok
()
&&
origResult
.
branch
>
0
{
code
=
me
.
Promote
(
orig
,
origResult
,
context
)
code
=
fs
.
Promote
(
orig
,
origResult
,
context
)
}
if
code
.
Ok
()
&&
origResult
.
branch
>
0
{
// 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
// original. We force a refresh of the attribute (so
// the Ino is filled in.), and then force PathNodeFs
// to see the Inode number.
me
.
branchCache
.
GetFresh
(
orig
)
inode
:=
me
.
nodeFs
.
Node
(
orig
)
fs
.
branchCache
.
GetFresh
(
orig
)
inode
:=
fs
.
nodeFs
.
Node
(
orig
)
inode
.
FsNode
()
.
GetAttr
(
nil
,
nil
)
}
if
code
.
Ok
()
{
code
=
me
.
promoteDirsTo
(
newName
)
code
=
fs
.
promoteDirsTo
(
newName
)
}
if
code
.
Ok
()
{
code
=
me
.
fileSystems
[
0
]
.
Link
(
orig
,
newName
,
context
)
code
=
fs
.
fileSystems
[
0
]
.
Link
(
orig
,
newName
,
context
)
}
if
code
.
Ok
()
{
me
.
removeDeletion
(
newName
)
me
.
branchCache
.
GetFresh
(
newName
)
fs
.
removeDeletion
(
newName
)
fs
.
branchCache
.
GetFresh
(
newName
)
}
return
code
}
func
(
me
*
UnionFs
)
Rmdir
(
path
string
,
context
*
fuse
.
Context
)
(
code
fuse
.
Status
)
{
r
:=
me
.
getBranch
(
path
)
func
(
fs
*
UnionFs
)
Rmdir
(
path
string
,
context
*
fuse
.
Context
)
(
code
fuse
.
Status
)
{
r
:=
fs
.
getBranch
(
path
)
if
r
.
code
!=
fuse
.
OK
{
return
r
.
code
}
...
...
@@ -381,7 +381,7 @@ func (me *UnionFs) Rmdir(path string, context *fuse.Context) (code fuse.Status)
return
fuse
.
Status
(
syscall
.
ENOTDIR
)
}
stream
,
code
:=
me
.
OpenDir
(
path
,
context
)
stream
,
code
:=
fs
.
OpenDir
(
path
,
context
)
found
:=
false
for
_
=
range
stream
{
found
=
true
...
...
@@ -391,115 +391,115 @@ func (me *UnionFs) Rmdir(path string, context *fuse.Context) (code fuse.Status)
}
if
r
.
branch
>
0
{
code
=
me
.
putDeletion
(
path
)
code
=
fs
.
putDeletion
(
path
)
return
code
}
code
=
me
.
fileSystems
[
0
]
.
Rmdir
(
path
,
context
)
code
=
fs
.
fileSystems
[
0
]
.
Rmdir
(
path
,
context
)
if
code
!=
fuse
.
OK
{
return
code
}
r
=
me
.
branchCache
.
GetFresh
(
path
)
.
(
branchResult
)
r
=
fs
.
branchCache
.
GetFresh
(
path
)
.
(
branchResult
)
if
r
.
branch
>
0
{
code
=
me
.
putDeletion
(
path
)
code
=
fs
.
putDeletion
(
path
)
}
return
code
}
func
(
me
*
UnionFs
)
Mkdir
(
path
string
,
mode
uint32
,
context
*
fuse
.
Context
)
(
code
fuse
.
Status
)
{
deleted
,
code
:=
me
.
isDeleted
(
path
)
func
(
fs
*
UnionFs
)
Mkdir
(
path
string
,
mode
uint32
,
context
*
fuse
.
Context
)
(
code
fuse
.
Status
)
{
deleted
,
code
:=
fs
.
isDeleted
(
path
)
if
!
code
.
Ok
()
{
return
code
}
if
!
deleted
{
r
:=
me
.
getBranch
(
path
)
r
:=
fs
.
getBranch
(
path
)
if
r
.
code
!=
fuse
.
ENOENT
{
return
fuse
.
Status
(
syscall
.
EEXIST
)
}
}
code
=
me
.
promoteDirsTo
(
path
)
code
=
fs
.
promoteDirsTo
(
path
)
if
code
.
Ok
()
{
code
=
me
.
fileSystems
[
0
]
.
Mkdir
(
path
,
mode
,
context
)
code
=
fs
.
fileSystems
[
0
]
.
Mkdir
(
path
,
mode
,
context
)
}
if
code
.
Ok
()
{
me
.
removeDeletion
(
path
)
fs
.
removeDeletion
(
path
)
attr
:=
&
fuse
.
Attr
{
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
stream
,
code
=
me
.
OpenDir
(
path
,
context
)
stream
,
code
=
fs
.
OpenDir
(
path
,
context
)
if
code
.
Ok
()
{
// This shouldn't happen, but let's be safe.
for
entry
:=
range
stream
{
me
.
putDeletion
(
filepath
.
Join
(
path
,
entry
.
Name
))
fs
.
putDeletion
(
filepath
.
Join
(
path
,
entry
.
Name
))
}
}
return
code
}
func
(
me
*
UnionFs
)
Symlink
(
pointedTo
string
,
linkName
string
,
context
*
fuse
.
Context
)
(
code
fuse
.
Status
)
{
code
=
me
.
promoteDirsTo
(
linkName
)
func
(
fs
*
UnionFs
)
Symlink
(
pointedTo
string
,
linkName
string
,
context
*
fuse
.
Context
)
(
code
fuse
.
Status
)
{
code
=
fs
.
promoteDirsTo
(
linkName
)
if
code
.
Ok
()
{
code
=
me
.
fileSystems
[
0
]
.
Symlink
(
pointedTo
,
linkName
,
context
)
code
=
fs
.
fileSystems
[
0
]
.
Symlink
(
pointedTo
,
linkName
,
context
)
}
if
code
.
Ok
()
{
me
.
removeDeletion
(
linkName
)
me
.
branchCache
.
GetFresh
(
linkName
)
fs
.
removeDeletion
(
linkName
)
fs
.
branchCache
.
GetFresh
(
linkName
)
}
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
{
return
fuse
.
OK
}
r
:=
me
.
getBranch
(
path
)
r
:=
fs
.
getBranch
(
path
)
if
r
.
branch
>
0
{
code
=
me
.
Promote
(
path
,
r
,
context
)
code
=
fs
.
Promote
(
path
,
r
,
context
)
r
.
branch
=
0
}
if
code
.
Ok
()
{
code
=
me
.
fileSystems
[
0
]
.
Truncate
(
path
,
size
,
context
)
code
=
fs
.
fileSystems
[
0
]
.
Truncate
(
path
,
size
,
context
)
}
if
code
.
Ok
()
{
r
.
attr
.
Size
=
size
now
:=
time
.
Now
()
r
.
attr
.
SetTimes
(
nil
,
&
now
,
&
now
)
me
.
branchCache
.
Set
(
path
,
r
)
fs
.
branchCache
.
Set
(
path
,
r
)
}
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
)
r
:=
me
.
getBranch
(
name
)
r
:=
fs
.
getBranch
(
name
)
code
=
r
.
code
if
code
.
Ok
()
&&
r
.
branch
>
0
{
code
=
me
.
Promote
(
name
,
r
,
context
)
code
=
fs
.
Promote
(
name
,
r
,
context
)
r
.
branch
=
0
}
if
code
.
Ok
()
{
code
=
me
.
fileSystems
[
0
]
.
Utimens
(
name
,
atime
,
mtime
,
context
)
code
=
fs
.
fileSystems
[
0
]
.
Utimens
(
name
,
atime
,
mtime
,
context
)
}
if
code
.
Ok
()
{
r
.
attr
.
SetNs
(
atime
,
mtime
,
time
.
Now
()
.
UnixNano
())
me
.
branchCache
.
Set
(
name
,
r
)
fs
.
branchCache
.
Set
(
name
,
r
)
}
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
)
r
:=
me
.
getBranch
(
name
)
r
:=
fs
.
getBranch
(
name
)
if
r
.
attr
==
nil
||
r
.
code
!=
fuse
.
OK
{
return
r
.
code
}
...
...
@@ -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
.
branch
>
0
{
code
:=
me
.
Promote
(
name
,
r
,
context
)
code
:=
fs
.
Promote
(
name
,
r
,
context
)
if
code
!=
fuse
.
OK
{
return
code
}
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
.
Gid
=
gid
now
:=
time
.
Now
()
r
.
attr
.
SetTimes
(
nil
,
nil
,
&
now
)
me
.
branchCache
.
Set
(
name
,
r
)
fs
.
branchCache
.
Set
(
name
,
r
)
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
)
r
:=
me
.
getBranch
(
name
)
r
:=
fs
.
getBranch
(
name
)
if
r
.
attr
==
nil
{
return
r
.
code
}
...
...
@@ -543,55 +543,55 @@ func (me *UnionFs) Chmod(name string, mode uint32, context *fuse.Context) (code
if
oldMode
!=
mode
{
if
r
.
branch
>
0
{
code
:=
me
.
Promote
(
name
,
r
,
context
)
code
:=
fs
.
Promote
(
name
,
r
,
context
)
if
code
!=
fuse
.
OK
{
return
code
}
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
now
:=
time
.
Now
()
r
.
attr
.
SetTimes
(
nil
,
nil
,
&
now
)
me
.
branchCache
.
Set
(
name
,
r
)
fs
.
branchCache
.
Set
(
name
,
r
)
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.
mode
=
mode
&^
raw
.
W_OK
if
name
==
""
{
return
fuse
.
OK
}
r
:=
me
.
getBranch
(
name
)
r
:=
fs
.
getBranch
(
name
)
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
}
func
(
me
*
UnionFs
)
Unlink
(
name
string
,
context
*
fuse
.
Context
)
(
code
fuse
.
Status
)
{
r
:=
me
.
getBranch
(
name
)
func
(
fs
*
UnionFs
)
Unlink
(
name
string
,
context
*
fuse
.
Context
)
(
code
fuse
.
Status
)
{
r
:=
fs
.
getBranch
(
name
)
if
r
.
branch
==
0
{
code
=
me
.
fileSystems
[
0
]
.
Unlink
(
name
,
context
)
code
=
fs
.
fileSystems
[
0
]
.
Unlink
(
name
,
context
)
if
code
!=
fuse
.
OK
{
return
code
}
r
=
me
.
branchCache
.
GetFresh
(
name
)
.
(
branchResult
)
r
=
fs
.
branchCache
.
GetFresh
(
name
)
.
(
branchResult
)
}
if
r
.
branch
>
0
{
// It would be nice to do the putDeletion async.
code
=
me
.
putDeletion
(
name
)
code
=
fs
.
putDeletion
(
name
)
}
return
code
}
func
(
me
*
UnionFs
)
Readlink
(
name
string
,
context
*
fuse
.
Context
)
(
out
string
,
code
fuse
.
Status
)
{
r
:=
me
.
getBranch
(
name
)
func
(
fs
*
UnionFs
)
Readlink
(
name
string
,
context
*
fuse
.
Context
)
(
out
string
,
code
fuse
.
Status
)
{
r
:=
fs
.
getBranch
(
name
)
if
r
.
branch
>=
0
{
return
me
.
fileSystems
[
r
.
branch
]
.
Readlink
(
name
,
context
)
return
fs
.
fileSystems
[
r
.
branch
]
.
Readlink
(
name
,
context
)
}
return
""
,
fuse
.
ENOENT
}
...
...
@@ -605,14 +605,14 @@ func stripSlash(fn string) string {
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
=
stripSlash
(
dirName
)
var
todo
[]
string
var
results
[]
branchResult
for
dirName
!=
""
{
r
:=
me
.
getBranch
(
dirName
)
r
:=
fs
.
getBranch
(
dirName
)
if
!
r
.
code
.
Ok
()
{
log
.
Println
(
"path component does not exist"
,
filename
,
dirName
)
...
...
@@ -634,43 +634,43 @@ func (me *UnionFs) promoteDirsTo(filename string) fuse.Status {
j
:=
len
(
todo
)
-
i
-
1
d
:=
todo
[
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
{
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
}
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
me
.
branchCache
.
Set
(
d
,
r
)
fs
.
branchCache
.
Set
(
d
,
r
)
}
return
fuse
.
OK
}
func
(
me
*
UnionFs
)
Create
(
name
string
,
flags
uint32
,
mode
uint32
,
context
*
fuse
.
Context
)
(
fuseFile
fuse
.
File
,
code
fuse
.
Status
)
{
writable
:=
me
.
fileSystems
[
0
]
func
(
fs
*
UnionFs
)
Create
(
name
string
,
flags
uint32
,
mode
uint32
,
context
*
fuse
.
Context
)
(
fuseFile
fuse
.
File
,
code
fuse
.
Status
)
{
writable
:=
fs
.
fileSystems
[
0
]
code
=
me
.
promoteDirsTo
(
name
)
code
=
fs
.
promoteDirsTo
(
name
)
if
code
!=
fuse
.
OK
{
return
nil
,
code
}
fuseFile
,
code
=
writable
.
Create
(
name
,
flags
,
mode
,
context
)
if
code
.
Ok
()
{
fuseFile
=
me
.
newUnionFsFile
(
fuseFile
,
0
)
me
.
removeDeletion
(
name
)
fuseFile
=
fs
.
newUnionFsFile
(
fuseFile
,
0
)
fs
.
removeDeletion
(
name
)
now
:=
time
.
Now
()
a
:=
fuse
.
Attr
{
Mode
:
fuse
.
S_IFREG
|
mode
,
}
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
}
func
(
me
*
UnionFs
)
GetAttr
(
name
string
,
context
*
fuse
.
Context
)
(
a
*
fuse
.
Attr
,
s
fuse
.
Status
)
{
_
,
hidden
:=
me
.
hiddenFiles
[
name
]
func
(
fs
*
UnionFs
)
GetAttr
(
name
string
,
context
*
fuse
.
Context
)
(
a
*
fuse
.
Attr
,
s
fuse
.
Status
)
{
_
,
hidden
:=
fs
.
hiddenFiles
[
name
]
if
hidden
{
return
nil
,
fuse
.
ENOENT
}
...
...
@@ -679,10 +679,10 @@ func (me *UnionFs) GetAttr(name string, context *fuse.Context) (a *fuse.Attr, s
Mode
:
fuse
.
S_IFREG
|
0777
,
},
fuse
.
OK
}
if
name
==
me
.
options
.
DeletionDirName
{
if
name
==
fs
.
options
.
DeletionDirName
{
return
nil
,
fuse
.
ENOENT
}
isDel
,
s
:=
me
.
isDeleted
(
name
)
isDel
,
s
:=
fs
.
isDeleted
(
name
)
if
!
s
.
Ok
()
{
return
nil
,
s
}
...
...
@@ -690,7 +690,7 @@ func (me *UnionFs) GetAttr(name string, context *fuse.Context) (a *fuse.Attr, s
if
isDel
{
return
nil
,
fuse
.
ENOENT
}
r
:=
me
.
getBranch
(
name
)
r
:=
fs
.
getBranch
(
name
)
if
r
.
branch
<
0
{
return
nil
,
fuse
.
ENOENT
}
...
...
@@ -700,20 +700,20 @@ func (me *UnionFs) GetAttr(name string, context *fuse.Context) (a *fuse.Attr, s
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
{
return
nil
,
fuse
.
ENODATA
}
r
:=
me
.
getBranch
(
name
)
r
:=
fs
.
getBranch
(
name
)
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
}
func
(
me
*
UnionFs
)
OpenDir
(
directory
string
,
context
*
fuse
.
Context
)
(
stream
chan
fuse
.
DirEntry
,
status
fuse
.
Status
)
{
dirBranch
:=
me
.
getBranch
(
directory
)
func
(
fs
*
UnionFs
)
OpenDir
(
directory
string
,
context
*
fuse
.
Context
)
(
stream
chan
fuse
.
DirEntry
,
status
fuse
.
Status
)
{
dirBranch
:=
fs
.
getBranch
(
directory
)
if
dirBranch
.
branch
<
0
{
return
nil
,
fuse
.
ENOENT
}
...
...
@@ -725,17 +725,17 @@ func (me *UnionFs) OpenDir(directory string, context *fuse.Context) (stream chan
wg
.
Add
(
1
)
go
func
()
{
deletions
=
newDirnameMap
(
me
.
fileSystems
[
0
],
me
.
options
.
DeletionDirName
)
deletions
=
newDirnameMap
(
fs
.
fileSystems
[
0
],
fs
.
options
.
DeletionDirName
)
wg
.
Done
()
}()
entries
:=
make
([]
map
[
string
]
uint32
,
len
(
me
.
fileSystems
))
for
i
:=
range
me
.
fileSystems
{
entries
:=
make
([]
map
[
string
]
uint32
,
len
(
fs
.
fileSystems
))
for
i
:=
range
fs
.
fileSystems
{
entries
[
i
]
=
make
(
map
[
string
]
uint32
)
}
statuses
:=
make
([]
fuse
.
Status
,
len
(
me
.
fileSystems
))
for
i
,
l
:=
range
me
.
fileSystems
{
statuses
:=
make
([]
fuse
.
Status
,
len
(
fs
.
fileSystems
))
for
i
,
l
:=
range
fs
.
fileSystems
{
if
i
>=
dirBranch
.
branch
{
wg
.
Add
(
1
)
go
func
(
j
int
,
pfs
fuse
.
FileSystem
)
{
...
...
@@ -755,7 +755,7 @@ func (me *UnionFs) OpenDir(directory string, context *fuse.Context) (stream chan
wg
.
Wait
()
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
{
deletions
=
map
[
string
]
bool
{}
}
else
{
...
...
@@ -789,8 +789,8 @@ func (me *UnionFs) OpenDir(directory string, context *fuse.Context) (stream chan
}
}
if
directory
==
""
{
delete
(
results
,
me
.
options
.
DeletionDirName
)
for
name
,
_
:=
range
me
.
hiddenFiles
{
delete
(
results
,
fs
.
options
.
DeletionDirName
)
for
name
,
_
:=
range
fs
.
hiddenFiles
{
delete
(
results
,
name
)
}
}
...
...
@@ -809,10 +809,10 @@ func (me *UnionFs) OpenDir(directory string, context *fuse.Context) (stream chan
// recursivePromote promotes path, and if a directory, everything
// below that directory. It returns a list of all promoted paths, in
// 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
{}
if
pathResult
.
branch
>
0
{
code
=
me
.
Promote
(
path
,
pathResult
,
context
)
code
=
fs
.
Promote
(
path
,
pathResult
,
context
)
}
if
code
.
Ok
()
{
...
...
@@ -821,15 +821,15 @@ func (me *UnionFs) recursivePromote(path string, pathResult branchResult, contex
if
code
.
Ok
()
&&
pathResult
.
attr
!=
nil
&&
pathResult
.
attr
.
IsDir
()
{
var
stream
chan
fuse
.
DirEntry
stream
,
code
=
me
.
OpenDir
(
path
,
context
)
stream
,
code
=
fs
.
OpenDir
(
path
,
context
)
for
e
:=
range
stream
{
if
!
code
.
Ok
()
{
break
}
subnames
:=
[]
string
{}
p
:=
filepath
.
Join
(
path
,
e
.
Name
)
r
:=
me
.
getBranch
(
p
)
subnames
,
code
=
me
.
recursivePromote
(
p
,
r
,
context
)
r
:=
fs
.
getBranch
(
p
)
subnames
,
code
=
fs
.
recursivePromote
(
p
,
r
,
context
)
names
=
append
(
names
,
subnames
...
)
}
}
...
...
@@ -840,17 +840,17 @@ func (me *UnionFs) recursivePromote(path string, pathResult branchResult, contex
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
{}
if
code
.
Ok
()
{
names
,
code
=
me
.
recursivePromote
(
srcDir
,
srcResult
,
context
)
names
,
code
=
fs
.
recursivePromote
(
srcDir
,
srcResult
,
context
)
}
if
code
.
Ok
()
{
code
=
me
.
promoteDirsTo
(
dstDir
)
code
=
fs
.
promoteDirsTo
(
dstDir
)
}
if
code
.
Ok
()
{
writable
:=
me
.
fileSystems
[
0
]
writable
:=
fs
.
fileSystems
[
0
]
code
=
writable
.
Rename
(
srcDir
,
dstDir
,
context
)
}
...
...
@@ -858,65 +858,65 @@ func (me *UnionFs) renameDirectory(srcResult branchResult, srcDir string, dstDir
for
_
,
srcName
:=
range
names
{
relative
:=
strings
.
TrimLeft
(
srcName
[
len
(
srcDir
)
:
],
string
(
filepath
.
Separator
))
dst
:=
filepath
.
Join
(
dstDir
,
relative
)
me
.
removeDeletion
(
dst
)
fs
.
removeDeletion
(
dst
)
srcResult
:=
me
.
getBranch
(
srcName
)
srcResult
:=
fs
.
getBranch
(
srcName
)
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
{
code
=
me
.
putDeletion
(
srcName
)
code
=
fs
.
putDeletion
(
srcName
)
}
}
}
return
code
}
func
(
me
*
UnionFs
)
Rename
(
src
string
,
dst
string
,
context
*
fuse
.
Context
)
(
code
fuse
.
Status
)
{
srcResult
:=
me
.
getBranch
(
src
)
func
(
fs
*
UnionFs
)
Rename
(
src
string
,
dst
string
,
context
*
fuse
.
Context
)
(
code
fuse
.
Status
)
{
srcResult
:=
fs
.
getBranch
(
src
)
code
=
srcResult
.
code
if
code
.
Ok
()
{
code
=
srcResult
.
code
}
if
srcResult
.
attr
.
IsDir
()
{
return
me
.
renameDirectory
(
srcResult
,
src
,
dst
,
context
)
return
fs
.
renameDirectory
(
srcResult
,
src
,
dst
,
context
)
}
if
code
.
Ok
()
&&
srcResult
.
branch
>
0
{
code
=
me
.
Promote
(
src
,
srcResult
,
context
)
code
=
fs
.
Promote
(
src
,
srcResult
,
context
)
}
if
code
.
Ok
()
{
code
=
me
.
promoteDirsTo
(
dst
)
code
=
fs
.
promoteDirsTo
(
dst
)
}
if
code
.
Ok
()
{
code
=
me
.
fileSystems
[
0
]
.
Rename
(
src
,
dst
,
context
)
code
=
fs
.
fileSystems
[
0
]
.
Rename
(
src
,
dst
,
context
)
}
if
code
.
Ok
()
{
me
.
removeDeletion
(
dst
)
fs
.
removeDeletion
(
dst
)
// 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
{
code
=
me
.
putDeletion
(
src
)
code
=
fs
.
putDeletion
(
src
)
}
}
return
code
}
func
(
me
*
UnionFs
)
DropBranchCache
(
names
[]
string
)
{
me
.
branchCache
.
DropAll
(
names
)
func
(
fs
*
UnionFs
)
DropBranchCache
(
names
[]
string
)
{
fs
.
branchCache
.
DropAll
(
names
)
}
func
(
me
*
UnionFs
)
DropDeletionCache
()
{
me
.
deletionCache
.
DropCache
()
func
(
fs
*
UnionFs
)
DropDeletionCache
()
{
fs
.
deletionCache
.
DropCache
()
}
func
(
me
*
UnionFs
)
DropSubFsCaches
()
{
for
_
,
fs
:=
range
me
.
fileSystems
{
func
(
fs
*
UnionFs
)
DropSubFsCaches
()
{
for
_
,
fs
:=
range
fs
.
fileSystems
{
a
,
code
:=
fs
.
GetAttr
(
_DROP_CACHE
,
nil
)
if
code
.
Ok
()
&&
a
.
IsRegular
()
{
f
,
_
:=
fs
.
Open
(
_DROP_CACHE
,
uint32
(
os
.
O_WRONLY
),
nil
)
...
...
@@ -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
flags
&
fuse
.
O_ANYWRITE
!=
0
{
log
.
Println
(
"Forced cache drop on"
,
me
)
me
.
DropBranchCache
(
nil
)
me
.
DropDeletionCache
()
me
.
DropSubFsCaches
()
me
.
nodeFs
.
ForgetClientInodes
()
log
.
Println
(
"Forced cache drop on"
,
fs
)
fs
.
DropBranchCache
(
nil
)
fs
.
DropDeletionCache
()
fs
.
DropSubFsCaches
()
fs
.
nodeFs
.
ForgetClientInodes
()
}
return
fuse
.
NewDevNullFile
(),
fuse
.
OK
}
r
:=
me
.
getBranch
(
name
)
r
:=
fs
.
getBranch
(
name
)
if
r
.
branch
<
0
{
// This should not happen, as a GetAttr() should have
// already verified existence.
...
...
@@ -947,32 +947,32 @@ func (me *UnionFs) Open(name string, flags uint32, context *fuse.Context) (fuseF
return
nil
,
fuse
.
ENOENT
}
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
{
return
nil
,
code
}
r
.
branch
=
0
now
:=
time
.
Now
()
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
{
fuseFile
=
me
.
newUnionFsFile
(
fuseFile
,
r
.
branch
)
fuseFile
=
fs
.
newUnionFsFile
(
fuseFile
,
r
.
branch
)
}
return
fuseFile
,
status
}
func
(
me
*
UnionFs
)
String
()
string
{
func
(
fs
*
UnionFs
)
String
()
string
{
names
:=
[]
string
{}
for
_
,
fs
:=
range
me
.
fileSystems
{
for
_
,
fs
:=
range
fs
.
fileSystems
{
names
=
append
(
names
,
fs
.
String
())
}
return
fmt
.
Sprintf
(
"UnionFs(%v)"
,
names
)
}
func
(
me
*
UnionFs
)
StatFs
(
name
string
)
*
fuse
.
StatfsOut
{
return
me
.
fileSystems
[
0
]
.
StatFs
(
""
)
func
(
fs
*
UnionFs
)
StatFs
(
name
string
)
*
fuse
.
StatfsOut
{
return
fs
.
fileSystems
[
0
]
.
StatFs
(
""
)
}
type
unionFsFile
struct
{
...
...
@@ -982,37 +982,37 @@ type unionFsFile struct {
layer
int
}
func
(
me
*
unionFsFile
)
String
()
string
{
return
fmt
.
Sprintf
(
"unionFsFile(%s)"
,
me
.
File
.
String
())
func
(
fs
*
unionFsFile
)
String
()
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
{
File
:
f
,
ufs
:
me
,
ufs
:
fs
,
layer
:
branch
,
}
}
func
(
me
*
unionFsFile
)
InnerFile
()
(
file
fuse
.
File
)
{
return
me
.
File
func
(
fs
*
unionFsFile
)
InnerFile
()
(
file
fuse
.
File
)
{
return
fs
.
File
}
// We can't hook on Release. Release has no response, so it is not
// ordered wrt any following calls.
func
(
me
*
unionFsFile
)
Flush
()
(
code
fuse
.
Status
)
{
code
=
me
.
File
.
Flush
()
path
:=
me
.
ufs
.
nodeFs
.
Path
(
me
.
node
)
me
.
ufs
.
branchCache
.
GetFresh
(
path
)
func
(
fs
*
unionFsFile
)
Flush
()
(
code
fuse
.
Status
)
{
code
=
fs
.
File
.
Flush
()
path
:=
fs
.
ufs
.
nodeFs
.
Path
(
fs
.
node
)
fs
.
ufs
.
branchCache
.
GetFresh
(
path
)
return
code
}
func
(
me
*
unionFsFile
)
SetInode
(
node
*
fuse
.
Inode
)
{
me
.
node
=
node
func
(
fs
*
unionFsFile
)
SetInode
(
node
*
fuse
.
Inode
)
{
fs
.
node
=
node
}
func
(
me
*
unionFsFile
)
GetAttr
()
(
*
fuse
.
Attr
,
fuse
.
Status
)
{
fi
,
code
:=
me
.
File
.
GetAttr
()
func
(
fs
*
unionFsFile
)
GetAttr
()
(
*
fuse
.
Attr
,
fuse
.
Status
)
{
fi
,
code
:=
fs
.
File
.
GetAttr
()
if
fi
!=
nil
{
f
:=
*
fi
fi
=
&
f
...
...
zipfs/memtree.go
View file @
5514ae72
...
...
@@ -30,24 +30,24 @@ func NewMemTreeFs() *MemTreeFs {
return
d
}
func
(
me
*
MemTreeFs
)
OnMount
(
conn
*
fuse
.
FileSystemConnector
)
{
for
k
,
v
:=
range
me
.
files
{
me
.
addFile
(
k
,
v
)
func
(
fs
*
MemTreeFs
)
OnMount
(
conn
*
fuse
.
FileSystemConnector
)
{
for
k
,
v
:=
range
fs
.
files
{
fs
.
addFile
(
k
,
v
)
}
me
.
files
=
nil
fs
.
files
=
nil
}
func
(
me
*
MemTreeFs
)
Root
()
fuse
.
FsNode
{
return
&
me
.
root
func
(
fs
*
MemTreeFs
)
Root
()
fuse
.
FsNode
{
return
&
fs
.
root
}
func
(
me
*
memNode
)
Print
(
indent
int
)
{
func
(
n
*
memNode
)
Print
(
indent
int
)
{
s
:=
""
for
i
:=
0
;
i
<
indent
;
i
++
{
s
=
s
+
" "
}
children
:=
me
.
Inode
()
.
Children
()
children
:=
n
.
Inode
()
.
Children
()
for
k
,
v
:=
range
children
{
if
v
.
IsDir
()
{
fmt
.
Println
(
s
+
k
+
":"
)
...
...
@@ -62,12 +62,12 @@ func (me *memNode) Print(indent int) {
}
// 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
}
func
(
me
*
memNode
)
OpenDir
(
context
*
fuse
.
Context
)
(
stream
chan
fuse
.
DirEntry
,
code
fuse
.
Status
)
{
children
:=
me
.
Inode
()
.
Children
()
func
(
n
*
memNode
)
OpenDir
(
context
*
fuse
.
Context
)
(
stream
chan
fuse
.
DirEntry
,
code
fuse
.
Status
)
{
children
:=
n
.
Inode
()
.
Children
()
stream
=
make
(
chan
fuse
.
DirEntry
,
len
(
children
))
for
k
,
v
:=
range
children
{
mode
:=
fuse
.
S_IFREG
|
0666
...
...
@@ -83,32 +83,32 @@ func (me *memNode) OpenDir(context *fuse.Context) (stream chan fuse.DirEntry, co
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
{
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
}
func
(
me
*
memNode
)
GetAttr
(
file
fuse
.
File
,
context
*
fuse
.
Context
)
(
*
fuse
.
Attr
,
fuse
.
Status
)
{
if
me
.
Inode
()
.
IsDir
()
{
func
(
n
*
memNode
)
GetAttr
(
file
fuse
.
File
,
context
*
fuse
.
Context
)
(
*
fuse
.
Attr
,
fuse
.
Status
)
{
if
n
.
Inode
()
.
IsDir
()
{
return
&
fuse
.
Attr
{
Mode
:
fuse
.
S_IFDIR
|
0777
,
},
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
,
"/"
)
node
:=
me
.
root
.
Inode
()
node
:=
n
.
root
.
Inode
()
for
i
,
c
:=
range
comps
{
child
:=
node
.
GetChild
(
c
)
if
child
==
nil
{
...
...
zipfs/multizip.go
View file @
5514ae72
...
...
@@ -42,19 +42,19 @@ func NewMultiZipFs() *MultiZipFs {
return
m
}
func
(
me
*
MultiZipFs
)
String
()
string
{
func
(
fs
*
MultiZipFs
)
String
()
string
{
return
"MultiZipFs"
}
func
(
me
*
MultiZipFs
)
OnMount
(
nodeFs
*
fuse
.
PathNodeFs
)
{
me
.
nodeFs
=
nodeFs
func
(
fs
*
MultiZipFs
)
OnMount
(
nodeFs
*
fuse
.
PathNodeFs
)
{
fs
.
nodeFs
=
nodeFs
}
func
(
me
*
MultiZipFs
)
OpenDir
(
name
string
,
context
*
fuse
.
Context
)
(
stream
chan
fuse
.
DirEntry
,
code
fuse
.
Status
)
{
me
.
lock
.
RLock
()
defer
me
.
lock
.
RUnlock
()
func
(
fs
*
MultiZipFs
)
OpenDir
(
name
string
,
context
*
fuse
.
Context
)
(
stream
chan
fuse
.
DirEntry
,
code
fuse
.
Status
)
{
fs
.
lock
.
RLock
()
defer
fs
.
lock
.
RUnlock
()
stream
=
make
(
chan
fuse
.
DirEntry
,
len
(
me
.
zips
)
+
2
)
stream
=
make
(
chan
fuse
.
DirEntry
,
len
(
fs
.
zips
)
+
2
)
if
name
==
""
{
var
d
fuse
.
DirEntry
d
.
Name
=
"config"
...
...
@@ -63,7 +63,7 @@ func (me *MultiZipFs) OpenDir(name string, context *fuse.Context) (stream chan f
}
if
name
==
"config"
{
for
k
:=
range
me
.
zips
{
for
k
:=
range
fs
.
zips
{
var
d
fuse
.
DirEntry
d
.
Name
=
k
d
.
Mode
=
fuse
.
S_IFLNK
...
...
@@ -75,7 +75,7 @@ func (me *MultiZipFs) OpenDir(name string, context *fuse.Context) (stream chan f
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
{}
if
name
==
""
{
// Should not write in top dir.
...
...
@@ -97,11 +97,11 @@ func (me *MultiZipFs) GetAttr(name string, context *fuse.Context) (*fuse.Attr, f
submode
=
fuse
.
S_IFLNK
|
0600
}
me
.
lock
.
RLock
()
defer
me
.
lock
.
RUnlock
()
fs
.
lock
.
RLock
()
defer
fs
.
lock
.
RUnlock
()
a
.
Mode
=
submode
_
,
hasDir
:=
me
.
zips
[
base
]
_
,
hasDir
:=
fs
.
zips
[
base
]
if
hasDir
{
return
a
,
fuse
.
OK
}
...
...
@@ -109,20 +109,20 @@ func (me *MultiZipFs) GetAttr(name string, context *fuse.Context) (*fuse.Attr, f
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
)
if
dir
==
CONFIG_PREFIX
{
me
.
lock
.
Lock
()
defer
me
.
lock
.
Unlock
()
fs
.
lock
.
Lock
()
defer
fs
.
lock
.
Unlock
()
zfs
,
ok
:=
me
.
zips
[
basename
]
zfs
,
ok
:=
fs
.
zips
[
basename
]
if
ok
{
code
=
me
.
nodeFs
.
UnmountNode
(
zfs
.
Root
()
.
Inode
())
code
=
fs
.
nodeFs
.
UnmountNode
(
zfs
.
Root
()
.
Inode
())
if
!
code
.
Ok
()
{
return
code
}
delete
(
me
.
zips
,
basename
)
delete
(
me
.
dirZipFileMap
,
basename
)
delete
(
fs
.
zips
,
basename
)
delete
(
fs
.
dirZipFileMap
,
basename
)
return
fuse
.
OK
}
else
{
return
fuse
.
ENOENT
...
...
@@ -131,48 +131,48 @@ func (me *MultiZipFs) Unlink(name string, context *fuse.Context) (code fuse.Stat
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
)
if
dir
!=
CONFIG_PREFIX
{
return
""
,
fuse
.
ENOENT
}
me
.
lock
.
Lock
()
defer
me
.
lock
.
Unlock
()
fs
.
lock
.
Lock
()
defer
fs
.
lock
.
Unlock
()
zipfile
,
ok
:=
me
.
dirZipFileMap
[
base
]
zipfile
,
ok
:=
fs
.
dirZipFileMap
[
base
]
if
!
ok
{
return
""
,
fuse
.
ENOENT
}
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
)
if
dir
!=
CONFIG_PREFIX
{
return
fuse
.
EPERM
}
me
.
lock
.
Lock
()
defer
me
.
lock
.
Unlock
()
fs
.
lock
.
Lock
()
defer
fs
.
lock
.
Unlock
()
_
,
ok
:=
me
.
dirZipFileMap
[
base
]
_
,
ok
:=
fs
.
dirZipFileMap
[
base
]
if
ok
{
return
fuse
.
EBUSY
}
fs
,
err
:=
NewArchiveFileSystem
(
value
)
a
fs
,
err
:=
NewArchiveFileSystem
(
value
)
if
err
!=
nil
{
log
.
Println
(
"NewZipArchiveFileSystem failed."
,
err
)
return
fuse
.
EINVAL
}
code
=
me
.
nodeFs
.
Mount
(
base
,
fs
,
nil
)
code
=
fs
.
nodeFs
.
Mount
(
base
,
a
fs
,
nil
)
if
!
code
.
Ok
()
{
return
code
}
me
.
dirZipFileMap
[
base
]
=
value
me
.
zips
[
base
]
=
fs
fs
.
dirZipFileMap
[
base
]
=
value
fs
.
zips
[
base
]
=
a
fs
return
fuse
.
OK
}
zipfs/tarfs.go
View file @
5514ae72
...
...
@@ -33,14 +33,14 @@ type TarFile struct {
tar
.
Header
}
func
(
me
*
TarFile
)
Stat
()
*
fuse
.
Attr
{
fi
,
_
:=
HeaderToFileInfo
(
&
me
.
Header
)
func
(
f
*
TarFile
)
Stat
()
*
fuse
.
Attr
{
fi
,
_
:=
HeaderToFileInfo
(
&
f
.
Header
)
fi
.
Mode
|=
syscall
.
S_IFREG
return
fi
}
func
(
me
*
TarFile
)
Data
()
[]
byte
{
return
me
.
data
func
(
f
*
TarFile
)
Data
()
[]
byte
{
return
f
.
data
}
func
NewTarTree
(
r
io
.
Reader
)
map
[
string
]
MemFile
{
...
...
zipfs/zipfs.go
View file @
5514ae72
...
...
@@ -19,23 +19,23 @@ type ZipFile struct {
*
zip
.
File
}
func
(
me
*
ZipFile
)
Stat
()
*
fuse
.
Attr
{
func
(
f
*
ZipFile
)
Stat
()
*
fuse
.
Attr
{
// TODO - do something intelligent with timestamps.
return
&
fuse
.
Attr
{
Mode
:
fuse
.
S_IFREG
|
0444
,
Size
:
uint64
(
me
.
File
.
UncompressedSize
),
Size
:
uint64
(
f
.
File
.
UncompressedSize
),
}
}
func
(
me
*
ZipFile
)
Data
()
[]
byte
{
zf
:=
(
*
me
)
func
(
f
*
ZipFile
)
Data
()
[]
byte
{
zf
:=
(
*
f
)
rc
,
err
:=
zf
.
Open
()
if
err
!=
nil
{
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
{
panic
(
err
)
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment