diff --git a/dbbackup b/dbbackup index 9f35671..b71c77e 100755 Binary files a/dbbackup and b/dbbackup differ diff --git a/internal/restore/formats.go b/internal/restore/formats.go index d9e4ade..db558dc 100644 --- a/internal/restore/formats.go +++ b/internal/restore/formats.go @@ -1,6 +1,9 @@ package restore import ( + "compress/gzip" + "io" + "os" "strings" ) @@ -18,7 +21,7 @@ const ( 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 { lower := strings.ToLower(filename) @@ -27,11 +30,24 @@ func DetectArchiveFormat(filename string) ArchiveFormat { 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") { - 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") { // Determine if MySQL or PostgreSQL based on naming convention if strings.Contains(lower, "mysql") || strings.Contains(lower, "mariadb") { @@ -40,11 +56,7 @@ func DetectArchiveFormat(filename string) ArchiveFormat { return FormatPostgreSQLSQLGz } - // Check for uncompressed formats - if strings.HasSuffix(lower, ".dump") { - return FormatPostgreSQLDump - } - + // Check for uncompressed SQL formats if strings.HasSuffix(lower, ".sql") { // Determine if MySQL or PostgreSQL based on naming convention if strings.Contains(lower, "mysql") || strings.Contains(lower, "mariadb") { @@ -60,6 +72,36 @@ func DetectArchiveFormat(filename string) ArchiveFormat { 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 func (f ArchiveFormat) IsCompressed() bool { return f == FormatPostgreSQLDumpGz ||