@@ -1405,3 +1405,215 @@ calc_file_checksum(pgFile *file)
1405
1405
1406
1406
return true;
1407
1407
}
1408
+
1409
+ /* Validate given page
1410
+ * return value:
1411
+ * 0 - if the page is not found
1412
+ * 1 - if the page is found and valid
1413
+ * -1 - if the page is found but invalid
1414
+ */
1415
+ #define PAGE_IS_NOT_FOUND 0
1416
+ #define PAGE_IS_FOUND_AND_VALID 1
1417
+ #define PAGE_IS_FOUND_AND__NOT_VALID -1
1418
+ static int
1419
+ validate_one_page (Page page , pgFile * file ,
1420
+ BlockNumber blknum , XLogRecPtr stop_lsn ,
1421
+ uint32 checksum_version )
1422
+ {
1423
+ PageHeader phdr ;
1424
+ XLogRecPtr lsn ;
1425
+ bool page_header_is_sane = false;
1426
+ bool checksum_is_ok = false;
1427
+
1428
+ /* new level of paranoia */
1429
+ if (page == NULL )
1430
+ {
1431
+ elog (LOG , "File %s, block %u, page is NULL" ,
1432
+ file -> path , blknum );
1433
+ return PAGE_IS_NOT_FOUND ;
1434
+ }
1435
+
1436
+ if (PageIsNew (page ))
1437
+ {
1438
+ int i ;
1439
+ /* Check if the page is zeroed. */
1440
+ for (i = 0 ; i < BLCKSZ && page [i ] == 0 ; i ++ );
1441
+
1442
+ if (i == BLCKSZ )
1443
+ {
1444
+ elog (LOG , "File: %s blknum %u, page is New. empty zeroed page" ,
1445
+ file -> path , blknum );
1446
+ return PAGE_IS_FOUND_AND_VALID ;
1447
+ }
1448
+ else
1449
+ {
1450
+ elog (WARNING , "File: %s, block %u, page is New, but not zeroed" ,
1451
+ file -> path , blknum );
1452
+ }
1453
+
1454
+ /* Page is zeroed. No sense to check header and checksum. */
1455
+ page_header_is_sane = false;
1456
+ }
1457
+ else
1458
+ {
1459
+ phdr = (PageHeader ) page ;
1460
+
1461
+ if (PageGetPageSize (phdr ) == BLCKSZ &&
1462
+ PageGetPageLayoutVersion (phdr ) == PG_PAGE_LAYOUT_VERSION &&
1463
+ (phdr -> pd_flags & ~PD_VALID_FLAG_BITS ) == 0 &&
1464
+ phdr -> pd_lower >= SizeOfPageHeaderData &&
1465
+ phdr -> pd_lower <= phdr -> pd_upper &&
1466
+ phdr -> pd_upper <= phdr -> pd_special &&
1467
+ phdr -> pd_special <= BLCKSZ &&
1468
+ phdr -> pd_special == MAXALIGN (phdr -> pd_special ))
1469
+ page_header_is_sane = true;
1470
+ }
1471
+
1472
+ if (page_header_is_sane )
1473
+ {
1474
+ /* Verify checksum */
1475
+ if (checksum_version )
1476
+ {
1477
+ /*
1478
+ * If checksum is wrong, sleep a bit and then try again
1479
+ * several times. If it didn't help, throw error
1480
+ */
1481
+ if (pg_checksum_page (page , file -> segno * RELSEG_SIZE + blknum )
1482
+ == ((PageHeader ) page )-> pd_checksum )
1483
+ {
1484
+ checksum_is_ok = true;
1485
+ }
1486
+ else
1487
+ {
1488
+ elog (WARNING , "File: %s blknum %u have wrong checksum" ,
1489
+ file -> path , blknum );
1490
+ }
1491
+ }
1492
+
1493
+ if (!checksum_version )
1494
+ {
1495
+ /* Get lsn from page header. Ensure that page is from our time */
1496
+ lsn = PageXLogRecPtrGet (phdr -> pd_lsn );
1497
+
1498
+ if (lsn > stop_lsn )
1499
+ elog (WARNING , "File: %s, block %u, checksum is not enabled."
1500
+ "page is from future: pageLSN %X/%X stopLSN %X/%X" ,
1501
+ file -> path , blknum , (uint32 ) (lsn >> 32 ), (uint32 ) lsn ,
1502
+ (uint32 ) (stop_lsn >> 32 ), (uint32 ) stop_lsn );
1503
+ else
1504
+ return PAGE_IS_FOUND_AND_VALID ;
1505
+ }
1506
+
1507
+ if (checksum_is_ok )
1508
+ {
1509
+ /* Get lsn from page header. Ensure that page is from our time */
1510
+ lsn = PageXLogRecPtrGet (phdr -> pd_lsn );
1511
+
1512
+ if (lsn > stop_lsn )
1513
+ elog (WARNING , "File: %s, block %u, checksum is correct."
1514
+ "page is from future: pageLSN %X/%X stopLSN %X/%X" ,
1515
+ file -> path , blknum , (uint32 ) (lsn >> 32 ), (uint32 ) lsn ,
1516
+ (uint32 ) (stop_lsn >> 32 ), (uint32 ) stop_lsn );
1517
+ else
1518
+ return PAGE_IS_FOUND_AND_VALID ;
1519
+ }
1520
+ }
1521
+
1522
+ return PAGE_IS_FOUND_AND__NOT_VALID ;
1523
+ }
1524
+
1525
+ /* Valiate pages of datafile in backup one by one */
1526
+ bool
1527
+ check_file_pages (pgFile * file , XLogRecPtr stop_lsn , uint32 checksum_version )
1528
+ {
1529
+ size_t read_len = 0 ;
1530
+ bool is_valid = true;
1531
+ FILE * in ;
1532
+
1533
+ elog (VERBOSE , "validate relation blocks for file %s" , file -> name );
1534
+
1535
+ in = fopen (file -> path , PG_BINARY_R );
1536
+ if (in == NULL )
1537
+ {
1538
+ if (errno == ENOENT )
1539
+ {
1540
+ elog (WARNING , "File \"%s\" is not found" , file -> path );
1541
+ return false;
1542
+ }
1543
+
1544
+ elog (ERROR , "cannot open file \"%s\": %s" ,
1545
+ file -> path , strerror (errno ));
1546
+ }
1547
+
1548
+ /* read and validate pages one by one */
1549
+ while (true)
1550
+ {
1551
+ Page compressed_page = NULL ; /* used as read buffer */
1552
+ Page page = NULL ;
1553
+ BackupPageHeader header ;
1554
+ BlockNumber blknum ;
1555
+
1556
+ /* read BackupPageHeader */
1557
+ read_len = fread (& header , 1 , sizeof (header ), in );
1558
+ if (read_len != sizeof (header ))
1559
+ {
1560
+ int errno_tmp = errno ;
1561
+ if (read_len == 0 && feof (in ))
1562
+ break ; /* EOF found */
1563
+ else if (read_len != 0 && feof (in ))
1564
+ elog (ERROR ,
1565
+ "odd size page found at block %u of \"%s\"" ,
1566
+ blknum , file -> path );
1567
+ else
1568
+ elog (ERROR , "cannot read header of block %u of \"%s\": %s" ,
1569
+ blknum , file -> path , strerror (errno_tmp ));
1570
+ }
1571
+
1572
+ if (header .block < blknum )
1573
+ elog (ERROR , "backup is broken at file->path %s block %u" ,
1574
+ file -> path , blknum );
1575
+
1576
+ blknum = header .block ;
1577
+
1578
+ if (header .compressed_size == PageIsTruncated )
1579
+ {
1580
+ elog (LOG , "File %s, block %u is truncated" ,
1581
+ file -> path , blknum );
1582
+ continue ;
1583
+ }
1584
+
1585
+ Assert (header .compressed_size <= BLCKSZ );
1586
+
1587
+ read_len = fread (compressed_page , 1 ,
1588
+ MAXALIGN (header .compressed_size ), in );
1589
+ if (read_len != MAXALIGN (header .compressed_size ))
1590
+ elog (ERROR , "cannot read block %u of \"%s\" read %lu of %d" ,
1591
+ blknum , file -> path , read_len , header .compressed_size );
1592
+
1593
+ if (header .compressed_size != BLCKSZ )
1594
+ {
1595
+ int32 uncompressed_size = 0 ;
1596
+
1597
+ uncompressed_size = do_decompress (page , BLCKSZ ,
1598
+ compressed_page ,
1599
+ MAXALIGN (header .compressed_size ),
1600
+ file -> compress_alg );
1601
+
1602
+ if (uncompressed_size != BLCKSZ )
1603
+ elog (ERROR , "page of file \"%s\" uncompressed to %d bytes. != BLCKSZ" ,
1604
+ file -> path , uncompressed_size );
1605
+
1606
+ if (validate_one_page (page , file , blknum ,
1607
+ stop_lsn , checksum_version ) == PAGE_IS_FOUND_AND__NOT_VALID )
1608
+ is_valid = false;
1609
+ }
1610
+ else
1611
+ {
1612
+ if (validate_one_page (compressed_page , file , blknum ,
1613
+ stop_lsn , checksum_version ) == PAGE_IS_FOUND_AND__NOT_VALID )
1614
+ is_valid = false;
1615
+ }
1616
+ }
1617
+
1618
+ return is_valid ;
1619
+ }
0 commit comments