diff --git a/pg_filedump.c b/pg_filedump.c index f3650da..0bee1e3 100644 --- a/pg_filedump.c +++ b/pg_filedump.c @@ -83,9 +83,34 @@ static unsigned int bytesToFormat = 0; /* Block version number */ static unsigned int blockVersion = 0; +/* Flag to indicate filemap file */ +static unsigned int isMapperFile = 0; + /* Program exit code */ static int exitCode = 0; +/* Relmapper structs */ +/* Maybe ask community to put this into utils/relmapper.h? */ +#define RELMAPPER_FILEMAGIC 0x592717 +char magic_buffer[8]; +char relmap_file[512]; +typedef struct RelMapping +{ + Oid mapoid; /* OID of a catalog */ + Oid mapfilenode; /* its filenode number */ +} RelMapping; + +/* crc and pad are ignored here, even though they are + * present in the backend code. We assume that anyone + * seeking to inspect the contents of pg_filenode.map + * probably have a corrupted or non-functional cluster */ +typedef struct RelMapFile +{ + int32 magic; /* always RELMAPPER_FILEMAGIC */ + int32 num_mappings; /* number of valid RelMapping entries */ + RelMapping mappings[FLEXIBLE_ARRAY_MEMBER]; +} RelMapFile; + /* * Function Prototypes */ @@ -127,6 +152,8 @@ static void FormatControl(char *buffer); static void FormatBinary(char *buffer, unsigned int numBytes, unsigned int startIndex); static void DumpBinaryBlock(char *buffer); +static int CheckForRelmap(FILE *fp); +static int PrintMappings(RelMapFile *map); /* Send properly formed usage information to the user. */ @@ -179,6 +206,7 @@ DisplayOptions(unsigned int validOptions) " -c Interpret the file listed as a control file\n" " -f Display formatted content dump along with interpretation\n" " -S Force block size to [blocksize]\n" + "If a pg_filenode.map file is passed in, all options will be ignored\n" "\nReport bugs to \n"); } @@ -430,6 +458,7 @@ ConsumeOptions(int numOptions, char **options) fileName = options[x]; if (!(segmentOptions & SEGMENT_NUMBER_FORCED)) segmentNumber = GetSegmentNumberFromFileName(fileName); + isMapperFile = CheckForRelmap(fp); } else { @@ -2000,6 +2029,44 @@ DumpFileContents(unsigned int blockOptions, return result; } +int +CheckForRelmap(FILE *fp) +{ + // Get the first 8 bytes for comparison + fread(magic_buffer,1,8,fp); + // Put things back where we found them + rewind(fp); + + // If it's a relmapper file, then ingest the whole thing + if ( (int) magic_buffer & RELMAPPER_FILEMAGIC ) { + fread(relmap_file,1,512,fp); + return 1; + } + return 0; +} + +int +PrintMappings(RelMapFile *map) +{ + RelMapping *mappings; + RelMapping m; + + // Print Metadata + printf("Magic Number: %x\n",map->magic); + printf("Num Mappings: %d\n",map->num_mappings); + + // Print Mappings + printf("Detailed Mappings list:\n"); + mappings = map->mappings; + for (int i=0; i < map->num_mappings; i++) { + m = mappings[i]; + printf("OID: %u\tFilenode: %u\n", + m.mapoid, + m.mapfilenode); + } + return 1; +} + /* Consume the options and iterate through the given file, formatting as * requested. */ int @@ -2030,17 +2097,21 @@ main(int argv, char **argc) else if (!(blockOptions & BLOCK_FORCED)) blockSize = GetBlockSize(fp); - exitCode = DumpFileContents(blockOptions, - controlOptions, - fp, - blockSize, - blockStart, - blockEnd, - false /* is toast realtion */, - 0, /* no toast Oid */ - 0, /* no toast external size */ - NULL /* no out toast value */ - ); + if (isMapperFile) { + exitCode = PrintMappings((RelMapFile *) relmap_file); + } else { + exitCode = DumpFileContents(blockOptions, + controlOptions, + fp, + blockSize, + blockStart, + blockEnd, + false /* is toast realtion */, + 0, /* no toast Oid */ + 0, /* no toast external size */ + NULL /* no out toast value */ + ); + } } if (fp)