Commit 03784884 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

Implement fuse.CopyFile to copy between FileSystems generically.

Use it in UnionFs.
parent df652252
...@@ -3,32 +3,35 @@ include $(GOROOT)/src/Make.inc ...@@ -3,32 +3,35 @@ include $(GOROOT)/src/Make.inc
TARG=github.com/hanwen/go-fuse/fuse TARG=github.com/hanwen/go-fuse/fuse
GOFILES=api.go \ GOFILES=\
misc.go\ api.go \
request.go \
fuse.go\
direntry.go\
mount.go\
types.go\
pathfilesystem.go \
bufferpool.go \ bufferpool.go \
copy.go \
default.go \ default.go \
direntry.go\
files.go \ files.go \
fuse.go\
latencymap.go \
lockingfs.go \ lockingfs.go \
loggingfs.go \
loopback.go \ loopback.go \
misc.go \
mount.go \
opcode.go \
pathdebug.go \
pathfilesystem.go \
pathops.go \
request.go \
timingfs.go \ timingfs.go \
timingrawfs.go \ timingrawfs.go \
types.go\
version.gen.go \
xattr.go \ xattr.go \
pathdebug.go \
opcode.go \ include $(GOROOT)/src/Make.pkg
pathops.go \
latencymap.go \
loggingfs.go \
version.gen.go
version.gen.go: version.gen.go:
echo "package fuse" > $@ echo "package fuse" > $@
git log -n1 --pretty=format:'const version = "%h (%cd)"' --date=iso >> $@ git log -n1 --pretty=format:'const version = "%h (%cd)"' --date=iso >> $@
include $(GOROOT)/src/Make.pkg
package fuse
import (
"os"
)
func CopyFile(srcFs, destFs FileSystem, srcFile, destFile string) Status {
src, code := srcFs.Open(srcFile, uint32(os.O_RDONLY))
if !code.Ok() {
return code
}
defer src.Release()
defer src.Flush()
attr, code := srcFs.GetAttr(srcFile)
if !code.Ok() {
return code
}
w := WriteIn{
Flags: uint32(os.O_WRONLY|os.O_CREATE|os.O_TRUNC),
}
dst, code := destFs.Create(destFile, w.Flags, attr.Mode)
if !code.Ok() {
return code
}
defer dst.Release()
defer dst.Flush()
bp := NewBufferPool()
r := ReadIn{
Size: 128 * (1<<10),
}
for {
data, code := src.Read(&r, bp)
if !code.Ok() {
return code
}
if len(data) == 0 {
break;
}
n, code := dst.Write(&w, data)
if !code.Ok() {
return code
}
if int(n) < len(data) {
return EIO
}
if len(data) < int(r.Size) {
break;
}
r.Offset += uint64(len(data))
w.Offset += uint64(len(data))
bp.FreeBuffer(data)
}
return OK
}
package fuse
import (
"testing"
"io/ioutil"
)
func TestCopyFile(t *testing.T) {
d1 := MakeTempDir()
d2 := MakeTempDir()
fs1 := NewLoopbackFileSystem(d1)
fs2 := NewLoopbackFileSystem(d2)
content1 := "blabla"
err := ioutil.WriteFile(d1 + "/file", []byte(content1), 0644)
CheckSuccess(err)
code := CopyFile(fs1, fs2, "file", "file")
if !code.Ok() {
t.Fatal("Unexpected ret code", code)
}
data, err := ioutil.ReadFile(d2 + "/file")
if content1 != string(data) {
t.Fatal("Unexpected content", string(data))
}
content2 := "foobar"
err = ioutil.WriteFile(d2 + "/file", []byte(content2), 0644)
CheckSuccess(err)
// Copy back: should overwrite.
code = CopyFile(fs2, fs1, "file", "file")
if !code.Ok() {
t.Fatal("Unexpected ret code", code)
}
data, err = ioutil.ReadFile(d1 + "/file")
if content2 != string(data) {
t.Fatal("Unexpected content", string(data))
}
}
...@@ -4,7 +4,6 @@ import ( ...@@ -4,7 +4,6 @@ import (
"crypto/md5" "crypto/md5"
"fmt" "fmt"
"github.com/hanwen/go-fuse/fuse" "github.com/hanwen/go-fuse/fuse"
"io"
"io/ioutil" "io/ioutil"
"log" "log"
"os" "os"
...@@ -229,48 +228,21 @@ func (me *UnionFs) putDeletion(name string) fuse.Status { ...@@ -229,48 +228,21 @@ func (me *UnionFs) putDeletion(name string) fuse.Status {
//////////////// ////////////////
// Promotion. // Promotion.
// From the golang blog.
func CopyFile(dstName, srcName string) (written int64, err os.Error) {
src, err := os.Open(srcName)
if err != nil {
return
}
defer src.Close()
dir, _ := filepath.Split(dstName)
fi, err := os.Stat(dir)
if fi != nil && !fi.IsDirectory() {
return 0, os.NewError("Destination is not a directory.")
}
if err != nil {
return 0, err
}
dst, err := os.Create(dstName)
if err != nil {
return
}
defer dst.Close()
return io.Copy(dst, src)
}
func (me *UnionFs) Promote(name string, srcResult branchResult) fuse.Status { func (me *UnionFs) Promote(name string, srcResult branchResult) fuse.Status {
writable := me.branches[0] writable := me.branches[0]
sourceFs := me.branches[srcResult.branch] sourceFs := me.branches[srcResult.branch]
// Promote directories. // Promote directories.
me.promoteDirsTo(name) me.promoteDirsTo(name)
_, err := CopyFile(writable.GetPath(name), sourceFs.GetPath(name)) code := fuse.CopyFile(sourceFs, writable, name, name)
r := me.getBranch(name) if !code.Ok() {
r.branch = 0 me.branchCache.GetFresh(name)
me.branchCache.Set(name, r) return code
} else {
if err != nil { r := me.getBranch(name)
log.Println("promote error: ", name, err.String()) r.branch = 0
return fuse.EPERM me.branchCache.Set(name, r)
} }
return fuse.OK return fuse.OK
......
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