package server import ( "archive/zip" "fmt" "io" "mime/multipart" "os" "path/filepath" "github.com/gin-gonic/gin" "warpbox/lib/models" ) func listCompletedFilesFromDisk(boxID string) ([]models.BoxFile, error) { entries, err := os.ReadDir(boxPath(boxID)) if err != nil { return nil, err } files := make([]models.BoxFile, 0, len(entries)) for _, entry := range entries { if entry.IsDir() || entry.Name() == boxManifestFile { continue } info, err := entry.Info() if err != nil { return nil, err } name := entry.Name() mimeType := mimeTypeForFile(filepath.Join(boxPath(boxID), name), name) files = append(files, decorateBoxFile(boxID, models.BoxFile{ ID: name, Name: name, Size: info.Size(), MimeType: mimeType, Status: fileStatusReady, })) } return files, nil } func addFileToZip(zipWriter *zip.Writer, boxID string, filename string) error { path := filepath.Join(boxPath(boxID), filename) source, err := os.Open(path) if err != nil { return err } defer source.Close() destination, err := zipWriter.Create(filename) if err != nil { return err } _, err = io.Copy(destination, source) return err } func saveManifestUploadedFile(ctx *gin.Context, boxID string, fileID string, file *multipart.FileHeader) (models.BoxFile, error) { boxManifestMu.Lock() defer boxManifestMu.Unlock() manifest, err := readBoxManifestUnlocked(boxID) if err != nil { return models.BoxFile{}, err } fileIndex := -1 for index, manifestFile := range manifest.Files { if manifestFile.ID == fileID { fileIndex = index break } } if fileIndex < 0 { return models.BoxFile{}, fmt.Errorf("File not found") } filename := manifest.Files[fileIndex].Name if err := os.MkdirAll(boxPath(boxID), 0755); err != nil { return models.BoxFile{}, fmt.Errorf("Could not prepare upload box") } destination := filepath.Join(boxPath(boxID), filename) if err := ctx.SaveUploadedFile(file, destination); err != nil { manifest.Files[fileIndex].Status = fileStatusFailed writeBoxManifestUnlocked(boxID, manifest) return models.BoxFile{}, fmt.Errorf("Could not save uploaded file") } manifest.Files[fileIndex].Size = file.Size manifest.Files[fileIndex].MimeType = mimeTypeForFile(destination, filename) manifest.Files[fileIndex].Status = fileStatusReady if err := writeBoxManifestUnlocked(boxID, manifest); err != nil { return models.BoxFile{}, err } return decorateBoxFile(boxID, manifest.Files[fileIndex]), nil } func saveUploadedFile(ctx *gin.Context, boxID string, file *multipart.FileHeader) (gin.H, error) { filename, ok := safeFilename(file.Filename) if !ok { return nil, fmt.Errorf("Invalid filename") } boxPath := boxPath(boxID) if err := os.MkdirAll(boxPath, 0755); err != nil { return nil, fmt.Errorf("Could not prepare upload box") } filename = uniqueFilename(boxPath, filename) destination := filepath.Join(boxPath, filename) if err := ctx.SaveUploadedFile(file, destination); err != nil { return nil, fmt.Errorf("Could not save uploaded file") } return gin.H{"name": filename, "size": file.Size}, nil }