Coverage Report

Created: 2025-06-13 06:29

/src/gdal/port/cpl_vsi_virtual.h
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 *
3
 * Project:  VSI Virtual File System
4
 * Purpose:  Declarations for classes related to the virtual filesystem.
5
 *           These would only be normally required by applications implementing
6
 *           their own virtual file system classes which should be rare.
7
 *           The class interface may be fragile through versions.
8
 * Author:   Frank Warmerdam, warmerdam@pobox.com
9
 *
10
 ******************************************************************************
11
 * Copyright (c) 2005, Frank Warmerdam <warmerdam@pobox.com>
12
 * Copyright (c) 2010-2014, Even Rouault <even dot rouault at spatialys.com>
13
 *
14
 * SPDX-License-Identifier: MIT
15
 ****************************************************************************/
16
17
#ifndef CPL_VSI_VIRTUAL_H_INCLUDED
18
#define CPL_VSI_VIRTUAL_H_INCLUDED
19
20
#include "cpl_progress.h"
21
#include "cpl_vsi.h"
22
#include "cpl_vsi_error.h"
23
#include "cpl_string.h"
24
#include "cpl_multiproc.h"
25
26
#include <map>
27
#include <memory>
28
#include <vector>
29
#include <string>
30
31
// To avoid aliasing to GetDiskFreeSpace to GetDiskFreeSpaceA on Windows
32
#ifdef GetDiskFreeSpace
33
#undef GetDiskFreeSpace
34
#endif
35
36
// To avoid aliasing to CopyFile to CopyFileA on Windows
37
#ifdef CopyFile
38
#undef CopyFile
39
#endif
40
41
/************************************************************************/
42
/*                           VSIVirtualHandle                           */
43
/************************************************************************/
44
45
/** Virtual file handle */
46
struct CPL_DLL VSIVirtualHandle
47
{
48
  public:
49
    virtual int Seek(vsi_l_offset nOffset, int nWhence) = 0;
50
    virtual vsi_l_offset Tell() = 0;
51
    virtual size_t Read(void *pBuffer, size_t nSize, size_t nCount) = 0;
52
    virtual int ReadMultiRange(int nRanges, void **ppData,
53
                               const vsi_l_offset *panOffsets,
54
                               const size_t *panSizes);
55
56
    /** This method is called when code plans to access soon one or several
57
     * ranges in a file. Some file systems may be able to use this hint to
58
     * for example asynchronously start such requests.
59
     *
60
     * Offsets may be given in a non-increasing order, and may potentially
61
     * overlap.
62
     *
63
     * @param nRanges Size of the panOffsets and panSizes arrays.
64
     * @param panOffsets Array containing the start offset of each range.
65
     * @param panSizes Array containing the size (in bytes) of each range.
66
     * @since GDAL 3.7
67
     */
68
    virtual void AdviseRead(CPL_UNUSED int nRanges,
69
                            CPL_UNUSED const vsi_l_offset *panOffsets,
70
                            CPL_UNUSED const size_t *panSizes)
71
0
    {
72
0
    }
73
74
    /** Return the total maximum number of bytes that AdviseRead() can handle
75
     * at once.
76
     *
77
     * Some AdviseRead() implementations may give up if the sum of the values
78
     * in the panSizes[] array provided to AdviseRead() exceeds a limit.
79
     *
80
     * Callers might use that threshold to optimize the efficiency of
81
     * AdviseRead().
82
     *
83
     * A returned value of 0 indicates a unknown limit.
84
     * @since GDAL 3.9
85
     */
86
    virtual size_t GetAdviseReadTotalBytesLimit() const
87
0
    {
88
0
        return 0;
89
0
    }
90
91
    virtual size_t Write(const void *pBuffer, size_t nSize, size_t nCount) = 0;
92
93
    int Printf(CPL_FORMAT_STRING(const char *pszFormat), ...)
94
        CPL_PRINT_FUNC_FORMAT(2, 3);
95
96
    virtual void ClearErr() = 0;
97
98
    virtual int Eof() = 0;
99
100
    virtual int Error() = 0;
101
102
    virtual int Flush()
103
0
    {
104
0
        return 0;
105
0
    }
106
107
    virtual int Close() = 0;
108
    // Base implementation that only supports file extension.
109
    virtual int Truncate(vsi_l_offset nNewSize);
110
111
    virtual void *GetNativeFileDescriptor()
112
0
    {
113
0
        return nullptr;
114
0
    }
115
116
    virtual VSIRangeStatus GetRangeStatus(CPL_UNUSED vsi_l_offset nOffset,
117
                                          CPL_UNUSED vsi_l_offset nLength)
118
0
    {
119
0
        return VSI_RANGE_STATUS_UNKNOWN;
120
0
    }
121
122
    virtual bool HasPRead() const;
123
    virtual size_t PRead(void *pBuffer, size_t nSize,
124
                         vsi_l_offset nOffset) const;
125
126
    /** Ask current operations to be interrupted.
127
     * Implementations must be thread-safe, as this will typically be called
128
     * from another thread than the active one for this file.
129
     */
130
    virtual void Interrupt()
131
0
    {
132
0
    }
133
134
    // NOTE: when adding new methods, besides the "actual" implementations,
135
    // also consider the VSICachedFile one.
136
137
    virtual ~VSIVirtualHandle()
138
6.97k
    {
139
6.97k
    }
140
};
141
142
/************************************************************************/
143
/*                        VSIVirtualHandleCloser                        */
144
/************************************************************************/
145
146
/** Helper close to use with a std:unique_ptr<VSIVirtualHandle>,
147
 *  such as VSIVirtualHandleUniquePtr. */
148
struct VSIVirtualHandleCloser
149
{
150
    /** Operator () that closes and deletes the file handle. */
151
    void operator()(VSIVirtualHandle *poHandle)
152
2.15k
    {
153
2.15k
        if (poHandle)
154
2.15k
        {
155
2.15k
            poHandle->Close();
156
2.15k
            delete poHandle;
157
2.15k
        }
158
2.15k
    }
159
};
160
161
/** Unique pointer of VSIVirtualHandle that calls the Close() method */
162
typedef std::unique_ptr<VSIVirtualHandle, VSIVirtualHandleCloser>
163
    VSIVirtualHandleUniquePtr;
164
165
/************************************************************************/
166
/*                         VSIFilesystemHandler                         */
167
/************************************************************************/
168
169
#ifndef DOXYGEN_SKIP
170
class CPL_DLL VSIFilesystemHandler
171
{
172
173
  public:
174
    virtual ~VSIFilesystemHandler()
175
0
    {
176
0
    }
177
178
    VSIVirtualHandle *Open(const char *pszFilename, const char *pszAccess);
179
180
    virtual VSIVirtualHandle *Open(const char *pszFilename,
181
                                   const char *pszAccess, bool bSetError,
182
                                   CSLConstList papszOptions) = 0;
183
    virtual int Stat(const char *pszFilename, VSIStatBufL *pStatBuf,
184
                     int nFlags) = 0;
185
186
    virtual int Unlink(const char *pszFilename)
187
0
    {
188
0
        (void)pszFilename;
189
0
        errno = ENOENT;
190
0
        return -1;
191
0
    }
192
193
    virtual int *UnlinkBatch(CSLConstList papszFiles);
194
195
    virtual int Mkdir(const char *pszDirname, long nMode)
196
0
    {
197
0
        (void)pszDirname;
198
0
        (void)nMode;
199
0
        errno = ENOENT;
200
0
        return -1;
201
0
    }
202
203
    virtual int Rmdir(const char *pszDirname)
204
0
    {
205
0
        (void)pszDirname;
206
0
        errno = ENOENT;
207
0
        return -1;
208
0
    }
209
210
    virtual int RmdirRecursive(const char *pszDirname);
211
212
    char **ReadDir(const char *pszDirname)
213
0
    {
214
0
        return ReadDirEx(pszDirname, 0);
215
0
    }
216
217
    virtual char **ReadDirEx(const char * /*pszDirname*/, int /* nMaxFiles */)
218
0
    {
219
0
        return nullptr;
220
0
    }
221
222
    virtual char **SiblingFiles(const char * /*pszFilename*/)
223
0
    {
224
0
        return nullptr;
225
0
    }
226
227
    virtual int Rename(const char *oldpath, const char *newpath,
228
                       GDALProgressFunc pProgressFunc, void *pProgressData)
229
0
    {
230
0
        (void)oldpath;
231
0
        (void)newpath;
232
0
        (void)pProgressFunc;
233
0
        (void)pProgressData;
234
0
        errno = ENOENT;
235
0
        return -1;
236
0
    }
237
238
    virtual int IsCaseSensitive(const char *pszFilename)
239
0
    {
240
0
        (void)pszFilename;
241
0
        return TRUE;
242
0
    }
243
244
    virtual GIntBig GetDiskFreeSpace(const char * /* pszDirname */)
245
0
    {
246
0
        return -1;
247
0
    }
248
249
    virtual int SupportsSparseFiles(const char * /* pszPath */)
250
0
    {
251
0
        return FALSE;
252
0
    }
253
254
    virtual int HasOptimizedReadMultiRange(const char * /* pszPath */)
255
0
    {
256
0
        return FALSE;
257
0
    }
258
259
    virtual const char *GetActualURL(const char * /*pszFilename*/)
260
0
    {
261
0
        return nullptr;
262
0
    }
263
264
    virtual const char *GetOptions()
265
0
    {
266
0
        return nullptr;
267
0
    }
268
269
    virtual char *GetSignedURL(const char * /*pszFilename*/,
270
                               CSLConstList /* papszOptions */)
271
0
    {
272
0
        return nullptr;
273
0
    }
274
275
    virtual bool Sync(const char *pszSource, const char *pszTarget,
276
                      const char *const *papszOptions,
277
                      GDALProgressFunc pProgressFunc, void *pProgressData,
278
                      char ***ppapszOutputs);
279
280
    virtual int CopyFile(const char *pszSource, const char *pszTarget,
281
                         VSILFILE *fpSource, vsi_l_offset nSourceSize,
282
                         const char *const *papszOptions,
283
                         GDALProgressFunc pProgressFunc, void *pProgressData);
284
285
    virtual int
286
    CopyFileRestartable(const char *pszSource, const char *pszTarget,
287
                        const char *pszInputPayload, char **ppszOutputPayload,
288
                        CSLConstList papszOptions,
289
                        GDALProgressFunc pProgressFunc, void *pProgressData);
290
291
    virtual VSIDIR *OpenDir(const char *pszPath, int nRecurseDepth,
292
                            const char *const *papszOptions);
293
294
    virtual char **GetFileMetadata(const char *pszFilename,
295
                                   const char *pszDomain,
296
                                   CSLConstList papszOptions);
297
298
    virtual bool SetFileMetadata(const char *pszFilename,
299
                                 CSLConstList papszMetadata,
300
                                 const char *pszDomain,
301
                                 CSLConstList papszOptions);
302
303
    virtual bool
304
    MultipartUploadGetCapabilities(int *pbNonSequentialUploadSupported,
305
                                   int *pbParallelUploadSupported,
306
                                   int *pbAbortSupported, size_t *pnMinPartSize,
307
                                   size_t *pnMaxPartSize, int *pnMaxPartCount);
308
309
    virtual char *MultipartUploadStart(const char *pszFilename,
310
                                       CSLConstList papszOptions);
311
312
    virtual char *MultipartUploadAddPart(const char *pszFilename,
313
                                         const char *pszUploadId,
314
                                         int nPartNumber,
315
                                         vsi_l_offset nFileOffset,
316
                                         const void *pData, size_t nDataLength,
317
                                         CSLConstList papszOptions);
318
319
    virtual bool
320
    MultipartUploadEnd(const char *pszFilename, const char *pszUploadId,
321
                       size_t nPartIdsCount, const char *const *apszPartIds,
322
                       vsi_l_offset nTotalSize, CSLConstList papszOptions);
323
324
    virtual bool MultipartUploadAbort(const char *pszFilename,
325
                                      const char *pszUploadId,
326
                                      CSLConstList papszOptions);
327
328
    virtual bool AbortPendingUploads(const char * /*pszFilename*/)
329
0
    {
330
0
        return true;
331
0
    }
332
333
    virtual std::string
334
    GetStreamingFilename(const std::string &osFilename) const
335
0
    {
336
0
        return osFilename;
337
0
    }
338
339
    virtual std::string
340
    GetNonStreamingFilename(const std::string &osFilename) const
341
0
    {
342
0
        return osFilename;
343
0
    }
344
345
    /** Return the canonical filename.
346
     *
347
     * May be implemented by case-insensitive filesystems
348
     * (currently Win32 and MacOSX)
349
     * to return the filename with its actual case (i.e. the one that would
350
     * be used when listing the content of the directory).
351
     */
352
    virtual std::string
353
    GetCanonicalFilename(const std::string &osFilename) const
354
0
    {
355
0
        return osFilename;
356
0
    }
357
358
    virtual bool IsLocal(const char * /* pszPath */)
359
0
    {
360
0
        return true;
361
0
    }
362
363
    virtual bool SupportsSequentialWrite(const char * /* pszPath */,
364
                                         bool /* bAllowLocalTempFile */)
365
0
    {
366
0
        return true;
367
0
    }
368
369
    virtual bool SupportsRandomWrite(const char * /* pszPath */,
370
                                     bool /* bAllowLocalTempFile */)
371
0
    {
372
0
        return true;
373
0
    }
374
375
    virtual bool SupportsRead(const char * /* pszPath */)
376
0
    {
377
0
        return true;
378
0
    }
379
380
    virtual VSIFilesystemHandler *Duplicate(const char * /* pszPrefix */)
381
0
    {
382
0
        CPLError(CE_Failure, CPLE_NotSupported,
383
0
                 "Duplicate() not supported on this file system");
384
0
        return nullptr;
385
0
    }
386
387
    /** Return the directory separator.
388
     *
389
     * Default is forward slash. The only exception currently is the Windows
390
     * file system which returns anti-slash, unless the specified path is of the
391
     * form "{drive_letter}:/{rest_of_the_path}".
392
     */
393
    virtual const char *GetDirectorySeparator(CPL_UNUSED const char *pszPath)
394
16.3k
    {
395
16.3k
        return "/";
396
16.3k
    }
397
};
398
#endif /* #ifndef DOXYGEN_SKIP */
399
400
/************************************************************************/
401
/*                            VSIFileManager                            */
402
/************************************************************************/
403
404
#ifndef DOXYGEN_SKIP
405
class CPL_DLL VSIFileManager
406
{
407
  private:
408
    VSIFilesystemHandler *poDefaultHandler = nullptr;
409
    std::map<std::string, VSIFilesystemHandler *> oHandlers{};
410
411
    VSIFileManager();
412
413
    static VSIFileManager *Get();
414
415
    CPL_DISALLOW_COPY_ASSIGN(VSIFileManager)
416
417
  public:
418
    ~VSIFileManager();
419
420
    static VSIFilesystemHandler *GetHandler(const char *);
421
    static void InstallHandler(const std::string &osPrefix,
422
                               VSIFilesystemHandler *);
423
    static void RemoveHandler(const std::string &osPrefix);
424
425
    static char **GetPrefixes();
426
};
427
#endif /* #ifndef DOXYGEN_SKIP */
428
429
/************************************************************************/
430
/* ==================================================================== */
431
/*                       VSIArchiveFilesystemHandler                   */
432
/* ==================================================================== */
433
/************************************************************************/
434
435
#ifndef DOXYGEN_SKIP
436
437
class VSIArchiveEntryFileOffset
438
{
439
  public:
440
    virtual ~VSIArchiveEntryFileOffset();
441
};
442
443
typedef struct
444
{
445
    char *fileName;
446
    vsi_l_offset uncompressed_size;
447
    VSIArchiveEntryFileOffset *file_pos;
448
    int bIsDir;
449
    GIntBig nModifiedTime;
450
} VSIArchiveEntry;
451
452
class VSIArchiveContent
453
{
454
  public:
455
    time_t mTime = 0;
456
    vsi_l_offset nFileSize = 0;
457
    int nEntries = 0;
458
    VSIArchiveEntry *entries = nullptr;
459
460
    ~VSIArchiveContent();
461
};
462
463
class VSIArchiveReader
464
{
465
  public:
466
    virtual ~VSIArchiveReader();
467
468
    virtual int GotoFirstFile() = 0;
469
    virtual int GotoNextFile() = 0;
470
    virtual VSIArchiveEntryFileOffset *GetFileOffset() = 0;
471
    virtual GUIntBig GetFileSize() = 0;
472
    virtual CPLString GetFileName() = 0;
473
    virtual GIntBig GetModifiedTime() = 0;
474
    virtual int GotoFileOffset(VSIArchiveEntryFileOffset *pOffset) = 0;
475
};
476
477
class VSIArchiveFilesystemHandler : public VSIFilesystemHandler
478
{
479
    CPL_DISALLOW_COPY_ASSIGN(VSIArchiveFilesystemHandler)
480
481
  protected:
482
    CPLMutex *hMutex = nullptr;
483
    /* We use a cache that contains the list of files contained in a VSIArchive
484
     * file as */
485
    /* unarchive.c is quite inefficient in listing them. This speeds up access
486
     * to VSIArchive files */
487
    /* containing ~1000 files like a CADRG product */
488
    std::map<CPLString, VSIArchiveContent *> oFileList{};
489
490
    virtual const char *GetPrefix() = 0;
491
    virtual std::vector<CPLString> GetExtensions() = 0;
492
    virtual VSIArchiveReader *CreateReader(const char *pszArchiveFileName) = 0;
493
494
  public:
495
    VSIArchiveFilesystemHandler();
496
    virtual ~VSIArchiveFilesystemHandler();
497
498
    int Stat(const char *pszFilename, VSIStatBufL *pStatBuf,
499
             int nFlags) override;
500
    char **ReadDirEx(const char *pszDirname, int nMaxFiles) override;
501
502
    virtual const VSIArchiveContent *
503
    GetContentOfArchive(const char *archiveFilename,
504
                        VSIArchiveReader *poReader = nullptr);
505
    virtual char *SplitFilename(const char *pszFilename,
506
                                CPLString &osFileInArchive,
507
                                int bCheckMainFileExists);
508
    virtual VSIArchiveReader *OpenArchiveFile(const char *archiveFilename,
509
                                              const char *fileInArchiveName);
510
    virtual int FindFileInArchive(const char *archiveFilename,
511
                                  const char *fileInArchiveName,
512
                                  const VSIArchiveEntry **archiveEntry);
513
514
    virtual bool IsLocal(const char *pszPath) override;
515
516
    virtual bool
517
    SupportsSequentialWrite(const char * /* pszPath */,
518
                            bool /* bAllowLocalTempFile */) override
519
0
    {
520
0
        return false;
521
0
    }
522
523
    virtual bool SupportsRandomWrite(const char * /* pszPath */,
524
                                     bool /* bAllowLocalTempFile */) override
525
0
    {
526
0
        return false;
527
0
    }
528
};
529
530
/************************************************************************/
531
/*                              VSIDIR                                  */
532
/************************************************************************/
533
534
struct CPL_DLL VSIDIR
535
{
536
0
    VSIDIR() = default;
537
    virtual ~VSIDIR();
538
539
    virtual const VSIDIREntry *NextDirEntry() = 0;
540
541
  private:
542
    VSIDIR(const VSIDIR &) = delete;
543
    VSIDIR &operator=(const VSIDIR &) = delete;
544
};
545
546
#endif /* #ifndef DOXYGEN_SKIP */
547
548
VSIVirtualHandle CPL_DLL *
549
VSICreateBufferedReaderHandle(VSIVirtualHandle *poBaseHandle);
550
VSIVirtualHandle *
551
VSICreateBufferedReaderHandle(VSIVirtualHandle *poBaseHandle,
552
                              const GByte *pabyBeginningContent,
553
                              vsi_l_offset nCheatFileSize);
554
constexpr int VSI_CACHED_DEFAULT_CHUNK_SIZE = 32768;
555
VSIVirtualHandle CPL_DLL *
556
VSICreateCachedFile(VSIVirtualHandle *poBaseHandle,
557
                    size_t nChunkSize = VSI_CACHED_DEFAULT_CHUNK_SIZE,
558
                    size_t nCacheSize = 0);
559
560
const int CPL_DEFLATE_TYPE_GZIP = 0;
561
const int CPL_DEFLATE_TYPE_ZLIB = 1;
562
const int CPL_DEFLATE_TYPE_RAW_DEFLATE = 2;
563
VSIVirtualHandle CPL_DLL *VSICreateGZipWritable(VSIVirtualHandle *poBaseHandle,
564
                                                int nDeflateType,
565
                                                int bAutoCloseBaseHandle);
566
567
VSIVirtualHandle *VSICreateGZipWritable(VSIVirtualHandle *poBaseHandle,
568
                                        int nDeflateType,
569
                                        bool bAutoCloseBaseHandle, int nThreads,
570
                                        size_t nChunkSize,
571
                                        size_t nSOZIPIndexEltSize,
572
                                        std::vector<uint8_t> *panSOZIPIndex);
573
574
VSIVirtualHandle *
575
VSICreateUploadOnCloseFile(VSIVirtualHandleUniquePtr &&poWritableHandle,
576
                           VSIVirtualHandleUniquePtr &&poTmpFile,
577
                           const std::string &osTmpFilename);
578
579
#endif /* ndef CPL_VSI_VIRTUAL_H_INCLUDED */