Coverage Report

Created: 2025-08-11 09:23

/src/gdal/port/cpl_vsil.cpp
Line
Count
Source (jump to first uncovered line)
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)
74
414k
{
75
414k
    return VSIReadDirEx(pszPath, 0);
76
414k
}
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)
108
852k
{
109
852k
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath);
110
111
852k
    return poFSHandler->ReadDirEx(pszPath, nMaxFiles);
112
852k
}
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)
136
1.33M
{
137
1.33M
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
138
139
1.33M
    return poFSHandler->SiblingFiles(pszFilename);
140
1.33M
}
141
142
/************************************************************************/
143
/*                           VSIFnMatch()                               */
144
/************************************************************************/
145
146
static bool VSIFnMatch(const char *pszPattern, const char *pszStr)
147
0
{
148
0
    for (; *pszPattern && *pszStr; pszPattern++, pszStr++)
149
0
    {
150
0
        if (*pszPattern == '*')
151
0
        {
152
0
            if (pszPattern[1] == 0)
153
0
                return true;
154
0
            for (; *pszStr; ++pszStr)
155
0
            {
156
0
                if (VSIFnMatch(pszPattern + 1, pszStr))
157
0
                    return true;
158
0
            }
159
0
            return false;
160
0
        }
161
0
        else if (*pszPattern == '?')
162
0
        {
163
            // match single any char
164
0
        }
165
0
        else if (*pszPattern == '[')
166
0
        {
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
0
            const char *pszOpenBracket = pszPattern;
176
0
            ++pszPattern;
177
0
            const bool isNot = (*pszPattern == '!');
178
0
            if (isNot)
179
0
            {
180
0
                ++pszOpenBracket;
181
0
                ++pszPattern;
182
0
            }
183
0
            bool res = false;
184
0
            for (; *pszPattern; ++pszPattern)
185
0
            {
186
0
                if ((*pszPattern == ']' || *pszPattern == '-') &&
187
0
                    pszPattern == pszOpenBracket + 1)
188
0
                {
189
0
                    if (*pszStr == *pszPattern)
190
0
                    {
191
0
                        res = true;
192
0
                    }
193
0
                }
194
0
                else if (*pszPattern == ']')
195
0
                {
196
0
                    break;
197
0
                }
198
0
                else if (pszPattern[1] == '-' && pszPattern[2] != 0 &&
199
0
                         pszPattern[2] != ']')
200
0
                {
201
0
                    if (*pszStr >= pszPattern[0] && *pszStr <= pszPattern[2])
202
0
                    {
203
0
                        res = true;
204
0
                    }
205
0
                    pszPattern += 2;
206
0
                }
207
0
                else if (*pszStr == *pszPattern)
208
0
                {
209
0
                    res = true;
210
0
                }
211
0
            }
212
0
            if (*pszPattern == 0)
213
0
                return false;
214
0
            if (!res && !isNot)
215
0
                return false;
216
0
            if (res && isNot)
217
0
                return false;
218
0
        }
219
0
        else if (*pszPattern != *pszStr)
220
0
        {
221
0
            return false;
222
0
        }
223
0
    }
224
0
    return *pszPattern == 0 && *pszStr == 0;
225
0
}
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,
293
               GDALProgressFunc pProgressFunc, void *pProgressData)
294
0
{
295
0
    CPL_IGNORE_RET_VAL(papszOptions);
296
297
0
    CPLStringList aosRes;
298
0
    std::vector<std::pair<std::string, size_t>> candidates;
299
0
    candidates.emplace_back(pszPattern, 0);
300
0
    while (!candidates.empty())
301
0
    {
302
0
        auto [osPattern, nPosStart] = candidates.back();
303
0
        pszPattern = osPattern.c_str() + nPosStart;
304
0
        candidates.pop_back();
305
306
0
        std::string osPath = osPattern.substr(0, nPosStart);
307
0
        std::string osCurPath;
308
0
        for (;; ++pszPattern)
309
0
        {
310
0
            if (*pszPattern == 0 || *pszPattern == '/' || *pszPattern == '\\')
311
0
            {
312
0
                struct VSIDirCloser
313
0
                {
314
0
                    void operator()(VSIDIR *dir)
315
0
                    {
316
0
                        VSICloseDir(dir);
317
0
                    }
318
0
                };
319
320
0
                if (osCurPath == "**")
321
0
                {
322
0
                    std::unique_ptr<VSIDIR, VSIDirCloser> psDir(
323
0
                        VSIOpenDir(osPath.c_str(), -1, nullptr));
324
0
                    if (!psDir)
325
0
                        return nullptr;
326
0
                    while (const VSIDIREntry *psEntry =
327
0
                               VSIGetNextDirEntry(psDir.get()))
328
0
                    {
329
0
                        if (pProgressFunc &&
330
0
                            !pProgressFunc(0, "", pProgressData))
331
0
                        {
332
0
                            return nullptr;
333
0
                        }
334
0
                        {
335
0
                            std::string osCandidate(osPath);
336
0
                            osCandidate += psEntry->pszName;
337
0
                            nPosStart = osCandidate.size();
338
0
                            if (*pszPattern)
339
0
                            {
340
0
                                osCandidate += pszPattern;
341
0
                            }
342
0
                            candidates.emplace_back(std::move(osCandidate),
343
0
                                                    nPosStart);
344
0
                        }
345
0
                    }
346
0
                    osPath.clear();
347
0
                    break;
348
0
                }
349
0
                else if (osCurPath.find_first_of("*?[") != std::string::npos)
350
0
                {
351
0
                    std::unique_ptr<VSIDIR, VSIDirCloser> psDir(
352
0
                        VSIOpenDir(osPath.c_str(), 0, nullptr));
353
0
                    if (!psDir)
354
0
                        return nullptr;
355
0
                    while (const VSIDIREntry *psEntry =
356
0
                               VSIGetNextDirEntry(psDir.get()))
357
0
                    {
358
0
                        if (pProgressFunc &&
359
0
                            !pProgressFunc(0, "", pProgressData))
360
0
                        {
361
0
                            return nullptr;
362
0
                        }
363
0
                        if (VSIFnMatch(osCurPath.c_str(), psEntry->pszName))
364
0
                        {
365
0
                            std::string osCandidate(osPath);
366
0
                            osCandidate += psEntry->pszName;
367
0
                            nPosStart = osCandidate.size();
368
0
                            if (*pszPattern)
369
0
                            {
370
0
                                osCandidate += pszPattern;
371
0
                            }
372
0
                            candidates.emplace_back(std::move(osCandidate),
373
0
                                                    nPosStart);
374
0
                        }
375
0
                    }
376
0
                    osPath.clear();
377
0
                    break;
378
0
                }
379
0
                else if (*pszPattern == 0)
380
0
                {
381
0
                    osPath += osCurPath;
382
0
                    break;
383
0
                }
384
0
                else
385
0
                {
386
0
                    osPath += osCurPath;
387
0
                    osPath += *pszPattern;
388
0
                    osCurPath.clear();
389
0
                }
390
0
            }
391
0
            else
392
0
            {
393
0
                osCurPath += *pszPattern;
394
0
            }
395
0
        }
396
0
        if (!osPath.empty())
397
0
        {
398
0
            VSIStatBufL sStat;
399
0
            if (VSIStatL(osPath.c_str(), &sStat) == 0)
400
0
                aosRes.AddString(osPath.c_str());
401
0
        }
402
0
    }
403
404
0
    return aosRes.StealList();
405
0
}
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)
420
19.9M
{
421
19.9M
    if (STARTS_WITH(pszPath, "http://") || STARTS_WITH(pszPath, "https://"))
422
76
        return "/";
423
424
19.9M
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath);
425
19.9M
    return poFSHandler->GetDirectorySeparator(pszPath);
426
19.9M
}
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)
460
65
{
461
65
    const char SEP = VSIGetDirectorySeparator(pszPathIn)[0];
462
463
65
    const char *const apszOptions[] = {"NAME_AND_TYPE_ONLY=YES", nullptr};
464
65
    VSIDIR *psDir = VSIOpenDir(pszPathIn, -1, apszOptions);
465
65
    if (!psDir)
466
3
        return nullptr;
467
62
    CPLStringList oFiles;
468
3.94k
    while (auto psEntry = VSIGetNextDirEntry(psDir))
469
3.88k
    {
470
3.88k
        if (VSI_ISDIR(psEntry->nMode) && psEntry->pszName[0] &&
471
3.88k
            psEntry->pszName[strlen(psEntry->pszName) - 1] != SEP)
472
852
        {
473
852
            oFiles.AddString((std::string(psEntry->pszName) + SEP).c_str());
474
852
        }
475
3.03k
        else
476
3.03k
        {
477
3.03k
            oFiles.AddString(psEntry->pszName);
478
3.03k
        }
479
3.88k
    }
480
62
    VSICloseDir(psDir);
481
482
62
    return oFiles.StealList();
483
65
}
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
0
{
499
0
    return VSIReadDir(pszPath);
500
0
}
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,
543
                   const char *const *papszOptions)
544
78.2k
{
545
78.2k
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath);
546
547
78.2k
    return poFSHandler->OpenDir(pszPath, nRecurseDepth, papszOptions);
548
78.2k
}
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)
583
317k
{
584
317k
    return dir->NextDirEntry();
585
317k
}
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)
602
78.0k
{
603
78.0k
    delete dir;
604
78.0k
}
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)
627
628
1.26M
{
629
1.26M
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPathname);
630
631
1.26M
    return poFSHandler->Mkdir(pszPathname, mode);
632
1.26M
}
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)
649
2.22M
{
650
2.22M
    if (pszPathname == nullptr || pszPathname[0] == '\0' ||
651
2.22M
        strncmp("/", pszPathname, 2) == 0)
652
8
    {
653
8
        return -1;
654
8
    }
655
656
2.22M
    const CPLString osPathname(pszPathname);
657
2.22M
    VSIStatBufL sStat;
658
2.22M
    if (VSIStatL(osPathname, &sStat) == 0)
659
888k
    {
660
888k
        return VSI_ISDIR(sStat.st_mode) ? 0 : -1;
661
888k
    }
662
1.33M
    const std::string osParentPath(CPLGetPathSafe(osPathname));
663
664
    // Prevent crazy paths from recursing forever.
665
1.33M
    if (osParentPath == osPathname ||
666
1.33M
        osParentPath.length() >= osPathname.length())
667
0
    {
668
0
        return -1;
669
0
    }
670
671
1.33M
    if (!osParentPath.empty() && VSIStatL(osParentPath.c_str(), &sStat) != 0)
672
749k
    {
673
749k
        if (VSIMkdirRecursive(osParentPath.c_str(), mode) != 0)
674
67.1k
            return -1;
675
749k
    }
676
677
1.26M
    return VSIMkdir(osPathname, mode);
678
1.33M
}
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)
700
701
1.33M
{
702
1.33M
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
703
704
1.33M
    return poFSHandler->Unlink(pszFilename);
705
1.33M
}
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)
731
0
{
732
0
    VSIFilesystemHandler *poFSHandler = nullptr;
733
0
    for (CSLConstList papszIter = papszFiles; papszIter && *papszIter;
734
0
         ++papszIter)
735
0
    {
736
0
        auto poFSHandlerThisFile = VSIFileManager::GetHandler(*papszIter);
737
0
        if (poFSHandler == nullptr)
738
0
            poFSHandler = poFSHandlerThisFile;
739
0
        else if (poFSHandler != poFSHandlerThisFile)
740
0
        {
741
0
            CPLError(CE_Failure, CPLE_AppDefined,
742
0
                     "Files belong to different file system handlers");
743
0
            poFSHandler = nullptr;
744
0
            break;
745
0
        }
746
0
    }
747
0
    if (poFSHandler == nullptr)
748
0
        return nullptr;
749
0
    return poFSHandler->UnlinkBatch(papszFiles);
750
0
}
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)
781
782
2.54k
{
783
2.54k
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(oldpath);
784
785
2.54k
    return poFSHandler->Rename(oldpath, newpath, nullptr, nullptr);
786
2.54k
}
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,
815
            const char *const *papszOptions, GDALProgressFunc pProgressFunc,
816
            void *pProgressData)
817
0
{
818
819
0
    if (strcmp(oldpath, newpath) == 0)
820
0
        return 0;
821
822
0
    VSIFilesystemHandler *poOldFSHandler = VSIFileManager::GetHandler(oldpath);
823
0
    VSIFilesystemHandler *poNewFSHandler = VSIFileManager::GetHandler(newpath);
824
825
0
    VSIStatBufL sStat;
826
0
    if (VSIStatL(oldpath, &sStat) != 0)
827
0
    {
828
0
        CPLDebug("VSI", "%s is not a object", oldpath);
829
0
        errno = ENOENT;
830
0
        return -1;
831
0
    }
832
833
0
    std::string sNewpath(newpath);
834
0
    VSIStatBufL sStatNew;
835
0
    if (VSIStatL(newpath, &sStatNew) == 0 && VSI_ISDIR(sStatNew.st_mode))
836
0
    {
837
0
        sNewpath =
838
0
            CPLFormFilenameSafe(newpath, CPLGetFilename(oldpath), nullptr);
839
0
    }
840
841
0
    int ret = 0;
842
843
0
    if (poOldFSHandler == poNewFSHandler)
844
0
    {
845
0
        ret = poOldFSHandler->Rename(oldpath, sNewpath.c_str(), pProgressFunc,
846
0
                                     pProgressData);
847
0
        if (ret == 0 && pProgressFunc)
848
0
            ret = pProgressFunc(1.0, "", pProgressData) ? 0 : -1;
849
0
        return ret;
850
0
    }
851
852
0
    if (VSI_ISDIR(sStat.st_mode))
853
0
    {
854
0
        const CPLStringList aosList(VSIReadDir(oldpath));
855
0
        poNewFSHandler->Mkdir(sNewpath.c_str(), 0755);
856
0
        bool bFoundFiles = false;
857
0
        const int nListSize = aosList.size();
858
0
        for (int i = 0; ret == 0 && i < nListSize; i++)
859
0
        {
860
0
            if (strcmp(aosList[i], ".") != 0 && strcmp(aosList[i], "..") != 0)
861
0
            {
862
0
                bFoundFiles = true;
863
0
                const std::string osSrc =
864
0
                    CPLFormFilenameSafe(oldpath, aosList[i], nullptr);
865
0
                const std::string osTarget =
866
0
                    CPLFormFilenameSafe(sNewpath.c_str(), aosList[i], nullptr);
867
0
                void *pScaledProgress = GDALCreateScaledProgress(
868
0
                    static_cast<double>(i) / nListSize,
869
0
                    static_cast<double>(i + 1) / nListSize, pProgressFunc,
870
0
                    pProgressData);
871
0
                ret = VSIMove(osSrc.c_str(), osTarget.c_str(), papszOptions,
872
0
                              pScaledProgress ? GDALScaledProgress : nullptr,
873
0
                              pScaledProgress);
874
0
                GDALDestroyScaledProgress(pScaledProgress);
875
0
            }
876
0
        }
877
0
        if (!bFoundFiles)
878
0
            ret = VSIStatL(sNewpath.c_str(), &sStat);
879
0
        if (ret == 0)
880
0
            ret = poOldFSHandler->Rmdir(oldpath);
881
0
    }
882
0
    else
883
0
    {
884
0
        ret = VSICopyFile(oldpath, sNewpath.c_str(), nullptr, sStat.st_size,
885
0
                          nullptr, pProgressFunc, pProgressData) == 0 &&
886
0
                      VSIUnlink(oldpath) == 0
887
0
                  ? 0
888
0
                  : -1;
889
0
    }
890
0
    if (ret == 0 && pProgressFunc)
891
0
        ret = pProgressFunc(1.0, "", pProgressData) ? 0 : -1;
892
0
    return ret;
893
0
}
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,
930
                VSILFILE *fpSource, vsi_l_offset nSourceSize,
931
                const char *const *papszOptions, GDALProgressFunc pProgressFunc,
932
                void *pProgressData)
933
934
2.21k
{
935
2.21k
    if (!pszSource && !fpSource)
936
0
    {
937
0
        CPLError(CE_Failure, CPLE_AppDefined,
938
0
                 "pszSource == nullptr && fpSource == nullptr");
939
0
        return -1;
940
0
    }
941
2.21k
    if (!pszTarget || pszTarget[0] == '\0')
942
0
    {
943
0
        return -1;
944
0
    }
945
946
2.21k
    VSIFilesystemHandler *poFSHandlerTarget =
947
2.21k
        VSIFileManager::GetHandler(pszTarget);
948
2.21k
    return poFSHandlerTarget->CopyFile(pszSource, pszTarget, fpSource,
949
2.21k
                                       nSourceSize, papszOptions, pProgressFunc,
950
2.21k
                                       pProgressData);
951
2.21k
}
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,
1023
                           const char *pszInputPayload,
1024
                           char **ppszOutputPayload,
1025
                           const char *const *papszOptions,
1026
                           GDALProgressFunc pProgressFunc, void *pProgressData)
1027
1028
0
{
1029
0
    if (!pszSource)
1030
0
    {
1031
0
        return -1;
1032
0
    }
1033
0
    if (!pszTarget || pszTarget[0] == '\0')
1034
0
    {
1035
0
        return -1;
1036
0
    }
1037
0
    if (!ppszOutputPayload)
1038
0
    {
1039
0
        return -1;
1040
0
    }
1041
1042
0
    VSIFilesystemHandler *poFSHandlerTarget =
1043
0
        VSIFileManager::GetHandler(pszTarget);
1044
0
    return poFSHandlerTarget->CopyFileRestartable(
1045
0
        pszSource, pszTarget, pszInputPayload, ppszOutputPayload, papszOptions,
1046
0
        pProgressFunc, pProgressData);
1047
0
}
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,
1130
            const char *const *papszOptions, GDALProgressFunc pProgressFunc,
1131
            void *pProgressData, char ***ppapszOutputs)
1132
1133
0
{
1134
0
    if (pszSource[0] == '\0' || pszTarget[0] == '\0')
1135
0
    {
1136
0
        return FALSE;
1137
0
    }
1138
1139
0
    VSIFilesystemHandler *poFSHandlerSource =
1140
0
        VSIFileManager::GetHandler(pszSource);
1141
0
    VSIFilesystemHandler *poFSHandlerTarget =
1142
0
        VSIFileManager::GetHandler(pszTarget);
1143
0
    VSIFilesystemHandler *poFSHandlerLocal = VSIFileManager::GetHandler("");
1144
0
    VSIFilesystemHandler *poFSHandlerMem =
1145
0
        VSIFileManager::GetHandler("/vsimem/");
1146
0
    VSIFilesystemHandler *poFSHandler = poFSHandlerSource;
1147
0
    if (poFSHandlerTarget != poFSHandlerLocal &&
1148
0
        poFSHandlerTarget != poFSHandlerMem)
1149
0
    {
1150
0
        poFSHandler = poFSHandlerTarget;
1151
0
    }
1152
1153
0
    return poFSHandler->Sync(pszSource, pszTarget, papszOptions, pProgressFunc,
1154
0
                             pProgressData, ppapszOutputs)
1155
0
               ? TRUE
1156
0
               : FALSE;
1157
0
}
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(
1187
    const char *pszFilename, int *pbNonSequentialUploadSupported,
1188
    int *pbParallelUploadSupported, int *pbAbortSupported,
1189
    size_t *pnMinPartSize, size_t *pnMaxPartSize, int *pnMaxPartCount)
1190
0
{
1191
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
1192
1193
0
    return poFSHandler->MultipartUploadGetCapabilities(
1194
0
        pbNonSequentialUploadSupported, pbParallelUploadSupported,
1195
0
        pbAbortSupported, pnMinPartSize, pnMaxPartSize, pnMaxPartCount);
1196
0
}
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,
1236
                              CSLConstList papszOptions)
1237
0
{
1238
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
1239
1240
0
    return poFSHandler->MultipartUploadStart(pszFilename, papszOptions);
1241
0
}
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,
1274
                                const char *pszUploadId, int nPartNumber,
1275
                                vsi_l_offset nFileOffset, const void *pData,
1276
                                size_t nDataLength, CSLConstList papszOptions)
1277
0
{
1278
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
1279
1280
0
    return poFSHandler->MultipartUploadAddPart(pszFilename, pszUploadId,
1281
0
                                               nPartNumber, nFileOffset, pData,
1282
0
                                               nDataLength, papszOptions);
1283
0
}
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,
1311
                          size_t nPartIdsCount, const char *const *apszPartIds,
1312
                          vsi_l_offset nTotalSize, CSLConstList papszOptions)
1313
0
{
1314
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
1315
1316
0
    return poFSHandler->MultipartUploadEnd(pszFilename, pszUploadId,
1317
0
                                           nPartIdsCount, apszPartIds,
1318
0
                                           nTotalSize, papszOptions);
1319
0
}
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,
1346
                            CSLConstList papszOptions)
1347
0
{
1348
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
1349
1350
0
    return poFSHandler->MultipartUploadAbort(pszFilename, pszUploadId,
1351
0
                                             papszOptions);
1352
0
}
1353
1354
#ifndef DOXYGEN_SKIP
1355
1356
/************************************************************************/
1357
/*                     MultipartUploadGetCapabilities()                 */
1358
/************************************************************************/
1359
1360
bool VSIFilesystemHandler::MultipartUploadGetCapabilities(int *, int *, int *,
1361
                                                          size_t *, size_t *,
1362
                                                          int *)
1363
0
{
1364
0
    CPLError(
1365
0
        CE_Failure, CPLE_NotSupported,
1366
0
        "MultipartUploadGetCapabilities() not supported by this file system");
1367
0
    return false;
1368
0
}
1369
1370
/************************************************************************/
1371
/*                         MultipartUploadStart()                       */
1372
/************************************************************************/
1373
1374
char *VSIFilesystemHandler::MultipartUploadStart(const char *, CSLConstList)
1375
0
{
1376
0
    CPLError(CE_Failure, CPLE_NotSupported,
1377
0
             "MultipartUploadStart() not supported by this file system");
1378
0
    return nullptr;
1379
0
}
1380
1381
/************************************************************************/
1382
/*                       MultipartUploadAddPart()                       */
1383
/************************************************************************/
1384
1385
char *VSIFilesystemHandler::MultipartUploadAddPart(const char *, const char *,
1386
                                                   int, vsi_l_offset,
1387
                                                   const void *, size_t,
1388
                                                   CSLConstList)
1389
0
{
1390
0
    CPLError(CE_Failure, CPLE_NotSupported,
1391
0
             "MultipartUploadAddPart() not supported by this file system");
1392
0
    return nullptr;
1393
0
}
1394
1395
/************************************************************************/
1396
/*                         MultipartUploadEnd()                         */
1397
/************************************************************************/
1398
1399
bool VSIFilesystemHandler::MultipartUploadEnd(const char *, const char *,
1400
                                              size_t, const char *const *,
1401
                                              vsi_l_offset, CSLConstList)
1402
0
{
1403
0
    CPLError(CE_Failure, CPLE_NotSupported,
1404
0
             "MultipartUploadEnd() not supported by this file system");
1405
0
    return FALSE;
1406
0
}
1407
1408
/************************************************************************/
1409
/*                         MultipartUploadAbort()                       */
1410
/************************************************************************/
1411
1412
bool VSIFilesystemHandler::MultipartUploadAbort(const char *, const char *,
1413
                                                CSLConstList)
1414
0
{
1415
0
    CPLError(CE_Failure, CPLE_NotSupported,
1416
0
             "MultipartUploadAbort() not supported by this file system");
1417
0
    return FALSE;
1418
0
}
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)
1448
0
{
1449
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
1450
1451
0
    return poFSHandler->AbortPendingUploads(pszFilename);
1452
0
}
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)
1475
1476
80
{
1477
80
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszDirname);
1478
1479
80
    return poFSHandler->Rmdir(pszDirname);
1480
80
}
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)
1501
40.4k
{
1502
40.4k
    if (pszDirname == nullptr || pszDirname[0] == '\0' ||
1503
40.4k
        strncmp("/", pszDirname, 2) == 0)
1504
0
    {
1505
0
        return -1;
1506
0
    }
1507
40.4k
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszDirname);
1508
40.4k
    return poFSHandler->RmdirRecursive(pszDirname);
1509
40.4k
}
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)
1537
1538
27.9M
{
1539
27.9M
    return VSIStatExL(pszFilename, psStatBuf, 0);
1540
27.9M
}
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)
1577
1578
34.1M
{
1579
34.1M
    char szAltPath[4] = {'\0'};
1580
1581
    // Enable to work on "C:" as if it were "C:\".
1582
34.1M
    if (pszFilename[0] != '\0' && pszFilename[1] == ':' &&
1583
34.1M
        pszFilename[2] == '\0')
1584
445
    {
1585
445
        szAltPath[0] = pszFilename[0];
1586
445
        szAltPath[1] = pszFilename[1];
1587
445
        szAltPath[2] = '\\';
1588
445
        szAltPath[3] = '\0';
1589
1590
445
        pszFilename = szAltPath;
1591
445
    }
1592
1593
34.1M
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
1594
1595
34.1M
    if (nFlags == 0)
1596
27.9M
        nFlags =
1597
27.9M
            VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG | VSI_STAT_SIZE_FLAG;
1598
1599
34.1M
    return poFSHandler->Stat(pszFilename, psStatBuf, nFlags);
1600
34.1M
}
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,
1655
                          CSLConstList papszOptions)
1656
0
{
1657
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
1658
0
    return poFSHandler->GetFileMetadata(pszFilename, pszDomain, papszOptions);
1659
0
}
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,
1725
                       const char *pszDomain, CSLConstList papszOptions)
1726
0
{
1727
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
1728
0
    return poFSHandler->SetFileMetadata(pszFilename, papszMetadata, pszDomain,
1729
0
                                        papszOptions)
1730
0
               ? 1
1731
0
               : 0;
1732
0
}
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)
1759
1.22M
{
1760
1.22M
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
1761
1762
1.22M
    return poFSHandler->IsCaseSensitive(pszFilename);
1763
1.22M
}
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)
1788
0
{
1789
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath);
1790
1791
0
    return poFSHandler->SupportsSparseFiles(pszPath);
1792
0
}
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)
1816
8.85k
{
1817
8.85k
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath);
1818
1819
8.85k
    return poFSHandler->IsLocal(pszPath);
1820
8.85k
}
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)
1841
0
{
1842
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath);
1843
1844
0
    return CPLStrdup(poFSHandler->GetCanonicalFilename(pszPath).c_str());
1845
0
}
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)
1865
8.83k
{
1866
8.83k
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath);
1867
1868
8.83k
    return poFSHandler->SupportsSequentialWrite(pszPath, bAllowLocalTempFile);
1869
8.83k
}
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)
1889
30
{
1890
30
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath);
1891
1892
30
    return poFSHandler->SupportsRandomWrite(pszPath, bAllowLocalTempFile);
1893
30
}
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)
1914
44.3k
{
1915
44.3k
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath);
1916
1917
44.3k
    return poFSHandler->HasOptimizedReadMultiRange(pszPath);
1918
44.3k
}
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)
1943
0
{
1944
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
1945
1946
0
    return poFSHandler->GetActualURL(pszFilename);
1947
0
}
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)
1987
0
{
1988
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
1989
1990
0
    return poFSHandler->GetSignedURL(pszFilename, papszOptions);
1991
0
}
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)
2024
2025
27.9M
{
2026
27.9M
    return VSIFOpenExL(pszFilename, pszAccess, false);
2027
27.9M
}
2028
2029
/************************************************************************/
2030
/*                               Open()                                 */
2031
/************************************************************************/
2032
2033
#ifndef DOXYGEN_SKIP
2034
2035
VSIVirtualHandle *VSIFilesystemHandler::Open(const char *pszFilename,
2036
                                             const char *pszAccess)
2037
1.01M
{
2038
1.01M
    return Open(pszFilename, pszAccess, false, nullptr);
2039
1.01M
}
2040
2041
/************************************************************************/
2042
/*                             CopyFile()                               */
2043
/************************************************************************/
2044
2045
int VSIFilesystemHandler::CopyFile(const char *pszSource, const char *pszTarget,
2046
                                   VSILFILE *fpSource, vsi_l_offset nSourceSize,
2047
                                   CSLConstList papszOptions,
2048
                                   GDALProgressFunc pProgressFunc,
2049
                                   void *pProgressData)
2050
2.12k
{
2051
2.12k
    VSIVirtualHandleUniquePtr poFileHandleAutoClose;
2052
2.12k
    if (!fpSource)
2053
2.12k
    {
2054
2.12k
        CPLAssert(pszSource);
2055
2.12k
        fpSource = VSIFOpenExL(pszSource, "rb", TRUE);
2056
2.12k
        if (!fpSource)
2057
0
        {
2058
0
            CPLError(CE_Failure, CPLE_FileIO, "Cannot open %s", pszSource);
2059
0
            return -1;
2060
0
        }
2061
2.12k
        poFileHandleAutoClose.reset(fpSource);
2062
2.12k
    }
2063
2.12k
    if (nSourceSize == static_cast<vsi_l_offset>(-1) &&
2064
2.12k
        pProgressFunc != nullptr && pszSource != nullptr)
2065
0
    {
2066
0
        VSIStatBufL sStat;
2067
0
        if (VSIStatL(pszSource, &sStat) == 0)
2068
0
        {
2069
0
            nSourceSize = sStat.st_size;
2070
0
        }
2071
0
    }
2072
2073
2.12k
    VSILFILE *fpOut = VSIFOpenEx2L(pszTarget, "wb", TRUE, papszOptions);
2074
2.12k
    if (!fpOut)
2075
0
    {
2076
0
        CPLError(CE_Failure, CPLE_FileIO, "Cannot create %s", pszTarget);
2077
0
        return -1;
2078
0
    }
2079
2080
2.12k
    CPLString osMsg;
2081
2.12k
    if (pszSource)
2082
2.12k
        osMsg.Printf("Copying of %s", pszSource);
2083
0
    else
2084
0
        pszSource = "(unknown filename)";
2085
2086
2.12k
    int ret = 0;
2087
2.12k
    constexpr size_t nBufferSize = 10 * 4096;
2088
2.12k
    std::vector<GByte> abyBuffer(nBufferSize, 0);
2089
2.12k
    GUIntBig nOffset = 0;
2090
2.20k
    while (true)
2091
2.20k
    {
2092
2.20k
        const size_t nRead = VSIFReadL(&abyBuffer[0], 1, nBufferSize, fpSource);
2093
2.20k
        if (nRead < nBufferSize && VSIFErrorL(fpSource))
2094
0
        {
2095
0
            CPLError(
2096
0
                CE_Failure, CPLE_FileIO,
2097
0
                "Copying of %s to %s failed: error while reading source file",
2098
0
                pszSource, pszTarget);
2099
0
            ret = -1;
2100
0
            break;
2101
0
        }
2102
2.20k
        if (nRead > 0)
2103
2.20k
        {
2104
2.20k
            const size_t nWritten = VSIFWriteL(&abyBuffer[0], 1, nRead, fpOut);
2105
2.20k
            if (nWritten != nRead)
2106
0
            {
2107
0
                CPLError(CE_Failure, CPLE_FileIO,
2108
0
                         "Copying of %s to %s failed: error while writing into "
2109
0
                         "target file",
2110
0
                         pszSource, pszTarget);
2111
0
                ret = -1;
2112
0
                break;
2113
0
            }
2114
2.20k
            nOffset += nRead;
2115
2.20k
            if (pProgressFunc &&
2116
2.20k
                !pProgressFunc(
2117
0
                    nSourceSize == 0 ? 1.0
2118
0
                    : nSourceSize > 0 &&
2119
0
                            nSourceSize != static_cast<vsi_l_offset>(-1)
2120
0
                        ? double(nOffset) / nSourceSize
2121
0
                        : 0.0,
2122
0
                    !osMsg.empty() ? osMsg.c_str() : nullptr, pProgressData))
2123
0
            {
2124
0
                ret = -1;
2125
0
                break;
2126
0
            }
2127
2.20k
        }
2128
2.20k
        if (nRead < nBufferSize)
2129
2.12k
        {
2130
2.12k
            break;
2131
2.12k
        }
2132
2.20k
    }
2133
2134
2.12k
    if (nSourceSize != static_cast<vsi_l_offset>(-1) && nOffset != nSourceSize)
2135
0
    {
2136
0
        CPLError(CE_Failure, CPLE_FileIO,
2137
0
                 "Copying of %s to %s failed: %" PRIu64 " bytes were copied "
2138
0
                 "whereas %" PRIu64 " were expected",
2139
0
                 pszSource, pszTarget, static_cast<uint64_t>(nOffset),
2140
0
                 static_cast<uint64_t>(nSourceSize));
2141
0
        ret = -1;
2142
0
    }
2143
2144
2.12k
    if (VSIFCloseL(fpOut) != 0)
2145
0
    {
2146
0
        ret = -1;
2147
0
    }
2148
2149
2.12k
    if (ret != 0)
2150
0
        VSIUnlink(pszTarget);
2151
2152
2.12k
    return ret;
2153
2.12k
}
2154
2155
/************************************************************************/
2156
/*                       CopyFileRestartable()                          */
2157
/************************************************************************/
2158
2159
int VSIFilesystemHandler::CopyFileRestartable(
2160
    const char *pszSource, const char *pszTarget,
2161
    const char * /* pszInputPayload */, char **ppszOutputPayload,
2162
    CSLConstList papszOptions, GDALProgressFunc pProgressFunc,
2163
    void *pProgressData)
2164
0
{
2165
0
    *ppszOutputPayload = nullptr;
2166
0
    return CopyFile(pszSource, pszTarget, nullptr,
2167
0
                    static_cast<vsi_l_offset>(-1), papszOptions, pProgressFunc,
2168
0
                    pProgressData);
2169
0
}
2170
2171
/************************************************************************/
2172
/*                               Sync()                                 */
2173
/************************************************************************/
2174
2175
bool VSIFilesystemHandler::Sync(const char *pszSource, const char *pszTarget,
2176
                                const char *const *papszOptions,
2177
                                GDALProgressFunc pProgressFunc,
2178
                                void *pProgressData, char ***ppapszOutputs)
2179
0
{
2180
0
    const char SOURCE_SEP = VSIGetDirectorySeparator(pszSource)[0];
2181
2182
0
    if (ppapszOutputs)
2183
0
    {
2184
0
        *ppapszOutputs = nullptr;
2185
0
    }
2186
2187
0
    VSIStatBufL sSource;
2188
0
    CPLString osSource(pszSource);
2189
0
    CPLString osSourceWithoutSlash(pszSource);
2190
0
    if (osSourceWithoutSlash.back() == '/' ||
2191
0
        osSourceWithoutSlash.back() == '\\')
2192
0
    {
2193
0
        osSourceWithoutSlash.pop_back();
2194
0
    }
2195
0
    if (VSIStatL(osSourceWithoutSlash, &sSource) < 0)
2196
0
    {
2197
0
        CPLError(CE_Failure, CPLE_FileIO, "%s does not exist", pszSource);
2198
0
        return false;
2199
0
    }
2200
2201
0
    if (VSI_ISDIR(sSource.st_mode))
2202
0
    {
2203
0
        std::string osTargetDir(pszTarget);
2204
0
        if (osSource.back() != '/' && osSource.back() != '\\')
2205
0
        {
2206
0
            osTargetDir = CPLFormFilenameSafe(
2207
0
                osTargetDir.c_str(), CPLGetFilename(pszSource), nullptr);
2208
0
        }
2209
2210
0
        VSIStatBufL sTarget;
2211
0
        bool ret = true;
2212
0
        if (VSIStatL(osTargetDir.c_str(), &sTarget) < 0)
2213
0
        {
2214
0
            if (VSIMkdirRecursive(osTargetDir.c_str(), 0755) < 0)
2215
0
            {
2216
0
                CPLError(CE_Failure, CPLE_FileIO, "Cannot create directory %s",
2217
0
                         osTargetDir.c_str());
2218
0
                return false;
2219
0
            }
2220
0
        }
2221
2222
0
        if (!CPLFetchBool(papszOptions, "STOP_ON_DIR", false))
2223
0
        {
2224
0
            CPLStringList aosChildOptions(CSLDuplicate(papszOptions));
2225
0
            if (!CPLFetchBool(papszOptions, "RECURSIVE", true))
2226
0
            {
2227
0
                aosChildOptions.SetNameValue("RECURSIVE", nullptr);
2228
0
                aosChildOptions.AddString("STOP_ON_DIR=TRUE");
2229
0
            }
2230
2231
0
            char **papszSrcFiles = VSIReadDir(osSourceWithoutSlash);
2232
0
            int nFileCount = 0;
2233
0
            for (auto iter = papszSrcFiles; iter && *iter; ++iter)
2234
0
            {
2235
0
                if (strcmp(*iter, ".") != 0 && strcmp(*iter, "..") != 0)
2236
0
                {
2237
0
                    nFileCount++;
2238
0
                }
2239
0
            }
2240
0
            int iFile = 0;
2241
0
            const int nDenom = std::max(1, nFileCount);
2242
0
            for (auto iter = papszSrcFiles; iter && *iter; ++iter, ++iFile)
2243
0
            {
2244
0
                if (strcmp(*iter, ".") == 0 || strcmp(*iter, "..") == 0)
2245
0
                {
2246
0
                    continue;
2247
0
                }
2248
0
                const std::string osSubSource(CPLFormFilenameSafe(
2249
0
                    osSourceWithoutSlash.c_str(), *iter, nullptr));
2250
0
                const std::string osSubTarget(
2251
0
                    CPLFormFilenameSafe(osTargetDir.c_str(), *iter, nullptr));
2252
0
                void *pScaledProgress = GDALCreateScaledProgress(
2253
0
                    double(iFile) / nDenom, double(iFile + 1) / nDenom,
2254
0
                    pProgressFunc, pProgressData);
2255
0
                ret = Sync((osSubSource + SOURCE_SEP).c_str(),
2256
0
                           osSubTarget.c_str(), aosChildOptions.List(),
2257
0
                           GDALScaledProgress, pScaledProgress, nullptr);
2258
0
                GDALDestroyScaledProgress(pScaledProgress);
2259
0
                if (!ret)
2260
0
                {
2261
0
                    break;
2262
0
                }
2263
0
            }
2264
0
            CSLDestroy(papszSrcFiles);
2265
0
        }
2266
0
        return ret;
2267
0
    }
2268
2269
0
    VSIStatBufL sTarget;
2270
0
    std::string osTarget(pszTarget);
2271
0
    if (VSIStatL(osTarget.c_str(), &sTarget) == 0)
2272
0
    {
2273
0
        bool bTargetIsFile = true;
2274
0
        if (VSI_ISDIR(sTarget.st_mode))
2275
0
        {
2276
0
            osTarget = CPLFormFilenameSafe(osTarget.c_str(),
2277
0
                                           CPLGetFilename(pszSource), nullptr);
2278
0
            bTargetIsFile = VSIStatL(osTarget.c_str(), &sTarget) == 0 &&
2279
0
                            !CPL_TO_BOOL(VSI_ISDIR(sTarget.st_mode));
2280
0
        }
2281
0
        if (bTargetIsFile)
2282
0
        {
2283
0
            if (sSource.st_size == sTarget.st_size &&
2284
0
                sSource.st_mtime == sTarget.st_mtime && sSource.st_mtime != 0)
2285
0
            {
2286
0
                CPLDebug("VSI",
2287
0
                         "%s and %s have same size and modification "
2288
0
                         "date. Skipping copying",
2289
0
                         osSourceWithoutSlash.c_str(), osTarget.c_str());
2290
0
                return true;
2291
0
            }
2292
0
        }
2293
0
    }
2294
2295
0
    VSILFILE *fpIn = VSIFOpenExL(osSourceWithoutSlash, "rb", TRUE);
2296
0
    if (fpIn == nullptr)
2297
0
    {
2298
0
        CPLError(CE_Failure, CPLE_FileIO, "Cannot open %s",
2299
0
                 osSourceWithoutSlash.c_str());
2300
0
        return false;
2301
0
    }
2302
2303
0
    VSILFILE *fpOut = VSIFOpenExL(osTarget.c_str(), "wb", TRUE);
2304
0
    if (fpOut == nullptr)
2305
0
    {
2306
0
        CPLError(CE_Failure, CPLE_FileIO, "Cannot create %s", osTarget.c_str());
2307
0
        VSIFCloseL(fpIn);
2308
0
        return false;
2309
0
    }
2310
2311
0
    bool ret = true;
2312
0
    constexpr size_t nBufferSize = 10 * 4096;
2313
0
    std::vector<GByte> abyBuffer(nBufferSize, 0);
2314
0
    GUIntBig nOffset = 0;
2315
0
    CPLString osMsg;
2316
0
    osMsg.Printf("Copying of %s", osSourceWithoutSlash.c_str());
2317
0
    while (true)
2318
0
    {
2319
0
        size_t nRead = VSIFReadL(&abyBuffer[0], 1, nBufferSize, fpIn);
2320
0
        size_t nWritten = VSIFWriteL(&abyBuffer[0], 1, nRead, fpOut);
2321
0
        if (nWritten != nRead)
2322
0
        {
2323
0
            CPLError(CE_Failure, CPLE_FileIO, "Copying of %s to %s failed",
2324
0
                     osSourceWithoutSlash.c_str(), osTarget.c_str());
2325
0
            ret = false;
2326
0
            break;
2327
0
        }
2328
0
        nOffset += nRead;
2329
0
        if (pProgressFunc && !pProgressFunc(double(nOffset) / sSource.st_size,
2330
0
                                            osMsg.c_str(), pProgressData))
2331
0
        {
2332
0
            ret = false;
2333
0
            break;
2334
0
        }
2335
0
        if (nRead < nBufferSize)
2336
0
        {
2337
0
            break;
2338
0
        }
2339
0
    }
2340
2341
0
    VSIFCloseL(fpIn);
2342
0
    if (VSIFCloseL(fpOut) != 0)
2343
0
    {
2344
0
        ret = false;
2345
0
    }
2346
0
    return ret;
2347
0
}
2348
2349
/************************************************************************/
2350
/*                  VSIVirtualHandleOnlyVisibleAtCloseTime()            */
2351
/************************************************************************/
2352
2353
class VSIVirtualHandleOnlyVisibleAtCloseTime final : public VSIProxyFileHandle
2354
{
2355
    const std::string m_osTargetName;
2356
    const std::string m_osTmpName;
2357
    bool m_bAlreadyClosed = false;
2358
    bool m_bCancelCreation = false;
2359
2360
  public:
2361
    VSIVirtualHandleOnlyVisibleAtCloseTime(
2362
        VSIVirtualHandleUniquePtr &&nativeHandle,
2363
        const std::string &osTargetName, const std::string &osTmpName)
2364
0
        : VSIProxyFileHandle(std::move(nativeHandle)),
2365
0
          m_osTargetName(osTargetName), m_osTmpName(osTmpName)
2366
0
    {
2367
0
    }
2368
2369
    ~VSIVirtualHandleOnlyVisibleAtCloseTime()
2370
0
    {
2371
0
        VSIVirtualHandleOnlyVisibleAtCloseTime::Close();
2372
0
    }
2373
2374
    void CancelCreation() override
2375
0
    {
2376
0
        VSIProxyFileHandle::CancelCreation();
2377
0
        m_bCancelCreation = true;
2378
0
    }
2379
2380
    int Close() override;
2381
};
2382
2383
int VSIVirtualHandleOnlyVisibleAtCloseTime::Close()
2384
0
{
2385
0
    if (m_bAlreadyClosed)
2386
0
        return 0;
2387
0
    m_bAlreadyClosed = true;
2388
0
    int ret = VSIProxyFileHandle::Close();
2389
0
    if (ret != 0)
2390
0
        return ret;
2391
0
    return m_bCancelCreation
2392
0
               ? VSIUnlink(m_osTmpName.c_str())
2393
0
               : VSIRename(m_osTmpName.c_str(), m_osTargetName.c_str());
2394
0
}
2395
2396
/************************************************************************/
2397
/*                       CreateOnlyVisibleAtCloseTime()                 */
2398
/************************************************************************/
2399
2400
VSIVirtualHandle *VSIFilesystemHandler::CreateOnlyVisibleAtCloseTime(
2401
    const char *pszFilename, bool bEmulationAllowed, CSLConstList papszOptions)
2402
0
{
2403
0
    if (!bEmulationAllowed)
2404
0
        return nullptr;
2405
2406
0
    const std::string tmpName = std::string(pszFilename).append(".tmp");
2407
0
    VSIVirtualHandleUniquePtr nativeHandle(
2408
0
        Open(tmpName.c_str(), "wb+", true, papszOptions));
2409
0
    if (!nativeHandle)
2410
0
        return nullptr;
2411
0
    return std::make_unique<VSIVirtualHandleOnlyVisibleAtCloseTime>(
2412
0
               std::move(nativeHandle), pszFilename, tmpName)
2413
0
        .release();
2414
0
}
2415
2416
/************************************************************************/
2417
/*                            VSIDIREntry()                             */
2418
/************************************************************************/
2419
2420
VSIDIREntry::VSIDIREntry()
2421
113k
    : pszName(nullptr), nMode(0), nSize(0), nMTime(0), bModeKnown(false),
2422
113k
      bSizeKnown(false), bMTimeKnown(false), papszExtra(nullptr)
2423
113k
{
2424
113k
}
2425
2426
/************************************************************************/
2427
/*                            VSIDIREntry()                             */
2428
/************************************************************************/
2429
2430
VSIDIREntry::VSIDIREntry(const VSIDIREntry &other)
2431
0
    : pszName(VSIStrdup(other.pszName)), nMode(other.nMode), nSize(other.nSize),
2432
0
      nMTime(other.nMTime), bModeKnown(other.bModeKnown),
2433
0
      bSizeKnown(other.bSizeKnown), bMTimeKnown(other.bMTimeKnown),
2434
0
      papszExtra(CSLDuplicate(other.papszExtra))
2435
0
{
2436
0
}
2437
2438
/************************************************************************/
2439
/*                           ~VSIDIREntry()                             */
2440
/************************************************************************/
2441
2442
VSIDIREntry::~VSIDIREntry()
2443
113k
{
2444
113k
    CPLFree(pszName);
2445
113k
    CSLDestroy(papszExtra);
2446
113k
}
2447
2448
/************************************************************************/
2449
/*                              ~VSIDIR()                               */
2450
/************************************************************************/
2451
2452
VSIDIR::~VSIDIR()
2453
119k
{
2454
119k
}
2455
2456
/************************************************************************/
2457
/*                            VSIDIRGeneric                             */
2458
/************************************************************************/
2459
2460
namespace
2461
{
2462
struct VSIDIRGeneric : public VSIDIR
2463
{
2464
    CPLString osRootPath{};
2465
    CPLString osBasePath{};
2466
    char **papszContent = nullptr;
2467
    int nRecurseDepth = 0;
2468
    int nPos = 0;
2469
    VSIDIREntry entry{};
2470
    std::vector<VSIDIRGeneric *> aoStackSubDir{};
2471
    VSIFilesystemHandler *poFS = nullptr;
2472
    std::string m_osFilterPrefix{};
2473
2474
103k
    explicit VSIDIRGeneric(VSIFilesystemHandler *poFSIn) : poFS(poFSIn)
2475
103k
    {
2476
103k
    }
2477
2478
    ~VSIDIRGeneric();
2479
2480
    const VSIDIREntry *NextDirEntry() override;
2481
2482
    VSIDIRGeneric(const VSIDIRGeneric &) = delete;
2483
    VSIDIRGeneric &operator=(const VSIDIRGeneric &) = delete;
2484
};
2485
2486
/************************************************************************/
2487
/*                         ~VSIDIRGeneric()                             */
2488
/************************************************************************/
2489
2490
VSIDIRGeneric::~VSIDIRGeneric()
2491
103k
{
2492
104k
    while (!aoStackSubDir.empty())
2493
1.08k
    {
2494
1.08k
        delete aoStackSubDir.back();
2495
1.08k
        aoStackSubDir.pop_back();
2496
1.08k
    }
2497
103k
    CSLDestroy(papszContent);
2498
103k
}
2499
2500
}  // namespace
2501
2502
/************************************************************************/
2503
/*                            OpenDir()                                 */
2504
/************************************************************************/
2505
2506
VSIDIR *VSIFilesystemHandler::OpenDir(const char *pszPath, int nRecurseDepth,
2507
                                      const char *const *papszOptions)
2508
103k
{
2509
103k
    char **papszContent = VSIReadDir(pszPath);
2510
103k
    VSIStatBufL sStatL;
2511
103k
    if (papszContent == nullptr &&
2512
103k
        (VSIStatL(pszPath, &sStatL) != 0 || !VSI_ISDIR(sStatL.st_mode)))
2513
150
    {
2514
150
        return nullptr;
2515
150
    }
2516
103k
    VSIDIRGeneric *dir = new VSIDIRGeneric(this);
2517
103k
    dir->osRootPath = pszPath;
2518
103k
    if (!dir->osRootPath.empty() &&
2519
103k
        (dir->osRootPath.back() == '/' || dir->osRootPath.back() == '\\'))
2520
4
        dir->osRootPath.pop_back();
2521
103k
    dir->nRecurseDepth = nRecurseDepth;
2522
103k
    dir->papszContent = papszContent;
2523
103k
    dir->m_osFilterPrefix = CSLFetchNameValueDef(papszOptions, "PREFIX", "");
2524
103k
    return dir;
2525
103k
}
2526
2527
/************************************************************************/
2528
/*                           NextDirEntry()                             */
2529
/************************************************************************/
2530
2531
const VSIDIREntry *VSIDIRGeneric::NextDirEntry()
2532
1.36M
{
2533
1.36M
    const char SEP = VSIGetDirectorySeparator(osRootPath.c_str())[0];
2534
2535
1.36M
begin:
2536
1.36M
    if (VSI_ISDIR(entry.nMode) && nRecurseDepth != 0)
2537
25.3k
    {
2538
25.3k
        CPLString osCurFile(osRootPath);
2539
25.3k
        if (!osCurFile.empty())
2540
25.3k
            osCurFile += SEP;
2541
25.3k
        osCurFile += entry.pszName;
2542
25.3k
        auto subdir =
2543
25.3k
            static_cast<VSIDIRGeneric *>(poFS->VSIFilesystemHandler::OpenDir(
2544
25.3k
                osCurFile, nRecurseDepth - 1, nullptr));
2545
25.3k
        if (subdir)
2546
25.3k
        {
2547
25.3k
            subdir->osRootPath = osRootPath;
2548
25.3k
            subdir->osBasePath = entry.pszName;
2549
25.3k
            subdir->m_osFilterPrefix = m_osFilterPrefix;
2550
25.3k
            aoStackSubDir.push_back(subdir);
2551
25.3k
        }
2552
25.3k
        entry.nMode = 0;
2553
25.3k
    }
2554
2555
1.39M
    while (!aoStackSubDir.empty())
2556
1.16M
    {
2557
1.16M
        auto l_entry = aoStackSubDir.back()->NextDirEntry();
2558
1.16M
        if (l_entry)
2559
1.13M
        {
2560
1.13M
            return l_entry;
2561
1.13M
        }
2562
24.2k
        delete aoStackSubDir.back();
2563
24.2k
        aoStackSubDir.pop_back();
2564
24.2k
    }
2565
2566
228k
    if (papszContent == nullptr)
2567
3.83k
    {
2568
3.83k
        return nullptr;
2569
3.83k
    }
2570
2571
225k
    while (true)
2572
225k
    {
2573
225k
        if (!papszContent[nPos])
2574
98.2k
        {
2575
98.2k
            return nullptr;
2576
98.2k
        }
2577
        // Skip . and ..entries
2578
127k
        if (papszContent[nPos][0] == '.' &&
2579
127k
            (papszContent[nPos][1] == '\0' ||
2580
5.99k
             (papszContent[nPos][1] == '.' && papszContent[nPos][2] == '\0')))
2581
273
        {
2582
273
            nPos++;
2583
273
        }
2584
126k
        else
2585
126k
        {
2586
126k
            CPLFree(entry.pszName);
2587
126k
            CPLString osName(osBasePath);
2588
126k
            if (!osName.empty())
2589
28.2k
                osName += SEP;
2590
126k
            osName += papszContent[nPos];
2591
126k
            nPos++;
2592
2593
126k
            entry.pszName = CPLStrdup(osName);
2594
126k
            entry.nMode = 0;
2595
126k
            CPLString osCurFile(osRootPath);
2596
126k
            if (!osCurFile.empty())
2597
126k
                osCurFile += SEP;
2598
126k
            osCurFile += entry.pszName;
2599
2600
126k
            const auto StatFile = [&osCurFile, this]()
2601
126k
            {
2602
126k
                VSIStatBufL sStatL;
2603
126k
                if (VSIStatL(osCurFile, &sStatL) == 0)
2604
126k
                {
2605
126k
                    entry.nMode = sStatL.st_mode;
2606
126k
                    entry.nSize = sStatL.st_size;
2607
126k
                    entry.nMTime = sStatL.st_mtime;
2608
126k
                    entry.bModeKnown = true;
2609
126k
                    entry.bSizeKnown = true;
2610
126k
                    entry.bMTimeKnown = true;
2611
126k
                }
2612
199
                else
2613
199
                {
2614
199
                    entry.nMode = 0;
2615
199
                    entry.nSize = 0;
2616
199
                    entry.nMTime = 0;
2617
199
                    entry.bModeKnown = false;
2618
199
                    entry.bSizeKnown = false;
2619
199
                    entry.bMTimeKnown = false;
2620
199
                }
2621
126k
            };
2622
2623
126k
            if (!m_osFilterPrefix.empty() &&
2624
126k
                m_osFilterPrefix.size() > osName.size())
2625
0
            {
2626
0
                if (STARTS_WITH(m_osFilterPrefix.c_str(), osName.c_str()) &&
2627
0
                    m_osFilterPrefix[osName.size()] == SEP)
2628
0
                {
2629
0
                    StatFile();
2630
0
                    if (VSI_ISDIR(entry.nMode))
2631
0
                    {
2632
0
                        goto begin;
2633
0
                    }
2634
0
                }
2635
0
                continue;
2636
0
            }
2637
126k
            if (!m_osFilterPrefix.empty() &&
2638
126k
                !STARTS_WITH(osName.c_str(), m_osFilterPrefix.c_str()))
2639
0
            {
2640
0
                continue;
2641
0
            }
2642
2643
126k
            StatFile();
2644
2645
126k
            break;
2646
126k
        }
2647
127k
    }
2648
2649
126k
    return &(entry);
2650
224k
}
2651
2652
/************************************************************************/
2653
/*                           UnlinkBatch()                              */
2654
/************************************************************************/
2655
2656
int *VSIFilesystemHandler::UnlinkBatch(CSLConstList papszFiles)
2657
0
{
2658
0
    int *panRet =
2659
0
        static_cast<int *>(CPLMalloc(sizeof(int) * CSLCount(papszFiles)));
2660
0
    for (int i = 0; papszFiles && papszFiles[i]; ++i)
2661
0
    {
2662
0
        panRet[i] = VSIUnlink(papszFiles[i]) == 0;
2663
0
    }
2664
0
    return panRet;
2665
0
}
2666
2667
/************************************************************************/
2668
/*                          RmdirRecursive()                            */
2669
/************************************************************************/
2670
2671
int VSIFilesystemHandler::RmdirRecursive(const char *pszDirname)
2672
0
{
2673
0
    CPLString osDirnameWithoutEndSlash(pszDirname);
2674
0
    if (!osDirnameWithoutEndSlash.empty() &&
2675
0
        (osDirnameWithoutEndSlash.back() == '/' ||
2676
0
         osDirnameWithoutEndSlash.back() == '\\'))
2677
0
    {
2678
0
        osDirnameWithoutEndSlash.pop_back();
2679
0
    }
2680
2681
0
    const char SEP = VSIGetDirectorySeparator(pszDirname)[0];
2682
2683
0
    CPLStringList aosOptions;
2684
0
    auto poDir =
2685
0
        std::unique_ptr<VSIDIR>(OpenDir(pszDirname, -1, aosOptions.List()));
2686
0
    if (!poDir)
2687
0
        return -1;
2688
0
    std::vector<std::string> aosDirs;
2689
0
    while (true)
2690
0
    {
2691
0
        auto entry = poDir->NextDirEntry();
2692
0
        if (!entry)
2693
0
            break;
2694
2695
0
        CPLString osFilename(osDirnameWithoutEndSlash + SEP + entry->pszName);
2696
0
        if ((entry->nMode & S_IFDIR))
2697
0
        {
2698
0
            aosDirs.push_back(std::move(osFilename));
2699
0
        }
2700
0
        else
2701
0
        {
2702
0
            if (VSIUnlink(osFilename) != 0)
2703
0
                return -1;
2704
0
        }
2705
0
    }
2706
2707
    // Sort in reverse order, so that inner-most directories are deleted first
2708
0
    std::sort(aosDirs.begin(), aosDirs.end(),
2709
0
              [](const std::string &a, const std::string &b) { return a > b; });
2710
2711
0
    for (const auto &osDir : aosDirs)
2712
0
    {
2713
0
        if (VSIRmdir(osDir.c_str()) != 0)
2714
0
            return -1;
2715
0
    }
2716
2717
0
    return VSIRmdir(pszDirname);
2718
0
}
2719
2720
/************************************************************************/
2721
/*                          GetFileMetadata()                           */
2722
/************************************************************************/
2723
2724
char **VSIFilesystemHandler::GetFileMetadata(const char * /* pszFilename*/,
2725
                                             const char * /*pszDomain*/,
2726
                                             CSLConstList /*papszOptions*/)
2727
0
{
2728
0
    return nullptr;
2729
0
}
2730
2731
/************************************************************************/
2732
/*                          SetFileMetadata()                           */
2733
/************************************************************************/
2734
2735
bool VSIFilesystemHandler::SetFileMetadata(const char * /* pszFilename*/,
2736
                                           CSLConstList /* papszMetadata */,
2737
                                           const char * /* pszDomain */,
2738
                                           CSLConstList /* papszOptions */)
2739
0
{
2740
0
    CPLError(CE_Failure, CPLE_NotSupported, "SetFileMetadata() not supported");
2741
0
    return false;
2742
0
}
2743
2744
#endif
2745
2746
/************************************************************************/
2747
/*                             VSIFOpenExL()                            */
2748
/************************************************************************/
2749
2750
/**
2751
 * \brief Open/create file.
2752
 *
2753
 * This function opens (or creates) a file with the desired access.
2754
 * Binary access is always implied and
2755
 * the "b" does not need to be included in the pszAccess string.
2756
 *
2757
 * Note that the "VSILFILE *" returned by this function is
2758
 * *NOT* a standard C library FILE *, and cannot be used with any functions
2759
 * other than the "VSI*L" family of functions.  They aren't "real" FILE objects.
2760
 *
2761
 * On windows it is possible to define the configuration option
2762
 * GDAL_FILE_IS_UTF8 to have pszFilename treated as being in the local
2763
 * encoding instead of UTF-8, restoring the pre-1.8.0 behavior of VSIFOpenL().
2764
 *
2765
 * This method goes through the VSIFileHandler virtualization and may
2766
 * work on unusual filesystems such as in memory.
2767
 *
2768
 * Analog of the POSIX fopen() function.
2769
 *
2770
 * @param pszFilename the file to open.  UTF-8 encoded.
2771
 * @param pszAccess access requested (i.e. "r", "r+", "w")
2772
 * @param bSetError flag determining whether or not this open call
2773
 * should set VSIErrors on failure.
2774
 *
2775
 * @return NULL on failure, or the file handle.
2776
 *
2777
 * @since GDAL 2.1
2778
 */
2779
2780
VSILFILE *VSIFOpenExL(const char *pszFilename, const char *pszAccess,
2781
                      int bSetError)
2782
2783
30.4M
{
2784
30.4M
    return VSIFOpenEx2L(pszFilename, pszAccess, bSetError, nullptr);
2785
30.4M
}
2786
2787
/************************************************************************/
2788
/*                            VSIFOpenEx2L()                            */
2789
/************************************************************************/
2790
2791
/**
2792
 * \brief Open/create file.
2793
 *
2794
 * This function opens (or creates) a file with the desired access.
2795
 * Binary access is always implied and
2796
 * the "b" does not need to be included in the pszAccess string.
2797
 *
2798
 * Note that the "VSILFILE *" returned by this function is
2799
 * *NOT* a standard C library FILE *, and cannot be used with any functions
2800
 * other than the "VSI*L" family of functions.  They aren't "real" FILE objects.
2801
 *
2802
 * On windows it is possible to define the configuration option
2803
 * GDAL_FILE_IS_UTF8 to have pszFilename treated as being in the local
2804
 * encoding instead of UTF-8, restoring the pre-1.8.0 behavior of VSIFOpenL().
2805
 *
2806
 * This method goes through the VSIFileHandler virtualization and may
2807
 * work on unusual filesystems such as in memory.
2808
 *
2809
 * The following options are supported:
2810
 * <ul>
2811
 * <li>MIME headers such as Content-Type and Content-Encoding
2812
 * are supported for the /vsis3/, /vsigs/, /vsiaz/, /vsiadls/ file systems.</li>
2813
 * <li>DISABLE_READDIR_ON_OPEN=YES/NO (GDAL >= 3.6) for /vsicurl/ and other
2814
 * network-based file systems. By default, directory file listing is done,
2815
 * unless YES is specified.</li>
2816
 * <li>WRITE_THROUGH=YES (GDAL >= 3.8) for the Windows regular files to
2817
 * set the FILE_FLAG_WRITE_THROUGH flag to the CreateFile() function. In that
2818
 * mode, the data is written to the system cache but is flushed to disk without
2819
 * delay.</li>
2820
 * </ul>
2821
 *
2822
 * Options specifics to /vsis3/, /vsigs/, /vsioss/ and /vsiaz/ in "w" mode:
2823
 * <ul>
2824
 * <li>CHUNK_SIZE=val in MiB. (GDAL >= 3.10) Size of a block. Default is 50 MiB.
2825
 * For /vsis3/, /vsigz/, /vsioss/, it can be up to 5000 MiB.
2826
 * For /vsiaz/, only taken into account when BLOB_TYPE=BLOCK. It can be up to 4000 MiB.
2827
 * </li>
2828
 * </ul>
2829
 *
2830
 * Options specifics to /vsiaz/ in "w" mode:
2831
 * <ul>
2832
 * <li>BLOB_TYPE=APPEND/BLOCK. (GDAL >= 3.10) Type of blob. Defaults to APPEND.
2833
 * Append blocks are limited to 195 GiB
2834
 * (however if the file size is below 4 MiB, a block blob will be created in a
2835
 * single PUT operation)
2836
 * </li>
2837
 * </ul>
2838
 *
2839
 * Analog of the POSIX fopen() function.
2840
 *
2841
 * @param pszFilename the file to open.  UTF-8 encoded.
2842
 * @param pszAccess access requested (i.e. "r", "r+", "w")
2843
 * @param bSetError flag determining whether or not this open call
2844
 * should set VSIErrors on failure.
2845
 * @param papszOptions NULL or NULL-terminated list of strings. The content is
2846
 *                     highly file system dependent.
2847
 *
2848
 *
2849
 * @return NULL on failure, or the file handle.
2850
 *
2851
 * @since GDAL 3.3
2852
 */
2853
2854
VSILFILE *VSIFOpenEx2L(const char *pszFilename, const char *pszAccess,
2855
                       int bSetError, CSLConstList papszOptions)
2856
2857
31.9M
{
2858
    // Too long filenames can cause excessive memory allocation due to
2859
    // recursion in some filesystem handlers
2860
31.9M
    constexpr size_t knMaxPath = 8192;
2861
31.9M
    if (CPLStrnlen(pszFilename, knMaxPath) == knMaxPath)
2862
9.75k
        return nullptr;
2863
2864
31.9M
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
2865
2866
31.9M
    VSILFILE *fp = poFSHandler->Open(pszFilename, pszAccess,
2867
31.9M
                                     CPL_TO_BOOL(bSetError), papszOptions);
2868
2869
31.9M
    VSIDebug4("VSIFOpenEx2L(%s,%s,%d) = %p", pszFilename, pszAccess, bSetError,
2870
31.9M
              fp);
2871
2872
31.9M
    return fp;
2873
31.9M
}
2874
2875
/************************************************************************/
2876
/*                             VSIFCloseL()                             */
2877
/************************************************************************/
2878
2879
/**
2880
 * \fn VSIVirtualHandle::Close()
2881
 * \brief Close file.
2882
 *
2883
 * This function closes the indicated file.
2884
 *
2885
 * This method goes through the VSIFileHandler virtualization and may
2886
 * work on unusual filesystems such as in memory.
2887
 *
2888
 * Analog of the POSIX fclose() function.
2889
 *
2890
 * @return 0 on success or -1 on failure.
2891
 */
2892
2893
/**
2894
 * \brief Close file.
2895
 *
2896
 * This function closes the indicated file.
2897
 *
2898
 * This method goes through the VSIFileHandler virtualization and may
2899
 * work on unusual filesystems such as in memory.
2900
 *
2901
 * Analog of the POSIX fclose() function.
2902
 *
2903
 * @param fp file handle opened with VSIFOpenL().  Passing a nullptr produces
2904
 * undefined behavior.
2905
 *
2906
 * @return 0 on success or -1 on failure.
2907
 */
2908
2909
int VSIFCloseL(VSILFILE *fp)
2910
2911
21.7M
{
2912
21.7M
    VSIDebug1("VSIFCloseL(%p)", fp);
2913
2914
21.7M
    const int nResult = fp->Close();
2915
2916
21.7M
    delete fp;
2917
2918
21.7M
    return nResult;
2919
21.7M
}
2920
2921
/************************************************************************/
2922
/*                             VSIFSeekL()                              */
2923
/************************************************************************/
2924
2925
/**
2926
 * \fn int VSIVirtualHandle::Seek( vsi_l_offset nOffset, int nWhence )
2927
 * \brief Seek to requested offset.
2928
 *
2929
 * Seek to the desired offset (nOffset) in the indicated 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 fseek() call.
2935
 *
2936
 * Caution: vsi_l_offset is a unsigned type, so SEEK_CUR can only be used
2937
 * for positive seek. If negative seek is needed, use
2938
 * handle->Seek( handle->Tell() + negative_offset, SEEK_SET ).
2939
 *
2940
 * @param nOffset offset in bytes.
2941
 * @param nWhence one of SEEK_SET, SEEK_CUR or SEEK_END.
2942
 *
2943
 * @return 0 on success or -1 one failure.
2944
 */
2945
2946
/**
2947
 * \brief Seek to requested offset.
2948
 *
2949
 * Seek to the desired offset (nOffset) in the indicated file.
2950
 *
2951
 * This method goes through the VSIFileHandler virtualization and may
2952
 * work on unusual filesystems such as in memory.
2953
 *
2954
 * Analog of the POSIX fseek() call.
2955
 *
2956
 * Caution: vsi_l_offset is a unsigned type, so SEEK_CUR can only be used
2957
 * for positive seek. If negative seek is needed, use
2958
 * VSIFSeekL( fp, VSIFTellL(fp) + negative_offset, SEEK_SET ).
2959
 *
2960
 * @param fp file handle opened with VSIFOpenL().
2961
 * @param nOffset offset in bytes.
2962
 * @param nWhence one of SEEK_SET, SEEK_CUR or SEEK_END.
2963
 *
2964
 * @return 0 on success or -1 one failure.
2965
 */
2966
2967
int VSIFSeekL(VSILFILE *fp, vsi_l_offset nOffset, int nWhence)
2968
2969
833M
{
2970
833M
    return fp->Seek(nOffset, nWhence);
2971
833M
}
2972
2973
/************************************************************************/
2974
/*                             VSIFTellL()                              */
2975
/************************************************************************/
2976
2977
/**
2978
 * \fn VSIVirtualHandle::Tell()
2979
 * \brief Tell current file offset.
2980
 *
2981
 * Returns the current file read/write offset in bytes from the beginning of
2982
 * the file.
2983
 *
2984
 * This method goes through the VSIFileHandler virtualization and may
2985
 * work on unusual filesystems such as in memory.
2986
 *
2987
 * Analog of the POSIX ftell() call.
2988
 *
2989
 * @return file offset in bytes.
2990
 */
2991
2992
/**
2993
 * \brief Tell current file offset.
2994
 *
2995
 * Returns the current file read/write offset in bytes from the beginning of
2996
 * the file.
2997
 *
2998
 * This method goes through the VSIFileHandler virtualization and may
2999
 * work on unusual filesystems such as in memory.
3000
 *
3001
 * Analog of the POSIX ftell() call.
3002
 *
3003
 * @param fp file handle opened with VSIFOpenL().
3004
 *
3005
 * @return file offset in bytes.
3006
 */
3007
3008
vsi_l_offset VSIFTellL(VSILFILE *fp)
3009
3010
1.08G
{
3011
1.08G
    return fp->Tell();
3012
1.08G
}
3013
3014
/************************************************************************/
3015
/*                             VSIRewindL()                             */
3016
/************************************************************************/
3017
3018
/**
3019
 * \brief Rewind the file pointer to the beginning of the file.
3020
 *
3021
 * This is equivalent to VSIFSeekL( fp, 0, SEEK_SET )
3022
 *
3023
 * Analog of the POSIX rewind() call.
3024
 *
3025
 * @param fp file handle opened with VSIFOpenL().
3026
 */
3027
3028
void VSIRewindL(VSILFILE *fp)
3029
3030
1.97M
{
3031
1.97M
    CPL_IGNORE_RET_VAL(VSIFSeekL(fp, 0, SEEK_SET));
3032
1.97M
}
3033
3034
/************************************************************************/
3035
/*                             VSIFFlushL()                             */
3036
/************************************************************************/
3037
3038
/**
3039
 * \fn VSIVirtualHandle::Flush()
3040
 * \brief Flush pending writes to disk.
3041
 *
3042
 * For files in write or update mode and on filesystem types where it is
3043
 * applicable, all pending output on the file is flushed to the physical disk.
3044
 *
3045
 * This method goes through the VSIFileHandler virtualization and may
3046
 * work on unusual filesystems such as in memory.
3047
 *
3048
 * Analog of the POSIX fflush() call.
3049
 *
3050
 * On Windows regular files, this method does nothing, unless the
3051
 * VSI_FLUSH configuration option is set to YES (and only when the file has
3052
 * *not* been opened with the WRITE_THROUGH option).
3053
 *
3054
 * @return 0 on success or -1 on error.
3055
 */
3056
3057
/**
3058
 * \brief Flush pending writes to disk.
3059
 *
3060
 * For files in write or update mode and on filesystem types where it is
3061
 * applicable, all pending output on the file is flushed to the physical disk.
3062
 *
3063
 * This method goes through the VSIFileHandler virtualization and may
3064
 * work on unusual filesystems such as in memory.
3065
 *
3066
 * Analog of the POSIX fflush() call.
3067
 *
3068
 * On Windows regular files, this method does nothing, unless the
3069
 * VSI_FLUSH configuration option is set to YES (and only when the file has
3070
 * *not* been opened with the WRITE_THROUGH option).
3071
 *
3072
 * @param fp file handle opened with VSIFOpenL().
3073
 *
3074
 * @return 0 on success or -1 on error.
3075
 */
3076
3077
int VSIFFlushL(VSILFILE *fp)
3078
3079
247k
{
3080
247k
    return fp->Flush();
3081
247k
}
3082
3083
/************************************************************************/
3084
/*                             VSIFReadL()                              */
3085
/************************************************************************/
3086
3087
/**
3088
 * \fn VSIVirtualHandle::Read( void *pBuffer, size_t nSize, size_t nCount )
3089
 * \brief Read bytes from file.
3090
 *
3091
 * Reads nCount objects of nSize bytes from the indicated file at the
3092
 * current offset into the indicated buffer.
3093
 *
3094
 * This method goes through the VSIFileHandler virtualization and may
3095
 * work on unusual filesystems such as in memory.
3096
 *
3097
 * Analog of the POSIX fread() call.
3098
 *
3099
 * @param pBuffer the buffer into which the data should be read (at least
3100
 * nCount * nSize bytes in size.
3101
 * @param nSize size of objects to read in bytes.
3102
 * @param nCount number of objects to read.
3103
 *
3104
 * @return number of objects successfully read. If that number is less than
3105
 * nCount, VSIFEofL() or VSIFErrorL() can be used to determine the reason for
3106
 * the short read.
3107
 */
3108
3109
/**
3110
 * \brief Read bytes from file.
3111
 *
3112
 * Reads nCount objects of nSize bytes from the indicated file at the
3113
 * current offset into the indicated buffer.
3114
 *
3115
 * This method goes through the VSIFileHandler virtualization and may
3116
 * work on unusual filesystems such as in memory.
3117
 *
3118
 * Analog of the POSIX fread() call.
3119
 *
3120
 * @param pBuffer the buffer into which the data should be read (at least
3121
 * nCount * nSize bytes in size.
3122
 * @param nSize size of objects to read in bytes.
3123
 * @param nCount number of objects to read.
3124
 * @param fp file handle opened with VSIFOpenL().
3125
 *
3126
 * @return number of objects successfully read. If that number is less than
3127
 * nCount, VSIFEofL() or VSIFErrorL() can be used to determine the reason for
3128
 * the short read.
3129
 */
3130
3131
size_t VSIFReadL(void *pBuffer, size_t nSize, size_t nCount, VSILFILE *fp)
3132
3133
1.93G
{
3134
1.93G
    return fp->Read(pBuffer, nSize, nCount);
3135
1.93G
}
3136
3137
/************************************************************************/
3138
/*                       VSIFReadMultiRangeL()                          */
3139
/************************************************************************/
3140
3141
/**
3142
 * \fn VSIVirtualHandle::ReadMultiRange( int nRanges, void ** ppData,
3143
 *                                       const vsi_l_offset* panOffsets,
3144
 *                                       const size_t* panSizes )
3145
 * \brief Read several ranges of bytes from file.
3146
 *
3147
 * Reads nRanges objects of panSizes[i] bytes from the indicated file at the
3148
 * offset panOffsets[i] into the buffer ppData[i].
3149
 *
3150
 * Ranges must be sorted in ascending start offset, and must not overlap each
3151
 * other.
3152
 *
3153
 * This method goes through the VSIFileHandler virtualization and may
3154
 * work on unusual filesystems such as in memory or /vsicurl/.
3155
 *
3156
 * @param nRanges number of ranges to read.
3157
 * @param ppData array of nRanges buffer into which the data should be read
3158
 *               (ppData[i] must be at list panSizes[i] bytes).
3159
 * @param panOffsets array of nRanges offsets at which the data should be read.
3160
 * @param panSizes array of nRanges sizes of objects to read (in bytes).
3161
 *
3162
 * @return 0 in case of success, -1 otherwise.
3163
 * @since GDAL 1.9.0
3164
 */
3165
3166
/**
3167
 * \brief Read several ranges of bytes from file.
3168
 *
3169
 * Reads nRanges objects of panSizes[i] bytes from the indicated file at the
3170
 * offset panOffsets[i] into the buffer ppData[i].
3171
 *
3172
 * Ranges must be sorted in ascending start offset, and must not overlap each
3173
 * other.
3174
 *
3175
 * This method goes through the VSIFileHandler virtualization and may
3176
 * work on unusual filesystems such as in memory or /vsicurl/.
3177
 *
3178
 * @param nRanges number of ranges to read.
3179
 * @param ppData array of nRanges buffer into which the data should be read
3180
 *               (ppData[i] must be at list panSizes[i] bytes).
3181
 * @param panOffsets array of nRanges offsets at which the data should be read.
3182
 * @param panSizes array of nRanges sizes of objects to read (in bytes).
3183
 * @param fp file handle opened with VSIFOpenL().
3184
 *
3185
 * @return 0 in case of success, -1 otherwise.
3186
 * @since GDAL 1.9.0
3187
 */
3188
3189
int VSIFReadMultiRangeL(int nRanges, void **ppData,
3190
                        const vsi_l_offset *panOffsets, const size_t *panSizes,
3191
                        VSILFILE *fp)
3192
0
{
3193
0
    return fp->ReadMultiRange(nRanges, ppData, panOffsets, panSizes);
3194
0
}
3195
3196
/************************************************************************/
3197
/*                             VSIFWriteL()                             */
3198
/************************************************************************/
3199
3200
/**
3201
 * \fn VSIVirtualHandle::Write( const void *pBuffer,
3202
 *                              size_t nSize, size_t nCount )
3203
 * \brief Write bytes to file.
3204
 *
3205
 * Writes nCount objects of nSize bytes to the indicated file at the
3206
 * current offset into the indicated buffer.
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 fwrite() call.
3212
 *
3213
 * @param pBuffer the buffer from which the data should be written (at least
3214
 * nCount * nSize bytes in size.
3215
 * @param nSize size of objects to write in bytes.
3216
 * @param nCount number of objects to write.
3217
 *
3218
 * @return number of objects successfully written.
3219
 */
3220
3221
/**
3222
 * \brief Write bytes to file.
3223
 *
3224
 * Writes nCount objects of nSize bytes to the indicated file at the
3225
 * current offset into the indicated buffer.
3226
 *
3227
 * This method goes through the VSIFileHandler virtualization and may
3228
 * work on unusual filesystems such as in memory.
3229
 *
3230
 * Analog of the POSIX fwrite() call.
3231
 *
3232
 * @param pBuffer the buffer from which the data should be written (at least
3233
 * nCount * nSize bytes in size.
3234
 * @param nSize size of objects to write in bytes.
3235
 * @param nCount number of objects to write.
3236
 * @param fp file handle opened with VSIFOpenL().
3237
 *
3238
 * @return number of objects successfully written.
3239
 */
3240
3241
size_t VSIFWriteL(const void *pBuffer, size_t nSize, size_t nCount,
3242
                  VSILFILE *fp)
3243
3244
86.3M
{
3245
86.3M
    return fp->Write(pBuffer, nSize, nCount);
3246
86.3M
}
3247
3248
/************************************************************************/
3249
/*                              VSIFEofL()                              */
3250
/************************************************************************/
3251
3252
/**
3253
 * \fn VSIVirtualHandle::Eof()
3254
 * \brief Test for end of file.
3255
 *
3256
 * Returns TRUE (non-zero) if an end-of-file condition occurred during the
3257
 * previous read operation. The end-of-file flag is cleared by a successful
3258
 * VSIFSeekL() call, or a call to VSIFClearErrL().
3259
 *
3260
 * This method goes through the VSIFileHandler virtualization and may
3261
 * work on unusual filesystems such as in memory.
3262
 *
3263
 * Analog of the POSIX feof() call.
3264
 *
3265
 * @return TRUE if at EOF, else FALSE.
3266
 */
3267
3268
/**
3269
 * \brief Test for end of file.
3270
 *
3271
 * Returns TRUE (non-zero) if an end-of-file condition occurred during the
3272
 * previous read operation. The end-of-file flag is cleared by a successful
3273
 * VSIFSeekL() call, or a call to VSIFClearErrL().
3274
 *
3275
 * This method goes through the VSIFileHandler virtualization and may
3276
 * work on unusual filesystems such as in memory.
3277
 *
3278
 * Analog of the POSIX feof() call.
3279
 *
3280
 * @param fp file handle opened with VSIFOpenL().
3281
 *
3282
 * @return TRUE if at EOF, else FALSE.
3283
 */
3284
3285
int VSIFEofL(VSILFILE *fp)
3286
3287
43.7M
{
3288
43.7M
    return fp->Eof();
3289
43.7M
}
3290
3291
/************************************************************************/
3292
/*                            VSIFErrorL()                              */
3293
/************************************************************************/
3294
3295
/**
3296
 * \fn VSIVirtualHandle::Error()
3297
 * \brief Test the error indicator.
3298
 *
3299
 * Returns TRUE (non-zero) if an error condition occurred during the
3300
 * previous read operation. The error indicator is cleared by a call to
3301
 * VSIFClearErrL(). Note that a end-of-file situation, reported by VSIFEofL(),
3302
 * is *not* an error reported by VSIFErrorL().
3303
 *
3304
 * This method goes through the VSIFileHandler virtualization and may
3305
 * work on unusual filesystems such as in memory.
3306
 *
3307
 * Analog of the POSIX ferror() call.
3308
 *
3309
 * @return TRUE if the error indicator is set, else FALSE.
3310
 * @since 3.10
3311
 */
3312
3313
/**
3314
 * \brief Test the error indicator.
3315
 *
3316
 * Returns TRUE (non-zero) if an error condition occurred during the
3317
 * previous read operation. The error indicator is cleared by a call to
3318
 * VSIFClearErrL(). Note that a end-of-file situation, reported by VSIFEofL(),
3319
 * is *not* an error reported by VSIFErrorL().
3320
 *
3321
 * This method goes through the VSIFileHandler virtualization and may
3322
 * work on unusual filesystems such as in memory.
3323
 *
3324
 * Analog of the POSIX feof() call.
3325
 *
3326
 * @param fp file handle opened with VSIFOpenL().
3327
 *
3328
 * @return TRUE if the error indicator is set, else FALSE.
3329
 * @since 3.10
3330
 */
3331
3332
int VSIFErrorL(VSILFILE *fp)
3333
3334
133k
{
3335
133k
    return fp->Error();
3336
133k
}
3337
3338
/************************************************************************/
3339
/*                           VSIFClearErrL()                            */
3340
/************************************************************************/
3341
3342
/**
3343
 * \fn VSIVirtualHandle::ClearErr()
3344
 * \brief Reset the error and end-of-file indicators.
3345
 *
3346
 * This method goes through the VSIFileHandler virtualization and may
3347
 * work on unusual filesystems such as in memory.
3348
 *
3349
 * Analog of the POSIX clearerr() call.
3350
 *
3351
 * @since 3.10
3352
 */
3353
3354
/**
3355
 * \brief Reset the error and end-of-file indicators.
3356
 *
3357
 * This method goes through the VSIFileHandler virtualization and may
3358
 * work on unusual filesystems such as in memory.
3359
 *
3360
 * Analog of the POSIX clearerr() call.
3361
 *
3362
 * @param fp file handle opened with VSIFOpenL().
3363
 *
3364
 * @since 3.10
3365
 */
3366
3367
void VSIFClearErrL(VSILFILE *fp)
3368
3369
890
{
3370
890
    fp->ClearErr();
3371
890
}
3372
3373
/************************************************************************/
3374
/*                            VSIFTruncateL()                           */
3375
/************************************************************************/
3376
3377
/**
3378
 * \fn VSIVirtualHandle::Truncate( vsi_l_offset nNewSize )
3379
 * \brief Truncate/expand the file to the specified size
3380
3381
 * This method goes through the VSIFileHandler virtualization and may
3382
 * work on unusual filesystems such as in memory.
3383
 *
3384
 * Analog of the POSIX ftruncate() call.
3385
 *
3386
 * @param nNewSize new size in bytes.
3387
 *
3388
 * @return 0 on success
3389
 * @since GDAL 1.9.0
3390
 */
3391
3392
/**
3393
 * \brief Truncate/expand the file to the specified size
3394
3395
 * This method goes through the VSIFileHandler virtualization and may
3396
 * work on unusual filesystems such as in memory.
3397
 *
3398
 * Analog of the POSIX ftruncate() call.
3399
 *
3400
 * @param fp file handle opened with VSIFOpenL().
3401
 * @param nNewSize new size in bytes.
3402
 *
3403
 * @return 0 on success
3404
 * @since GDAL 1.9.0
3405
 */
3406
3407
int VSIFTruncateL(VSILFILE *fp, vsi_l_offset nNewSize)
3408
3409
2.88k
{
3410
2.88k
    return fp->Truncate(nNewSize);
3411
2.88k
}
3412
3413
/************************************************************************/
3414
/*                            VSIFPrintfL()                             */
3415
/************************************************************************/
3416
3417
/**
3418
 * \brief Formatted write to file.
3419
 *
3420
 * Provides fprintf() style formatted output to a VSI*L file.  This formats
3421
 * an internal buffer which is written using VSIFWriteL().
3422
 *
3423
 * Analog of the POSIX fprintf() call.
3424
 *
3425
 * @param fp file handle opened with VSIFOpenL().
3426
 * @param pszFormat the printf() style format string.
3427
 *
3428
 * @return the number of bytes written or -1 on an error.
3429
 */
3430
3431
int VSIFPrintfL(VSILFILE *fp, CPL_FORMAT_STRING(const char *pszFormat), ...)
3432
3433
21.2M
{
3434
21.2M
    va_list args;
3435
3436
21.2M
    va_start(args, pszFormat);
3437
21.2M
    CPLString osResult;
3438
21.2M
    osResult.vPrintf(pszFormat, args);
3439
21.2M
    va_end(args);
3440
3441
21.2M
    return static_cast<int>(
3442
21.2M
        VSIFWriteL(osResult.c_str(), 1, osResult.length(), fp));
3443
21.2M
}
3444
3445
/************************************************************************/
3446
/*                 VSIVirtualHandle::Printf()                           */
3447
/************************************************************************/
3448
3449
/**
3450
 * \brief Formatted write to file.
3451
 *
3452
 * Provides fprintf() style formatted output to a VSI*L file.  This formats
3453
 * an internal buffer which is written using VSIFWriteL().
3454
 *
3455
 * Analog of the POSIX fprintf() call.
3456
 *
3457
 * @param pszFormat the printf() style format string.
3458
 *
3459
 * @return the number of bytes written or -1 on an error.
3460
 */
3461
3462
int VSIVirtualHandle::Printf(CPL_FORMAT_STRING(const char *pszFormat), ...)
3463
58.8k
{
3464
58.8k
    va_list args;
3465
3466
58.8k
    va_start(args, pszFormat);
3467
58.8k
    CPLString osResult;
3468
58.8k
    osResult.vPrintf(pszFormat, args);
3469
58.8k
    va_end(args);
3470
3471
58.8k
    return static_cast<int>(Write(osResult.c_str(), 1, osResult.length()));
3472
58.8k
}
3473
3474
/************************************************************************/
3475
/*                              VSIFPutcL()                              */
3476
/************************************************************************/
3477
3478
// TODO: should we put in conformance with POSIX regarding the return
3479
// value. As of today (2015-08-29), no code in GDAL sources actually
3480
// check the return value.
3481
3482
/**
3483
 * \brief Write a single byte to the file
3484
 *
3485
 * Writes the character nChar, cast to an unsigned char, to file.
3486
 *
3487
 * Almost an analog of the POSIX  fputc() call, except that it returns
3488
 * the  number of  character  written (1  or 0),  and  not the  (cast)
3489
 * character itself or EOF.
3490
 *
3491
 * @param nChar character to write.
3492
 * @param fp file handle opened with VSIFOpenL().
3493
 *
3494
 * @return 1 in case of success, 0 on error.
3495
 */
3496
3497
int VSIFPutcL(int nChar, VSILFILE *fp)
3498
3499
580k
{
3500
580k
    const unsigned char cChar = static_cast<unsigned char>(nChar);
3501
580k
    return static_cast<int>(VSIFWriteL(&cChar, 1, 1, fp));
3502
580k
}
3503
3504
/************************************************************************/
3505
/*                        VSIFGetRangeStatusL()                        */
3506
/************************************************************************/
3507
3508
/**
3509
 * \fn VSIVirtualHandle::GetRangeStatus( vsi_l_offset nOffset,
3510
 *                                       vsi_l_offset nLength )
3511
 * \brief Return if a given file range contains data or holes filled with zeroes
3512
 *
3513
 * This uses the filesystem capabilities of querying which regions of
3514
 * a sparse file are allocated or not. This is currently only
3515
 * implemented for Linux (and no other Unix derivatives) and Windows.
3516
 *
3517
 * Note: A return of VSI_RANGE_STATUS_DATA doesn't exclude that the
3518
 * extent is filled with zeroes! It must be interpreted as "may
3519
 * contain non-zero data".
3520
 *
3521
 * @param nOffset offset of the start of the extent.
3522
 * @param nLength extent length.
3523
 *
3524
 * @return extent status: VSI_RANGE_STATUS_UNKNOWN, VSI_RANGE_STATUS_DATA or
3525
 *         VSI_RANGE_STATUS_HOLE
3526
 * @since GDAL 2.2
3527
 */
3528
3529
/**
3530
 * \brief Return if a given file range contains data or holes filled with zeroes
3531
 *
3532
 * This uses the filesystem capabilities of querying which regions of
3533
 * a sparse file are allocated or not. This is currently only
3534
 * implemented for Linux (and no other Unix derivatives) and Windows.
3535
 *
3536
 * Note: A return of VSI_RANGE_STATUS_DATA doesn't exclude that the
3537
 * extent is filled with zeroes! It must be interpreted as "may
3538
 * contain non-zero data".
3539
 *
3540
 * @param fp file handle opened with VSIFOpenL().
3541
 * @param nOffset offset of the start of the extent.
3542
 * @param nLength extent length.
3543
 *
3544
 * @return extent status: VSI_RANGE_STATUS_UNKNOWN, VSI_RANGE_STATUS_DATA or
3545
 *         VSI_RANGE_STATUS_HOLE
3546
 * @since GDAL 2.2
3547
 */
3548
3549
VSIRangeStatus VSIFGetRangeStatusL(VSILFILE *fp, vsi_l_offset nOffset,
3550
                                   vsi_l_offset nLength)
3551
1.60k
{
3552
1.60k
    return fp->GetRangeStatus(nOffset, nLength);
3553
1.60k
}
3554
3555
/************************************************************************/
3556
/*                           VSIIngestFile()                            */
3557
/************************************************************************/
3558
3559
/**
3560
 * \brief Ingest a file into memory.
3561
 *
3562
 * Read the whole content of a file into a memory buffer.
3563
 *
3564
 * Either fp or pszFilename can be NULL, but not both at the same time.
3565
 *
3566
 * If fp is passed non-NULL, it is the responsibility of the caller to
3567
 * close it.
3568
 *
3569
 * If non-NULL, the returned buffer is guaranteed to be NUL-terminated.
3570
 *
3571
 * @param fp file handle opened with VSIFOpenL().
3572
 * @param pszFilename filename.
3573
 * @param ppabyRet pointer to the target buffer. *ppabyRet must be freed with
3574
 *                 VSIFree()
3575
 * @param pnSize pointer to variable to store the file size. May be NULL.
3576
 * @param nMaxSize maximum size of file allowed. If no limit, set to a negative
3577
 *                 value.
3578
 *
3579
 * @return TRUE in case of success.
3580
 *
3581
 * @since GDAL 1.11
3582
 */
3583
3584
int VSIIngestFile(VSILFILE *fp, const char *pszFilename, GByte **ppabyRet,
3585
                  vsi_l_offset *pnSize, GIntBig nMaxSize)
3586
2.65M
{
3587
2.65M
    if (fp == nullptr && pszFilename == nullptr)
3588
0
        return FALSE;
3589
2.65M
    if (ppabyRet == nullptr)
3590
0
        return FALSE;
3591
3592
2.65M
    *ppabyRet = nullptr;
3593
2.65M
    if (pnSize != nullptr)
3594
2.19M
        *pnSize = 0;
3595
3596
2.65M
    bool bFreeFP = false;
3597
2.65M
    if (nullptr == fp)
3598
2.60M
    {
3599
2.60M
        fp = VSIFOpenL(pszFilename, "rb");
3600
2.60M
        if (nullptr == fp)
3601
339k
        {
3602
339k
            CPLError(CE_Failure, CPLE_FileIO, "Cannot open file '%s'",
3603
339k
                     pszFilename);
3604
339k
            return FALSE;
3605
339k
        }
3606
2.26M
        bFreeFP = true;
3607
2.26M
    }
3608
45.3k
    else
3609
45.3k
    {
3610
45.3k
        if (VSIFSeekL(fp, 0, SEEK_SET) != 0)
3611
0
            return FALSE;
3612
45.3k
    }
3613
3614
2.31M
    vsi_l_offset nDataLen = 0;
3615
3616
2.31M
    if (pszFilename == nullptr || strcmp(pszFilename, "/vsistdin/") == 0)
3617
2.22k
    {
3618
2.22k
        vsi_l_offset nDataAlloc = 0;
3619
2.22k
        if (VSIFSeekL(fp, 0, SEEK_SET) != 0)
3620
0
        {
3621
0
            if (bFreeFP)
3622
0
                CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
3623
0
            return FALSE;
3624
0
        }
3625
12.6k
        while (true)
3626
12.6k
        {
3627
12.6k
            if (nDataLen + 8192 + 1 > nDataAlloc)
3628
6.96k
            {
3629
6.96k
                nDataAlloc = (nDataAlloc * 4) / 3 + 8192 + 1;
3630
6.96k
                if (nDataAlloc >
3631
6.96k
                    static_cast<vsi_l_offset>(static_cast<size_t>(nDataAlloc)))
3632
0
                {
3633
0
                    CPLError(CE_Failure, CPLE_AppDefined,
3634
0
                             "Input file too large to be opened");
3635
0
                    VSIFree(*ppabyRet);
3636
0
                    *ppabyRet = nullptr;
3637
0
                    if (bFreeFP)
3638
0
                        CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
3639
0
                    return FALSE;
3640
0
                }
3641
6.96k
                GByte *pabyNew = static_cast<GByte *>(
3642
6.96k
                    VSIRealloc(*ppabyRet, static_cast<size_t>(nDataAlloc)));
3643
6.96k
                if (pabyNew == nullptr)
3644
0
                {
3645
0
                    CPLError(CE_Failure, CPLE_OutOfMemory,
3646
0
                             "Cannot allocate " CPL_FRMT_GIB " bytes",
3647
0
                             nDataAlloc);
3648
0
                    VSIFree(*ppabyRet);
3649
0
                    *ppabyRet = nullptr;
3650
0
                    if (bFreeFP)
3651
0
                        CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
3652
0
                    return FALSE;
3653
0
                }
3654
6.96k
                *ppabyRet = pabyNew;
3655
6.96k
            }
3656
12.6k
            const int nRead =
3657
12.6k
                static_cast<int>(VSIFReadL(*ppabyRet + nDataLen, 1, 8192, fp));
3658
12.6k
            nDataLen += nRead;
3659
3660
12.6k
            if (nMaxSize >= 0 && nDataLen > static_cast<vsi_l_offset>(nMaxSize))
3661
0
            {
3662
0
                CPLError(CE_Failure, CPLE_AppDefined,
3663
0
                         "Input file too large to be opened");
3664
0
                VSIFree(*ppabyRet);
3665
0
                *ppabyRet = nullptr;
3666
0
                if (pnSize != nullptr)
3667
0
                    *pnSize = 0;
3668
0
                if (bFreeFP)
3669
0
                    CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
3670
0
                return FALSE;
3671
0
            }
3672
3673
12.6k
            if (pnSize != nullptr)
3674
0
                *pnSize += nRead;
3675
12.6k
            (*ppabyRet)[nDataLen] = '\0';
3676
12.6k
            if (nRead == 0)
3677
2.22k
                break;
3678
12.6k
        }
3679
2.22k
    }
3680
2.31M
    else
3681
2.31M
    {
3682
2.31M
        if (VSIFSeekL(fp, 0, SEEK_END) != 0)
3683
346
        {
3684
346
            if (bFreeFP)
3685
346
                CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
3686
346
            return FALSE;
3687
346
        }
3688
2.31M
        nDataLen = VSIFTellL(fp);
3689
3690
        // With "large" VSI I/O API we can read data chunks larger than
3691
        // VSIMalloc could allocate. Catch it here.
3692
2.31M
        if (nDataLen !=
3693
2.31M
                static_cast<vsi_l_offset>(static_cast<size_t>(nDataLen)) ||
3694
2.31M
            nDataLen + 1 < nDataLen
3695
            // opening a directory returns nDataLen = INT_MAX (on 32bit) or
3696
            // INT64_MAX (on 64bit)
3697
2.31M
            || nDataLen + 1 > std::numeric_limits<size_t>::max() / 2 ||
3698
2.31M
            (nMaxSize >= 0 && nDataLen > static_cast<vsi_l_offset>(nMaxSize)))
3699
91
        {
3700
91
            CPLError(CE_Failure, CPLE_AppDefined,
3701
91
                     "Input file too large to be opened");
3702
91
            if (bFreeFP)
3703
91
                CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
3704
91
            return FALSE;
3705
91
        }
3706
3707
2.31M
        if (VSIFSeekL(fp, 0, SEEK_SET) != 0)
3708
0
        {
3709
0
            if (bFreeFP)
3710
0
                CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
3711
0
            return FALSE;
3712
0
        }
3713
3714
2.31M
        *ppabyRet =
3715
2.31M
            static_cast<GByte *>(VSIMalloc(static_cast<size_t>(nDataLen + 1)));
3716
2.31M
        if (nullptr == *ppabyRet)
3717
0
        {
3718
0
            CPLError(CE_Failure, CPLE_OutOfMemory,
3719
0
                     "Cannot allocate " CPL_FRMT_GIB " bytes", nDataLen + 1);
3720
0
            if (bFreeFP)
3721
0
                CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
3722
0
            return FALSE;
3723
0
        }
3724
3725
2.31M
        (*ppabyRet)[nDataLen] = '\0';
3726
2.31M
        if (nDataLen !=
3727
2.31M
            VSIFReadL(*ppabyRet, 1, static_cast<size_t>(nDataLen), fp))
3728
32
        {
3729
32
            CPLError(CE_Failure, CPLE_FileIO,
3730
32
                     "Cannot read " CPL_FRMT_GIB " bytes", nDataLen);
3731
32
            VSIFree(*ppabyRet);
3732
32
            *ppabyRet = nullptr;
3733
32
            if (bFreeFP)
3734
32
                CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
3735
32
            return FALSE;
3736
32
        }
3737
2.31M
        if (pnSize != nullptr)
3738
1.90M
            *pnSize = nDataLen;
3739
2.31M
    }
3740
2.31M
    if (bFreeFP)
3741
2.26M
        CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
3742
2.31M
    return TRUE;
3743
2.31M
}
3744
3745
/************************************************************************/
3746
/*                         VSIOverwriteFile()                           */
3747
/************************************************************************/
3748
3749
/**
3750
 * \brief Overwrite an existing file with content from another one
3751
 *
3752
 * @param fpTarget file handle opened with VSIFOpenL() with "rb+" flag.
3753
 * @param pszSourceFilename source filename
3754
 *
3755
 * @return TRUE in case of success.
3756
 *
3757
 * @since GDAL 3.1
3758
 */
3759
3760
int VSIOverwriteFile(VSILFILE *fpTarget, const char *pszSourceFilename)
3761
0
{
3762
0
    VSILFILE *fpSource = VSIFOpenL(pszSourceFilename, "rb");
3763
0
    if (fpSource == nullptr)
3764
0
    {
3765
0
        CPLError(CE_Failure, CPLE_FileIO, "Cannot open %s", pszSourceFilename);
3766
0
        return false;
3767
0
    }
3768
3769
0
    const size_t nBufferSize = 4096;
3770
0
    void *pBuffer = CPLMalloc(nBufferSize);
3771
0
    VSIFSeekL(fpTarget, 0, SEEK_SET);
3772
0
    bool bRet = true;
3773
0
    while (true)
3774
0
    {
3775
0
        size_t nRead = VSIFReadL(pBuffer, 1, nBufferSize, fpSource);
3776
0
        size_t nWritten = VSIFWriteL(pBuffer, 1, nRead, fpTarget);
3777
0
        if (nWritten != nRead)
3778
0
        {
3779
0
            bRet = false;
3780
0
            break;
3781
0
        }
3782
0
        if (nRead < nBufferSize)
3783
0
            break;
3784
0
    }
3785
3786
0
    if (bRet)
3787
0
    {
3788
0
        bRet = VSIFTruncateL(fpTarget, VSIFTellL(fpTarget)) == 0;
3789
0
        if (!bRet)
3790
0
        {
3791
0
            CPLError(CE_Failure, CPLE_FileIO, "Truncation failed");
3792
0
        }
3793
0
    }
3794
3795
0
    CPLFree(pBuffer);
3796
0
    VSIFCloseL(fpSource);
3797
0
    return bRet;
3798
0
}
3799
3800
/************************************************************************/
3801
/*                        VSIFGetNativeFileDescriptorL()                */
3802
/************************************************************************/
3803
3804
/**
3805
 * \fn VSIVirtualHandle::GetNativeFileDescriptor()
3806
 * \brief Returns the "native" file descriptor for the virtual handle.
3807
 *
3808
 * This will only return a non-NULL value for "real" files handled by the
3809
 * operating system (to be opposed to GDAL virtual file systems).
3810
 *
3811
 * On POSIX systems, this will be a integer value ("fd") cast as a void*.
3812
 * On Windows systems, this will be the HANDLE.
3813
 *
3814
 * @return the native file descriptor, or NULL.
3815
 */
3816
3817
/**
3818
 * \brief Returns the "native" file descriptor for the virtual handle.
3819
 *
3820
 * This will only return a non-NULL value for "real" files handled by the
3821
 * operating system (to be opposed to GDAL virtual file systems).
3822
 *
3823
 * On POSIX systems, this will be a integer value ("fd") cast as a void*.
3824
 * On Windows systems, this will be the HANDLE.
3825
 *
3826
 * @param fp file handle opened with VSIFOpenL().
3827
 *
3828
 * @return the native file descriptor, or NULL.
3829
 */
3830
3831
void *VSIFGetNativeFileDescriptorL(VSILFILE *fp)
3832
0
{
3833
0
    return fp->GetNativeFileDescriptor();
3834
0
}
3835
3836
/************************************************************************/
3837
/*                      VSIGetDiskFreeSpace()                           */
3838
/************************************************************************/
3839
3840
/**
3841
 * \brief Return free disk space available on the filesystem.
3842
 *
3843
 * This function returns the free disk space available on the filesystem.
3844
 *
3845
 * @param pszDirname a directory of the filesystem to query.
3846
 * @return The free space in bytes. Or -1 in case of error.
3847
 * @since GDAL 2.1
3848
 */
3849
3850
GIntBig VSIGetDiskFreeSpace(const char *pszDirname)
3851
0
{
3852
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszDirname);
3853
3854
0
    return poFSHandler->GetDiskFreeSpace(pszDirname);
3855
0
}
3856
3857
/************************************************************************/
3858
/*                    VSIGetFileSystemsPrefixes()                       */
3859
/************************************************************************/
3860
3861
/**
3862
 * \brief Return the list of prefixes for virtual file system handlers
3863
 * currently registered.
3864
 *
3865
 * Typically: "", "/vsimem/", "/vsicurl/", etc
3866
 *
3867
 * @return a NULL terminated list of prefixes. Must be freed with CSLDestroy()
3868
 * @since GDAL 2.3
3869
 */
3870
3871
char **VSIGetFileSystemsPrefixes(void)
3872
0
{
3873
0
    return VSIFileManager::GetPrefixes();
3874
0
}
3875
3876
/************************************************************************/
3877
/*                     VSIGetFileSystemOptions()                        */
3878
/************************************************************************/
3879
3880
/**
3881
 * \brief Return the list of options associated with a virtual file system
3882
 * handler as a serialized XML string.
3883
 *
3884
 * Those options may be set as configuration options with CPLSetConfigOption().
3885
 *
3886
 * @param pszFilename a filename, or prefix of a virtual file system handler.
3887
 * @return a string, which must not be freed, or NULL if no options is declared.
3888
 * @since GDAL 2.3
3889
 */
3890
3891
const char *VSIGetFileSystemOptions(const char *pszFilename)
3892
0
{
3893
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
3894
3895
0
    return poFSHandler->GetOptions();
3896
0
}
3897
3898
/************************************************************************/
3899
/*                       VSISetPathSpecificOption()                     */
3900
/************************************************************************/
3901
3902
static std::mutex oMutexPathSpecificOptions;
3903
3904
// key is a path prefix
3905
// value is a map of key, value pair
3906
static std::map<std::string, std::map<std::string, std::string>>
3907
    oMapPathSpecificOptions;
3908
3909
/**
3910
 * \brief Set a credential (or more generally an option related to a
3911
 *        virtual file system) for a given path prefix.
3912
 * @deprecated in GDAL 3.6 for the better named VSISetPathSpecificOption()
3913
 * @see VSISetPathSpecificOption()
3914
 */
3915
void VSISetCredential(const char *pszPathPrefix, const char *pszKey,
3916
                      const char *pszValue)
3917
0
{
3918
0
    VSISetPathSpecificOption(pszPathPrefix, pszKey, pszValue);
3919
0
}
3920
3921
/**
3922
 * \brief Set a path specific option for a given path prefix.
3923
 *
3924
 * Such option is typically, but not limited to, a credential setting for a
3925
 * virtual file system.
3926
 *
3927
 * That option may also be set as a configuration option with
3928
 * CPLSetConfigOption(), but this function allows to specify them with a
3929
 * granularity at the level of a file path, which makes it easier if using the
3930
 * same virtual file system but with different credentials (e.g. different
3931
 * credentials for bucket "/vsis3/foo" and "/vsis3/bar")
3932
 *
3933
 * This is supported for the following virtual file systems:
3934
 * /vsis3/, /vsigs/, /vsiaz/, /vsioss/, /vsiwebhdfs, /vsiswift.
3935
 * Note: setting them for a path starting with /vsiXXX/ will also apply for
3936
 * /vsiXXX_streaming/ requests.
3937
 *
3938
 * Note that no particular care is taken to store them in RAM in a secure way.
3939
 * So they might accidentally hit persistent storage if swapping occurs, or
3940
 * someone with access to the memory allocated by the process may be able to
3941
 * read them.
3942
 *
3943
 * @param pszPathPrefix a path prefix of a virtual file system handler.
3944
 *                      Typically of the form "/vsiXXX/bucket". Must NOT be
3945
 * NULL. Should not include trailing slashes.
3946
 * @param pszKey        Option name. Must NOT be NULL.
3947
 * @param pszValue      Option value. May be NULL to erase it.
3948
 *
3949
 * @since GDAL 3.6
3950
 */
3951
3952
void VSISetPathSpecificOption(const char *pszPathPrefix, const char *pszKey,
3953
                              const char *pszValue)
3954
0
{
3955
0
    std::lock_guard<std::mutex> oLock(oMutexPathSpecificOptions);
3956
0
    auto oIter = oMapPathSpecificOptions.find(pszPathPrefix);
3957
0
    CPLString osKey(pszKey);
3958
0
    osKey.toupper();
3959
0
    if (oIter == oMapPathSpecificOptions.end())
3960
0
    {
3961
0
        if (pszValue != nullptr)
3962
0
            oMapPathSpecificOptions[pszPathPrefix][osKey] = pszValue;
3963
0
    }
3964
0
    else if (pszValue != nullptr)
3965
0
        oIter->second[osKey] = pszValue;
3966
0
    else
3967
0
        oIter->second.erase(osKey);
3968
0
}
3969
3970
/************************************************************************/
3971
/*                       VSIClearPathSpecificOptions()                  */
3972
/************************************************************************/
3973
3974
/**
3975
 * \brief Clear path specific options set with VSISetPathSpecificOption()
3976
 * @deprecated in GDAL 3.6 for the better named VSIClearPathSpecificOptions()
3977
 * @see VSIClearPathSpecificOptions()
3978
 */
3979
void VSIClearCredentials(const char *pszPathPrefix)
3980
0
{
3981
0
    return VSIClearPathSpecificOptions(pszPathPrefix);
3982
0
}
3983
3984
/**
3985
 * \brief Clear path specific options set with VSISetPathSpecificOption()
3986
 *
3987
 * Note that no particular care is taken to remove them from RAM in a secure
3988
 * way.
3989
 *
3990
 * @param pszPathPrefix If set to NULL, all path specific options are cleared.
3991
 *                      If set to not-NULL, only those set with
3992
 *                      VSISetPathSpecificOption(pszPathPrefix, ...) will be
3993
 * cleared.
3994
 *
3995
 * @since GDAL 3.6
3996
 */
3997
void VSIClearPathSpecificOptions(const char *pszPathPrefix)
3998
0
{
3999
0
    std::lock_guard<std::mutex> oLock(oMutexPathSpecificOptions);
4000
0
    if (pszPathPrefix == nullptr)
4001
0
    {
4002
0
        oMapPathSpecificOptions.clear();
4003
0
    }
4004
0
    else
4005
0
    {
4006
0
        oMapPathSpecificOptions.erase(pszPathPrefix);
4007
0
    }
4008
0
}
4009
4010
/************************************************************************/
4011
/*                        VSIGetPathSpecificOption()                    */
4012
/************************************************************************/
4013
4014
/**
4015
 * \brief Get the value of a credential (or more generally an option related to
4016
 * a virtual file system) for a given path.
4017
 * @deprecated in GDAL 3.6 for the better named VSIGetPathSpecificOption()
4018
 * @see VSIGetPathSpecificOption()
4019
 */
4020
const char *VSIGetCredential(const char *pszPath, const char *pszKey,
4021
                             const char *pszDefault)
4022
0
{
4023
0
    return VSIGetPathSpecificOption(pszPath, pszKey, pszDefault);
4024
0
}
4025
4026
/**
4027
 * \brief Get the value a path specific option.
4028
 *
4029
 * Such option is typically, but not limited to, a credential setting for a
4030
 * virtual file system.
4031
 *
4032
 * If no match occurs, CPLGetConfigOption(pszKey, pszDefault) is returned.
4033
 *
4034
 * Mostly to be used by virtual file system implementations.
4035
 *
4036
 * @since GDAL 3.6
4037
 * @see VSISetPathSpecificOption()
4038
 */
4039
const char *VSIGetPathSpecificOption(const char *pszPath, const char *pszKey,
4040
                                     const char *pszDefault)
4041
29.2M
{
4042
29.2M
    {
4043
29.2M
        std::lock_guard<std::mutex> oLock(oMutexPathSpecificOptions);
4044
29.2M
        for (auto it = oMapPathSpecificOptions.rbegin();
4045
29.2M
             it != oMapPathSpecificOptions.rend(); ++it)
4046
0
        {
4047
0
            if (STARTS_WITH(pszPath, it->first.c_str()))
4048
0
            {
4049
0
                auto oIter = it->second.find(CPLString(pszKey).toupper());
4050
0
                if (oIter != it->second.end())
4051
0
                    return oIter->second.c_str();
4052
0
            }
4053
0
        }
4054
29.2M
    }
4055
29.2M
    return CPLGetConfigOption(pszKey, pszDefault);
4056
29.2M
}
4057
4058
/************************************************************************/
4059
/*                      VSIDuplicateFileSystemHandler()                 */
4060
/************************************************************************/
4061
4062
/**
4063
 * \brief Duplicate an existing file system handler.
4064
 *
4065
 * A number of virtual file system for remote object stores use protocols
4066
 * identical or close to popular ones (typically AWS S3), but with slightly
4067
 * different settings (at the very least the endpoint).
4068
 *
4069
 * This functions allows to duplicate the source virtual file system handler
4070
 * as a new one with a different prefix (when the source virtual file system
4071
 * handler supports the duplication operation).
4072
 *
4073
 * VSISetPathSpecificOption() will typically be called afterwards to change
4074
 * configurable settings on the cloned file system handler (e.g. AWS_S3_ENDPOINT
4075
 * for a clone of /vsis3/).
4076
 *
4077
 * @since GDAL 3.7
4078
 */
4079
bool VSIDuplicateFileSystemHandler(const char *pszSourceFSName,
4080
                                   const char *pszNewFSName)
4081
0
{
4082
0
    VSIFilesystemHandler *poTargetFSHandler =
4083
0
        VSIFileManager::GetHandler(pszNewFSName);
4084
0
    if (poTargetFSHandler != VSIFileManager::GetHandler("/"))
4085
0
    {
4086
0
        CPLError(CE_Failure, CPLE_AppDefined,
4087
0
                 "%s is already a known virtual file system", pszNewFSName);
4088
0
        return false;
4089
0
    }
4090
4091
0
    VSIFilesystemHandler *poSourceFSHandler =
4092
0
        VSIFileManager::GetHandler(pszSourceFSName);
4093
0
    if (!poSourceFSHandler)
4094
0
    {
4095
0
        CPLError(CE_Failure, CPLE_AppDefined,
4096
0
                 "%s is not a known virtual file system", pszSourceFSName);
4097
0
        return false;
4098
0
    }
4099
4100
0
    poTargetFSHandler = poSourceFSHandler->Duplicate(pszNewFSName);
4101
0
    if (!poTargetFSHandler)
4102
0
        return false;
4103
4104
0
    VSIFileManager::InstallHandler(pszNewFSName, poTargetFSHandler);
4105
0
    return true;
4106
0
}
4107
4108
/************************************************************************/
4109
/* ==================================================================== */
4110
/*                           VSIFileManager()                           */
4111
/* ==================================================================== */
4112
/************************************************************************/
4113
4114
#ifndef DOXYGEN_SKIP
4115
4116
/*
4117
** Notes on Multithreading:
4118
**
4119
** The VSIFileManager maintains a list of file type handlers (mem, large
4120
** file, etc).  It should be thread safe.
4121
**/
4122
4123
/************************************************************************/
4124
/*                           VSIFileManager()                           */
4125
/************************************************************************/
4126
4127
88
VSIFileManager::VSIFileManager() : poDefaultHandler(nullptr)
4128
88
{
4129
88
}
4130
4131
/************************************************************************/
4132
/*                          ~VSIFileManager()                           */
4133
/************************************************************************/
4134
4135
VSIFileManager::~VSIFileManager()
4136
0
{
4137
0
    std::set<VSIFilesystemHandler *> oSetAlreadyDeleted;
4138
0
    for (std::map<std::string, VSIFilesystemHandler *>::const_iterator iter =
4139
0
             oHandlers.begin();
4140
0
         iter != oHandlers.end(); ++iter)
4141
0
    {
4142
0
        if (oSetAlreadyDeleted.find(iter->second) == oSetAlreadyDeleted.end())
4143
0
        {
4144
0
            oSetAlreadyDeleted.insert(iter->second);
4145
0
            delete iter->second;
4146
0
        }
4147
0
    }
4148
4149
0
    delete poDefaultHandler;
4150
0
}
4151
4152
/************************************************************************/
4153
/*                                Get()                                 */
4154
/************************************************************************/
4155
4156
static VSIFileManager *poManager = nullptr;
4157
static CPLMutex *hVSIFileManagerMutex = nullptr;
4158
4159
VSIFileManager *VSIFileManager::Get()
4160
98.8M
{
4161
98.8M
    CPLMutexHolder oHolder(&hVSIFileManagerMutex);
4162
98.8M
    if (poManager != nullptr)
4163
98.8M
    {
4164
98.8M
        return poManager;
4165
98.8M
    }
4166
4167
88
    poManager = new VSIFileManager;
4168
88
    VSIInstallLargeFileHandler();
4169
88
    VSIInstallSubFileHandler();
4170
88
    VSIInstallMemFileHandler();
4171
88
#ifdef HAVE_LIBZ
4172
88
    VSIInstallGZipFileHandler();
4173
88
    VSIInstallZipFileHandler();
4174
88
#endif
4175
#ifdef HAVE_LIBARCHIVE
4176
    VSIInstall7zFileHandler();
4177
    VSIInstallRarFileHandler();
4178
#endif
4179
88
#ifdef HAVE_CURL
4180
88
    VSIInstallCurlFileHandler();
4181
88
    VSIInstallCurlStreamingFileHandler();
4182
88
    VSIInstallS3FileHandler();
4183
88
    VSIInstallS3StreamingFileHandler();
4184
88
    VSIInstallGSFileHandler();
4185
88
    VSIInstallGSStreamingFileHandler();
4186
88
    VSIInstallAzureFileHandler();
4187
88
    VSIInstallAzureStreamingFileHandler();
4188
88
    VSIInstallADLSFileHandler();
4189
88
    VSIInstallOSSFileHandler();
4190
88
    VSIInstallOSSStreamingFileHandler();
4191
88
    VSIInstallSwiftFileHandler();
4192
88
    VSIInstallSwiftStreamingFileHandler();
4193
88
    VSIInstallWebHdfsHandler();
4194
88
#endif
4195
88
    VSIInstallStdinHandler();
4196
88
    VSIInstallHdfsHandler();
4197
88
    VSIInstallStdoutHandler();
4198
88
    VSIInstallSparseFileHandler();
4199
88
    VSIInstallTarFileHandler();
4200
88
    VSIInstallCachedFileHandler();
4201
88
    VSIInstallCryptFileHandler();
4202
4203
88
    return poManager;
4204
98.8M
}
4205
4206
/************************************************************************/
4207
/*                           GetPrefixes()                              */
4208
/************************************************************************/
4209
4210
char **VSIFileManager::GetPrefixes()
4211
0
{
4212
0
    CPLMutexHolder oHolder(&hVSIFileManagerMutex);
4213
0
    CPLStringList aosList;
4214
0
    for (const auto &oIter : Get()->oHandlers)
4215
0
    {
4216
0
        if (oIter.first != "/vsicurl?")
4217
0
        {
4218
0
            aosList.AddString(oIter.first.c_str());
4219
0
        }
4220
0
    }
4221
0
    return aosList.StealList();
4222
0
}
4223
4224
/************************************************************************/
4225
/*                             GetHandler()                             */
4226
/************************************************************************/
4227
4228
VSIFilesystemHandler *VSIFileManager::GetHandler(const char *pszPath)
4229
4230
98.8M
{
4231
98.8M
    VSIFileManager *poThis = Get();
4232
98.8M
    const size_t nPathLen = strlen(pszPath);
4233
4234
98.8M
    for (std::map<std::string, VSIFilesystemHandler *>::const_iterator iter =
4235
98.8M
             poThis->oHandlers.begin();
4236
1.94G
         iter != poThis->oHandlers.end(); ++iter)
4237
1.94G
    {
4238
1.94G
        const char *pszIterKey = iter->first.c_str();
4239
1.94G
        const size_t nIterKeyLen = iter->first.size();
4240
1.94G
        if (strncmp(pszPath, pszIterKey, nIterKeyLen) == 0)
4241
91.1M
            return iter->second;
4242
4243
        // "/vsimem\foo" should be handled as "/vsimem/foo".
4244
1.85G
        if (nIterKeyLen && nPathLen > nIterKeyLen &&
4245
1.85G
            pszIterKey[nIterKeyLen - 1] == '/' &&
4246
1.85G
            pszPath[nIterKeyLen - 1] == '\\' &&
4247
1.85G
            strncmp(pszPath, pszIterKey, nIterKeyLen - 1) == 0)
4248
107k
            return iter->second;
4249
4250
        // /vsimem should be treated as a match for /vsimem/.
4251
1.85G
        if (nPathLen + 1 == nIterKeyLen &&
4252
1.85G
            strncmp(pszPath, pszIterKey, nPathLen) == 0)
4253
2.94M
            return iter->second;
4254
1.85G
    }
4255
4256
4.62M
    return poThis->poDefaultHandler;
4257
98.8M
}
4258
4259
/************************************************************************/
4260
/*                           InstallHandler()                           */
4261
/************************************************************************/
4262
4263
void VSIFileManager::InstallHandler(const std::string &osPrefix,
4264
                                    VSIFilesystemHandler *poHandler)
4265
4266
2.56k
{
4267
2.56k
    if (osPrefix == "")
4268
88
        Get()->poDefaultHandler = poHandler;
4269
2.47k
    else
4270
2.47k
        Get()->oHandlers[osPrefix] = poHandler;
4271
2.56k
}
4272
4273
/************************************************************************/
4274
/*                          RemoveHandler()                             */
4275
/************************************************************************/
4276
4277
void VSIFileManager::RemoveHandler(const std::string &osPrefix)
4278
0
{
4279
0
    if (osPrefix == "")
4280
0
        Get()->poDefaultHandler = nullptr;
4281
0
    else
4282
0
        Get()->oHandlers.erase(osPrefix);
4283
0
}
4284
4285
/************************************************************************/
4286
/*                       VSICleanupFileManager()                        */
4287
/************************************************************************/
4288
4289
void VSICleanupFileManager()
4290
4291
0
{
4292
0
    if (poManager)
4293
0
    {
4294
0
        delete poManager;
4295
0
        poManager = nullptr;
4296
0
    }
4297
4298
0
    if (hVSIFileManagerMutex != nullptr)
4299
0
    {
4300
0
        CPLDestroyMutex(hVSIFileManagerMutex);
4301
0
        hVSIFileManagerMutex = nullptr;
4302
0
    }
4303
4304
0
#ifdef HAVE_CURL
4305
0
    VSICURLDestroyCacheFileProp();
4306
0
#endif
4307
0
}
4308
4309
/************************************************************************/
4310
/*                            Truncate()                                */
4311
/************************************************************************/
4312
4313
int VSIVirtualHandle::Truncate(vsi_l_offset nNewSize)
4314
0
{
4315
0
    const vsi_l_offset nOriginalPos = Tell();
4316
0
    if (Seek(0, SEEK_END) == 0 && nNewSize >= Tell())
4317
0
    {
4318
        // Fill with zeroes
4319
0
        std::vector<GByte> aoBytes(4096, 0);
4320
0
        vsi_l_offset nCurOffset = nOriginalPos;
4321
0
        while (nCurOffset < nNewSize)
4322
0
        {
4323
0
            constexpr vsi_l_offset nMaxOffset = 4096;
4324
0
            const int nSize =
4325
0
                static_cast<int>(std::min(nMaxOffset, nNewSize - nCurOffset));
4326
0
            if (Write(&aoBytes[0], nSize, 1) != 1)
4327
0
            {
4328
0
                Seek(nOriginalPos, SEEK_SET);
4329
0
                return -1;
4330
0
            }
4331
0
            nCurOffset += nSize;
4332
0
        }
4333
0
        return Seek(nOriginalPos, SEEK_SET) == 0 ? 0 : -1;
4334
0
    }
4335
4336
0
    CPLDebug("VSI", "Truncation is not supported in generic implementation "
4337
0
                    "of Truncate()");
4338
0
    Seek(nOriginalPos, SEEK_SET);
4339
0
    return -1;
4340
0
}
4341
4342
/************************************************************************/
4343
/*                           ReadMultiRange()                           */
4344
/************************************************************************/
4345
4346
int VSIVirtualHandle::ReadMultiRange(int nRanges, void **ppData,
4347
                                     const vsi_l_offset *panOffsets,
4348
                                     const size_t *panSizes)
4349
0
{
4350
0
    int nRet = 0;
4351
0
    const vsi_l_offset nCurOffset = Tell();
4352
0
    for (int i = 0; i < nRanges; i++)
4353
0
    {
4354
0
        if (Seek(panOffsets[i], SEEK_SET) < 0)
4355
0
        {
4356
0
            nRet = -1;
4357
0
            break;
4358
0
        }
4359
4360
0
        const size_t nRead = Read(ppData[i], 1, panSizes[i]);
4361
0
        if (panSizes[i] != nRead)
4362
0
        {
4363
0
            nRet = -1;
4364
0
            break;
4365
0
        }
4366
0
    }
4367
4368
0
    Seek(nCurOffset, SEEK_SET);
4369
4370
0
    return nRet;
4371
0
}
4372
4373
#endif  // #ifndef DOXYGEN_SKIP
4374
4375
/************************************************************************/
4376
/*                            HasPRead()                                */
4377
/************************************************************************/
4378
4379
/** Returns whether this file handle supports the PRead() method.
4380
 *
4381
 * @since GDAL 3.6
4382
 */
4383
bool VSIVirtualHandle::HasPRead() const
4384
3.67k
{
4385
3.67k
    return false;
4386
3.67k
}
4387
4388
/************************************************************************/
4389
/*                             PRead()                                  */
4390
/************************************************************************/
4391
4392
/** Do a parallel-compatible read operation.
4393
 *
4394
 * This methods reads into pBuffer up to nSize bytes starting at offset nOffset
4395
 * in the file. The current file offset is not affected by this method.
4396
 *
4397
 * The implementation is thread-safe: several threads can issue PRead()
4398
 * concurrently on the same VSIVirtualHandle object.
4399
 *
4400
 * This method has the same semantics as pread() Linux operation. It is only
4401
 * available if HasPRead() returns true.
4402
 *
4403
 * @param pBuffer output buffer (must be at least nSize bytes large).
4404
 * @param nSize   number of bytes to read in the file.
4405
 * @param nOffset file offset from which to read.
4406
 * @return number of bytes read.
4407
 * @since GDAL 3.6
4408
 */
4409
size_t VSIVirtualHandle::PRead(CPL_UNUSED void *pBuffer,
4410
                               CPL_UNUSED size_t nSize,
4411
                               CPL_UNUSED vsi_l_offset nOffset) const
4412
0
{
4413
0
    return 0;
4414
0
}
4415
4416
#ifndef DOXYGEN_SKIP
4417
/************************************************************************/
4418
/*                  VSIProxyFileHandle::CancelCreation()                */
4419
/************************************************************************/
4420
4421
void VSIProxyFileHandle::CancelCreation()
4422
0
{
4423
0
    m_nativeHandle->CancelCreation();
4424
0
}
4425
#endif