github.com/bosssauce/ponzu@v0.11.1-0.20200102001432-9bc41b703131/system/backup/archive.go (about) 1 package backup 2 3 import ( 4 "archive/tar" 5 "compress/gzip" 6 "context" 7 "fmt" 8 "io" 9 "os" 10 "path/filepath" 11 ) 12 13 // ArchiveFS walks the filesystem starting from basedir writing files encountered 14 // tarred and gzipped to the provided writer 15 func ArchiveFS(ctx context.Context, basedir string, w io.Writer) error { 16 gz := gzip.NewWriter(w) 17 tarball := tar.NewWriter(gz) 18 19 absPath, err := filepath.Abs(basedir) 20 if err != nil { 21 return err 22 } 23 24 info, err := os.Lstat(absPath) 25 if err != nil { 26 return err 27 } 28 29 if info.Mode()&os.ModeSymlink == os.ModeSymlink { 30 // This is a symlink - we need to follow it 31 bdir, err := os.Readlink(absPath) 32 if err != nil { 33 return err 34 } 35 basedir = bdir 36 } 37 38 errChan := make(chan error, 1) 39 walkFn := func(path string, info os.FileInfo, err error) error { 40 if err != nil { 41 return err 42 } 43 44 hdr, err := tar.FileInfoHeader(info, "") 45 if err != nil { 46 return err 47 } 48 49 hdr.Name = path 50 51 err = tarball.WriteHeader(hdr) 52 if err != nil { 53 return err 54 } 55 56 if !info.IsDir() { 57 src, err := os.Open(path) 58 if err != nil { 59 return err 60 } 61 defer src.Close() 62 63 _, err = io.Copy(tarball, src) 64 if err != nil { 65 return err 66 } 67 68 err = tarball.Flush() 69 if err != nil { 70 return err 71 } 72 73 err = gz.Flush() 74 if err != nil { 75 return err 76 } 77 } 78 79 return nil 80 } 81 82 // stop processing if we get a cancellation signal 83 err = filepath.Walk(basedir, func(path string, info os.FileInfo, err error) error { 84 go func() { errChan <- walkFn(path, info, err) }() 85 86 select { 87 case <-ctx.Done(): 88 if err := ctx.Err(); err != nil { 89 return err 90 } 91 case err := <-errChan: 92 if err != nil { 93 return err 94 } 95 } 96 97 return nil 98 }) 99 if err != nil { 100 fmt.Println(err) 101 return err 102 } 103 104 err = gz.Close() 105 if err != nil { 106 return err 107 } 108 err = tarball.Close() 109 if err != nil { 110 return err 111 } 112 113 return nil 114 }