github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/worker/archive/zip.go (about) 1 package archive 2 3 import ( 4 "archive/zip" 5 "io" 6 "time" 7 8 "github.com/cozy/cozy-stack/model/job" 9 "github.com/cozy/cozy-stack/model/vfs" 10 ) 11 12 type zipMessage struct { 13 Files map[string]string `json:"files"` // path -> fileID 14 DirID string `json:"dir_id"` 15 Filename string `json:"filename"` 16 } 17 18 // WorkerZip is a worker that creates zip archives. 19 func WorkerZip(ctx *job.TaskContext) error { 20 msg := &zipMessage{} 21 if err := ctx.UnmarshalMessage(msg); err != nil { 22 return err 23 } 24 fs := ctx.Instance.VFS() 25 return createZip(fs, msg.Files, msg.DirID, msg.Filename) 26 } 27 28 func createZip(fs vfs.VFS, files map[string]string, dirID, filename string) error { 29 now := time.Now() 30 zipDoc, err := vfs.NewFileDoc(filename, dirID, -1, nil, "application/zip", "zip", now, false, false, false, nil) 31 if err != nil { 32 return err 33 } 34 zipDoc.CozyMetadata = vfs.NewCozyMetadata("") 35 zipDoc.CozyMetadata.UploadedAt = &now 36 z, err := fs.CreateFile(zipDoc, nil) 37 if err != nil { 38 return err 39 } 40 w := zip.NewWriter(z) 41 for filePath, fileID := range files { 42 err = addFileToZip(fs, w, fileID, filePath) 43 if err != nil { 44 break 45 } 46 } 47 werr := w.Close() 48 zerr := z.Close() 49 if err != nil { 50 return err 51 } 52 if werr != nil { 53 return werr 54 } 55 return zerr 56 } 57 58 func addFileToZip(fs vfs.VFS, w *zip.Writer, fileID, filePath string) error { 59 file, err := fs.FileByID(fileID) 60 if err != nil { 61 return err 62 } 63 fr, err := fs.OpenFile(file) 64 if err != nil { 65 return err 66 } 67 defer fr.Close() 68 header := &zip.FileHeader{ 69 Name: filePath, 70 Method: zip.Deflate, 71 Modified: file.UpdatedAt, 72 } 73 if file.Executable { 74 header.SetMode(0750) 75 } else { 76 header.SetMode(0640) 77 } 78 f, err := w.CreateHeader(header) 79 if err != nil { 80 return err 81 } 82 _, err = io.Copy(f, fr) 83 return err 84 }