Fix checksum validation for relations that have more than one segment.
A blkno argument passed to pg_checksum_page procedure should be not a relative block number in a given segment but an absolute block number in the entire relation. It's the same for the segment number 0, but for segment number N the difference is RELSEG_SIZE * N. Aleksander Alekseev
This commit is contained in:
		| @ -59,7 +59,7 @@ not require any manual adjustments of the Makefile. | ||||
| ------------------------------------------------------------------------ | ||||
| Invocation: | ||||
|  | ||||
| pg_filedump [-abcdfhikxy] [-R startblock [endblock]] [-S blocksize] file | ||||
| pg_filedump [-abcdfhikxy] [-R startblock [endblock]] [-S blocksize] [-s segsize] [-n segnumber] file | ||||
|  | ||||
| Defaults are: relative addressing, range of the entire file, block size | ||||
|               as listed on block 0 in the file | ||||
| @ -80,6 +80,8 @@ The following options are valid for heap and index files: | ||||
|         [startblock]: block to start at | ||||
|         [endblock]: block to end at | ||||
|       A startblock without an endblock will format the single block | ||||
|   -s  Force segment size to [segsize] | ||||
|   -n  Force segment number to [segnumber] | ||||
|   -S  Force block size to [blocksize] | ||||
|   -x  Force interpreted formatting of block items as index items | ||||
|   -y  Force interpreted formatting of block items as heap items | ||||
|  | ||||
							
								
								
									
										105
									
								
								pg_filedump.c
									
									
									
									
									
								
							
							
						
						
									
										105
									
								
								pg_filedump.c
									
									
									
									
									
								
							| @ -52,6 +52,12 @@ static unsigned int blockSize = 0; | ||||
| /* Current block in file */ | ||||
| static unsigned int currentBlock = 0; | ||||
|  | ||||
| /* Segment size in bytes */ | ||||
| static unsigned int segmentSize = RELSEG_SIZE * BLCKSZ; | ||||
|  | ||||
| /* Number of current segment */ | ||||
| static unsigned int segmentNumber = 0; | ||||
|  | ||||
| /* Offset of current block */ | ||||
| static unsigned int pageOffset = 0; | ||||
|  | ||||
| @ -95,7 +101,7 @@ DisplayOptions(unsigned int validOptions) | ||||
| 			 FD_VERSION, FD_PG_VERSION); | ||||
|  | ||||
| 	printf | ||||
| 		("\nUsage: pg_filedump [-abcdfhikxy] [-R startblock [endblock]] [-S blocksize] file\n\n" | ||||
| 		("\nUsage: pg_filedump [-abcdfhikxy] [-R startblock [endblock]] [-S blocksize] [-s segsize] [-n segnumber] file\n\n" | ||||
| 	   "Display formatted contents of a PostgreSQL heap/index/control file\n" | ||||
| 	   "Defaults are: relative addressing, range of the entire file, block\n" | ||||
| 		 "               size as listed on block 0 in the file\n\n" | ||||
| @ -114,6 +120,8 @@ DisplayOptions(unsigned int validOptions) | ||||
| 		 "      indexed from 0)\n" "        [startblock]: block to start at\n" | ||||
| 		 "        [endblock]: block to end at\n" | ||||
| 	  "      A startblock without an endblock will format the single block\n" | ||||
| 		 "  -s  Force segment size to [segsize]\n" | ||||
| 		 "  -n  Force segment number to [segnumber]\n" | ||||
| 		 "  -S  Force block size to [blocksize]\n" | ||||
| 		 "  -x  Force interpreted formatting of block items as index items\n" | ||||
| 		 "  -y  Force interpreted formatting of block items as heap items\n\n" | ||||
| @ -124,6 +132,31 @@ DisplayOptions(unsigned int validOptions) | ||||
| 		 "\nReport bugs to <pgsql-bugs@postgresql.org>\n"); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Determine segment number by segment file name. For instance, if file | ||||
|  * name is /path/to/xxxx.7 procedure returns 7. Default return value is 0. | ||||
|  */ | ||||
| static unsigned int | ||||
| GetSegmentNumberFromFileName(const char* fileName) | ||||
| { | ||||
| 	int segnumOffset = strlen(fileName) - 1; | ||||
|  | ||||
| 	if(segnumOffset < 0) | ||||
| 		return 0; | ||||
|  | ||||
| 	while(isdigit(fileName[segnumOffset])) | ||||
| 	{ | ||||
| 		segnumOffset--; | ||||
| 		if(segnumOffset < 0) | ||||
| 			return 0; | ||||
| 	} | ||||
|  | ||||
| 	if(fileName[segnumOffset] != '.') | ||||
| 		return 0; | ||||
|  | ||||
|     return atoi(&fileName[segnumOffset+1]); | ||||
| } | ||||
|  | ||||
| /*	Iterate through the provided options and set the option flags. */ | ||||
| /*	An error will result in a positive rc and will force a display */ | ||||
| /*	of the usage information.  This routine returns enum */ | ||||
| @ -235,6 +268,69 @@ ConsumeOptions(int numOptions, char **options) | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 		/* Check for the special case where the user forces a segment size. */ | ||||
| 		else if ((optionStringLength == 2) | ||||
| 				 && (strcmp(optionString, "-s") == 0)) | ||||
| 		{ | ||||
| 			int			localSegmentSize; | ||||
|  | ||||
| 			SET_OPTION(segmentOptions, SEGMENT_SIZE_FORCED, 's'); | ||||
| 			/* Only accept the forced size option once */ | ||||
| 			if (rc == OPT_RC_DUPLICATE) | ||||
| 				break; | ||||
|  | ||||
| 			/* The token immediately following -s is the segment size */ | ||||
| 			if (x >= (numOptions - 2)) | ||||
| 			{ | ||||
| 				rc = OPT_RC_INVALID; | ||||
| 				printf("Error: Missing segment size identifier.\n"); | ||||
| 				break; | ||||
| 			} | ||||
|  | ||||
| 			/* Next option encountered must be forced segment size */ | ||||
| 			optionString = options[++x]; | ||||
| 			if ((localSegmentSize = GetOptionValue(optionString)) > 0) | ||||
| 				segmentSize = (unsigned int) localSegmentSize; | ||||
| 			else | ||||
| 			{ | ||||
| 				rc = OPT_RC_INVALID; | ||||
| 				printf("Error: Invalid segment size requested <%s>.\n", | ||||
| 					   optionString); | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 		/* Check for the special case where the user forces a segment number */ | ||||
| 		/* instead of having the tool determine it by file name. */ | ||||
| 		else if ((optionStringLength == 2) | ||||
| 				 && (strcmp(optionString, "-n") == 0)) | ||||
| 		{ | ||||
| 			int			localSegmentNumber; | ||||
|  | ||||
| 			SET_OPTION(segmentOptions, SEGMENT_NUMBER_FORCED, 'n'); | ||||
| 			/* Only accept the forced segment number option once */ | ||||
| 			if (rc == OPT_RC_DUPLICATE) | ||||
| 				break; | ||||
|  | ||||
| 			/* The token immediately following -n is the segment number */ | ||||
| 			if (x >= (numOptions - 2)) | ||||
| 			{ | ||||
| 				rc = OPT_RC_INVALID; | ||||
| 				printf("Error: Missing segment number identifier.\n"); | ||||
| 				break; | ||||
| 			} | ||||
|  | ||||
| 			/* Next option encountered must be forced segment number */ | ||||
| 			optionString = options[++x]; | ||||
| 			if ((localSegmentNumber = GetOptionValue(optionString)) > 0) | ||||
| 				segmentNumber = (unsigned int) localSegmentNumber; | ||||
| 			else | ||||
| 			{ | ||||
| 				rc = OPT_RC_INVALID; | ||||
| 				printf("Error: Invalid segment number requested <%s>.\n", | ||||
| 					   optionString); | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 		/* The last option MUST be the file name */ | ||||
| 		else if (x == (numOptions - 1)) | ||||
| 		{ | ||||
| @ -243,7 +339,11 @@ ConsumeOptions(int numOptions, char **options) | ||||
| 			{ | ||||
| 				fp = fopen(optionString, "rb"); | ||||
| 				if (fp) | ||||
| 				{ | ||||
| 					fileName = options[x]; | ||||
| 					if(!(segmentOptions & SEGMENT_NUMBER_FORCED)) | ||||
| 						segmentNumber = GetSegmentNumberFromFileName(fileName); | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					rc = OPT_RC_FILE; | ||||
| @ -691,7 +791,8 @@ FormatHeader(Page page, BlockNumber blkno) | ||||
|  | ||||
| 		if (blockOptions & BLOCK_CHECKSUMS) | ||||
| 		{ | ||||
| 			uint16		calc_checksum = pg_checksum_page(page, blkno); | ||||
| 			uint32	delta = (segmentSize/blockSize)*segmentNumber; | ||||
| 			uint16	calc_checksum = pg_checksum_page(page, delta + blkno); | ||||
|  | ||||
| 			if (calc_checksum != pageHeader->pd_checksum) | ||||
| 				printf(" Error: checksum failure: calculated 0x%04x.\n\n", | ||||
|  | ||||
| @ -55,6 +55,15 @@ typedef enum blockSwitches | ||||
| 	BLOCK_CHECKSUMS = 0x00000040	/* -k: verify block checksums */ | ||||
| } blockSwitches; | ||||
|  | ||||
| /* Segment-related options */ | ||||
| static unsigned int segmentOptions = 0; | ||||
|  | ||||
| typedef enum segmentSwitches | ||||
| { | ||||
| 	SEGMENT_SIZE_FORCED = 0x00000001,	/* -s: Segment size forced */ | ||||
| 	SEGMENT_NUMBER_FORCED = 0x00000002,	/* -n: Segment number forced */ | ||||
| } segmentSwitches; | ||||
|  | ||||
| /* -R[start]:Block range start */ | ||||
| static int	blockStart = -1; | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user