LCOV - code coverage report
Current view: top level - port - cpl_vsi_error.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 60 88 68.2 %
Date: 2024-04-29 01:40:10 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  VSI Virtual File System
       4             :  * Purpose:  Implement an error system for reporting file system errors.
       5             :  *           Filesystem errors need to be handled separately from the
       6             :  *           CPLError architecture because they are potentially ignored.
       7             :  * Author:   Rob Emanuele, rdemanuele at gmail.com
       8             :  *
       9             :  ******************************************************************************
      10             :  * Copyright (c) 2016, Rob Emanuele <rdemanuele at gmail.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
      23             :  * OR 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             : #include "cpl_vsi_error.h"
      32             : 
      33             : #include <cstdarg>
      34             : #include <cstdio>
      35             : 
      36             : #include "cpl_config.h"
      37             : #include "cpl_conv.h"
      38             : #include "cpl_error.h"
      39             : #include "cpl_multiproc.h"
      40             : #include "cpl_string.h"
      41             : #include "cpl_vsi.h"
      42             : 
      43             : #if !defined(va_copy) && defined(__va_copy)
      44             : #define va_copy __va_copy
      45             : #endif
      46             : 
      47             : // TODO(rouault): Why is this here?
      48             : #if !defined(_WIN32)
      49             : #include <string.h>
      50             : #endif
      51             : 
      52             : #define TIMESTAMP_DEBUG
      53             : // #define MEMORY_DEBUG
      54             : 
      55             : constexpr int DEFAULT_LAST_ERR_MSG_SIZE =
      56             : #if !defined(HAVE_VSNPRINTF)
      57             :     20000
      58             : #else
      59             :     500
      60             : #endif
      61             :     ;
      62             : 
      63             : typedef struct
      64             : {
      65             :     VSIErrorNum nLastErrNo;
      66             :     int nLastErrMsgMax;
      67             :     char szLastErrMsg[DEFAULT_LAST_ERR_MSG_SIZE];
      68             :     // Do not add anything here. szLastErrMsg must be the last field. See
      69             :     // CPLRealloc() below.
      70             : } VSIErrorContext;
      71             : 
      72             : /************************************************************************/
      73             : /*                         CPLGetErrorContext()                         */
      74             : /************************************************************************/
      75             : 
      76      133492 : static VSIErrorContext *VSIGetErrorContext()
      77             : 
      78             : {
      79      133492 :     int bError = FALSE;
      80             :     VSIErrorContext *psCtx = reinterpret_cast<VSIErrorContext *>(
      81      133492 :         CPLGetTLSEx(CTLS_VSIERRORCONTEXT, &bError));
      82      133473 :     if (bError)
      83           0 :         return nullptr;
      84             : 
      85      133473 :     if (psCtx == nullptr)
      86             :     {
      87             :         psCtx = static_cast<VSIErrorContext *>(
      88        1098 :             VSICalloc(sizeof(VSIErrorContext), 1));
      89        1098 :         if (psCtx == nullptr)
      90             :         {
      91           0 :             fprintf(stderr, /*ok*/
      92             :                     "Out of memory attempting to record a VSI error.\n");
      93           0 :             return nullptr;
      94             :         }
      95        1098 :         psCtx->nLastErrNo = VSIE_None;
      96        1098 :         psCtx->nLastErrMsgMax = sizeof(psCtx->szLastErrMsg);
      97        1098 :         CPLSetTLS(CTLS_VSIERRORCONTEXT, psCtx, TRUE);
      98             :     }
      99             : 
     100      133462 :     return psCtx;
     101             : }
     102             : 
     103             : /************************************************************************/
     104             : /*                             VSIErrorV()                              */
     105             : /************************************************************************/
     106             : 
     107       18612 : static void VSIErrorV(VSIErrorNum err_no, const char *fmt, va_list args)
     108             : {
     109       18612 :     VSIErrorContext *psCtx = VSIGetErrorContext();
     110       18612 :     if (psCtx == nullptr)
     111           0 :         return;
     112             : 
     113             : /* -------------------------------------------------------------------- */
     114             : /*      Expand the error message                                        */
     115             : /* -------------------------------------------------------------------- */
     116             : #if defined(HAVE_VSNPRINTF)
     117             :     {
     118             :         va_list wrk_args;
     119             : 
     120             : #ifdef va_copy
     121       18612 :         va_copy(wrk_args, args);
     122             : #else
     123             :         wrk_args = args;
     124             : #endif
     125             : 
     126       18612 :         int nPreviousSize = 0;
     127       18612 :         int nPR = 0;
     128          53 :         while (((nPR = CPLvsnprintf(psCtx->szLastErrMsg + nPreviousSize,
     129       18665 :                                     psCtx->nLastErrMsgMax - nPreviousSize, fmt,
     130       18665 :                                     wrk_args)) == -1 ||
     131       18718 :                 nPR >= psCtx->nLastErrMsgMax - nPreviousSize - 1) &&
     132          53 :                psCtx->nLastErrMsgMax < 1000000)
     133             :         {
     134             : #ifdef va_copy
     135          53 :             va_end(wrk_args);
     136          53 :             va_copy(wrk_args, args);
     137             : #else
     138             :             wrk_args = args;
     139             : #endif
     140          53 :             psCtx->nLastErrMsgMax *= 3;
     141         106 :             psCtx = static_cast<VSIErrorContext *>(CPLRealloc(
     142             :                 psCtx, sizeof(VSIErrorContext) - DEFAULT_LAST_ERR_MSG_SIZE +
     143          53 :                            psCtx->nLastErrMsgMax + 1));
     144          53 :             CPLSetTLS(CTLS_VSIERRORCONTEXT, psCtx, TRUE);
     145             :         }
     146             : 
     147       18612 :         va_end(wrk_args);
     148             :     }
     149             : #else  // !HAVE_VSNPRINTF
     150             :     CPLvsnprintf(psCtx->szLastErrMsg, psCtx->nLastErrMsgMax, fmt, args);
     151             : #endif
     152             : 
     153       18612 :     psCtx->nLastErrNo = err_no;
     154             : }
     155             : 
     156             : /**********************************************************************
     157             :  *                          VSIError()
     158             :  **********************************************************************/
     159             : 
     160             : /**
     161             :  * Report an VSI filesystem error.
     162             :  *
     163             :  * This function records an error in the filesystem that may or may not be
     164             :  * used in the future, for example converted into a CPLError. This allows
     165             :  * filesystem errors to be available to error handling functionality, but
     166             :  * reported only when necessary.
     167             :  *
     168             :  * @param err_no the error number (VSIE_*) from cpl_vsi_error.h.
     169             :  * @param fmt a printf() style format string.  Any additional arguments
     170             :  * will be treated as arguments to fill in this format in a manner
     171             :  * similar to printf().
     172             :  */
     173             : 
     174       18612 : void VSIError(VSIErrorNum err_no, CPL_FORMAT_STRING(const char *fmt), ...)
     175             : {
     176             :     va_list args;
     177             : 
     178             :     // Expand the error message.
     179       18612 :     va_start(args, fmt);
     180       18612 :     VSIErrorV(err_no, fmt, args);
     181       18612 :     va_end(args);
     182       18612 : }
     183             : 
     184             : /**********************************************************************
     185             :  *                          VSIErrorReset()
     186             :  **********************************************************************/
     187             : 
     188             : /**
     189             :  * Erase any traces of previous errors.
     190             :  *
     191             :  * This is used to clear out the latest file system error when it is either
     192             :  * translated into a CPLError call or when it is determined to be ignorable.
     193             :  */
     194             : 
     195      103637 : void CPL_STDCALL VSIErrorReset()
     196             : {
     197      103637 :     VSIErrorContext *psCtx = VSIGetErrorContext();
     198      103635 :     if (psCtx == nullptr)
     199           0 :         return;
     200             : 
     201      103635 :     psCtx->nLastErrNo = VSIE_None;
     202      103635 :     psCtx->szLastErrMsg[0] = '\0';
     203             : }
     204             : 
     205             : /**********************************************************************
     206             :  *                          VSIGetLastErrorNo()
     207             :  **********************************************************************/
     208             : 
     209             : /**
     210             :  * Fetch the last error number.
     211             :  *
     212             :  * Fetches the last error number posted with VSIError(), that hasn't
     213             :  * been cleared by VSIErrorReset().  This is the error number, not the error
     214             :  * class.
     215             :  *
     216             :  * @return the error number of the last error to occur, or VSIE_None (0)
     217             :  * if there are no posted errors.
     218             :  */
     219             : 
     220        5686 : VSIErrorNum CPL_STDCALL VSIGetLastErrorNo()
     221             : {
     222        5686 :     VSIErrorContext *psCtx = VSIGetErrorContext();
     223        5658 :     if (psCtx == nullptr)
     224           0 :         return 0;
     225             : 
     226        5658 :     return psCtx->nLastErrNo;
     227             : }
     228             : 
     229             : /**********************************************************************
     230             :  *                          VSIGetLastErrorMsg()
     231             :  **********************************************************************/
     232             : 
     233             : /**
     234             :  * Get the last error message.
     235             :  *
     236             :  * Fetches the last error message posted with VSIError(), that hasn't
     237             :  * been cleared by VSIErrorReset().  The returned pointer is to an internal
     238             :  * string that should not be altered or freed.
     239             :  *
     240             :  * @return the last error message, or NULL if there is no posted error
     241             :  * message.
     242             :  */
     243             : 
     244        5575 : const char *CPL_STDCALL VSIGetLastErrorMsg()
     245             : {
     246        5575 :     VSIErrorContext *psCtx = VSIGetErrorContext();
     247        5555 :     if (psCtx == nullptr)
     248           0 :         return "";
     249             : 
     250        5555 :     return psCtx->szLastErrMsg;
     251             : }
     252             : 
     253             : /**********************************************************************
     254             :  *                          VSItoCPLError()
     255             :  **********************************************************************/
     256             : 
     257             : /**
     258             :  * Translate the VSI error into a CPLError call
     259             :  *
     260             :  * If there is a VSIError that is set, translate it to a CPLError call
     261             :  * with the given CPLErr error class, and either an appropriate CPLErrorNum
     262             :  * given the VSIErrorNum, or the given default CPLErrorNum.
     263             :  *
     264             :  * @return TRUE if a CPLError was issued, or FALSE if not.
     265             :  */
     266             : 
     267        5666 : int CPL_DLL CPL_STDCALL VSIToCPLError(CPLErr eErrClass,
     268             :                                       CPLErrorNum eDefaultErrorNo)
     269             : {
     270        5666 :     const int err = VSIGetLastErrorNo();
     271        5652 :     switch (err)
     272             :     {
     273         146 :         case VSIE_None:
     274         146 :             return FALSE;
     275        5503 :         case VSIE_FileError:
     276        5503 :             CPLError(eErrClass, eDefaultErrorNo, "%s", VSIGetLastErrorMsg());
     277        5522 :             break;
     278           4 :         case VSIE_HttpError:
     279           4 :             CPLError(eErrClass, CPLE_HttpResponse, "%s", VSIGetLastErrorMsg());
     280           4 :             break;
     281           0 :         case VSIE_AWSError:
     282           0 :             CPLError(eErrClass, CPLE_AWSError, "%s", VSIGetLastErrorMsg());
     283           0 :             break;
     284           0 :         case VSIE_AWSAccessDenied:
     285           0 :             CPLError(eErrClass, CPLE_AWSAccessDenied, "%s",
     286             :                      VSIGetLastErrorMsg());
     287           0 :             break;
     288           0 :         case VSIE_AWSBucketNotFound:
     289           0 :             CPLError(eErrClass, CPLE_AWSBucketNotFound, "%s",
     290             :                      VSIGetLastErrorMsg());
     291           0 :             break;
     292           0 :         case VSIE_AWSObjectNotFound:
     293           0 :             CPLError(eErrClass, CPLE_AWSObjectNotFound, "%s",
     294             :                      VSIGetLastErrorMsg());
     295           0 :             break;
     296           0 :         case VSIE_AWSInvalidCredentials:
     297           0 :             CPLError(eErrClass, CPLE_AWSInvalidCredentials, "%s",
     298             :                      VSIGetLastErrorMsg());
     299           0 :             break;
     300           0 :         case VSIE_AWSSignatureDoesNotMatch:
     301           0 :             CPLError(eErrClass, CPLE_AWSSignatureDoesNotMatch, "%s",
     302             :                      VSIGetLastErrorMsg());
     303           0 :             break;
     304           0 :         default:
     305           0 :             CPLError(eErrClass, CPLE_HttpResponse,
     306             :                      "A filesystem error with code %d occurred", err);
     307           0 :             break;
     308             :     }
     309             : 
     310        5526 :     return TRUE;
     311             : }

Generated by: LCOV version 1.14