package fileUtilities import ( "archive/zip" "fmt" "forever-files/types" "io" "os" "path" "strings" ) func CreateZip(fileName, outDir, baseDir string, partition []types.FileMetadata) error { // Create a buffer to write our archive to. outFile := path.Join(outDir, fileName+".zip") zipFile, err := os.OpenFile(outFile, os.O_CREATE|os.O_WRONLY, 0644) if err != nil { return fmt.Errorf("error opening/creating zip file: %w", err) } // Create a new zip archive. w := zip.NewWriter(zipFile) files := prepFiles(baseDir, partition) for _, file := range files { zf, err := w.Create(file.Name) if err != nil { return fmt.Errorf("error creating zip file: %w", err) } f, err := os.Open(file.Path) if err != nil { fmt.Println(fmt.Sprintf("error opening file: %v", err)) fmt.Println(fmt.Sprintf("skipping file: %v", file.Path)) continue } if _, err := io.Copy(zf, f); err != nil { return fmt.Errorf("error copying file to zip file: %w", err) } err = f.Close() if err != nil { return fmt.Errorf("error closing file: %w", err) } } // Make sure to check the error on Close. err = w.Close() if err != nil { return fmt.Errorf("error closing zip file: %w", err) } err = zipFile.Close() if err != nil { return fmt.Errorf("error closing zip file: %w", err) } return nil } func prepFiles(baseDir string, partition []types.FileMetadata) []struct { Name, Path string } { var files []struct { Name, Path string } for _, file := range partition { filePath := path.Join(file.Path, file.Name) // from zip.Create documentation: // ...The name must be a relative path: it must not start with a // drive letter (e.g. C:) or leading slash, and only forward slashes // are allowed... fileName := strings.Replace(replaceBackslashes(strings.Replace(filePath, baseDir, "", 1)), "/", "", 1) files = append(files, struct { Name, Path string }{ Name: fileName, Path: filePath, }) } return files } func replaceBackslashes(input string) string { return strings.ReplaceAll(input, "\\", "/") }