diff --git a/pg_checksums.c b/pg_checksums.c index dbe79e6..d7fc320 100644 --- a/pg_checksums.c +++ b/pg_checksums.c @@ -53,6 +53,9 @@ extern char *optarg; #define INT64_MODIFIER "l" #endif +#define PG_TEMP_FILES_DIR "pgsql_tmp" +#define PG_TEMP_FILE_PREFIX "pgsql_tmp" + static int64 files = 0; static int64 blocks = 0; static int64 skippedblocks = 0; @@ -114,7 +117,6 @@ usage(void) printf(_("Report bugs to https://github.com/credativ/pg_checksums/issues/new.\n")); } - /* * isRelFileName * @@ -464,7 +466,20 @@ scan_directory(const char *basedir, const char *subdir, bool sizeonly) char fn[MAXPGPATH]; struct stat st; - if (!isRelFileName(de->d_name)) + if (strcmp(de->d_name, ".") == 0 || + strcmp(de->d_name, "..") == 0) + continue; + + /* Skip temporary files */ + if (strncmp(de->d_name, + PG_TEMP_FILE_PREFIX, + strlen(PG_TEMP_FILE_PREFIX)) == 0) + continue; + + /* Skip temporary folders */ + if (strncmp(de->d_name, + PG_TEMP_FILES_DIR, + strlen(PG_TEMP_FILES_DIR)) == 0) continue; snprintf(fn, sizeof(fn), "%s/%s", path, de->d_name); @@ -490,6 +505,13 @@ scan_directory(const char *basedir, const char *subdir, bool sizeonly) *segmentpath; BlockNumber segmentno = 0; + /* + * Only normal relation files can be analyzed. Note that this + * skips temporary relations. + */ + if (!isRelFileName(de->d_name)) + continue; + /* * Cut off at the segment boundary (".") to get the segment number * in order to mix it into the checksum. Then also cut off at the diff --git a/t/001_checksums.pl b/t/001_checksums.pl index 16fc28f..2b11827 100644 --- a/t/001_checksums.pl +++ b/t/001_checksums.pl @@ -6,7 +6,7 @@ use Config; use PostgresNode; use TestLib; -use Test::More tests => 44; +use Test::More tests => 49; program_help_ok('pg_checksums'); program_version_ok('pg_checksums'); @@ -80,34 +80,73 @@ $node->command_ok(['pg_checksums', '-a', '-D', $pgdata], 'pg_checksums are again activated in offline cluster'); +#exit 0; $node->start; $node->command_ok(['pg_checksums', '-c', '-D', $pgdata], 'pg_checksums can be verified in online cluster'); # create table to corrupt and get their relfilenode -my $file_corrupt = $node->safe_psql('postgres', - q{SELECT a INTO corrupt1 FROM generate_series(1,10000) AS a; ALTER TABLE corrupt1 SET (autovacuum_enabled=false); SELECT pg_relation_filepath('corrupt1')} +create_corruption($node, 'corrupt1', 'pg_default'); + +$node->command_checks_all([ 'pg_checksums', '-c', '-D', $pgdata], + 1, + [qr/Bad checksums: 1/s], + [qr/checksum verification failed/s], + 'pg_checksums reports checksum mismatch' ); -# set page header and block sizes -my $pageheader_size = 24; -my $block_size = $node->safe_psql('postgres', 'SHOW block_size;'); +# drop corrupt table again and make sure there is no more corruption +$node->safe_psql('postgres', 'DROP TABLE corrupt1;'); +$node->command_ok(['pg_checksums', '-c', '-D', $pgdata], + 'pg_checksums can be verified in online cluster: '.getcwd()); -# induce corruption -$node->stop; -open my $file, '+<', "$pgdata/$file_corrupt"; -seek($file, $pageheader_size, 0); -syswrite($file, '\0\0\0\0\0\0\0\0\0'); -close $file; + +# create table to corrupt in a non-default tablespace and get their relfilenode +my $tablespace_dir = getcwd()."/tmp_check/ts_corrupt_dir"; +mkdir ($tablespace_dir); +$node->safe_psql('postgres', "CREATE TABLESPACE ts_corrupt LOCATION '".$tablespace_dir."';"); +create_corruption($node, 'corrupt2', 'ts_corrupt'); $node->command_checks_all([ 'pg_checksums', '-c', '-D', $pgdata], 1, [qr/Bad checksums: 1/s], [qr/checksum verification failed/s], - 'pg_checksums reports checksum mismatch' + 'pg_checksums reports checksum mismatch on non-default tablespace' ); +# drop corrupt table again and make sure there is no more corruption +$node->safe_psql('postgres', 'DROP TABLE corrupt2;'); +$node->command_ok(['pg_checksums', '-c', '-D', $pgdata], + 'pg_checksums can be verified in online cluster'); + +# Utility routine to create a table with corrupted checksums. +# It stops the node (if running), and starts it again. +sub create_corruption +{ + my $node = shift; + my $table = shift; + my $tablespace = shift; + + my $query = "SELECT a INTO ".$table." FROM generate_series(1,10000) AS a; ALTER TABLE ".$table." SET (autovacuum_enabled=false), SET TABLESPACE ".$tablespace."; SELECT pg_relation_filepath('".$table."')"; + my $file_name = $node->safe_psql('postgres', $query); + + # set page header and block sizes + my $pageheader_size = 24; + my $block_size = $node->safe_psql('postgres', 'SHOW block_size;'); + + $node->stop; + + open my $file, '+<', "$pgdata/$file_name"; + seek($file, $pageheader_size, 0); + syswrite($file, '\0\0\0\0\0\0\0\0\0'); + close $file; + + $node->start; + + return; +} + # Utility routine to check that pg_checksums is able to detect # correctly-named relation files filled with some corrupted data. sub fail_corrupt