Archive for April, 2025
Golang: Creating and repairing par2 files
by admin on Apr.01, 2025, under News
PAR2 files (short for Parity Archive Volume Set, version 2) are a form of forward‑error‑correction (“erasure code”) data designed to verify and—if needed—repair missing or corrupted files in any collection of data. Instead of simply telling you a file is bad (as a checksum does), PAR2 files store enough redundancy to reconstruct damaged or missing portions up to the total amount of parity data provided
The following sample code provides a sample implementation using the github.com/akalin/gopar/par2 library to achieve this.
package main
import (
"flag"
"fmt"
"os"
"path/filepath"
"github.com/akalin/gopar/par2"
)
// CreatePAR2 creates a par2 file at outputPath from the given file paths using the provided slice and parity counts.
func CreatePAR2(outputPath string, files []string, sliceByteCount, parityCount int) error {
opts := par2.CreateOptions{
SliceByteCount: sliceByteCount,
NumParityShards: parityCount,
}
return par2.Create(outputPath, files, opts)
}
// VerifyPAR2 verifies the par2 file at parPath using default verify options and returns the result.
func VerifyPAR2(parPath string) (par2.VerifyResult, error) {
return par2.Verify(parPath, par2.VerifyOptions{})
}
// RepairPAR2 repairs files as indicated by the par2 file at parPath using default repair options.
func RepairPAR2(parPath string) (par2.RepairResult, error) {
return par2.Repair(parPath, par2.RepairOptions{})
}
func main() {
action := flag.String("action", "create", "action to perform: create, verify, repair")
sliceSize := flag.Int("slice", 1024, "slice byte count")
parityCount := flag.Int("parity", 10, "number of parity shards")
parFile := flag.String("par", "parity.par2", "output par2 file (for create) or par2 file to verify/repair")
flag.Parse()
switch *action {
case "create":
if flag.NArg() == 0 {
fmt.Fprintln(os.Stderr, "Usage: -action=create -slice=1024 -parity=10 -par=parity.par2 file1 file2 ...")
os.Exit(1)
}
files := flag.Args()
absFiles := make([]string, len(files))
for i, f := range files {
a, err := filepath.Abs(f)
if err != nil {
fmt.Fprintf(os.Stderr, "Error converting %s to absolute path: %v\n", f, err)
os.Exit(1)
}
absFiles[i] = a
}
if err := CreatePAR2(*parFile, absFiles, *sliceSize, *parityCount); err != nil {
fmt.Fprintf(os.Stderr, "Error creating par2 file: %v\n", err)
os.Exit(1)
}
fmt.Println("par2 file created successfully.")
case "verify":
res, err := VerifyPAR2(*parFile)
if err != nil {
fmt.Fprintf(os.Stderr, "Error verifying par2 file: %v\n", err)
os.Exit(1)
}
fmt.Printf("Verification result:\n%+v\n", res)
case "repair":
res, err := RepairPAR2(*parFile)
if err != nil {
fmt.Fprintf(os.Stderr, "Error repairing par2 file: %v\n", err)
os.Exit(1)
}
fmt.Printf("Repair result:\n%+v\n", res)
default:
fmt.Fprintf(os.Stderr, "Unknown action: %s\n", *action)
os.Exit(1)
}
}



