@@ -160,7 +160,14 @@ int max_safe_fds = 32; /* default if not changed */
160160
161161#define FileIsNotOpen (file ) (VfdCache[file].fd == VFD_CLOSED)
162162
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+ */
163169#define FileUnknownPos ((off_t) -1)
170+ #define FilePosIsUnknown (pos ) ((pos) < 0)
164171
165172/* these are the assigned bits in fdstate below: */
166173#define FD_TEMPORARY (1 << 0) /* T = delete when closed */
@@ -174,7 +181,7 @@ typedef struct vfd
174181 File nextFree ; /* link to next free VFD, if in freelist */
175182 File lruMoreRecently ; /* doubly linked recency-of-use list */
176183 File lruLessRecently ;
177- off_t seekPos ; /* current logical file position */
184+ off_t seekPos ; /* current logical file position, or -1 */
178185 off_t fileSize ; /* current size of file (0 if not temporary) */
179186 char * fileName ; /* name of file, or NULL for unused VFD */
180187 /* NB: fileName is malloc'd, and must be free'd when closing the VFD */
@@ -967,19 +974,33 @@ LruDelete(File file)
967974
968975 vfdP = & VfdCache [file ];
969976
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+ }
976992
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+ */
978997 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 );
982999 vfdP -> fd = VFD_CLOSED ;
1000+ -- nfile ;
1001+
1002+ /* delete the vfd record from the LRU ring */
1003+ Delete (file );
9831004}
9841005
9851006static void
@@ -1030,22 +1051,39 @@ LruInsert(File file)
10301051 vfdP -> fileMode );
10311052 if (vfdP -> fd < 0 )
10321053 {
1033- DO_DB (elog (LOG , "RE_OPEN FAILED : %d" , errno ));
1054+ DO_DB (elog (LOG , "re-open failed : %m" ));
10341055 return -1 ;
10351056 }
10361057 else
10371058 {
1038- DO_DB (elog (LOG , "RE_OPEN SUCCESS" ));
10391059 ++ nfile ;
10401060 }
10411061
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+ */
10431069 if (vfdP -> seekPos != (off_t ) 0 )
10441070 {
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+ }
10491087 }
10501088 }
10511089
@@ -1428,15 +1466,15 @@ FileClose(File file)
14281466
14291467 if (!FileIsNotOpen (file ))
14301468 {
1431- /* remove the file from the lru ring */
1432- Delete (file );
1433-
14341469 /* close the file */
14351470 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 );
14371472
14381473 -- nfile ;
14391474 vfdP -> fd = VFD_CLOSED ;
1475+
1476+ /* remove the file from the lru ring */
1477+ Delete (file );
14401478 }
14411479
14421480 /*
@@ -1566,6 +1604,7 @@ int
15661604FileRead (File file , char * buffer , int amount )
15671605{
15681606 int returnCode ;
1607+ Vfd * vfdP ;
15691608
15701609 Assert (FileIsValid (file ));
15711610
@@ -1578,11 +1617,17 @@ FileRead(File file, char *buffer, int amount)
15781617 if (returnCode < 0 )
15791618 return returnCode ;
15801619
1620+ vfdP = & VfdCache [file ];
1621+
15811622retry :
1582- returnCode = read (VfdCache [ file ]. fd , buffer , amount );
1623+ returnCode = read (vfdP -> fd , buffer , amount );
15831624
15841625 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+ }
15861631 else
15871632 {
15881633 /*
@@ -1611,7 +1656,7 @@ FileRead(File file, char *buffer, int amount)
16111656 goto retry ;
16121657
16131658 /* Trouble, so assume we don't know the file position anymore */
1614- VfdCache [ file ]. seekPos = FileUnknownPos ;
1659+ vfdP -> seekPos = FileUnknownPos ;
16151660 }
16161661
16171662 return returnCode ;
@@ -1621,6 +1666,7 @@ int
16211666FileWrite (File file , char * buffer , int amount )
16221667{
16231668 int returnCode ;
1669+ Vfd * vfdP ;
16241670
16251671 Assert (FileIsValid (file ));
16261672
@@ -1633,6 +1679,8 @@ FileWrite(File file, char *buffer, int amount)
16331679 if (returnCode < 0 )
16341680 return returnCode ;
16351681
1682+ vfdP = & VfdCache [file ];
1683+
16361684 /*
16371685 * If enforcing temp_file_limit and it's a temp file, check to see if the
16381686 * 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)
16411689 * message if we do that. All current callers would just throw error
16421690 * immediately anyway, so this is safe at present.
16431691 */
1644- if (temp_file_limit >= 0 && (VfdCache [ file ]. fdstate & FD_TEMPORARY ))
1692+ if (temp_file_limit >= 0 && (vfdP -> fdstate & FD_TEMPORARY ))
16451693 {
1646- off_t newPos = VfdCache [ file ]. seekPos + amount ;
1694+ off_t newPos ;
16471695
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 )
16491710 {
16501711 uint64 newTotal = temporary_files_size ;
16511712
1652- newTotal += newPos - VfdCache [ file ]. fileSize ;
1713+ newTotal += newPos - vfdP -> fileSize ;
16531714 if (newTotal > (uint64 ) temp_file_limit * (uint64 ) 1024 )
16541715 ereport (ERROR ,
16551716 (errcode (ERRCODE_CONFIGURATION_LIMIT_EXCEEDED ),
@@ -1660,25 +1721,33 @@ FileWrite(File file, char *buffer, int amount)
16601721
16611722retry :
16621723 errno = 0 ;
1663- returnCode = write (VfdCache [ file ]. fd , buffer , amount );
1724+ returnCode = write (vfdP -> fd , buffer , amount );
16641725
16651726 /* if write didn't set errno, assume problem is no disk space */
16661727 if (returnCode != amount && errno == 0 )
16671728 errno = ENOSPC ;
16681729
16691730 if (returnCode >= 0 )
16701731 {
1671- VfdCache [file ].seekPos += returnCode ;
1732+ /* if seekPos is unknown, leave it that way */
1733+ if (!FilePosIsUnknown (vfdP -> seekPos ))
1734+ vfdP -> seekPos += returnCode ;
16721735
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 )
16751744 {
1676- off_t newPos = VfdCache [ file ]. seekPos ;
1745+ off_t newPos = vfdP -> seekPos ;
16771746
1678- if (newPos > VfdCache [ file ]. fileSize )
1747+ if (newPos > vfdP -> fileSize )
16791748 {
1680- temporary_files_size += newPos - VfdCache [ file ]. fileSize ;
1681- VfdCache [ file ]. fileSize = newPos ;
1749+ temporary_files_size += newPos - vfdP -> fileSize ;
1750+ vfdP -> fileSize = newPos ;
16821751 }
16831752 }
16841753 }
@@ -1706,7 +1775,7 @@ FileWrite(File file, char *buffer, int amount)
17061775 goto retry ;
17071776
17081777 /* Trouble, so assume we don't know the file position anymore */
1709- VfdCache [ file ]. seekPos = FileUnknownPos ;
1778+ vfdP -> seekPos = FileUnknownPos ;
17101779 }
17111780
17121781 return returnCode ;
@@ -1732,7 +1801,7 @@ FileSync(File file)
17321801off_t
17331802FileSeek (File file , off_t offset , int whence )
17341803{
1735- int returnCode ;
1804+ Vfd * vfdP ;
17361805
17371806 Assert (FileIsValid (file ));
17381807
@@ -1741,25 +1810,33 @@ FileSeek(File file, off_t offset, int whence)
17411810 (int64 ) VfdCache [file ].seekPos ,
17421811 (int64 ) offset , whence ));
17431812
1813+ vfdP = & VfdCache [file ];
1814+
17441815 if (FileIsNotOpen (file ))
17451816 {
17461817 switch (whence )
17471818 {
17481819 case SEEK_SET :
17491820 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 ;
17531826 break ;
17541827 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 ;
17561835 break ;
17571836 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 );
17631840 break ;
17641841 default :
17651842 elog (ERROR , "invalid whence: %d" , whence );
@@ -1772,27 +1849,27 @@ FileSeek(File file, off_t offset, int whence)
17721849 {
17731850 case SEEK_SET :
17741851 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 );
17801858 break ;
17811859 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 );
17851862 break ;
17861863 case SEEK_END :
1787- VfdCache [file ].seekPos = lseek (VfdCache [file ].fd ,
1788- offset , whence );
1864+ vfdP -> seekPos = lseek (vfdP -> fd , offset , whence );
17891865 break ;
17901866 default :
17911867 elog (ERROR , "invalid whence: %d" , whence );
17921868 break ;
17931869 }
17941870 }
1795- return VfdCache [file ].seekPos ;
1871+
1872+ return vfdP -> seekPos ;
17961873}
17971874
17981875/*
0 commit comments