• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OSGeo / gdal / 14945877415

10 May 2025 01:37PM UTC coverage: 70.838% (+0.004%) from 70.834%
14945877415

Pull #12331

github

web-flow
Merge e74fde6a5 into a1ee70739
Pull Request #12331: GDALG: do not Open() in update mode, and 100% code coverage

12 of 12 new or added lines in 2 files covered. (100.0%)

73 existing lines in 35 files now uncovered.

565410 of 798178 relevant lines covered (70.84%)

234821.49 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

54.92
/port/cpl_vsi_error.cpp
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
 * SPDX-License-Identifier: MIT
13
 ****************************************************************************/
14

15
#include "cpl_vsi_error.h"
16

17
#include <cstdarg>
18
#include <cstdio>
19

20
#include "cpl_config.h"
21
#include "cpl_conv.h"
22
#include "cpl_error.h"
23
#include "cpl_multiproc.h"
24
#include "cpl_string.h"
25
#include "cpl_vsi.h"
26

27
#if !defined(va_copy) && defined(__va_copy)
28
#define va_copy __va_copy
29
#endif
30

31
// TODO(rouault): Why is this here?
32
#if !defined(_WIN32)
33
#include <string.h>
34
#endif
35

36
#define TIMESTAMP_DEBUG
37
// #define MEMORY_DEBUG
38

39
constexpr int DEFAULT_LAST_ERR_MSG_SIZE =
40
#if !defined(HAVE_VSNPRINTF)
41
    20000
42
#else
43
    500
44
#endif
45
    ;
46

47
typedef struct
48
{
49
    VSIErrorNum nLastErrNo;
50
    int nLastErrMsgMax;
51
    char szLastErrMsg[DEFAULT_LAST_ERR_MSG_SIZE];
52
    // Do not add anything here. szLastErrMsg must be the last field. See
53
    // CPLRealloc() below.
54
} VSIErrorContext;
55

56
/************************************************************************/
57
/*                         CPLGetErrorContext()                         */
58
/************************************************************************/
59

60
static VSIErrorContext *VSIGetErrorContext()
159,182✔
61

62
{
63
    int bError = FALSE;
159,182✔
64
    VSIErrorContext *psCtx = reinterpret_cast<VSIErrorContext *>(
65
        CPLGetTLSEx(CTLS_VSIERRORCONTEXT, &bError));
159,182✔
66
    if (bError)
159,159✔
67
        return nullptr;
×
68

69
    if (psCtx == nullptr)
159,159✔
70
    {
71
        psCtx = static_cast<VSIErrorContext *>(
72
            VSICalloc(sizeof(VSIErrorContext), 1));
1,365✔
73
        if (psCtx == nullptr)
1,365✔
74
        {
75
            fprintf(stderr, /*ok*/
×
76
                    "Out of memory attempting to record a VSI error.\n");
77
            return nullptr;
×
78
        }
79
        psCtx->nLastErrNo = VSIE_None;
1,365✔
80
        psCtx->nLastErrMsgMax = sizeof(psCtx->szLastErrMsg);
1,365✔
81
        CPLSetTLS(CTLS_VSIERRORCONTEXT, psCtx, TRUE);
1,365✔
82
    }
83

84
    return psCtx;
159,182✔
85
}
86

87
/************************************************************************/
88
/*                             VSIErrorV()                              */
89
/************************************************************************/
90

91
static void VSIErrorV(VSIErrorNum err_no, const char *fmt, va_list args)
19,367✔
92
{
93
    VSIErrorContext *psCtx = VSIGetErrorContext();
19,367✔
94
    if (psCtx == nullptr)
19,367✔
95
        return;
×
96

97
/* -------------------------------------------------------------------- */
98
/*      Expand the error message                                        */
99
/* -------------------------------------------------------------------- */
100
#if defined(HAVE_VSNPRINTF)
101
    {
102
        va_list wrk_args;
103

104
#ifdef va_copy
105
        va_copy(wrk_args, args);
19,367✔
106
#else
107
        wrk_args = args;
108
#endif
109

110
        int nPreviousSize = 0;
19,367✔
111
        int nPR = 0;
19,367✔
112
        while (((nPR = CPLvsnprintf(psCtx->szLastErrMsg + nPreviousSize,
58✔
113
                                    psCtx->nLastErrMsgMax - nPreviousSize, fmt,
19,425✔
114
                                    wrk_args)) == -1 ||
19,423✔
115
                nPR >= psCtx->nLastErrMsgMax - nPreviousSize - 1) &&
19,483✔
116
               psCtx->nLastErrMsgMax < 1000000)
59✔
117
        {
118
#ifdef va_copy
119
            va_end(wrk_args);
58✔
120
            va_copy(wrk_args, args);
58✔
121
#else
122
            wrk_args = args;
123
#endif
124
            psCtx->nLastErrMsgMax *= 3;
58✔
125
            psCtx = static_cast<VSIErrorContext *>(CPLRealloc(
116✔
126
                psCtx, sizeof(VSIErrorContext) - DEFAULT_LAST_ERR_MSG_SIZE +
127
                           psCtx->nLastErrMsgMax + 1));
58✔
128
            CPLSetTLS(CTLS_VSIERRORCONTEXT, psCtx, TRUE);
58✔
129
        }
130

131
        va_end(wrk_args);
19,366✔
132
    }
133
#else  // !HAVE_VSNPRINTF
134
    CPLvsnprintf(psCtx->szLastErrMsg, psCtx->nLastErrMsgMax, fmt, args);
135
#endif
136

137
    psCtx->nLastErrNo = err_no;
19,366✔
138
}
139

140
/**********************************************************************
141
 *                          VSIError()
142
 **********************************************************************/
143

144
/**
145
 * Report an VSI filesystem error.
146
 *
147
 * This function records an error in the filesystem that may or may not be
148
 * used in the future, for example converted into a CPLError. This allows
149
 * filesystem errors to be available to error handling functionality, but
150
 * reported only when necessary.
151
 *
152
 * @param err_no the error number (VSIE_*) from cpl_vsi_error.h.
153
 * @param fmt a printf() style format string.  Any additional arguments
154
 * will be treated as arguments to fill in this format in a manner
155
 * similar to printf().
156
 */
157

158
void VSIError(VSIErrorNum err_no, CPL_FORMAT_STRING(const char *fmt), ...)
19,366✔
159
{
160
    va_list args;
161

162
    // Expand the error message.
163
    va_start(args, fmt);
19,366✔
164
    VSIErrorV(err_no, fmt, args);
19,366✔
165
    va_end(args);
19,366✔
166
}
19,366✔
167

168
/**********************************************************************
169
 *                          VSIErrorReset()
170
 **********************************************************************/
171

172
/**
173
 * Erase any traces of previous errors.
174
 *
175
 * This is used to clear out the latest file system error when it is either
176
 * translated into a CPLError call or when it is determined to be ignorable.
177
 */
178

179
void CPL_STDCALL VSIErrorReset()
128,972✔
180
{
181
    VSIErrorContext *psCtx = VSIGetErrorContext();
128,972✔
182
    if (psCtx == nullptr)
128,976✔
183
        return;
×
184

185
    psCtx->nLastErrNo = VSIE_None;
128,976✔
186
    psCtx->szLastErrMsg[0] = '\0';
128,976✔
187
}
188

189
/**********************************************************************
190
 *                          VSIGetLastErrorNo()
191
 **********************************************************************/
192

193
/**
194
 * Fetch the last error number.
195
 *
196
 * Fetches the last error number posted with VSIError(), that hasn't
197
 * been cleared by VSIErrorReset().  This is the error number, not the error
198
 * class.
199
 *
200
 * @return the error number of the last error to occur, or VSIE_None (0)
201
 * if there are no posted errors.
202
 */
203

204
VSIErrorNum CPL_STDCALL VSIGetLastErrorNo()
5,578✔
205
{
206
    VSIErrorContext *psCtx = VSIGetErrorContext();
5,578✔
207
    if (psCtx == nullptr)
5,573✔
208
        return 0;
×
209

210
    return psCtx->nLastErrNo;
5,573✔
211
}
212

213
/**********************************************************************
214
 *                          VSIGetLastErrorMsg()
215
 **********************************************************************/
216

217
/**
218
 * Get the last error message.
219
 *
220
 * Fetches the last error message posted with VSIError(), that hasn't
221
 * been cleared by VSIErrorReset().  The returned pointer is to an internal
222
 * string that should not be altered or freed.
223
 *
224
 * @return the last error message, or NULL if there is no posted error
225
 * message.
226
 */
227

228
const char *CPL_STDCALL VSIGetLastErrorMsg()
5,278✔
229
{
230
    VSIErrorContext *psCtx = VSIGetErrorContext();
5,278✔
231
    if (psCtx == nullptr)
5,248✔
232
        return "";
×
233

234
    return psCtx->szLastErrMsg;
5,248✔
235
}
236

237
/**********************************************************************
238
 *                          VSItoCPLError()
239
 **********************************************************************/
240

241
/**
242
 * Translate the VSI error into a CPLError call
243
 *
244
 * If there is a VSIError that is set, translate it to a CPLError call
245
 * with the given CPLErr error class, and either an appropriate CPLErrorNum
246
 * given the VSIErrorNum, or the given default CPLErrorNum.
247
 *
248
 * @return TRUE if a CPLError was issued, or FALSE if not.
249
 */
250

251
int CPL_STDCALL VSIToCPLError(CPLErr eErrClass, CPLErrorNum eDefaultErrorNo)
5,563✔
252
{
253
    const int err = VSIGetLastErrorNo();
5,563✔
254
    switch (err)
5,528✔
255
    {
256
        case VSIE_None:
354✔
257
            return FALSE;
354✔
258
        case VSIE_FileError:
5,201✔
259
            CPLError(eErrClass, eDefaultErrorNo, "%s", VSIGetLastErrorMsg());
5,201✔
260
            break;
5,205✔
261
        case VSIE_HttpError:
4✔
262
            CPLError(eErrClass, CPLE_HttpResponse, "%s", VSIGetLastErrorMsg());
4✔
263
            break;
4✔
264
        case VSIE_AWSError:
×
265
            CPLError(eErrClass, CPLE_AWSError, "%s", VSIGetLastErrorMsg());
×
266
            break;
×
267
        case VSIE_AWSAccessDenied:
×
268
            CPLError(eErrClass, CPLE_AWSAccessDenied, "%s",
×
269
                     VSIGetLastErrorMsg());
270
            break;
×
271
        case VSIE_AWSBucketNotFound:
×
272
            CPLError(eErrClass, CPLE_AWSBucketNotFound, "%s",
×
273
                     VSIGetLastErrorMsg());
274
            break;
×
275
        case VSIE_AWSObjectNotFound:
×
276
            CPLError(eErrClass, CPLE_AWSObjectNotFound, "%s",
×
277
                     VSIGetLastErrorMsg());
278
            break;
×
279
        case VSIE_AWSInvalidCredentials:
×
280
            CPLError(eErrClass, CPLE_AWSInvalidCredentials, "%s",
×
281
                     VSIGetLastErrorMsg());
282
            break;
×
283
        case VSIE_AWSSignatureDoesNotMatch:
×
284
            CPLError(eErrClass, CPLE_AWSSignatureDoesNotMatch, "%s",
×
285
                     VSIGetLastErrorMsg());
UNCOV
286
            break;
×
287
        default:
×
288
            CPLError(eErrClass, CPLE_HttpResponse,
×
289
                     "A filesystem error with code %d occurred", err);
290
            break;
×
291
    }
292

293
    return TRUE;
5,208✔
294
}
295

296
/**********************************************************************
297
 *                        VSIToCPLErrorWithMsg()
298
 **********************************************************************/
299

300
/**
301
 * Translate the VSI error into a CPLError call
302
 *
303
 * If there is a VSIError that is set, translate it to a CPLError call
304
 * with the given CPLErr error class, and either an appropriate CPLErrorNum
305
 * given the VSIErrorNum, or the given default CPLErrorNum.
306
 */
307

308
void VSIToCPLErrorWithMsg(CPLErr eErrClass, CPLErrorNum eDefaultErrorNo,
17✔
309
                          const char *pszMsg)
310
{
311
    const int err = VSIGetLastErrorNo();
17✔
312
    switch (err)
17✔
313
    {
314
        case VSIE_None:
×
315
            CPLError(eErrClass, eDefaultErrorNo, "%s", pszMsg);
×
316
            break;
×
317
        case VSIE_FileError:
17✔
318
            CPLError(eErrClass, eDefaultErrorNo, "%s: %s", pszMsg,
17✔
319
                     VSIGetLastErrorMsg());
320
            break;
17✔
321
        case VSIE_HttpError:
×
322
            CPLError(eErrClass, CPLE_HttpResponse, "%s: %s", pszMsg,
×
323
                     VSIGetLastErrorMsg());
324
            break;
×
325
        case VSIE_AWSError:
×
326
            CPLError(eErrClass, CPLE_AWSError, "%s: %s", pszMsg,
×
327
                     VSIGetLastErrorMsg());
328
            break;
×
329
        case VSIE_AWSAccessDenied:
×
330
            CPLError(eErrClass, CPLE_AWSAccessDenied, "%s: %s", pszMsg,
×
331
                     VSIGetLastErrorMsg());
332
            break;
×
333
        case VSIE_AWSBucketNotFound:
×
334
            CPLError(eErrClass, CPLE_AWSBucketNotFound, "%s: %s", pszMsg,
×
335
                     VSIGetLastErrorMsg());
336
            break;
×
337
        case VSIE_AWSObjectNotFound:
×
338
            CPLError(eErrClass, CPLE_AWSObjectNotFound, "%s: %s", pszMsg,
×
339
                     VSIGetLastErrorMsg());
340
            break;
×
341
        case VSIE_AWSInvalidCredentials:
×
342
            CPLError(eErrClass, CPLE_AWSInvalidCredentials, "%s: %s", pszMsg,
×
343
                     VSIGetLastErrorMsg());
344
            break;
×
345
        case VSIE_AWSSignatureDoesNotMatch:
×
346
            CPLError(eErrClass, CPLE_AWSSignatureDoesNotMatch, "%s: %s", pszMsg,
×
347
                     VSIGetLastErrorMsg());
348
            break;
×
349
        default:
×
350
            CPLError(eErrClass, CPLE_HttpResponse,
×
351
                     "%s: A filesystem error with code %d occurred", pszMsg,
352
                     err);
353
            break;
×
354
    }
355
}
17✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc