@@ -160,7 +160,14 @@ int max_safe_fds = 32; /* default if not changed */
160
160
161
161
#define FileIsNotOpen (file ) (VfdCache[file].fd == VFD_CLOSED)
162
162
163
+ /*
164
+ * Note: a VFD's seekPos is normally always valid, but if for some reason
165
+ * an lseek() fails, it might become set to FileUnknownPos. We can struggle
166
+ * along without knowing the seek position in many cases, but in some places
167
+ * we have to fail if we don't have it.
168
+ */
163
169
#define FileUnknownPos ((off_t) -1)
170
+ #define FilePosIsUnknown (pos ) ((pos) < 0)
164
171
165
172
/* these are the assigned bits in fdstate below: */
166
173
#define FD_TEMPORARY (1 << 0) /* T = delete when closed */
@@ -174,7 +181,7 @@ typedef struct vfd
174
181
File nextFree ; /* link to next free VFD, if in freelist */
175
182
File lruMoreRecently ; /* doubly linked recency-of-use list */
176
183
File lruLessRecently ;
177
- off_t seekPos ; /* current logical file position */
184
+ off_t seekPos ; /* current logical file position, or -1 */
178
185
off_t fileSize ; /* current size of file (0 if not temporary) */
179
186
char * fileName ; /* name of file, or NULL for unused VFD */
180
187
/* NB: fileName is malloc'd, and must be free'd when closing the VFD */
@@ -967,19 +974,33 @@ LruDelete(File file)
967
974
968
975
vfdP = & VfdCache [file ];
969
976
970
- /* delete the vfd record from the LRU ring */
971
- Delete (file );
972
-
973
- /* save the seek position */
974
- vfdP -> seekPos = lseek (vfdP -> fd , (off_t ) 0 , SEEK_CUR );
975
- Assert (vfdP -> seekPos != (off_t ) - 1 );
977
+ /*
978
+ * Normally we should know the seek position, but if for some reason we
979
+ * have lost track of it, try again to get it. If we still can't get it,
980
+ * we have a problem: we will be unable to restore the file seek position
981
+ * when and if the file is re-opened. But we can't really throw an error
982
+ * and refuse to close the file, or activities such as transaction cleanup
983
+ * will be broken.
984
+ */
985
+ if (FilePosIsUnknown (vfdP -> seekPos ))
986
+ {
987
+ vfdP -> seekPos = lseek (vfdP -> fd , (off_t ) 0 , SEEK_CUR );
988
+ if (FilePosIsUnknown (vfdP -> seekPos ))
989
+ elog (LOG , "could not seek file \"%s\" before closing: %m" ,
990
+ vfdP -> fileName );
991
+ }
976
992
977
- /* close the file */
993
+ /*
994
+ * Close the file. We aren't expecting this to fail; if it does, better
995
+ * to leak the FD than to mess up our internal state.
996
+ */
978
997
if (close (vfdP -> fd ))
979
- elog (ERROR , "could not close file \"%s\": %m" , vfdP -> fileName );
980
-
981
- -- nfile ;
998
+ elog (LOG , "could not close file \"%s\": %m" , vfdP -> fileName );
982
999
vfdP -> fd = VFD_CLOSED ;
1000
+ -- nfile ;
1001
+
1002
+ /* delete the vfd record from the LRU ring */
1003
+ Delete (file );
983
1004
}
984
1005
985
1006
static void
@@ -1030,22 +1051,39 @@ LruInsert(File file)
1030
1051
vfdP -> fileMode );
1031
1052
if (vfdP -> fd < 0 )
1032
1053
{
1033
- DO_DB (elog (LOG , "RE_OPEN FAILED : %d" , errno ));
1054
+ DO_DB (elog (LOG , "re-open failed : %m" ));
1034
1055
return -1 ;
1035
1056
}
1036
1057
else
1037
1058
{
1038
- DO_DB (elog (LOG , "RE_OPEN SUCCESS" ));
1039
1059
++ nfile ;
1040
1060
}
1041
1061
1042
- /* seek to the right position */
1062
+ /*
1063
+ * Seek to the right position. We need no special case for seekPos
1064
+ * equal to FileUnknownPos, as lseek() will certainly reject that
1065
+ * (thus completing the logic noted in LruDelete() that we will fail
1066
+ * to re-open a file if we couldn't get its seek position before
1067
+ * closing).
1068
+ */
1043
1069
if (vfdP -> seekPos != (off_t ) 0 )
1044
1070
{
1045
- off_t returnValue PG_USED_FOR_ASSERTS_ONLY ;
1046
-
1047
- returnValue = lseek (vfdP -> fd , vfdP -> seekPos , SEEK_SET );
1048
- Assert (returnValue != (off_t ) - 1 );
1071
+ if (lseek (vfdP -> fd , vfdP -> seekPos , SEEK_SET ) < 0 )
1072
+ {
1073
+ /*
1074
+ * If we fail to restore the seek position, treat it like an
1075
+ * open() failure.
1076
+ */
1077
+ int save_errno = errno ;
1078
+
1079
+ elog (LOG , "could not seek file \"%s\" after re-opening: %m" ,
1080
+ vfdP -> fileName );
1081
+ (void ) close (vfdP -> fd );
1082
+ vfdP -> fd = VFD_CLOSED ;
1083
+ -- nfile ;
1084
+ errno = save_errno ;
1085
+ return -1 ;
1086
+ }
1049
1087
}
1050
1088
}
1051
1089
@@ -1428,15 +1466,15 @@ FileClose(File file)
1428
1466
1429
1467
if (!FileIsNotOpen (file ))
1430
1468
{
1431
- /* remove the file from the lru ring */
1432
- Delete (file );
1433
-
1434
1469
/* close the file */
1435
1470
if (close (vfdP -> fd ))
1436
- elog (ERROR , "could not close file \"%s\": %m" , vfdP -> fileName );
1471
+ elog (LOG , "could not close file \"%s\": %m" , vfdP -> fileName );
1437
1472
1438
1473
-- nfile ;
1439
1474
vfdP -> fd = VFD_CLOSED ;
1475
+
1476
+ /* remove the file from the lru ring */
1477
+ Delete (file );
1440
1478
}
1441
1479
1442
1480
/*
@@ -1566,6 +1604,7 @@ int
1566
1604
FileRead (File file , char * buffer , int amount )
1567
1605
{
1568
1606
int returnCode ;
1607
+ Vfd * vfdP ;
1569
1608
1570
1609
Assert (FileIsValid (file ));
1571
1610
@@ -1578,11 +1617,17 @@ FileRead(File file, char *buffer, int amount)
1578
1617
if (returnCode < 0 )
1579
1618
return returnCode ;
1580
1619
1620
+ vfdP = & VfdCache [file ];
1621
+
1581
1622
retry :
1582
- returnCode = read (VfdCache [ file ]. fd , buffer , amount );
1623
+ returnCode = read (vfdP -> fd , buffer , amount );
1583
1624
1584
1625
if (returnCode >= 0 )
1585
- VfdCache [file ].seekPos += returnCode ;
1626
+ {
1627
+ /* if seekPos is unknown, leave it that way */
1628
+ if (!FilePosIsUnknown (vfdP -> seekPos ))
1629
+ vfdP -> seekPos += returnCode ;
1630
+ }
1586
1631
else
1587
1632
{
1588
1633
/*
@@ -1611,7 +1656,7 @@ FileRead(File file, char *buffer, int amount)
1611
1656
goto retry ;
1612
1657
1613
1658
/* Trouble, so assume we don't know the file position anymore */
1614
- VfdCache [ file ]. seekPos = FileUnknownPos ;
1659
+ vfdP -> seekPos = FileUnknownPos ;
1615
1660
}
1616
1661
1617
1662
return returnCode ;
@@ -1621,6 +1666,7 @@ int
1621
1666
FileWrite (File file , char * buffer , int amount )
1622
1667
{
1623
1668
int returnCode ;
1669
+ Vfd * vfdP ;
1624
1670
1625
1671
Assert (FileIsValid (file ));
1626
1672
@@ -1633,6 +1679,8 @@ FileWrite(File file, char *buffer, int amount)
1633
1679
if (returnCode < 0 )
1634
1680
return returnCode ;
1635
1681
1682
+ vfdP = & VfdCache [file ];
1683
+
1636
1684
/*
1637
1685
* If enforcing temp_file_limit and it's a temp file, check to see if the
1638
1686
* write would overrun temp_file_limit, and throw error if so. Note: it's
@@ -1641,15 +1689,28 @@ FileWrite(File file, char *buffer, int amount)
1641
1689
* message if we do that. All current callers would just throw error
1642
1690
* immediately anyway, so this is safe at present.
1643
1691
*/
1644
- if (temp_file_limit >= 0 && (VfdCache [ file ]. fdstate & FD_TEMPORARY ))
1692
+ if (temp_file_limit >= 0 && (vfdP -> fdstate & FD_TEMPORARY ))
1645
1693
{
1646
- off_t newPos = VfdCache [ file ]. seekPos + amount ;
1694
+ off_t newPos ;
1647
1695
1648
- if (newPos > VfdCache [file ].fileSize )
1696
+ /*
1697
+ * Normally we should know the seek position, but if for some reason
1698
+ * we have lost track of it, try again to get it. Here, it's fine to
1699
+ * throw an error if we still can't get it.
1700
+ */
1701
+ if (FilePosIsUnknown (vfdP -> seekPos ))
1702
+ {
1703
+ vfdP -> seekPos = lseek (vfdP -> fd , (off_t ) 0 , SEEK_CUR );
1704
+ if (FilePosIsUnknown (vfdP -> seekPos ))
1705
+ elog (ERROR , "could not seek file \"%s\": %m" , vfdP -> fileName );
1706
+ }
1707
+
1708
+ newPos = vfdP -> seekPos + amount ;
1709
+ if (newPos > vfdP -> fileSize )
1649
1710
{
1650
1711
uint64 newTotal = temporary_files_size ;
1651
1712
1652
- newTotal += newPos - VfdCache [ file ]. fileSize ;
1713
+ newTotal += newPos - vfdP -> fileSize ;
1653
1714
if (newTotal > (uint64 ) temp_file_limit * (uint64 ) 1024 )
1654
1715
ereport (ERROR ,
1655
1716
(errcode (ERRCODE_CONFIGURATION_LIMIT_EXCEEDED ),
@@ -1660,25 +1721,33 @@ FileWrite(File file, char *buffer, int amount)
1660
1721
1661
1722
retry :
1662
1723
errno = 0 ;
1663
- returnCode = write (VfdCache [ file ]. fd , buffer , amount );
1724
+ returnCode = write (vfdP -> fd , buffer , amount );
1664
1725
1665
1726
/* if write didn't set errno, assume problem is no disk space */
1666
1727
if (returnCode != amount && errno == 0 )
1667
1728
errno = ENOSPC ;
1668
1729
1669
1730
if (returnCode >= 0 )
1670
1731
{
1671
- VfdCache [file ].seekPos += returnCode ;
1732
+ /* if seekPos is unknown, leave it that way */
1733
+ if (!FilePosIsUnknown (vfdP -> seekPos ))
1734
+ vfdP -> seekPos += returnCode ;
1672
1735
1673
- /* maintain fileSize and temporary_files_size if it's a temp file */
1674
- if (VfdCache [file ].fdstate & FD_TEMPORARY )
1736
+ /*
1737
+ * Maintain fileSize and temporary_files_size if it's a temp file.
1738
+ *
1739
+ * If seekPos is -1 (unknown), this will do nothing; but we could only
1740
+ * get here in that state if we're not enforcing temporary_files_size,
1741
+ * so we don't care.
1742
+ */
1743
+ if (vfdP -> fdstate & FD_TEMPORARY )
1675
1744
{
1676
- off_t newPos = VfdCache [ file ]. seekPos ;
1745
+ off_t newPos = vfdP -> seekPos ;
1677
1746
1678
- if (newPos > VfdCache [ file ]. fileSize )
1747
+ if (newPos > vfdP -> fileSize )
1679
1748
{
1680
- temporary_files_size += newPos - VfdCache [ file ]. fileSize ;
1681
- VfdCache [ file ]. fileSize = newPos ;
1749
+ temporary_files_size += newPos - vfdP -> fileSize ;
1750
+ vfdP -> fileSize = newPos ;
1682
1751
}
1683
1752
}
1684
1753
}
@@ -1706,7 +1775,7 @@ FileWrite(File file, char *buffer, int amount)
1706
1775
goto retry ;
1707
1776
1708
1777
/* Trouble, so assume we don't know the file position anymore */
1709
- VfdCache [ file ]. seekPos = FileUnknownPos ;
1778
+ vfdP -> seekPos = FileUnknownPos ;
1710
1779
}
1711
1780
1712
1781
return returnCode ;
@@ -1732,7 +1801,7 @@ FileSync(File file)
1732
1801
off_t
1733
1802
FileSeek (File file , off_t offset , int whence )
1734
1803
{
1735
- int returnCode ;
1804
+ Vfd * vfdP ;
1736
1805
1737
1806
Assert (FileIsValid (file ));
1738
1807
@@ -1741,25 +1810,33 @@ FileSeek(File file, off_t offset, int whence)
1741
1810
(int64 ) VfdCache [file ].seekPos ,
1742
1811
(int64 ) offset , whence ));
1743
1812
1813
+ vfdP = & VfdCache [file ];
1814
+
1744
1815
if (FileIsNotOpen (file ))
1745
1816
{
1746
1817
switch (whence )
1747
1818
{
1748
1819
case SEEK_SET :
1749
1820
if (offset < 0 )
1750
- elog (ERROR , "invalid seek offset: " INT64_FORMAT ,
1751
- (int64 ) offset );
1752
- VfdCache [file ].seekPos = offset ;
1821
+ {
1822
+ errno = EINVAL ;
1823
+ return (off_t ) - 1 ;
1824
+ }
1825
+ vfdP -> seekPos = offset ;
1753
1826
break ;
1754
1827
case SEEK_CUR :
1755
- VfdCache [file ].seekPos += offset ;
1828
+ if (FilePosIsUnknown (vfdP -> seekPos ) ||
1829
+ vfdP -> seekPos + offset < 0 )
1830
+ {
1831
+ errno = EINVAL ;
1832
+ return (off_t ) - 1 ;
1833
+ }
1834
+ vfdP -> seekPos += offset ;
1756
1835
break ;
1757
1836
case SEEK_END :
1758
- returnCode = FileAccess (file );
1759
- if (returnCode < 0 )
1760
- return returnCode ;
1761
- VfdCache [file ].seekPos = lseek (VfdCache [file ].fd ,
1762
- offset , whence );
1837
+ if (FileAccess (file ) < 0 )
1838
+ return (off_t ) - 1 ;
1839
+ vfdP -> seekPos = lseek (vfdP -> fd , offset , whence );
1763
1840
break ;
1764
1841
default :
1765
1842
elog (ERROR , "invalid whence: %d" , whence );
@@ -1772,27 +1849,27 @@ FileSeek(File file, off_t offset, int whence)
1772
1849
{
1773
1850
case SEEK_SET :
1774
1851
if (offset < 0 )
1775
- elog (ERROR , "invalid seek offset: " INT64_FORMAT ,
1776
- (int64 ) offset );
1777
- if (VfdCache [file ].seekPos != offset )
1778
- VfdCache [file ].seekPos = lseek (VfdCache [file ].fd ,
1779
- offset , whence );
1852
+ {
1853
+ errno = EINVAL ;
1854
+ return (off_t ) - 1 ;
1855
+ }
1856
+ if (vfdP -> seekPos != offset )
1857
+ vfdP -> seekPos = lseek (vfdP -> fd , offset , whence );
1780
1858
break ;
1781
1859
case SEEK_CUR :
1782
- if (offset != 0 || VfdCache [file ].seekPos == FileUnknownPos )
1783
- VfdCache [file ].seekPos = lseek (VfdCache [file ].fd ,
1784
- offset , whence );
1860
+ if (offset != 0 || FilePosIsUnknown (vfdP -> seekPos ))
1861
+ vfdP -> seekPos = lseek (vfdP -> fd , offset , whence );
1785
1862
break ;
1786
1863
case SEEK_END :
1787
- VfdCache [file ].seekPos = lseek (VfdCache [file ].fd ,
1788
- offset , whence );
1864
+ vfdP -> seekPos = lseek (vfdP -> fd , offset , whence );
1789
1865
break ;
1790
1866
default :
1791
1867
elog (ERROR , "invalid whence: %d" , whence );
1792
1868
break ;
1793
1869
}
1794
1870
}
1795
- return VfdCache [file ].seekPos ;
1871
+
1872
+ return vfdP -> seekPos ;
1796
1873
}
1797
1874
1798
1875
/*
0 commit comments