LCOV - code coverage report
Current view: top level - port - cpl_vsil_plugin.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 58 228 25.4 %
Date: 2024-11-21 22:18:42 Functions: 17 47 36.2 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  CPL - Common Portability Library
       4             :  * Purpose:  Implement VSI large file api for plugins
       5             :  * Author:   Thomas Bonfort, thomas.bonfort@airbus.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2019, Thomas Bonfort <thomas.bonfort@airbus.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "cpl_port.h"
      14             : #include "cpl_vsil_plugin.h"
      15             : 
      16             : //! @cond Doxygen_Suppress
      17             : #ifndef DOXYGEN_SKIP
      18             : 
      19             : namespace cpl
      20             : {
      21             : 
      22           2 : VSIPluginHandle::VSIPluginHandle(VSIPluginFilesystemHandler *poFSIn,
      23           2 :                                  void *cbDataIn)
      24           2 :     : poFS(poFSIn), cbData(cbDataIn)
      25             : {
      26           2 : }
      27             : 
      28           4 : VSIPluginHandle::~VSIPluginHandle()
      29             : {
      30           2 :     if (cbData)
      31             :     {
      32           0 :         VSIPluginHandle::Close();
      33             :     }
      34           4 : }
      35             : 
      36           0 : int VSIPluginHandle::Seek(vsi_l_offset nOffset, int nWhence)
      37             : {
      38           0 :     return poFS->Seek(cbData, nOffset, nWhence);
      39             : }
      40             : 
      41           0 : vsi_l_offset VSIPluginHandle::Tell()
      42             : {
      43           0 :     return poFS->Tell(cbData);
      44             : }
      45             : 
      46           0 : size_t VSIPluginHandle::Read(void *const pBuffer, size_t const nSize,
      47             :                              size_t const nMemb)
      48             : {
      49           0 :     return poFS->Read(cbData, pBuffer, nSize, nMemb);
      50             : }
      51             : 
      52           0 : int VSIPluginHandle::Eof()
      53             : {
      54           0 :     return poFS->Eof(cbData);
      55             : }
      56             : 
      57           0 : int VSIPluginHandle::Error()
      58             : {
      59           0 :     return poFS->Error(cbData);
      60             : }
      61             : 
      62           0 : void VSIPluginHandle::ClearErr()
      63             : {
      64           0 :     poFS->ClearErr(cbData);
      65           0 : }
      66             : 
      67           2 : int VSIPluginHandle::Close()
      68             : {
      69           2 :     int ret = poFS->Close(cbData);
      70           2 :     cbData = nullptr;
      71           2 :     return ret;
      72             : }
      73             : 
      74           0 : int VSIPluginHandle::ReadMultiRange(int nRanges, void **ppData,
      75             :                                     const vsi_l_offset *panOffsets,
      76             :                                     const size_t *panSizes)
      77             : {
      78           0 :     return poFS->ReadMultiRange(cbData, nRanges, ppData, panOffsets, panSizes);
      79             : }
      80             : 
      81           2 : void VSIPluginHandle::AdviseRead(int nRanges, const vsi_l_offset *panOffsets,
      82             :                                  const size_t *panSizes)
      83             : {
      84           2 :     poFS->AdviseRead(cbData, nRanges, panOffsets, panSizes);
      85           2 : }
      86             : 
      87           0 : VSIRangeStatus VSIPluginHandle::GetRangeStatus(vsi_l_offset nOffset,
      88             :                                                vsi_l_offset nLength)
      89             : {
      90           0 :     return poFS->GetRangeStatus(cbData, nOffset, nLength);
      91             : }
      92             : 
      93           0 : size_t VSIPluginHandle::Write(const void *pBuffer, size_t nSize, size_t nCount)
      94             : {
      95           0 :     return poFS->Write(cbData, pBuffer, nSize, nCount);
      96             : }
      97             : 
      98           0 : int VSIPluginHandle::Flush()
      99             : {
     100           0 :     return poFS->Flush(cbData);
     101             : }
     102             : 
     103           0 : int VSIPluginHandle::Truncate(vsi_l_offset nNewSize)
     104             : {
     105           0 :     return poFS->Truncate(cbData, nNewSize);
     106             : }
     107             : 
     108           2 : VSIPluginFilesystemHandler::VSIPluginFilesystemHandler(
     109           2 :     const char *pszPrefix, const VSIFilesystemPluginCallbacksStruct *cbIn)
     110           2 :     : m_Prefix(pszPrefix), m_cb(nullptr)
     111             : {
     112           2 :     m_cb = new VSIFilesystemPluginCallbacksStruct(*cbIn);
     113           2 : }
     114             : 
     115           2 : VSIPluginFilesystemHandler::~VSIPluginFilesystemHandler()
     116             : {
     117           1 :     delete m_cb;
     118           2 : }
     119             : 
     120             : VSIVirtualHandle *
     121           3 : VSIPluginFilesystemHandler::Open(const char *pszFilename, const char *pszAccess,
     122             :                                  bool bSetError,
     123             :                                  CSLConstList /* papszOptions */)
     124             : {
     125           3 :     if (!IsValidFilename(pszFilename))
     126           0 :         return nullptr;
     127           3 :     void *cbData = m_cb->open(m_cb->pUserData, GetCallbackFilename(pszFilename),
     128             :                               pszAccess);
     129           3 :     if (cbData == nullptr)
     130             :     {
     131           1 :         if (bSetError)
     132             :         {
     133           0 :             VSIError(VSIE_FileError, "%s: %s", pszFilename, strerror(errno));
     134             :         }
     135           1 :         return nullptr;
     136             :     }
     137           2 :     if (m_cb->nBufferSize == 0)
     138             :     {
     139           2 :         return new VSIPluginHandle(this, cbData);
     140             :     }
     141             :     else
     142             :     {
     143           0 :         return VSICreateCachedFile(
     144           0 :             new VSIPluginHandle(this, cbData), m_cb->nBufferSize,
     145           0 :             (m_cb->nCacheSize < m_cb->nBufferSize) ? m_cb->nBufferSize
     146           0 :                                                    : m_cb->nCacheSize);
     147             :     }
     148             : }
     149             : 
     150             : const char *
     151           3 : VSIPluginFilesystemHandler::GetCallbackFilename(const char *pszFilename)
     152             : {
     153           3 :     return pszFilename + strlen(m_Prefix);
     154             : }
     155             : 
     156           3 : bool VSIPluginFilesystemHandler::IsValidFilename(const char *pszFilename)
     157             : {
     158           3 :     if (!STARTS_WITH_CI(pszFilename, m_Prefix))
     159           0 :         return false;
     160           3 :     return true;
     161             : }
     162             : 
     163           0 : int VSIPluginFilesystemHandler::Stat(const char *pszFilename,
     164             :                                      VSIStatBufL *pStatBuf, int nFlags)
     165             : {
     166           0 :     if (!IsValidFilename(pszFilename))
     167             :     {
     168           0 :         errno = EBADF;
     169           0 :         return -1;
     170             :     }
     171             : 
     172           0 :     memset(pStatBuf, 0, sizeof(VSIStatBufL));
     173             : 
     174           0 :     int nRet = 0;
     175           0 :     if (m_cb->stat != nullptr)
     176             :     {
     177           0 :         nRet = m_cb->stat(m_cb->pUserData, GetCallbackFilename(pszFilename),
     178             :                           pStatBuf, nFlags);
     179             :     }
     180             :     else
     181             :     {
     182           0 :         nRet = -1;
     183             :     }
     184           0 :     return nRet;
     185             : }
     186             : 
     187           0 : int VSIPluginFilesystemHandler::Seek(void *pFile, vsi_l_offset nOffset,
     188             :                                      int nWhence)
     189             : {
     190           0 :     if (m_cb->seek != nullptr)
     191             :     {
     192           0 :         return m_cb->seek(pFile, nOffset, nWhence);
     193             :     }
     194           0 :     CPLError(CE_Failure, CPLE_AppDefined, "Seek not implemented for %s plugin",
     195             :              m_Prefix);
     196           0 :     return -1;
     197             : }
     198             : 
     199           0 : vsi_l_offset VSIPluginFilesystemHandler::Tell(void *pFile)
     200             : {
     201           0 :     if (m_cb->tell != nullptr)
     202             :     {
     203           0 :         return m_cb->tell(pFile);
     204             :     }
     205           0 :     CPLError(CE_Failure, CPLE_AppDefined, "Tell not implemented for %s plugin",
     206             :              m_Prefix);
     207           0 :     return -1;
     208             : }
     209             : 
     210           0 : size_t VSIPluginFilesystemHandler::Read(void *pFile, void *pBuffer,
     211             :                                         size_t nSize, size_t nCount)
     212             : {
     213           0 :     if (m_cb->read != nullptr)
     214             :     {
     215           0 :         return m_cb->read(pFile, pBuffer, nSize, nCount);
     216             :     }
     217           0 :     CPLError(CE_Failure, CPLE_AppDefined, "Read not implemented for %s plugin",
     218             :              m_Prefix);
     219           0 :     return -1;
     220             : }
     221             : 
     222           0 : int VSIPluginFilesystemHandler::HasOptimizedReadMultiRange(
     223             :     const char * /*pszPath*/)
     224             : {
     225           0 :     if (m_cb->read_multi_range != nullptr)
     226             :     {
     227           0 :         return TRUE;
     228             :     }
     229           0 :     return FALSE;
     230             : }
     231             : 
     232           0 : VSIRangeStatus VSIPluginFilesystemHandler::GetRangeStatus(void *pFile,
     233             :                                                           vsi_l_offset nOffset,
     234             :                                                           vsi_l_offset nLength)
     235             : {
     236           0 :     if (m_cb->get_range_status != nullptr)
     237             :     {
     238           0 :         return m_cb->get_range_status(pFile, nOffset, nLength);
     239             :     }
     240           0 :     return VSI_RANGE_STATUS_UNKNOWN;
     241             : }
     242             : 
     243           0 : int VSIPluginFilesystemHandler::ReadMultiRange(void *pFile, int nRanges,
     244             :                                                void **ppData,
     245             :                                                const vsi_l_offset *panOffsets,
     246             :                                                const size_t *panSizes)
     247             : {
     248           0 :     if (m_cb->read_multi_range == nullptr)
     249             :     {
     250           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     251             :                  "Read not implemented for %s plugin", m_Prefix);
     252           0 :         return -1;
     253             :     }
     254             :     int iRange;
     255           0 :     int nMergedRanges = 1;
     256           0 :     for (iRange = 0; iRange < nRanges - 1; iRange++)
     257             :     {
     258           0 :         if (panOffsets[iRange] + panSizes[iRange] != panOffsets[iRange + 1])
     259             :         {
     260           0 :             nMergedRanges++;
     261             :         }
     262             :     }
     263           0 :     if (nMergedRanges == nRanges)
     264             :     {
     265           0 :         return m_cb->read_multi_range(pFile, nRanges, ppData, panOffsets,
     266           0 :                                       panSizes);
     267             :     }
     268             : 
     269           0 :     vsi_l_offset *mOffsets = new vsi_l_offset[nMergedRanges];
     270           0 :     size_t *mSizes = new size_t[nMergedRanges];
     271           0 :     char **mData = new char *[nMergedRanges];
     272             : 
     273           0 :     int curRange = 0;
     274           0 :     mSizes[curRange] = panSizes[0];
     275           0 :     mOffsets[curRange] = panOffsets[0];
     276           0 :     for (iRange = 0; iRange < nRanges - 1; iRange++)
     277             :     {
     278           0 :         if (panOffsets[iRange] + panSizes[iRange] == panOffsets[iRange + 1])
     279             :         {
     280           0 :             mSizes[curRange] += panSizes[iRange + 1];
     281             :         }
     282             :         else
     283             :         {
     284           0 :             mData[curRange] = new char[mSizes[curRange]];
     285             :             // start a new range
     286           0 :             curRange++;
     287           0 :             mSizes[curRange] = panSizes[iRange + 1];
     288           0 :             mOffsets[curRange] = panOffsets[iRange + 1];
     289             :         }
     290             :     }
     291           0 :     mData[curRange] = new char[mSizes[curRange]];
     292             : 
     293           0 :     int ret = m_cb->read_multi_range(pFile, nMergedRanges,
     294             :                                      reinterpret_cast<void **>(mData), mOffsets,
     295             :                                      mSizes);
     296             : 
     297           0 :     curRange = 0;
     298           0 :     size_t curOffset = panSizes[0];
     299           0 :     memcpy(ppData[0], mData[0], panSizes[0]);
     300           0 :     for (iRange = 0; iRange < nRanges - 1; iRange++)
     301             :     {
     302           0 :         if (panOffsets[iRange] + panSizes[iRange] == panOffsets[iRange + 1])
     303             :         {
     304           0 :             memcpy(ppData[iRange + 1], mData[curRange] + curOffset,
     305           0 :                    panSizes[iRange + 1]);
     306           0 :             curOffset += panSizes[iRange + 1];
     307             :         }
     308             :         else
     309             :         {
     310           0 :             curRange++;
     311           0 :             memcpy(ppData[iRange + 1], mData[curRange], panSizes[iRange + 1]);
     312           0 :             curOffset = panSizes[iRange + 1];
     313             :         }
     314             :     }
     315             : 
     316           0 :     delete[] mOffsets;
     317           0 :     delete[] mSizes;
     318           0 :     for (int i = 0; i < nMergedRanges; i++)
     319             :     {
     320           0 :         delete[] mData[i];
     321             :     }
     322           0 :     delete[] mData;
     323             : 
     324           0 :     return ret;
     325             : }
     326             : 
     327           2 : void VSIPluginFilesystemHandler::AdviseRead(void *pFile, int nRanges,
     328             :                                             const vsi_l_offset *panOffsets,
     329             :                                             const size_t *panSizes)
     330             : {
     331           2 :     if (m_cb->advise_read != nullptr)
     332             :     {
     333           1 :         m_cb->advise_read(pFile, nRanges, panOffsets, panSizes);
     334             :     }
     335             :     else
     336             :     {
     337           1 :         if (!m_bWarnedAdviseReadImplemented)
     338             :         {
     339           1 :             m_bWarnedAdviseReadImplemented = true;
     340           1 :             CPLDebug("VSIPlugin", "AdviseRead() not implemented");
     341             :         }
     342             :     }
     343           2 : }
     344             : 
     345           0 : int VSIPluginFilesystemHandler::Eof(void *pFile)
     346             : {
     347           0 :     if (m_cb->eof != nullptr)
     348             :     {
     349           0 :         return m_cb->eof(pFile);
     350             :     }
     351           0 :     CPLError(CE_Failure, CPLE_AppDefined, "Eof not implemented for %s plugin",
     352             :              m_Prefix);
     353           0 :     return -1;
     354             : }
     355             : 
     356           0 : int VSIPluginFilesystemHandler::Error(void *pFile)
     357             : {
     358           0 :     if (m_cb->error)
     359             :     {
     360           0 :         return m_cb->error(pFile);
     361             :     }
     362           0 :     CPLDebug("CPL", "Error() not implemented for %s plugin", m_Prefix);
     363           0 :     return 0;
     364             : }
     365             : 
     366           0 : void VSIPluginFilesystemHandler::ClearErr(void *pFile)
     367             : {
     368           0 :     if (m_cb->clear_err)
     369             :     {
     370           0 :         m_cb->clear_err(pFile);
     371             :     }
     372             :     else
     373             :     {
     374           0 :         CPLDebug("CPL", "ClearErr() not implemented for %s plugin", m_Prefix);
     375             :     }
     376           0 : }
     377             : 
     378           2 : int VSIPluginFilesystemHandler::Close(void *pFile)
     379             : {
     380           2 :     if (m_cb->close != nullptr)
     381             :     {
     382           0 :         return m_cb->close(pFile);
     383             :     }
     384           2 :     CPLError(CE_Failure, CPLE_AppDefined, "Close not implemented for %s plugin",
     385             :              m_Prefix);
     386           2 :     return -1;
     387             : }
     388             : 
     389           0 : size_t VSIPluginFilesystemHandler::Write(void *pFile, const void *psBuffer,
     390             :                                          size_t nSize, size_t nCount)
     391             : {
     392           0 :     if (m_cb->write != nullptr)
     393             :     {
     394           0 :         return m_cb->write(pFile, psBuffer, nSize, nCount);
     395             :     }
     396           0 :     CPLError(CE_Failure, CPLE_AppDefined, "Write not implemented for %s plugin",
     397             :              m_Prefix);
     398           0 :     return -1;
     399             : }
     400             : 
     401           0 : int VSIPluginFilesystemHandler::Flush(void *pFile)
     402             : {
     403           0 :     if (m_cb->flush != nullptr)
     404             :     {
     405           0 :         return m_cb->flush(pFile);
     406             :     }
     407           0 :     CPLError(CE_Failure, CPLE_AppDefined, "Flush not implemented for %s plugin",
     408             :              m_Prefix);
     409           0 :     return -1;
     410             : }
     411             : 
     412           0 : int VSIPluginFilesystemHandler::Truncate(void *pFile, vsi_l_offset nNewSize)
     413             : {
     414           0 :     if (m_cb->truncate != nullptr)
     415             :     {
     416           0 :         return m_cb->truncate(pFile, nNewSize);
     417             :     }
     418           0 :     CPLError(CE_Failure, CPLE_AppDefined,
     419             :              "Truncate not implemented for %s plugin", m_Prefix);
     420           0 :     return -1;
     421             : }
     422             : 
     423           0 : char **VSIPluginFilesystemHandler::ReadDirEx(const char *pszDirname,
     424             :                                              int nMaxFiles)
     425             : {
     426           0 :     if (!IsValidFilename(pszDirname))
     427           0 :         return nullptr;
     428           0 :     if (m_cb->read_dir != nullptr)
     429             :     {
     430           0 :         return m_cb->read_dir(m_cb->pUserData, GetCallbackFilename(pszDirname),
     431           0 :                               nMaxFiles);
     432             :     }
     433           0 :     return nullptr;
     434             : }
     435             : 
     436           0 : char **VSIPluginFilesystemHandler::SiblingFiles(const char *pszFilename)
     437             : {
     438           0 :     if (!IsValidFilename(pszFilename))
     439           0 :         return nullptr;
     440           0 :     if (m_cb->sibling_files != nullptr)
     441             :     {
     442           0 :         return m_cb->sibling_files(m_cb->pUserData,
     443           0 :                                    GetCallbackFilename(pszFilename));
     444             :     }
     445           0 :     return nullptr;
     446             : }
     447             : 
     448           0 : int VSIPluginFilesystemHandler::Unlink(const char *pszFilename)
     449             : {
     450           0 :     if (m_cb->unlink == nullptr || !IsValidFilename(pszFilename))
     451           0 :         return -1;
     452           0 :     return unlink(GetCallbackFilename(pszFilename));
     453             : }
     454             : 
     455           0 : int VSIPluginFilesystemHandler::Rename(const char *oldpath, const char *newpath)
     456             : {
     457           0 :     if (m_cb->rename == nullptr || !IsValidFilename(oldpath) ||
     458           0 :         !IsValidFilename(newpath))
     459           0 :         return -1;
     460           0 :     return m_cb->rename(m_cb->pUserData, GetCallbackFilename(oldpath),
     461           0 :                         GetCallbackFilename(newpath));
     462             : }
     463             : 
     464           0 : int VSIPluginFilesystemHandler::Mkdir(const char *pszDirname, long nMode)
     465             : {
     466           0 :     if (m_cb->mkdir == nullptr || !IsValidFilename(pszDirname))
     467           0 :         return -1;
     468           0 :     return m_cb->mkdir(m_cb->pUserData, GetCallbackFilename(pszDirname), nMode);
     469             : }
     470             : 
     471           0 : int VSIPluginFilesystemHandler::Rmdir(const char *pszDirname)
     472             : {
     473           0 :     if (m_cb->rmdir == nullptr || !IsValidFilename(pszDirname))
     474           0 :         return -1;
     475           0 :     return m_cb->rmdir(m_cb->pUserData, GetCallbackFilename(pszDirname));
     476             : }
     477             : }  // namespace cpl
     478             : 
     479             : #endif  // DOXYGEN_SKIP
     480             : //! @endcond
     481             : 
     482           2 : int VSIInstallPluginHandler(const char *pszPrefix,
     483             :                             const VSIFilesystemPluginCallbacksStruct *poCb)
     484             : {
     485             :     VSIFilesystemHandler *poHandler =
     486           2 :         new cpl::VSIPluginFilesystemHandler(pszPrefix, poCb);
     487             :     // TODO: check pszPrefix starts and ends with a /
     488           2 :     VSIFileManager::InstallHandler(pszPrefix, poHandler);
     489           2 :     return 0;
     490             : }
     491             : 
     492           3 : int VSIRemovePluginHandler(const char *pszPrefix)
     493             : {
     494           3 :     VSIFileManager::RemoveHandler(pszPrefix);
     495           3 :     return 0;
     496             : }
     497             : 
     498             : VSIFilesystemPluginCallbacksStruct *
     499           2 : VSIAllocFilesystemPluginCallbacksStruct(void)
     500             : {
     501             :     return static_cast<VSIFilesystemPluginCallbacksStruct *>(
     502           2 :         VSI_CALLOC_VERBOSE(1, sizeof(VSIFilesystemPluginCallbacksStruct)));
     503             : }
     504             : 
     505           2 : void VSIFreeFilesystemPluginCallbacksStruct(
     506             :     VSIFilesystemPluginCallbacksStruct *poCb)
     507             : {
     508           2 :     CPLFree(poCb);
     509           2 : }

Generated by: LCOV version 1.14