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

Generated by: LCOV version 1.14