LCOV - code coverage report
Current view: top level - port - cpl_vsil_unix_stdio_64.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 265 292 90.8 %
Date: 2025-05-24 03:54:53 Functions: 35 35 100.0 %

          Line data    Source code
       1             : /**********************************************************************
       2             :  *
       3             :  * Project:  CPL - Common Portability Library
       4             :  * Purpose:  Implement VSI large file api for Unix platforms with fseek64()
       5             :  *           and ftell64() such as IRIX.
       6             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7             :  *
       8             :  **********************************************************************
       9             :  * Copyright (c) 2001, Frank Warmerdam
      10             :  * Copyright (c) 2010-2014, Even Rouault <even dot rouault at spatialys.com>
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  ****************************************************************************
      14             :  *
      15             :  * NB: Note that in wrappers we are always saving the error state (errno
      16             :  * variable) to avoid side effects during debug prints or other possible
      17             :  * standard function calls (error states will be overwritten after such
      18             :  * a call).
      19             :  *
      20             :  ****************************************************************************/
      21             : 
      22             : //! @cond Doxygen_Suppress
      23             : 
      24             : // #define VSI_COUNT_BYTES_READ
      25             : 
      26             : // Some unusual filesystems do not work if _FORTIFY_SOURCE in GCC or
      27             : // clang is used within this source file, especially if techniques
      28             : // like those in vsipreload are used.  Fortify source interacts poorly with
      29             : // filesystems that use fread for forward seeks.  This leads to SIGSEGV within
      30             : // fread calls.
      31             : //
      32             : // See this for hardening background info: https://wiki.debian.org/Hardening
      33             : #undef _FORTIFY_SOURCE
      34             : 
      35             : // 64 bit IO is only available on 32-bit android since API 24 / Android 7.0
      36             : // See
      37             : // https://android.googlesource.com/platform/bionic/+/master/docs/32-bit-abi.md
      38             : #if defined(__ANDROID_API__) && __ANDROID_API__ >= 24
      39             : #define _FILE_OFFSET_BITS 64
      40             : #endif
      41             : 
      42             : #include "cpl_port.h"
      43             : 
      44             : #if !defined(_WIN32)
      45             : 
      46             : #include "cpl_vsi.h"
      47             : #include "cpl_vsi_virtual.h"
      48             : 
      49             : #include <cstddef>
      50             : #include <cstdio>
      51             : #include <cstring>
      52             : #include <dirent.h>
      53             : #include <errno.h>
      54             : #if HAVE_FCNTL_H
      55             : #include <fcntl.h>
      56             : #endif
      57             : #include <sys/stat.h>
      58             : #ifdef HAVE_STATVFS
      59             : #include <sys/statvfs.h>
      60             : #endif
      61             : #include <sys/types.h>
      62             : #if HAVE_UNISTD_H
      63             : #include <unistd.h>
      64             : #endif
      65             : #ifdef HAVE_PREAD_BSD
      66             : #include <sys/uio.h>
      67             : #endif
      68             : 
      69             : #if defined(__MACH__) && defined(__APPLE__)
      70             : #define HAS_CASE_INSENSITIVE_FILE_SYSTEM
      71             : #include <stdio.h>
      72             : #include <stdlib.h>
      73             : #include <limits.h>
      74             : #endif
      75             : 
      76             : #include <limits>
      77             : #include <new>
      78             : 
      79             : #include "cpl_config.h"
      80             : #include "cpl_conv.h"
      81             : #include "cpl_error.h"
      82             : #include "cpl_multiproc.h"
      83             : #include "cpl_string.h"
      84             : #include "cpl_vsi_error.h"
      85             : 
      86             : #if defined(UNIX_STDIO_64)
      87             : 
      88             : #ifndef VSI_FTELL64
      89             : #define VSI_FTELL64 ftell64
      90             : #endif
      91             : #ifndef VSI_FSEEK64
      92             : #define VSI_FSEEK64 fseek64
      93             : #endif
      94             : #ifndef VSI_FOPEN64
      95             : #define VSI_FOPEN64 fopen64
      96             : #endif
      97             : #ifndef VSI_STAT64
      98             : #define VSI_STAT64 stat64
      99             : #endif
     100             : #ifndef VSI_STAT64_T
     101             : #define VSI_STAT64_T stat64
     102             : #endif
     103             : #ifndef VSI_FTRUNCATE64
     104             : #define VSI_FTRUNCATE64 ftruncate64
     105             : #endif
     106             : 
     107             : #else /* not UNIX_STDIO_64 */
     108             : 
     109             : #ifndef VSI_FTELL64
     110             : #define VSI_FTELL64 ftell
     111             : #endif
     112             : #ifndef VSI_FSEEK64
     113             : #define VSI_FSEEK64 fseek
     114             : #endif
     115             : #ifndef VSI_FOPEN64
     116             : #define VSI_FOPEN64 fopen
     117             : #endif
     118             : #ifndef VSI_STAT64
     119             : #define VSI_STAT64 stat
     120             : #endif
     121             : #ifndef VSI_STAT64_T
     122             : #define VSI_STAT64_T stat
     123             : #endif
     124             : #ifndef VSI_FTRUNCATE64
     125             : #define VSI_FTRUNCATE64 ftruncate
     126             : #endif
     127             : 
     128             : #endif /* ndef UNIX_STDIO_64 */
     129             : 
     130             : #ifndef BUILD_WITHOUT_64BIT_OFFSET
     131             : // Ensure we have working 64 bit API
     132             : static_assert(sizeof(VSI_FTELL64(stdout)) == sizeof(vsi_l_offset),
     133             :               "File API does not seem to support 64-bit offset. "
     134             :               "If you still want to build GDAL without > 4GB file support, "
     135             :               "add the -DBUILD_WITHOUT_64BIT_OFFSET define");
     136             : static_assert(sizeof(VSIStatBufL::st_size) == sizeof(vsi_l_offset),
     137             :               "File API does not seem to support 64-bit file size. "
     138             :               "If you still want to build GDAL without > 4GB file support, "
     139             :               "add the -DBUILD_WITHOUT_64BIT_OFFSET define");
     140             : #endif
     141             : 
     142             : /************************************************************************/
     143             : /* ==================================================================== */
     144             : /*                       VSIUnixStdioFilesystemHandler                  */
     145             : /* ==================================================================== */
     146             : /************************************************************************/
     147             : 
     148             : class VSIUnixStdioFilesystemHandler final : public VSIFilesystemHandler
     149             : {
     150             :     CPL_DISALLOW_COPY_ASSIGN(VSIUnixStdioFilesystemHandler)
     151             : 
     152             : #ifdef VSI_COUNT_BYTES_READ
     153             :     vsi_l_offset nTotalBytesRead = 0;
     154             :     CPLMutex *hMutex = nullptr;
     155             : #endif
     156             : 
     157             :   public:
     158        1616 :     VSIUnixStdioFilesystemHandler() = default;
     159             : #ifdef VSI_COUNT_BYTES_READ
     160             :     ~VSIUnixStdioFilesystemHandler() override;
     161             : #endif
     162             : 
     163             :     VSIVirtualHandle *Open(const char *pszFilename, const char *pszAccess,
     164             :                            bool bSetError,
     165             :                            CSLConstList /* papszOptions */) override;
     166             :     int Stat(const char *pszFilename, VSIStatBufL *pStatBuf,
     167             :              int nFlags) override;
     168             :     int Unlink(const char *pszFilename) override;
     169             :     int Rename(const char *oldpath, const char *newpath, GDALProgressFunc,
     170             :                void *) override;
     171             :     int Mkdir(const char *pszDirname, long nMode) override;
     172             :     int Rmdir(const char *pszDirname) override;
     173             :     char **ReadDirEx(const char *pszDirname, int nMaxFiles) override;
     174             :     GIntBig GetDiskFreeSpace(const char *pszDirname) override;
     175             :     int SupportsSparseFiles(const char *pszPath) override;
     176             : 
     177             :     bool IsLocal(const char *pszPath) override;
     178             :     bool SupportsSequentialWrite(const char *pszPath,
     179             :                                  bool /* bAllowLocalTempFile */) override;
     180             :     bool SupportsRandomWrite(const char *pszPath,
     181             :                              bool /* bAllowLocalTempFile */) override;
     182             : 
     183             :     VSIDIR *OpenDir(const char *pszPath, int nRecurseDepth,
     184             :                     const char *const *papszOptions) override;
     185             : 
     186             : #ifdef HAS_CASE_INSENSITIVE_FILE_SYSTEM
     187             :     std::string
     188             :     GetCanonicalFilename(const std::string &osFilename) const override;
     189             : #endif
     190             : 
     191             : #ifdef VSI_COUNT_BYTES_READ
     192             :     void AddToTotal(vsi_l_offset nBytes);
     193             : #endif
     194             : };
     195             : 
     196             : /************************************************************************/
     197             : /* ==================================================================== */
     198             : /*                        VSIUnixStdioHandle                            */
     199             : /* ==================================================================== */
     200             : /************************************************************************/
     201             : 
     202             : class VSIUnixStdioHandle final : public VSIVirtualHandle
     203             : {
     204             :     CPL_DISALLOW_COPY_ASSIGN(VSIUnixStdioHandle)
     205             : 
     206             :     FILE *fp = nullptr;
     207             :     vsi_l_offset m_nOffset = 0;
     208             :     bool bReadOnly = true;
     209             :     bool bLastOpWrite = false;
     210             :     bool bLastOpRead = false;
     211             :     bool bAtEOF = false;
     212             :     bool bError = false;
     213             :     // In a+ mode, disable any optimization since the behavior of the file
     214             :     // pointer on Mac and other BSD system is to have a seek() to the end of
     215             :     // file and thus a call to our Seek(0, SEEK_SET) before a read will be a
     216             :     // no-op.
     217             :     bool bModeAppendReadWrite = false;
     218             : #ifdef VSI_COUNT_BYTES_READ
     219             :     vsi_l_offset nTotalBytesRead = 0;
     220             :     VSIUnixStdioFilesystemHandler *poFS = nullptr;
     221             : #endif
     222             :   public:
     223             :     VSIUnixStdioHandle(VSIUnixStdioFilesystemHandler *poFSIn, FILE *fpIn,
     224             :                        bool bReadOnlyIn, bool bModeAppendReadWriteIn);
     225             : 
     226             :     int Seek(vsi_l_offset nOffsetIn, int nWhence) override;
     227             :     vsi_l_offset Tell() override;
     228             :     size_t Read(void *pBuffer, size_t nSize, size_t nMemb) override;
     229             :     size_t Write(const void *pBuffer, size_t nSize, size_t nMemb) override;
     230             :     void ClearErr() override;
     231             :     int Eof() override;
     232             :     int Error() override;
     233             :     int Flush() override;
     234             :     int Close() override;
     235             :     int Truncate(vsi_l_offset nNewSize) override;
     236             : 
     237          55 :     void *GetNativeFileDescriptor() override
     238             :     {
     239          55 :         return reinterpret_cast<void *>(static_cast<uintptr_t>(fileno(fp)));
     240             :     }
     241             : 
     242             :     VSIRangeStatus GetRangeStatus(vsi_l_offset nOffset,
     243             :                                   vsi_l_offset nLength) override;
     244             : #if defined(HAVE_PREAD64) || (defined(HAVE_PREAD_BSD) && SIZEOF_OFF_T == 8)
     245             :     bool HasPRead() const override;
     246             :     size_t PRead(void * /*pBuffer*/, size_t /* nSize */,
     247             :                  vsi_l_offset /*nOffset*/) const override;
     248             : #endif
     249             : };
     250             : 
     251             : /************************************************************************/
     252             : /*                       VSIUnixStdioHandle()                           */
     253             : /************************************************************************/
     254             : 
     255      122762 : VSIUnixStdioHandle::VSIUnixStdioHandle(
     256             : #ifndef VSI_COUNT_BYTES_READ
     257             :     CPL_UNUSED
     258             : #endif
     259             :         VSIUnixStdioFilesystemHandler *poFSIn,
     260      122762 :     FILE *fpIn, bool bReadOnlyIn, bool bModeAppendReadWriteIn)
     261             :     : fp(fpIn), bReadOnly(bReadOnlyIn),
     262      122762 :       bModeAppendReadWrite(bModeAppendReadWriteIn)
     263             : #ifdef VSI_COUNT_BYTES_READ
     264             :       ,
     265             :       poFS(poFSIn)
     266             : #endif
     267             : {
     268      122673 : }
     269             : 
     270             : /************************************************************************/
     271             : /*                               Close()                                */
     272             : /************************************************************************/
     273             : 
     274      122564 : int VSIUnixStdioHandle::Close()
     275             : 
     276             : {
     277      122564 :     if (!fp)
     278          12 :         return 0;
     279             : 
     280             :     VSIDebug1("VSIUnixStdioHandle::Close(%p)", fp);
     281             : 
     282             : #ifdef VSI_COUNT_BYTES_READ
     283             :     poFS->AddToTotal(nTotalBytesRead);
     284             : #endif
     285             : 
     286      122552 :     int ret = fclose(fp);
     287      122441 :     fp = nullptr;
     288      122441 :     return ret;
     289             : }
     290             : 
     291             : /************************************************************************/
     292             : /*                                Seek()                                */
     293             : /************************************************************************/
     294             : 
     295     3438990 : int VSIUnixStdioHandle::Seek(vsi_l_offset nOffsetIn, int nWhence)
     296             : {
     297     3438990 :     bAtEOF = false;
     298             : 
     299             :     // Seeks that do nothing are still surprisingly expensive with MSVCRT.
     300             :     // try and short circuit if possible.
     301     3438990 :     if (!bModeAppendReadWrite && nWhence == SEEK_SET && nOffsetIn == m_nOffset)
     302      711460 :         return 0;
     303             : 
     304             :     // On a read-only file, we can avoid a lseek() system call to be issued
     305             :     // if the next position to seek to is within the buffered page.
     306     2727530 :     if (bReadOnly && nWhence == SEEK_SET)
     307             :     {
     308     1883290 :         const int l_PAGE_SIZE = 4096;
     309     1883290 :         if (nOffsetIn > m_nOffset && nOffsetIn < l_PAGE_SIZE + m_nOffset)
     310             :         {
     311       64790 :             const int nDiff = static_cast<int>(nOffsetIn - m_nOffset);
     312             :             // Do not zero-initialize the buffer. We don't read from it
     313             :             GByte abyTemp[l_PAGE_SIZE];
     314       64790 :             const int nRead = static_cast<int>(fread(abyTemp, 1, nDiff, fp));
     315       64790 :             if (nRead == nDiff)
     316             :             {
     317       64768 :                 m_nOffset = nOffsetIn;
     318       64768 :                 bLastOpWrite = false;
     319       64768 :                 bLastOpRead = false;
     320       64768 :                 return 0;
     321             :             }
     322             :         }
     323             :     }
     324             : 
     325             : #if !defined(UNIX_STDIO_64) && SIZEOF_UNSIGNED_LONG == 4
     326             :     if (nOffsetIn > static_cast<vsi_l_offset>(std::numeric_limits<long>::max()))
     327             :     {
     328             :         CPLError(
     329             :             CE_Failure, CPLE_AppDefined,
     330             :             "Attempt at seeking beyond long extent. Lack of 64-bit file I/O");
     331             :         return -1;
     332             :     }
     333             : #endif
     334             : 
     335     2662760 :     const int nResult = VSI_FSEEK64(fp, nOffsetIn, nWhence);
     336     2662770 :     const int nError = errno;
     337             : 
     338             : #ifdef VSI_DEBUG
     339             : 
     340             :     if (nWhence == SEEK_SET)
     341             :     {
     342             :         VSIDebug3("VSIUnixStdioHandle::Seek(%p," CPL_FRMT_GUIB
     343             :                   ",SEEK_SET) = %d",
     344             :                   fp, nOffsetIn, nResult);
     345             :     }
     346             :     else if (nWhence == SEEK_END)
     347             :     {
     348             :         VSIDebug3("VSIUnixStdioHandle::Seek(%p," CPL_FRMT_GUIB
     349             :                   ",SEEK_END) = %d",
     350             :                   fp, nOffsetIn, nResult);
     351             :     }
     352             :     else if (nWhence == SEEK_CUR)
     353             :     {
     354             :         VSIDebug3("VSIUnixStdioHandle::Seek(%p," CPL_FRMT_GUIB
     355             :                   ",SEEK_CUR) = %d",
     356             :                   fp, nOffsetIn, nResult);
     357             :     }
     358             :     else
     359             :     {
     360             :         VSIDebug4("VSIUnixStdioHandle::Seek(%p," CPL_FRMT_GUIB
     361             :                   ",%d-Unknown) = %d",
     362             :                   fp, nOffsetIn, nWhence, nResult);
     363             :     }
     364             : 
     365             : #endif
     366             : 
     367     2662770 :     if (nResult != -1)
     368             :     {
     369     2662770 :         if (nWhence == SEEK_SET)
     370             :         {
     371     2021110 :             m_nOffset = nOffsetIn;
     372             :         }
     373      641656 :         else if (nWhence == SEEK_END)
     374             :         {
     375      563819 :             m_nOffset = VSI_FTELL64(fp);
     376             :         }
     377       77837 :         else if (nWhence == SEEK_CUR)
     378             :         {
     379             :             if (nOffsetIn > INT_MAX)
     380             :             {
     381             :                 // printf("likely negative offset intended\n");
     382             :             }
     383       77835 :             m_nOffset += nOffsetIn;
     384             :         }
     385             :     }
     386             : 
     387     2662770 :     bLastOpWrite = false;
     388     2662770 :     bLastOpRead = false;
     389             : 
     390     2662770 :     errno = nError;
     391     2662770 :     return nResult;
     392             : }
     393             : 
     394             : /************************************************************************/
     395             : /*                                Tell()                                */
     396             : /************************************************************************/
     397             : 
     398     2324990 : vsi_l_offset VSIUnixStdioHandle::Tell()
     399             : 
     400             : {
     401             : #if 0
     402             :     const vsi_l_offset nOffset = VSI_FTELL64( fp );
     403             :     const int nError = errno;
     404             : 
     405             :     VSIDebug2( "VSIUnixStdioHandle::Tell(%p) = %ld",
     406             :                fp, static_cast<long>(nOffset) );
     407             : 
     408             :     errno = nError;
     409             : #endif
     410             : 
     411     2324990 :     return m_nOffset;
     412             : }
     413             : 
     414             : /************************************************************************/
     415             : /*                               Flush()                                */
     416             : /************************************************************************/
     417             : 
     418       36344 : int VSIUnixStdioHandle::Flush()
     419             : 
     420             : {
     421             :     VSIDebug1("VSIUnixStdioHandle::Flush(%p)", fp);
     422             : 
     423       36344 :     return fflush(fp);
     424             : }
     425             : 
     426             : /************************************************************************/
     427             : /*                                Read()                                */
     428             : /************************************************************************/
     429             : 
     430     7771750 : size_t VSIUnixStdioHandle::Read(void *pBuffer, size_t nSize, size_t nCount)
     431             : 
     432             : {
     433             :     /* -------------------------------------------------------------------- */
     434             :     /*      If a fwrite() is followed by an fread(), the POSIX rules are    */
     435             :     /*      that some of the write may still be buffered and lost.  We      */
     436             :     /*      are required to do a seek between to force flushing.   So we    */
     437             :     /*      keep careful track of what happened last to know if we          */
     438             :     /*      skipped a flushing seek that we may need to do now.             */
     439             :     /* -------------------------------------------------------------------- */
     440     7771750 :     if (!bModeAppendReadWrite && bLastOpWrite)
     441             :     {
     442        2862 :         if (VSI_FSEEK64(fp, m_nOffset, SEEK_SET) != 0)
     443             :         {
     444             :             VSIDebug1("Write calling seek failed. %d", m_nOffset);
     445             :         }
     446             :     }
     447             : 
     448             :     /* -------------------------------------------------------------------- */
     449             :     /*      Perform the read.                                               */
     450             :     /* -------------------------------------------------------------------- */
     451     7771750 :     const size_t nResult = fread(pBuffer, nSize, nCount, fp);
     452             : 
     453             : #ifdef VSI_DEBUG
     454             :     const int nError = errno;
     455             :     VSIDebug4("VSIUnixStdioHandle::Read(%p,%ld,%ld) = %ld", fp,
     456             :               static_cast<long>(nSize), static_cast<long>(nCount),
     457             :               static_cast<long>(nResult));
     458             :     errno = nError;
     459             : #endif
     460             : 
     461             :     /* -------------------------------------------------------------------- */
     462             :     /*      Update current offset.                                          */
     463             :     /* -------------------------------------------------------------------- */
     464             : 
     465             : #ifdef VSI_COUNT_BYTES_READ
     466             :     nTotalBytesRead += nSize * nResult;
     467             : #endif
     468             : 
     469     7771600 :     m_nOffset += nSize * nResult;
     470     7771600 :     bLastOpWrite = false;
     471     7771600 :     bLastOpRead = true;
     472             : 
     473     7771600 :     if (nResult != nCount)
     474             :     {
     475       87418 :         if (ferror(fp))
     476        1034 :             bError = true;
     477             :         else
     478             :         {
     479       86383 :             CPLAssert(feof(fp));
     480       86383 :             bAtEOF = true;
     481             :         }
     482             : 
     483       87417 :         errno = 0;
     484       87417 :         vsi_l_offset nNewOffset = VSI_FTELL64(fp);
     485       87416 :         if (errno == 0)  // ftell() can fail if we are end of file with a pipe.
     486       87418 :             m_nOffset = nNewOffset;
     487             :         else
     488           0 :             CPLDebug("VSI", "%s", VSIStrerror(errno));
     489             :     }
     490             : 
     491     7771690 :     return nResult;
     492             : }
     493             : 
     494             : /************************************************************************/
     495             : /*                               Write()                                */
     496             : /************************************************************************/
     497             : 
     498     2375480 : size_t VSIUnixStdioHandle::Write(const void *pBuffer, size_t nSize,
     499             :                                  size_t nCount)
     500             : 
     501             : {
     502             :     /* -------------------------------------------------------------------- */
     503             :     /*      If a fwrite() is followed by an fread(), the POSIX rules are    */
     504             :     /*      that some of the write may still be buffered and lost.  We      */
     505             :     /*      are required to do a seek between to force flushing.   So we    */
     506             :     /*      keep careful track of what happened last to know if we          */
     507             :     /*      skipped a flushing seek that we may need to do now.             */
     508             :     /* -------------------------------------------------------------------- */
     509     2375480 :     if (!bModeAppendReadWrite && bLastOpRead)
     510             :     {
     511        1864 :         if (VSI_FSEEK64(fp, m_nOffset, SEEK_SET) != 0)
     512             :         {
     513             :             VSIDebug1("Write calling seek failed. %d", m_nOffset);
     514             :         }
     515             :     }
     516             : 
     517             :     /* -------------------------------------------------------------------- */
     518             :     /*      Perform the write.                                              */
     519             :     /* -------------------------------------------------------------------- */
     520     2375480 :     const size_t nResult = fwrite(pBuffer, nSize, nCount, fp);
     521             : 
     522             : #if VSI_DEBUG
     523             :     const int nError = errno;
     524             : 
     525             :     VSIDebug4("VSIUnixStdioHandle::Write(%p,%ld,%ld) = %ld", fp,
     526             :               static_cast<long>(nSize), static_cast<long>(nCount),
     527             :               static_cast<long>(nResult));
     528             : 
     529             :     errno = nError;
     530             : #endif
     531             : 
     532             :     /* -------------------------------------------------------------------- */
     533             :     /*      Update current offset.                                          */
     534             :     /* -------------------------------------------------------------------- */
     535     2375480 :     m_nOffset += nSize * nResult;
     536     2375480 :     bLastOpWrite = true;
     537     2375480 :     bLastOpRead = false;
     538             : 
     539     2375480 :     return nResult;
     540             : }
     541             : 
     542             : /************************************************************************/
     543             : /*                             ClearErr()                               */
     544             : /************************************************************************/
     545             : 
     546        5394 : void VSIUnixStdioHandle::ClearErr()
     547             : 
     548             : {
     549        5394 :     clearerr(fp);
     550        5394 :     bAtEOF = false;
     551        5394 :     bError = false;
     552        5394 : }
     553             : 
     554             : /************************************************************************/
     555             : /*                              Error()                                 */
     556             : /************************************************************************/
     557             : 
     558       58559 : int VSIUnixStdioHandle::Error()
     559             : 
     560             : {
     561       58559 :     return bError ? TRUE : FALSE;
     562             : }
     563             : 
     564             : /************************************************************************/
     565             : /*                                Eof()                                 */
     566             : /************************************************************************/
     567             : 
     568      153619 : int VSIUnixStdioHandle::Eof()
     569             : 
     570             : {
     571      153619 :     return bAtEOF ? TRUE : FALSE;
     572             : }
     573             : 
     574             : /************************************************************************/
     575             : /*                             Truncate()                               */
     576             : /************************************************************************/
     577             : 
     578         544 : int VSIUnixStdioHandle::Truncate(vsi_l_offset nNewSize)
     579             : {
     580         544 :     fflush(fp);
     581         544 :     return VSI_FTRUNCATE64(fileno(fp), nNewSize);
     582             : }
     583             : 
     584             : /************************************************************************/
     585             : /*                          GetRangeStatus()                            */
     586             : /************************************************************************/
     587             : 
     588             : #ifdef __linux
     589             : #if !defined(MISSING_LINUX_FS_H)
     590             : #include <linux/fs.h>  // FS_IOC_FIEMAP
     591             : #endif
     592             : #ifdef FS_IOC_FIEMAP
     593             : #include <linux/types.h>   // for types used in linux/fiemap.h
     594             : #include <linux/fiemap.h>  // struct fiemap
     595             : #endif
     596             : #include <sys/ioctl.h>
     597             : #include <errno.h>
     598             : #endif
     599             : 
     600         497 : VSIRangeStatus VSIUnixStdioHandle::GetRangeStatus(vsi_l_offset
     601             : #ifdef FS_IOC_FIEMAP
     602             :                                                       nOffset
     603             : #endif
     604             :                                                   ,
     605             :                                                   vsi_l_offset
     606             : #ifdef FS_IOC_FIEMAP
     607             :                                                       nLength
     608             : #endif
     609             : )
     610             : {
     611             : #ifdef FS_IOC_FIEMAP
     612             :     // fiemap IOCTL documented at
     613             :     // https://www.kernel.org/doc/Documentation/filesystems/fiemap.txt
     614             : 
     615             :     // The fiemap struct contains a "variable length" array at its end
     616             :     // As we are interested in only one extent, we allocate the base size of
     617             :     // fiemap + one fiemap_extent.
     618             :     GByte abyBuffer[sizeof(struct fiemap) + sizeof(struct fiemap_extent)];
     619         497 :     int fd = fileno(fp);
     620         497 :     struct fiemap *psExtentMap = reinterpret_cast<struct fiemap *>(&abyBuffer);
     621         497 :     memset(psExtentMap, 0,
     622             :            sizeof(struct fiemap) + sizeof(struct fiemap_extent));
     623         497 :     psExtentMap->fm_start = nOffset;
     624         497 :     psExtentMap->fm_length = nLength;
     625         497 :     psExtentMap->fm_extent_count = 1;
     626         497 :     int ret = ioctl(fd, FS_IOC_FIEMAP, psExtentMap);
     627         497 :     if (ret < 0)
     628           0 :         return VSI_RANGE_STATUS_UNKNOWN;
     629         497 :     if (psExtentMap->fm_mapped_extents == 0)
     630           2 :         return VSI_RANGE_STATUS_HOLE;
     631             :     // In case there is one extent with unknown status, retry after having
     632             :     // asked the kernel to sync the file.
     633         495 :     const fiemap_extent *pasExtent = &(psExtentMap->fm_extents[0]);
     634         495 :     if (psExtentMap->fm_mapped_extents == 1 &&
     635         495 :         (pasExtent[0].fe_flags & FIEMAP_EXTENT_UNKNOWN) != 0)
     636             :     {
     637          20 :         psExtentMap->fm_flags = FIEMAP_FLAG_SYNC;
     638          20 :         psExtentMap->fm_start = nOffset;
     639          20 :         psExtentMap->fm_length = nLength;
     640          20 :         psExtentMap->fm_extent_count = 1;
     641          20 :         ret = ioctl(fd, FS_IOC_FIEMAP, psExtentMap);
     642          20 :         if (ret < 0)
     643           0 :             return VSI_RANGE_STATUS_UNKNOWN;
     644          20 :         if (psExtentMap->fm_mapped_extents == 0)
     645           0 :             return VSI_RANGE_STATUS_HOLE;
     646             :     }
     647         495 :     return VSI_RANGE_STATUS_DATA;
     648             : #else
     649             :     static bool bMessageEmitted = false;
     650             :     if (!bMessageEmitted)
     651             :     {
     652             :         CPLDebug("VSI", "Sorry: GetExtentStatus() not implemented for "
     653             :                         "this operating system");
     654             :         bMessageEmitted = true;
     655             :     }
     656             :     return VSI_RANGE_STATUS_UNKNOWN;
     657             : #endif
     658             : }
     659             : 
     660             : /************************************************************************/
     661             : /*                             HasPRead()                               */
     662             : /************************************************************************/
     663             : 
     664             : #if defined(HAVE_PREAD64) || (defined(HAVE_PREAD_BSD) && SIZEOF_OFF_T == 8)
     665         720 : bool VSIUnixStdioHandle::HasPRead() const
     666             : {
     667         720 :     return true;
     668             : }
     669             : 
     670             : /************************************************************************/
     671             : /*                              PRead()                                 */
     672             : /************************************************************************/
     673             : 
     674       24424 : size_t VSIUnixStdioHandle::PRead(void *pBuffer, size_t nSize,
     675             :                                  vsi_l_offset nOffset) const
     676             : {
     677             : #ifdef HAVE_PREAD64
     678       24424 :     return pread64(fileno(fp), pBuffer, nSize, nOffset);
     679             : #else
     680             :     return pread(fileno(fp), pBuffer, nSize, static_cast<off_t>(nOffset));
     681             : #endif
     682             : }
     683             : #endif
     684             : 
     685             : /************************************************************************/
     686             : /* ==================================================================== */
     687             : /*                       VSIUnixStdioFilesystemHandler                  */
     688             : /* ==================================================================== */
     689             : /************************************************************************/
     690             : 
     691             : #ifdef VSI_COUNT_BYTES_READ
     692             : /************************************************************************/
     693             : /*                     ~VSIUnixStdioFilesystemHandler()                 */
     694             : /************************************************************************/
     695             : 
     696             : VSIUnixStdioFilesystemHandler::~VSIUnixStdioFilesystemHandler()
     697             : {
     698             :     CPLDebug(
     699             :         "VSI",
     700             :         "~VSIUnixStdioFilesystemHandler() : nTotalBytesRead = " CPL_FRMT_GUIB,
     701             :         nTotalBytesRead);
     702             : 
     703             :     if (hMutex != nullptr)
     704             :         CPLDestroyMutex(hMutex);
     705             :     hMutex = nullptr;
     706             : }
     707             : #endif
     708             : 
     709             : /************************************************************************/
     710             : /*                                Open()                                */
     711             : /************************************************************************/
     712             : 
     713             : VSIVirtualHandle *
     714      181701 : VSIUnixStdioFilesystemHandler::Open(const char *pszFilename,
     715             :                                     const char *pszAccess, bool bSetError,
     716             :                                     CSLConstList /* papszOptions */)
     717             : 
     718             : {
     719      181701 :     FILE *fp = VSI_FOPEN64(pszFilename, pszAccess);
     720      181570 :     const int nError = errno;
     721             : 
     722             :     VSIDebug3("VSIUnixStdioFilesystemHandler::Open(\"%s\",\"%s\") = %p",
     723             :               pszFilename, pszAccess, fp);
     724             : 
     725      181570 :     if (fp == nullptr)
     726             :     {
     727       58979 :         if (bSetError)
     728             :         {
     729       13514 :             VSIError(VSIE_FileError, "%s: %s", pszFilename, strerror(nError));
     730             :         }
     731       58912 :         errno = nError;
     732       58912 :         return nullptr;
     733             :     }
     734             : 
     735      122591 :     const bool bReadOnly =
     736      122591 :         strcmp(pszAccess, "rb") == 0 || strcmp(pszAccess, "r") == 0;
     737      122591 :     const bool bModeAppendReadWrite =
     738      122591 :         strcmp(pszAccess, "a+b") == 0 || strcmp(pszAccess, "a+") == 0;
     739             :     VSIUnixStdioHandle *poHandle = new (std::nothrow)
     740      122591 :         VSIUnixStdioHandle(this, fp, bReadOnly, bModeAppendReadWrite);
     741      122672 :     if (poHandle == nullptr)
     742             :     {
     743           0 :         fclose(fp);
     744           0 :         return nullptr;
     745             :     }
     746             : 
     747      122672 :     errno = nError;
     748             : 
     749             :     /* -------------------------------------------------------------------- */
     750             :     /*      If VSI_CACHE is set we want to use a cached reader instead      */
     751             :     /*      of more direct io on the underlying file.                       */
     752             :     /* -------------------------------------------------------------------- */
     753      122672 :     if (bReadOnly && CPLTestBool(CPLGetConfigOption("VSI_CACHE", "FALSE")))
     754             :     {
     755           5 :         return VSICreateCachedFile(poHandle);
     756             :     }
     757             : 
     758      122788 :     return poHandle;
     759             : }
     760             : 
     761             : /************************************************************************/
     762             : /*                                Stat()                                */
     763             : /************************************************************************/
     764             : 
     765      219477 : int VSIUnixStdioFilesystemHandler::Stat(const char *pszFilename,
     766             :                                         VSIStatBufL *pStatBuf, int /* nFlags */)
     767             : {
     768      219477 :     return (VSI_STAT64(pszFilename, pStatBuf));
     769             : }
     770             : 
     771             : /************************************************************************/
     772             : /*                               Unlink()                               */
     773             : /************************************************************************/
     774             : 
     775        4627 : int VSIUnixStdioFilesystemHandler::Unlink(const char *pszFilename)
     776             : 
     777             : {
     778        4627 :     return unlink(pszFilename);
     779             : }
     780             : 
     781             : /************************************************************************/
     782             : /*                               Rename()                               */
     783             : /************************************************************************/
     784             : 
     785         531 : int VSIUnixStdioFilesystemHandler::Rename(const char *oldpath,
     786             :                                           const char *newpath, GDALProgressFunc,
     787             :                                           void *)
     788             : 
     789             : {
     790         531 :     return rename(oldpath, newpath);
     791             : }
     792             : 
     793             : /************************************************************************/
     794             : /*                               Mkdir()                                */
     795             : /************************************************************************/
     796             : 
     797         624 : int VSIUnixStdioFilesystemHandler::Mkdir(const char *pszPathname, long nMode)
     798             : 
     799             : {
     800         624 :     return mkdir(pszPathname, static_cast<int>(nMode));
     801             : }
     802             : 
     803             : /************************************************************************/
     804             : /*                               Rmdir()                                */
     805             : /************************************************************************/
     806             : 
     807          53 : int VSIUnixStdioFilesystemHandler::Rmdir(const char *pszPathname)
     808             : 
     809             : {
     810          53 :     return rmdir(pszPathname);
     811             : }
     812             : 
     813             : /************************************************************************/
     814             : /*                              ReadDirEx()                             */
     815             : /************************************************************************/
     816             : 
     817       21667 : char **VSIUnixStdioFilesystemHandler::ReadDirEx(const char *pszPath,
     818             :                                                 int nMaxFiles)
     819             : 
     820             : {
     821       21667 :     if (strlen(pszPath) == 0)
     822          17 :         pszPath = ".";
     823             : 
     824       43333 :     CPLStringList oDir;
     825       21666 :     DIR *hDir = opendir(pszPath);
     826       21667 :     if (hDir != nullptr)
     827             :     {
     828             :         // We want to avoid returning NULL for an empty list.
     829       19393 :         oDir.Assign(static_cast<char **>(CPLCalloc(2, sizeof(char *))));
     830             : 
     831       19392 :         struct dirent *psDirEntry = nullptr;
     832     1751210 :         while ((psDirEntry = readdir(hDir)) != nullptr)
     833             :         {
     834     1731900 :             oDir.AddString(psDirEntry->d_name);
     835     1731820 :             if (nMaxFiles > 0 && oDir.Count() > nMaxFiles)
     836           5 :                 break;
     837             :         }
     838             : 
     839       19396 :         closedir(hDir);
     840             :     }
     841             :     else
     842             :     {
     843             :         // Should we generate an error?
     844             :         // For now we'll just return NULL (at the end of the function).
     845             :     }
     846             : 
     847       43334 :     return oDir.StealList();
     848             : }
     849             : 
     850             : /************************************************************************/
     851             : /*                        GetDiskFreeSpace()                            */
     852             : /************************************************************************/
     853             : 
     854           3 : GIntBig VSIUnixStdioFilesystemHandler::GetDiskFreeSpace(const char *
     855             : #ifdef HAVE_STATVFS
     856             :                                                             pszDirname
     857             : #endif
     858             : )
     859             : {
     860           3 :     GIntBig nRet = -1;
     861             : #ifdef HAVE_STATVFS
     862             : 
     863             : #ifdef HAVE_STATVFS64
     864             :     struct statvfs64 buf;
     865           3 :     if (statvfs64(pszDirname, &buf) == 0)
     866             :     {
     867           2 :         nRet = static_cast<GIntBig>(buf.f_frsize *
     868           2 :                                     static_cast<GUIntBig>(buf.f_bavail));
     869             :     }
     870             : #else
     871             :     struct statvfs buf;
     872             :     if (statvfs(pszDirname, &buf) == 0)
     873             :     {
     874             :         nRet = static_cast<GIntBig>(buf.f_frsize *
     875             :                                     static_cast<GUIntBig>(buf.f_bavail));
     876             :     }
     877             : #endif
     878             : 
     879             : #endif
     880           3 :     return nRet;
     881             : }
     882             : 
     883             : /************************************************************************/
     884             : /*                      SupportsSparseFiles()                           */
     885             : /************************************************************************/
     886             : 
     887             : #ifdef __linux
     888             : #include <sys/vfs.h>
     889             : #endif
     890             : 
     891           2 : int VSIUnixStdioFilesystemHandler::SupportsSparseFiles(const char *
     892             : #ifdef __linux
     893             :                                                            pszPath
     894             : #endif
     895             : )
     896             : {
     897             : #ifdef __linux
     898             :     struct statfs sStatFS;
     899           2 :     if (statfs(pszPath, &sStatFS) == 0)
     900             :     {
     901             :         // Add here any missing filesystem supporting sparse files.
     902             :         // See http://en.wikipedia.org/wiki/Comparison_of_file_systems
     903           2 :         switch (static_cast<unsigned>(sStatFS.f_type))
     904             :         {
     905             :             // Codes from http://man7.org/linux/man-pages/man2/statfs.2.html
     906           2 :             case 0xef53U:      // ext2, 3, 4
     907             :             case 0x52654973U:  // reiser
     908             :             case 0x58465342U:  // xfs
     909             :             case 0x3153464aU:  // jfs
     910             :             case 0x5346544eU:  // ntfs
     911             :             case 0x9123683eU:  // brfs
     912             :             // nfs: NFS < 4.2 supports creating sparse files (but reading them
     913             :             // not efficiently).
     914             :             case 0x6969U:
     915             :             case 0x01021994U:  // tmpfs
     916           2 :                 return TRUE;
     917             : 
     918           0 :             case 0x4d44U:  // msdos
     919           0 :                 return FALSE;
     920             : 
     921           0 :             case 0x53464846U:  // Windows Subsystem for Linux fs
     922             :             {
     923             :                 static bool bUnknownFSEmitted = false;
     924           0 :                 if (!bUnknownFSEmitted)
     925             :                 {
     926           0 :                     CPLDebug("VSI",
     927             :                              "Windows Subsystem for Linux FS is at "
     928             :                              "the time of writing not known to support sparse "
     929             :                              "files");
     930           0 :                     bUnknownFSEmitted = true;
     931             :                 }
     932           0 :                 return FALSE;
     933             :             }
     934             : 
     935           0 :             default:
     936             :             {
     937             :                 static bool bUnknownFSEmitted = false;
     938           0 :                 if (!bUnknownFSEmitted)
     939             :                 {
     940           0 :                     CPLDebug("VSI",
     941             :                              "Filesystem with type %X unknown. "
     942             :                              "Assuming it does not support sparse files",
     943           0 :                              static_cast<int>(sStatFS.f_type));
     944           0 :                     bUnknownFSEmitted = true;
     945             :                 }
     946           0 :                 return FALSE;
     947             :             }
     948             :         }
     949             :     }
     950           0 :     return FALSE;
     951             : #else
     952             :     static bool bMessageEmitted = false;
     953             :     if (!bMessageEmitted)
     954             :     {
     955             :         CPLDebug("VSI", "Sorry: SupportsSparseFiles() not implemented "
     956             :                         "for this operating system");
     957             :         bMessageEmitted = true;
     958             :     }
     959             :     return FALSE;
     960             : #endif
     961             : }
     962             : 
     963             : /************************************************************************/
     964             : /*                          IsLocal()                                   */
     965             : /************************************************************************/
     966             : 
     967         139 : bool VSIUnixStdioFilesystemHandler::IsLocal(const char *
     968             : #ifdef __linux
     969             :                                                 pszPath
     970             : #endif
     971             : )
     972             : {
     973             : #ifdef __linux
     974             :     struct statfs sStatFS;
     975         139 :     if (statfs(pszPath, &sStatFS) == 0)
     976             :     {
     977             :         // See http://en.wikipedia.org/wiki/Comparison_of_file_systems
     978         137 :         switch (static_cast<unsigned>(sStatFS.f_type))
     979             :         {
     980             :             // Codes from http://man7.org/linux/man-pages/man2/statfs.2.html
     981           0 :             case 0x6969U:      // NFS
     982             :             case 0x517bU:      // SMB
     983             :             case 0xff534d42U:  // CIFS
     984             :             case 0xfe534d42U:  // SMB2
     985             :                 // (https://github.com/libuv/libuv/blob/97dcdb1926f6aca43171e1614338bcef067abd59/src/unix/fs.c#L960)
     986           0 :                 return false;
     987             :         }
     988             :     }
     989             : #else
     990             :     static bool bMessageEmitted = false;
     991             :     if (!bMessageEmitted)
     992             :     {
     993             :         CPLDebug("VSI", "Sorry: IsLocal() not implemented "
     994             :                         "for this operating system");
     995             :         bMessageEmitted = true;
     996             :     }
     997             : #endif
     998         139 :     return true;
     999             : }
    1000             : 
    1001             : /************************************************************************/
    1002             : /*                    SupportsSequentialWrite()                         */
    1003             : /************************************************************************/
    1004             : 
    1005         124 : bool VSIUnixStdioFilesystemHandler::SupportsSequentialWrite(
    1006             :     const char *pszPath, bool /* bAllowLocalTempFile */)
    1007             : {
    1008             :     VSIStatBufL sStat;
    1009         124 :     if (VSIStatL(pszPath, &sStat) == 0)
    1010          56 :         return access(pszPath, W_OK) == 0;
    1011          68 :     return access(CPLGetDirnameSafe(pszPath).c_str(), W_OK) == 0;
    1012             : }
    1013             : 
    1014             : /************************************************************************/
    1015             : /*                     SupportsRandomWrite()                            */
    1016             : /************************************************************************/
    1017             : 
    1018          68 : bool VSIUnixStdioFilesystemHandler::SupportsRandomWrite(
    1019             :     const char *pszPath, bool /* bAllowLocalTempFile */)
    1020             : {
    1021          68 :     return SupportsSequentialWrite(pszPath, false);
    1022             : }
    1023             : 
    1024             : /************************************************************************/
    1025             : /*                            VSIDIRUnixStdio                           */
    1026             : /************************************************************************/
    1027             : 
    1028             : struct VSIDIRUnixStdio final : public VSIDIR
    1029             : {
    1030             :     CPLString osRootPath{};
    1031             :     CPLString osBasePath{};
    1032             :     DIR *m_psDir = nullptr;
    1033             :     int nRecurseDepth = 0;
    1034             :     VSIDIREntry entry{};
    1035             :     std::vector<VSIDIRUnixStdio *> aoStackSubDir{};
    1036             :     VSIUnixStdioFilesystemHandler *poFS = nullptr;
    1037             :     std::string m_osFilterPrefix{};
    1038             :     bool m_bNameAndTypeOnly = false;
    1039             : 
    1040         155 :     explicit VSIDIRUnixStdio(VSIUnixStdioFilesystemHandler *poFSIn)
    1041         155 :         : poFS(poFSIn)
    1042             :     {
    1043         155 :     }
    1044             : 
    1045             :     ~VSIDIRUnixStdio();
    1046             : 
    1047             :     const VSIDIREntry *NextDirEntry() override;
    1048             : 
    1049             :     VSIDIRUnixStdio(const VSIDIRUnixStdio &) = delete;
    1050             :     VSIDIRUnixStdio &operator=(const VSIDIRUnixStdio &) = delete;
    1051             : };
    1052             : 
    1053             : /************************************************************************/
    1054             : /*                        ~VSIDIRUnixStdio()                            */
    1055             : /************************************************************************/
    1056             : 
    1057         465 : VSIDIRUnixStdio::~VSIDIRUnixStdio()
    1058             : {
    1059         155 :     while (!aoStackSubDir.empty())
    1060             :     {
    1061           0 :         delete aoStackSubDir.back();
    1062           0 :         aoStackSubDir.pop_back();
    1063             :     }
    1064         155 :     closedir(m_psDir);
    1065         310 : }
    1066             : 
    1067             : /************************************************************************/
    1068             : /*                            OpenDir()                                 */
    1069             : /************************************************************************/
    1070             : 
    1071         167 : VSIDIR *VSIUnixStdioFilesystemHandler::OpenDir(const char *pszPath,
    1072             :                                                int nRecurseDepth,
    1073             :                                                const char *const *papszOptions)
    1074             : {
    1075         167 :     DIR *psDir = opendir(pszPath);
    1076         167 :     if (psDir == nullptr)
    1077             :     {
    1078          12 :         return nullptr;
    1079             :     }
    1080         155 :     VSIDIRUnixStdio *dir = new VSIDIRUnixStdio(this);
    1081         155 :     dir->osRootPath = pszPath;
    1082         155 :     dir->nRecurseDepth = nRecurseDepth;
    1083         155 :     dir->m_psDir = psDir;
    1084         155 :     dir->m_osFilterPrefix = CSLFetchNameValueDef(papszOptions, "PREFIX", "");
    1085         155 :     dir->m_bNameAndTypeOnly = CPLTestBool(
    1086             :         CSLFetchNameValueDef(papszOptions, "NAME_AND_TYPE_ONLY", "NO"));
    1087         155 :     return dir;
    1088             : }
    1089             : 
    1090             : /************************************************************************/
    1091             : /*                           NextDirEntry()                             */
    1092             : /************************************************************************/
    1093             : 
    1094        2875 : const VSIDIREntry *VSIDIRUnixStdio::NextDirEntry()
    1095             : {
    1096        2875 : begin:
    1097        2875 :     if (VSI_ISDIR(entry.nMode) && nRecurseDepth != 0)
    1098             :     {
    1099          74 :         CPLString osCurFile(osRootPath);
    1100          74 :         if (!osCurFile.empty())
    1101          74 :             osCurFile += '/';
    1102          74 :         osCurFile += entry.pszName;
    1103             :         auto subdir = static_cast<VSIDIRUnixStdio *>(
    1104          74 :             poFS->VSIUnixStdioFilesystemHandler::OpenDir(
    1105          74 :                 osCurFile, nRecurseDepth - 1, nullptr));
    1106          74 :         if (subdir)
    1107             :         {
    1108          74 :             subdir->osRootPath = osRootPath;
    1109          74 :             subdir->osBasePath = entry.pszName;
    1110          74 :             subdir->m_osFilterPrefix = m_osFilterPrefix;
    1111          74 :             subdir->m_bNameAndTypeOnly = m_bNameAndTypeOnly;
    1112          74 :             aoStackSubDir.push_back(subdir);
    1113             :         }
    1114          74 :         entry.nMode = 0;
    1115             :     }
    1116             : 
    1117        2949 :     while (!aoStackSubDir.empty())
    1118             :     {
    1119         372 :         auto l_entry = aoStackSubDir.back()->NextDirEntry();
    1120         372 :         if (l_entry)
    1121             :         {
    1122         298 :             return l_entry;
    1123             :         }
    1124          74 :         delete aoStackSubDir.back();
    1125          74 :         aoStackSubDir.pop_back();
    1126             :     }
    1127             : 
    1128             :     while (true)
    1129             :     {
    1130        2882 :         const auto *psEntry = readdir(m_psDir);
    1131        2882 :         if (psEntry == nullptr)
    1132             :         {
    1133         149 :             return nullptr;
    1134             :         }
    1135             :         // Skip . and ..entries
    1136        2733 :         if (psEntry->d_name[0] == '.' &&
    1137         303 :             (psEntry->d_name[1] == '\0' ||
    1138         153 :              (psEntry->d_name[1] == '.' && psEntry->d_name[2] == '\0')))
    1139             :         {
    1140             :             // do nothing
    1141             :         }
    1142             :         else
    1143             :         {
    1144        2433 :             CPLFree(entry.pszName);
    1145        2433 :             CPLString osName(osBasePath);
    1146        2433 :             if (!osName.empty())
    1147         268 :                 osName += '/';
    1148        2433 :             osName += psEntry->d_name;
    1149             : 
    1150        2433 :             entry.pszName = CPLStrdup(osName);
    1151        2433 :             entry.nMode = 0;
    1152        2433 :             entry.nSize = 0;
    1153        2433 :             entry.nMTime = 0;
    1154        2433 :             entry.bModeKnown = false;
    1155        2433 :             entry.bSizeKnown = false;
    1156        2433 :             entry.bMTimeKnown = false;
    1157             : 
    1158        2433 :             CPLString osCurFile(osRootPath);
    1159        2433 :             if (!osCurFile.empty())
    1160        2433 :                 osCurFile += '/';
    1161        2433 :             osCurFile += entry.pszName;
    1162             : 
    1163             : #if !defined(__sun) && !defined(__HAIKU__)
    1164        2433 :             if (psEntry->d_type == DT_REG)
    1165        2313 :                 entry.nMode = S_IFREG;
    1166         120 :             else if (psEntry->d_type == DT_DIR)
    1167         120 :                 entry.nMode = S_IFDIR;
    1168           0 :             else if (psEntry->d_type == DT_LNK)
    1169           0 :                 entry.nMode = S_IFLNK;
    1170             : #endif
    1171             : 
    1172        4224 :             const auto StatFile = [&osCurFile, this]()
    1173             :             {
    1174             :                 VSIStatBufL sStatL;
    1175        2112 :                 if (VSIStatL(osCurFile, &sStatL) == 0)
    1176             :                 {
    1177        2112 :                     entry.nMode = sStatL.st_mode;
    1178        2112 :                     entry.nSize = sStatL.st_size;
    1179        2112 :                     entry.nMTime = sStatL.st_mtime;
    1180        2112 :                     entry.bModeKnown = true;
    1181        2112 :                     entry.bSizeKnown = true;
    1182        2112 :                     entry.bMTimeKnown = true;
    1183             :                 }
    1184        2112 :             };
    1185             : 
    1186        2445 :             if (!m_osFilterPrefix.empty() &&
    1187          12 :                 m_osFilterPrefix.size() > osName.size())
    1188             :             {
    1189           6 :                 if (STARTS_WITH(m_osFilterPrefix.c_str(), osName.c_str()) &&
    1190           2 :                     m_osFilterPrefix[osName.size()] == '/')
    1191             :                 {
    1192             : #if !defined(__sun) && !defined(__HAIKU__)
    1193           1 :                     if (psEntry->d_type == DT_UNKNOWN)
    1194             : #endif
    1195             :                     {
    1196           0 :                         StatFile();
    1197             :                     }
    1198           1 :                     if (VSI_ISDIR(entry.nMode))
    1199             :                     {
    1200           1 :                         goto begin;
    1201             :                     }
    1202             :                 }
    1203           3 :                 continue;
    1204             :             }
    1205        2437 :             if (!m_osFilterPrefix.empty() &&
    1206           8 :                 !STARTS_WITH(osName.c_str(), m_osFilterPrefix.c_str()))
    1207             :             {
    1208           2 :                 continue;
    1209             :             }
    1210             : 
    1211        2427 :             if (!m_bNameAndTypeOnly
    1212             : #if !defined(__sun) && !defined(__HAIKU__)
    1213         315 :                 || psEntry->d_type == DT_UNKNOWN
    1214             : #endif
    1215             :             )
    1216             :             {
    1217        2112 :                 StatFile();
    1218             :             }
    1219             : 
    1220        2427 :             break;
    1221             :         }
    1222         305 :     }
    1223             : 
    1224        2427 :     return &(entry);
    1225             : }
    1226             : 
    1227             : #ifdef VSI_COUNT_BYTES_READ
    1228             : /************************************************************************/
    1229             : /*                            AddToTotal()                              */
    1230             : /************************************************************************/
    1231             : 
    1232             : void VSIUnixStdioFilesystemHandler::AddToTotal(vsi_l_offset nBytes)
    1233             : {
    1234             :     CPLMutexHolder oHolder(&hMutex);
    1235             :     nTotalBytesRead += nBytes;
    1236             : }
    1237             : 
    1238             : #endif
    1239             : 
    1240             : /************************************************************************/
    1241             : /*                      GetCanonicalFilename()                          */
    1242             : /************************************************************************/
    1243             : 
    1244             : #ifdef HAS_CASE_INSENSITIVE_FILE_SYSTEM
    1245             : std::string VSIUnixStdioFilesystemHandler::GetCanonicalFilename(
    1246             :     const std::string &osFilename) const
    1247             : {
    1248             :     char szResolvedPath[PATH_MAX];
    1249             :     const char *pszFilename = osFilename.c_str();
    1250             :     if (realpath(pszFilename, szResolvedPath))
    1251             :     {
    1252             :         const char *pszFilenameLastPart = strrchr(pszFilename, '/');
    1253             :         const char *pszResolvedFilenameLastPart = strrchr(szResolvedPath, '/');
    1254             :         if (pszFilenameLastPart && pszResolvedFilenameLastPart &&
    1255             :             EQUAL(pszFilenameLastPart, pszResolvedFilenameLastPart))
    1256             :         {
    1257             :             std::string osRet;
    1258             :             osRet.assign(pszFilename, pszFilenameLastPart - pszFilename);
    1259             :             osRet += pszResolvedFilenameLastPart;
    1260             :             return osRet;
    1261             :         }
    1262             :         return szResolvedPath;
    1263             :     }
    1264             :     return osFilename;
    1265             : }
    1266             : #endif
    1267             : 
    1268             : /************************************************************************/
    1269             : /*                     VSIInstallLargeFileHandler()                     */
    1270             : /************************************************************************/
    1271             : 
    1272        1616 : void VSIInstallLargeFileHandler()
    1273             : 
    1274             : {
    1275        1616 :     VSIFileManager::InstallHandler("", new VSIUnixStdioFilesystemHandler());
    1276        1616 : }
    1277             : 
    1278             : #endif  // ndef WIN32
    1279             : 
    1280             : //! @endcond

Generated by: LCOV version 1.14