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

OSGeo / gdal / 15899162844

26 Jun 2025 10:14AM UTC coverage: 71.088% (+0.004%) from 71.084%
15899162844

Pull #12623

github

web-flow
Merge c704a8392 into f5cb024d4
Pull Request #12623: gdal raster overview add: add a --overview-src option

209 of 244 new or added lines in 5 files covered. (85.66%)

96 existing lines in 44 files now uncovered.

574014 of 807474 relevant lines covered (71.09%)

250815.03 hits per line

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

89.29
/port/cpl_vsil.cpp
1
/******************************************************************************
2
 *
3
 * Project:  VSI Virtual File System
4
 * Purpose:  Implementation VSI*L File API and other file system access
5
 *           methods going through file virtualization.
6
 * Author:   Frank Warmerdam, warmerdam@pobox.com
7
 *
8
 ******************************************************************************
9
 * Copyright (c) 2005, Frank Warmerdam <warmerdam@pobox.com>
10
 * Copyright (c) 2008-2014, Even Rouault <even dot rouault at spatialys.com>
11
 *
12
 * SPDX-License-Identifier: MIT
13
 ****************************************************************************/
14

15
#include "cpl_port.h"
16
#include "cpl_vsi.h"
17

18
#include <cassert>
19
#include <cinttypes>
20
#include <cstdarg>
21
#include <cstddef>
22
#include <cstring>
23
#if HAVE_FCNTL_H
24
#include <fcntl.h>
25
#endif
26

27
#include <algorithm>
28
#include <limits>
29
#include <map>
30
#include <memory>
31
#include <mutex>
32
#include <set>
33
#include <string>
34
#include <utility>
35
#include <vector>
36

37
#include "cpl_conv.h"
38
#include "cpl_error.h"
39
#include "cpl_multiproc.h"
40
#include "cpl_string.h"
41
#include "cpl_vsi_virtual.h"
42
#include "cpl_vsil_curl_class.h"
43

44
// To avoid aliasing to GetDiskFreeSpace to GetDiskFreeSpaceA on Windows
45
#ifdef GetDiskFreeSpace
46
#undef GetDiskFreeSpace
47
#endif
48

49
/************************************************************************/
50
/*                             VSIReadDir()                             */
51
/************************************************************************/
52

53
/**
54
 * \brief Read names in a directory.
55
 *
56
 * This function abstracts access to directory contains.  It returns a
57
 * list of strings containing the names of files, and directories in this
58
 * directory.  The resulting string list becomes the responsibility of the
59
 * application and should be freed with CSLDestroy() when no longer needed.
60
 *
61
 * Note that no error is issued via CPLError() if the directory path is
62
 * invalid, though NULL is returned.
63
 *
64
 * This function used to be known as CPLReadDir(), but the old name is now
65
 * deprecated.
66
 *
67
 * @param pszPath the relative, or absolute path of a directory to read.
68
 * UTF-8 encoded.
69
 * @return The list of entries in the directory, or NULL if the directory
70
 * doesn't exist.  Filenames are returned in UTF-8 encoding.
71
 */
72

73
char **VSIReadDir(const char *pszPath)
14,907✔
74
{
75
    return VSIReadDirEx(pszPath, 0);
14,907✔
76
}
77

78
/************************************************************************/
79
/*                             VSIReadDirEx()                           */
80
/************************************************************************/
81

82
/**
83
 * \brief Read names in a directory.
84
 *
85
 * This function abstracts access to directory contains.  It returns a
86
 * list of strings containing the names of files, and directories in this
87
 * directory.  The resulting string list becomes the responsibility of the
88
 * application and should be freed with CSLDestroy() when no longer needed.
89
 *
90
 * Note that no error is issued via CPLError() if the directory path is
91
 * invalid, though NULL is returned.
92
 *
93
 * If nMaxFiles is set to a positive number, directory listing will stop after
94
 * that limit has been reached. Note that to indicate truncate, at least one
95
 * element more than the nMaxFiles limit will be returned. If CSLCount() on the
96
 * result is lesser or equal to nMaxFiles, then no truncation occurred.
97
 *
98
 * @param pszPath the relative, or absolute path of a directory to read.
99
 * UTF-8 encoded.
100
 * @param nMaxFiles maximum number of files after which to stop, or 0 for no
101
 * limit.
102
 * @return The list of entries in the directory, or NULL if the directory
103
 * doesn't exist.  Filenames are returned in UTF-8 encoding.
104
 * @since GDAL 2.1
105
 */
106

107
char **VSIReadDirEx(const char *pszPath, int nMaxFiles)
52,765✔
108
{
109
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath);
52,765✔
110

111
    return poFSHandler->ReadDirEx(pszPath, nMaxFiles);
52,766✔
112
}
113

114
/************************************************************************/
115
/*                             VSISiblingFiles()                        */
116
/************************************************************************/
117

118
/**
119
 * \brief Return related filenames
120
 *
121
 * This function is essentially meant at being used by GDAL internals.
122
 *
123
 * @param pszFilename the path of a filename to inspect
124
 * UTF-8 encoded.
125
 * @return The list of entries, relative to the directory, of all sidecar
126
 * files available or NULL if the list is not known.
127
 * Filenames are returned in UTF-8 encoding.
128
 * Most implementations will return NULL, and a subsequent ReadDir will
129
 * list all files available in the file's directory. This function will be
130
 * overridden by VSI FilesystemHandlers that wish to force e.g. an empty list
131
 * to avoid opening non-existent files on slow filesystems. The return value
132
 * shall be destroyed with CSLDestroy()
133
 * @since GDAL 3.2
134
 */
135
char **VSISiblingFiles(const char *pszFilename)
76,933✔
136
{
137
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
76,933✔
138

139
    return poFSHandler->SiblingFiles(pszFilename);
76,933✔
140
}
141

142
/************************************************************************/
143
/*                           VSIFnMatch()                               */
144
/************************************************************************/
145

146
static bool VSIFnMatch(const char *pszPattern, const char *pszStr)
535✔
147
{
148
    for (; *pszPattern && *pszStr; pszPattern++, pszStr++)
535✔
149
    {
150
        if (*pszPattern == '*')
529✔
151
        {
152
            if (pszPattern[1] == 0)
14✔
153
                return true;
4✔
154
            for (; *pszStr; ++pszStr)
46✔
155
            {
156
                if (VSIFnMatch(pszPattern + 1, pszStr))
40✔
157
                    return true;
4✔
158
            }
159
            return false;
6✔
160
        }
161
        else if (*pszPattern == '?')
515✔
162
        {
163
            // match single any char
164
        }
165
        else if (*pszPattern == '[')
511✔
166
        {
167
            // match character classes and ranges
168
            // "[abcd]" will match a character that is a, b, c or d
169
            // "[a-z]" will match a character that is a to z
170
            // "[!abcd] will match a character that is *not* a, b, c or d
171
            // "[]]" will match character ]
172
            // "[]-]" will match character ] or -
173
            // "[!]a-]" will match a character that is *not* ], a or -
174

175
            const char *pszOpenBracket = pszPattern;
10✔
176
            ++pszPattern;
10✔
177
            const bool isNot = (*pszPattern == '!');
10✔
178
            if (isNot)
10✔
179
            {
180
                ++pszOpenBracket;
3✔
181
                ++pszPattern;
3✔
182
            }
183
            bool res = false;
10✔
184
            for (; *pszPattern; ++pszPattern)
22✔
185
            {
186
                if ((*pszPattern == ']' || *pszPattern == '-') &&
21✔
187
                    pszPattern == pszOpenBracket + 1)
13✔
188
                {
189
                    if (*pszStr == *pszPattern)
3✔
190
                    {
191
                        res = true;
2✔
192
                    }
193
                }
194
                else if (*pszPattern == ']')
18✔
195
                {
196
                    break;
9✔
197
                }
198
                else if (pszPattern[1] == '-' && pszPattern[2] != 0 &&
9✔
199
                         pszPattern[2] != ']')
2✔
200
                {
201
                    if (*pszStr >= pszPattern[0] && *pszStr <= pszPattern[2])
1✔
202
                    {
203
                        res = true;
1✔
204
                    }
205
                    pszPattern += 2;
1✔
206
                }
207
                else if (*pszStr == *pszPattern)
8✔
208
                {
209
                    res = true;
2✔
210
                }
211
            }
212
            if (*pszPattern == 0)
10✔
213
                return false;
1✔
214
            if (!res && !isNot)
9✔
215
                return false;
1✔
216
            if (res && isNot)
8✔
217
                return false;
×
218
        }
219
        else if (*pszPattern != *pszStr)
501✔
220
        {
221
            return false;
450✔
222
        }
223
    }
224
    return *pszPattern == 0 && *pszStr == 0;
6✔
225
}
226

227
/************************************************************************/
228
/*                             VSIGlob()                                */
229
/************************************************************************/
230

231
/**
232
 \brief Return a list of file and directory names matching
233
 a pattern that can contain wildcards.
234

235
 This function has similar behavior to the POSIX glob() function:
236
 https://man7.org/linux/man-pages/man7/glob.7.html
237

238
 In particular it supports the following wildcards:
239
 <ul>
240
 <li>'*': match any string</li>
241
 <li>'?': match any single character</li>
242
 <li>'[': match character class or range, with '!' immediately after '['
243
 to indicate negation.</li>
244
 </ul>
245
 Refer to to the above man page for more details.
246

247
 It also supports the "**" recursive wildcard, behaving similarly to Python
248
 glob.glob() with recursive=True. Be careful of the amount of memory and time
249
 required when using that recursive wildcard on directories with a large
250
 amount of files and subdirectories.
251

252
 Examples, given a file hierarchy:
253
 - one.tif
254
 - my_subdir/two.tif
255
 - my_subdir/subsubdir/three.tif
256

257
 \code{.cpp}
258
 VSIGlob("one.tif",NULL,NULL,NULL) returns ["one.tif", NULL]
259
 VSIGlob("*.tif",NULL,NULL,NULL) returns ["one.tif", NULL]
260
 VSIGlob("on?.tif",NULL,NULL,NULL) returns ["one.tif", NULL]
261
 VSIGlob("on[a-z].tif",NULL,NULL,NULL) returns ["one.tif", NULL]
262
 VSIGlob("on[ef].tif",NULL,NULL,NULL) returns ["one.tif", NULL]
263
 VSIGlob("on[!e].tif",NULL,NULL,NULL) returns NULL
264
 VSIGlob("my_subdir" "/" "*.tif",NULL,NULL,NULL) returns ["my_subdir/two.tif", NULL]
265
 VSIGlob("**" "/" "*.tif",NULL,NULL,NULL) returns ["one.tif", "my_subdir/two.tif", "my_subdir/subsubdir/three.tif", NULL]
266
 \endcode
267

268
 In the current implementation, matching is done based on the assumption that
269
 a character fits into a single byte, which will not work properly on
270
 non-ASCII UTF-8 filenames.
271

272
 VSIGlob() works with any virtual file systems supported by GDAL, including
273
 network file systems such as /vsis3/, /vsigs/, /vsiaz/, etc. But note that
274
 for those ones, the pattern is not passed to the remote server, and thus large
275
 amount of filenames can be transferred from the remote server to the host
276
 where the filtering is done.
277

278
 @param pszPattern the relative, or absolute path of a directory to read.
279
 UTF-8 encoded.
280
 @param papszOptions NULL-terminate list of options, or NULL. None supported
281
 currently.
282
 @param pProgressFunc Progress function, or NULL. This is only used as a way
283
 for the user to cancel operation if it takes too much time. The percentage
284
 passed to the callback is not significant (always at 0).
285
 @param pProgressData User data passed to the progress function, or NULL.
286
 @return The list of matched filenames, which must be freed with CSLDestroy().
287
 Filenames are returned in UTF-8 encoding.
288

289
 @since GDAL 3.11
290
*/
291

292
char **VSIGlob(const char *pszPattern, const char *const *papszOptions,
17✔
293
               GDALProgressFunc pProgressFunc, void *pProgressData)
294
{
295
    CPL_IGNORE_RET_VAL(papszOptions);
17✔
296

297
    CPLStringList aosRes;
34✔
298
    std::vector<std::pair<std::string, size_t>> candidates;
34✔
299
    candidates.emplace_back(pszPattern, 0);
17✔
300
    while (!candidates.empty())
48✔
301
    {
302
        auto [osPattern, nPosStart] = candidates.back();
31✔
303
        pszPattern = osPattern.c_str() + nPosStart;
31✔
304
        candidates.pop_back();
31✔
305

306
        std::string osPath = osPattern.substr(0, nPosStart);
31✔
307
        std::string osCurPath;
31✔
308
        for (;; ++pszPattern)
515✔
309
        {
310
            if (*pszPattern == 0 || *pszPattern == '/' || *pszPattern == '\\')
546✔
311
            {
312
                struct VSIDirCloser
313
                {
314
                    void operator()(VSIDIR *dir)
15✔
315
                    {
316
                        VSICloseDir(dir);
15✔
317
                    }
15✔
318
                };
319

320
                if (osCurPath == "**")
104✔
321
                {
322
                    std::unique_ptr<VSIDIR, VSIDirCloser> psDir(
323
                        VSIOpenDir(osPath.c_str(), -1, nullptr));
1✔
324
                    if (!psDir)
1✔
325
                        return nullptr;
×
326
                    while (const VSIDIREntry *psEntry =
327
                               VSIGetNextDirEntry(psDir.get()))
5✔
328
                    {
329
                        if (pProgressFunc &&
4✔
330
                            !pProgressFunc(0, "", pProgressData))
×
331
                        {
332
                            return nullptr;
×
333
                        }
334
                        {
335
                            std::string osCandidate(osPath);
8✔
336
                            osCandidate += psEntry->pszName;
4✔
337
                            nPosStart = osCandidate.size();
4✔
338
                            if (*pszPattern)
4✔
339
                            {
340
                                osCandidate += pszPattern;
4✔
341
                            }
342
                            candidates.emplace_back(std::move(osCandidate),
4✔
343
                                                    nPosStart);
4✔
344
                        }
345
                    }
4✔
346
                    osPath.clear();
1✔
347
                    break;
1✔
348
                }
349
                else if (osCurPath.find_first_of("*?[") != std::string::npos)
103✔
350
                {
351
                    std::unique_ptr<VSIDIR, VSIDirCloser> psDir(
352
                        VSIOpenDir(osPath.c_str(), 0, nullptr));
14✔
353
                    if (!psDir)
14✔
354
                        return nullptr;
×
355
                    while (const VSIDIREntry *psEntry =
356
                               VSIGetNextDirEntry(psDir.get()))
446✔
357
                    {
358
                        if (pProgressFunc &&
432✔
359
                            !pProgressFunc(0, "", pProgressData))
×
360
                        {
361
                            return nullptr;
×
362
                        }
363
                        if (VSIFnMatch(osCurPath.c_str(), psEntry->pszName))
432✔
364
                        {
365
                            std::string osCandidate(osPath);
20✔
366
                            osCandidate += psEntry->pszName;
10✔
367
                            nPosStart = osCandidate.size();
10✔
368
                            if (*pszPattern)
10✔
369
                            {
370
                                osCandidate += pszPattern;
2✔
371
                            }
372
                            candidates.emplace_back(std::move(osCandidate),
10✔
373
                                                    nPosStart);
10✔
374
                        }
375
                    }
432✔
376
                    osPath.clear();
14✔
377
                    break;
14✔
378
                }
379
                else if (*pszPattern == 0)
89✔
380
                {
381
                    osPath += osCurPath;
16✔
382
                    break;
16✔
383
                }
384
                else
385
                {
386
                    osPath += osCurPath;
73✔
387
                    osPath += *pszPattern;
73✔
388
                    osCurPath.clear();
73✔
389
                }
73✔
390
            }
391
            else
392
            {
393
                osCurPath += *pszPattern;
442✔
394
            }
395
        }
515✔
396
        if (!osPath.empty())
31✔
397
        {
398
            VSIStatBufL sStat;
399
            if (VSIStatL(osPath.c_str(), &sStat) == 0)
16✔
400
                aosRes.AddString(osPath.c_str());
11✔
401
        }
402
    }
403

404
    return aosRes.StealList();
17✔
405
}
406

407
/************************************************************************/
408
/*                      VSIGetDirectorySeparator()                      */
409
/************************************************************************/
410

411
/** Return the directory separator for the specified path.
412
 *
413
 * Default is forward slash. The only exception currently is the Windows
414
 * file system which returns backslash, unless the specified path is of the
415
 * form "{drive_letter}:/{rest_of_the_path}".
416
 *
417
 * @since 3.9
418
 */
419
const char *VSIGetDirectorySeparator(const char *pszPath)
913,053✔
420
{
421
    if (STARTS_WITH(pszPath, "http://") || STARTS_WITH(pszPath, "https://"))
913,053✔
422
        return "/";
512✔
423

424
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath);
912,541✔
425
    return poFSHandler->GetDirectorySeparator(pszPath);
912,561✔
426
}
427

428
/************************************************************************/
429
/*                             VSIReadRecursive()                       */
430
/************************************************************************/
431

432
/**
433
 * \brief Read names in a directory recursively.
434
 *
435
 * This function abstracts access to directory contents and subdirectories.
436
 * It returns a list of strings containing the names of files and directories
437
 * in this directory and all subdirectories.  The resulting string list becomes
438
 * the responsibility of the application and should be freed with CSLDestroy()
439
 * when no longer needed.
440
 *
441
 * Note that no error is issued via CPLError() if the directory path is
442
 * invalid, though NULL is returned.
443
 *
444
 * Note: since GDAL 3.9, for recursive mode, the directory separator will no
445
 * longer be always forward slash, but will be the one returned by
446
 * VSIGetDirectorySeparator(pszPathIn), so potentially backslash on Windows
447
 * file systems.
448
 *
449
 * @param pszPathIn the relative, or absolute path of a directory to read.
450
 * UTF-8 encoded.
451
 *
452
 * @return The list of entries in the directory and subdirectories
453
 * or NULL if the directory doesn't exist.  Filenames are returned in UTF-8
454
 * encoding.
455
 * @since GDAL 1.10.0
456
 *
457
 */
458

459
char **VSIReadDirRecursive(const char *pszPathIn)
1,110✔
460
{
461
    const char SEP = VSIGetDirectorySeparator(pszPathIn)[0];
1,110✔
462

463
    const char *const apszOptions[] = {"NAME_AND_TYPE_ONLY=YES", nullptr};
1,110✔
464
    VSIDIR *psDir = VSIOpenDir(pszPathIn, -1, apszOptions);
1,110✔
465
    if (!psDir)
1,110✔
466
        return nullptr;
3✔
467
    CPLStringList oFiles;
2,214✔
468
    while (auto psEntry = VSIGetNextDirEntry(psDir))
4,157✔
469
    {
470
        if (VSI_ISDIR(psEntry->nMode) && psEntry->pszName[0] &&
3,050✔
471
            psEntry->pszName[strlen(psEntry->pszName) - 1] != SEP)
1,331✔
472
        {
473
            oFiles.AddString((std::string(psEntry->pszName) + SEP).c_str());
1,331✔
474
        }
475
        else
476
        {
477
            oFiles.AddString(psEntry->pszName);
1,719✔
478
        }
479
    }
3,050✔
480
    VSICloseDir(psDir);
1,107✔
481

482
    return oFiles.StealList();
1,107✔
483
}
484

485
/************************************************************************/
486
/*                             CPLReadDir()                             */
487
/*                                                                      */
488
/*      This is present only to provide ABI compatibility with older    */
489
/*      versions.                                                       */
490
/************************************************************************/
491
#undef CPLReadDir
492

493
CPL_C_START
494
char CPL_DLL **CPLReadDir(const char *pszPath);
495
CPL_C_END
496

497
char **CPLReadDir(const char *pszPath)
×
498
{
499
    return VSIReadDir(pszPath);
×
500
}
501

502
/************************************************************************/
503
/*                             VSIOpenDir()                             */
504
/************************************************************************/
505

506
/**
507
 * \brief Open a directory to read its entries.
508
 *
509
 * This function is close to the POSIX opendir() function.
510
 *
511
 * For /vsis3/, /vsigs/, /vsioss/, /vsiaz/ and /vsiadls/, this function has an
512
 * efficient implementation, minimizing the number of network requests, when
513
 * invoked with nRecurseDepth <= 0.
514
 *
515
 * Entries are read by calling VSIGetNextDirEntry() on the handled returned by
516
 * that function, until it returns NULL. VSICloseDir() must be called once done
517
 * with the returned directory handle.
518
 *
519
 * @param pszPath the relative, or absolute path of a directory to read.
520
 * UTF-8 encoded.
521
 * @param nRecurseDepth 0 means do not recurse in subdirectories, 1 means
522
 * recurse only in the first level of subdirectories, etc. -1 means unlimited
523
 * recursion level
524
 * @param papszOptions NULL terminated list of options, or NULL. The following
525
 * options are implemented:
526
 * <ul>
527
 * <li>PREFIX=string: (GDAL >= 3.4) Filter to select filenames only starting
528
 *     with the specified prefix. Implemented efficiently for /vsis3/, /vsigs/,
529
 *     and /vsiaz/ (but not /vsiadls/)
530
 * </li>
531
 * <li>NAME_AND_TYPE_ONLY=YES/NO: (GDAL >= 3.4) Defaults to NO. If set to YES,
532
 *     only the pszName and nMode members of VSIDIR are guaranteed to be set.
533
 *     This is implemented efficiently for the Unix virtual file system.
534
 * </li>
535
 * </ul>
536
 *
537
 * @return a handle, or NULL in case of error
538
 * @since GDAL 2.4
539
 *
540
 */
541

542
VSIDIR *VSIOpenDir(const char *pszPath, int nRecurseDepth,
1,315✔
543
                   const char *const *papszOptions)
544
{
545
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath);
1,315✔
546

547
    return poFSHandler->OpenDir(pszPath, nRecurseDepth, papszOptions);
1,315✔
548
}
549

550
/************************************************************************/
551
/*                          VSIGetNextDirEntry()                        */
552
/************************************************************************/
553

554
/**
555
 * \brief Return the next entry of the directory
556
 *
557
 * This function is close to the POSIX readdir() function. It actually returns
558
 * more information (file size, last modification time), which on 'real' file
559
 * systems involve one 'stat' call per file.
560
 *
561
 * For filesystems that can have both a regular file and a directory name of
562
 * the same name (typically /vsis3/), when this situation of duplicate happens,
563
 * the directory name will be suffixed by a slash character. Otherwise directory
564
 * names are not suffixed by slash.
565
 *
566
 * The returned entry remains valid until the next call to VSINextDirEntry()
567
 * or VSICloseDir() with the same handle.
568
 *
569
 * Note: since GDAL 3.9, for recursive mode, the directory separator will no
570
 * longer be always forward slash, but will be the one returned by
571
 * VSIGetDirectorySeparator(pszPathIn), so potentially backslash on Windows
572
 * file systems.
573
 *
574
 * @param dir Directory handled returned by VSIOpenDir(). Must not be NULL.
575
 *
576
 * @return a entry, or NULL if there is no more entry in the directory. This
577
 * return value must not be freed.
578
 * @since GDAL 2.4
579
 *
580
 */
581

582
const VSIDIREntry *VSIGetNextDirEntry(VSIDIR *dir)
11,565✔
583
{
584
    return dir->NextDirEntry();
11,565✔
585
}
586

587
/************************************************************************/
588
/*                             VSICloseDir()                            */
589
/************************************************************************/
590

591
/**
592
 * \brief Close a directory
593
 *
594
 * This function is close to the POSIX closedir() function.
595
 *
596
 * @param dir Directory handled returned by VSIOpenDir().
597
 *
598
 * @since GDAL 2.4
599
 */
600

601
void VSICloseDir(VSIDIR *dir)
1,283✔
602
{
603
    delete dir;
1,283✔
604
}
1,283✔
605

606
/************************************************************************/
607
/*                              VSIMkdir()                              */
608
/************************************************************************/
609

610
/**
611
 * \brief Create a directory.
612
 *
613
 * Create a new directory with the indicated mode. For POSIX-style systems,
614
 * the mode is modified by the file creation mask (umask). However, some
615
 * file systems and platforms may not use umask, or they may ignore the mode
616
 * completely. So a reasonable cross-platform default mode value is 0755.
617
 *
618
 * Analog of the POSIX mkdir() function.
619
 *
620
 * @param pszPathname the path to the directory to create. UTF-8 encoded.
621
 * @param mode the permissions mode.
622
 *
623
 * @return 0 on success or -1 on an error.
624
 */
625

626
int VSIMkdir(const char *pszPathname, long mode)
97,944✔
627

628
{
629
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPathname);
97,944✔
630

631
    return poFSHandler->Mkdir(pszPathname, mode);
97,944✔
632
}
633

634
/************************************************************************/
635
/*                       VSIMkdirRecursive()                            */
636
/************************************************************************/
637

638
/**
639
 * \brief Create a directory and all its ancestors
640
 *
641
 * @param pszPathname the path to the directory to create. UTF-8 encoded.
642
 * @param mode the permissions mode.
643
 *
644
 * @return 0 on success or -1 on an error.
645
 * @since GDAL 2.3
646
 */
647

648
int VSIMkdirRecursive(const char *pszPathname, long mode)
139,436✔
649
{
650
    if (pszPathname == nullptr || pszPathname[0] == '\0' ||
139,436✔
651
        strncmp("/", pszPathname, 2) == 0)
139,436✔
652
    {
UNCOV
653
        return -1;
×
654
    }
655

656
    const CPLString osPathname(pszPathname);
278,872✔
657
    VSIStatBufL sStat;
658
    if (VSIStatL(osPathname, &sStat) == 0)
139,436✔
659
    {
660
        return VSI_ISDIR(sStat.st_mode) ? 0 : -1;
48,950✔
661
    }
662
    const std::string osParentPath(CPLGetPathSafe(osPathname));
180,972✔
663

664
    // Prevent crazy paths from recursing forever.
665
    if (osParentPath == osPathname ||
180,972✔
666
        osParentPath.length() >= osPathname.length())
90,486✔
667
    {
668
        return -1;
×
669
    }
670

671
    if (!osParentPath.empty() && VSIStatL(osParentPath.c_str(), &sStat) != 0)
90,486✔
672
    {
673
        if (VSIMkdirRecursive(osParentPath.c_str(), mode) != 0)
45,355✔
674
            return -1;
20✔
675
    }
676

677
    return VSIMkdir(osPathname, mode);
90,465✔
678
}
679

680
/************************************************************************/
681
/*                             VSIUnlink()                              */
682
/************************************************************************/
683

684
/**
685
 * \brief Delete a file.
686
 *
687
 * Deletes a file object from the file system.
688
 *
689
 * This method goes through the VSIFileHandler virtualization and may
690
 * work on unusual filesystems such as in memory.
691
 *
692
 * Analog of the POSIX unlink() function.
693
 *
694
 * @param pszFilename the path of the file to be deleted. UTF-8 encoded.
695
 *
696
 * @return 0 on success or -1 on an error.
697
 */
698

699
int VSIUnlink(const char *pszFilename)
85,241✔
700

701
{
702
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
85,241✔
703

704
    return poFSHandler->Unlink(pszFilename);
85,241✔
705
}
706

707
/************************************************************************/
708
/*                           VSIUnlinkBatch()                           */
709
/************************************************************************/
710

711
/**
712
 * \brief Delete several files, possibly in a batch.
713
 *
714
 * All files should belong to the same file system handler.
715
 *
716
 * This is implemented efficiently for /vsis3/ and /vsigs/ (provided for /vsigs/
717
 * that OAuth2 authentication is used).
718
 *
719
 * @param papszFiles NULL terminated list of files. UTF-8 encoded.
720
 *
721
 * @return an array of size CSLCount(papszFiles), whose values are TRUE or FALSE
722
 * depending on the success of deletion of the corresponding file. The array
723
 * should be freed with VSIFree().
724
 * NULL might be return in case of a more general error (for example,
725
 * files belonging to different file system handlers)
726
 *
727
 * @since GDAL 3.1
728
 */
729

730
int *VSIUnlinkBatch(CSLConstList papszFiles)
11✔
731
{
732
    VSIFilesystemHandler *poFSHandler = nullptr;
11✔
733
    for (CSLConstList papszIter = papszFiles; papszIter && *papszIter;
30✔
734
         ++papszIter)
735
    {
736
        auto poFSHandlerThisFile = VSIFileManager::GetHandler(*papszIter);
20✔
737
        if (poFSHandler == nullptr)
20✔
738
            poFSHandler = poFSHandlerThisFile;
10✔
739
        else if (poFSHandler != poFSHandlerThisFile)
10✔
740
        {
741
            CPLError(CE_Failure, CPLE_AppDefined,
1✔
742
                     "Files belong to different file system handlers");
743
            poFSHandler = nullptr;
1✔
744
            break;
1✔
745
        }
746
    }
747
    if (poFSHandler == nullptr)
11✔
748
        return nullptr;
2✔
749
    return poFSHandler->UnlinkBatch(papszFiles);
9✔
750
}
751

752
/************************************************************************/
753
/*                             VSIRename()                              */
754
/************************************************************************/
755

756
/**
757
 * \brief Rename a file.
758
 *
759
 * Renames a file object in the file system.  It should be possible
760
 * to rename a file onto a new directory, but it is safest if this
761
 * function is only used to rename files that remain in the same directory.
762
 *
763
 * This function only works if the new path is located on the same VSI
764
 * virtual file system than the old path. If not, use VSIMove() instead.
765
 *
766
 * This method goes through the VSIFileHandler virtualization and may
767
 * work on unusual filesystems such as in memory or cloud object storage.
768
 * Note that for cloud object storage, renaming a directory may involve
769
 * renaming all files it contains recursively, and is thus not an atomic
770
 * operation (and could be expensive on directories with many files!)
771
 *
772
 * Analog of the POSIX rename() function.
773
 *
774
 * @param oldpath the name of the file to be renamed.  UTF-8 encoded.
775
 * @param newpath the name the file should be given.  UTF-8 encoded.
776
 *
777
 * @return 0 on success or -1 on an error.
778
 */
779

780
int VSIRename(const char *oldpath, const char *newpath)
1,004✔
781

782
{
783
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(oldpath);
1,004✔
784

785
    return poFSHandler->Rename(oldpath, newpath, nullptr, nullptr);
1,004✔
786
}
787

788
/************************************************************************/
789
/*                             VSIMove()                                */
790
/************************************************************************/
791

792
/**
793
 * \brief Move (or rename) a file.
794
 *
795
 * If the new path is an existing directory, the file will be moved to it.
796
 *
797
 * The function can work even if the files are not located on the same VSI
798
 * virtual file system, but it will involve copying and deletion.
799
 *
800
 * Note that for cloud object storage, moving/renaming a directory may involve
801
 * renaming all files it contains recursively, and is thus not an atomic
802
 * operation (and could be slow and expensive on directories with many files!)
803
 *
804
 * @param oldpath the path of the file to be renamed/moved.  UTF-8 encoded.
805
 * @param newpath the new path the file should be given.  UTF-8 encoded.
806
 * @param papszOptions Null terminated list of options, or NULL.
807
 * @param pProgressFunc Progress callback, or NULL.
808
 * @param pProgressData User data of progress callback, or NULL.
809
 *
810
 * @return 0 on success or -1 on error.
811
 * @since GDAL 3.11
812
 */
813

814
int VSIMove(const char *oldpath, const char *newpath,
12✔
815
            const char *const *papszOptions, GDALProgressFunc pProgressFunc,
816
            void *pProgressData)
817
{
818

819
    if (strcmp(oldpath, newpath) == 0)
12✔
820
        return 0;
1✔
821

822
    VSIFilesystemHandler *poOldFSHandler = VSIFileManager::GetHandler(oldpath);
11✔
823
    VSIFilesystemHandler *poNewFSHandler = VSIFileManager::GetHandler(newpath);
11✔
824

825
    VSIStatBufL sStat;
826
    if (VSIStatL(oldpath, &sStat) != 0)
11✔
827
    {
828
        CPLDebug("VSI", "%s is not a object", oldpath);
2✔
829
        errno = ENOENT;
2✔
830
        return -1;
2✔
831
    }
832

833
    std::string sNewpath(newpath);
18✔
834
    VSIStatBufL sStatNew;
835
    if (VSIStatL(newpath, &sStatNew) == 0 && VSI_ISDIR(sStatNew.st_mode))
9✔
836
    {
837
        sNewpath =
838
            CPLFormFilenameSafe(newpath, CPLGetFilename(oldpath), nullptr);
4✔
839
    }
840

841
    int ret = 0;
9✔
842

843
    if (poOldFSHandler == poNewFSHandler)
9✔
844
    {
845
        ret = poOldFSHandler->Rename(oldpath, sNewpath.c_str(), pProgressFunc,
2✔
846
                                     pProgressData);
2✔
847
        if (ret == 0 && pProgressFunc)
2✔
848
            ret = pProgressFunc(1.0, "", pProgressData) ? 0 : -1;
1✔
849
        return ret;
2✔
850
    }
851

852
    if (VSI_ISDIR(sStat.st_mode))
7✔
853
    {
854
        const CPLStringList aosList(VSIReadDir(oldpath));
6✔
855
        poNewFSHandler->Mkdir(sNewpath.c_str(), 0755);
3✔
856
        bool bFoundFiles = false;
3✔
857
        const int nListSize = aosList.size();
3✔
858
        for (int i = 0; ret == 0 && i < nListSize; i++)
6✔
859
        {
860
            if (strcmp(aosList[i], ".") != 0 && strcmp(aosList[i], "..") != 0)
3✔
861
            {
862
                bFoundFiles = true;
1✔
863
                const std::string osSrc =
864
                    CPLFormFilenameSafe(oldpath, aosList[i], nullptr);
2✔
865
                const std::string osTarget =
866
                    CPLFormFilenameSafe(sNewpath.c_str(), aosList[i], nullptr);
2✔
867
                void *pScaledProgress = GDALCreateScaledProgress(
2✔
868
                    static_cast<double>(i) / nListSize,
1✔
869
                    static_cast<double>(i + 1) / nListSize, pProgressFunc,
1✔
870
                    pProgressData);
871
                ret = VSIMove(osSrc.c_str(), osTarget.c_str(), papszOptions,
1✔
872
                              pScaledProgress ? GDALScaledProgress : nullptr,
873
                              pScaledProgress);
874
                GDALDestroyScaledProgress(pScaledProgress);
1✔
875
            }
876
        }
877
        if (!bFoundFiles)
3✔
878
            ret = VSIStatL(sNewpath.c_str(), &sStat);
2✔
879
        if (ret == 0)
3✔
880
            ret = poOldFSHandler->Rmdir(oldpath);
3✔
881
    }
882
    else
883
    {
884
        ret = VSICopyFile(oldpath, sNewpath.c_str(), nullptr, sStat.st_size,
8✔
885
                          nullptr, pProgressFunc, pProgressData) == 0 &&
3✔
886
                      VSIUnlink(oldpath) == 0
3✔
887
                  ? 0
7✔
888
                  : -1;
889
    }
890
    if (ret == 0 && pProgressFunc)
7✔
891
        ret = pProgressFunc(1.0, "", pProgressData) ? 0 : -1;
4✔
892
    return ret;
7✔
893
}
894

895
/************************************************************************/
896
/*                             VSICopyFile()                            */
897
/************************************************************************/
898

899
/**
900
 * \brief Copy a source file into a target file.
901
 *
902
 * For a /vsizip/foo.zip/bar target, the options available are those of
903
 * CPLAddFileInZip()
904
 *
905
 * The following copies are made fully on the target server, without local
906
 * download from source and upload to target:
907
 * - /vsis3/ -> /vsis3/
908
 * - /vsigs/ -> /vsigs/
909
 * - /vsiaz/ -> /vsiaz/
910
 * - /vsiadls/ -> /vsiadls/
911
 * - any of the above or /vsicurl/ -> /vsiaz/ (starting with GDAL 3.8)
912
 *
913
 * @param pszSource Source filename. UTF-8 encoded. May be NULL if fpSource is
914
 * not NULL.
915
 * @param pszTarget Target filename.  UTF-8 encoded. Must not be NULL
916
 * @param fpSource File handle on the source file. May be NULL if pszSource is
917
 * not NULL.
918
 * @param nSourceSize Size of the source file. Pass -1 if unknown.
919
 * If set to -1, and progress callback is used, VSIStatL() will be used on
920
 * pszSource to retrieve the source size.
921
 * @param papszOptions Null terminated list of options, or NULL.
922
 * @param pProgressFunc Progress callback, or NULL.
923
 * @param pProgressData User data of progress callback, or NULL.
924
 *
925
 * @return 0 on success.
926
 * @since GDAL 3.7
927
 */
928

929
int VSICopyFile(const char *pszSource, const char *pszTarget,
2,284✔
930
                VSILFILE *fpSource, vsi_l_offset nSourceSize,
931
                const char *const *papszOptions, GDALProgressFunc pProgressFunc,
932
                void *pProgressData)
933

934
{
935
    if (!pszSource && !fpSource)
2,284✔
936
    {
937
        CPLError(CE_Failure, CPLE_AppDefined,
1✔
938
                 "pszSource == nullptr && fpSource == nullptr");
939
        return -1;
1✔
940
    }
941
    if (!pszTarget || pszTarget[0] == '\0')
2,283✔
942
    {
943
        return -1;
×
944
    }
945

946
    VSIFilesystemHandler *poFSHandlerTarget =
947
        VSIFileManager::GetHandler(pszTarget);
2,283✔
948
    return poFSHandlerTarget->CopyFile(pszSource, pszTarget, fpSource,
2,283✔
949
                                       nSourceSize, papszOptions, pProgressFunc,
950
                                       pProgressData);
2,283✔
951
}
952

953
/************************************************************************/
954
/*                       VSICopyFileRestartable()                       */
955
/************************************************************************/
956

957
/**
958
 \brief Copy a source file into a target file in a way that can (potentially)
959
 be restarted.
960

961
 This function provides the possibility of efficiently restarting upload of
962
 large files to cloud storage that implements upload in a chunked way,
963
 such as /vsis3/ and /vsigs/.
964
 For other destination file systems, this function may fallback to
965
 VSICopyFile() and not provide any smart restartable implementation.
966

967
 Example of a potential workflow:
968

969
 @code{.cpp}
970
 char* pszOutputPayload = NULL;
971
 int ret = VSICopyFileRestartable(pszSource, pszTarget, NULL,
972
                                  &pszOutputPayload, NULL, NULL, NULL);
973
 while( ret == 1 ) // add also a limiting counter to avoid potentiall endless looping
974
 {
975
     // TODO: wait for some time
976

977
     char* pszOutputPayloadNew = NULL;
978
     const char* pszInputPayload = pszOutputPayload;
979
     ret = VSICopyFileRestartable(pszSource, pszTarget, pszInputPayload,
980
                                  &pszOutputPayloadNew, NULL, NULL, NULL);
981
     VSIFree(pszOutputPayload);
982
     pszOutputPayload = pszOutputPayloadNew;
983
 }
984
 VSIFree(pszOutputPayload);
985
 @endcode
986

987
 @param pszSource Source filename. UTF-8 encoded. Must not be NULL
988
 @param pszTarget Target filename. UTF-8 encoded. Must not be NULL
989
 @param pszInputPayload NULL at the first invocation. When doing a retry,
990
                        should be the content of *ppszOutputPayload from a
991
                        previous invocation.
992
 @param[out] ppszOutputPayload Pointer to an output string that will be set to
993
                               a value that can be provided as pszInputPayload
994
                               for a next call to VSICopyFileRestartable().
995
                               ppszOutputPayload must not be NULL.
996
                               The string set in *ppszOutputPayload, if not NULL,
997
                               is JSON-encoded, and can be re-used in another
998
                               process instance. It must be freed with VSIFree()
999
                               when no longer needed.
1000
 @param papszOptions Null terminated list of options, or NULL.
1001
 Currently accepted options are:
1002
 <ul>
1003
 <li>NUM_THREADS=integer or ALL_CPUS. Number of threads to use for parallel
1004
 file copying. Only use for when /vsis3/, /vsigs/, /vsiaz/ or /vsiadls/ is in
1005
 source or target. The default is 10.
1006
 </li>
1007
 <li>CHUNK_SIZE=integer. Maximum size of chunk (in bytes) to use
1008
 to split large objects. For upload to /vsis3/, this chunk size must be set at
1009
 least to 5 MB. The default is 50 MB.
1010
 </li>
1011
 </ul>
1012
 @param pProgressFunc Progress callback, or NULL.
1013
 @param pProgressData User data of progress callback, or NULL.
1014
 @return 0 on success,
1015
         -1 on (non-restartable) failure,
1016
         1 if VSICopyFileRestartable() can be called again in a restartable way
1017
 @since GDAL 3.10
1018

1019
 @see VSIAbortPendingUploads()
1020
*/
1021

1022
int VSICopyFileRestartable(const char *pszSource, const char *pszTarget,
20✔
1023
                           const char *pszInputPayload,
1024
                           char **ppszOutputPayload,
1025
                           const char *const *papszOptions,
1026
                           GDALProgressFunc pProgressFunc, void *pProgressData)
1027

1028
{
1029
    if (!pszSource)
20✔
1030
    {
1031
        return -1;
×
1032
    }
1033
    if (!pszTarget || pszTarget[0] == '\0')
20✔
1034
    {
1035
        return -1;
×
1036
    }
1037
    if (!ppszOutputPayload)
20✔
1038
    {
1039
        return -1;
×
1040
    }
1041

1042
    VSIFilesystemHandler *poFSHandlerTarget =
1043
        VSIFileManager::GetHandler(pszTarget);
20✔
1044
    return poFSHandlerTarget->CopyFileRestartable(
20✔
1045
        pszSource, pszTarget, pszInputPayload, ppszOutputPayload, papszOptions,
1046
        pProgressFunc, pProgressData);
20✔
1047
}
1048

1049
/************************************************************************/
1050
/*                             VSISync()                                */
1051
/************************************************************************/
1052

1053
/**
1054
 * \brief Synchronize a source file/directory with a target file/directory.
1055
 *
1056
 * This is a analog of the 'rsync' utility. In the current implementation,
1057
 * rsync would be more efficient for local file copying, but VSISync() main
1058
 * interest is when the source or target is a remote
1059
 * file system like /vsis3/ or /vsigs/, in which case it can take into account
1060
 * the timestamps of the files (or optionally the ETag/MD5Sum) to avoid
1061
 * unneeded copy operations.
1062
 *
1063
 * This is only implemented efficiently for:
1064
 * <ul>
1065
 * <li> local filesystem <--> remote filesystem.</li>
1066
 * <li> remote filesystem <--> remote filesystem (starting with GDAL 3.1).
1067
 * Where the source and target remote filesystems are the same and one of
1068
 * /vsis3/, /vsigs/ or /vsiaz/. Or when the target is /vsiaz/ and the source
1069
 * is /vsis3/, /vsigs/, /vsiadls/ or /vsicurl/ (starting with GDAL 3.8)</li>
1070
 * </ul>
1071
 *
1072
 * Similarly to rsync behavior, if the source filename ends with a slash,
1073
 * it means that the content of the directory must be copied, but not the
1074
 * directory name. For example, assuming "/home/even/foo" contains a file "bar",
1075
 * VSISync("/home/even/foo/", "/mnt/media", ...) will create a "/mnt/media/bar"
1076
 * file. Whereas VSISync("/home/even/foo", "/mnt/media", ...) will create a
1077
 * "/mnt/media/foo" directory which contains a bar file.
1078
 *
1079
 * @param pszSource Source file or directory.  UTF-8 encoded.
1080
 * @param pszTarget Target file or directory.  UTF-8 encoded.
1081
 * @param papszOptions Null terminated list of options, or NULL.
1082
 * Currently accepted options are:
1083
 * <ul>
1084
 * <li>RECURSIVE=NO (the default is YES)</li>
1085
 * <li>SYNC_STRATEGY=TIMESTAMP/ETAG/OVERWRITE.
1086
 *
1087
 *     Determines which criterion is used to determine if a target file must be
1088
 *     replaced when it already exists and has the same file size as the source.
1089
 *     Only applies for a source or target being a network filesystem.
1090
 *
1091
 *     The default is TIMESTAMP (similarly to how 'aws s3 sync' works), that is
1092
 *     to say that for an upload operation, a remote file is
1093
 *     replaced if it has a different size or if it is older than the source.
1094
 *     For a download operation, a local file is  replaced if it has a different
1095
 *     size or if it is newer than the remote file.
1096
 *
1097
 *     The ETAG strategy assumes that the ETag metadata of the remote file is
1098
 *     the MD5Sum of the file content, which is only true in the case of /vsis3/
1099
 *     for files not using KMS server side encryption and uploaded in a single
1100
 *     PUT operation (so smaller than 50 MB given the default used by GDAL).
1101
 *     Only to be used for /vsis3/, /vsigs/ or other filesystems using a
1102
 *     MD5Sum as ETAG.
1103
 *
1104
 *     The OVERWRITE strategy (GDAL >= 3.2) will always overwrite the target
1105
 *     file with the source one.
1106
 * </li>
1107
 * <li>NUM_THREADS=integer. (GDAL >= 3.1) Number of threads to use for parallel
1108
 * file copying. Only use for when /vsis3/, /vsigs/, /vsiaz/ or /vsiadls/ is in
1109
 * source or target. The default is 10 since GDAL 3.3</li>
1110
 * <li>CHUNK_SIZE=integer. (GDAL >= 3.1) Maximum size of chunk (in bytes) to use
1111
 * to split large objects when downloading them from /vsis3/, /vsigs/, /vsiaz/
1112
 * or /vsiadls/ to local file system, or for upload to /vsis3/, /vsiaz/ or
1113
 * /vsiadls/ from local file system. Only used if NUM_THREADS > 1. For upload to
1114
 * /vsis3/, this chunk size must be set at least to 5 MB. The default is 8 MB
1115
 * since GDAL 3.3</li> <li>x-amz-KEY=value. (GDAL >= 3.5) MIME header to pass
1116
 * during creation of a /vsis3/ object.</li> <li>x-goog-KEY=value. (GDAL >= 3.5)
1117
 * MIME header to pass during creation of a /vsigs/ object.</li>
1118
 * <li>x-ms-KEY=value. (GDAL >= 3.5) MIME header to pass during creation of a
1119
 * /vsiaz/ or /vsiadls/ object.</li>
1120
 * </ul>
1121
 * @param pProgressFunc Progress callback, or NULL.
1122
 * @param pProgressData User data of progress callback, or NULL.
1123
 * @param ppapszOutputs Unused. Should be set to NULL for now.
1124
 *
1125
 * @return TRUE on success or FALSE on an error.
1126
 * @since GDAL 2.4
1127
 */
1128

1129
int VSISync(const char *pszSource, const char *pszTarget,
49✔
1130
            const char *const *papszOptions, GDALProgressFunc pProgressFunc,
1131
            void *pProgressData, char ***ppapszOutputs)
1132

1133
{
1134
    if (pszSource[0] == '\0' || pszTarget[0] == '\0')
49✔
1135
    {
1136
        return FALSE;
×
1137
    }
1138

1139
    VSIFilesystemHandler *poFSHandlerSource =
1140
        VSIFileManager::GetHandler(pszSource);
49✔
1141
    VSIFilesystemHandler *poFSHandlerTarget =
1142
        VSIFileManager::GetHandler(pszTarget);
49✔
1143
    VSIFilesystemHandler *poFSHandlerLocal = VSIFileManager::GetHandler("");
49✔
1144
    VSIFilesystemHandler *poFSHandlerMem =
1145
        VSIFileManager::GetHandler("/vsimem/");
49✔
1146
    VSIFilesystemHandler *poFSHandler = poFSHandlerSource;
49✔
1147
    if (poFSHandlerTarget != poFSHandlerLocal &&
49✔
1148
        poFSHandlerTarget != poFSHandlerMem)
1149
    {
1150
        poFSHandler = poFSHandlerTarget;
22✔
1151
    }
1152

1153
    return poFSHandler->Sync(pszSource, pszTarget, papszOptions, pProgressFunc,
98✔
1154
                             pProgressData, ppapszOutputs)
49✔
1155
               ? TRUE
49✔
1156
               : FALSE;
49✔
1157
}
1158

1159
/************************************************************************/
1160
/*                    VSIMultipartUploadGetCapabilities()               */
1161
/************************************************************************/
1162

1163
/**
1164
 * \brief Return capabilities for multiple part file upload.
1165
 *
1166
 * @param pszFilename Filename, or virtual file system prefix, onto which
1167
 * capabilities should apply.
1168
 * @param[out] pbNonSequentialUploadSupported If not null,
1169
 * the pointed value is set if parts can be uploaded in a non-sequential way.
1170
 * @param[out] pbParallelUploadSupported If not null,
1171
 * the pointed value is set if parts can be uploaded in a parallel way.
1172
 * (implies *pbNonSequentialUploadSupported = true)
1173
 * @param[out] pbAbortSupported If not null,
1174
 * the pointed value is set if VSIMultipartUploadAbort() is implemented.
1175
 * @param[out] pnMinPartSize If not null, the pointed value is set to the minimum
1176
 * size of parts (but the last one), in MiB.
1177
 * @param[out] pnMaxPartSize If not null, the pointed value is set to the maximum
1178
 * size of parts, in MiB.
1179
 * @param[out] pnMaxPartCount  If not null, the pointed value is set to the
1180
 * maximum number of parts that can be uploaded.
1181
 *
1182
 * @return TRUE in case of success, FALSE otherwise.
1183
 *
1184
 * @since 3.10
1185
 */
1186
int VSIMultipartUploadGetCapabilities(
7✔
1187
    const char *pszFilename, int *pbNonSequentialUploadSupported,
1188
    int *pbParallelUploadSupported, int *pbAbortSupported,
1189
    size_t *pnMinPartSize, size_t *pnMaxPartSize, int *pnMaxPartCount)
1190
{
1191
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
7✔
1192

1193
    return poFSHandler->MultipartUploadGetCapabilities(
14✔
1194
        pbNonSequentialUploadSupported, pbParallelUploadSupported,
1195
        pbAbortSupported, pnMinPartSize, pnMaxPartSize, pnMaxPartCount);
7✔
1196
}
1197

1198
/************************************************************************/
1199
/*                     VSIMultipartUploadStart()                        */
1200
/************************************************************************/
1201

1202
/**
1203
 * \brief Initiates the upload a (big) file in a piece-wise way.
1204
 *
1205
 * Using this API directly is generally not needed, but in very advanced cases,
1206
 * as VSIFOpenL(..., "wb") + VSIFWriteL(), VSISync(), VSICopyFile() or
1207
 * VSICopyFileRestartable() may be able to leverage it when needed.
1208
 *
1209
 * This is only implemented for the /vsis3/, /vsigs/, /vsiaz/, /vsiadls/ and
1210
 * /vsioss/ virtual file systems.
1211
 *
1212
 * The typical workflow is to do :
1213
 * - VSIMultipartUploadStart()
1214
 * - VSIMultipartUploadAddPart(): several times
1215
 * - VSIMultipartUploadEnd()
1216
 *
1217
 * If VSIMultipartUploadAbort() is supported by the filesystem (VSIMultipartUploadGetCapabilities()
1218
 * can be used to determine it), this function should be called to cancel an
1219
 * upload. This can be needed to avoid extra billing for some cloud storage
1220
 * providers.
1221
 *
1222
 * The following options are supported:
1223
 * <ul>
1224
 * <li>MIME headers such as Content-Type and Content-Encoding
1225
 * are supported for the /vsis3/, /vsigs/, /vsiaz/, /vsiadls/ file systems.</li>
1226
 * </ul>
1227
 *
1228
 * @param pszFilename Filename to create
1229
 * @param papszOptions NULL or null-terminated list of options.
1230
 * @return an upload ID to pass to other VSIMultipartUploadXXXXX() functions,
1231
 * and to free with CPLFree() once done, or nullptr in case of error.
1232
 *
1233
 * @since 3.10
1234
 */
1235
char *VSIMultipartUploadStart(const char *pszFilename,
4✔
1236
                              CSLConstList papszOptions)
1237
{
1238
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
4✔
1239

1240
    return poFSHandler->MultipartUploadStart(pszFilename, papszOptions);
4✔
1241
}
1242

1243
/************************************************************************/
1244
/*                     VSIMultipartUploadAddPart()                      */
1245
/************************************************************************/
1246

1247
/**
1248
 * \brief Uploads a new part to a multi-part uploaded file.
1249
 *
1250
 * Cf VSIMultipartUploadStart().
1251
 *
1252
 * VSIMultipartUploadGetCapabilities() returns hints on the constraints that
1253
 * apply to the upload, in terms of minimum/maximum size of each part, maximum
1254
 * number of parts, and whether non-sequential or parallel uploads are
1255
 * supported.
1256
 *
1257
 * @param pszFilename Filename to which to append the new part. Should be the
1258
 *                    same as the one used for VSIMultipartUploadStart()
1259
 * @param pszUploadId Value returned by VSIMultipartUploadStart()
1260
 * @param nPartNumber Part number, starting at 1.
1261
 * @param nFileOffset Offset within the file at which (starts at 0) the passed
1262
 *                    data starts.
1263
 * @param pData       Pointer to an array of nDataLength bytes.
1264
 * @param nDataLength Size in bytes of pData.
1265
 * @param papszOptions Unused. Should be nullptr.
1266
 *
1267
 * @return a part identifier that must be passed into the apszPartIds[] array of
1268
 * VSIMultipartUploadEnd(), and to free with CPLFree() once done, or nullptr in
1269
 * case of error.
1270
 *
1271
 * @since 3.10
1272
 */
1273
char *VSIMultipartUploadAddPart(const char *pszFilename,
5✔
1274
                                const char *pszUploadId, int nPartNumber,
1275
                                vsi_l_offset nFileOffset, const void *pData,
1276
                                size_t nDataLength, CSLConstList papszOptions)
1277
{
1278
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
5✔
1279

1280
    return poFSHandler->MultipartUploadAddPart(pszFilename, pszUploadId,
5✔
1281
                                               nPartNumber, nFileOffset, pData,
1282
                                               nDataLength, papszOptions);
5✔
1283
}
1284

1285
/************************************************************************/
1286
/*                       VSIMultipartUploadEnd()                        */
1287
/************************************************************************/
1288

1289
/**
1290
 * \brief Completes a multi-part file upload.
1291
 *
1292
 * Cf VSIMultipartUploadStart().
1293
 *
1294
 * @param pszFilename Filename for which multipart upload should be completed.
1295
 *                    Should be the same as the one used for
1296
 *                    VSIMultipartUploadStart()
1297
 * @param pszUploadId Value returned by VSIMultipartUploadStart()
1298
 * @param nPartIdsCount Number of parts,  andsize of apszPartIds
1299
 * @param apszPartIds Array of part identifiers (as returned by
1300
 *                    VSIMultipartUploadAddPart()), that must be ordered in
1301
 *                    the sequential order of parts, and of size nPartIdsCount.
1302
 * @param nTotalSize  Total size of the file in bytes (must be equal to the sum
1303
 *                    of nDataLength passed to VSIMultipartUploadAddPart())
1304
 * @param papszOptions Unused. Should be nullptr.
1305
 *
1306
 * @return TRUE in case of success, FALSE in case of failure.
1307
 *
1308
 * @since 3.10
1309
 */
1310
int VSIMultipartUploadEnd(const char *pszFilename, const char *pszUploadId,
5✔
1311
                          size_t nPartIdsCount, const char *const *apszPartIds,
1312
                          vsi_l_offset nTotalSize, CSLConstList papszOptions)
1313
{
1314
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
5✔
1315

1316
    return poFSHandler->MultipartUploadEnd(pszFilename, pszUploadId,
10✔
1317
                                           nPartIdsCount, apszPartIds,
1318
                                           nTotalSize, papszOptions);
5✔
1319
}
1320

1321
/************************************************************************/
1322
/*                       VSIMultipartUploadAbort()                      */
1323
/************************************************************************/
1324

1325
/**
1326
 * \brief Aborts a multi-part file upload.
1327
 *
1328
 * Cf VSIMultipartUploadStart().
1329
 *
1330
 * This function is not implemented for all virtual file systems.
1331
 * Use VSIMultipartUploadGetCapabilities() to determine if it is supported.
1332
 *
1333
 * This can be needed to avoid extra billing for some cloud storage providers.
1334
 *
1335
 * @param pszFilename Filename for which multipart upload should be completed.
1336
 *                    Should be the same as the one used for
1337
 *                    VSIMultipartUploadStart()
1338
 * @param pszUploadId Value returned by VSIMultipartUploadStart()
1339
 * @param papszOptions Unused. Should be nullptr.
1340
 *
1341
 * @return TRUE in case of success, FALSE in case of failure.
1342
 *
1343
 * @since 3.10
1344
 */
1345
int VSIMultipartUploadAbort(const char *pszFilename, const char *pszUploadId,
6✔
1346
                            CSLConstList papszOptions)
1347
{
1348
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
6✔
1349

1350
    return poFSHandler->MultipartUploadAbort(pszFilename, pszUploadId,
12✔
1351
                                             papszOptions);
6✔
1352
}
1353

1354
#ifndef DOXYGEN_SKIP
1355

1356
/************************************************************************/
1357
/*                     MultipartUploadGetCapabilities()                 */
1358
/************************************************************************/
1359

1360
bool VSIFilesystemHandler::MultipartUploadGetCapabilities(int *, int *, int *,
2✔
1361
                                                          size_t *, size_t *,
1362
                                                          int *)
1363
{
1364
    CPLError(
2✔
1365
        CE_Failure, CPLE_NotSupported,
1366
        "MultipartUploadGetCapabilities() not supported by this file system");
1367
    return false;
2✔
1368
}
1369

1370
/************************************************************************/
1371
/*                         MultipartUploadStart()                       */
1372
/************************************************************************/
1373

1374
char *VSIFilesystemHandler::MultipartUploadStart(const char *, CSLConstList)
1✔
1375
{
1376
    CPLError(CE_Failure, CPLE_NotSupported,
1✔
1377
             "MultipartUploadStart() not supported by this file system");
1378
    return nullptr;
1✔
1379
}
1380

1381
/************************************************************************/
1382
/*                       MultipartUploadAddPart()                       */
1383
/************************************************************************/
1384

1385
char *VSIFilesystemHandler::MultipartUploadAddPart(const char *, const char *,
1✔
1386
                                                   int, vsi_l_offset,
1387
                                                   const void *, size_t,
1388
                                                   CSLConstList)
1389
{
1390
    CPLError(CE_Failure, CPLE_NotSupported,
1✔
1391
             "MultipartUploadAddPart() not supported by this file system");
1392
    return nullptr;
1✔
1393
}
1394

1395
/************************************************************************/
1396
/*                         MultipartUploadEnd()                         */
1397
/************************************************************************/
1398

1399
bool VSIFilesystemHandler::MultipartUploadEnd(const char *, const char *,
1✔
1400
                                              size_t, const char *const *,
1401
                                              vsi_l_offset, CSLConstList)
1402
{
1403
    CPLError(CE_Failure, CPLE_NotSupported,
1✔
1404
             "MultipartUploadEnd() not supported by this file system");
1405
    return FALSE;
1✔
1406
}
1407

1408
/************************************************************************/
1409
/*                         MultipartUploadAbort()                       */
1410
/************************************************************************/
1411

1412
bool VSIFilesystemHandler::MultipartUploadAbort(const char *, const char *,
1✔
1413
                                                CSLConstList)
1414
{
1415
    CPLError(CE_Failure, CPLE_NotSupported,
1✔
1416
             "MultipartUploadAbort() not supported by this file system");
1417
    return FALSE;
1✔
1418
}
1419

1420
#endif
1421

1422
/************************************************************************/
1423
/*                         VSIAbortPendingUploads()                     */
1424
/************************************************************************/
1425

1426
/**
1427
 * \brief Abort all ongoing multi-part uploads.
1428
 *
1429
 * Abort ongoing multi-part uploads on AWS S3 and Google Cloud Storage. This
1430
 * can be used in case a process doing such uploads was killed in a unclean way.
1431
 *
1432
 * This can be needed to avoid extra billing for some cloud storage providers.
1433
 *
1434
 * Without effect on other virtual file systems.
1435
 *
1436
 * VSIMultipartUploadAbort() can also be used to cancel a given upload, if the
1437
 * upload ID is known.
1438
 *
1439
 * @param pszFilename filename or prefix of a directory into which multipart
1440
 * uploads must be aborted. This can be the root directory of a bucket.  UTF-8
1441
 * encoded.
1442
 *
1443
 * @return TRUE on success or FALSE on an error.
1444
 * @since GDAL 3.4
1445
 */
1446

1447
int VSIAbortPendingUploads(const char *pszFilename)
1✔
1448
{
1449
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
1✔
1450

1451
    return poFSHandler->AbortPendingUploads(pszFilename);
1✔
1452
}
1453

1454
/************************************************************************/
1455
/*                              VSIRmdir()                              */
1456
/************************************************************************/
1457

1458
/**
1459
 * \brief Delete a directory.
1460
 *
1461
 * Deletes a directory object from the file system.  On some systems
1462
 * the directory must be empty before it can be deleted.
1463
 *
1464
 * This method goes through the VSIFileHandler virtualization and may
1465
 * work on unusual filesystems such as in memory.
1466
 *
1467
 * Analog of the POSIX rmdir() function.
1468
 *
1469
 * @param pszDirname the path of the directory to be deleted.  UTF-8 encoded.
1470
 *
1471
 * @return 0 on success or -1 on an error.
1472
 */
1473

1474
int VSIRmdir(const char *pszDirname)
153✔
1475

1476
{
1477
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszDirname);
153✔
1478

1479
    return poFSHandler->Rmdir(pszDirname);
153✔
1480
}
1481

1482
/************************************************************************/
1483
/*                         VSIRmdirRecursive()                          */
1484
/************************************************************************/
1485

1486
/**
1487
 * \brief Delete a directory recursively
1488
 *
1489
 * Deletes a directory object and its content from the file system.
1490
 *
1491
 * Starting with GDAL 3.1, /vsis3/ has an efficient implementation of this
1492
 * function.
1493
 * Starting with GDAL 3.4, /vsigs/ has an efficient implementation of this
1494
 * function, provided that OAuth2 authentication is used.
1495
 *
1496
 * @return 0 on success or -1 on an error.
1497
 * @since GDAL 2.3
1498
 */
1499

1500
int VSIRmdirRecursive(const char *pszDirname)
4,758✔
1501
{
1502
    if (pszDirname == nullptr || pszDirname[0] == '\0' ||
4,758✔
1503
        strncmp("/", pszDirname, 2) == 0)
4,758✔
1504
    {
1505
        return -1;
×
1506
    }
1507
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszDirname);
4,758✔
1508
    return poFSHandler->RmdirRecursive(pszDirname);
4,758✔
1509
}
1510

1511
/************************************************************************/
1512
/*                              VSIStatL()                              */
1513
/************************************************************************/
1514

1515
/**
1516
 * \brief Get filesystem object info.
1517
 *
1518
 * Fetches status information about a filesystem object (file, directory, etc).
1519
 * The returned information is placed in the VSIStatBufL structure.   For
1520
 * portability, only use the st_size (size in bytes) and st_mode (file type).
1521
 * This method is similar to VSIStat(), but will work on large files on
1522
 * systems where this requires special calls.
1523
 *
1524
 * This method goes through the VSIFileHandler virtualization and may
1525
 * work on unusual filesystems such as in memory.
1526
 *
1527
 * Analog of the POSIX stat() function.
1528
 *
1529
 * @param pszFilename the path of the filesystem object to be queried.
1530
 * UTF-8 encoded.
1531
 * @param psStatBuf the structure to load with information.
1532
 *
1533
 * @return 0 on success or -1 on an error.
1534
 */
1535

1536
int VSIStatL(const char *pszFilename, VSIStatBufL *psStatBuf)
432,018✔
1537

1538
{
1539
    return VSIStatExL(pszFilename, psStatBuf, 0);
432,018✔
1540
}
1541

1542
/************************************************************************/
1543
/*                            VSIStatExL()                              */
1544
/************************************************************************/
1545

1546
/**
1547
 * \brief Get filesystem object info.
1548
 *
1549
 * Fetches status information about a filesystem object (file, directory, etc).
1550
 * The returned information is placed in the VSIStatBufL structure.   For
1551
 * portability, only use the st_size (size in bytes) and st_mode (file type).
1552
 * This method is similar to VSIStat(), but will work on large files on
1553
 * systems where this requires special calls.
1554
 *
1555
 * This method goes through the VSIFileHandler virtualization and may
1556
 * work on unusual filesystems such as in memory.
1557
 *
1558
 * Analog of the POSIX stat() function, with an extra parameter to
1559
 * specify which information is needed, which offers a potential for
1560
 * speed optimizations on specialized and potentially slow virtual
1561
 * filesystem objects (/vsigzip/, /vsicurl/)
1562
 *
1563
 * @param pszFilename the path of the filesystem object to be queried.
1564
 * UTF-8 encoded.
1565
 * @param psStatBuf the structure to load with information.
1566
 * @param nFlags 0 to get all information, or VSI_STAT_EXISTS_FLAG,
1567
 *                 VSI_STAT_NATURE_FLAG, VSI_STAT_SIZE_FLAG,
1568
 * VSI_STAT_SET_ERROR_FLAG, VSI_STAT_CACHE_ONLY or a combination of those to get
1569
 * partial info.
1570
 *
1571
 * @return 0 on success or -1 on an error.
1572
 *
1573
 * @since GDAL 1.8.0
1574
 */
1575

1576
int VSIStatExL(const char *pszFilename, VSIStatBufL *psStatBuf, int nFlags)
814,097✔
1577

1578
{
1579
    char szAltPath[4] = {'\0'};
814,097✔
1580

1581
    // Enable to work on "C:" as if it were "C:\".
1582
    if (pszFilename[0] != '\0' && pszFilename[1] == ':' &&
814,097✔
1583
        pszFilename[2] == '\0')
20✔
1584
    {
1585
        szAltPath[0] = pszFilename[0];
×
1586
        szAltPath[1] = pszFilename[1];
×
1587
        szAltPath[2] = '\\';
×
1588
        szAltPath[3] = '\0';
×
1589

1590
        pszFilename = szAltPath;
×
1591
    }
1592

1593
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
814,097✔
1594

1595
    if (nFlags == 0)
814,096✔
1596
        nFlags =
435,653✔
1597
            VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG | VSI_STAT_SIZE_FLAG;
1598

1599
    return poFSHandler->Stat(pszFilename, psStatBuf, nFlags);
1,628,190✔
1600
}
1601

1602
/************************************************************************/
1603
/*                       VSIGetFileMetadata()                           */
1604
/************************************************************************/
1605

1606
/**
1607
 * \brief Get metadata on files.
1608
 *
1609
 * Implemented currently only for network-like filesystems, or starting
1610
 * with GDAL 3.7 for /vsizip/
1611
 *
1612
 * Starting with GDAL 3.11, calling it with pszFilename being the root of a
1613
 * /vsigs/ bucket and pszDomain == nullptr, and when authenticated through
1614
 * OAuth2, will result in returning the result of a "Buckets: get"
1615
 * operation (https://cloud.google.com/storage/docs/json_api/v1/buckets/get),
1616
 * with the keys of the top-level JSON document as keys of the key=value pairs
1617
 * returned by this function.
1618
 *
1619
 * @param pszFilename the path of the filesystem object to be queried.
1620
 * UTF-8 encoded.
1621
 * @param pszDomain Metadata domain to query. Depends on the file system.
1622
 * The following ones are supported:
1623
 * <ul>
1624
 * <li>HEADERS: to get HTTP headers for network-like filesystems (/vsicurl/,
1625
 * /vsis3/, /vsgis/, etc)</li>
1626
 * <li>TAGS:
1627
 *   <ul>
1628
 *     <li>/vsis3/: to get S3 Object tagging information</li>
1629
 *     <li>/vsiaz/: to get blob tags. Refer to
1630
 *     https://docs.microsoft.com/en-us/rest/api/storageservices/get-blob-tags
1631
 *     </li>
1632
 *   </ul>
1633
 * </li>
1634
 * <li>STATUS: specific to /vsiadls/: returns all system defined properties for
1635
 * a path (seems in practice to be a subset of HEADERS)</li> <li>ACL: specific
1636
 * to /vsiadls/ and /vsigs/: returns the access control list for a path. For
1637
 * /vsigs/, a single XML=xml_content string is returned. Refer to
1638
 * https://cloud.google.com/storage/docs/xml-api/get-object-acls
1639
 * </li>
1640
 * <li>METADATA: specific to /vsiaz/: to get blob metadata. Refer to
1641
 * https://docs.microsoft.com/en-us/rest/api/storageservices/get-blob-metadata.
1642
 * Note: this will be a subset of what pszDomain=HEADERS returns</li>
1643
 * <li>ZIP: specific to /vsizip/: to obtain ZIP specific metadata, in particular
1644
 * if a file is SOZIP-enabled (SOZIP_VALID=YES)</li>
1645
 * </ul>
1646
 * @param papszOptions Unused. Should be set to NULL.
1647
 *
1648
 * @return a NULL-terminated list of key=value strings, to be freed with
1649
 * CSLDestroy() or NULL in case of error / empty list.
1650
 *
1651
 * @since GDAL 3.1.0
1652
 */
1653

1654
char **VSIGetFileMetadata(const char *pszFilename, const char *pszDomain,
91✔
1655
                          CSLConstList papszOptions)
1656
{
1657
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
91✔
1658
    return poFSHandler->GetFileMetadata(pszFilename, pszDomain, papszOptions);
91✔
1659
}
1660

1661
/************************************************************************/
1662
/*                       VSISetFileMetadata()                           */
1663
/************************************************************************/
1664

1665
/**
1666
 * \brief Set metadata on files.
1667
 *
1668
 * Implemented currently only for /vsis3/, /vsigs/, /vsiaz/ and /vsiadls/
1669
 *
1670
 * @param pszFilename the path of the filesystem object to be set.
1671
 * UTF-8 encoded.
1672
 * @param papszMetadata NULL-terminated list of key=value strings.
1673
 * @param pszDomain Metadata domain to set. Depends on the file system.
1674
 * The following are supported:
1675
 * <ul>
1676
 * <li>HEADERS: specific to /vsis3/ and /vsigs/: to set HTTP headers, such as
1677
 * "Content-Type", or other file system specific header.
1678
 * For /vsigs/, this also includes: x-goog-meta-{key}={value}. Note that you
1679
 * should specify all metadata to be set, as existing metadata will be
1680
 * overridden.
1681
 * </li>
1682
 * <li>TAGS: Content of papszMetadata should be KEY=VALUE pairs.
1683
 *    <ul>
1684
 *      <li>/vsis3/: to set S3 Object tagging information</li>
1685
 *      <li>/vsiaz/: to set blob tags. Refer to
1686
 * https://docs.microsoft.com/en-us/rest/api/storageservices/set-blob-tags.
1687
 * Note: storageV2 must be enabled on the account</li>
1688
 *    </ul>
1689
 * </li>
1690
 * <li>PROPERTIES:
1691
 *    <ul>
1692
 *      <li>to /vsiaz/: to set properties. Refer to
1693
 * https://docs.microsoft.com/en-us/rest/api/storageservices/set-blob-properties.</li>
1694
 *      <li>to /vsiadls/: to set properties. Refer to
1695
 * https://docs.microsoft.com/en-us/rest/api/storageservices/datalakestoragegen2/path/update
1696
 * for headers valid for action=setProperties.</li>
1697
 *    </ul>
1698
 * </li>
1699
 * <li>ACL: specific to /vsiadls/ and /vsigs/: to set access control list.
1700
 * For /vsiadls/, refer to
1701
 * https://docs.microsoft.com/en-us/rest/api/storageservices/datalakestoragegen2/path/update
1702
 * for headers valid for action=setAccessControl or setAccessControlRecursive.
1703
 * In setAccessControlRecursive, x-ms-acl must be specified in papszMetadata.
1704
 * For /vsigs/, refer to
1705
 * https://cloud.google.com/storage/docs/xml-api/put-object-acls. A single
1706
 * XML=xml_content string should be specified as in papszMetadata.
1707
 * </li>
1708
 * <li>METADATA: specific to /vsiaz/: to set blob metadata. Refer to
1709
 * https://docs.microsoft.com/en-us/rest/api/storageservices/set-blob-metadata.
1710
 * Content of papszMetadata should be strings in the form
1711
 * x-ms-meta-name=value</li>
1712
 * </ul>
1713
 * @param papszOptions NULL or NULL terminated list of options.
1714
 *                     For /vsiadls/ and pszDomain=ACL, "RECURSIVE=TRUE" can be
1715
 *                     set to set the access control list recursively. When
1716
 *                     RECURSIVE=TRUE is set, MODE should also be set to one of
1717
 *                     "set", "modify" or "remove".
1718
 *
1719
 * @return TRUE in case of success.
1720
 *
1721
 * @since GDAL 3.1.0
1722
 */
1723

1724
int VSISetFileMetadata(const char *pszFilename, CSLConstList papszMetadata,
17✔
1725
                       const char *pszDomain, CSLConstList papszOptions)
1726
{
1727
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
17✔
1728
    return poFSHandler->SetFileMetadata(pszFilename, papszMetadata, pszDomain,
34✔
1729
                                        papszOptions)
17✔
1730
               ? 1
17✔
1731
               : 0;
17✔
1732
}
1733

1734
/************************************************************************/
1735
/*                       VSIIsCaseSensitiveFS()                         */
1736
/************************************************************************/
1737

1738
/**
1739
 * \brief Returns if the filenames of the filesystem are case sensitive.
1740
 *
1741
 * This method retrieves to which filesystem belongs the passed filename
1742
 * and return TRUE if the filenames of that filesystem are case sensitive.
1743
 *
1744
 * Currently, this will return FALSE only for Windows real filenames. Other
1745
 * VSI virtual filesystems are case sensitive.
1746
 *
1747
 * This methods avoid ugly \#ifndef _WIN32 / \#endif code, that is wrong when
1748
 * dealing with virtual filenames.
1749
 *
1750
 * @param pszFilename the path of the filesystem object to be tested.
1751
 * UTF-8 encoded.
1752
 *
1753
 * @return TRUE if the filenames of the filesystem are case sensitive.
1754
 *
1755
 * @since GDAL 1.8.0
1756
 */
1757

1758
int VSIIsCaseSensitiveFS(const char *pszFilename)
27,738✔
1759
{
1760
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
27,738✔
1761

1762
    return poFSHandler->IsCaseSensitive(pszFilename);
27,738✔
1763
}
1764

1765
/************************************************************************/
1766
/*                       VSISupportsSparseFiles()                       */
1767
/************************************************************************/
1768

1769
/**
1770
 * \brief Returns if the filesystem supports sparse files.
1771
 *
1772
 * Only supported on Linux (and no other Unix derivatives) and
1773
 * Windows.  On Linux, the answer depends on a few hardcoded
1774
 * signatures for common filesystems. Other filesystems will be
1775
 * considered as not supporting sparse files.
1776
 *
1777
 * @param pszPath the path of the filesystem object to be tested.
1778
 * UTF-8 encoded.
1779
 *
1780
 * @return TRUE if the file system is known to support sparse files. FALSE may
1781
 *              be returned both in cases where it is known to not support them,
1782
 *              or when it is unknown.
1783
 *
1784
 * @since GDAL 2.2
1785
 */
1786

1787
int VSISupportsSparseFiles(const char *pszPath)
2✔
1788
{
1789
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath);
2✔
1790

1791
    return poFSHandler->SupportsSparseFiles(pszPath);
2✔
1792
}
1793

1794
/************************************************************************/
1795
/*                           VSIIsLocal()                               */
1796
/************************************************************************/
1797

1798
/**
1799
 * \brief Returns if the file/filesystem is "local".
1800
 *
1801
 * The concept of local is mostly by opposition with a network / remote
1802
 * file system whose access time can be long.
1803
 *
1804
 * /vsimem/ is considered to be a local file system, although a non-persistent
1805
 * one.
1806
 *
1807
 * @param pszPath the path of the filesystem object to be tested.
1808
 * UTF-8 encoded.
1809
 *
1810
 * @return TRUE or FALSE
1811
 *
1812
 * @since GDAL 3.6
1813
 */
1814

1815
bool VSIIsLocal(const char *pszPath)
248✔
1816
{
1817
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath);
248✔
1818

1819
    return poFSHandler->IsLocal(pszPath);
248✔
1820
}
1821

1822
/************************************************************************/
1823
/*                       VSIGetCanonicalFilename()                      */
1824
/************************************************************************/
1825

1826
/**
1827
 * \brief Returns the canonical filename.
1828
 *
1829
 * May be implemented by case-insensitive filesystems
1830
 * (currently Win32 and MacOSX) to return the filename with its actual case
1831
 * (i.e. the one that would be used when listing the content of the directory).
1832
 *
1833
 * @param pszPath UTF-8 encoded path
1834
 *
1835
 * @return UTF-8 encoded string, to free with VSIFree()
1836
 *
1837
 * @since GDAL 3.8
1838
 */
1839

1840
char *VSIGetCanonicalFilename(const char *pszPath)
248✔
1841
{
1842
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath);
248✔
1843

1844
    return CPLStrdup(poFSHandler->GetCanonicalFilename(pszPath).c_str());
248✔
1845
}
1846

1847
/************************************************************************/
1848
/*                      VSISupportsSequentialWrite()                    */
1849
/************************************************************************/
1850

1851
/**
1852
 * \brief Returns if the filesystem supports sequential write.
1853
 *
1854
 * @param pszPath the path of the filesystem object to be tested.
1855
 * UTF-8 encoded.
1856
 * @param bAllowLocalTempFile whether the file system is allowed to use a
1857
 * local temporary file before uploading to the target location.
1858
 *
1859
 * @return TRUE or FALSE
1860
 *
1861
 * @since GDAL 3.6
1862
 */
1863

1864
bool VSISupportsSequentialWrite(const char *pszPath, bool bAllowLocalTempFile)
104✔
1865
{
1866
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath);
104✔
1867

1868
    return poFSHandler->SupportsSequentialWrite(pszPath, bAllowLocalTempFile);
104✔
1869
}
1870

1871
/************************************************************************/
1872
/*                      VSISupportsRandomWrite()                        */
1873
/************************************************************************/
1874

1875
/**
1876
 * \brief Returns if the filesystem supports random write.
1877
 *
1878
 * @param pszPath the path of the filesystem object to be tested.
1879
 * UTF-8 encoded.
1880
 * @param bAllowLocalTempFile whether the file system is allowed to use a
1881
 * local temporary file before uploading to the target location.
1882
 *
1883
 * @return TRUE or FALSE
1884
 *
1885
 * @since GDAL 3.6
1886
 */
1887

1888
bool VSISupportsRandomWrite(const char *pszPath, bool bAllowLocalTempFile)
326✔
1889
{
1890
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath);
326✔
1891

1892
    return poFSHandler->SupportsRandomWrite(pszPath, bAllowLocalTempFile);
326✔
1893
}
1894

1895
/************************************************************************/
1896
/*                     VSIHasOptimizedReadMultiRange()                  */
1897
/************************************************************************/
1898

1899
/**
1900
 * \brief Returns if the filesystem supports efficient multi-range reading.
1901
 *
1902
 * Currently only returns TRUE for /vsicurl/ and derived file systems.
1903
 *
1904
 * @param pszPath the path of the filesystem object to be tested.
1905
 * UTF-8 encoded.
1906
 *
1907
 * @return TRUE if the file system is known to have an efficient multi-range
1908
 * reading.
1909
 *
1910
 * @since GDAL 2.3
1911
 */
1912

1913
int VSIHasOptimizedReadMultiRange(const char *pszPath)
15,297✔
1914
{
1915
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath);
15,297✔
1916

1917
    return poFSHandler->HasOptimizedReadMultiRange(pszPath);
15,296✔
1918
}
1919

1920
/************************************************************************/
1921
/*                        VSIGetActualURL()                             */
1922
/************************************************************************/
1923

1924
/**
1925
 * \brief Returns the actual URL of a supplied filename.
1926
 *
1927
 * Currently only returns a non-NULL value for network-based virtual file
1928
 * systems. For example "/vsis3/bucket/filename" will be expanded as
1929
 * "https://bucket.s3.amazon.com/filename"
1930
 *
1931
 * Note that the lifetime of the returned string, is short, and may be
1932
 * invalidated by any following GDAL functions.
1933
 *
1934
 * @param pszFilename the path of the filesystem object. UTF-8 encoded.
1935
 *
1936
 * @return the actual URL corresponding to the supplied filename, or NULL.
1937
 * Should not be freed.
1938
 *
1939
 * @since GDAL 2.3
1940
 */
1941

1942
const char *VSIGetActualURL(const char *pszFilename)
9✔
1943
{
1944
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
9✔
1945

1946
    return poFSHandler->GetActualURL(pszFilename);
9✔
1947
}
1948

1949
/************************************************************************/
1950
/*                        VSIGetSignedURL()                             */
1951
/************************************************************************/
1952

1953
/**
1954
 * \brief Returns a signed URL of a supplied filename.
1955
 *
1956
 * Currently only returns a non-NULL value for /vsis3/, /vsigs/, /vsiaz/ and
1957
 * /vsioss/ For example "/vsis3/bucket/filename" will be expanded as
1958
 * "https://bucket.s3.amazon.com/filename?X-Amz-Algorithm=AWS4-HMAC-SHA256..."
1959
 * Configuration options that apply for file opening (typically to provide
1960
 * credentials), and are returned by VSIGetFileSystemOptions(), are also valid
1961
 * in that context.
1962
 *
1963
 * @param pszFilename the path of the filesystem object. UTF-8 encoded.
1964
 * @param papszOptions list of options, or NULL. Depend on file system handler.
1965
 * For /vsis3/, /vsigs/, /vsiaz/ and /vsioss/, the following options are
1966
 * supported: <ul> <li>START_DATE=YYMMDDTHHMMSSZ: date and time in UTC following
1967
 * ISO 8601 standard, corresponding to the start of validity of the URL. If not
1968
 * specified, current date time.</li> <li>EXPIRATION_DELAY=number_of_seconds:
1969
 * number between 1 and 604800 (seven days) for the validity of the signed URL.
1970
 * Defaults to 3600 (one hour)</li> <li>VERB=GET/HEAD/DELETE/PUT/POST: HTTP VERB
1971
 * for which the request will be used. Default to GET.</li>
1972
 * </ul>
1973
 *
1974
 * /vsiaz/ supports additional options:
1975
 * <ul>
1976
 * <li>SIGNEDIDENTIFIER=value: to relate the given shared access signature
1977
 * to a corresponding stored access policy.</li>
1978
 * <li>SIGNEDPERMISSIONS=r|w: permissions associated with the shared access
1979
 * signature. Normally deduced from VERB.</li>
1980
 * </ul>
1981
 *
1982
 * @return a signed URL, or NULL. Should be freed with CPLFree().
1983
 * @since GDAL 2.3
1984
 */
1985

1986
char *VSIGetSignedURL(const char *pszFilename, CSLConstList papszOptions)
25✔
1987
{
1988
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
25✔
1989

1990
    return poFSHandler->GetSignedURL(pszFilename, papszOptions);
25✔
1991
}
1992

1993
/************************************************************************/
1994
/*                             VSIFOpenL()                              */
1995
/************************************************************************/
1996

1997
/**
1998
 * \brief Open file.
1999
 *
2000
 * This function opens a file with the desired access.  Large files (larger
2001
 * than 2GB) should be supported.  Binary access is always implied and
2002
 * the "b" does not need to be included in the pszAccess string.
2003
 *
2004
 * Note that the "VSILFILE *" returned since GDAL 1.8.0 by this function is
2005
 * *NOT* a standard C library FILE *, and cannot be used with any functions
2006
 * other than the "VSI*L" family of functions.  They aren't "real" FILE objects.
2007
 *
2008
 * On windows it is possible to define the configuration option
2009
 * GDAL_FILE_IS_UTF8 to have pszFilename treated as being in the local
2010
 * encoding instead of UTF-8, restoring the pre-1.8.0 behavior of VSIFOpenL().
2011
 *
2012
 * This method goes through the VSIFileHandler virtualization and may
2013
 * work on unusual filesystems such as in memory.
2014
 *
2015
 * Analog of the POSIX fopen() function.
2016
 *
2017
 * @param pszFilename the file to open.  UTF-8 encoded.
2018
 * @param pszAccess access requested (i.e. "r", "r+", "w")
2019
 *
2020
 * @return NULL on failure, or the file handle.
2021
 */
2022

2023
VSILFILE *VSIFOpenL(const char *pszFilename, const char *pszAccess)
234,184✔
2024

2025
{
2026
    return VSIFOpenExL(pszFilename, pszAccess, false);
234,184✔
2027
}
2028

2029
/************************************************************************/
2030
/*                               Open()                                 */
2031
/************************************************************************/
2032

2033
#ifndef DOXYGEN_SKIP
2034

2035
VSIVirtualHandle *VSIFilesystemHandler::Open(const char *pszFilename,
5,779✔
2036
                                             const char *pszAccess)
2037
{
2038
    return Open(pszFilename, pszAccess, false, nullptr);
5,779✔
2039
}
2040

2041
/************************************************************************/
2042
/*                             CopyFile()                               */
2043
/************************************************************************/
2044

2045
int VSIFilesystemHandler::CopyFile(const char *pszSource, const char *pszTarget,
2,259✔
2046
                                   VSILFILE *fpSource, vsi_l_offset nSourceSize,
2047
                                   CSLConstList papszOptions,
2048
                                   GDALProgressFunc pProgressFunc,
2049
                                   void *pProgressData)
2050
{
2051
    VSIVirtualHandleUniquePtr poFileHandleAutoClose;
2,259✔
2052
    if (!fpSource)
2,259✔
2053
    {
2054
        CPLAssert(pszSource);
2,242✔
2055
        fpSource = VSIFOpenExL(pszSource, "rb", TRUE);
2,242✔
2056
        if (!fpSource)
2,242✔
2057
        {
2058
            CPLError(CE_Failure, CPLE_FileIO, "Cannot open %s", pszSource);
1✔
2059
            return -1;
1✔
2060
        }
2061
        poFileHandleAutoClose.reset(fpSource);
2,241✔
2062
    }
2063
    if (nSourceSize == static_cast<vsi_l_offset>(-1) &&
2,258✔
2064
        pProgressFunc != nullptr && pszSource != nullptr)
3✔
2065
    {
2066
        VSIStatBufL sStat;
2067
        if (VSIStatL(pszSource, &sStat) == 0)
3✔
2068
        {
2069
            nSourceSize = sStat.st_size;
3✔
2070
        }
2071
    }
2072

2073
    VSILFILE *fpOut = VSIFOpenEx2L(pszTarget, "wb", TRUE, papszOptions);
2,258✔
2074
    if (!fpOut)
2,258✔
2075
    {
2076
        CPLError(CE_Failure, CPLE_FileIO, "Cannot create %s", pszTarget);
3✔
2077
        return -1;
3✔
2078
    }
2079

2080
    CPLString osMsg;
4,510✔
2081
    if (pszSource)
2,255✔
2082
        osMsg.Printf("Copying of %s", pszSource);
2,253✔
2083
    else
2084
        pszSource = "(unknown filename)";
2✔
2085

2086
    int ret = 0;
2,255✔
2087
    constexpr size_t nBufferSize = 10 * 4096;
2,255✔
2088
    std::vector<GByte> abyBuffer(nBufferSize, 0);
2,255✔
2089
    GUIntBig nOffset = 0;
2,255✔
2090
    while (true)
2091
    {
2092
        const size_t nRead = VSIFReadL(&abyBuffer[0], 1, nBufferSize, fpSource);
2,557✔
2093
        if (nRead < nBufferSize && VSIFErrorL(fpSource))
2,557✔
2094
        {
2095
            CPLError(
7✔
2096
                CE_Failure, CPLE_FileIO,
2097
                "Copying of %s to %s failed: error while reading source file",
2098
                pszSource, pszTarget);
2099
            ret = -1;
7✔
2100
            break;
7✔
2101
        }
2102
        if (nRead > 0)
2,550✔
2103
        {
2104
            const size_t nWritten = VSIFWriteL(&abyBuffer[0], 1, nRead, fpOut);
2,549✔
2105
            if (nWritten != nRead)
2,549✔
2106
            {
2107
                CPLError(CE_Failure, CPLE_FileIO,
20✔
2108
                         "Copying of %s to %s failed: error while writing into "
2109
                         "target file",
2110
                         pszSource, pszTarget);
2111
                ret = -1;
20✔
2112
                break;
20✔
2113
            }
2114
            nOffset += nRead;
2,529✔
2115
            if (pProgressFunc &&
2,578✔
2116
                !pProgressFunc(
98✔
2117
                    nSourceSize == 0 ? 1.0
2118
                    : nSourceSize > 0 &&
49✔
2119
                            nSourceSize != static_cast<vsi_l_offset>(-1)
2120
                        ? double(nOffset) / nSourceSize
98✔
2121
                        : 0.0,
2122
                    !osMsg.empty() ? osMsg.c_str() : nullptr, pProgressData))
49✔
2123
            {
2124
                ret = -1;
1✔
2125
                break;
1✔
2126
            }
2127
        }
2128
        if (nRead < nBufferSize)
2,529✔
2129
        {
2130
            break;
2,227✔
2131
        }
2132
    }
302✔
2133

2134
    if (nSourceSize != static_cast<vsi_l_offset>(-1) && nOffset != nSourceSize)
2,255✔
2135
    {
2136
        CPLError(CE_Failure, CPLE_FileIO,
2✔
2137
                 "Copying of %s to %s failed: %" PRIu64 " bytes were copied "
2138
                 "whereas %" PRIu64 " were expected",
2139
                 pszSource, pszTarget, static_cast<uint64_t>(nOffset),
2140
                 static_cast<uint64_t>(nSourceSize));
2141
        ret = -1;
2✔
2142
    }
2143

2144
    if (VSIFCloseL(fpOut) != 0)
2,255✔
2145
    {
2146
        ret = -1;
1✔
2147
    }
2148

2149
    if (ret != 0)
2,255✔
2150
        VSIUnlink(pszTarget);
29✔
2151

2152
    return ret;
2,255✔
2153
}
2154

2155
/************************************************************************/
2156
/*                       CopyFileRestartable()                          */
2157
/************************************************************************/
2158

2159
int VSIFilesystemHandler::CopyFileRestartable(
2✔
2160
    const char *pszSource, const char *pszTarget,
2161
    const char * /* pszInputPayload */, char **ppszOutputPayload,
2162
    CSLConstList papszOptions, GDALProgressFunc pProgressFunc,
2163
    void *pProgressData)
2164
{
2165
    *ppszOutputPayload = nullptr;
2✔
2166
    return CopyFile(pszSource, pszTarget, nullptr,
2✔
2167
                    static_cast<vsi_l_offset>(-1), papszOptions, pProgressFunc,
2168
                    pProgressData);
2✔
2169
}
2170

2171
/************************************************************************/
2172
/*                               Sync()                                 */
2173
/************************************************************************/
2174

2175
bool VSIFilesystemHandler::Sync(const char *pszSource, const char *pszTarget,
31✔
2176
                                const char *const *papszOptions,
2177
                                GDALProgressFunc pProgressFunc,
2178
                                void *pProgressData, char ***ppapszOutputs)
2179
{
2180
    const char SOURCE_SEP = VSIGetDirectorySeparator(pszSource)[0];
31✔
2181

2182
    if (ppapszOutputs)
31✔
2183
    {
2184
        *ppapszOutputs = nullptr;
×
2185
    }
2186

2187
    VSIStatBufL sSource;
2188
    CPLString osSource(pszSource);
62✔
2189
    CPLString osSourceWithoutSlash(pszSource);
62✔
2190
    if (osSourceWithoutSlash.back() == '/' ||
40✔
2191
        osSourceWithoutSlash.back() == '\\')
9✔
2192
    {
2193
        osSourceWithoutSlash.pop_back();
22✔
2194
    }
2195
    if (VSIStatL(osSourceWithoutSlash, &sSource) < 0)
31✔
2196
    {
2197
        CPLError(CE_Failure, CPLE_FileIO, "%s does not exist", pszSource);
2✔
2198
        return false;
2✔
2199
    }
2200

2201
    if (VSI_ISDIR(sSource.st_mode))
29✔
2202
    {
2203
        std::string osTargetDir(pszTarget);
22✔
2204
        if (osSource.back() != '/' && osSource.back() != '\\')
11✔
2205
        {
2206
            osTargetDir = CPLFormFilenameSafe(
2✔
2207
                osTargetDir.c_str(), CPLGetFilename(pszSource), nullptr);
1✔
2208
        }
2209

2210
        VSIStatBufL sTarget;
2211
        bool ret = true;
11✔
2212
        if (VSIStatL(osTargetDir.c_str(), &sTarget) < 0)
11✔
2213
        {
2214
            if (VSIMkdirRecursive(osTargetDir.c_str(), 0755) < 0)
9✔
2215
            {
2216
                CPLError(CE_Failure, CPLE_FileIO, "Cannot create directory %s",
1✔
2217
                         osTargetDir.c_str());
2218
                return false;
1✔
2219
            }
2220
        }
2221

2222
        if (!CPLFetchBool(papszOptions, "STOP_ON_DIR", false))
10✔
2223
        {
2224
            CPLStringList aosChildOptions(CSLDuplicate(papszOptions));
20✔
2225
            if (!CPLFetchBool(papszOptions, "RECURSIVE", true))
10✔
2226
            {
2227
                aosChildOptions.SetNameValue("RECURSIVE", nullptr);
×
2228
                aosChildOptions.AddString("STOP_ON_DIR=TRUE");
×
2229
            }
2230

2231
            char **papszSrcFiles = VSIReadDir(osSourceWithoutSlash);
10✔
2232
            int nFileCount = 0;
10✔
2233
            for (auto iter = papszSrcFiles; iter && *iter; ++iter)
27✔
2234
            {
2235
                if (strcmp(*iter, ".") != 0 && strcmp(*iter, "..") != 0)
17✔
2236
                {
2237
                    nFileCount++;
17✔
2238
                }
2239
            }
2240
            int iFile = 0;
10✔
2241
            const int nDenom = std::max(1, nFileCount);
10✔
2242
            for (auto iter = papszSrcFiles; iter && *iter; ++iter, ++iFile)
27✔
2243
            {
2244
                if (strcmp(*iter, ".") == 0 || strcmp(*iter, "..") == 0)
17✔
2245
                {
2246
                    continue;
×
2247
                }
2248
                const std::string osSubSource(CPLFormFilenameSafe(
2249
                    osSourceWithoutSlash.c_str(), *iter, nullptr));
17✔
2250
                const std::string osSubTarget(
2251
                    CPLFormFilenameSafe(osTargetDir.c_str(), *iter, nullptr));
17✔
2252
                void *pScaledProgress = GDALCreateScaledProgress(
34✔
2253
                    double(iFile) / nDenom, double(iFile + 1) / nDenom,
17✔
2254
                    pProgressFunc, pProgressData);
2255
                ret = Sync((osSubSource + SOURCE_SEP).c_str(),
17✔
2256
                           osSubTarget.c_str(), aosChildOptions.List(),
17✔
2257
                           GDALScaledProgress, pScaledProgress, nullptr);
17✔
2258
                GDALDestroyScaledProgress(pScaledProgress);
17✔
2259
                if (!ret)
17✔
2260
                {
2261
                    break;
×
2262
                }
2263
            }
2264
            CSLDestroy(papszSrcFiles);
10✔
2265
        }
2266
        return ret;
10✔
2267
    }
2268

2269
    VSIStatBufL sTarget;
2270
    std::string osTarget(pszTarget);
36✔
2271
    if (VSIStatL(osTarget.c_str(), &sTarget) == 0)
18✔
2272
    {
2273
        bool bTargetIsFile = true;
4✔
2274
        if (VSI_ISDIR(sTarget.st_mode))
4✔
2275
        {
2276
            osTarget = CPLFormFilenameSafe(osTarget.c_str(),
4✔
2277
                                           CPLGetFilename(pszSource), nullptr);
2✔
2278
            bTargetIsFile = VSIStatL(osTarget.c_str(), &sTarget) == 0 &&
3✔
2279
                            !CPL_TO_BOOL(VSI_ISDIR(sTarget.st_mode));
1✔
2280
        }
2281
        if (bTargetIsFile)
4✔
2282
        {
2283
            if (sSource.st_size == sTarget.st_size &&
3✔
2284
                sSource.st_mtime == sTarget.st_mtime && sSource.st_mtime != 0)
3✔
2285
            {
2286
                CPLDebug("VSI",
2✔
2287
                         "%s and %s have same size and modification "
2288
                         "date. Skipping copying",
2289
                         osSourceWithoutSlash.c_str(), osTarget.c_str());
2290
                return true;
2✔
2291
            }
2292
        }
2293
    }
2294

2295
    VSILFILE *fpIn = VSIFOpenExL(osSourceWithoutSlash, "rb", TRUE);
16✔
2296
    if (fpIn == nullptr)
16✔
2297
    {
2298
        CPLError(CE_Failure, CPLE_FileIO, "Cannot open %s",
×
2299
                 osSourceWithoutSlash.c_str());
2300
        return false;
×
2301
    }
2302

2303
    VSILFILE *fpOut = VSIFOpenExL(osTarget.c_str(), "wb", TRUE);
16✔
2304
    if (fpOut == nullptr)
16✔
2305
    {
2306
        CPLError(CE_Failure, CPLE_FileIO, "Cannot create %s", osTarget.c_str());
2✔
2307
        VSIFCloseL(fpIn);
2✔
2308
        return false;
2✔
2309
    }
2310

2311
    bool ret = true;
14✔
2312
    constexpr size_t nBufferSize = 10 * 4096;
14✔
2313
    std::vector<GByte> abyBuffer(nBufferSize, 0);
28✔
2314
    GUIntBig nOffset = 0;
14✔
2315
    CPLString osMsg;
14✔
2316
    osMsg.Printf("Copying of %s", osSourceWithoutSlash.c_str());
14✔
2317
    while (true)
2318
    {
2319
        size_t nRead = VSIFReadL(&abyBuffer[0], 1, nBufferSize, fpIn);
17✔
2320
        size_t nWritten = VSIFWriteL(&abyBuffer[0], 1, nRead, fpOut);
17✔
2321
        if (nWritten != nRead)
17✔
2322
        {
2323
            CPLError(CE_Failure, CPLE_FileIO, "Copying of %s to %s failed",
×
2324
                     osSourceWithoutSlash.c_str(), osTarget.c_str());
2325
            ret = false;
×
2326
            break;
×
2327
        }
2328
        nOffset += nRead;
17✔
2329
        if (pProgressFunc && !pProgressFunc(double(nOffset) / sSource.st_size,
17✔
2330
                                            osMsg.c_str(), pProgressData))
2331
        {
2332
            ret = false;
×
2333
            break;
×
2334
        }
2335
        if (nRead < nBufferSize)
17✔
2336
        {
2337
            break;
14✔
2338
        }
2339
    }
3✔
2340

2341
    VSIFCloseL(fpIn);
14✔
2342
    if (VSIFCloseL(fpOut) != 0)
14✔
2343
    {
2344
        ret = false;
×
2345
    }
2346
    return ret;
14✔
2347
}
2348

2349
/************************************************************************/
2350
/*                            VSIDIREntry()                             */
2351
/************************************************************************/
2352

2353
VSIDIREntry::VSIDIREntry()
3,572✔
2354
    : pszName(nullptr), nMode(0), nSize(0), nMTime(0), bModeKnown(false),
2355
      bSizeKnown(false), bMTimeKnown(false), papszExtra(nullptr)
3,572✔
2356
{
2357
}
3,572✔
2358

2359
/************************************************************************/
2360
/*                            VSIDIREntry()                             */
2361
/************************************************************************/
2362

2363
VSIDIREntry::VSIDIREntry(const VSIDIREntry &other)
6✔
2364
    : pszName(VSIStrdup(other.pszName)), nMode(other.nMode), nSize(other.nSize),
6✔
2365
      nMTime(other.nMTime), bModeKnown(other.bModeKnown),
6✔
2366
      bSizeKnown(other.bSizeKnown), bMTimeKnown(other.bMTimeKnown),
6✔
2367
      papszExtra(CSLDuplicate(other.papszExtra))
6✔
2368
{
2369
}
6✔
2370

2371
/************************************************************************/
2372
/*                           ~VSIDIREntry()                             */
2373
/************************************************************************/
2374

2375
VSIDIREntry::~VSIDIREntry()
7,156✔
2376
{
2377
    CPLFree(pszName);
3,578✔
2378
    CSLDestroy(papszExtra);
3,578✔
2379
}
3,578✔
2380

2381
/************************************************************************/
2382
/*                              ~VSIDIR()                               */
2383
/************************************************************************/
2384

2385
VSIDIR::~VSIDIR()
3,180✔
2386
{
2387
}
3,180✔
2388

2389
/************************************************************************/
2390
/*                            VSIDIRGeneric                             */
2391
/************************************************************************/
2392

2393
namespace
2394
{
2395
struct VSIDIRGeneric : public VSIDIR
2396
{
2397
    CPLString osRootPath{};
2398
    CPLString osBasePath{};
2399
    char **papszContent = nullptr;
2400
    int nRecurseDepth = 0;
2401
    int nPos = 0;
2402
    VSIDIREntry entry{};
2403
    std::vector<VSIDIRGeneric *> aoStackSubDir{};
2404
    VSIFilesystemHandler *poFS = nullptr;
2405
    std::string m_osFilterPrefix{};
2406

2407
    explicit VSIDIRGeneric(VSIFilesystemHandler *poFSIn) : poFS(poFSIn)
2,526✔
2408
    {
2409
    }
2,526✔
2410

2411
    ~VSIDIRGeneric();
2412

2413
    const VSIDIREntry *NextDirEntry() override;
2414

2415
    VSIDIRGeneric(const VSIDIRGeneric &) = delete;
2416
    VSIDIRGeneric &operator=(const VSIDIRGeneric &) = delete;
2417
};
2418

2419
/************************************************************************/
2420
/*                         ~VSIDIRGeneric()                             */
2421
/************************************************************************/
2422

2423
VSIDIRGeneric::~VSIDIRGeneric()
7,578✔
2424
{
2425
    while (!aoStackSubDir.empty())
2,531✔
2426
    {
2427
        delete aoStackSubDir.back();
5✔
2428
        aoStackSubDir.pop_back();
5✔
2429
    }
2430
    CSLDestroy(papszContent);
2,526✔
2431
}
5,052✔
2432

2433
}  // namespace
2434

2435
/************************************************************************/
2436
/*                            OpenDir()                                 */
2437
/************************************************************************/
2438

2439
VSIDIR *VSIFilesystemHandler::OpenDir(const char *pszPath, int nRecurseDepth,
2,536✔
2440
                                      const char *const *papszOptions)
2441
{
2442
    char **papszContent = VSIReadDir(pszPath);
2,536✔
2443
    VSIStatBufL sStatL;
2444
    if (papszContent == nullptr &&
2,976✔
2445
        (VSIStatL(pszPath, &sStatL) != 0 || !VSI_ISDIR(sStatL.st_mode)))
440✔
2446
    {
2447
        return nullptr;
10✔
2448
    }
2449
    VSIDIRGeneric *dir = new VSIDIRGeneric(this);
2,526✔
2450
    dir->osRootPath = pszPath;
2,526✔
2451
    if (!dir->osRootPath.empty() &&
5,052✔
2452
        (dir->osRootPath.back() == '/' || dir->osRootPath.back() == '\\'))
2,526✔
2453
        dir->osRootPath.pop_back();
15✔
2454
    dir->nRecurseDepth = nRecurseDepth;
2,526✔
2455
    dir->papszContent = papszContent;
2,526✔
2456
    dir->m_osFilterPrefix = CSLFetchNameValueDef(papszOptions, "PREFIX", "");
2,526✔
2457
    return dir;
2,526✔
2458
}
2459

2460
/************************************************************************/
2461
/*                           NextDirEntry()                             */
2462
/************************************************************************/
2463

2464
const VSIDIREntry *VSIDIRGeneric::NextDirEntry()
507,888✔
2465
{
2466
    const char SEP = VSIGetDirectorySeparator(osRootPath.c_str())[0];
507,888✔
2467

2468
begin:
507,889✔
2469
    if (VSI_ISDIR(entry.nMode) && nRecurseDepth != 0)
507,889✔
2470
    {
2471
        CPLString osCurFile(osRootPath);
1,318✔
2472
        if (!osCurFile.empty())
1,318✔
2473
            osCurFile += SEP;
1,318✔
2474
        osCurFile += entry.pszName;
1,318✔
2475
        auto subdir =
2476
            static_cast<VSIDIRGeneric *>(poFS->VSIFilesystemHandler::OpenDir(
1,318✔
2477
                osCurFile, nRecurseDepth - 1, nullptr));
1,318✔
2478
        if (subdir)
1,318✔
2479
        {
2480
            subdir->osRootPath = osRootPath;
1,318✔
2481
            subdir->osBasePath = entry.pszName;
1,318✔
2482
            subdir->m_osFilterPrefix = m_osFilterPrefix;
1,318✔
2483
            aoStackSubDir.push_back(subdir);
1,318✔
2484
        }
2485
        entry.nMode = 0;
1,318✔
2486
    }
2487

2488
    while (!aoStackSubDir.empty())
509,202✔
2489
    {
2490
        auto l_entry = aoStackSubDir.back()->NextDirEntry();
503,592✔
2491
        if (l_entry)
503,592✔
2492
        {
2493
            return l_entry;
502,279✔
2494
        }
2495
        delete aoStackSubDir.back();
1,313✔
2496
        aoStackSubDir.pop_back();
1,313✔
2497
    }
2498

2499
    if (papszContent == nullptr)
5,610✔
2500
    {
2501
        return nullptr;
430✔
2502
    }
2503

2504
    while (true)
2505
    {
2506
        if (!papszContent[nPos])
5,208✔
2507
        {
2508
            return nullptr;
2,084✔
2509
        }
2510
        // Skip . and ..entries
2511
        if (papszContent[nPos][0] == '.' &&
3,124✔
2512
            (papszContent[nPos][1] == '\0' ||
115✔
2513
             (papszContent[nPos][1] == '.' && papszContent[nPos][2] == '\0')))
115✔
2514
        {
2515
            nPos++;
23✔
2516
        }
2517
        else
2518
        {
2519
            CPLFree(entry.pszName);
3,101✔
2520
            CPLString osName(osBasePath);
3,101✔
2521
            if (!osName.empty())
3,101✔
2522
                osName += SEP;
1,928✔
2523
            osName += papszContent[nPos];
3,101✔
2524
            nPos++;
3,101✔
2525

2526
            entry.pszName = CPLStrdup(osName);
3,101✔
2527
            entry.nMode = 0;
3,101✔
2528
            CPLString osCurFile(osRootPath);
3,101✔
2529
            if (!osCurFile.empty())
3,101✔
2530
                osCurFile += SEP;
3,101✔
2531
            osCurFile += entry.pszName;
3,101✔
2532

2533
            const auto StatFile = [&osCurFile, this]()
6,192✔
2534
            {
2535
                VSIStatBufL sStatL;
2536
                if (VSIStatL(osCurFile, &sStatL) == 0)
3,096✔
2537
                {
2538
                    entry.nMode = sStatL.st_mode;
3,094✔
2539
                    entry.nSize = sStatL.st_size;
3,094✔
2540
                    entry.nMTime = sStatL.st_mtime;
3,094✔
2541
                    entry.bModeKnown = true;
3,094✔
2542
                    entry.bSizeKnown = true;
3,094✔
2543
                    entry.bMTimeKnown = true;
3,094✔
2544
                }
2545
                else
2546
                {
2547
                    entry.nMode = 0;
2✔
2548
                    entry.nSize = 0;
2✔
2549
                    entry.nMTime = 0;
2✔
2550
                    entry.bModeKnown = false;
2✔
2551
                    entry.bSizeKnown = false;
2✔
2552
                    entry.bMTimeKnown = false;
2✔
2553
                }
2554
            };
3,096✔
2555

2556
            if (!m_osFilterPrefix.empty() &&
3,113✔
2557
                m_osFilterPrefix.size() > osName.size())
12✔
2558
            {
2559
                if (STARTS_WITH(m_osFilterPrefix.c_str(), osName.c_str()) &&
6✔
2560
                    m_osFilterPrefix[osName.size()] == SEP)
2✔
2561
                {
2562
                    StatFile();
1✔
2563
                    if (VSI_ISDIR(entry.nMode))
1✔
2564
                    {
2565
                        goto begin;
1✔
2566
                    }
2567
                }
2568
                continue;
3✔
2569
            }
2570
            if (!m_osFilterPrefix.empty() &&
3,105✔
2571
                !STARTS_WITH(osName.c_str(), m_osFilterPrefix.c_str()))
8✔
2572
            {
2573
                continue;
2✔
2574
            }
2575

2576
            StatFile();
3,095✔
2577

2578
            break;
3,095✔
2579
        }
2580
    }
28✔
2581

2582
    return &(entry);
3,095✔
2583
}
2584

2585
/************************************************************************/
2586
/*                           UnlinkBatch()                              */
2587
/************************************************************************/
2588

2589
int *VSIFilesystemHandler::UnlinkBatch(CSLConstList papszFiles)
1✔
2590
{
2591
    int *panRet =
2592
        static_cast<int *>(CPLMalloc(sizeof(int) * CSLCount(papszFiles)));
1✔
2593
    for (int i = 0; papszFiles && papszFiles[i]; ++i)
3✔
2594
    {
2595
        panRet[i] = VSIUnlink(papszFiles[i]) == 0;
2✔
2596
    }
2597
    return panRet;
1✔
2598
}
2599

2600
/************************************************************************/
2601
/*                          RmdirRecursive()                            */
2602
/************************************************************************/
2603

2604
int VSIFilesystemHandler::RmdirRecursive(const char *pszDirname)
29✔
2605
{
2606
    CPLString osDirnameWithoutEndSlash(pszDirname);
58✔
2607
    if (!osDirnameWithoutEndSlash.empty() &&
58✔
2608
        (osDirnameWithoutEndSlash.back() == '/' ||
29✔
2609
         osDirnameWithoutEndSlash.back() == '\\'))
29✔
2610
    {
2611
        osDirnameWithoutEndSlash.pop_back();
×
2612
    }
2613

2614
    const char SEP = VSIGetDirectorySeparator(pszDirname)[0];
29✔
2615

2616
    CPLStringList aosOptions;
58✔
2617
    auto poDir =
2618
        std::unique_ptr<VSIDIR>(OpenDir(pszDirname, -1, aosOptions.List()));
58✔
2619
    if (!poDir)
29✔
2620
        return -1;
8✔
2621
    std::vector<std::string> aosDirs;
42✔
2622
    while (true)
2623
    {
2624
        auto entry = poDir->NextDirEntry();
123✔
2625
        if (!entry)
123✔
2626
            break;
21✔
2627

2628
        CPLString osFilename(osDirnameWithoutEndSlash + SEP + entry->pszName);
204✔
2629
        if ((entry->nMode & S_IFDIR))
102✔
2630
        {
2631
            aosDirs.push_back(std::move(osFilename));
6✔
2632
        }
2633
        else
2634
        {
2635
            if (VSIUnlink(osFilename) != 0)
96✔
2636
                return -1;
×
2637
        }
2638
    }
102✔
2639

2640
    // Sort in reverse order, so that inner-most directories are deleted first
2641
    std::sort(aosDirs.begin(), aosDirs.end(),
21✔
2642
              [](const std::string &a, const std::string &b) { return a > b; });
2✔
2643

2644
    for (const auto &osDir : aosDirs)
27✔
2645
    {
2646
        if (VSIRmdir(osDir.c_str()) != 0)
6✔
2647
            return -1;
×
2648
    }
2649

2650
    return VSIRmdir(pszDirname);
21✔
2651
}
2652

2653
/************************************************************************/
2654
/*                          GetFileMetadata()                           */
2655
/************************************************************************/
2656

2657
char **VSIFilesystemHandler::GetFileMetadata(const char * /* pszFilename*/,
×
2658
                                             const char * /*pszDomain*/,
2659
                                             CSLConstList /*papszOptions*/)
2660
{
2661
    return nullptr;
×
2662
}
2663

2664
/************************************************************************/
2665
/*                          SetFileMetadata()                           */
2666
/************************************************************************/
2667

2668
bool VSIFilesystemHandler::SetFileMetadata(const char * /* pszFilename*/,
×
2669
                                           CSLConstList /* papszMetadata */,
2670
                                           const char * /* pszDomain */,
2671
                                           CSLConstList /* papszOptions */)
2672
{
2673
    CPLError(CE_Failure, CPLE_NotSupported, "SetFileMetadata() not supported");
×
2674
    return false;
×
2675
}
2676

2677
#endif
2678

2679
/************************************************************************/
2680
/*                             VSIFOpenExL()                            */
2681
/************************************************************************/
2682

2683
/**
2684
 * \brief Open/create file.
2685
 *
2686
 * This function opens (or creates) a file with the desired access.
2687
 * Binary access is always implied and
2688
 * the "b" does not need to be included in the pszAccess string.
2689
 *
2690
 * Note that the "VSILFILE *" returned by this function is
2691
 * *NOT* a standard C library FILE *, and cannot be used with any functions
2692
 * other than the "VSI*L" family of functions.  They aren't "real" FILE objects.
2693
 *
2694
 * On windows it is possible to define the configuration option
2695
 * GDAL_FILE_IS_UTF8 to have pszFilename treated as being in the local
2696
 * encoding instead of UTF-8, restoring the pre-1.8.0 behavior of VSIFOpenL().
2697
 *
2698
 * This method goes through the VSIFileHandler virtualization and may
2699
 * work on unusual filesystems such as in memory.
2700
 *
2701
 * Analog of the POSIX fopen() function.
2702
 *
2703
 * @param pszFilename the file to open.  UTF-8 encoded.
2704
 * @param pszAccess access requested (i.e. "r", "r+", "w")
2705
 * @param bSetError flag determining whether or not this open call
2706
 * should set VSIErrors on failure.
2707
 *
2708
 * @return NULL on failure, or the file handle.
2709
 *
2710
 * @since GDAL 2.1
2711
 */
2712

2713
VSILFILE *VSIFOpenExL(const char *pszFilename, const char *pszAccess,
383,480✔
2714
                      int bSetError)
2715

2716
{
2717
    return VSIFOpenEx2L(pszFilename, pszAccess, bSetError, nullptr);
383,480✔
2718
}
2719

2720
/************************************************************************/
2721
/*                            VSIFOpenEx2L()                            */
2722
/************************************************************************/
2723

2724
/**
2725
 * \brief Open/create file.
2726
 *
2727
 * This function opens (or creates) a file with the desired access.
2728
 * Binary access is always implied and
2729
 * the "b" does not need to be included in the pszAccess string.
2730
 *
2731
 * Note that the "VSILFILE *" returned by this function is
2732
 * *NOT* a standard C library FILE *, and cannot be used with any functions
2733
 * other than the "VSI*L" family of functions.  They aren't "real" FILE objects.
2734
 *
2735
 * On windows it is possible to define the configuration option
2736
 * GDAL_FILE_IS_UTF8 to have pszFilename treated as being in the local
2737
 * encoding instead of UTF-8, restoring the pre-1.8.0 behavior of VSIFOpenL().
2738
 *
2739
 * This method goes through the VSIFileHandler virtualization and may
2740
 * work on unusual filesystems such as in memory.
2741
 *
2742
 * The following options are supported:
2743
 * <ul>
2744
 * <li>MIME headers such as Content-Type and Content-Encoding
2745
 * are supported for the /vsis3/, /vsigs/, /vsiaz/, /vsiadls/ file systems.</li>
2746
 * <li>DISABLE_READDIR_ON_OPEN=YES/NO (GDAL >= 3.6) for /vsicurl/ and other
2747
 * network-based file systems. By default, directory file listing is done,
2748
 * unless YES is specified.</li>
2749
 * <li>WRITE_THROUGH=YES (GDAL >= 3.8) for the Windows regular files to
2750
 * set the FILE_FLAG_WRITE_THROUGH flag to the CreateFile() function. In that
2751
 * mode, the data is written to the system cache but is flushed to disk without
2752
 * delay.</li>
2753
 * </ul>
2754
 *
2755
 * Options specifics to /vsis3/, /vsigs/, /vsioss/ and /vsiaz/ in "w" mode:
2756
 * <ul>
2757
 * <li>CHUNK_SIZE=val in MiB. (GDAL >= 3.10) Size of a block. Default is 50 MiB.
2758
 * For /vsis3/, /vsigz/, /vsioss/, it can be up to 5000 MiB.
2759
 * For /vsiaz/, only taken into account when BLOB_TYPE=BLOCK. It can be up to 4000 MiB.
2760
 * </li>
2761
 * </ul>
2762
 *
2763
 * Options specifics to /vsiaz/ in "w" mode:
2764
 * <ul>
2765
 * <li>BLOB_TYPE=APPEND/BLOCK. (GDAL >= 3.10) Type of blob. Defaults to APPEND.
2766
 * Append blocks are limited to 195 GiB
2767
 * (however if the file size is below 4 MiB, a block blob will be created in a
2768
 * single PUT operation)
2769
 * </li>
2770
 * </ul>
2771
 *
2772
 * Analog of the POSIX fopen() function.
2773
 *
2774
 * @param pszFilename the file to open.  UTF-8 encoded.
2775
 * @param pszAccess access requested (i.e. "r", "r+", "w")
2776
 * @param bSetError flag determining whether or not this open call
2777
 * should set VSIErrors on failure.
2778
 * @param papszOptions NULL or NULL-terminated list of strings. The content is
2779
 *                     highly file system dependent.
2780
 *
2781
 *
2782
 * @return NULL on failure, or the file handle.
2783
 *
2784
 * @since GDAL 3.3
2785
 */
2786

2787
VSILFILE *VSIFOpenEx2L(const char *pszFilename, const char *pszAccess,
412,644✔
2788
                       int bSetError, CSLConstList papszOptions)
2789

2790
{
2791
    // Too long filenames can cause excessive memory allocation due to
2792
    // recursion in some filesystem handlers
2793
    constexpr size_t knMaxPath = 8192;
412,644✔
2794
    if (CPLStrnlen(pszFilename, knMaxPath) == knMaxPath)
412,644✔
2795
        return nullptr;
5✔
2796

2797
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
412,688✔
2798

2799
    VSILFILE *fp = poFSHandler->Open(pszFilename, pszAccess,
412,702✔
2800
                                     CPL_TO_BOOL(bSetError), papszOptions);
412,704✔
2801

2802
    VSIDebug4("VSIFOpenEx2L(%s,%s,%d) = %p", pszFilename, pszAccess, bSetError,
2803
              fp);
2804

2805
    return fp;
412,705✔
2806
}
2807

2808
/************************************************************************/
2809
/*                             VSIFCloseL()                             */
2810
/************************************************************************/
2811

2812
/**
2813
 * \fn VSIVirtualHandle::Close()
2814
 * \brief Close file.
2815
 *
2816
 * This function closes the indicated file.
2817
 *
2818
 * This method goes through the VSIFileHandler virtualization and may
2819
 * work on unusual filesystems such as in memory.
2820
 *
2821
 * Analog of the POSIX fclose() function.
2822
 *
2823
 * @return 0 on success or -1 on failure.
2824
 */
2825

2826
/**
2827
 * \brief Close file.
2828
 *
2829
 * This function closes the indicated file.
2830
 *
2831
 * This method goes through the VSIFileHandler virtualization and may
2832
 * work on unusual filesystems such as in memory.
2833
 *
2834
 * Analog of the POSIX fclose() function.
2835
 *
2836
 * @param fp file handle opened with VSIFOpenL().  Passing a nullptr produces
2837
 * undefined behavior.
2838
 *
2839
 * @return 0 on success or -1 on failure.
2840
 */
2841

2842
int VSIFCloseL(VSILFILE *fp)
296,400✔
2843

2844
{
2845
    VSIDebug1("VSIFCloseL(%p)", fp);
2846

2847
    const int nResult = fp->Close();
296,400✔
2848

2849
    delete fp;
296,009✔
2850

2851
    return nResult;
296,014✔
2852
}
2853

2854
/************************************************************************/
2855
/*                             VSIFSeekL()                              */
2856
/************************************************************************/
2857

2858
/**
2859
 * \fn int VSIVirtualHandle::Seek( vsi_l_offset nOffset, int nWhence )
2860
 * \brief Seek to requested offset.
2861
 *
2862
 * Seek to the desired offset (nOffset) in the indicated file.
2863
 *
2864
 * This method goes through the VSIFileHandler virtualization and may
2865
 * work on unusual filesystems such as in memory.
2866
 *
2867
 * Analog of the POSIX fseek() call.
2868
 *
2869
 * Caution: vsi_l_offset is a unsigned type, so SEEK_CUR can only be used
2870
 * for positive seek. If negative seek is needed, use
2871
 * handle->Seek( handle->Tell() + negative_offset, SEEK_SET ).
2872
 *
2873
 * @param nOffset offset in bytes.
2874
 * @param nWhence one of SEEK_SET, SEEK_CUR or SEEK_END.
2875
 *
2876
 * @return 0 on success or -1 one failure.
2877
 */
2878

2879
/**
2880
 * \brief Seek to requested offset.
2881
 *
2882
 * Seek to the desired offset (nOffset) in the indicated file.
2883
 *
2884
 * This method goes through the VSIFileHandler virtualization and may
2885
 * work on unusual filesystems such as in memory.
2886
 *
2887
 * Analog of the POSIX fseek() call.
2888
 *
2889
 * Caution: vsi_l_offset is a unsigned type, so SEEK_CUR can only be used
2890
 * for positive seek. If negative seek is needed, use
2891
 * VSIFSeekL( fp, VSIFTellL(fp) + negative_offset, SEEK_SET ).
2892
 *
2893
 * @param fp file handle opened with VSIFOpenL().
2894
 * @param nOffset offset in bytes.
2895
 * @param nWhence one of SEEK_SET, SEEK_CUR or SEEK_END.
2896
 *
2897
 * @return 0 on success or -1 one failure.
2898
 */
2899

2900
int VSIFSeekL(VSILFILE *fp, vsi_l_offset nOffset, int nWhence)
8,438,320✔
2901

2902
{
2903
    return fp->Seek(nOffset, nWhence);
8,438,320✔
2904
}
2905

2906
/************************************************************************/
2907
/*                             VSIFTellL()                              */
2908
/************************************************************************/
2909

2910
/**
2911
 * \fn VSIVirtualHandle::Tell()
2912
 * \brief Tell current file offset.
2913
 *
2914
 * Returns the current file read/write offset in bytes from the beginning of
2915
 * the file.
2916
 *
2917
 * This method goes through the VSIFileHandler virtualization and may
2918
 * work on unusual filesystems such as in memory.
2919
 *
2920
 * Analog of the POSIX ftell() call.
2921
 *
2922
 * @return file offset in bytes.
2923
 */
2924

2925
/**
2926
 * \brief Tell current file offset.
2927
 *
2928
 * Returns the current file read/write offset in bytes from the beginning of
2929
 * the file.
2930
 *
2931
 * This method goes through the VSIFileHandler virtualization and may
2932
 * work on unusual filesystems such as in memory.
2933
 *
2934
 * Analog of the POSIX ftell() call.
2935
 *
2936
 * @param fp file handle opened with VSIFOpenL().
2937
 *
2938
 * @return file offset in bytes.
2939
 */
2940

2941
vsi_l_offset VSIFTellL(VSILFILE *fp)
5,711,330✔
2942

2943
{
2944
    return fp->Tell();
5,711,330✔
2945
}
2946

2947
/************************************************************************/
2948
/*                             VSIRewindL()                             */
2949
/************************************************************************/
2950

2951
/**
2952
 * \brief Rewind the file pointer to the beginning of the file.
2953
 *
2954
 * This is equivalent to VSIFSeekL( fp, 0, SEEK_SET )
2955
 *
2956
 * Analog of the POSIX rewind() call.
2957
 *
2958
 * @param fp file handle opened with VSIFOpenL().
2959
 */
2960

2961
void VSIRewindL(VSILFILE *fp)
86,220✔
2962

2963
{
2964
    CPL_IGNORE_RET_VAL(VSIFSeekL(fp, 0, SEEK_SET));
86,220✔
2965
}
86,220✔
2966

2967
/************************************************************************/
2968
/*                             VSIFFlushL()                             */
2969
/************************************************************************/
2970

2971
/**
2972
 * \fn VSIVirtualHandle::Flush()
2973
 * \brief Flush pending writes to disk.
2974
 *
2975
 * For files in write or update mode and on filesystem types where it is
2976
 * applicable, all pending output on the file is flushed to the physical disk.
2977
 *
2978
 * This method goes through the VSIFileHandler virtualization and may
2979
 * work on unusual filesystems such as in memory.
2980
 *
2981
 * Analog of the POSIX fflush() call.
2982
 *
2983
 * On Windows regular files, this method does nothing, unless the
2984
 * VSI_FLUSH configuration option is set to YES (and only when the file has
2985
 * *not* been opened with the WRITE_THROUGH option).
2986
 *
2987
 * @return 0 on success or -1 on error.
2988
 */
2989

2990
/**
2991
 * \brief Flush pending writes to disk.
2992
 *
2993
 * For files in write or update mode and on filesystem types where it is
2994
 * applicable, all pending output on the file is flushed to the physical disk.
2995
 *
2996
 * This method goes through the VSIFileHandler virtualization and may
2997
 * work on unusual filesystems such as in memory.
2998
 *
2999
 * Analog of the POSIX fflush() call.
3000
 *
3001
 * On Windows regular files, this method does nothing, unless the
3002
 * VSI_FLUSH configuration option is set to YES (and only when the file has
3003
 * *not* been opened with the WRITE_THROUGH option).
3004
 *
3005
 * @param fp file handle opened with VSIFOpenL().
3006
 *
3007
 * @return 0 on success or -1 on error.
3008
 */
3009

3010
int VSIFFlushL(VSILFILE *fp)
70,382✔
3011

3012
{
3013
    return fp->Flush();
70,382✔
3014
}
3015

3016
/************************************************************************/
3017
/*                             VSIFReadL()                              */
3018
/************************************************************************/
3019

3020
/**
3021
 * \fn VSIVirtualHandle::Read( void *pBuffer, size_t nSize, size_t nCount )
3022
 * \brief Read bytes from file.
3023
 *
3024
 * Reads nCount objects of nSize bytes from the indicated file at the
3025
 * current offset into the indicated buffer.
3026
 *
3027
 * This method goes through the VSIFileHandler virtualization and may
3028
 * work on unusual filesystems such as in memory.
3029
 *
3030
 * Analog of the POSIX fread() call.
3031
 *
3032
 * @param pBuffer the buffer into which the data should be read (at least
3033
 * nCount * nSize bytes in size.
3034
 * @param nSize size of objects to read in bytes.
3035
 * @param nCount number of objects to read.
3036
 *
3037
 * @return number of objects successfully read. If that number is less than
3038
 * nCount, VSIFEofL() or VSIFErrorL() can be used to determine the reason for
3039
 * the short read.
3040
 */
3041

3042
/**
3043
 * \brief Read bytes from file.
3044
 *
3045
 * Reads nCount objects of nSize bytes from the indicated file at the
3046
 * current offset into the indicated buffer.
3047
 *
3048
 * This method goes through the VSIFileHandler virtualization and may
3049
 * work on unusual filesystems such as in memory.
3050
 *
3051
 * Analog of the POSIX fread() call.
3052
 *
3053
 * @param pBuffer the buffer into which the data should be read (at least
3054
 * nCount * nSize bytes in size.
3055
 * @param nSize size of objects to read in bytes.
3056
 * @param nCount number of objects to read.
3057
 * @param fp file handle opened with VSIFOpenL().
3058
 *
3059
 * @return number of objects successfully read. If that number is less than
3060
 * nCount, VSIFEofL() or VSIFErrorL() can be used to determine the reason for
3061
 * the short read.
3062
 */
3063

3064
size_t VSIFReadL(void *pBuffer, size_t nSize, size_t nCount, VSILFILE *fp)
15,485,300✔
3065

3066
{
3067
    return fp->Read(pBuffer, nSize, nCount);
15,485,300✔
3068
}
3069

3070
/************************************************************************/
3071
/*                       VSIFReadMultiRangeL()                          */
3072
/************************************************************************/
3073

3074
/**
3075
 * \fn VSIVirtualHandle::ReadMultiRange( int nRanges, void ** ppData,
3076
 *                                       const vsi_l_offset* panOffsets,
3077
 *                                       const size_t* panSizes )
3078
 * \brief Read several ranges of bytes from file.
3079
 *
3080
 * Reads nRanges objects of panSizes[i] bytes from the indicated file at the
3081
 * offset panOffsets[i] into the buffer ppData[i].
3082
 *
3083
 * Ranges must be sorted in ascending start offset, and must not overlap each
3084
 * other.
3085
 *
3086
 * This method goes through the VSIFileHandler virtualization and may
3087
 * work on unusual filesystems such as in memory or /vsicurl/.
3088
 *
3089
 * @param nRanges number of ranges to read.
3090
 * @param ppData array of nRanges buffer into which the data should be read
3091
 *               (ppData[i] must be at list panSizes[i] bytes).
3092
 * @param panOffsets array of nRanges offsets at which the data should be read.
3093
 * @param panSizes array of nRanges sizes of objects to read (in bytes).
3094
 *
3095
 * @return 0 in case of success, -1 otherwise.
3096
 * @since GDAL 1.9.0
3097
 */
3098

3099
/**
3100
 * \brief Read several ranges of bytes from file.
3101
 *
3102
 * Reads nRanges objects of panSizes[i] bytes from the indicated file at the
3103
 * offset panOffsets[i] into the buffer ppData[i].
3104
 *
3105
 * Ranges must be sorted in ascending start offset, and must not overlap each
3106
 * other.
3107
 *
3108
 * This method goes through the VSIFileHandler virtualization and may
3109
 * work on unusual filesystems such as in memory or /vsicurl/.
3110
 *
3111
 * @param nRanges number of ranges to read.
3112
 * @param ppData array of nRanges buffer into which the data should be read
3113
 *               (ppData[i] must be at list panSizes[i] bytes).
3114
 * @param panOffsets array of nRanges offsets at which the data should be read.
3115
 * @param panSizes array of nRanges sizes of objects to read (in bytes).
3116
 * @param fp file handle opened with VSIFOpenL().
3117
 *
3118
 * @return 0 in case of success, -1 otherwise.
3119
 * @since GDAL 1.9.0
3120
 */
3121

3122
int VSIFReadMultiRangeL(int nRanges, void **ppData,
764✔
3123
                        const vsi_l_offset *panOffsets, const size_t *panSizes,
3124
                        VSILFILE *fp)
3125
{
3126
    return fp->ReadMultiRange(nRanges, ppData, panOffsets, panSizes);
764✔
3127
}
3128

3129
/************************************************************************/
3130
/*                             VSIFWriteL()                             */
3131
/************************************************************************/
3132

3133
/**
3134
 * \fn VSIVirtualHandle::Write( const void *pBuffer,
3135
 *                              size_t nSize, size_t nCount )
3136
 * \brief Write bytes to file.
3137
 *
3138
 * Writes nCount objects of nSize bytes to the indicated file at the
3139
 * current offset into the indicated buffer.
3140
 *
3141
 * This method goes through the VSIFileHandler virtualization and may
3142
 * work on unusual filesystems such as in memory.
3143
 *
3144
 * Analog of the POSIX fwrite() call.
3145
 *
3146
 * @param pBuffer the buffer from which the data should be written (at least
3147
 * nCount * nSize bytes in size.
3148
 * @param nSize size of objects to write in bytes.
3149
 * @param nCount number of objects to write.
3150
 *
3151
 * @return number of objects successfully written.
3152
 */
3153

3154
/**
3155
 * \brief Write bytes to file.
3156
 *
3157
 * Writes nCount objects of nSize bytes to the indicated file at the
3158
 * current offset into the indicated buffer.
3159
 *
3160
 * This method goes through the VSIFileHandler virtualization and may
3161
 * work on unusual filesystems such as in memory.
3162
 *
3163
 * Analog of the POSIX fwrite() call.
3164
 *
3165
 * @param pBuffer the buffer from which the data should be written (at least
3166
 * nCount * nSize bytes in size.
3167
 * @param nSize size of objects to write in bytes.
3168
 * @param nCount number of objects to write.
3169
 * @param fp file handle opened with VSIFOpenL().
3170
 *
3171
 * @return number of objects successfully written.
3172
 */
3173

3174
size_t VSIFWriteL(const void *pBuffer, size_t nSize, size_t nCount,
4,305,330✔
3175
                  VSILFILE *fp)
3176

3177
{
3178
    return fp->Write(pBuffer, nSize, nCount);
4,305,330✔
3179
}
3180

3181
/************************************************************************/
3182
/*                              VSIFEofL()                              */
3183
/************************************************************************/
3184

3185
/**
3186
 * \fn VSIVirtualHandle::Eof()
3187
 * \brief Test for end of file.
3188
 *
3189
 * Returns TRUE (non-zero) if an end-of-file condition occurred during the
3190
 * previous read operation. The end-of-file flag is cleared by a successful
3191
 * VSIFSeekL() call, or a call to VSIFClearErrL().
3192
 *
3193
 * This method goes through the VSIFileHandler virtualization and may
3194
 * work on unusual filesystems such as in memory.
3195
 *
3196
 * Analog of the POSIX feof() call.
3197
 *
3198
 * @return TRUE if at EOF, else FALSE.
3199
 */
3200

3201
/**
3202
 * \brief Test for end of file.
3203
 *
3204
 * Returns TRUE (non-zero) if an end-of-file condition occurred during the
3205
 * previous read operation. The end-of-file flag is cleared by a successful
3206
 * VSIFSeekL() call, or a call to VSIFClearErrL().
3207
 *
3208
 * This method goes through the VSIFileHandler virtualization and may
3209
 * work on unusual filesystems such as in memory.
3210
 *
3211
 * Analog of the POSIX feof() call.
3212
 *
3213
 * @param fp file handle opened with VSIFOpenL().
3214
 *
3215
 * @return TRUE if at EOF, else FALSE.
3216
 */
3217

3218
int VSIFEofL(VSILFILE *fp)
281,321✔
3219

3220
{
3221
    return fp->Eof();
281,321✔
3222
}
3223

3224
/************************************************************************/
3225
/*                            VSIFErrorL()                              */
3226
/************************************************************************/
3227

3228
/**
3229
 * \fn VSIVirtualHandle::Error()
3230
 * \brief Test the error indicator.
3231
 *
3232
 * Returns TRUE (non-zero) if an error condition occurred during the
3233
 * previous read operation. The error indicator is cleared by a call to
3234
 * VSIFClearErrL(). Note that a end-of-file situation, reported by VSIFEofL(),
3235
 * is *not* an error reported by VSIFErrorL().
3236
 *
3237
 * This method goes through the VSIFileHandler virtualization and may
3238
 * work on unusual filesystems such as in memory.
3239
 *
3240
 * Analog of the POSIX ferror() call.
3241
 *
3242
 * @return TRUE if the error indicator is set, else FALSE.
3243
 * @since 3.10
3244
 */
3245

3246
/**
3247
 * \brief Test the error indicator.
3248
 *
3249
 * Returns TRUE (non-zero) if an error condition occurred during the
3250
 * previous read operation. The error indicator is cleared by a call to
3251
 * VSIFClearErrL(). Note that a end-of-file situation, reported by VSIFEofL(),
3252
 * is *not* an error reported by VSIFErrorL().
3253
 *
3254
 * This method goes through the VSIFileHandler virtualization and may
3255
 * work on unusual filesystems such as in memory.
3256
 *
3257
 * Analog of the POSIX feof() call.
3258
 *
3259
 * @param fp file handle opened with VSIFOpenL().
3260
 *
3261
 * @return TRUE if the error indicator is set, else FALSE.
3262
 * @since 3.10
3263
 */
3264

3265
int VSIFErrorL(VSILFILE *fp)
90,498✔
3266

3267
{
3268
    return fp->Error();
90,498✔
3269
}
3270

3271
/************************************************************************/
3272
/*                           VSIFClearErrL()                            */
3273
/************************************************************************/
3274

3275
/**
3276
 * \fn VSIVirtualHandle::ClearErr()
3277
 * \brief Reset the error and end-of-file indicators.
3278
 *
3279
 * This method goes through the VSIFileHandler virtualization and may
3280
 * work on unusual filesystems such as in memory.
3281
 *
3282
 * Analog of the POSIX clearerr() call.
3283
 *
3284
 * @since 3.10
3285
 */
3286

3287
/**
3288
 * \brief Reset the error and end-of-file indicators.
3289
 *
3290
 * This method goes through the VSIFileHandler virtualization and may
3291
 * work on unusual filesystems such as in memory.
3292
 *
3293
 * Analog of the POSIX clearerr() call.
3294
 *
3295
 * @param fp file handle opened with VSIFOpenL().
3296
 *
3297
 * @since 3.10
3298
 */
3299

3300
void VSIFClearErrL(VSILFILE *fp)
31,228✔
3301

3302
{
3303
    fp->ClearErr();
31,228✔
3304
}
31,228✔
3305

3306
/************************************************************************/
3307
/*                            VSIFTruncateL()                           */
3308
/************************************************************************/
3309

3310
/**
3311
 * \fn VSIVirtualHandle::Truncate( vsi_l_offset nNewSize )
3312
 * \brief Truncate/expand the file to the specified size
3313

3314
 * This method goes through the VSIFileHandler virtualization and may
3315
 * work on unusual filesystems such as in memory.
3316
 *
3317
 * Analog of the POSIX ftruncate() call.
3318
 *
3319
 * @param nNewSize new size in bytes.
3320
 *
3321
 * @return 0 on success
3322
 * @since GDAL 1.9.0
3323
 */
3324

3325
/**
3326
 * \brief Truncate/expand the file to the specified size
3327

3328
 * This method goes through the VSIFileHandler virtualization and may
3329
 * work on unusual filesystems such as in memory.
3330
 *
3331
 * Analog of the POSIX ftruncate() call.
3332
 *
3333
 * @param fp file handle opened with VSIFOpenL().
3334
 * @param nNewSize new size in bytes.
3335
 *
3336
 * @return 0 on success
3337
 * @since GDAL 1.9.0
3338
 */
3339

3340
int VSIFTruncateL(VSILFILE *fp, vsi_l_offset nNewSize)
1,293✔
3341

3342
{
3343
    return fp->Truncate(nNewSize);
1,293✔
3344
}
3345

3346
/************************************************************************/
3347
/*                            VSIFPrintfL()                             */
3348
/************************************************************************/
3349

3350
/**
3351
 * \brief Formatted write to file.
3352
 *
3353
 * Provides fprintf() style formatted output to a VSI*L file.  This formats
3354
 * an internal buffer which is written using VSIFWriteL().
3355
 *
3356
 * Analog of the POSIX fprintf() call.
3357
 *
3358
 * @param fp file handle opened with VSIFOpenL().
3359
 * @param pszFormat the printf() style format string.
3360
 *
3361
 * @return the number of bytes written or -1 on an error.
3362
 */
3363

3364
int VSIFPrintfL(VSILFILE *fp, CPL_FORMAT_STRING(const char *pszFormat), ...)
82,793✔
3365

3366
{
3367
    va_list args;
3368

3369
    va_start(args, pszFormat);
82,793✔
3370
    CPLString osResult;
82,793✔
3371
    osResult.vPrintf(pszFormat, args);
82,793✔
3372
    va_end(args);
82,793✔
3373

3374
    return static_cast<int>(
3375
        VSIFWriteL(osResult.c_str(), 1, osResult.length(), fp));
165,586✔
3376
}
3377

3378
/************************************************************************/
3379
/*                 VSIVirtualHandle::Printf()                           */
3380
/************************************************************************/
3381

3382
/**
3383
 * \brief Formatted write to file.
3384
 *
3385
 * Provides fprintf() style formatted output to a VSI*L file.  This formats
3386
 * an internal buffer which is written using VSIFWriteL().
3387
 *
3388
 * Analog of the POSIX fprintf() call.
3389
 *
3390
 * @param pszFormat the printf() style format string.
3391
 *
3392
 * @return the number of bytes written or -1 on an error.
3393
 */
3394

3395
int VSIVirtualHandle::Printf(CPL_FORMAT_STRING(const char *pszFormat), ...)
770✔
3396
{
3397
    va_list args;
3398

3399
    va_start(args, pszFormat);
770✔
3400
    CPLString osResult;
770✔
3401
    osResult.vPrintf(pszFormat, args);
770✔
3402
    va_end(args);
770✔
3403

3404
    return static_cast<int>(Write(osResult.c_str(), 1, osResult.length()));
1,540✔
3405
}
3406

3407
/************************************************************************/
3408
/*                              VSIFPutcL()                              */
3409
/************************************************************************/
3410

3411
// TODO: should we put in conformance with POSIX regarding the return
3412
// value. As of today (2015-08-29), no code in GDAL sources actually
3413
// check the return value.
3414

3415
/**
3416
 * \brief Write a single byte to the file
3417
 *
3418
 * Writes the character nChar, cast to an unsigned char, to file.
3419
 *
3420
 * Almost an analog of the POSIX  fputc() call, except that it returns
3421
 * the  number of  character  written (1  or 0),  and  not the  (cast)
3422
 * character itself or EOF.
3423
 *
3424
 * @param nChar character to write.
3425
 * @param fp file handle opened with VSIFOpenL().
3426
 *
3427
 * @return 1 in case of success, 0 on error.
3428
 */
3429

3430
int VSIFPutcL(int nChar, VSILFILE *fp)
464✔
3431

3432
{
3433
    const unsigned char cChar = static_cast<unsigned char>(nChar);
464✔
3434
    return static_cast<int>(VSIFWriteL(&cChar, 1, 1, fp));
464✔
3435
}
3436

3437
/************************************************************************/
3438
/*                        VSIFGetRangeStatusL()                        */
3439
/************************************************************************/
3440

3441
/**
3442
 * \fn VSIVirtualHandle::GetRangeStatus( vsi_l_offset nOffset,
3443
 *                                       vsi_l_offset nLength )
3444
 * \brief Return if a given file range contains data or holes filled with zeroes
3445
 *
3446
 * This uses the filesystem capabilities of querying which regions of
3447
 * a sparse file are allocated or not. This is currently only
3448
 * implemented for Linux (and no other Unix derivatives) and Windows.
3449
 *
3450
 * Note: A return of VSI_RANGE_STATUS_DATA doesn't exclude that the
3451
 * extent is filled with zeroes! It must be interpreted as "may
3452
 * contain non-zero data".
3453
 *
3454
 * @param nOffset offset of the start of the extent.
3455
 * @param nLength extent length.
3456
 *
3457
 * @return extent status: VSI_RANGE_STATUS_UNKNOWN, VSI_RANGE_STATUS_DATA or
3458
 *         VSI_RANGE_STATUS_HOLE
3459
 * @since GDAL 2.2
3460
 */
3461

3462
/**
3463
 * \brief Return if a given file range contains data or holes filled with zeroes
3464
 *
3465
 * This uses the filesystem capabilities of querying which regions of
3466
 * a sparse file are allocated or not. This is currently only
3467
 * implemented for Linux (and no other Unix derivatives) and Windows.
3468
 *
3469
 * Note: A return of VSI_RANGE_STATUS_DATA doesn't exclude that the
3470
 * extent is filled with zeroes! It must be interpreted as "may
3471
 * contain non-zero data".
3472
 *
3473
 * @param fp file handle opened with VSIFOpenL().
3474
 * @param nOffset offset of the start of the extent.
3475
 * @param nLength extent length.
3476
 *
3477
 * @return extent status: VSI_RANGE_STATUS_UNKNOWN, VSI_RANGE_STATUS_DATA or
3478
 *         VSI_RANGE_STATUS_HOLE
3479
 * @since GDAL 2.2
3480
 */
3481

3482
VSIRangeStatus VSIFGetRangeStatusL(VSILFILE *fp, vsi_l_offset nOffset,
650✔
3483
                                   vsi_l_offset nLength)
3484
{
3485
    return fp->GetRangeStatus(nOffset, nLength);
650✔
3486
}
3487

3488
/************************************************************************/
3489
/*                           VSIIngestFile()                            */
3490
/************************************************************************/
3491

3492
/**
3493
 * \brief Ingest a file into memory.
3494
 *
3495
 * Read the whole content of a file into a memory buffer.
3496
 *
3497
 * Either fp or pszFilename can be NULL, but not both at the same time.
3498
 *
3499
 * If fp is passed non-NULL, it is the responsibility of the caller to
3500
 * close it.
3501
 *
3502
 * If non-NULL, the returned buffer is guaranteed to be NUL-terminated.
3503
 *
3504
 * @param fp file handle opened with VSIFOpenL().
3505
 * @param pszFilename filename.
3506
 * @param ppabyRet pointer to the target buffer. *ppabyRet must be freed with
3507
 *                 VSIFree()
3508
 * @param pnSize pointer to variable to store the file size. May be NULL.
3509
 * @param nMaxSize maximum size of file allowed. If no limit, set to a negative
3510
 *                 value.
3511
 *
3512
 * @return TRUE in case of success.
3513
 *
3514
 * @since GDAL 1.11
3515
 */
3516

3517
int VSIIngestFile(VSILFILE *fp, const char *pszFilename, GByte **ppabyRet,
12,553✔
3518
                  vsi_l_offset *pnSize, GIntBig nMaxSize)
3519
{
3520
    if (fp == nullptr && pszFilename == nullptr)
12,553✔
3521
        return FALSE;
×
3522
    if (ppabyRet == nullptr)
12,553✔
3523
        return FALSE;
×
3524

3525
    *ppabyRet = nullptr;
12,553✔
3526
    if (pnSize != nullptr)
12,553✔
3527
        *pnSize = 0;
5,790✔
3528

3529
    bool bFreeFP = false;
12,553✔
3530
    if (nullptr == fp)
12,553✔
3531
    {
3532
        fp = VSIFOpenL(pszFilename, "rb");
11,322✔
3533
        if (nullptr == fp)
11,322✔
3534
        {
3535
            CPLError(CE_Failure, CPLE_FileIO, "Cannot open file '%s'",
917✔
3536
                     pszFilename);
3537
            return FALSE;
917✔
3538
        }
3539
        bFreeFP = true;
10,405✔
3540
    }
3541
    else
3542
    {
3543
        if (VSIFSeekL(fp, 0, SEEK_SET) != 0)
1,231✔
3544
            return FALSE;
×
3545
    }
3546

3547
    vsi_l_offset nDataLen = 0;
11,636✔
3548

3549
    if (pszFilename == nullptr || strcmp(pszFilename, "/vsistdin/") == 0)
11,636✔
3550
    {
3551
        vsi_l_offset nDataAlloc = 0;
100✔
3552
        if (VSIFSeekL(fp, 0, SEEK_SET) != 0)
100✔
3553
        {
3554
            if (bFreeFP)
×
3555
                CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
×
3556
            return FALSE;
×
3557
        }
3558
        while (true)
3559
        {
3560
            if (nDataLen + 8192 + 1 > nDataAlloc)
507✔
3561
            {
3562
                nDataAlloc = (nDataAlloc * 4) / 3 + 8192 + 1;
233✔
3563
                if (nDataAlloc >
3564
                    static_cast<vsi_l_offset>(static_cast<size_t>(nDataAlloc)))
3565
                {
3566
                    CPLError(CE_Failure, CPLE_AppDefined,
3567
                             "Input file too large to be opened");
3568
                    VSIFree(*ppabyRet);
3569
                    *ppabyRet = nullptr;
3570
                    if (bFreeFP)
3571
                        CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
3572
                    return FALSE;
3573
                }
3574
                GByte *pabyNew = static_cast<GByte *>(
3575
                    VSIRealloc(*ppabyRet, static_cast<size_t>(nDataAlloc)));
233✔
3576
                if (pabyNew == nullptr)
233✔
3577
                {
3578
                    CPLError(CE_Failure, CPLE_OutOfMemory,
×
3579
                             "Cannot allocate " CPL_FRMT_GIB " bytes",
3580
                             nDataAlloc);
3581
                    VSIFree(*ppabyRet);
×
3582
                    *ppabyRet = nullptr;
×
3583
                    if (bFreeFP)
×
3584
                        CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
×
3585
                    return FALSE;
×
3586
                }
3587
                *ppabyRet = pabyNew;
233✔
3588
            }
3589
            const int nRead =
3590
                static_cast<int>(VSIFReadL(*ppabyRet + nDataLen, 1, 8192, fp));
507✔
3591
            nDataLen += nRead;
507✔
3592

3593
            if (nMaxSize >= 0 && nDataLen > static_cast<vsi_l_offset>(nMaxSize))
507✔
3594
            {
3595
                CPLError(CE_Failure, CPLE_AppDefined,
×
3596
                         "Input file too large to be opened");
3597
                VSIFree(*ppabyRet);
×
3598
                *ppabyRet = nullptr;
×
3599
                if (pnSize != nullptr)
×
3600
                    *pnSize = 0;
×
3601
                if (bFreeFP)
×
3602
                    CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
×
3603
                return FALSE;
×
3604
            }
3605

3606
            if (pnSize != nullptr)
507✔
3607
                *pnSize += nRead;
245✔
3608
            (*ppabyRet)[nDataLen] = '\0';
507✔
3609
            if (nRead == 0)
507✔
3610
                break;
100✔
3611
        }
507✔
3612
    }
3613
    else
3614
    {
3615
        if (VSIFSeekL(fp, 0, SEEK_END) != 0)
11,536✔
3616
        {
3617
            if (bFreeFP)
×
3618
                CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
×
3619
            return FALSE;
×
3620
        }
3621
        nDataLen = VSIFTellL(fp);
11,536✔
3622

3623
        // With "large" VSI I/O API we can read data chunks larger than
3624
        // VSIMalloc could allocate. Catch it here.
3625
        if (nDataLen !=
11,536✔
3626
                static_cast<vsi_l_offset>(static_cast<size_t>(nDataLen)) ||
3627
            nDataLen + 1 < nDataLen
3628
            // opening a directory returns nDataLen = INT_MAX (on 32bit) or
3629
            // INT64_MAX (on 64bit)
3630
            || nDataLen + 1 > std::numeric_limits<size_t>::max() / 2 ||
17,846✔
3631
            (nMaxSize >= 0 && nDataLen > static_cast<vsi_l_offset>(nMaxSize)))
6,310✔
3632
        {
3633
            CPLError(CE_Failure, CPLE_AppDefined,
×
3634
                     "Input file too large to be opened");
3635
            if (bFreeFP)
×
3636
                CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
×
3637
            return FALSE;
×
3638
        }
3639

3640
        if (VSIFSeekL(fp, 0, SEEK_SET) != 0)
11,536✔
3641
        {
3642
            if (bFreeFP)
×
3643
                CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
×
3644
            return FALSE;
×
3645
        }
3646

3647
        *ppabyRet =
11,536✔
3648
            static_cast<GByte *>(VSIMalloc(static_cast<size_t>(nDataLen + 1)));
11,536✔
3649
        if (nullptr == *ppabyRet)
11,536✔
3650
        {
3651
            CPLError(CE_Failure, CPLE_OutOfMemory,
×
3652
                     "Cannot allocate " CPL_FRMT_GIB " bytes", nDataLen + 1);
3653
            if (bFreeFP)
×
3654
                CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
×
3655
            return FALSE;
×
3656
        }
3657

3658
        (*ppabyRet)[nDataLen] = '\0';
11,536✔
3659
        if (nDataLen !=
11,536✔
3660
            VSIFReadL(*ppabyRet, 1, static_cast<size_t>(nDataLen), fp))
11,536✔
3661
        {
3662
            CPLError(CE_Failure, CPLE_FileIO,
×
3663
                     "Cannot read " CPL_FRMT_GIB " bytes", nDataLen);
3664
            VSIFree(*ppabyRet);
×
3665
            *ppabyRet = nullptr;
×
3666
            if (bFreeFP)
×
3667
                CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
×
3668
            return FALSE;
×
3669
        }
3670
        if (pnSize != nullptr)
11,536✔
3671
            *pnSize = nDataLen;
4,884✔
3672
    }
3673
    if (bFreeFP)
11,636✔
3674
        CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
10,405✔
3675
    return TRUE;
11,636✔
3676
}
3677

3678
/************************************************************************/
3679
/*                         VSIOverwriteFile()                           */
3680
/************************************************************************/
3681

3682
/**
3683
 * \brief Overwrite an existing file with content from another one
3684
 *
3685
 * @param fpTarget file handle opened with VSIFOpenL() with "rb+" flag.
3686
 * @param pszSourceFilename source filename
3687
 *
3688
 * @return TRUE in case of success.
3689
 *
3690
 * @since GDAL 3.1
3691
 */
3692

3693
int VSIOverwriteFile(VSILFILE *fpTarget, const char *pszSourceFilename)
4✔
3694
{
3695
    VSILFILE *fpSource = VSIFOpenL(pszSourceFilename, "rb");
4✔
3696
    if (fpSource == nullptr)
4✔
3697
    {
3698
        CPLError(CE_Failure, CPLE_FileIO, "Cannot open %s", pszSourceFilename);
×
3699
        return false;
×
3700
    }
3701

3702
    const size_t nBufferSize = 4096;
4✔
3703
    void *pBuffer = CPLMalloc(nBufferSize);
4✔
3704
    VSIFSeekL(fpTarget, 0, SEEK_SET);
4✔
3705
    bool bRet = true;
4✔
3706
    while (true)
3707
    {
3708
        size_t nRead = VSIFReadL(pBuffer, 1, nBufferSize, fpSource);
4✔
3709
        size_t nWritten = VSIFWriteL(pBuffer, 1, nRead, fpTarget);
4✔
3710
        if (nWritten != nRead)
4✔
3711
        {
3712
            bRet = false;
×
3713
            break;
×
3714
        }
3715
        if (nRead < nBufferSize)
4✔
3716
            break;
4✔
3717
    }
×
3718

3719
    if (bRet)
4✔
3720
    {
3721
        bRet = VSIFTruncateL(fpTarget, VSIFTellL(fpTarget)) == 0;
4✔
3722
        if (!bRet)
4✔
3723
        {
3724
            CPLError(CE_Failure, CPLE_FileIO, "Truncation failed");
×
3725
        }
3726
    }
3727

3728
    CPLFree(pBuffer);
4✔
3729
    VSIFCloseL(fpSource);
4✔
3730
    return bRet;
4✔
3731
}
3732

3733
/************************************************************************/
3734
/*                        VSIFGetNativeFileDescriptorL()                */
3735
/************************************************************************/
3736

3737
/**
3738
 * \fn VSIVirtualHandle::GetNativeFileDescriptor()
3739
 * \brief Returns the "native" file descriptor for the virtual handle.
3740
 *
3741
 * This will only return a non-NULL value for "real" files handled by the
3742
 * operating system (to be opposed to GDAL virtual file systems).
3743
 *
3744
 * On POSIX systems, this will be a integer value ("fd") cast as a void*.
3745
 * On Windows systems, this will be the HANDLE.
3746
 *
3747
 * @return the native file descriptor, or NULL.
3748
 */
3749

3750
/**
3751
 * \brief Returns the "native" file descriptor for the virtual handle.
3752
 *
3753
 * This will only return a non-NULL value for "real" files handled by the
3754
 * operating system (to be opposed to GDAL virtual file systems).
3755
 *
3756
 * On POSIX systems, this will be a integer value ("fd") cast as a void*.
3757
 * On Windows systems, this will be the HANDLE.
3758
 *
3759
 * @param fp file handle opened with VSIFOpenL().
3760
 *
3761
 * @return the native file descriptor, or NULL.
3762
 */
3763

3764
void *VSIFGetNativeFileDescriptorL(VSILFILE *fp)
64✔
3765
{
3766
    return fp->GetNativeFileDescriptor();
64✔
3767
}
3768

3769
/************************************************************************/
3770
/*                      VSIGetDiskFreeSpace()                           */
3771
/************************************************************************/
3772

3773
/**
3774
 * \brief Return free disk space available on the filesystem.
3775
 *
3776
 * This function returns the free disk space available on the filesystem.
3777
 *
3778
 * @param pszDirname a directory of the filesystem to query.
3779
 * @return The free space in bytes. Or -1 in case of error.
3780
 * @since GDAL 2.1
3781
 */
3782

3783
GIntBig VSIGetDiskFreeSpace(const char *pszDirname)
74✔
3784
{
3785
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszDirname);
74✔
3786

3787
    return poFSHandler->GetDiskFreeSpace(pszDirname);
74✔
3788
}
3789

3790
/************************************************************************/
3791
/*                    VSIGetFileSystemsPrefixes()                       */
3792
/************************************************************************/
3793

3794
/**
3795
 * \brief Return the list of prefixes for virtual file system handlers
3796
 * currently registered.
3797
 *
3798
 * Typically: "", "/vsimem/", "/vsicurl/", etc
3799
 *
3800
 * @return a NULL terminated list of prefixes. Must be freed with CSLDestroy()
3801
 * @since GDAL 2.3
3802
 */
3803

3804
char **VSIGetFileSystemsPrefixes(void)
9✔
3805
{
3806
    return VSIFileManager::GetPrefixes();
9✔
3807
}
3808

3809
/************************************************************************/
3810
/*                     VSIGetFileSystemOptions()                        */
3811
/************************************************************************/
3812

3813
/**
3814
 * \brief Return the list of options associated with a virtual file system
3815
 * handler as a serialized XML string.
3816
 *
3817
 * Those options may be set as configuration options with CPLSetConfigOption().
3818
 *
3819
 * @param pszFilename a filename, or prefix of a virtual file system handler.
3820
 * @return a string, which must not be freed, or NULL if no options is declared.
3821
 * @since GDAL 2.3
3822
 */
3823

3824
const char *VSIGetFileSystemOptions(const char *pszFilename)
36✔
3825
{
3826
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
36✔
3827

3828
    return poFSHandler->GetOptions();
36✔
3829
}
3830

3831
/************************************************************************/
3832
/*                       VSISetPathSpecificOption()                     */
3833
/************************************************************************/
3834

3835
static std::mutex oMutexPathSpecificOptions;
3836

3837
// key is a path prefix
3838
// value is a map of key, value pair
3839
static std::map<std::string, std::map<std::string, std::string>>
3840
    oMapPathSpecificOptions;
3841

3842
/**
3843
 * \brief Set a credential (or more generally an option related to a
3844
 *        virtual file system) for a given path prefix.
3845
 * @deprecated in GDAL 3.6 for the better named VSISetPathSpecificOption()
3846
 * @see VSISetPathSpecificOption()
3847
 */
3848
void VSISetCredential(const char *pszPathPrefix, const char *pszKey,
×
3849
                      const char *pszValue)
3850
{
3851
    VSISetPathSpecificOption(pszPathPrefix, pszKey, pszValue);
×
3852
}
×
3853

3854
/**
3855
 * \brief Set a path specific option for a given path prefix.
3856
 *
3857
 * Such option is typically, but not limited to, a credential setting for a
3858
 * virtual file system.
3859
 *
3860
 * That option may also be set as a configuration option with
3861
 * CPLSetConfigOption(), but this function allows to specify them with a
3862
 * granularity at the level of a file path, which makes it easier if using the
3863
 * same virtual file system but with different credentials (e.g. different
3864
 * credentials for bucket "/vsis3/foo" and "/vsis3/bar")
3865
 *
3866
 * This is supported for the following virtual file systems:
3867
 * /vsis3/, /vsigs/, /vsiaz/, /vsioss/, /vsiwebhdfs, /vsiswift.
3868
 * Note: setting them for a path starting with /vsiXXX/ will also apply for
3869
 * /vsiXXX_streaming/ requests.
3870
 *
3871
 * Note that no particular care is taken to store them in RAM in a secure way.
3872
 * So they might accidentally hit persistent storage if swapping occurs, or
3873
 * someone with access to the memory allocated by the process may be able to
3874
 * read them.
3875
 *
3876
 * @param pszPathPrefix a path prefix of a virtual file system handler.
3877
 *                      Typically of the form "/vsiXXX/bucket". Must NOT be
3878
 * NULL. Should not include trailing slashes.
3879
 * @param pszKey        Option name. Must NOT be NULL.
3880
 * @param pszValue      Option value. May be NULL to erase it.
3881
 *
3882
 * @since GDAL 3.6
3883
 */
3884

3885
void VSISetPathSpecificOption(const char *pszPathPrefix, const char *pszKey,
89✔
3886
                              const char *pszValue)
3887
{
3888
    std::lock_guard<std::mutex> oLock(oMutexPathSpecificOptions);
178✔
3889
    auto oIter = oMapPathSpecificOptions.find(pszPathPrefix);
89✔
3890
    CPLString osKey(pszKey);
178✔
3891
    osKey.toupper();
89✔
3892
    if (oIter == oMapPathSpecificOptions.end())
89✔
3893
    {
3894
        if (pszValue != nullptr)
23✔
3895
            oMapPathSpecificOptions[pszPathPrefix][osKey] = pszValue;
23✔
3896
    }
3897
    else if (pszValue != nullptr)
66✔
3898
        oIter->second[osKey] = pszValue;
58✔
3899
    else
3900
        oIter->second.erase(osKey);
8✔
3901
}
89✔
3902

3903
/************************************************************************/
3904
/*                       VSIClearPathSpecificOptions()                  */
3905
/************************************************************************/
3906

3907
/**
3908
 * \brief Clear path specific options set with VSISetPathSpecificOption()
3909
 * @deprecated in GDAL 3.6 for the better named VSIClearPathSpecificOptions()
3910
 * @see VSIClearPathSpecificOptions()
3911
 */
3912
void VSIClearCredentials(const char *pszPathPrefix)
×
3913
{
3914
    return VSIClearPathSpecificOptions(pszPathPrefix);
×
3915
}
3916

3917
/**
3918
 * \brief Clear path specific options set with VSISetPathSpecificOption()
3919
 *
3920
 * Note that no particular care is taken to remove them from RAM in a secure
3921
 * way.
3922
 *
3923
 * @param pszPathPrefix If set to NULL, all path specific options are cleared.
3924
 *                      If set to not-NULL, only those set with
3925
 *                      VSISetPathSpecificOption(pszPathPrefix, ...) will be
3926
 * cleared.
3927
 *
3928
 * @since GDAL 3.6
3929
 */
3930
void VSIClearPathSpecificOptions(const char *pszPathPrefix)
18✔
3931
{
3932
    std::lock_guard<std::mutex> oLock(oMutexPathSpecificOptions);
36✔
3933
    if (pszPathPrefix == nullptr)
18✔
3934
    {
3935
        oMapPathSpecificOptions.clear();
2✔
3936
    }
3937
    else
3938
    {
3939
        oMapPathSpecificOptions.erase(pszPathPrefix);
16✔
3940
    }
3941
}
18✔
3942

3943
/************************************************************************/
3944
/*                        VSIGetPathSpecificOption()                    */
3945
/************************************************************************/
3946

3947
/**
3948
 * \brief Get the value of a credential (or more generally an option related to
3949
 * a virtual file system) for a given path.
3950
 * @deprecated in GDAL 3.6 for the better named VSIGetPathSpecificOption()
3951
 * @see VSIGetPathSpecificOption()
3952
 */
3953
const char *VSIGetCredential(const char *pszPath, const char *pszKey,
×
3954
                             const char *pszDefault)
3955
{
3956
    return VSIGetPathSpecificOption(pszPath, pszKey, pszDefault);
×
3957
}
3958

3959
/**
3960
 * \brief Get the value a path specific option.
3961
 *
3962
 * Such option is typically, but not limited to, a credential setting for a
3963
 * virtual file system.
3964
 *
3965
 * If no match occurs, CPLGetConfigOption(pszKey, pszDefault) is returned.
3966
 *
3967
 * Mostly to be used by virtual file system implementations.
3968
 *
3969
 * @since GDAL 3.6
3970
 * @see VSISetPathSpecificOption()
3971
 */
3972
const char *VSIGetPathSpecificOption(const char *pszPath, const char *pszKey,
140,315✔
3973
                                     const char *pszDefault)
3974
{
3975
    {
3976
        std::lock_guard<std::mutex> oLock(oMutexPathSpecificOptions);
140,315✔
3977
        for (auto it = oMapPathSpecificOptions.rbegin();
173,326✔
3978
             it != oMapPathSpecificOptions.rend(); ++it)
206,336✔
3979
        {
3980
            if (STARTS_WITH(pszPath, it->first.c_str()))
33,266✔
3981
            {
3982
                auto oIter = it->second.find(CPLString(pszKey).toupper());
3,238✔
3983
                if (oIter != it->second.end())
3,238✔
3984
                    return oIter->second.c_str();
256✔
3985
            }
3986
        }
3987
    }
3988
    return CPLGetConfigOption(pszKey, pszDefault);
140,060✔
3989
}
3990

3991
/************************************************************************/
3992
/*                      VSIDuplicateFileSystemHandler()                 */
3993
/************************************************************************/
3994

3995
/**
3996
 * \brief Duplicate an existing file system handler.
3997
 *
3998
 * A number of virtual file system for remote object stores use protocols
3999
 * identical or close to popular ones (typically AWS S3), but with slightly
4000
 * different settings (at the very least the endpoint).
4001
 *
4002
 * This functions allows to duplicate the source virtual file system handler
4003
 * as a new one with a different prefix (when the source virtual file system
4004
 * handler supports the duplication operation).
4005
 *
4006
 * VSISetPathSpecificOption() will typically be called afterwards to change
4007
 * configurable settings on the cloned file system handler (e.g. AWS_S3_ENDPOINT
4008
 * for a clone of /vsis3/).
4009
 *
4010
 * @since GDAL 3.7
4011
 */
4012
bool VSIDuplicateFileSystemHandler(const char *pszSourceFSName,
4✔
4013
                                   const char *pszNewFSName)
4014
{
4015
    VSIFilesystemHandler *poTargetFSHandler =
4016
        VSIFileManager::GetHandler(pszNewFSName);
4✔
4017
    if (poTargetFSHandler != VSIFileManager::GetHandler("/"))
4✔
4018
    {
4019
        CPLError(CE_Failure, CPLE_AppDefined,
1✔
4020
                 "%s is already a known virtual file system", pszNewFSName);
4021
        return false;
1✔
4022
    }
4023

4024
    VSIFilesystemHandler *poSourceFSHandler =
4025
        VSIFileManager::GetHandler(pszSourceFSName);
3✔
4026
    if (!poSourceFSHandler)
3✔
4027
    {
4028
        CPLError(CE_Failure, CPLE_AppDefined,
×
4029
                 "%s is not a known virtual file system", pszSourceFSName);
4030
        return false;
×
4031
    }
4032

4033
    poTargetFSHandler = poSourceFSHandler->Duplicate(pszNewFSName);
3✔
4034
    if (!poTargetFSHandler)
3✔
4035
        return false;
2✔
4036

4037
    VSIFileManager::InstallHandler(pszNewFSName, poTargetFSHandler);
1✔
4038
    return true;
1✔
4039
}
4040

4041
/************************************************************************/
4042
/* ==================================================================== */
4043
/*                           VSIFileManager()                           */
4044
/* ==================================================================== */
4045
/************************************************************************/
4046

4047
#ifndef DOXYGEN_SKIP
4048

4049
/*
4050
** Notes on Multithreading:
4051
**
4052
** The VSIFileManager maintains a list of file type handlers (mem, large
4053
** file, etc).  It should be thread safe.
4054
**/
4055

4056
/************************************************************************/
4057
/*                           VSIFileManager()                           */
4058
/************************************************************************/
4059

4060
VSIFileManager::VSIFileManager() : poDefaultHandler(nullptr)
1,642✔
4061
{
4062
}
1,642✔
4063

4064
/************************************************************************/
4065
/*                          ~VSIFileManager()                           */
4066
/************************************************************************/
4067

4068
VSIFileManager::~VSIFileManager()
1,113✔
4069
{
4070
    std::set<VSIFilesystemHandler *> oSetAlreadyDeleted;
2,226✔
4071
    for (std::map<std::string, VSIFilesystemHandler *>::const_iterator iter =
34,505✔
4072
             oHandlers.begin();
1,113✔
4073
         iter != oHandlers.end(); ++iter)
70,123✔
4074
    {
4075
        if (oSetAlreadyDeleted.find(iter->second) == oSetAlreadyDeleted.end())
34,505✔
4076
        {
4077
            oSetAlreadyDeleted.insert(iter->second);
31,166✔
4078
            delete iter->second;
31,166✔
4079
        }
4080
    }
4081

4082
    delete poDefaultHandler;
1,113✔
4083
}
1,113✔
4084

4085
/************************************************************************/
4086
/*                                Get()                                 */
4087
/************************************************************************/
4088

4089
static VSIFileManager *poManager = nullptr;
4090
static CPLMutex *hVSIFileManagerMutex = nullptr;
4091

4092
VSIFileManager *VSIFileManager::Get()
2,687,650✔
4093
{
4094
    CPLMutexHolder oHolder(&hVSIFileManagerMutex);
5,375,440✔
4095
    if (poManager != nullptr)
2,687,790✔
4096
    {
4097
        return poManager;
2,686,150✔
4098
    }
4099

4100
    poManager = new VSIFileManager;
1,642✔
4101
    VSIInstallLargeFileHandler();
1,642✔
4102
    VSIInstallSubFileHandler();
1,642✔
4103
    VSIInstallMemFileHandler();
1,642✔
4104
#ifdef HAVE_LIBZ
4105
    VSIInstallGZipFileHandler();
1,642✔
4106
    VSIInstallZipFileHandler();
1,642✔
4107
#endif
4108
#ifdef HAVE_LIBARCHIVE
4109
    VSIInstall7zFileHandler();
4110
    VSIInstallRarFileHandler();
4111
#endif
4112
#ifdef HAVE_CURL
4113
    VSIInstallCurlFileHandler();
1,642✔
4114
    VSIInstallCurlStreamingFileHandler();
1,642✔
4115
    VSIInstallS3FileHandler();
1,642✔
4116
    VSIInstallS3StreamingFileHandler();
1,642✔
4117
    VSIInstallGSFileHandler();
1,642✔
4118
    VSIInstallGSStreamingFileHandler();
1,642✔
4119
    VSIInstallAzureFileHandler();
1,642✔
4120
    VSIInstallAzureStreamingFileHandler();
1,642✔
4121
    VSIInstallADLSFileHandler();
1,642✔
4122
    VSIInstallOSSFileHandler();
1,642✔
4123
    VSIInstallOSSStreamingFileHandler();
1,642✔
4124
    VSIInstallSwiftFileHandler();
1,642✔
4125
    VSIInstallSwiftStreamingFileHandler();
1,642✔
4126
    VSIInstallWebHdfsHandler();
1,642✔
4127
#endif
4128
    VSIInstallStdinHandler();
1,642✔
4129
    VSIInstallHdfsHandler();
1,642✔
4130
    VSIInstallStdoutHandler();
1,642✔
4131
    VSIInstallSparseFileHandler();
1,642✔
4132
    VSIInstallTarFileHandler();
1,642✔
4133
    VSIInstallCachedFileHandler();
1,642✔
4134
    VSIInstallCryptFileHandler();
1,642✔
4135

4136
    return poManager;
1,642✔
4137
}
4138

4139
/************************************************************************/
4140
/*                           GetPrefixes()                              */
4141
/************************************************************************/
4142

4143
char **VSIFileManager::GetPrefixes()
663✔
4144
{
4145
    CPLMutexHolder oHolder(&hVSIFileManagerMutex);
1,326✔
4146
    CPLStringList aosList;
1,326✔
4147
    for (const auto &oIter : Get()->oHandlers)
21,216✔
4148
    {
4149
        if (oIter.first != "/vsicurl?")
20,553✔
4150
        {
4151
            aosList.AddString(oIter.first.c_str());
19,890✔
4152
        }
4153
    }
4154
    return aosList.StealList();
1,326✔
4155
}
4156

4157
/************************************************************************/
4158
/*                             GetHandler()                             */
4159
/************************************************************************/
4160

4161
VSIFilesystemHandler *VSIFileManager::GetHandler(const char *pszPath)
2,634,560✔
4162

4163
{
4164
    VSIFileManager *poThis = Get();
2,634,560✔
4165
    const size_t nPathLen = strlen(pszPath);
2,634,630✔
4166

4167
    for (std::map<std::string, VSIFilesystemHandler *>::const_iterator iter =
58,369,000✔
4168
             poThis->oHandlers.begin();
2,634,630✔
4169
         iter != poThis->oHandlers.end(); ++iter)
119,371,000✔
4170
    {
4171
        const char *pszIterKey = iter->first.c_str();
60,174,400✔
4172
        const size_t nIterKeyLen = iter->first.size();
60,185,200✔
4173
        if (strncmp(pszPath, pszIterKey, nIterKeyLen) == 0)
60,191,200✔
4174
            return iter->second;
1,823,510✔
4175

4176
        // "/vsimem\foo" should be handled as "/vsimem/foo".
4177
        if (nIterKeyLen && nPathLen > nIterKeyLen &&
58,478,600✔
4178
            pszIterKey[nIterKeyLen - 1] == '/' &&
51,460,300✔
4179
            pszPath[nIterKeyLen - 1] == '\\' &&
45,449,900✔
4180
            strncmp(pszPath, pszIterKey, nIterKeyLen - 1) == 0)
30✔
4181
            return iter->second;
×
4182

4183
        // /vsimem should be treated as a match for /vsimem/.
4184
        if (nPathLen + 1 == nIterKeyLen &&
58,478,600✔
4185
            strncmp(pszPath, pszIterKey, nPathLen) == 0)
564,252✔
4186
            return iter->second;
110,914✔
4187
    }
4188

4189
    return poThis->poDefaultHandler;
811,038✔
4190
}
4191

4192
/************************************************************************/
4193
/*                           InstallHandler()                           */
4194
/************************************************************************/
4195

4196
void VSIFileManager::InstallHandler(const std::string &osPrefix,
52,495✔
4197
                                    VSIFilesystemHandler *poHandler)
4198

4199
{
4200
    if (osPrefix == "")
52,495✔
4201
        Get()->poDefaultHandler = poHandler;
1,642✔
4202
    else
4203
        Get()->oHandlers[osPrefix] = poHandler;
50,853✔
4204
}
52,495✔
4205

4206
/************************************************************************/
4207
/*                          RemoveHandler()                             */
4208
/************************************************************************/
4209

4210
void VSIFileManager::RemoveHandler(const std::string &osPrefix)
3✔
4211
{
4212
    if (osPrefix == "")
3✔
4213
        Get()->poDefaultHandler = nullptr;
×
4214
    else
4215
        Get()->oHandlers.erase(osPrefix);
3✔
4216
}
3✔
4217

4218
/************************************************************************/
4219
/*                       VSICleanupFileManager()                        */
4220
/************************************************************************/
4221

4222
void VSICleanupFileManager()
1,113✔
4223

4224
{
4225
    if (poManager)
1,113✔
4226
    {
4227
        delete poManager;
1,113✔
4228
        poManager = nullptr;
1,113✔
4229
    }
4230

4231
    if (hVSIFileManagerMutex != nullptr)
1,113✔
4232
    {
4233
        CPLDestroyMutex(hVSIFileManagerMutex);
1,113✔
4234
        hVSIFileManagerMutex = nullptr;
1,113✔
4235
    }
4236

4237
#ifdef HAVE_CURL
4238
    VSICURLDestroyCacheFileProp();
1,113✔
4239
#endif
4240
}
1,113✔
4241

4242
/************************************************************************/
4243
/*                            Truncate()                                */
4244
/************************************************************************/
4245

4246
int VSIVirtualHandle::Truncate(vsi_l_offset nNewSize)
2✔
4247
{
4248
    const vsi_l_offset nOriginalPos = Tell();
2✔
4249
    if (Seek(0, SEEK_END) == 0 && nNewSize >= Tell())
2✔
4250
    {
4251
        // Fill with zeroes
4252
        std::vector<GByte> aoBytes(4096, 0);
2✔
4253
        vsi_l_offset nCurOffset = nOriginalPos;
1✔
4254
        while (nCurOffset < nNewSize)
3✔
4255
        {
4256
            constexpr vsi_l_offset nMaxOffset = 4096;
2✔
4257
            const int nSize =
4258
                static_cast<int>(std::min(nMaxOffset, nNewSize - nCurOffset));
2✔
4259
            if (Write(&aoBytes[0], nSize, 1) != 1)
2✔
4260
            {
4261
                Seek(nOriginalPos, SEEK_SET);
×
4262
                return -1;
×
4263
            }
4264
            nCurOffset += nSize;
2✔
4265
        }
4266
        return Seek(nOriginalPos, SEEK_SET) == 0 ? 0 : -1;
1✔
4267
    }
4268

4269
    CPLDebug("VSI", "Truncation is not supported in generic implementation "
1✔
4270
                    "of Truncate()");
4271
    Seek(nOriginalPos, SEEK_SET);
1✔
4272
    return -1;
1✔
4273
}
4274

4275
/************************************************************************/
4276
/*                           ReadMultiRange()                           */
4277
/************************************************************************/
4278

4279
int VSIVirtualHandle::ReadMultiRange(int nRanges, void **ppData,
763✔
4280
                                     const vsi_l_offset *panOffsets,
4281
                                     const size_t *panSizes)
4282
{
4283
    int nRet = 0;
763✔
4284
    const vsi_l_offset nCurOffset = Tell();
763✔
4285
    for (int i = 0; i < nRanges; i++)
58,779✔
4286
    {
4287
        if (Seek(panOffsets[i], SEEK_SET) < 0)
58,035✔
4288
        {
4289
            nRet = -1;
×
4290
            break;
×
4291
        }
4292

4293
        const size_t nRead = Read(ppData[i], 1, panSizes[i]);
58,035✔
4294
        if (panSizes[i] != nRead)
58,035✔
4295
        {
4296
            nRet = -1;
19✔
4297
            break;
19✔
4298
        }
4299
    }
4300

4301
    Seek(nCurOffset, SEEK_SET);
763✔
4302

4303
    return nRet;
763✔
4304
}
4305

4306
#endif  // #ifndef DOXYGEN_SKIP
4307

4308
/************************************************************************/
4309
/*                            HasPRead()                                */
4310
/************************************************************************/
4311

4312
/** Returns whether this file handle supports the PRead() method.
4313
 *
4314
 * @since GDAL 3.6
4315
 */
4316
bool VSIVirtualHandle::HasPRead() const
×
4317
{
4318
    return false;
×
4319
}
4320

4321
/************************************************************************/
4322
/*                             PRead()                                  */
4323
/************************************************************************/
4324

4325
/** Do a parallel-compatible read operation.
4326
 *
4327
 * This methods reads into pBuffer up to nSize bytes starting at offset nOffset
4328
 * in the file. The current file offset is not affected by this method.
4329
 *
4330
 * The implementation is thread-safe: several threads can issue PRead()
4331
 * concurrently on the same VSIVirtualHandle object.
4332
 *
4333
 * This method has the same semantics as pread() Linux operation. It is only
4334
 * available if HasPRead() returns true.
4335
 *
4336
 * @param pBuffer output buffer (must be at least nSize bytes large).
4337
 * @param nSize   number of bytes to read in the file.
4338
 * @param nOffset file offset from which to read.
4339
 * @return number of bytes read.
4340
 * @since GDAL 3.6
4341
 */
4342
size_t VSIVirtualHandle::PRead(CPL_UNUSED void *pBuffer,
×
4343
                               CPL_UNUSED size_t nSize,
4344
                               CPL_UNUSED vsi_l_offset nOffset) const
4345
{
4346
    return 0;
×
4347
}
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