Fix format detection: check file content for PGDMP signature, not just extension

This commit is contained in:
2025-11-07 12:39:09 +00:00
parent 069313e70b
commit a8ce8c4457
2 changed files with 50 additions and 8 deletions

BIN
dbbackup

Binary file not shown.

View File

@ -1,6 +1,9 @@
package restore package restore
import ( import (
"compress/gzip"
"io"
"os"
"strings" "strings"
) )
@ -18,7 +21,7 @@ const (
FormatUnknown ArchiveFormat = "Unknown" FormatUnknown ArchiveFormat = "Unknown"
) )
// DetectArchiveFormat detects the format of a backup archive from its filename // DetectArchiveFormat detects the format of a backup archive from its filename and content
func DetectArchiveFormat(filename string) ArchiveFormat { func DetectArchiveFormat(filename string) ArchiveFormat {
lower := strings.ToLower(filename) lower := strings.ToLower(filename)
@ -27,11 +30,24 @@ func DetectArchiveFormat(filename string) ArchiveFormat {
return FormatClusterTarGz return FormatClusterTarGz
} }
// Check for compressed formats // For .dump files, check if they're actually custom format or SQL text
if strings.HasSuffix(lower, ".dump.gz") { if strings.HasSuffix(lower, ".dump.gz") {
return FormatPostgreSQLDumpGz if isCustomFormat(filename, true) {
return FormatPostgreSQLDumpGz
}
// If not custom format, treat as SQL
return FormatPostgreSQLSQLGz
} }
if strings.HasSuffix(lower, ".dump") {
if isCustomFormat(filename, false) {
return FormatPostgreSQLDump
}
// If not custom format, treat as SQL
return FormatPostgreSQLSQL
}
// Check for compressed SQL formats
if strings.HasSuffix(lower, ".sql.gz") { if strings.HasSuffix(lower, ".sql.gz") {
// Determine if MySQL or PostgreSQL based on naming convention // Determine if MySQL or PostgreSQL based on naming convention
if strings.Contains(lower, "mysql") || strings.Contains(lower, "mariadb") { if strings.Contains(lower, "mysql") || strings.Contains(lower, "mariadb") {
@ -40,11 +56,7 @@ func DetectArchiveFormat(filename string) ArchiveFormat {
return FormatPostgreSQLSQLGz return FormatPostgreSQLSQLGz
} }
// Check for uncompressed formats // Check for uncompressed SQL formats
if strings.HasSuffix(lower, ".dump") {
return FormatPostgreSQLDump
}
if strings.HasSuffix(lower, ".sql") { if strings.HasSuffix(lower, ".sql") {
// Determine if MySQL or PostgreSQL based on naming convention // Determine if MySQL or PostgreSQL based on naming convention
if strings.Contains(lower, "mysql") || strings.Contains(lower, "mariadb") { if strings.Contains(lower, "mysql") || strings.Contains(lower, "mariadb") {
@ -60,6 +72,36 @@ func DetectArchiveFormat(filename string) ArchiveFormat {
return FormatUnknown return FormatUnknown
} }
// isCustomFormat checks if a file is PostgreSQL custom format (has PGDMP signature)
func isCustomFormat(filename string, compressed bool) bool {
file, err := os.Open(filename)
if err != nil {
return false
}
defer file.Close()
var reader io.Reader = file
// Handle compression
if compressed {
gz, err := gzip.NewReader(file)
if err != nil {
return false
}
defer gz.Close()
reader = gz
}
// Read first 5 bytes to check for PGDMP signature
buffer := make([]byte, 5)
n, err := reader.Read(buffer)
if err != nil || n < 5 {
return false
}
return string(buffer) == "PGDMP"
}
// IsCompressed returns true if the archive format is compressed // IsCompressed returns true if the archive format is compressed
func (f ArchiveFormat) IsCompressed() bool { func (f ArchiveFormat) IsCompressed() bool {
return f == FormatPostgreSQLDumpGz || return f == FormatPostgreSQLDumpGz ||