Commit 0a3f35a3 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

Create NewTarTree() and accept .tar.gz and .tar.bz2.

parent 0ec6d90d
......@@ -23,9 +23,9 @@ func main() {
}
var fs fuse.FileSystem
fs, err := zipfs.NewZipArchiveFileSystem(flag.Arg(1))
fs, err := zipfs.NewArchiveFileSystem(flag.Arg(1))
if err != nil {
fmt.Fprintf(os.Stderr, "NewZipArchiveFileSystem failed: %v\n", err)
fmt.Fprintf(os.Stderr, "NewArchiveFileSystem failed: %v\n", err)
os.Exit(1)
}
debugFs := fuse.NewFileSystemDebug()
......
......@@ -6,6 +6,7 @@ DEPS=../fuse
GOFILES=zipfs.go \
multizip.go \
tarfs.go \
memtree.go
include $(GOROOT)/src/Make.pkg
......
......@@ -10,8 +10,8 @@ import (
type MemFile interface {
Stat() *os.FileInfo
Data() []byte
Stat() *os.FileInfo
Data() []byte
}
type MemTree struct {
......@@ -76,7 +76,7 @@ func (me *MemTree) FindDir(name string) *MemTree {
////////////////////////////////////////////////////////////////
type MemTreeFileSystem struct {
tree *MemTree
tree *MemTree
fuse.DefaultFileSystem
}
......@@ -126,18 +126,18 @@ func (me *MemTreeFileSystem) OpenDir(name string) (stream chan fuse.DirEntry, co
if dir == nil {
panic("dir")
}
stream = make(chan fuse.DirEntry, len(dir.files)+len(dir.subdirs))
for k, _ := range dir.files {
stream <- fuse.DirEntry{
Name: k,
Mode: mem_FILEMODE,
Name: k,
Mode: mem_FILEMODE,
}
}
for k, _ := range dir.subdirs {
stream <- fuse.DirEntry{
Name: k,
Mode: mem_DIRMODE,
Name: k,
Mode: mem_DIRMODE,
}
}
close(stream)
......
......@@ -43,10 +43,10 @@ func (me *zipCreateFile) Write(input *fuse.WriteIn, nameBytes []byte) (uint32, f
zipFile := string(nameBytes)
zipFile = strings.Trim(zipFile, "\n ")
fs, err := NewZipArchiveFileSystem(zipFile)
fs, err := NewArchiveFileSystem(zipFile)
if err != nil {
// TODO
log.Println("NewZipArchiveFileSystem failed:", err)
log.Println("NewZipArchiveFileSystem failed.")
me.zfs.pendingZips[me.Basename] = false, false
return 0, fuse.ENOSYS
}
......@@ -73,10 +73,10 @@ func (me *zipCreateFile) Write(input *fuse.WriteIn, nameBytes []byte) (uint32, f
// reference to the FileSystemConnector to be able to execute
// mounts.
type MultiZipFs struct {
Connector *fuse.FileSystemConnector
lock sync.RWMutex
zips map[string]*MemTreeFileSystem
pendingZips map[string]bool
Connector *fuse.FileSystemConnector
lock sync.RWMutex
zips map[string]*MemTreeFileSystem
pendingZips map[string]bool
dirZipFileMap map[string]string
fuse.DefaultFileSystem
......
package zipfs
import (
"archive/tar"
"bytes"
"compress/bzip2"
"compress/gzip"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"syscall"
)
var _ = fmt.Println
// TODO - handle symlinks.
func HeaderToFileInfo(h *tar.Header) *os.FileInfo {
return &os.FileInfo{
Name: h.Name,
Mode: uint32(h.Mode),
Uid: h.Uid,
Gid: h.Gid,
Size: h.Size,
Mtime_ns: h.Mtime,
//Linkname: h.Linkname ,
Atime_ns: h.Atime,
Ctime_ns: h.Ctime,
}
}
type TarFile struct {
data []byte
tar.Header
}
func (me *TarFile) Stat() *os.FileInfo {
fi := HeaderToFileInfo(&me.Header)
fi.Mode |= syscall.S_IFREG
return fi
}
func (me *TarFile) Data() []byte {
return me.data
}
func NewTarTree(r io.Reader) *MemTree {
tree := NewMemTree()
tr := tar.NewReader(r)
var longName *string
for {
hdr, err := tr.Next()
if err == os.EOF {
// end of tar archive
break
}
if err != nil {
// handle error
}
if hdr.Typeflag == 'L' {
buf := bytes.NewBuffer(make([]byte, 0, hdr.Size))
io.Copy(buf, tr)
s := buf.String()
longName = &s
continue
}
if longName != nil {
hdr.Name = *longName
longName = nil
}
comps := strings.Split(filepath.Clean(hdr.Name), "/", -1)
base := ""
if !strings.HasSuffix(hdr.Name, "/") {
base = comps[len(comps)-1]
comps = comps[:len(comps)-1]
}
parent := tree
for _, c := range comps {
parent = parent.FindDir(c)
}
buf := bytes.NewBuffer(make([]byte, 0, hdr.Size))
io.Copy(buf, tr)
if base != "" {
b := buf.Bytes()
parent.files[base] = &TarFile{
Header: *hdr,
data: b,
}
}
}
return tree
}
func NewTarCompressedTree(name string, format string) (*MemTree, os.Error) {
f, err := os.Open(name)
if err != nil {
return nil, err
}
defer f.Close()
var stream io.Reader
switch format {
case "gz":
unzip, err := gzip.NewReader(f)
if err != nil {
return nil, err
}
defer unzip.Close()
stream = unzip
case "bz2":
unzip := bzip2.NewReader(f)
stream = unzip
}
return NewTarTree(stream), nil
}
......@@ -23,7 +23,7 @@ func (me *ZipFile) Stat() *os.FileInfo {
Size: int64(me.File.UncompressedSize),
}
}
func (me *ZipFile) Data() []byte {
data := make([]byte, me.UncompressedSize)
zf := (*me)
......@@ -72,11 +72,32 @@ func zipFilesToTree(files []*zip.File) *MemTree {
// NewZipArchiveFileSystem creates a new file-system for the
// zip file named name.
func NewZipArchiveFileSystem(name string) (*MemTreeFileSystem, os.Error) {
func NewZipTree(name string) (*MemTree, os.Error) {
r, err := zip.OpenReader(name)
if err != nil {
return nil, err
}
z := NewMemTreeFileSystem(zipFilesToTree(r.File))
return z, nil
return zipFilesToTree(r.File), nil
}
func NewArchiveFileSystem(name string) (fs *MemTreeFileSystem, err os.Error) {
var tree *MemTree
if strings.HasSuffix(name, ".zip") {
tree, err = NewZipTree(name)
}
if strings.HasSuffix(name, ".tar.gz") {
tree, err = NewTarCompressedTree(name, "gz")
}
if strings.HasSuffix(name, ".tar.bz2") {
tree, err = NewTarCompressedTree(name, "bz2")
}
if err != nil {
return nil, err
}
if tree == nil {
return nil, os.NewError(fmt.Sprintf("Unknown type for %v", name))
}
return NewMemTreeFileSystem(tree), nil
}
......@@ -9,7 +9,7 @@ import (
func TestZipFs(t *testing.T) {
wd, err := os.Getwd()
CheckSuccess(err)
zfs, err := NewZipArchiveFileSystem(wd + "/test.zip")
zfs, err := NewArchiveFileSystem(wd + "/test.zip")
if err != nil {
t.Error("NewZipArchiveFileSystem failed:", 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