Skip to content

Instantly share code, notes, and snippets.

@macrat
Created December 5, 2018 13:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save macrat/99739d9a0b00fe025ed7bc4b4afbd714 to your computer and use it in GitHub Desktop.
Save macrat/99739d9a0b00fe025ed7bc4b4afbd714 to your computer and use it in GitHub Desktop.
go言語でtarアーカイブをファイルシステムっぽく扱うやつ。作りかけ。
package main
import (
"archive/tar"
"io"
"os"
"path/filepath"
"gopkg.in/src-d/go-billy.v4"
"gopkg.in/src-d/go-billy.v4/osfs"
)
func walk(fs billy.Filesystem, path string, info os.FileInfo, walkFn filepath.WalkFunc) error {
if !info.IsDir() {
return walkFn(path, info, nil)
}
files, err := fs.ReadDir(path)
err1 := walkFn(path, info, err)
if err != nil || err1 != nil {
return err1
}
for _, file := range files {
filename := filepath.Join(path, file.Name())
fileInfo, err := fs.Lstat(filename)
if err != nil {
if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir {
return err
}
} else {
err = walk(fs, filename, fileInfo, walkFn)
if err != nil && (!fileInfo.IsDir() || err != filepath.SkipDir) {
return err
}
}
}
return nil
}
func walkFS(fs billy.Filesystem, walkFn filepath.WalkFunc) error {
info, err := fs.Lstat("/")
if err != nil {
err = walkFn("/", nil, err)
} else {
err = walk(fs, "/", info, walkFn)
}
if err == filepath.SkipDir {
return nil
}
return err
}
type TarFileSystem struct {
buf billy.Filesystem
}
func ReadWithBuffer(source io.Reader, buffer billy.Filesystem) (*TarFileSystem, error) {
fs := &TarFileSystem{buffer}
reader := tar.NewReader(source)
for {
header, err := reader.Next()
if err == io.EOF {
break
} else if err != nil {
return nil, err
}
if header.Typeflag == tar.TypeDir {
if err := fs.buf.MkdirAll(header.Name, os.ModeDir); err != nil {
return nil, err
}
continue
}
f, err := fs.buf.OpenFile(header.Name, os.O_WRONLY|os.O_CREATE, os.FileMode(header.Mode))
if err != nil {
return nil, err
}
if _, err = io.Copy(f, reader); err != nil {
return nil, err
}
}
return fs, nil
}
func (fs *TarFileSystem) Write(destination io.Writer) error {
writer := tar.NewWriter(destination)
defer writer.Close()
return walkFS(fs.buf, func(path string, info os.FileInfo, err error) error {
if path == "/" {
return nil
}
header := &tar.Header{
Name: path[1:],
Mode: int64(info.Mode() & os.ModePerm),
Size: info.Size(),
}
if info.IsDir() {
header.Typeflag = tar.TypeDir
if err := writer.WriteHeader(header); err != nil {
return err
}
} else {
header.Typeflag = tar.TypeReg
if err := writer.WriteHeader(header); err != nil {
return err
}
f, err := fs.buf.Open(path)
if err != nil {
return err
}
if _, err := io.Copy(writer, f); err != nil {
return err
}
}
return nil
})
}
func main() {
src, _ := os.Open("src.tar")
defer src.Close()
fs, err := ReadWithBuffer(src, osfs.New("./work"))
if err != nil {
panic(err.Error())
}
dst, _ := os.Create("dst.tar")
defer dst.Close()
if err := fs.Write(dst); err != nil {
panic(err.Error())
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment