Coverage Report

Created: 2025-06-22 06:59

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