package zipfs import ( "archive/zip" "fmt" "os" "strings" "path/filepath" "syscall" "log" ) var _ = log.Printf type ZipFile struct { *zip.File } func (me *ZipFile) Stat() *os.FileInfo { // TODO - do something intelligent with timestamps. return &os.FileInfo{ Mode: syscall.S_IFREG | 0444, Size: int64(me.File.UncompressedSize), } } func (me *ZipFile) Data() []byte { data := make([]byte, me.UncompressedSize) zf := (*me) rc, err := zf.Open() if err != nil { panic("zip open") } start := 0 for { n, err := rc.Read(data[start:]) start += n if err == os.EOF { break } if err != nil && err != os.EOF { panic(fmt.Sprintf("read err: %v, n %v, sz %v", err, n, len(data))) } } return data } func zipFilesToTree(files []*zip.File) *MemTree { t := NewMemTree() for _, f := range files { parent := t comps := strings.Split(filepath.Clean(f.Name), "/", -1) base := "" // Ugh - zip files have directories separate. if !strings.HasSuffix(f.Name, "/") { base = comps[len(comps)-1] comps = comps[:len(comps)-1] } for _, c := range comps { parent = parent.FindDir(c) } if base != "" { parent.files[base] = &ZipFile{File: f} } } return t } // NewZipArchiveFileSystem creates a new file-system for the // zip file named name. func NewZipTree(name string) (*MemTree, os.Error) { r, err := zip.OpenReader(name) if err != nil { return nil, err } 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 }