Created
December 5, 2018 13:32
-
-
Save macrat/99739d9a0b00fe025ed7bc4b4afbd714 to your computer and use it in GitHub Desktop.
go言語でtarアーカイブをファイルシステムっぽく扱うやつ。作りかけ。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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