LCOV - code coverage report
Current view: top level - port - cpl_vsil_plugin.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 58 213 27.2 %
Date: 2024-04-28 23:18:46 Functions: 17 43 39.5 %

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

Generated by: LCOV version 1.14