1
0
mirror of https://github.com/rclone/rclone.git synced 2025-11-23 21:44:49 +02:00
Files
rclone/vfs/zip.go

74 lines
1.6 KiB
Go
Raw Normal View History

package vfs
import (
"archive/zip"
"context"
"fmt"
"io"
"os"
"github.com/rclone/rclone/fs"
)
// CreateZip creates a zip file from a vfs.Dir writing it to w
func CreateZip(ctx context.Context, dir *Dir, w io.Writer) (err error) {
zipWriter := zip.NewWriter(w)
defer fs.CheckClose(zipWriter, &err)
var walk func(dir *Dir, root string) error
walk = func(dir *Dir, root string) error {
nodes, err := dir.ReadDirAll()
if err != nil {
return fmt.Errorf("create zip directory read: %w", err)
}
for _, node := range nodes {
switch e := node.(type) {
case *File:
in, err := e.Open(os.O_RDONLY)
if err != nil {
return fmt.Errorf("create zip open file: %w", err)
}
header := &zip.FileHeader{
Name: root + e.Name(),
Method: zip.Deflate,
Modified: e.ModTime(),
}
fileWriter, err := zipWriter.CreateHeader(header)
if err != nil {
fs.CheckClose(in, &err)
return fmt.Errorf("create zip file header: %w", err)
}
_, err = io.Copy(fileWriter, in)
if err != nil {
fs.CheckClose(in, &err)
return fmt.Errorf("create zip copy: %w", err)
}
fs.CheckClose(in, &err)
case *Dir:
name := root + e.Path()
if name != "" && name[len(name)-1] != '/' {
name += "/"
}
header := &zip.FileHeader{
Name: name,
Method: zip.Store,
Modified: e.ModTime(),
}
_, err := zipWriter.CreateHeader(header)
if err != nil {
return fmt.Errorf("create zip directory header: %w", err)
}
err = walk(e, name)
if err != nil {
return err
}
}
}
return nil
}
err = walk(dir, "")
if err != nil {
return err
}
return nil
}