Coverage Report

Created: 2025-08-28 06:57

/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
24
#include <fcntl.h>
25
26
#include <algorithm>
27
#include <limits>
28
#include <map>
29
#include <memory>
30
#include <mutex>
31
#include <set>
32
#include <string>
33
#include <utility>
34
#include <vector>
35
36
#include "cpl_conv.h"
37
#include "cpl_error.h"
38
#include "cpl_multiproc.h"
39
#include "cpl_string.h"
40
#include "cpl_vsi_virtual.h"
41
#include "cpl_vsil_curl_class.h"
42
43
// To avoid aliasing to GetDiskFreeSpace to GetDiskFreeSpaceA on Windows
44
#ifdef GetDiskFreeSpace
45
#undef GetDiskFreeSpace
46
#endif
47
48
/************************************************************************/
49
/*                             VSIReadDir()                             */
50
/************************************************************************/
51
52
/**
53
 * \brief Read names in a directory.
54
 *
55
 * This function abstracts access to directory contains.  It returns a
56
 * list of strings containing the names of files, and directories in this
57
 * directory.  The resulting string list becomes the responsibility of the
58
 * application and should be freed with CSLDestroy() when no longer needed.
59
 *
60
 * Note that no error is issued via CPLError() if the directory path is
61
 * invalid, though NULL is returned.
62
 *
63
 * This function used to be known as CPLReadDir(), but the old name is now
64
 * deprecated.
65
 *
66
 * @param pszPath the relative, or absolute path of a directory to read.
67
 * UTF-8 encoded.
68
 * @return The list of entries in the directory, or NULL if the directory
69
 * doesn't exist.  Filenames are returned in UTF-8 encoding.
70
 */
71
72
char **VSIReadDir(const char *pszPath)
73
0
{
74
0
    return VSIReadDirEx(pszPath, 0);
75
0
}
76
77
/************************************************************************/
78
/*                             VSIReadDirEx()                           */
79
/************************************************************************/
80
81
/**
82
 * \brief Read names in a directory.
83
 *
84
 * This function abstracts access to directory contains.  It returns a
85
 * list of strings containing the names of files, and directories in this
86
 * directory.  The resulting string list becomes the responsibility of the
87
 * application and should be freed with CSLDestroy() when no longer needed.
88
 *
89
 * Note that no error is issued via CPLError() if the directory path is
90
 * invalid, though NULL is returned.
91
 *
92
 * If nMaxFiles is set to a positive number, directory listing will stop after
93
 * that limit has been reached. Note that to indicate truncate, at least one
94
 * element more than the nMaxFiles limit will be returned. If CSLCount() on the
95
 * result is lesser or equal to nMaxFiles, then no truncation occurred.
96
 *
97
 * @param pszPath the relative, or absolute path of a directory to read.
98
 * UTF-8 encoded.
99
 * @param nMaxFiles maximum number of files after which to stop, or 0 for no
100
 * limit.
101
 * @return The list of entries in the directory, or NULL if the directory
102
 * doesn't exist.  Filenames are returned in UTF-8 encoding.
103
 * @since GDAL 2.1
104
 */
105
106
char **VSIReadDirEx(const char *pszPath, int nMaxFiles)
107
0
{
108
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath);
109
110
0
    return poFSHandler->ReadDirEx(pszPath, nMaxFiles);
111
0
}
112
113
/************************************************************************/
114
/*                             VSISiblingFiles()                        */
115
/************************************************************************/
116
117
/**
118
 * \brief Return related filenames
119
 *
120
 * This function is essentially meant at being used by GDAL internals.
121
 *
122
 * @param pszFilename the path of a filename to inspect
123
 * UTF-8 encoded.
124
 * @return The list of entries, relative to the directory, of all sidecar
125
 * files available or NULL if the list is not known.
126
 * Filenames are returned in UTF-8 encoding.
127
 * Most implementations will return NULL, and a subsequent ReadDir will
128
 * list all files available in the file's directory. This function will be
129
 * overridden by VSI FilesystemHandlers that wish to force e.g. an empty list
130
 * to avoid opening non-existent files on slow filesystems. The return value
131
 * shall be destroyed with CSLDestroy()
132
 * @since GDAL 3.2
133
 */
134
char **VSISiblingFiles(const char *pszFilename)
135
0
{
136
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
137
138
0
    return poFSHandler->SiblingFiles(pszFilename);
139
0
}
140
141
/************************************************************************/
142
/*                           VSIFnMatch()                               */
143
/************************************************************************/
144
145
static bool VSIFnMatch(const char *pszPattern, const char *pszStr)
146
0
{
147
0
    for (; *pszPattern && *pszStr; pszPattern++, pszStr++)
148
0
    {
149
0
        if (*pszPattern == '*')
150
0
        {
151
0
            if (pszPattern[1] == 0)
152
0
                return true;
153
0
            for (; *pszStr; ++pszStr)
154
0
            {
155
0
                if (VSIFnMatch(pszPattern + 1, pszStr))
156
0
                    return true;
157
0
            }
158
0
            return false;
159
0
        }
160
0
        else if (*pszPattern == '?')
161
0
        {
162
            // match single any char
163
0
        }
164
0
        else if (*pszPattern == '[')
165
0
        {
166
            // match character classes and ranges
167
            // "[abcd]" will match a character that is a, b, c or d
168
            // "[a-z]" will match a character that is a to z
169
            // "[!abcd] will match a character that is *not* a, b, c or d
170
            // "[]]" will match character ]
171
            // "[]-]" will match character ] or -
172
            // "[!]a-]" will match a character that is *not* ], a or -
173
174
0
            const char *pszOpenBracket = pszPattern;
175
0
            ++pszPattern;
176
0
            const bool isNot = (*pszPattern == '!');
177
0
            if (isNot)
178
0
            {
179
0
                ++pszOpenBracket;
180
0
                ++pszPattern;
181
0
            }
182
0
            bool res = false;
183
0
            for (; *pszPattern; ++pszPattern)
184
0
            {
185
0
                if ((*pszPattern == ']' || *pszPattern == '-') &&
186
0
                    pszPattern == pszOpenBracket + 1)
187
0
                {
188
0
                    if (*pszStr == *pszPattern)
189
0
                    {
190
0
                        res = true;
191
0
                    }
192
0
                }
193
0
                else if (*pszPattern == ']')
194
0
                {
195
0
                    break;
196
0
                }
197
0
                else if (pszPattern[1] == '-' && pszPattern[2] != 0 &&
198
0
                         pszPattern[2] != ']')
199
0
                {
200
0
                    if (*pszStr >= pszPattern[0] && *pszStr <= pszPattern[2])
201
0
                    {
202
0
                        res = true;
203
0
                    }
204
0
                    pszPattern += 2;
205
0
                }
206
0
                else if (*pszStr == *pszPattern)
207
0
                {
208
0
                    res = true;
209
0
                }
210
0
            }
211
0
            if (*pszPattern == 0)
212
0
                return false;
213
0
            if (!res && !isNot)
214
0
                return false;
215
0
            if (res && isNot)
216
0
                return false;
217
0
        }
218
0
        else if (*pszPattern != *pszStr)
219
0
        {
220
0
            return false;
221
0
        }
222
0
    }
223
0
    return *pszPattern == 0 && *pszStr == 0;
224
0
}
225
226
/************************************************************************/
227
/*                             VSIGlob()                                */
228
/************************************************************************/
229
230
/**
231
 \brief Return a list of file and directory names matching
232
 a pattern that can contain wildcards.
233
234
 This function has similar behavior to the POSIX glob() function:
235
 https://man7.org/linux/man-pages/man7/glob.7.html
236
237
 In particular it supports the following wildcards:
238
 <ul>
239
 <li>'*': match any string</li>
240
 <li>'?': match any single character</li>
241
 <li>'[': match character class or range, with '!' immediately after '['
242
 to indicate negation.</li>
243
 </ul>
244
 Refer to to the above man page for more details.
245
246
 It also supports the "**" recursive wildcard, behaving similarly to Python
247
 glob.glob() with recursive=True. Be careful of the amount of memory and time
248
 required when using that recursive wildcard on directories with a large
249
 amount of files and subdirectories.
250
251
 Examples, given a file hierarchy:
252
 - one.tif
253
 - my_subdir/two.tif
254
 - my_subdir/subsubdir/three.tif
255
256
 \code{.cpp}
257
 VSIGlob("one.tif",NULL,NULL,NULL) returns ["one.tif", NULL]
258
 VSIGlob("*.tif",NULL,NULL,NULL) returns ["one.tif", NULL]
259
 VSIGlob("on?.tif",NULL,NULL,NULL) returns ["one.tif", NULL]
260
 VSIGlob("on[a-z].tif",NULL,NULL,NULL) returns ["one.tif", NULL]
261
 VSIGlob("on[ef].tif",NULL,NULL,NULL) returns ["one.tif", NULL]
262
 VSIGlob("on[!e].tif",NULL,NULL,NULL) returns NULL
263
 VSIGlob("my_subdir" "/" "*.tif",NULL,NULL,NULL) returns ["my_subdir/two.tif", NULL]
264
 VSIGlob("**" "/" "*.tif",NULL,NULL,NULL) returns ["one.tif", "my_subdir/two.tif", "my_subdir/subsubdir/three.tif", NULL]
265
 \endcode
266
267
 In the current implementation, matching is done based on the assumption that
268
 a character fits into a single byte, which will not work properly on
269
 non-ASCII UTF-8 filenames.
270
271
 VSIGlob() works with any virtual file systems supported by GDAL, including
272
 network file systems such as /vsis3/, /vsigs/, /vsiaz/, etc. But note that
273
 for those ones, the pattern is not passed to the remote server, and thus large
274
 amount of filenames can be transferred from the remote server to the host
275
 where the filtering is done.
276
277
 @param pszPattern the relative, or absolute path of a directory to read.
278
 UTF-8 encoded.
279
 @param papszOptions NULL-terminate list of options, or NULL. None supported
280
 currently.
281
 @param pProgressFunc Progress function, or NULL. This is only used as a way
282
 for the user to cancel operation if it takes too much time. The percentage
283
 passed to the callback is not significant (always at 0).
284
 @param pProgressData User data passed to the progress function, or NULL.
285
 @return The list of matched filenames, which must be freed with CSLDestroy().
286
 Filenames are returned in UTF-8 encoding.
287
288
 @since GDAL 3.11
289
*/
290
291
char **VSIGlob(const char *pszPattern, const char *const *papszOptions,
292
               GDALProgressFunc pProgressFunc, void *pProgressData)
293
0
{
294
0
    CPL_IGNORE_RET_VAL(papszOptions);
295
296
0
    CPLStringList aosRes;
297
0
    std::vector<std::pair<std::string, size_t>> candidates;
298
0
    candidates.emplace_back(pszPattern, 0);
299
0
    while (!candidates.empty())
300
0
    {
301
0
        auto [osPattern, nPosStart] = candidates.back();
302
0
        pszPattern = osPattern.c_str() + nPosStart;
303
0
        candidates.pop_back();
304
305
0
        std::string osPath = osPattern.substr(0, nPosStart);
306
0
        std::string osCurPath;
307
0
        for (;; ++pszPattern)
308
0
        {
309
0
            if (*pszPattern == 0 || *pszPattern == '/' || *pszPattern == '\\')
310
0
            {
311
0
                struct VSIDirCloser
312
0
                {
313
0
                    void operator()(VSIDIR *dir)
314
0
                    {
315
0
                        VSICloseDir(dir);
316
0
                    }
317
0
                };
318
319
0
                if (osCurPath == "**")
320
0
                {
321
0
                    std::unique_ptr<VSIDIR, VSIDirCloser> psDir(
322
0
                        VSIOpenDir(osPath.c_str(), -1, nullptr));
323
0
                    if (!psDir)
324
0
                        return nullptr;
325
0
                    while (const VSIDIREntry *psEntry =
326
0
                               VSIGetNextDirEntry(psDir.get()))
327
0
                    {
328
0
                        if (pProgressFunc &&
329
0
                            !pProgressFunc(0, "", pProgressData))
330
0
                        {
331
0
                            return nullptr;
332
0
                        }
333
0
                        {
334
0
                            std::string osCandidate(osPath);
335
0
                            osCandidate += psEntry->pszName;
336
0
                            nPosStart = osCandidate.size();
337
0
                            if (*pszPattern)
338
0
                            {
339
0
                                osCandidate += pszPattern;
340
0
                            }
341
0
                            candidates.emplace_back(std::move(osCandidate),
342
0
                                                    nPosStart);
343
0
                        }
344
0
                    }
345
0
                    osPath.clear();
346
0
                    break;
347
0
                }
348
0
                else if (osCurPath.find_first_of("*?[") != std::string::npos)
349
0
                {
350
0
                    std::unique_ptr<VSIDIR, VSIDirCloser> psDir(
351
0
                        VSIOpenDir(osPath.c_str(), 0, nullptr));
352
0
                    if (!psDir)
353
0
                        return nullptr;
354
0
                    while (const VSIDIREntry *psEntry =
355
0
                               VSIGetNextDirEntry(psDir.get()))
356
0
                    {
357
0
                        if (pProgressFunc &&
358
0
                            !pProgressFunc(0, "", pProgressData))
359
0
                        {
360
0
                            return nullptr;
361
0
                        }
362
0
                        if (VSIFnMatch(osCurPath.c_str(), psEntry->pszName))
363
0
                        {
364
0
                            std::string osCandidate(osPath);
365
0
                            osCandidate += psEntry->pszName;
366
0
                            nPosStart = osCandidate.size();
367
0
                            if (*pszPattern)
368
0
                            {
369
0
                                osCandidate += pszPattern;
370
0
                            }
371
0
                            candidates.emplace_back(std::move(osCandidate),
372
0
                                                    nPosStart);
373
0
                        }
374
0
                    }
375
0
                    osPath.clear();
376
0
                    break;
377
0
                }
378
0
                else if (*pszPattern == 0)
379
0
                {
380
0
                    osPath += osCurPath;
381
0
                    break;
382
0
                }
383
0
                else
384
0
                {
385
0
                    osPath += osCurPath;
386
0
                    osPath += *pszPattern;
387
0
                    osCurPath.clear();
388
0
                }
389
0
            }
390
0
            else
391
0
            {
392
0
                osCurPath += *pszPattern;
393
0
            }
394
0
        }
395
0
        if (!osPath.empty())
396
0
        {
397
0
            VSIStatBufL sStat;
398
0
            if (VSIStatL(osPath.c_str(), &sStat) == 0)
399
0
                aosRes.AddString(osPath.c_str());
400
0
        }
401
0
    }
402
403
0
    return aosRes.StealList();
404
0
}
405
406
/************************************************************************/
407
/*                      VSIGetDirectorySeparator()                      */
408
/************************************************************************/
409
410
/** Return the directory separator for the specified path.
411
 *
412
 * Default is forward slash. The only exception currently is the Windows
413
 * file system which returns backslash, unless the specified path is of the
414
 * form "{drive_letter}:/{rest_of_the_path}".
415
 *
416
 * @since 3.9
417
 */
418
const char *VSIGetDirectorySeparator(const char *pszPath)
419
22.1k
{
420
22.1k
    if (STARTS_WITH(pszPath, "http://") || STARTS_WITH(pszPath, "https://"))
421
0
        return "/";
422
423
22.1k
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath);
424
22.1k
    return poFSHandler->GetDirectorySeparator(pszPath);
425
22.1k
}
426
427
/************************************************************************/
428
/*                             VSIReadRecursive()                       */
429
/************************************************************************/
430
431
/**
432
 * \brief Read names in a directory recursively.
433
 *
434
 * This function abstracts access to directory contents and subdirectories.
435
 * It returns a list of strings containing the names of files and directories
436
 * in this directory and all subdirectories.  The resulting string list becomes
437
 * the responsibility of the application and should be freed with CSLDestroy()
438
 * when no longer needed.
439
 *
440
 * Note that no error is issued via CPLError() if the directory path is
441
 * invalid, though NULL is returned.
442
 *
443
 * Note: since GDAL 3.9, for recursive mode, the directory separator will no
444
 * longer be always forward slash, but will be the one returned by
445
 * VSIGetDirectorySeparator(pszPathIn), so potentially backslash on Windows
446
 * file systems.
447
 *
448
 * @param pszPathIn the relative, or absolute path of a directory to read.
449
 * UTF-8 encoded.
450
 *
451
 * @return The list of entries in the directory and subdirectories
452
 * or NULL if the directory doesn't exist.  Filenames are returned in UTF-8
453
 * encoding.
454
 * @since GDAL 1.10.0
455
 *
456
 */
457
458
char **VSIReadDirRecursive(const char *pszPathIn)
459
0
{
460
0
    const char SEP = VSIGetDirectorySeparator(pszPathIn)[0];
461
462
0
    const char *const apszOptions[] = {"NAME_AND_TYPE_ONLY=YES", nullptr};
463
0
    VSIDIR *psDir = VSIOpenDir(pszPathIn, -1, apszOptions);
464
0
    if (!psDir)
465
0
        return nullptr;
466
0
    CPLStringList oFiles;
467
0
    while (auto psEntry = VSIGetNextDirEntry(psDir))
468
0
    {
469
0
        if (VSI_ISDIR(psEntry->nMode) && psEntry->pszName[0] &&
470
0
            psEntry->pszName[strlen(psEntry->pszName) - 1] != SEP)
471
0
        {
472
0
            oFiles.AddString((std::string(psEntry->pszName) + SEP).c_str());
473
0
        }
474
0
        else
475
0
        {
476
0
            oFiles.AddString(psEntry->pszName);
477
0
        }
478
0
    }
479
0
    VSICloseDir(psDir);
480
481
0
    return oFiles.StealList();
482
0
}
483
484
/************************************************************************/
485
/*                             CPLReadDir()                             */
486
/*                                                                      */
487
/*      This is present only to provide ABI compatibility with older    */
488
/*      versions.                                                       */
489
/************************************************************************/
490
#undef CPLReadDir
491
492
CPL_C_START
493
char CPL_DLL **CPLReadDir(const char *pszPath);
494
CPL_C_END
495
496
char **CPLReadDir(const char *pszPath)
497
0
{
498
0
    return VSIReadDir(pszPath);
499
0
}
500
501
/************************************************************************/
502
/*                             VSIOpenDir()                             */
503
/************************************************************************/
504
505
/**
506
 * \brief Open a directory to read its entries.
507
 *
508
 * This function is close to the POSIX opendir() function.
509
 *
510
 * For /vsis3/, /vsigs/, /vsioss/, /vsiaz/ and /vsiadls/, this function has an
511
 * efficient implementation, minimizing the number of network requests, when
512
 * invoked with nRecurseDepth <= 0.
513
 *
514
 * Entries are read by calling VSIGetNextDirEntry() on the handled returned by
515
 * that function, until it returns NULL. VSICloseDir() must be called once done
516
 * with the returned directory handle.
517
 *
518
 * @param pszPath the relative, or absolute path of a directory to read.
519
 * UTF-8 encoded.
520
 * @param nRecurseDepth 0 means do not recurse in subdirectories, 1 means
521
 * recurse only in the first level of subdirectories, etc. -1 means unlimited
522
 * recursion level
523
 * @param papszOptions NULL terminated list of options, or NULL. The following
524
 * options are implemented:
525
 * <ul>
526
 * <li>PREFIX=string: (GDAL >= 3.4) Filter to select filenames only starting
527
 *     with the specified prefix. Implemented efficiently for /vsis3/, /vsigs/,
528
 *     and /vsiaz/ (but not /vsiadls/)
529
 * </li>
530
 * <li>NAME_AND_TYPE_ONLY=YES/NO: (GDAL >= 3.4) Defaults to NO. If set to YES,
531
 *     only the pszName and nMode members of VSIDIR are guaranteed to be set.
532
 *     This is implemented efficiently for the Unix virtual file system.
533
 * </li>
534
 * </ul>
535
 *
536
 * @return a handle, or NULL in case of error
537
 * @since GDAL 2.4
538
 *
539
 */
540
541
VSIDIR *VSIOpenDir(const char *pszPath, int nRecurseDepth,
542
                   const char *const *papszOptions)
543
0
{
544
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath);
545
546
0
    return poFSHandler->OpenDir(pszPath, nRecurseDepth, papszOptions);
547
0
}
548
549
/************************************************************************/
550
/*                          VSIGetNextDirEntry()                        */
551
/************************************************************************/
552
553
/**
554
 * \brief Return the next entry of the directory
555
 *
556
 * This function is close to the POSIX readdir() function. It actually returns
557
 * more information (file size, last modification time), which on 'real' file
558
 * systems involve one 'stat' call per file.
559
 *
560
 * For filesystems that can have both a regular file and a directory name of
561
 * the same name (typically /vsis3/), when this situation of duplicate happens,
562
 * the directory name will be suffixed by a slash character. Otherwise directory
563
 * names are not suffixed by slash.
564
 *
565
 * The returned entry remains valid until the next call to VSINextDirEntry()
566
 * or VSICloseDir() with the same handle.
567
 *
568
 * Note: since GDAL 3.9, for recursive mode, the directory separator will no
569
 * longer be always forward slash, but will be the one returned by
570
 * VSIGetDirectorySeparator(pszPathIn), so potentially backslash on Windows
571
 * file systems.
572
 *
573
 * @param dir Directory handled returned by VSIOpenDir(). Must not be NULL.
574
 *
575
 * @return a entry, or NULL if there is no more entry in the directory. This
576
 * return value must not be freed.
577
 * @since GDAL 2.4
578
 *
579
 */
580
581
const VSIDIREntry *VSIGetNextDirEntry(VSIDIR *dir)
582
0
{
583
0
    return dir->NextDirEntry();
584
0
}
585
586
/************************************************************************/
587
/*                             VSICloseDir()                            */
588
/************************************************************************/
589
590
/**
591
 * \brief Close a directory
592
 *
593
 * This function is close to the POSIX closedir() function.
594
 *
595
 * @param dir Directory handled returned by VSIOpenDir().
596
 *
597
 * @since GDAL 2.4
598
 */
599
600
void VSICloseDir(VSIDIR *dir)
601
0
{
602
0
    delete dir;
603
0
}
604
605
/************************************************************************/
606
/*                              VSIMkdir()                              */
607
/************************************************************************/
608
609
/**
610
 * \brief Create a directory.
611
 *
612
 * Create a new directory with the indicated mode. For POSIX-style systems,
613
 * the mode is modified by the file creation mask (umask). However, some
614
 * file systems and platforms may not use umask, or they may ignore the mode
615
 * completely. So a reasonable cross-platform default mode value is 0755.
616
 *
617
 * Analog of the POSIX mkdir() function.
618
 *
619
 * @param pszPathname the path to the directory to create. UTF-8 encoded.
620
 * @param mode the permissions mode.
621
 *
622
 * @return 0 on success or -1 on an error.
623
 */
624
625
int VSIMkdir(const char *pszPathname, long mode)
626
627
0
{
628
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPathname);
629
630
0
    return poFSHandler->Mkdir(pszPathname, mode);
631
0
}
632
633
/************************************************************************/
634
/*                       VSIMkdirRecursive()                            */
635
/************************************************************************/
636
637
/**
638
 * \brief Create a directory and all its ancestors
639
 *
640
 * @param pszPathname the path to the directory to create. UTF-8 encoded.
641
 * @param mode the permissions mode.
642
 *
643
 * @return 0 on success or -1 on an error.
644
 * @since GDAL 2.3
645
 */
646
647
int VSIMkdirRecursive(const char *pszPathname, long mode)
648
5.76k
{
649
5.76k
    if (pszPathname == nullptr || pszPathname[0] == '\0' ||
650
5.76k
        strncmp("/", pszPathname, 2) == 0)
651
0
    {
652
0
        return -1;
653
0
    }
654
655
5.76k
    const CPLString osPathname(pszPathname);
656
5.76k
    VSIStatBufL sStat;
657
5.76k
    if (VSIStatL(osPathname, &sStat) == 0)
658
5.76k
    {
659
5.76k
        return VSI_ISDIR(sStat.st_mode) ? 0 : -1;
660
5.76k
    }
661
0
    const std::string osParentPath(CPLGetPathSafe(osPathname));
662
663
    // Prevent crazy paths from recursing forever.
664
0
    if (osParentPath == osPathname ||
665
0
        osParentPath.length() >= osPathname.length())
666
0
    {
667
0
        return -1;
668
0
    }
669
670
0
    if (!osParentPath.empty() && VSIStatL(osParentPath.c_str(), &sStat) != 0)
671
0
    {
672
0
        if (VSIMkdirRecursive(osParentPath.c_str(), mode) != 0)
673
0
            return -1;
674
0
    }
675
676
0
    return VSIMkdir(osPathname, mode);
677
0
}
678
679
/************************************************************************/
680
/*                             VSIUnlink()                              */
681
/************************************************************************/
682
683
/**
684
 * \brief Delete a file.
685
 *
686
 * Deletes a file object from the file system.
687
 *
688
 * This method goes through the VSIFileHandler virtualization and may
689
 * work on unusual filesystems such as in memory.
690
 *
691
 * Analog of the POSIX unlink() function.
692
 *
693
 * @param pszFilename the path of the file to be deleted. UTF-8 encoded.
694
 *
695
 * @return 0 on success or -1 on an error.
696
 */
697
698
int VSIUnlink(const char *pszFilename)
699
700
27.9k
{
701
27.9k
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
702
703
27.9k
    return poFSHandler->Unlink(pszFilename);
704
27.9k
}
705
706
/************************************************************************/
707
/*                           VSIUnlinkBatch()                           */
708
/************************************************************************/
709
710
/**
711
 * \brief Delete several files, possibly in a batch.
712
 *
713
 * All files should belong to the same file system handler.
714
 *
715
 * This is implemented efficiently for /vsis3/ and /vsigs/ (provided for /vsigs/
716
 * that OAuth2 authentication is used).
717
 *
718
 * @param papszFiles NULL terminated list of files. UTF-8 encoded.
719
 *
720
 * @return an array of size CSLCount(papszFiles), whose values are TRUE or FALSE
721
 * depending on the success of deletion of the corresponding file. The array
722
 * should be freed with VSIFree().
723
 * NULL might be return in case of a more general error (for example,
724
 * files belonging to different file system handlers)
725
 *
726
 * @since GDAL 3.1
727
 */
728
729
int *VSIUnlinkBatch(CSLConstList papszFiles)
730
0
{
731
0
    VSIFilesystemHandler *poFSHandler = nullptr;
732
0
    for (CSLConstList papszIter = papszFiles; papszIter && *papszIter;
733
0
         ++papszIter)
734
0
    {
735
0
        auto poFSHandlerThisFile = VSIFileManager::GetHandler(*papszIter);
736
0
        if (poFSHandler == nullptr)
737
0
            poFSHandler = poFSHandlerThisFile;
738
0
        else if (poFSHandler != poFSHandlerThisFile)
739
0
        {
740
0
            CPLError(CE_Failure, CPLE_AppDefined,
741
0
                     "Files belong to different file system handlers");
742
0
            poFSHandler = nullptr;
743
0
            break;
744
0
        }
745
0
    }
746
0
    if (poFSHandler == nullptr)
747
0
        return nullptr;
748
0
    return poFSHandler->UnlinkBatch(papszFiles);
749
0
}
750
751
/************************************************************************/
752
/*                             VSIRename()                              */
753
/************************************************************************/
754
755
/**
756
 * \brief Rename a file.
757
 *
758
 * Renames a file object in the file system.  It should be possible
759
 * to rename a file onto a new directory, but it is safest if this
760
 * function is only used to rename files that remain in the same directory.
761
 *
762
 * This function only works if the new path is located on the same VSI
763
 * virtual file system than the old path. If not, use VSIMove() instead.
764
 *
765
 * This method goes through the VSIFileHandler virtualization and may
766
 * work on unusual filesystems such as in memory or cloud object storage.
767
 * Note that for cloud object storage, renaming a directory may involve
768
 * renaming all files it contains recursively, and is thus not an atomic
769
 * operation (and could be expensive on directories with many files!)
770
 *
771
 * Analog of the POSIX rename() function.
772
 *
773
 * @param oldpath the name of the file to be renamed.  UTF-8 encoded.
774
 * @param newpath the name the file should be given.  UTF-8 encoded.
775
 *
776
 * @return 0 on success or -1 on an error.
777
 */
778
779
int VSIRename(const char *oldpath, const char *newpath)
780
781
0
{
782
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(oldpath);
783
784
0
    return poFSHandler->Rename(oldpath, newpath, nullptr, nullptr);
785
0
}
786
787
/************************************************************************/
788
/*                             VSIMove()                                */
789
/************************************************************************/
790
791
/**
792
 * \brief Move (or rename) a file.
793
 *
794
 * If the new path is an existing directory, the file will be moved to it.
795
 *
796
 * The function can work even if the files are not located on the same VSI
797
 * virtual file system, but it will involve copying and deletion.
798
 *
799
 * Note that for cloud object storage, moving/renaming a directory may involve
800
 * renaming all files it contains recursively, and is thus not an atomic
801
 * operation (and could be slow and expensive on directories with many files!)
802
 *
803
 * @param oldpath the path of the file to be renamed/moved.  UTF-8 encoded.
804
 * @param newpath the new path the file should be given.  UTF-8 encoded.
805
 * @param papszOptions Null terminated list of options, or NULL.
806
 * @param pProgressFunc Progress callback, or NULL.
807
 * @param pProgressData User data of progress callback, or NULL.
808
 *
809
 * @return 0 on success or -1 on error.
810
 * @since GDAL 3.11
811
 */
812
813
int VSIMove(const char *oldpath, const char *newpath,
814
            const char *const *papszOptions, GDALProgressFunc pProgressFunc,
815
            void *pProgressData)
816
0
{
817
818
0
    if (strcmp(oldpath, newpath) == 0)
819
0
        return 0;
820
821
0
    VSIFilesystemHandler *poOldFSHandler = VSIFileManager::GetHandler(oldpath);
822
0
    VSIFilesystemHandler *poNewFSHandler = VSIFileManager::GetHandler(newpath);
823
824
0
    VSIStatBufL sStat;
825
0
    if (VSIStatL(oldpath, &sStat) != 0)
826
0
    {
827
0
        CPLDebug("VSI", "%s is not a object", oldpath);
828
0
        errno = ENOENT;
829
0
        return -1;
830
0
    }
831
832
0
    std::string sNewpath(newpath);
833
0
    VSIStatBufL sStatNew;
834
0
    if (VSIStatL(newpath, &sStatNew) == 0 && VSI_ISDIR(sStatNew.st_mode))
835
0
    {
836
0
        sNewpath =
837
0
            CPLFormFilenameSafe(newpath, CPLGetFilename(oldpath), nullptr);
838
0
    }
839
840
0
    int ret = 0;
841
842
0
    if (poOldFSHandler == poNewFSHandler)
843
0
    {
844
0
        ret = poOldFSHandler->Rename(oldpath, sNewpath.c_str(), pProgressFunc,
845
0
                                     pProgressData);
846
0
        if (ret == 0 && pProgressFunc)
847
0
            ret = pProgressFunc(1.0, "", pProgressData) ? 0 : -1;
848
0
        return ret;
849
0
    }
850
851
0
    if (VSI_ISDIR(sStat.st_mode))
852
0
    {
853
0
        const CPLStringList aosList(VSIReadDir(oldpath));
854
0
        poNewFSHandler->Mkdir(sNewpath.c_str(), 0755);
855
0
        bool bFoundFiles = false;
856
0
        const int nListSize = aosList.size();
857
0
        for (int i = 0; ret == 0 && i < nListSize; i++)
858
0
        {
859
0
            if (strcmp(aosList[i], ".") != 0 && strcmp(aosList[i], "..") != 0)
860
0
            {
861
0
                bFoundFiles = true;
862
0
                const std::string osSrc =
863
0
                    CPLFormFilenameSafe(oldpath, aosList[i], nullptr);
864
0
                const std::string osTarget =
865
0
                    CPLFormFilenameSafe(sNewpath.c_str(), aosList[i], nullptr);
866
0
                void *pScaledProgress = GDALCreateScaledProgress(
867
0
                    static_cast<double>(i) / nListSize,
868
0
                    static_cast<double>(i + 1) / nListSize, pProgressFunc,
869
0
                    pProgressData);
870
0
                ret = VSIMove(osSrc.c_str(), osTarget.c_str(), papszOptions,
871
0
                              pScaledProgress ? GDALScaledProgress : nullptr,
872
0
                              pScaledProgress);
873
0
                GDALDestroyScaledProgress(pScaledProgress);
874
0
            }
875
0
        }
876
0
        if (!bFoundFiles)
877
0
            ret = VSIStatL(sNewpath.c_str(), &sStat);
878
0
        if (ret == 0)
879
0
            ret = poOldFSHandler->Rmdir(oldpath);
880
0
    }
881
0
    else
882
0
    {
883
0
        ret = VSICopyFile(oldpath, sNewpath.c_str(), nullptr, sStat.st_size,
884
0
                          nullptr, pProgressFunc, pProgressData) == 0 &&
885
0
                      VSIUnlink(oldpath) == 0
886
0
                  ? 0
887
0
                  : -1;
888
0
    }
889
0
    if (ret == 0 && pProgressFunc)
890
0
        ret = pProgressFunc(1.0, "", pProgressData) ? 0 : -1;
891
0
    return ret;
892
0
}
893
894
/************************************************************************/
895
/*                             VSICopyFile()                            */
896
/************************************************************************/
897
898
/**
899
 * \brief Copy a source file into a target file.
900
 *
901
 * For a /vsizip/foo.zip/bar target, the options available are those of
902
 * CPLAddFileInZip()
903
 *
904
 * The following copies are made fully on the target server, without local
905
 * download from source and upload to target:
906
 * - /vsis3/ -> /vsis3/
907
 * - /vsigs/ -> /vsigs/
908
 * - /vsiaz/ -> /vsiaz/
909
 * - /vsiadls/ -> /vsiadls/
910
 * - any of the above or /vsicurl/ -> /vsiaz/ (starting with GDAL 3.8)
911
 *
912
 * @param pszSource Source filename. UTF-8 encoded. May be NULL if fpSource is
913
 * not NULL.
914
 * @param pszTarget Target filename.  UTF-8 encoded. Must not be NULL
915
 * @param fpSource File handle on the source file. May be NULL if pszSource is
916
 * not NULL.
917
 * @param nSourceSize Size of the source file. Pass -1 if unknown.
918
 * If set to -1, and progress callback is used, VSIStatL() will be used on
919
 * pszSource to retrieve the source size.
920
 * @param papszOptions Null terminated list of options, or NULL.
921
 * @param pProgressFunc Progress callback, or NULL.
922
 * @param pProgressData User data of progress callback, or NULL.
923
 *
924
 * @return 0 on success.
925
 * @since GDAL 3.7
926
 */
927
928
int VSICopyFile(const char *pszSource, const char *pszTarget,
929
                VSILFILE *fpSource, vsi_l_offset nSourceSize,
930
                const char *const *papszOptions, GDALProgressFunc pProgressFunc,
931
                void *pProgressData)
932
933
0
{
934
0
    if (!pszSource && !fpSource)
935
0
    {
936
0
        CPLError(CE_Failure, CPLE_AppDefined,
937
0
                 "pszSource == nullptr && fpSource == nullptr");
938
0
        return -1;
939
0
    }
940
0
    if (!pszTarget || pszTarget[0] == '\0')
941
0
    {
942
0
        return -1;
943
0
    }
944
945
0
    VSIFilesystemHandler *poFSHandlerTarget =
946
0
        VSIFileManager::GetHandler(pszTarget);
947
0
    return poFSHandlerTarget->CopyFile(pszSource, pszTarget, fpSource,
948
0
                                       nSourceSize, papszOptions, pProgressFunc,
949
0
                                       pProgressData);
950
0
}
951
952
/************************************************************************/
953
/*                       VSICopyFileRestartable()                       */
954
/************************************************************************/
955
956
/**
957
 \brief Copy a source file into a target file in a way that can (potentially)
958
 be restarted.
959
960
 This function provides the possibility of efficiently restarting upload of
961
 large files to cloud storage that implements upload in a chunked way,
962
 such as /vsis3/ and /vsigs/.
963
 For other destination file systems, this function may fallback to
964
 VSICopyFile() and not provide any smart restartable implementation.
965
966
 Example of a potential workflow:
967
968
 @code{.cpp}
969
 char* pszOutputPayload = NULL;
970
 int ret = VSICopyFileRestartable(pszSource, pszTarget, NULL,
971
                                  &pszOutputPayload, NULL, NULL, NULL);
972
 while( ret == 1 ) // add also a limiting counter to avoid potentiall endless looping
973
 {
974
     // TODO: wait for some time
975
976
     char* pszOutputPayloadNew = NULL;
977
     const char* pszInputPayload = pszOutputPayload;
978
     ret = VSICopyFileRestartable(pszSource, pszTarget, pszInputPayload,
979
                                  &pszOutputPayloadNew, NULL, NULL, NULL);
980
     VSIFree(pszOutputPayload);
981
     pszOutputPayload = pszOutputPayloadNew;
982
 }
983
 VSIFree(pszOutputPayload);
984
 @endcode
985
986
 @param pszSource Source filename. UTF-8 encoded. Must not be NULL
987
 @param pszTarget Target filename. UTF-8 encoded. Must not be NULL
988
 @param pszInputPayload NULL at the first invocation. When doing a retry,
989
                        should be the content of *ppszOutputPayload from a
990
                        previous invocation.
991
 @param[out] ppszOutputPayload Pointer to an output string that will be set to
992
                               a value that can be provided as pszInputPayload
993
                               for a next call to VSICopyFileRestartable().
994
                               ppszOutputPayload must not be NULL.
995
                               The string set in *ppszOutputPayload, if not NULL,
996
                               is JSON-encoded, and can be re-used in another
997
                               process instance. It must be freed with VSIFree()
998
                               when no longer needed.
999
 @param papszOptions Null terminated list of options, or NULL.
1000
 Currently accepted options are:
1001
 <ul>
1002
 <li>NUM_THREADS=integer or ALL_CPUS. Number of threads to use for parallel
1003
 file copying. Only use for when /vsis3/, /vsigs/, /vsiaz/ or /vsiadls/ is in
1004
 source or target. The default is 10.
1005
 </li>
1006
 <li>CHUNK_SIZE=integer. Maximum size of chunk (in bytes) to use
1007
 to split large objects. For upload to /vsis3/, this chunk size must be set at
1008
 least to 5 MB. The default is 50 MB.
1009
 </li>
1010
 </ul>
1011
 @param pProgressFunc Progress callback, or NULL.
1012
 @param pProgressData User data of progress callback, or NULL.
1013
 @return 0 on success,
1014
         -1 on (non-restartable) failure,
1015
         1 if VSICopyFileRestartable() can be called again in a restartable way
1016
 @since GDAL 3.10
1017
1018
 @see VSIAbortPendingUploads()
1019
*/
1020
1021
int VSICopyFileRestartable(const char *pszSource, const char *pszTarget,
1022
                           const char *pszInputPayload,
1023
                           char **ppszOutputPayload,
1024
                           const char *const *papszOptions,
1025
                           GDALProgressFunc pProgressFunc, void *pProgressData)
1026
1027
0
{
1028
0
    if (!pszSource)
1029
0
    {
1030
0
        return -1;
1031
0
    }
1032
0
    if (!pszTarget || pszTarget[0] == '\0')
1033
0
    {
1034
0
        return -1;
1035
0
    }
1036
0
    if (!ppszOutputPayload)
1037
0
    {
1038
0
        return -1;
1039
0
    }
1040
1041
0
    VSIFilesystemHandler *poFSHandlerTarget =
1042
0
        VSIFileManager::GetHandler(pszTarget);
1043
0
    return poFSHandlerTarget->CopyFileRestartable(
1044
0
        pszSource, pszTarget, pszInputPayload, ppszOutputPayload, papszOptions,
1045
0
        pProgressFunc, pProgressData);
1046
0
}
1047
1048
/************************************************************************/
1049
/*                             VSISync()                                */
1050
/************************************************************************/
1051
1052
/**
1053
 * \brief Synchronize a source file/directory with a target file/directory.
1054
 *
1055
 * This is a analog of the 'rsync' utility. In the current implementation,
1056
 * rsync would be more efficient for local file copying, but VSISync() main
1057
 * interest is when the source or target is a remote
1058
 * file system like /vsis3/ or /vsigs/, in which case it can take into account
1059
 * the timestamps of the files (or optionally the ETag/MD5Sum) to avoid
1060
 * unneeded copy operations.
1061
 *
1062
 * This is only implemented efficiently for:
1063
 * <ul>
1064
 * <li> local filesystem <--> remote filesystem.</li>
1065
 * <li> remote filesystem <--> remote filesystem (starting with GDAL 3.1).
1066
 * Where the source and target remote filesystems are the same and one of
1067
 * /vsis3/, /vsigs/ or /vsiaz/. Or when the target is /vsiaz/ and the source
1068
 * is /vsis3/, /vsigs/, /vsiadls/ or /vsicurl/ (starting with GDAL 3.8)</li>
1069
 * </ul>
1070
 *
1071
 * Similarly to rsync behavior, if the source filename ends with a slash,
1072
 * it means that the content of the directory must be copied, but not the
1073
 * directory name. For example, assuming "/home/even/foo" contains a file "bar",
1074
 * VSISync("/home/even/foo/", "/mnt/media", ...) will create a "/mnt/media/bar"
1075
 * file. Whereas VSISync("/home/even/foo", "/mnt/media", ...) will create a
1076
 * "/mnt/media/foo" directory which contains a bar file.
1077
 *
1078
 * @param pszSource Source file or directory.  UTF-8 encoded.
1079
 * @param pszTarget Target file or directory.  UTF-8 encoded.
1080
 * @param papszOptions Null terminated list of options, or NULL.
1081
 * Currently accepted options are:
1082
 * <ul>
1083
 * <li>RECURSIVE=NO (the default is YES)</li>
1084
 * <li>SYNC_STRATEGY=TIMESTAMP/ETAG/OVERWRITE.
1085
 *
1086
 *     Determines which criterion is used to determine if a target file must be
1087
 *     replaced when it already exists and has the same file size as the source.
1088
 *     Only applies for a source or target being a network filesystem.
1089
 *
1090
 *     The default is TIMESTAMP (similarly to how 'aws s3 sync' works), that is
1091
 *     to say that for an upload operation, a remote file is
1092
 *     replaced if it has a different size or if it is older than the source.
1093
 *     For a download operation, a local file is  replaced if it has a different
1094
 *     size or if it is newer than the remote file.
1095
 *
1096
 *     The ETAG strategy assumes that the ETag metadata of the remote file is
1097
 *     the MD5Sum of the file content, which is only true in the case of /vsis3/
1098
 *     for files not using KMS server side encryption and uploaded in a single
1099
 *     PUT operation (so smaller than 50 MB given the default used by GDAL).
1100
 *     Only to be used for /vsis3/, /vsigs/ or other filesystems using a
1101
 *     MD5Sum as ETAG.
1102
 *
1103
 *     The OVERWRITE strategy (GDAL >= 3.2) will always overwrite the target
1104
 *     file with the source one.
1105
 * </li>
1106
 * <li>NUM_THREADS=integer. (GDAL >= 3.1) Number of threads to use for parallel
1107
 * file copying. Only use for when /vsis3/, /vsigs/, /vsiaz/ or /vsiadls/ is in
1108
 * source or target. The default is 10 since GDAL 3.3</li>
1109
 * <li>CHUNK_SIZE=integer. (GDAL >= 3.1) Maximum size of chunk (in bytes) to use
1110
 * to split large objects when downloading them from /vsis3/, /vsigs/, /vsiaz/
1111
 * or /vsiadls/ to local file system, or for upload to /vsis3/, /vsiaz/ or
1112
 * /vsiadls/ from local file system. Only used if NUM_THREADS > 1. For upload to
1113
 * /vsis3/, this chunk size must be set at least to 5 MB. The default is 8 MB
1114
 * since GDAL 3.3</li> <li>x-amz-KEY=value. (GDAL >= 3.5) MIME header to pass
1115
 * during creation of a /vsis3/ object.</li> <li>x-goog-KEY=value. (GDAL >= 3.5)
1116
 * MIME header to pass during creation of a /vsigs/ object.</li>
1117
 * <li>x-ms-KEY=value. (GDAL >= 3.5) MIME header to pass during creation of a
1118
 * /vsiaz/ or /vsiadls/ object.</li>
1119
 * </ul>
1120
 * @param pProgressFunc Progress callback, or NULL.
1121
 * @param pProgressData User data of progress callback, or NULL.
1122
 * @param ppapszOutputs Unused. Should be set to NULL for now.
1123
 *
1124
 * @return TRUE on success or FALSE on an error.
1125
 * @since GDAL 2.4
1126
 */
1127
1128
int VSISync(const char *pszSource, const char *pszTarget,
1129
            const char *const *papszOptions, GDALProgressFunc pProgressFunc,
1130
            void *pProgressData, char ***ppapszOutputs)
1131
1132
0
{
1133
0
    if (pszSource[0] == '\0' || pszTarget[0] == '\0')
1134
0
    {
1135
0
        return FALSE;
1136
0
    }
1137
1138
0
    VSIFilesystemHandler *poFSHandlerSource =
1139
0
        VSIFileManager::GetHandler(pszSource);
1140
0
    VSIFilesystemHandler *poFSHandlerTarget =
1141
0
        VSIFileManager::GetHandler(pszTarget);
1142
0
    VSIFilesystemHandler *poFSHandlerLocal = VSIFileManager::GetHandler("");
1143
0
    VSIFilesystemHandler *poFSHandlerMem =
1144
0
        VSIFileManager::GetHandler("/vsimem/");
1145
0
    VSIFilesystemHandler *poFSHandler = poFSHandlerSource;
1146
0
    if (poFSHandlerTarget != poFSHandlerLocal &&
1147
0
        poFSHandlerTarget != poFSHandlerMem)
1148
0
    {
1149
0
        poFSHandler = poFSHandlerTarget;
1150
0
    }
1151
1152
0
    return poFSHandler->Sync(pszSource, pszTarget, papszOptions, pProgressFunc,
1153
0
                             pProgressData, ppapszOutputs)
1154
0
               ? TRUE
1155
0
               : FALSE;
1156
0
}
1157
1158
/************************************************************************/
1159
/*                    VSIMultipartUploadGetCapabilities()               */
1160
/************************************************************************/
1161
1162
/**
1163
 * \brief Return capabilities for multiple part file upload.
1164
 *
1165
 * @param pszFilename Filename, or virtual file system prefix, onto which
1166
 * capabilities should apply.
1167
 * @param[out] pbNonSequentialUploadSupported If not null,
1168
 * the pointed value is set if parts can be uploaded in a non-sequential way.
1169
 * @param[out] pbParallelUploadSupported If not null,
1170
 * the pointed value is set if parts can be uploaded in a parallel way.
1171
 * (implies *pbNonSequentialUploadSupported = true)
1172
 * @param[out] pbAbortSupported If not null,
1173
 * the pointed value is set if VSIMultipartUploadAbort() is implemented.
1174
 * @param[out] pnMinPartSize If not null, the pointed value is set to the minimum
1175
 * size of parts (but the last one), in MiB.
1176
 * @param[out] pnMaxPartSize If not null, the pointed value is set to the maximum
1177
 * size of parts, in MiB.
1178
 * @param[out] pnMaxPartCount  If not null, the pointed value is set to the
1179
 * maximum number of parts that can be uploaded.
1180
 *
1181
 * @return TRUE in case of success, FALSE otherwise.
1182
 *
1183
 * @since 3.10
1184
 */
1185
int VSIMultipartUploadGetCapabilities(
1186
    const char *pszFilename, int *pbNonSequentialUploadSupported,
1187
    int *pbParallelUploadSupported, int *pbAbortSupported,
1188
    size_t *pnMinPartSize, size_t *pnMaxPartSize, int *pnMaxPartCount)
1189
0
{
1190
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
1191
1192
0
    return poFSHandler->MultipartUploadGetCapabilities(
1193
0
        pbNonSequentialUploadSupported, pbParallelUploadSupported,
1194
0
        pbAbortSupported, pnMinPartSize, pnMaxPartSize, pnMaxPartCount);
1195
0
}
1196
1197
/************************************************************************/
1198
/*                     VSIMultipartUploadStart()                        */
1199
/************************************************************************/
1200
1201
/**
1202
 * \brief Initiates the upload a (big) file in a piece-wise way.
1203
 *
1204
 * Using this API directly is generally not needed, but in very advanced cases,
1205
 * as VSIFOpenL(..., "wb") + VSIFWriteL(), VSISync(), VSICopyFile() or
1206
 * VSICopyFileRestartable() may be able to leverage it when needed.
1207
 *
1208
 * This is only implemented for the /vsis3/, /vsigs/, /vsiaz/, /vsiadls/ and
1209
 * /vsioss/ virtual file systems.
1210
 *
1211
 * The typical workflow is to do :
1212
 * - VSIMultipartUploadStart()
1213
 * - VSIMultipartUploadAddPart(): several times
1214
 * - VSIMultipartUploadEnd()
1215
 *
1216
 * If VSIMultipartUploadAbort() is supported by the filesystem (VSIMultipartUploadGetCapabilities()
1217
 * can be used to determine it), this function should be called to cancel an
1218
 * upload. This can be needed to avoid extra billing for some cloud storage
1219
 * providers.
1220
 *
1221
 * The following options are supported:
1222
 * <ul>
1223
 * <li>MIME headers such as Content-Type and Content-Encoding
1224
 * are supported for the /vsis3/, /vsigs/, /vsiaz/, /vsiadls/ file systems.</li>
1225
 * </ul>
1226
 *
1227
 * @param pszFilename Filename to create
1228
 * @param papszOptions NULL or null-terminated list of options.
1229
 * @return an upload ID to pass to other VSIMultipartUploadXXXXX() functions,
1230
 * and to free with CPLFree() once done, or nullptr in case of error.
1231
 *
1232
 * @since 3.10
1233
 */
1234
char *VSIMultipartUploadStart(const char *pszFilename,
1235
                              CSLConstList papszOptions)
1236
0
{
1237
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
1238
1239
0
    return poFSHandler->MultipartUploadStart(pszFilename, papszOptions);
1240
0
}
1241
1242
/************************************************************************/
1243
/*                     VSIMultipartUploadAddPart()                      */
1244
/************************************************************************/
1245
1246
/**
1247
 * \brief Uploads a new part to a multi-part uploaded file.
1248
 *
1249
 * Cf VSIMultipartUploadStart().
1250
 *
1251
 * VSIMultipartUploadGetCapabilities() returns hints on the constraints that
1252
 * apply to the upload, in terms of minimum/maximum size of each part, maximum
1253
 * number of parts, and whether non-sequential or parallel uploads are
1254
 * supported.
1255
 *
1256
 * @param pszFilename Filename to which to append the new part. Should be the
1257
 *                    same as the one used for VSIMultipartUploadStart()
1258
 * @param pszUploadId Value returned by VSIMultipartUploadStart()
1259
 * @param nPartNumber Part number, starting at 1.
1260
 * @param nFileOffset Offset within the file at which (starts at 0) the passed
1261
 *                    data starts.
1262
 * @param pData       Pointer to an array of nDataLength bytes.
1263
 * @param nDataLength Size in bytes of pData.
1264
 * @param papszOptions Unused. Should be nullptr.
1265
 *
1266
 * @return a part identifier that must be passed into the apszPartIds[] array of
1267
 * VSIMultipartUploadEnd(), and to free with CPLFree() once done, or nullptr in
1268
 * case of error.
1269
 *
1270
 * @since 3.10
1271
 */
1272
char *VSIMultipartUploadAddPart(const char *pszFilename,
1273
                                const char *pszUploadId, int nPartNumber,
1274
                                vsi_l_offset nFileOffset, const void *pData,
1275
                                size_t nDataLength, CSLConstList papszOptions)
1276
0
{
1277
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
1278
1279
0
    return poFSHandler->MultipartUploadAddPart(pszFilename, pszUploadId,
1280
0
                                               nPartNumber, nFileOffset, pData,
1281
0
                                               nDataLength, papszOptions);
1282
0
}
1283
1284
/************************************************************************/
1285
/*                       VSIMultipartUploadEnd()                        */
1286
/************************************************************************/
1287
1288
/**
1289
 * \brief Completes a multi-part file upload.
1290
 *
1291
 * Cf VSIMultipartUploadStart().
1292
 *
1293
 * @param pszFilename Filename for which multipart upload should be completed.
1294
 *                    Should be the same as the one used for
1295
 *                    VSIMultipartUploadStart()
1296
 * @param pszUploadId Value returned by VSIMultipartUploadStart()
1297
 * @param nPartIdsCount Number of parts,  andsize of apszPartIds
1298
 * @param apszPartIds Array of part identifiers (as returned by
1299
 *                    VSIMultipartUploadAddPart()), that must be ordered in
1300
 *                    the sequential order of parts, and of size nPartIdsCount.
1301
 * @param nTotalSize  Total size of the file in bytes (must be equal to the sum
1302
 *                    of nDataLength passed to VSIMultipartUploadAddPart())
1303
 * @param papszOptions Unused. Should be nullptr.
1304
 *
1305
 * @return TRUE in case of success, FALSE in case of failure.
1306
 *
1307
 * @since 3.10
1308
 */
1309
int VSIMultipartUploadEnd(const char *pszFilename, const char *pszUploadId,
1310
                          size_t nPartIdsCount, const char *const *apszPartIds,
1311
                          vsi_l_offset nTotalSize, CSLConstList papszOptions)
1312
0
{
1313
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
1314
1315
0
    return poFSHandler->MultipartUploadEnd(pszFilename, pszUploadId,
1316
0
                                           nPartIdsCount, apszPartIds,
1317
0
                                           nTotalSize, papszOptions);
1318
0
}
1319
1320
/************************************************************************/
1321
/*                       VSIMultipartUploadAbort()                      */
1322
/************************************************************************/
1323
1324
/**
1325
 * \brief Aborts a multi-part file upload.
1326
 *
1327
 * Cf VSIMultipartUploadStart().
1328
 *
1329
 * This function is not implemented for all virtual file systems.
1330
 * Use VSIMultipartUploadGetCapabilities() to determine if it is supported.
1331
 *
1332
 * This can be needed to avoid extra billing for some cloud storage providers.
1333
 *
1334
 * @param pszFilename Filename for which multipart upload should be completed.
1335
 *                    Should be the same as the one used for
1336
 *                    VSIMultipartUploadStart()
1337
 * @param pszUploadId Value returned by VSIMultipartUploadStart()
1338
 * @param papszOptions Unused. Should be nullptr.
1339
 *
1340
 * @return TRUE in case of success, FALSE in case of failure.
1341
 *
1342
 * @since 3.10
1343
 */
1344
int VSIMultipartUploadAbort(const char *pszFilename, const char *pszUploadId,
1345
                            CSLConstList papszOptions)
1346
0
{
1347
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
1348
1349
0
    return poFSHandler->MultipartUploadAbort(pszFilename, pszUploadId,
1350
0
                                             papszOptions);
1351
0
}
1352
1353
#ifndef DOXYGEN_SKIP
1354
1355
/************************************************************************/
1356
/*                     MultipartUploadGetCapabilities()                 */
1357
/************************************************************************/
1358
1359
bool VSIFilesystemHandler::MultipartUploadGetCapabilities(int *, int *, int *,
1360
                                                          size_t *, size_t *,
1361
                                                          int *)
1362
0
{
1363
0
    CPLError(
1364
0
        CE_Failure, CPLE_NotSupported,
1365
0
        "MultipartUploadGetCapabilities() not supported by this file system");
1366
0
    return false;
1367
0
}
1368
1369
/************************************************************************/
1370
/*                         MultipartUploadStart()                       */
1371
/************************************************************************/
1372
1373
char *VSIFilesystemHandler::MultipartUploadStart(const char *, CSLConstList)
1374
0
{
1375
0
    CPLError(CE_Failure, CPLE_NotSupported,
1376
0
             "MultipartUploadStart() not supported by this file system");
1377
0
    return nullptr;
1378
0
}
1379
1380
/************************************************************************/
1381
/*                       MultipartUploadAddPart()                       */
1382
/************************************************************************/
1383
1384
char *VSIFilesystemHandler::MultipartUploadAddPart(const char *, const char *,
1385
                                                   int, vsi_l_offset,
1386
                                                   const void *, size_t,
1387
                                                   CSLConstList)
1388
0
{
1389
0
    CPLError(CE_Failure, CPLE_NotSupported,
1390
0
             "MultipartUploadAddPart() not supported by this file system");
1391
0
    return nullptr;
1392
0
}
1393
1394
/************************************************************************/
1395
/*                         MultipartUploadEnd()                         */
1396
/************************************************************************/
1397
1398
bool VSIFilesystemHandler::MultipartUploadEnd(const char *, const char *,
1399
                                              size_t, const char *const *,
1400
                                              vsi_l_offset, CSLConstList)
1401
0
{
1402
0
    CPLError(CE_Failure, CPLE_NotSupported,
1403
0
             "MultipartUploadEnd() not supported by this file system");
1404
0
    return FALSE;
1405
0
}
1406
1407
/************************************************************************/
1408
/*                         MultipartUploadAbort()                       */
1409
/************************************************************************/
1410
1411
bool VSIFilesystemHandler::MultipartUploadAbort(const char *, const char *,
1412
                                                CSLConstList)
1413
0
{
1414
0
    CPLError(CE_Failure, CPLE_NotSupported,
1415
0
             "MultipartUploadAbort() not supported by this file system");
1416
0
    return FALSE;
1417
0
}
1418
1419
#endif
1420
1421
/************************************************************************/
1422
/*                         VSIAbortPendingUploads()                     */
1423
/************************************************************************/
1424
1425
/**
1426
 * \brief Abort all ongoing multi-part uploads.
1427
 *
1428
 * Abort ongoing multi-part uploads on AWS S3 and Google Cloud Storage. This
1429
 * can be used in case a process doing such uploads was killed in a unclean way.
1430
 *
1431
 * This can be needed to avoid extra billing for some cloud storage providers.
1432
 *
1433
 * Without effect on other virtual file systems.
1434
 *
1435
 * VSIMultipartUploadAbort() can also be used to cancel a given upload, if the
1436
 * upload ID is known.
1437
 *
1438
 * @param pszFilename filename or prefix of a directory into which multipart
1439
 * uploads must be aborted. This can be the root directory of a bucket.  UTF-8
1440
 * encoded.
1441
 *
1442
 * @return TRUE on success or FALSE on an error.
1443
 * @since GDAL 3.4
1444
 */
1445
1446
int VSIAbortPendingUploads(const char *pszFilename)
1447
0
{
1448
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
1449
1450
0
    return poFSHandler->AbortPendingUploads(pszFilename);
1451
0
}
1452
1453
/************************************************************************/
1454
/*                              VSIRmdir()                              */
1455
/************************************************************************/
1456
1457
/**
1458
 * \brief Delete a directory.
1459
 *
1460
 * Deletes a directory object from the file system.  On some systems
1461
 * the directory must be empty before it can be deleted.
1462
 *
1463
 * This method goes through the VSIFileHandler virtualization and may
1464
 * work on unusual filesystems such as in memory.
1465
 *
1466
 * Analog of the POSIX rmdir() function.
1467
 *
1468
 * @param pszDirname the path of the directory to be deleted.  UTF-8 encoded.
1469
 *
1470
 * @return 0 on success or -1 on an error.
1471
 */
1472
1473
int VSIRmdir(const char *pszDirname)
1474
1475
0
{
1476
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszDirname);
1477
1478
0
    return poFSHandler->Rmdir(pszDirname);
1479
0
}
1480
1481
/************************************************************************/
1482
/*                         VSIRmdirRecursive()                          */
1483
/************************************************************************/
1484
1485
/**
1486
 * \brief Delete a directory recursively
1487
 *
1488
 * Deletes a directory object and its content from the file system.
1489
 *
1490
 * Starting with GDAL 3.1, /vsis3/ has an efficient implementation of this
1491
 * function.
1492
 * Starting with GDAL 3.4, /vsigs/ has an efficient implementation of this
1493
 * function, provided that OAuth2 authentication is used.
1494
 *
1495
 * @return 0 on success or -1 on an error.
1496
 * @since GDAL 2.3
1497
 */
1498
1499
int VSIRmdirRecursive(const char *pszDirname)
1500
0
{
1501
0
    if (pszDirname == nullptr || pszDirname[0] == '\0' ||
1502
0
        strncmp("/", pszDirname, 2) == 0)
1503
0
    {
1504
0
        return -1;
1505
0
    }
1506
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszDirname);
1507
0
    return poFSHandler->RmdirRecursive(pszDirname);
1508
0
}
1509
1510
/************************************************************************/
1511
/*                              VSIStatL()                              */
1512
/************************************************************************/
1513
1514
/**
1515
 * \brief Get filesystem object info.
1516
 *
1517
 * Fetches status information about a filesystem object (file, directory, etc).
1518
 * The returned information is placed in the VSIStatBufL structure.   For
1519
 * portability, only use the st_size (size in bytes) and st_mode (file type).
1520
 * This method is similar to VSIStat(), but will work on large files on
1521
 * systems where this requires special calls.
1522
 *
1523
 * This method goes through the VSIFileHandler virtualization and may
1524
 * work on unusual filesystems such as in memory.
1525
 *
1526
 * Analog of the POSIX stat() function.
1527
 *
1528
 * @param pszFilename the path of the filesystem object to be queried.
1529
 * UTF-8 encoded.
1530
 * @param psStatBuf the structure to load with information.
1531
 *
1532
 * @return 0 on success or -1 on an error.
1533
 */
1534
1535
int VSIStatL(const char *pszFilename, VSIStatBufL *psStatBuf)
1536
1537
7.31k
{
1538
7.31k
    return VSIStatExL(pszFilename, psStatBuf, 0);
1539
7.31k
}
1540
1541
/************************************************************************/
1542
/*                            VSIStatExL()                              */
1543
/************************************************************************/
1544
1545
/**
1546
 * \brief Get filesystem object info.
1547
 *
1548
 * Fetches status information about a filesystem object (file, directory, etc).
1549
 * The returned information is placed in the VSIStatBufL structure.   For
1550
 * portability, only use the st_size (size in bytes) and st_mode (file type).
1551
 * This method is similar to VSIStat(), but will work on large files on
1552
 * systems where this requires special calls.
1553
 *
1554
 * This method goes through the VSIFileHandler virtualization and may
1555
 * work on unusual filesystems such as in memory.
1556
 *
1557
 * Analog of the POSIX stat() function, with an extra parameter to
1558
 * specify which information is needed, which offers a potential for
1559
 * speed optimizations on specialized and potentially slow virtual
1560
 * filesystem objects (/vsigzip/, /vsicurl/)
1561
 *
1562
 * @param pszFilename the path of the filesystem object to be queried.
1563
 * UTF-8 encoded.
1564
 * @param psStatBuf the structure to load with information.
1565
 * @param nFlags 0 to get all information, or VSI_STAT_EXISTS_FLAG,
1566
 *                 VSI_STAT_NATURE_FLAG, VSI_STAT_SIZE_FLAG,
1567
 * VSI_STAT_SET_ERROR_FLAG, VSI_STAT_CACHE_ONLY or a combination of those to get
1568
 * partial info.
1569
 *
1570
 * @return 0 on success or -1 on an error.
1571
 *
1572
 * @since GDAL 1.8.0
1573
 */
1574
1575
int VSIStatExL(const char *pszFilename, VSIStatBufL *psStatBuf, int nFlags)
1576
1577
18.2k
{
1578
18.2k
    char szAltPath[4] = {'\0'};
1579
1580
    // Enable to work on "C:" as if it were "C:\".
1581
18.2k
    if (pszFilename[0] != '\0' && pszFilename[1] == ':' &&
1582
18.2k
        pszFilename[2] == '\0')
1583
68
    {
1584
68
        szAltPath[0] = pszFilename[0];
1585
68
        szAltPath[1] = pszFilename[1];
1586
68
        szAltPath[2] = '\\';
1587
68
        szAltPath[3] = '\0';
1588
1589
68
        pszFilename = szAltPath;
1590
68
    }
1591
1592
18.2k
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
1593
1594
18.2k
    if (nFlags == 0)
1595
7.31k
        nFlags =
1596
7.31k
            VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG | VSI_STAT_SIZE_FLAG;
1597
1598
18.2k
    return poFSHandler->Stat(pszFilename, psStatBuf, nFlags);
1599
18.2k
}
1600
1601
/************************************************************************/
1602
/*                       VSIGetFileMetadata()                           */
1603
/************************************************************************/
1604
1605
/**
1606
 * \brief Get metadata on files.
1607
 *
1608
 * Implemented currently only for network-like filesystems, or starting
1609
 * with GDAL 3.7 for /vsizip/
1610
 *
1611
 * Starting with GDAL 3.11, calling it with pszFilename being the root of a
1612
 * /vsigs/ bucket and pszDomain == nullptr, and when authenticated through
1613
 * OAuth2, will result in returning the result of a "Buckets: get"
1614
 * operation (https://cloud.google.com/storage/docs/json_api/v1/buckets/get),
1615
 * with the keys of the top-level JSON document as keys of the key=value pairs
1616
 * returned by this function.
1617
 *
1618
 * @param pszFilename the path of the filesystem object to be queried.
1619
 * UTF-8 encoded.
1620
 * @param pszDomain Metadata domain to query. Depends on the file system.
1621
 * The following ones are supported:
1622
 * <ul>
1623
 * <li>HEADERS: to get HTTP headers for network-like filesystems (/vsicurl/,
1624
 * /vsis3/, /vsgis/, etc)</li>
1625
 * <li>TAGS:
1626
 *   <ul>
1627
 *     <li>/vsis3/: to get S3 Object tagging information</li>
1628
 *     <li>/vsiaz/: to get blob tags. Refer to
1629
 *     https://docs.microsoft.com/en-us/rest/api/storageservices/get-blob-tags
1630
 *     </li>
1631
 *   </ul>
1632
 * </li>
1633
 * <li>STATUS: specific to /vsiadls/: returns all system defined properties for
1634
 * a path (seems in practice to be a subset of HEADERS)</li> <li>ACL: specific
1635
 * to /vsiadls/ and /vsigs/: returns the access control list for a path. For
1636
 * /vsigs/, a single XML=xml_content string is returned. Refer to
1637
 * https://cloud.google.com/storage/docs/xml-api/get-object-acls
1638
 * </li>
1639
 * <li>METADATA: specific to /vsiaz/: to get blob metadata. Refer to
1640
 * https://docs.microsoft.com/en-us/rest/api/storageservices/get-blob-metadata.
1641
 * Note: this will be a subset of what pszDomain=HEADERS returns</li>
1642
 * <li>ZIP: specific to /vsizip/: to obtain ZIP specific metadata, in particular
1643
 * if a file is SOZIP-enabled (SOZIP_VALID=YES)</li>
1644
 * </ul>
1645
 * @param papszOptions Unused. Should be set to NULL.
1646
 *
1647
 * @return a NULL-terminated list of key=value strings, to be freed with
1648
 * CSLDestroy() or NULL in case of error / empty list.
1649
 *
1650
 * @since GDAL 3.1.0
1651
 */
1652
1653
char **VSIGetFileMetadata(const char *pszFilename, const char *pszDomain,
1654
                          CSLConstList papszOptions)
1655
0
{
1656
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
1657
0
    return poFSHandler->GetFileMetadata(pszFilename, pszDomain, papszOptions);
1658
0
}
1659
1660
/************************************************************************/
1661
/*                       VSISetFileMetadata()                           */
1662
/************************************************************************/
1663
1664
/**
1665
 * \brief Set metadata on files.
1666
 *
1667
 * Implemented currently only for /vsis3/, /vsigs/, /vsiaz/ and /vsiadls/
1668
 *
1669
 * @param pszFilename the path of the filesystem object to be set.
1670
 * UTF-8 encoded.
1671
 * @param papszMetadata NULL-terminated list of key=value strings.
1672
 * @param pszDomain Metadata domain to set. Depends on the file system.
1673
 * The following are supported:
1674
 * <ul>
1675
 * <li>HEADERS: specific to /vsis3/ and /vsigs/: to set HTTP headers, such as
1676
 * "Content-Type", or other file system specific header.
1677
 * For /vsigs/, this also includes: x-goog-meta-{key}={value}. Note that you
1678
 * should specify all metadata to be set, as existing metadata will be
1679
 * overridden.
1680
 * </li>
1681
 * <li>TAGS: Content of papszMetadata should be KEY=VALUE pairs.
1682
 *    <ul>
1683
 *      <li>/vsis3/: to set S3 Object tagging information</li>
1684
 *      <li>/vsiaz/: to set blob tags. Refer to
1685
 * https://docs.microsoft.com/en-us/rest/api/storageservices/set-blob-tags.
1686
 * Note: storageV2 must be enabled on the account</li>
1687
 *    </ul>
1688
 * </li>
1689
 * <li>PROPERTIES:
1690
 *    <ul>
1691
 *      <li>to /vsiaz/: to set properties. Refer to
1692
 * https://docs.microsoft.com/en-us/rest/api/storageservices/set-blob-properties.</li>
1693
 *      <li>to /vsiadls/: to set properties. Refer to
1694
 * https://docs.microsoft.com/en-us/rest/api/storageservices/datalakestoragegen2/path/update
1695
 * for headers valid for action=setProperties.</li>
1696
 *    </ul>
1697
 * </li>
1698
 * <li>ACL: specific to /vsiadls/ and /vsigs/: to set access control list.
1699
 * For /vsiadls/, refer to
1700
 * https://docs.microsoft.com/en-us/rest/api/storageservices/datalakestoragegen2/path/update
1701
 * for headers valid for action=setAccessControl or setAccessControlRecursive.
1702
 * In setAccessControlRecursive, x-ms-acl must be specified in papszMetadata.
1703
 * For /vsigs/, refer to
1704
 * https://cloud.google.com/storage/docs/xml-api/put-object-acls. A single
1705
 * XML=xml_content string should be specified as in papszMetadata.
1706
 * </li>
1707
 * <li>METADATA: specific to /vsiaz/: to set blob metadata. Refer to
1708
 * https://docs.microsoft.com/en-us/rest/api/storageservices/set-blob-metadata.
1709
 * Content of papszMetadata should be strings in the form
1710
 * x-ms-meta-name=value</li>
1711
 * </ul>
1712
 * @param papszOptions NULL or NULL terminated list of options.
1713
 *                     For /vsiadls/ and pszDomain=ACL, "RECURSIVE=TRUE" can be
1714
 *                     set to set the access control list recursively. When
1715
 *                     RECURSIVE=TRUE is set, MODE should also be set to one of
1716
 *                     "set", "modify" or "remove".
1717
 *
1718
 * @return TRUE in case of success.
1719
 *
1720
 * @since GDAL 3.1.0
1721
 */
1722
1723
int VSISetFileMetadata(const char *pszFilename, CSLConstList papszMetadata,
1724
                       const char *pszDomain, CSLConstList papszOptions)
1725
0
{
1726
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
1727
0
    return poFSHandler->SetFileMetadata(pszFilename, papszMetadata, pszDomain,
1728
0
                                        papszOptions)
1729
0
               ? 1
1730
0
               : 0;
1731
0
}
1732
1733
/************************************************************************/
1734
/*                       VSIIsCaseSensitiveFS()                         */
1735
/************************************************************************/
1736
1737
/**
1738
 * \brief Returns if the filenames of the filesystem are case sensitive.
1739
 *
1740
 * This method retrieves to which filesystem belongs the passed filename
1741
 * and return TRUE if the filenames of that filesystem are case sensitive.
1742
 *
1743
 * Currently, this will return FALSE only for Windows real filenames. Other
1744
 * VSI virtual filesystems are case sensitive.
1745
 *
1746
 * This methods avoid ugly \#ifndef _WIN32 / \#endif code, that is wrong when
1747
 * dealing with virtual filenames.
1748
 *
1749
 * @param pszFilename the path of the filesystem object to be tested.
1750
 * UTF-8 encoded.
1751
 *
1752
 * @return TRUE if the filenames of the filesystem are case sensitive.
1753
 *
1754
 * @since GDAL 1.8.0
1755
 */
1756
1757
int VSIIsCaseSensitiveFS(const char *pszFilename)
1758
0
{
1759
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
1760
1761
0
    return poFSHandler->IsCaseSensitive(pszFilename);
1762
0
}
1763
1764
/************************************************************************/
1765
/*                       VSISupportsSparseFiles()                       */
1766
/************************************************************************/
1767
1768
/**
1769
 * \brief Returns if the filesystem supports sparse files.
1770
 *
1771
 * Only supported on Linux (and no other Unix derivatives) and
1772
 * Windows.  On Linux, the answer depends on a few hardcoded
1773
 * signatures for common filesystems. Other filesystems will be
1774
 * considered as not supporting sparse files.
1775
 *
1776
 * @param pszPath the path of the filesystem object to be tested.
1777
 * UTF-8 encoded.
1778
 *
1779
 * @return TRUE if the file system is known to support sparse files. FALSE may
1780
 *              be returned both in cases where it is known to not support them,
1781
 *              or when it is unknown.
1782
 *
1783
 * @since GDAL 2.2
1784
 */
1785
1786
int VSISupportsSparseFiles(const char *pszPath)
1787
0
{
1788
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath);
1789
1790
0
    return poFSHandler->SupportsSparseFiles(pszPath);
1791
0
}
1792
1793
/************************************************************************/
1794
/*                           VSIIsLocal()                               */
1795
/************************************************************************/
1796
1797
/**
1798
 * \brief Returns if the file/filesystem is "local".
1799
 *
1800
 * The concept of local is mostly by opposition with a network / remote
1801
 * file system whose access time can be long.
1802
 *
1803
 * /vsimem/ is considered to be a local file system, although a non-persistent
1804
 * one.
1805
 *
1806
 * @param pszPath the path of the filesystem object to be tested.
1807
 * UTF-8 encoded.
1808
 *
1809
 * @return TRUE or FALSE
1810
 *
1811
 * @since GDAL 3.6
1812
 */
1813
1814
bool VSIIsLocal(const char *pszPath)
1815
0
{
1816
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath);
1817
1818
0
    return poFSHandler->IsLocal(pszPath);
1819
0
}
1820
1821
/************************************************************************/
1822
/*                       VSIGetCanonicalFilename()                      */
1823
/************************************************************************/
1824
1825
/**
1826
 * \brief Returns the canonical filename.
1827
 *
1828
 * May be implemented by case-insensitive filesystems
1829
 * (currently Win32 and MacOSX) to return the filename with its actual case
1830
 * (i.e. the one that would be used when listing the content of the directory).
1831
 *
1832
 * @param pszPath UTF-8 encoded path
1833
 *
1834
 * @return UTF-8 encoded string, to free with VSIFree()
1835
 *
1836
 * @since GDAL 3.8
1837
 */
1838
1839
char *VSIGetCanonicalFilename(const char *pszPath)
1840
0
{
1841
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath);
1842
1843
0
    return CPLStrdup(poFSHandler->GetCanonicalFilename(pszPath).c_str());
1844
0
}
1845
1846
/************************************************************************/
1847
/*                      VSISupportsSequentialWrite()                    */
1848
/************************************************************************/
1849
1850
/**
1851
 * \brief Returns if the filesystem supports sequential write.
1852
 *
1853
 * @param pszPath the path of the filesystem object to be tested.
1854
 * UTF-8 encoded.
1855
 * @param bAllowLocalTempFile whether the file system is allowed to use a
1856
 * local temporary file before uploading to the target location.
1857
 *
1858
 * @return TRUE or FALSE
1859
 *
1860
 * @since GDAL 3.6
1861
 */
1862
1863
bool VSISupportsSequentialWrite(const char *pszPath, bool bAllowLocalTempFile)
1864
0
{
1865
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath);
1866
1867
0
    return poFSHandler->SupportsSequentialWrite(pszPath, bAllowLocalTempFile);
1868
0
}
1869
1870
/************************************************************************/
1871
/*                      VSISupportsRandomWrite()                        */
1872
/************************************************************************/
1873
1874
/**
1875
 * \brief Returns if the filesystem supports random write.
1876
 *
1877
 * @param pszPath the path of the filesystem object to be tested.
1878
 * UTF-8 encoded.
1879
 * @param bAllowLocalTempFile whether the file system is allowed to use a
1880
 * local temporary file before uploading to the target location.
1881
 *
1882
 * @return TRUE or FALSE
1883
 *
1884
 * @since GDAL 3.6
1885
 */
1886
1887
bool VSISupportsRandomWrite(const char *pszPath, bool bAllowLocalTempFile)
1888
0
{
1889
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath);
1890
1891
0
    return poFSHandler->SupportsRandomWrite(pszPath, bAllowLocalTempFile);
1892
0
}
1893
1894
/************************************************************************/
1895
/*                     VSIHasOptimizedReadMultiRange()                  */
1896
/************************************************************************/
1897
1898
/**
1899
 * \brief Returns if the filesystem supports efficient multi-range reading.
1900
 *
1901
 * Currently only returns TRUE for /vsicurl/ and derived file systems.
1902
 *
1903
 * @param pszPath the path of the filesystem object to be tested.
1904
 * UTF-8 encoded.
1905
 *
1906
 * @return TRUE if the file system is known to have an efficient multi-range
1907
 * reading.
1908
 *
1909
 * @since GDAL 2.3
1910
 */
1911
1912
int VSIHasOptimizedReadMultiRange(const char *pszPath)
1913
0
{
1914
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath);
1915
1916
0
    return poFSHandler->HasOptimizedReadMultiRange(pszPath);
1917
0
}
1918
1919
/************************************************************************/
1920
/*                        VSIGetActualURL()                             */
1921
/************************************************************************/
1922
1923
/**
1924
 * \brief Returns the actual URL of a supplied filename.
1925
 *
1926
 * Currently only returns a non-NULL value for network-based virtual file
1927
 * systems. For example "/vsis3/bucket/filename" will be expanded as
1928
 * "https://bucket.s3.amazon.com/filename"
1929
 *
1930
 * Note that the lifetime of the returned string, is short, and may be
1931
 * invalidated by any following GDAL functions.
1932
 *
1933
 * @param pszFilename the path of the filesystem object. UTF-8 encoded.
1934
 *
1935
 * @return the actual URL corresponding to the supplied filename, or NULL.
1936
 * Should not be freed.
1937
 *
1938
 * @since GDAL 2.3
1939
 */
1940
1941
const char *VSIGetActualURL(const char *pszFilename)
1942
0
{
1943
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
1944
1945
0
    return poFSHandler->GetActualURL(pszFilename);
1946
0
}
1947
1948
/************************************************************************/
1949
/*                        VSIGetSignedURL()                             */
1950
/************************************************************************/
1951
1952
/**
1953
 * \brief Returns a signed URL of a supplied filename.
1954
 *
1955
 * Currently only returns a non-NULL value for /vsis3/, /vsigs/, /vsiaz/ and
1956
 * /vsioss/ For example "/vsis3/bucket/filename" will be expanded as
1957
 * "https://bucket.s3.amazon.com/filename?X-Amz-Algorithm=AWS4-HMAC-SHA256..."
1958
 * Configuration options that apply for file opening (typically to provide
1959
 * credentials), and are returned by VSIGetFileSystemOptions(), are also valid
1960
 * in that context.
1961
 *
1962
 * @param pszFilename the path of the filesystem object. UTF-8 encoded.
1963
 * @param papszOptions list of options, or NULL. Depend on file system handler.
1964
 * For /vsis3/, /vsigs/, /vsiaz/ and /vsioss/, the following options are
1965
 * supported: <ul> <li>START_DATE=YYMMDDTHHMMSSZ: date and time in UTC following
1966
 * ISO 8601 standard, corresponding to the start of validity of the URL. If not
1967
 * specified, current date time.</li> <li>EXPIRATION_DELAY=number_of_seconds:
1968
 * number between 1 and 604800 (seven days) for the validity of the signed URL.
1969
 * Defaults to 3600 (one hour)</li> <li>VERB=GET/HEAD/DELETE/PUT/POST: HTTP VERB
1970
 * for which the request will be used. Default to GET.</li>
1971
 * </ul>
1972
 *
1973
 * /vsiaz/ supports additional options:
1974
 * <ul>
1975
 * <li>SIGNEDIDENTIFIER=value: to relate the given shared access signature
1976
 * to a corresponding stored access policy.</li>
1977
 * <li>SIGNEDPERMISSIONS=r|w: permissions associated with the shared access
1978
 * signature. Normally deduced from VERB.</li>
1979
 * </ul>
1980
 *
1981
 * @return a signed URL, or NULL. Should be freed with CPLFree().
1982
 * @since GDAL 2.3
1983
 */
1984
1985
char *VSIGetSignedURL(const char *pszFilename, CSLConstList papszOptions)
1986
0
{
1987
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
1988
1989
0
    return poFSHandler->GetSignedURL(pszFilename, papszOptions);
1990
0
}
1991
1992
/************************************************************************/
1993
/*                             VSIFOpenL()                              */
1994
/************************************************************************/
1995
1996
/**
1997
 * \brief Open file.
1998
 *
1999
 * This function opens a file with the desired access.  Large files (larger
2000
 * than 2GB) should be supported.  Binary access is always implied and
2001
 * the "b" does not need to be included in the pszAccess string.
2002
 *
2003
 * Note that the "VSILFILE *" returned since GDAL 1.8.0 by this function is
2004
 * *NOT* a standard C library FILE *, and cannot be used with any functions
2005
 * other than the "VSI*L" family of functions.  They aren't "real" FILE objects.
2006
 *
2007
 * On windows it is possible to define the configuration option
2008
 * GDAL_FILE_IS_UTF8 to have pszFilename treated as being in the local
2009
 * encoding instead of UTF-8, restoring the pre-1.8.0 behavior of VSIFOpenL().
2010
 *
2011
 * This method goes through the VSIFileHandler virtualization and may
2012
 * work on unusual filesystems such as in memory.
2013
 *
2014
 * Analog of the POSIX fopen() function.
2015
 *
2016
 * @param pszFilename the file to open.  UTF-8 encoded.
2017
 * @param pszAccess access requested (i.e. "r", "r+", "w")
2018
 *
2019
 * @return NULL on failure, or the file handle.
2020
 */
2021
2022
VSILFILE *VSIFOpenL(const char *pszFilename, const char *pszAccess)
2023
2024
5.01k
{
2025
5.01k
    return VSIFOpenExL(pszFilename, pszAccess, false);
2026
5.01k
}
2027
2028
/************************************************************************/
2029
/*                               Open()                                 */
2030
/************************************************************************/
2031
2032
#ifndef DOXYGEN_SKIP
2033
2034
VSIVirtualHandleUniquePtr
2035
VSIFilesystemHandler::OpenStatic(const char *pszFilename, const char *pszAccess,
2036
                                 bool bSetError, CSLConstList papszOptions)
2037
9.50k
{
2038
9.50k
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
2039
2040
9.50k
    return poFSHandler->Open(pszFilename, pszAccess, bSetError, papszOptions);
2041
9.50k
}
2042
2043
/************************************************************************/
2044
/*                             CopyFile()                               */
2045
/************************************************************************/
2046
2047
int VSIFilesystemHandler::CopyFile(const char *pszSource, const char *pszTarget,
2048
                                   VSILFILE *fpSource, vsi_l_offset nSourceSize,
2049
                                   CSLConstList papszOptions,
2050
                                   GDALProgressFunc pProgressFunc,
2051
                                   void *pProgressData)
2052
0
{
2053
0
    VSIVirtualHandleUniquePtr poFileHandleAutoClose;
2054
0
    if (!fpSource)
2055
0
    {
2056
0
        CPLAssert(pszSource);
2057
0
        fpSource = VSIFOpenExL(pszSource, "rb", TRUE);
2058
0
        if (!fpSource)
2059
0
        {
2060
0
            CPLError(CE_Failure, CPLE_FileIO, "Cannot open %s", pszSource);
2061
0
            return -1;
2062
0
        }
2063
0
        poFileHandleAutoClose.reset(fpSource);
2064
0
    }
2065
0
    if (nSourceSize == static_cast<vsi_l_offset>(-1) &&
2066
0
        pProgressFunc != nullptr && pszSource != nullptr)
2067
0
    {
2068
0
        VSIStatBufL sStat;
2069
0
        if (VSIStatL(pszSource, &sStat) == 0)
2070
0
        {
2071
0
            nSourceSize = sStat.st_size;
2072
0
        }
2073
0
    }
2074
2075
0
    VSILFILE *fpOut = VSIFOpenEx2L(pszTarget, "wb", TRUE, papszOptions);
2076
0
    if (!fpOut)
2077
0
    {
2078
0
        CPLError(CE_Failure, CPLE_FileIO, "Cannot create %s", pszTarget);
2079
0
        return -1;
2080
0
    }
2081
2082
0
    CPLString osMsg;
2083
0
    if (pszSource)
2084
0
        osMsg.Printf("Copying of %s", pszSource);
2085
0
    else
2086
0
        pszSource = "(unknown filename)";
2087
2088
0
    int ret = 0;
2089
0
    constexpr size_t nBufferSize = 10 * 4096;
2090
0
    std::vector<GByte> abyBuffer(nBufferSize, 0);
2091
0
    GUIntBig nOffset = 0;
2092
0
    while (true)
2093
0
    {
2094
0
        const size_t nRead = VSIFReadL(&abyBuffer[0], 1, nBufferSize, fpSource);
2095
0
        if (nRead < nBufferSize && VSIFErrorL(fpSource))
2096
0
        {
2097
0
            CPLError(
2098
0
                CE_Failure, CPLE_FileIO,
2099
0
                "Copying of %s to %s failed: error while reading source file",
2100
0
                pszSource, pszTarget);
2101
0
            ret = -1;
2102
0
            break;
2103
0
        }
2104
0
        if (nRead > 0)
2105
0
        {
2106
0
            const size_t nWritten = VSIFWriteL(&abyBuffer[0], 1, nRead, fpOut);
2107
0
            if (nWritten != nRead)
2108
0
            {
2109
0
                CPLError(CE_Failure, CPLE_FileIO,
2110
0
                         "Copying of %s to %s failed: error while writing into "
2111
0
                         "target file",
2112
0
                         pszSource, pszTarget);
2113
0
                ret = -1;
2114
0
                break;
2115
0
            }
2116
0
            nOffset += nRead;
2117
0
            if (pProgressFunc &&
2118
0
                !pProgressFunc(
2119
0
                    nSourceSize == 0 ? 1.0
2120
0
                    : nSourceSize > 0 &&
2121
0
                            nSourceSize != static_cast<vsi_l_offset>(-1)
2122
0
                        ? double(nOffset) / nSourceSize
2123
0
                        : 0.0,
2124
0
                    !osMsg.empty() ? osMsg.c_str() : nullptr, pProgressData))
2125
0
            {
2126
0
                ret = -1;
2127
0
                break;
2128
0
            }
2129
0
        }
2130
0
        if (nRead < nBufferSize)
2131
0
        {
2132
0
            break;
2133
0
        }
2134
0
    }
2135
2136
0
    if (nSourceSize != static_cast<vsi_l_offset>(-1) && nOffset != nSourceSize)
2137
0
    {
2138
0
        CPLError(CE_Failure, CPLE_FileIO,
2139
0
                 "Copying of %s to %s failed: %" PRIu64 " bytes were copied "
2140
0
                 "whereas %" PRIu64 " were expected",
2141
0
                 pszSource, pszTarget, static_cast<uint64_t>(nOffset),
2142
0
                 static_cast<uint64_t>(nSourceSize));
2143
0
        ret = -1;
2144
0
    }
2145
2146
0
    if (VSIFCloseL(fpOut) != 0)
2147
0
    {
2148
0
        ret = -1;
2149
0
    }
2150
2151
0
    if (ret != 0)
2152
0
        VSIUnlink(pszTarget);
2153
2154
0
    return ret;
2155
0
}
2156
2157
/************************************************************************/
2158
/*                       CopyFileRestartable()                          */
2159
/************************************************************************/
2160
2161
int VSIFilesystemHandler::CopyFileRestartable(
2162
    const char *pszSource, const char *pszTarget,
2163
    const char * /* pszInputPayload */, char **ppszOutputPayload,
2164
    CSLConstList papszOptions, GDALProgressFunc pProgressFunc,
2165
    void *pProgressData)
2166
0
{
2167
0
    *ppszOutputPayload = nullptr;
2168
0
    return CopyFile(pszSource, pszTarget, nullptr,
2169
0
                    static_cast<vsi_l_offset>(-1), papszOptions, pProgressFunc,
2170
0
                    pProgressData);
2171
0
}
2172
2173
/************************************************************************/
2174
/*                               Sync()                                 */
2175
/************************************************************************/
2176
2177
bool VSIFilesystemHandler::Sync(const char *pszSource, const char *pszTarget,
2178
                                const char *const *papszOptions,
2179
                                GDALProgressFunc pProgressFunc,
2180
                                void *pProgressData, char ***ppapszOutputs)
2181
0
{
2182
0
    const char SOURCE_SEP = VSIGetDirectorySeparator(pszSource)[0];
2183
2184
0
    if (ppapszOutputs)
2185
0
    {
2186
0
        *ppapszOutputs = nullptr;
2187
0
    }
2188
2189
0
    VSIStatBufL sSource;
2190
0
    CPLString osSource(pszSource);
2191
0
    CPLString osSourceWithoutSlash(pszSource);
2192
0
    if (osSourceWithoutSlash.back() == '/' ||
2193
0
        osSourceWithoutSlash.back() == '\\')
2194
0
    {
2195
0
        osSourceWithoutSlash.pop_back();
2196
0
    }
2197
0
    if (VSIStatL(osSourceWithoutSlash, &sSource) < 0)
2198
0
    {
2199
0
        CPLError(CE_Failure, CPLE_FileIO, "%s does not exist", pszSource);
2200
0
        return false;
2201
0
    }
2202
2203
0
    if (VSI_ISDIR(sSource.st_mode))
2204
0
    {
2205
0
        std::string osTargetDir(pszTarget);
2206
0
        if (osSource.back() != '/' && osSource.back() != '\\')
2207
0
        {
2208
0
            osTargetDir = CPLFormFilenameSafe(
2209
0
                osTargetDir.c_str(), CPLGetFilename(pszSource), nullptr);
2210
0
        }
2211
2212
0
        VSIStatBufL sTarget;
2213
0
        bool ret = true;
2214
0
        if (VSIStatL(osTargetDir.c_str(), &sTarget) < 0)
2215
0
        {
2216
0
            if (VSIMkdirRecursive(osTargetDir.c_str(), 0755) < 0)
2217
0
            {
2218
0
                CPLError(CE_Failure, CPLE_FileIO, "Cannot create directory %s",
2219
0
                         osTargetDir.c_str());
2220
0
                return false;
2221
0
            }
2222
0
        }
2223
2224
0
        if (!CPLFetchBool(papszOptions, "STOP_ON_DIR", false))
2225
0
        {
2226
0
            CPLStringList aosChildOptions(CSLDuplicate(papszOptions));
2227
0
            if (!CPLFetchBool(papszOptions, "RECURSIVE", true))
2228
0
            {
2229
0
                aosChildOptions.SetNameValue("RECURSIVE", nullptr);
2230
0
                aosChildOptions.AddString("STOP_ON_DIR=TRUE");
2231
0
            }
2232
2233
0
            char **papszSrcFiles = VSIReadDir(osSourceWithoutSlash);
2234
0
            int nFileCount = 0;
2235
0
            for (auto iter = papszSrcFiles; iter && *iter; ++iter)
2236
0
            {
2237
0
                if (strcmp(*iter, ".") != 0 && strcmp(*iter, "..") != 0)
2238
0
                {
2239
0
                    nFileCount++;
2240
0
                }
2241
0
            }
2242
0
            int iFile = 0;
2243
0
            const int nDenom = std::max(1, nFileCount);
2244
0
            for (auto iter = papszSrcFiles; iter && *iter; ++iter, ++iFile)
2245
0
            {
2246
0
                if (strcmp(*iter, ".") == 0 || strcmp(*iter, "..") == 0)
2247
0
                {
2248
0
                    continue;
2249
0
                }
2250
0
                const std::string osSubSource(CPLFormFilenameSafe(
2251
0
                    osSourceWithoutSlash.c_str(), *iter, nullptr));
2252
0
                const std::string osSubTarget(
2253
0
                    CPLFormFilenameSafe(osTargetDir.c_str(), *iter, nullptr));
2254
0
                void *pScaledProgress = GDALCreateScaledProgress(
2255
0
                    double(iFile) / nDenom, double(iFile + 1) / nDenom,
2256
0
                    pProgressFunc, pProgressData);
2257
0
                ret = Sync((osSubSource + SOURCE_SEP).c_str(),
2258
0
                           osSubTarget.c_str(), aosChildOptions.List(),
2259
0
                           GDALScaledProgress, pScaledProgress, nullptr);
2260
0
                GDALDestroyScaledProgress(pScaledProgress);
2261
0
                if (!ret)
2262
0
                {
2263
0
                    break;
2264
0
                }
2265
0
            }
2266
0
            CSLDestroy(papszSrcFiles);
2267
0
        }
2268
0
        return ret;
2269
0
    }
2270
2271
0
    VSIStatBufL sTarget;
2272
0
    std::string osTarget(pszTarget);
2273
0
    if (VSIStatL(osTarget.c_str(), &sTarget) == 0)
2274
0
    {
2275
0
        bool bTargetIsFile = true;
2276
0
        if (VSI_ISDIR(sTarget.st_mode))
2277
0
        {
2278
0
            osTarget = CPLFormFilenameSafe(osTarget.c_str(),
2279
0
                                           CPLGetFilename(pszSource), nullptr);
2280
0
            bTargetIsFile = VSIStatL(osTarget.c_str(), &sTarget) == 0 &&
2281
0
                            !CPL_TO_BOOL(VSI_ISDIR(sTarget.st_mode));
2282
0
        }
2283
0
        if (bTargetIsFile)
2284
0
        {
2285
0
            if (sSource.st_size == sTarget.st_size &&
2286
0
                sSource.st_mtime == sTarget.st_mtime && sSource.st_mtime != 0)
2287
0
            {
2288
0
                CPLDebug("VSI",
2289
0
                         "%s and %s have same size and modification "
2290
0
                         "date. Skipping copying",
2291
0
                         osSourceWithoutSlash.c_str(), osTarget.c_str());
2292
0
                return true;
2293
0
            }
2294
0
        }
2295
0
    }
2296
2297
0
    VSILFILE *fpIn = VSIFOpenExL(osSourceWithoutSlash, "rb", TRUE);
2298
0
    if (fpIn == nullptr)
2299
0
    {
2300
0
        CPLError(CE_Failure, CPLE_FileIO, "Cannot open %s",
2301
0
                 osSourceWithoutSlash.c_str());
2302
0
        return false;
2303
0
    }
2304
2305
0
    VSILFILE *fpOut = VSIFOpenExL(osTarget.c_str(), "wb", TRUE);
2306
0
    if (fpOut == nullptr)
2307
0
    {
2308
0
        CPLError(CE_Failure, CPLE_FileIO, "Cannot create %s", osTarget.c_str());
2309
0
        VSIFCloseL(fpIn);
2310
0
        return false;
2311
0
    }
2312
2313
0
    bool ret = true;
2314
0
    constexpr size_t nBufferSize = 10 * 4096;
2315
0
    std::vector<GByte> abyBuffer(nBufferSize, 0);
2316
0
    GUIntBig nOffset = 0;
2317
0
    CPLString osMsg;
2318
0
    osMsg.Printf("Copying of %s", osSourceWithoutSlash.c_str());
2319
0
    while (true)
2320
0
    {
2321
0
        size_t nRead = VSIFReadL(&abyBuffer[0], 1, nBufferSize, fpIn);
2322
0
        size_t nWritten = VSIFWriteL(&abyBuffer[0], 1, nRead, fpOut);
2323
0
        if (nWritten != nRead)
2324
0
        {
2325
0
            CPLError(CE_Failure, CPLE_FileIO, "Copying of %s to %s failed",
2326
0
                     osSourceWithoutSlash.c_str(), osTarget.c_str());
2327
0
            ret = false;
2328
0
            break;
2329
0
        }
2330
0
        nOffset += nRead;
2331
0
        if (pProgressFunc && !pProgressFunc(double(nOffset) / sSource.st_size,
2332
0
                                            osMsg.c_str(), pProgressData))
2333
0
        {
2334
0
            ret = false;
2335
0
            break;
2336
0
        }
2337
0
        if (nRead < nBufferSize)
2338
0
        {
2339
0
            break;
2340
0
        }
2341
0
    }
2342
2343
0
    VSIFCloseL(fpIn);
2344
0
    if (VSIFCloseL(fpOut) != 0)
2345
0
    {
2346
0
        ret = false;
2347
0
    }
2348
0
    return ret;
2349
0
}
2350
2351
/************************************************************************/
2352
/*                  VSIVirtualHandleOnlyVisibleAtCloseTime()            */
2353
/************************************************************************/
2354
2355
class VSIVirtualHandleOnlyVisibleAtCloseTime final : public VSIProxyFileHandle
2356
{
2357
    const std::string m_osTargetName;
2358
    const std::string m_osTmpName;
2359
    bool m_bAlreadyClosed = false;
2360
    bool m_bCancelCreation = false;
2361
2362
  public:
2363
    VSIVirtualHandleOnlyVisibleAtCloseTime(
2364
        VSIVirtualHandleUniquePtr &&nativeHandle,
2365
        const std::string &osTargetName, const std::string &osTmpName)
2366
0
        : VSIProxyFileHandle(std::move(nativeHandle)),
2367
0
          m_osTargetName(osTargetName), m_osTmpName(osTmpName)
2368
0
    {
2369
0
    }
2370
2371
    ~VSIVirtualHandleOnlyVisibleAtCloseTime()
2372
0
    {
2373
0
        VSIVirtualHandleOnlyVisibleAtCloseTime::Close();
2374
0
    }
2375
2376
    void CancelCreation() override
2377
0
    {
2378
0
        VSIProxyFileHandle::CancelCreation();
2379
0
        m_bCancelCreation = true;
2380
0
    }
2381
2382
    int Close() override;
2383
};
2384
2385
int VSIVirtualHandleOnlyVisibleAtCloseTime::Close()
2386
0
{
2387
0
    if (m_bAlreadyClosed)
2388
0
        return 0;
2389
0
    m_bAlreadyClosed = true;
2390
0
    int ret = VSIProxyFileHandle::Close();
2391
0
    if (ret != 0)
2392
0
        return ret;
2393
0
    return m_bCancelCreation
2394
0
               ? VSIUnlink(m_osTmpName.c_str())
2395
0
               : VSIRename(m_osTmpName.c_str(), m_osTargetName.c_str());
2396
0
}
2397
2398
/************************************************************************/
2399
/*                       CreateOnlyVisibleAtCloseTime()                 */
2400
/************************************************************************/
2401
2402
VSIVirtualHandleUniquePtr VSIFilesystemHandler::CreateOnlyVisibleAtCloseTime(
2403
    const char *pszFilename, bool bEmulationAllowed, CSLConstList papszOptions)
2404
0
{
2405
0
    if (!bEmulationAllowed)
2406
0
        return nullptr;
2407
2408
0
    const std::string tmpName = std::string(pszFilename).append(".tmp");
2409
0
    VSIVirtualHandleUniquePtr nativeHandle(
2410
0
        Open(tmpName.c_str(), "wb+", true, papszOptions));
2411
0
    if (!nativeHandle)
2412
0
        return nullptr;
2413
0
    return VSIVirtualHandleUniquePtr(
2414
0
        std::make_unique<VSIVirtualHandleOnlyVisibleAtCloseTime>(
2415
0
            std::move(nativeHandle), pszFilename, tmpName)
2416
0
            .release());
2417
0
}
2418
2419
/************************************************************************/
2420
/*                            VSIDIREntry()                             */
2421
/************************************************************************/
2422
2423
VSIDIREntry::VSIDIREntry()
2424
0
    : pszName(nullptr), nMode(0), nSize(0), nMTime(0), bModeKnown(false),
2425
0
      bSizeKnown(false), bMTimeKnown(false), papszExtra(nullptr)
2426
0
{
2427
0
}
2428
2429
/************************************************************************/
2430
/*                            VSIDIREntry()                             */
2431
/************************************************************************/
2432
2433
VSIDIREntry::VSIDIREntry(const VSIDIREntry &other)
2434
0
    : pszName(VSIStrdup(other.pszName)), nMode(other.nMode), nSize(other.nSize),
2435
0
      nMTime(other.nMTime), bModeKnown(other.bModeKnown),
2436
0
      bSizeKnown(other.bSizeKnown), bMTimeKnown(other.bMTimeKnown),
2437
0
      papszExtra(CSLDuplicate(other.papszExtra))
2438
0
{
2439
0
}
2440
2441
/************************************************************************/
2442
/*                           ~VSIDIREntry()                             */
2443
/************************************************************************/
2444
2445
VSIDIREntry::~VSIDIREntry()
2446
0
{
2447
0
    CPLFree(pszName);
2448
0
    CSLDestroy(papszExtra);
2449
0
}
2450
2451
/************************************************************************/
2452
/*                              ~VSIDIR()                               */
2453
/************************************************************************/
2454
2455
VSIDIR::~VSIDIR()
2456
0
{
2457
0
}
2458
2459
/************************************************************************/
2460
/*                            VSIDIRGeneric                             */
2461
/************************************************************************/
2462
2463
namespace
2464
{
2465
struct VSIDIRGeneric : public VSIDIR
2466
{
2467
    CPLString osRootPath{};
2468
    CPLString osBasePath{};
2469
    char **papszContent = nullptr;
2470
    int nRecurseDepth = 0;
2471
    int nPos = 0;
2472
    VSIDIREntry entry{};
2473
    std::vector<VSIDIRGeneric *> aoStackSubDir{};
2474
    VSIFilesystemHandler *poFS = nullptr;
2475
    std::string m_osFilterPrefix{};
2476
2477
0
    explicit VSIDIRGeneric(VSIFilesystemHandler *poFSIn) : poFS(poFSIn)
2478
0
    {
2479
0
    }
2480
2481
    ~VSIDIRGeneric();
2482
2483
    const VSIDIREntry *NextDirEntry() override;
2484
2485
    VSIDIRGeneric(const VSIDIRGeneric &) = delete;
2486
    VSIDIRGeneric &operator=(const VSIDIRGeneric &) = delete;
2487
};
2488
2489
/************************************************************************/
2490
/*                         ~VSIDIRGeneric()                             */
2491
/************************************************************************/
2492
2493
VSIDIRGeneric::~VSIDIRGeneric()
2494
0
{
2495
0
    while (!aoStackSubDir.empty())
2496
0
    {
2497
0
        delete aoStackSubDir.back();
2498
0
        aoStackSubDir.pop_back();
2499
0
    }
2500
0
    CSLDestroy(papszContent);
2501
0
}
2502
2503
}  // namespace
2504
2505
/************************************************************************/
2506
/*                            OpenDir()                                 */
2507
/************************************************************************/
2508
2509
VSIDIR *VSIFilesystemHandler::OpenDir(const char *pszPath, int nRecurseDepth,
2510
                                      const char *const *papszOptions)
2511
0
{
2512
0
    char **papszContent = VSIReadDir(pszPath);
2513
0
    VSIStatBufL sStatL;
2514
0
    if (papszContent == nullptr &&
2515
0
        (VSIStatL(pszPath, &sStatL) != 0 || !VSI_ISDIR(sStatL.st_mode)))
2516
0
    {
2517
0
        return nullptr;
2518
0
    }
2519
0
    VSIDIRGeneric *dir = new VSIDIRGeneric(this);
2520
0
    dir->osRootPath = pszPath;
2521
0
    if (!dir->osRootPath.empty() &&
2522
0
        (dir->osRootPath.back() == '/' || dir->osRootPath.back() == '\\'))
2523
0
        dir->osRootPath.pop_back();
2524
0
    dir->nRecurseDepth = nRecurseDepth;
2525
0
    dir->papszContent = papszContent;
2526
0
    dir->m_osFilterPrefix = CSLFetchNameValueDef(papszOptions, "PREFIX", "");
2527
0
    return dir;
2528
0
}
2529
2530
/************************************************************************/
2531
/*                           NextDirEntry()                             */
2532
/************************************************************************/
2533
2534
const VSIDIREntry *VSIDIRGeneric::NextDirEntry()
2535
0
{
2536
0
    const char SEP = VSIGetDirectorySeparator(osRootPath.c_str())[0];
2537
2538
0
begin:
2539
0
    if (VSI_ISDIR(entry.nMode) && nRecurseDepth != 0)
2540
0
    {
2541
0
        CPLString osCurFile(osRootPath);
2542
0
        if (!osCurFile.empty())
2543
0
            osCurFile += SEP;
2544
0
        osCurFile += entry.pszName;
2545
0
        auto subdir =
2546
0
            static_cast<VSIDIRGeneric *>(poFS->VSIFilesystemHandler::OpenDir(
2547
0
                osCurFile, nRecurseDepth - 1, nullptr));
2548
0
        if (subdir)
2549
0
        {
2550
0
            subdir->osRootPath = osRootPath;
2551
0
            subdir->osBasePath = entry.pszName;
2552
0
            subdir->m_osFilterPrefix = m_osFilterPrefix;
2553
0
            aoStackSubDir.push_back(subdir);
2554
0
        }
2555
0
        entry.nMode = 0;
2556
0
    }
2557
2558
0
    while (!aoStackSubDir.empty())
2559
0
    {
2560
0
        auto l_entry = aoStackSubDir.back()->NextDirEntry();
2561
0
        if (l_entry)
2562
0
        {
2563
0
            return l_entry;
2564
0
        }
2565
0
        delete aoStackSubDir.back();
2566
0
        aoStackSubDir.pop_back();
2567
0
    }
2568
2569
0
    if (papszContent == nullptr)
2570
0
    {
2571
0
        return nullptr;
2572
0
    }
2573
2574
0
    while (true)
2575
0
    {
2576
0
        if (!papszContent[nPos])
2577
0
        {
2578
0
            return nullptr;
2579
0
        }
2580
        // Skip . and ..entries
2581
0
        if (papszContent[nPos][0] == '.' &&
2582
0
            (papszContent[nPos][1] == '\0' ||
2583
0
             (papszContent[nPos][1] == '.' && papszContent[nPos][2] == '\0')))
2584
0
        {
2585
0
            nPos++;
2586
0
        }
2587
0
        else
2588
0
        {
2589
0
            CPLFree(entry.pszName);
2590
0
            CPLString osName(osBasePath);
2591
0
            if (!osName.empty())
2592
0
                osName += SEP;
2593
0
            osName += papszContent[nPos];
2594
0
            nPos++;
2595
2596
0
            entry.pszName = CPLStrdup(osName);
2597
0
            entry.nMode = 0;
2598
0
            CPLString osCurFile(osRootPath);
2599
0
            if (!osCurFile.empty())
2600
0
                osCurFile += SEP;
2601
0
            osCurFile += entry.pszName;
2602
2603
0
            const auto StatFile = [&osCurFile, this]()
2604
0
            {
2605
0
                VSIStatBufL sStatL;
2606
0
                if (VSIStatL(osCurFile, &sStatL) == 0)
2607
0
                {
2608
0
                    entry.nMode = sStatL.st_mode;
2609
0
                    entry.nSize = sStatL.st_size;
2610
0
                    entry.nMTime = sStatL.st_mtime;
2611
0
                    entry.bModeKnown = true;
2612
0
                    entry.bSizeKnown = true;
2613
0
                    entry.bMTimeKnown = true;
2614
0
                }
2615
0
                else
2616
0
                {
2617
0
                    entry.nMode = 0;
2618
0
                    entry.nSize = 0;
2619
0
                    entry.nMTime = 0;
2620
0
                    entry.bModeKnown = false;
2621
0
                    entry.bSizeKnown = false;
2622
0
                    entry.bMTimeKnown = false;
2623
0
                }
2624
0
            };
2625
2626
0
            if (!m_osFilterPrefix.empty() &&
2627
0
                m_osFilterPrefix.size() > osName.size())
2628
0
            {
2629
0
                if (STARTS_WITH(m_osFilterPrefix.c_str(), osName.c_str()) &&
2630
0
                    m_osFilterPrefix[osName.size()] == SEP)
2631
0
                {
2632
0
                    StatFile();
2633
0
                    if (VSI_ISDIR(entry.nMode))
2634
0
                    {
2635
0
                        goto begin;
2636
0
                    }
2637
0
                }
2638
0
                continue;
2639
0
            }
2640
0
            if (!m_osFilterPrefix.empty() &&
2641
0
                !STARTS_WITH(osName.c_str(), m_osFilterPrefix.c_str()))
2642
0
            {
2643
0
                continue;
2644
0
            }
2645
2646
0
            StatFile();
2647
2648
0
            break;
2649
0
        }
2650
0
    }
2651
2652
0
    return &(entry);
2653
0
}
2654
2655
/************************************************************************/
2656
/*                           UnlinkBatch()                              */
2657
/************************************************************************/
2658
2659
int *VSIFilesystemHandler::UnlinkBatch(CSLConstList papszFiles)
2660
0
{
2661
0
    int *panRet =
2662
0
        static_cast<int *>(CPLMalloc(sizeof(int) * CSLCount(papszFiles)));
2663
0
    for (int i = 0; papszFiles && papszFiles[i]; ++i)
2664
0
    {
2665
0
        panRet[i] = VSIUnlink(papszFiles[i]) == 0;
2666
0
    }
2667
0
    return panRet;
2668
0
}
2669
2670
/************************************************************************/
2671
/*                          RmdirRecursive()                            */
2672
/************************************************************************/
2673
2674
int VSIFilesystemHandler::RmdirRecursive(const char *pszDirname)
2675
0
{
2676
0
    CPLString osDirnameWithoutEndSlash(pszDirname);
2677
0
    if (!osDirnameWithoutEndSlash.empty() &&
2678
0
        (osDirnameWithoutEndSlash.back() == '/' ||
2679
0
         osDirnameWithoutEndSlash.back() == '\\'))
2680
0
    {
2681
0
        osDirnameWithoutEndSlash.pop_back();
2682
0
    }
2683
2684
0
    const char SEP = VSIGetDirectorySeparator(pszDirname)[0];
2685
2686
0
    CPLStringList aosOptions;
2687
0
    auto poDir =
2688
0
        std::unique_ptr<VSIDIR>(OpenDir(pszDirname, -1, aosOptions.List()));
2689
0
    if (!poDir)
2690
0
        return -1;
2691
0
    std::vector<std::string> aosDirs;
2692
0
    while (true)
2693
0
    {
2694
0
        auto entry = poDir->NextDirEntry();
2695
0
        if (!entry)
2696
0
            break;
2697
2698
0
        CPLString osFilename(osDirnameWithoutEndSlash + SEP + entry->pszName);
2699
0
        if ((entry->nMode & S_IFDIR))
2700
0
        {
2701
0
            aosDirs.push_back(std::move(osFilename));
2702
0
        }
2703
0
        else
2704
0
        {
2705
0
            if (VSIUnlink(osFilename) != 0)
2706
0
                return -1;
2707
0
        }
2708
0
    }
2709
2710
    // Sort in reverse order, so that inner-most directories are deleted first
2711
0
    std::sort(aosDirs.begin(), aosDirs.end(),
2712
0
              [](const std::string &a, const std::string &b) { return a > b; });
2713
2714
0
    for (const auto &osDir : aosDirs)
2715
0
    {
2716
0
        if (VSIRmdir(osDir.c_str()) != 0)
2717
0
            return -1;
2718
0
    }
2719
2720
0
    return VSIRmdir(pszDirname);
2721
0
}
2722
2723
/************************************************************************/
2724
/*                          GetFileMetadata()                           */
2725
/************************************************************************/
2726
2727
char **VSIFilesystemHandler::GetFileMetadata(const char * /* pszFilename*/,
2728
                                             const char * /*pszDomain*/,
2729
                                             CSLConstList /*papszOptions*/)
2730
0
{
2731
0
    return nullptr;
2732
0
}
2733
2734
/************************************************************************/
2735
/*                          SetFileMetadata()                           */
2736
/************************************************************************/
2737
2738
bool VSIFilesystemHandler::SetFileMetadata(const char * /* pszFilename*/,
2739
                                           CSLConstList /* papszMetadata */,
2740
                                           const char * /* pszDomain */,
2741
                                           CSLConstList /* papszOptions */)
2742
0
{
2743
0
    CPLError(CE_Failure, CPLE_NotSupported, "SetFileMetadata() not supported");
2744
0
    return false;
2745
0
}
2746
2747
#endif
2748
2749
/************************************************************************/
2750
/*                             VSIFOpenExL()                            */
2751
/************************************************************************/
2752
2753
/**
2754
 * \brief Open/create file.
2755
 *
2756
 * This function opens (or creates) a file with the desired access.
2757
 * Binary access is always implied and
2758
 * the "b" does not need to be included in the pszAccess string.
2759
 *
2760
 * Note that the "VSILFILE *" returned by this function is
2761
 * *NOT* a standard C library FILE *, and cannot be used with any functions
2762
 * other than the "VSI*L" family of functions.  They aren't "real" FILE objects.
2763
 *
2764
 * On windows it is possible to define the configuration option
2765
 * GDAL_FILE_IS_UTF8 to have pszFilename treated as being in the local
2766
 * encoding instead of UTF-8, restoring the pre-1.8.0 behavior of VSIFOpenL().
2767
 *
2768
 * This method goes through the VSIFileHandler virtualization and may
2769
 * work on unusual filesystems such as in memory.
2770
 *
2771
 * Analog of the POSIX fopen() function.
2772
 *
2773
 * @param pszFilename the file to open.  UTF-8 encoded.
2774
 * @param pszAccess access requested (i.e. "r", "r+", "w")
2775
 * @param bSetError flag determining whether or not this open call
2776
 * should set VSIErrors on failure.
2777
 *
2778
 * @return NULL on failure, or the file handle.
2779
 *
2780
 * @since GDAL 2.1
2781
 */
2782
2783
VSILFILE *VSIFOpenExL(const char *pszFilename, const char *pszAccess,
2784
                      int bSetError)
2785
2786
5.01k
{
2787
5.01k
    return VSIFOpenEx2L(pszFilename, pszAccess, bSetError, nullptr);
2788
5.01k
}
2789
2790
/************************************************************************/
2791
/*                            VSIFOpenEx2L()                            */
2792
/************************************************************************/
2793
2794
/**
2795
 * \brief Open/create file.
2796
 *
2797
 * This function opens (or creates) a file with the desired access.
2798
 * Binary access is always implied and
2799
 * the "b" does not need to be included in the pszAccess string.
2800
 *
2801
 * Note that the "VSILFILE *" returned by this function is
2802
 * *NOT* a standard C library FILE *, and cannot be used with any functions
2803
 * other than the "VSI*L" family of functions.  They aren't "real" FILE objects.
2804
 *
2805
 * On windows it is possible to define the configuration option
2806
 * GDAL_FILE_IS_UTF8 to have pszFilename treated as being in the local
2807
 * encoding instead of UTF-8, restoring the pre-1.8.0 behavior of VSIFOpenL().
2808
 *
2809
 * This method goes through the VSIFileHandler virtualization and may
2810
 * work on unusual filesystems such as in memory.
2811
 *
2812
 * The following options are supported:
2813
 * <ul>
2814
 * <li>MIME headers such as Content-Type and Content-Encoding
2815
 * are supported for the /vsis3/, /vsigs/, /vsiaz/, /vsiadls/ file systems.</li>
2816
 * <li>DISABLE_READDIR_ON_OPEN=YES/NO (GDAL >= 3.6) for /vsicurl/ and other
2817
 * network-based file systems. By default, directory file listing is done,
2818
 * unless YES is specified.</li>
2819
 * <li>WRITE_THROUGH=YES (GDAL >= 3.8) for the Windows regular files to
2820
 * set the FILE_FLAG_WRITE_THROUGH flag to the CreateFile() function. In that
2821
 * mode, the data is written to the system cache but is flushed to disk without
2822
 * delay.</li>
2823
 * </ul>
2824
 *
2825
 * Options specifics to /vsis3/, /vsigs/, /vsioss/ and /vsiaz/ in "w" mode:
2826
 * <ul>
2827
 * <li>CHUNK_SIZE=val in MiB. (GDAL >= 3.10) Size of a block. Default is 50 MiB.
2828
 * For /vsis3/, /vsigz/, /vsioss/, it can be up to 5000 MiB.
2829
 * For /vsiaz/, only taken into account when BLOB_TYPE=BLOCK. It can be up to 4000 MiB.
2830
 * </li>
2831
 * </ul>
2832
 *
2833
 * Options specifics to /vsiaz/ in "w" mode:
2834
 * <ul>
2835
 * <li>BLOB_TYPE=APPEND/BLOCK. (GDAL >= 3.10) Type of blob. Defaults to APPEND.
2836
 * Append blocks are limited to 195 GiB
2837
 * (however if the file size is below 4 MiB, a block blob will be created in a
2838
 * single PUT operation)
2839
 * </li>
2840
 * </ul>
2841
 *
2842
 * Analog of the POSIX fopen() function.
2843
 *
2844
 * @param pszFilename the file to open.  UTF-8 encoded.
2845
 * @param pszAccess access requested (i.e. "r", "r+", "w")
2846
 * @param bSetError flag determining whether or not this open call
2847
 * should set VSIErrors on failure.
2848
 * @param papszOptions NULL or NULL-terminated list of strings. The content is
2849
 *                     highly file system dependent.
2850
 *
2851
 *
2852
 * @return NULL on failure, or the file handle.
2853
 *
2854
 * @since GDAL 3.3
2855
 */
2856
2857
VSILFILE *VSIFOpenEx2L(const char *pszFilename, const char *pszAccess,
2858
                       int bSetError, CSLConstList papszOptions)
2859
2860
5.01k
{
2861
    // Too long filenames can cause excessive memory allocation due to
2862
    // recursion in some filesystem handlers
2863
5.01k
    constexpr size_t knMaxPath = 8192;
2864
5.01k
    if (CPLStrnlen(pszFilename, knMaxPath) == knMaxPath)
2865
0
        return nullptr;
2866
2867
5.01k
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
2868
2869
5.01k
    auto fp = poFSHandler->Open(pszFilename, pszAccess, CPL_TO_BOOL(bSetError),
2870
5.01k
                                papszOptions);
2871
2872
5.01k
    VSIDebug4("VSIFOpenEx2L(%s,%s,%d) = %p", pszFilename, pszAccess, bSetError,
2873
5.01k
              fp.get());
2874
2875
5.01k
    return fp.release();
2876
5.01k
}
2877
2878
/************************************************************************/
2879
/*                             VSIFCloseL()                             */
2880
/************************************************************************/
2881
2882
/**
2883
 * \fn VSIVirtualHandle::Close()
2884
 * \brief Close file.
2885
 *
2886
 * This function closes the indicated file.
2887
 *
2888
 * This method goes through the VSIFileHandler virtualization and may
2889
 * work on unusual filesystems such as in memory.
2890
 *
2891
 * Analog of the POSIX fclose() function.
2892
 *
2893
 * @return 0 on success or -1 on failure.
2894
 */
2895
2896
/**
2897
 * \brief Close file.
2898
 *
2899
 * This function closes the indicated file.
2900
 *
2901
 * This method goes through the VSIFileHandler virtualization and may
2902
 * work on unusual filesystems such as in memory.
2903
 *
2904
 * Analog of the POSIX fclose() function.
2905
 *
2906
 * @param fp file handle opened with VSIFOpenL().  Passing a nullptr produces
2907
 * undefined behavior.
2908
 *
2909
 * @return 0 on success or -1 on failure.
2910
 */
2911
2912
int VSIFCloseL(VSILFILE *fp)
2913
2914
9.17k
{
2915
9.17k
    VSIDebug1("VSIFCloseL(%p)", fp);
2916
2917
9.17k
    const int nResult = fp->Close();
2918
2919
9.17k
    delete fp;
2920
2921
9.17k
    return nResult;
2922
9.17k
}
2923
2924
/************************************************************************/
2925
/*                             VSIFSeekL()                              */
2926
/************************************************************************/
2927
2928
/**
2929
 * \fn int VSIVirtualHandle::Seek( vsi_l_offset nOffset, int nWhence )
2930
 * \brief Seek to requested offset.
2931
 *
2932
 * Seek to the desired offset (nOffset) in the indicated file.
2933
 *
2934
 * This method goes through the VSIFileHandler virtualization and may
2935
 * work on unusual filesystems such as in memory.
2936
 *
2937
 * Analog of the POSIX fseek() call.
2938
 *
2939
 * Caution: vsi_l_offset is a unsigned type, so SEEK_CUR can only be used
2940
 * for positive seek. If negative seek is needed, use
2941
 * handle->Seek( handle->Tell() + negative_offset, SEEK_SET ).
2942
 *
2943
 * @param nOffset offset in bytes.
2944
 * @param nWhence one of SEEK_SET, SEEK_CUR or SEEK_END.
2945
 *
2946
 * @return 0 on success or -1 one failure.
2947
 */
2948
2949
/**
2950
 * \brief Seek to requested offset.
2951
 *
2952
 * Seek to the desired offset (nOffset) in the indicated file.
2953
 *
2954
 * This method goes through the VSIFileHandler virtualization and may
2955
 * work on unusual filesystems such as in memory.
2956
 *
2957
 * Analog of the POSIX fseek() call.
2958
 *
2959
 * Caution: vsi_l_offset is a unsigned type, so SEEK_CUR can only be used
2960
 * for positive seek. If negative seek is needed, use
2961
 * VSIFSeekL( fp, VSIFTellL(fp) + negative_offset, SEEK_SET ).
2962
 *
2963
 * @param fp file handle opened with VSIFOpenL().
2964
 * @param nOffset offset in bytes.
2965
 * @param nWhence one of SEEK_SET, SEEK_CUR or SEEK_END.
2966
 *
2967
 * @return 0 on success or -1 one failure.
2968
 */
2969
2970
int VSIFSeekL(VSILFILE *fp, vsi_l_offset nOffset, int nWhence)
2971
2972
276k
{
2973
276k
    return fp->Seek(nOffset, nWhence);
2974
276k
}
2975
2976
/************************************************************************/
2977
/*                             VSIFTellL()                              */
2978
/************************************************************************/
2979
2980
/**
2981
 * \fn VSIVirtualHandle::Tell()
2982
 * \brief Tell current file offset.
2983
 *
2984
 * Returns the current file read/write offset in bytes from the beginning of
2985
 * the file.
2986
 *
2987
 * This method goes through the VSIFileHandler virtualization and may
2988
 * work on unusual filesystems such as in memory.
2989
 *
2990
 * Analog of the POSIX ftell() call.
2991
 *
2992
 * @return file offset in bytes.
2993
 */
2994
2995
/**
2996
 * \brief Tell current file offset.
2997
 *
2998
 * Returns the current file read/write offset in bytes from the beginning of
2999
 * the file.
3000
 *
3001
 * This method goes through the VSIFileHandler virtualization and may
3002
 * work on unusual filesystems such as in memory.
3003
 *
3004
 * Analog of the POSIX ftell() call.
3005
 *
3006
 * @param fp file handle opened with VSIFOpenL().
3007
 *
3008
 * @return file offset in bytes.
3009
 */
3010
3011
vsi_l_offset VSIFTellL(VSILFILE *fp)
3012
3013
5.32k
{
3014
5.32k
    return fp->Tell();
3015
5.32k
}
3016
3017
/************************************************************************/
3018
/*                             VSIRewindL()                             */
3019
/************************************************************************/
3020
3021
/**
3022
 * \brief Rewind the file pointer to the beginning of the file.
3023
 *
3024
 * This is equivalent to VSIFSeekL( fp, 0, SEEK_SET )
3025
 *
3026
 * Analog of the POSIX rewind() call.
3027
 *
3028
 * @param fp file handle opened with VSIFOpenL().
3029
 */
3030
3031
void VSIRewindL(VSILFILE *fp)
3032
3033
0
{
3034
0
    CPL_IGNORE_RET_VAL(VSIFSeekL(fp, 0, SEEK_SET));
3035
0
}
3036
3037
/************************************************************************/
3038
/*                             VSIFFlushL()                             */
3039
/************************************************************************/
3040
3041
/**
3042
 * \fn VSIVirtualHandle::Flush()
3043
 * \brief Flush pending writes to disk.
3044
 *
3045
 * For files in write or update mode and on filesystem types where it is
3046
 * applicable, all pending output on the file is flushed to the physical disk.
3047
 *
3048
 * This method goes through the VSIFileHandler virtualization and may
3049
 * work on unusual filesystems such as in memory.
3050
 *
3051
 * Analog of the POSIX fflush() call.
3052
 *
3053
 * On Windows regular files, this method does nothing, unless the
3054
 * VSI_FLUSH configuration option is set to YES (and only when the file has
3055
 * *not* been opened with the WRITE_THROUGH option).
3056
 *
3057
 * @return 0 on success or -1 on error.
3058
 */
3059
3060
/**
3061
 * \brief Flush pending writes to disk.
3062
 *
3063
 * For files in write or update mode and on filesystem types where it is
3064
 * applicable, all pending output on the file is flushed to the physical disk.
3065
 *
3066
 * This method goes through the VSIFileHandler virtualization and may
3067
 * work on unusual filesystems such as in memory.
3068
 *
3069
 * Analog of the POSIX fflush() call.
3070
 *
3071
 * On Windows regular files, this method does nothing, unless the
3072
 * VSI_FLUSH configuration option is set to YES (and only when the file has
3073
 * *not* been opened with the WRITE_THROUGH option).
3074
 *
3075
 * @param fp file handle opened with VSIFOpenL().
3076
 *
3077
 * @return 0 on success or -1 on error.
3078
 */
3079
3080
int VSIFFlushL(VSILFILE *fp)
3081
3082
0
{
3083
0
    return fp->Flush();
3084
0
}
3085
3086
/************************************************************************/
3087
/*                             VSIFReadL()                              */
3088
/************************************************************************/
3089
3090
/**
3091
 * \fn VSIVirtualHandle::Read( void *pBuffer, size_t nSize, size_t nCount )
3092
 * \brief Read bytes from file.
3093
 *
3094
 * Reads nCount objects of nSize bytes from the indicated file at the
3095
 * current offset into the indicated buffer.
3096
 *
3097
 * This method goes through the VSIFileHandler virtualization and may
3098
 * work on unusual filesystems such as in memory.
3099
 *
3100
 * Analog of the POSIX fread() call.
3101
 *
3102
 * @param pBuffer the buffer into which the data should be read (at least
3103
 * nCount * nSize bytes in size.
3104
 * @param nSize size of objects to read in bytes.
3105
 * @param nCount number of objects to read.
3106
 *
3107
 * @return number of objects successfully read. If that number is less than
3108
 * nCount, VSIFEofL() or VSIFErrorL() can be used to determine the reason for
3109
 * the short read.
3110
 */
3111
3112
/**
3113
 * \brief Read bytes from file.
3114
 *
3115
 * Reads nCount objects of nSize bytes from the indicated file at the
3116
 * current offset into the indicated buffer.
3117
 *
3118
 * This method goes through the VSIFileHandler virtualization and may
3119
 * work on unusual filesystems such as in memory.
3120
 *
3121
 * Analog of the POSIX fread() call.
3122
 *
3123
 * @param pBuffer the buffer into which the data should be read (at least
3124
 * nCount * nSize bytes in size.
3125
 * @param nSize size of objects to read in bytes.
3126
 * @param nCount number of objects to read.
3127
 * @param fp file handle opened with VSIFOpenL().
3128
 *
3129
 * @return number of objects successfully read. If that number is less than
3130
 * nCount, VSIFEofL() or VSIFErrorL() can be used to determine the reason for
3131
 * the short read.
3132
 */
3133
3134
size_t VSIFReadL(void *pBuffer, size_t nSize, size_t nCount, VSILFILE *fp)
3135
3136
302k
{
3137
302k
    return fp->Read(pBuffer, nSize, nCount);
3138
302k
}
3139
3140
/************************************************************************/
3141
/*                       VSIFReadMultiRangeL()                          */
3142
/************************************************************************/
3143
3144
/**
3145
 * \fn VSIVirtualHandle::ReadMultiRange( int nRanges, void ** ppData,
3146
 *                                       const vsi_l_offset* panOffsets,
3147
 *                                       const size_t* panSizes )
3148
 * \brief Read several ranges of bytes from file.
3149
 *
3150
 * Reads nRanges objects of panSizes[i] bytes from the indicated file at the
3151
 * offset panOffsets[i] into the buffer ppData[i].
3152
 *
3153
 * Ranges must be sorted in ascending start offset, and must not overlap each
3154
 * other.
3155
 *
3156
 * This method goes through the VSIFileHandler virtualization and may
3157
 * work on unusual filesystems such as in memory or /vsicurl/.
3158
 *
3159
 * @param nRanges number of ranges to read.
3160
 * @param ppData array of nRanges buffer into which the data should be read
3161
 *               (ppData[i] must be at list panSizes[i] bytes).
3162
 * @param panOffsets array of nRanges offsets at which the data should be read.
3163
 * @param panSizes array of nRanges sizes of objects to read (in bytes).
3164
 *
3165
 * @return 0 in case of success, -1 otherwise.
3166
 * @since GDAL 1.9.0
3167
 */
3168
3169
/**
3170
 * \brief Read several ranges of bytes from file.
3171
 *
3172
 * Reads nRanges objects of panSizes[i] bytes from the indicated file at the
3173
 * offset panOffsets[i] into the buffer ppData[i].
3174
 *
3175
 * Ranges must be sorted in ascending start offset, and must not overlap each
3176
 * other.
3177
 *
3178
 * This method goes through the VSIFileHandler virtualization and may
3179
 * work on unusual filesystems such as in memory or /vsicurl/.
3180
 *
3181
 * @param nRanges number of ranges to read.
3182
 * @param ppData array of nRanges buffer into which the data should be read
3183
 *               (ppData[i] must be at list panSizes[i] bytes).
3184
 * @param panOffsets array of nRanges offsets at which the data should be read.
3185
 * @param panSizes array of nRanges sizes of objects to read (in bytes).
3186
 * @param fp file handle opened with VSIFOpenL().
3187
 *
3188
 * @return 0 in case of success, -1 otherwise.
3189
 * @since GDAL 1.9.0
3190
 */
3191
3192
int VSIFReadMultiRangeL(int nRanges, void **ppData,
3193
                        const vsi_l_offset *panOffsets, const size_t *panSizes,
3194
                        VSILFILE *fp)
3195
0
{
3196
0
    return fp->ReadMultiRange(nRanges, ppData, panOffsets, panSizes);
3197
0
}
3198
3199
/************************************************************************/
3200
/*                             VSIFWriteL()                             */
3201
/************************************************************************/
3202
3203
/**
3204
 * \fn VSIVirtualHandle::Write( const void *pBuffer,
3205
 *                              size_t nSize, size_t nCount )
3206
 * \brief Write bytes to file.
3207
 *
3208
 * Writes nCount objects of nSize bytes to the indicated file at the
3209
 * current offset into the indicated buffer.
3210
 *
3211
 * This method goes through the VSIFileHandler virtualization and may
3212
 * work on unusual filesystems such as in memory.
3213
 *
3214
 * Analog of the POSIX fwrite() call.
3215
 *
3216
 * @param pBuffer the buffer from which the data should be written (at least
3217
 * nCount * nSize bytes in size.
3218
 * @param nSize size of objects to write in bytes.
3219
 * @param nCount number of objects to write.
3220
 *
3221
 * @return number of objects successfully written.
3222
 */
3223
3224
/**
3225
 * \brief Write bytes to file.
3226
 *
3227
 * Writes nCount objects of nSize bytes to the indicated file at the
3228
 * current offset into the indicated buffer.
3229
 *
3230
 * This method goes through the VSIFileHandler virtualization and may
3231
 * work on unusual filesystems such as in memory.
3232
 *
3233
 * Analog of the POSIX fwrite() call.
3234
 *
3235
 * @param pBuffer the buffer from which the data should be written (at least
3236
 * nCount * nSize bytes in size.
3237
 * @param nSize size of objects to write in bytes.
3238
 * @param nCount number of objects to write.
3239
 * @param fp file handle opened with VSIFOpenL().
3240
 *
3241
 * @return number of objects successfully written.
3242
 */
3243
3244
size_t VSIFWriteL(const void *pBuffer, size_t nSize, size_t nCount,
3245
                  VSILFILE *fp)
3246
3247
0
{
3248
0
    return fp->Write(pBuffer, nSize, nCount);
3249
0
}
3250
3251
/************************************************************************/
3252
/*                              VSIFEofL()                              */
3253
/************************************************************************/
3254
3255
/**
3256
 * \fn VSIVirtualHandle::Eof()
3257
 * \brief Test for end of file.
3258
 *
3259
 * Returns TRUE (non-zero) if an end-of-file condition occurred during the
3260
 * previous read operation. The end-of-file flag is cleared by a successful
3261
 * VSIFSeekL() call, or a call to VSIFClearErrL().
3262
 *
3263
 * This method goes through the VSIFileHandler virtualization and may
3264
 * work on unusual filesystems such as in memory.
3265
 *
3266
 * Analog of the POSIX feof() call.
3267
 *
3268
 * @return TRUE if at EOF, else FALSE.
3269
 */
3270
3271
/**
3272
 * \brief Test for end of file.
3273
 *
3274
 * Returns TRUE (non-zero) if an end-of-file condition occurred during the
3275
 * previous read operation. The end-of-file flag is cleared by a successful
3276
 * VSIFSeekL() call, or a call to VSIFClearErrL().
3277
 *
3278
 * This method goes through the VSIFileHandler virtualization and may
3279
 * work on unusual filesystems such as in memory.
3280
 *
3281
 * Analog of the POSIX feof() call.
3282
 *
3283
 * @param fp file handle opened with VSIFOpenL().
3284
 *
3285
 * @return TRUE if at EOF, else FALSE.
3286
 */
3287
3288
int VSIFEofL(VSILFILE *fp)
3289
3290
0
{
3291
0
    return fp->Eof();
3292
0
}
3293
3294
/************************************************************************/
3295
/*                            VSIFErrorL()                              */
3296
/************************************************************************/
3297
3298
/**
3299
 * \fn VSIVirtualHandle::Error()
3300
 * \brief Test the error indicator.
3301
 *
3302
 * Returns TRUE (non-zero) if an error condition occurred during the
3303
 * previous read operation. The error indicator is cleared by a call to
3304
 * VSIFClearErrL(). Note that a end-of-file situation, reported by VSIFEofL(),
3305
 * is *not* an error reported by VSIFErrorL().
3306
 *
3307
 * This method goes through the VSIFileHandler virtualization and may
3308
 * work on unusual filesystems such as in memory.
3309
 *
3310
 * Analog of the POSIX ferror() call.
3311
 *
3312
 * @return TRUE if the error indicator is set, else FALSE.
3313
 * @since 3.10
3314
 */
3315
3316
/**
3317
 * \brief Test the error indicator.
3318
 *
3319
 * Returns TRUE (non-zero) if an error condition occurred during the
3320
 * previous read operation. The error indicator is cleared by a call to
3321
 * VSIFClearErrL(). Note that a end-of-file situation, reported by VSIFEofL(),
3322
 * is *not* an error reported by VSIFErrorL().
3323
 *
3324
 * This method goes through the VSIFileHandler virtualization and may
3325
 * work on unusual filesystems such as in memory.
3326
 *
3327
 * Analog of the POSIX feof() call.
3328
 *
3329
 * @param fp file handle opened with VSIFOpenL().
3330
 *
3331
 * @return TRUE if the error indicator is set, else FALSE.
3332
 * @since 3.10
3333
 */
3334
3335
int VSIFErrorL(VSILFILE *fp)
3336
3337
0
{
3338
0
    return fp->Error();
3339
0
}
3340
3341
/************************************************************************/
3342
/*                           VSIFClearErrL()                            */
3343
/************************************************************************/
3344
3345
/**
3346
 * \fn VSIVirtualHandle::ClearErr()
3347
 * \brief Reset the error and end-of-file indicators.
3348
 *
3349
 * This method goes through the VSIFileHandler virtualization and may
3350
 * work on unusual filesystems such as in memory.
3351
 *
3352
 * Analog of the POSIX clearerr() call.
3353
 *
3354
 * @since 3.10
3355
 */
3356
3357
/**
3358
 * \brief Reset the error and end-of-file indicators.
3359
 *
3360
 * This method goes through the VSIFileHandler virtualization and may
3361
 * work on unusual filesystems such as in memory.
3362
 *
3363
 * Analog of the POSIX clearerr() call.
3364
 *
3365
 * @param fp file handle opened with VSIFOpenL().
3366
 *
3367
 * @since 3.10
3368
 */
3369
3370
void VSIFClearErrL(VSILFILE *fp)
3371
3372
0
{
3373
0
    fp->ClearErr();
3374
0
}
3375
3376
/************************************************************************/
3377
/*                            VSIFTruncateL()                           */
3378
/************************************************************************/
3379
3380
/**
3381
 * \fn VSIVirtualHandle::Truncate( vsi_l_offset nNewSize )
3382
 * \brief Truncate/expand the file to the specified size
3383
3384
 * This method goes through the VSIFileHandler virtualization and may
3385
 * work on unusual filesystems such as in memory.
3386
 *
3387
 * Analog of the POSIX ftruncate() call.
3388
 *
3389
 * @param nNewSize new size in bytes.
3390
 *
3391
 * @return 0 on success
3392
 * @since GDAL 1.9.0
3393
 */
3394
3395
/**
3396
 * \brief Truncate/expand the file to the specified size
3397
3398
 * This method goes through the VSIFileHandler virtualization and may
3399
 * work on unusual filesystems such as in memory.
3400
 *
3401
 * Analog of the POSIX ftruncate() call.
3402
 *
3403
 * @param fp file handle opened with VSIFOpenL().
3404
 * @param nNewSize new size in bytes.
3405
 *
3406
 * @return 0 on success
3407
 * @since GDAL 1.9.0
3408
 */
3409
3410
int VSIFTruncateL(VSILFILE *fp, vsi_l_offset nNewSize)
3411
3412
0
{
3413
0
    return fp->Truncate(nNewSize);
3414
0
}
3415
3416
/************************************************************************/
3417
/*                            VSIFPrintfL()                             */
3418
/************************************************************************/
3419
3420
/**
3421
 * \brief Formatted write to file.
3422
 *
3423
 * Provides fprintf() style formatted output to a VSI*L file.  This formats
3424
 * an internal buffer which is written using VSIFWriteL().
3425
 *
3426
 * Analog of the POSIX fprintf() call.
3427
 *
3428
 * @param fp file handle opened with VSIFOpenL().
3429
 * @param pszFormat the printf() style format string.
3430
 *
3431
 * @return the number of bytes written or -1 on an error.
3432
 */
3433
3434
int VSIFPrintfL(VSILFILE *fp, CPL_FORMAT_STRING(const char *pszFormat), ...)
3435
3436
0
{
3437
0
    va_list args;
3438
3439
0
    va_start(args, pszFormat);
3440
0
    CPLString osResult;
3441
0
    osResult.vPrintf(pszFormat, args);
3442
0
    va_end(args);
3443
3444
0
    return static_cast<int>(
3445
0
        VSIFWriteL(osResult.c_str(), 1, osResult.length(), fp));
3446
0
}
3447
3448
/************************************************************************/
3449
/*                 VSIVirtualHandle::Printf()                           */
3450
/************************************************************************/
3451
3452
/**
3453
 * \brief Formatted write to file.
3454
 *
3455
 * Provides fprintf() style formatted output to a VSI*L file.  This formats
3456
 * an internal buffer which is written using VSIFWriteL().
3457
 *
3458
 * Analog of the POSIX fprintf() call.
3459
 *
3460
 * @param pszFormat the printf() style format string.
3461
 *
3462
 * @return the number of bytes written or -1 on an error.
3463
 */
3464
3465
int VSIVirtualHandle::Printf(CPL_FORMAT_STRING(const char *pszFormat), ...)
3466
0
{
3467
0
    va_list args;
3468
3469
0
    va_start(args, pszFormat);
3470
0
    CPLString osResult;
3471
0
    osResult.vPrintf(pszFormat, args);
3472
0
    va_end(args);
3473
3474
0
    return static_cast<int>(Write(osResult.c_str(), 1, osResult.length()));
3475
0
}
3476
3477
/************************************************************************/
3478
/*                              VSIFPutcL()                              */
3479
/************************************************************************/
3480
3481
// TODO: should we put in conformance with POSIX regarding the return
3482
// value. As of today (2015-08-29), no code in GDAL sources actually
3483
// check the return value.
3484
3485
/**
3486
 * \brief Write a single byte to the file
3487
 *
3488
 * Writes the character nChar, cast to an unsigned char, to file.
3489
 *
3490
 * Almost an analog of the POSIX  fputc() call, except that it returns
3491
 * the  number of  character  written (1  or 0),  and  not the  (cast)
3492
 * character itself or EOF.
3493
 *
3494
 * @param nChar character to write.
3495
 * @param fp file handle opened with VSIFOpenL().
3496
 *
3497
 * @return 1 in case of success, 0 on error.
3498
 */
3499
3500
int VSIFPutcL(int nChar, VSILFILE *fp)
3501
3502
0
{
3503
0
    const unsigned char cChar = static_cast<unsigned char>(nChar);
3504
0
    return static_cast<int>(VSIFWriteL(&cChar, 1, 1, fp));
3505
0
}
3506
3507
/************************************************************************/
3508
/*                        VSIFGetRangeStatusL()                        */
3509
/************************************************************************/
3510
3511
/**
3512
 * \fn VSIVirtualHandle::GetRangeStatus( vsi_l_offset nOffset,
3513
 *                                       vsi_l_offset nLength )
3514
 * \brief Return if a given file range contains data or holes filled with zeroes
3515
 *
3516
 * This uses the filesystem capabilities of querying which regions of
3517
 * a sparse file are allocated or not. This is currently only
3518
 * implemented for Linux (and no other Unix derivatives) and Windows.
3519
 *
3520
 * Note: A return of VSI_RANGE_STATUS_DATA doesn't exclude that the
3521
 * extent is filled with zeroes! It must be interpreted as "may
3522
 * contain non-zero data".
3523
 *
3524
 * @param nOffset offset of the start of the extent.
3525
 * @param nLength extent length.
3526
 *
3527
 * @return extent status: VSI_RANGE_STATUS_UNKNOWN, VSI_RANGE_STATUS_DATA or
3528
 *         VSI_RANGE_STATUS_HOLE
3529
 * @since GDAL 2.2
3530
 */
3531
3532
/**
3533
 * \brief Return if a given file range contains data or holes filled with zeroes
3534
 *
3535
 * This uses the filesystem capabilities of querying which regions of
3536
 * a sparse file are allocated or not. This is currently only
3537
 * implemented for Linux (and no other Unix derivatives) and Windows.
3538
 *
3539
 * Note: A return of VSI_RANGE_STATUS_DATA doesn't exclude that the
3540
 * extent is filled with zeroes! It must be interpreted as "may
3541
 * contain non-zero data".
3542
 *
3543
 * @param fp file handle opened with VSIFOpenL().
3544
 * @param nOffset offset of the start of the extent.
3545
 * @param nLength extent length.
3546
 *
3547
 * @return extent status: VSI_RANGE_STATUS_UNKNOWN, VSI_RANGE_STATUS_DATA or
3548
 *         VSI_RANGE_STATUS_HOLE
3549
 * @since GDAL 2.2
3550
 */
3551
3552
VSIRangeStatus VSIFGetRangeStatusL(VSILFILE *fp, vsi_l_offset nOffset,
3553
                                   vsi_l_offset nLength)
3554
0
{
3555
0
    return fp->GetRangeStatus(nOffset, nLength);
3556
0
}
3557
3558
/************************************************************************/
3559
/*                           VSIIngestFile()                            */
3560
/************************************************************************/
3561
3562
/**
3563
 * \brief Ingest a file into memory.
3564
 *
3565
 * Read the whole content of a file into a memory buffer.
3566
 *
3567
 * Either fp or pszFilename can be NULL, but not both at the same time.
3568
 *
3569
 * If fp is passed non-NULL, it is the responsibility of the caller to
3570
 * close it.
3571
 *
3572
 * If non-NULL, the returned buffer is guaranteed to be NUL-terminated.
3573
 *
3574
 * @param fp file handle opened with VSIFOpenL().
3575
 * @param pszFilename filename.
3576
 * @param ppabyRet pointer to the target buffer. *ppabyRet must be freed with
3577
 *                 VSIFree()
3578
 * @param pnSize pointer to variable to store the file size. May be NULL.
3579
 * @param nMaxSize maximum size of file allowed. If no limit, set to a negative
3580
 *                 value.
3581
 *
3582
 * @return TRUE in case of success.
3583
 *
3584
 * @since GDAL 1.11
3585
 */
3586
3587
int VSIIngestFile(VSILFILE *fp, const char *pszFilename, GByte **ppabyRet,
3588
                  vsi_l_offset *pnSize, GIntBig nMaxSize)
3589
647
{
3590
647
    if (fp == nullptr && pszFilename == nullptr)
3591
0
        return FALSE;
3592
647
    if (ppabyRet == nullptr)
3593
0
        return FALSE;
3594
3595
647
    *ppabyRet = nullptr;
3596
647
    if (pnSize != nullptr)
3597
0
        *pnSize = 0;
3598
3599
647
    bool bFreeFP = false;
3600
647
    if (nullptr == fp)
3601
647
    {
3602
647
        fp = VSIFOpenL(pszFilename, "rb");
3603
647
        if (nullptr == fp)
3604
0
        {
3605
0
            CPLError(CE_Failure, CPLE_FileIO, "Cannot open file '%s'",
3606
0
                     pszFilename);
3607
0
            return FALSE;
3608
0
        }
3609
647
        bFreeFP = true;
3610
647
    }
3611
0
    else
3612
0
    {
3613
0
        if (VSIFSeekL(fp, 0, SEEK_SET) != 0)
3614
0
            return FALSE;
3615
0
    }
3616
3617
647
    vsi_l_offset nDataLen = 0;
3618
3619
647
    if (pszFilename == nullptr || strcmp(pszFilename, "/vsistdin/") == 0)
3620
23
    {
3621
23
        vsi_l_offset nDataAlloc = 0;
3622
23
        if (VSIFSeekL(fp, 0, SEEK_SET) != 0)
3623
0
        {
3624
0
            if (bFreeFP)
3625
0
                CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
3626
0
            return FALSE;
3627
0
        }
3628
23
        while (true)
3629
23
        {
3630
23
            if (nDataLen + 8192 + 1 > nDataAlloc)
3631
23
            {
3632
23
                nDataAlloc = (nDataAlloc * 4) / 3 + 8192 + 1;
3633
23
                if (nDataAlloc >
3634
23
                    static_cast<vsi_l_offset>(static_cast<size_t>(nDataAlloc)))
3635
0
                {
3636
0
                    CPLError(CE_Failure, CPLE_AppDefined,
3637
0
                             "Input file too large to be opened");
3638
0
                    VSIFree(*ppabyRet);
3639
0
                    *ppabyRet = nullptr;
3640
0
                    if (bFreeFP)
3641
0
                        CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
3642
0
                    return FALSE;
3643
0
                }
3644
23
                GByte *pabyNew = static_cast<GByte *>(
3645
23
                    VSIRealloc(*ppabyRet, static_cast<size_t>(nDataAlloc)));
3646
23
                if (pabyNew == nullptr)
3647
0
                {
3648
0
                    CPLError(CE_Failure, CPLE_OutOfMemory,
3649
0
                             "Cannot allocate " CPL_FRMT_GIB " bytes",
3650
0
                             nDataAlloc);
3651
0
                    VSIFree(*ppabyRet);
3652
0
                    *ppabyRet = nullptr;
3653
0
                    if (bFreeFP)
3654
0
                        CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
3655
0
                    return FALSE;
3656
0
                }
3657
23
                *ppabyRet = pabyNew;
3658
23
            }
3659
23
            const int nRead =
3660
23
                static_cast<int>(VSIFReadL(*ppabyRet + nDataLen, 1, 8192, fp));
3661
23
            nDataLen += nRead;
3662
3663
23
            if (nMaxSize >= 0 && nDataLen > static_cast<vsi_l_offset>(nMaxSize))
3664
0
            {
3665
0
                CPLError(CE_Failure, CPLE_AppDefined,
3666
0
                         "Input file too large to be opened");
3667
0
                VSIFree(*ppabyRet);
3668
0
                *ppabyRet = nullptr;
3669
0
                if (pnSize != nullptr)
3670
0
                    *pnSize = 0;
3671
0
                if (bFreeFP)
3672
0
                    CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
3673
0
                return FALSE;
3674
0
            }
3675
3676
23
            if (pnSize != nullptr)
3677
0
                *pnSize += nRead;
3678
23
            (*ppabyRet)[nDataLen] = '\0';
3679
23
            if (nRead == 0)
3680
23
                break;
3681
23
        }
3682
23
    }
3683
624
    else
3684
624
    {
3685
624
        if (VSIFSeekL(fp, 0, SEEK_END) != 0)
3686
82
        {
3687
82
            if (bFreeFP)
3688
82
                CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
3689
82
            return FALSE;
3690
82
        }
3691
542
        nDataLen = VSIFTellL(fp);
3692
3693
        // With "large" VSI I/O API we can read data chunks larger than
3694
        // VSIMalloc could allocate. Catch it here.
3695
542
        if (nDataLen !=
3696
542
                static_cast<vsi_l_offset>(static_cast<size_t>(nDataLen)) ||
3697
542
            nDataLen + 1 < nDataLen
3698
            // opening a directory returns nDataLen = INT_MAX (on 32bit) or
3699
            // INT64_MAX (on 64bit)
3700
542
            || nDataLen + 1 > std::numeric_limits<size_t>::max() / 2 ||
3701
542
            (nMaxSize >= 0 && nDataLen > static_cast<vsi_l_offset>(nMaxSize)))
3702
159
        {
3703
159
            CPLError(CE_Failure, CPLE_AppDefined,
3704
159
                     "Input file too large to be opened");
3705
159
            if (bFreeFP)
3706
159
                CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
3707
159
            return FALSE;
3708
159
        }
3709
3710
383
        if (VSIFSeekL(fp, 0, SEEK_SET) != 0)
3711
0
        {
3712
0
            if (bFreeFP)
3713
0
                CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
3714
0
            return FALSE;
3715
0
        }
3716
3717
383
        *ppabyRet =
3718
383
            static_cast<GByte *>(VSIMalloc(static_cast<size_t>(nDataLen + 1)));
3719
383
        if (nullptr == *ppabyRet)
3720
0
        {
3721
0
            CPLError(CE_Failure, CPLE_OutOfMemory,
3722
0
                     "Cannot allocate " CPL_FRMT_GIB " bytes", nDataLen + 1);
3723
0
            if (bFreeFP)
3724
0
                CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
3725
0
            return FALSE;
3726
0
        }
3727
3728
383
        (*ppabyRet)[nDataLen] = '\0';
3729
383
        if (nDataLen !=
3730
383
            VSIFReadL(*ppabyRet, 1, static_cast<size_t>(nDataLen), fp))
3731
0
        {
3732
0
            CPLError(CE_Failure, CPLE_FileIO,
3733
0
                     "Cannot read " CPL_FRMT_GIB " bytes", nDataLen);
3734
0
            VSIFree(*ppabyRet);
3735
0
            *ppabyRet = nullptr;
3736
0
            if (bFreeFP)
3737
0
                CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
3738
0
            return FALSE;
3739
0
        }
3740
383
        if (pnSize != nullptr)
3741
0
            *pnSize = nDataLen;
3742
383
    }
3743
406
    if (bFreeFP)
3744
406
        CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
3745
406
    return TRUE;
3746
647
}
3747
3748
/************************************************************************/
3749
/*                         VSIOverwriteFile()                           */
3750
/************************************************************************/
3751
3752
/**
3753
 * \brief Overwrite an existing file with content from another one
3754
 *
3755
 * @param fpTarget file handle opened with VSIFOpenL() with "rb+" flag.
3756
 * @param pszSourceFilename source filename
3757
 *
3758
 * @return TRUE in case of success.
3759
 *
3760
 * @since GDAL 3.1
3761
 */
3762
3763
int VSIOverwriteFile(VSILFILE *fpTarget, const char *pszSourceFilename)
3764
0
{
3765
0
    VSILFILE *fpSource = VSIFOpenL(pszSourceFilename, "rb");
3766
0
    if (fpSource == nullptr)
3767
0
    {
3768
0
        CPLError(CE_Failure, CPLE_FileIO, "Cannot open %s", pszSourceFilename);
3769
0
        return false;
3770
0
    }
3771
3772
0
    const size_t nBufferSize = 4096;
3773
0
    void *pBuffer = CPLMalloc(nBufferSize);
3774
0
    VSIFSeekL(fpTarget, 0, SEEK_SET);
3775
0
    bool bRet = true;
3776
0
    while (true)
3777
0
    {
3778
0
        size_t nRead = VSIFReadL(pBuffer, 1, nBufferSize, fpSource);
3779
0
        size_t nWritten = VSIFWriteL(pBuffer, 1, nRead, fpTarget);
3780
0
        if (nWritten != nRead)
3781
0
        {
3782
0
            bRet = false;
3783
0
            break;
3784
0
        }
3785
0
        if (nRead < nBufferSize)
3786
0
            break;
3787
0
    }
3788
3789
0
    if (bRet)
3790
0
    {
3791
0
        bRet = VSIFTruncateL(fpTarget, VSIFTellL(fpTarget)) == 0;
3792
0
        if (!bRet)
3793
0
        {
3794
0
            CPLError(CE_Failure, CPLE_FileIO, "Truncation failed");
3795
0
        }
3796
0
    }
3797
3798
0
    CPLFree(pBuffer);
3799
0
    VSIFCloseL(fpSource);
3800
0
    return bRet;
3801
0
}
3802
3803
/************************************************************************/
3804
/*                        VSIFGetNativeFileDescriptorL()                */
3805
/************************************************************************/
3806
3807
/**
3808
 * \fn VSIVirtualHandle::GetNativeFileDescriptor()
3809
 * \brief Returns the "native" file descriptor for the virtual handle.
3810
 *
3811
 * This will only return a non-NULL value for "real" files handled by the
3812
 * operating system (to be opposed to GDAL virtual file systems).
3813
 *
3814
 * On POSIX systems, this will be a integer value ("fd") cast as a void*.
3815
 * On Windows systems, this will be the HANDLE.
3816
 *
3817
 * @return the native file descriptor, or NULL.
3818
 */
3819
3820
/**
3821
 * \brief Returns the "native" file descriptor for the virtual handle.
3822
 *
3823
 * This will only return a non-NULL value for "real" files handled by the
3824
 * operating system (to be opposed to GDAL virtual file systems).
3825
 *
3826
 * On POSIX systems, this will be a integer value ("fd") cast as a void*.
3827
 * On Windows systems, this will be the HANDLE.
3828
 *
3829
 * @param fp file handle opened with VSIFOpenL().
3830
 *
3831
 * @return the native file descriptor, or NULL.
3832
 */
3833
3834
void *VSIFGetNativeFileDescriptorL(VSILFILE *fp)
3835
0
{
3836
0
    return fp->GetNativeFileDescriptor();
3837
0
}
3838
3839
/************************************************************************/
3840
/*                      VSIGetDiskFreeSpace()                           */
3841
/************************************************************************/
3842
3843
/**
3844
 * \brief Return free disk space available on the filesystem.
3845
 *
3846
 * This function returns the free disk space available on the filesystem.
3847
 *
3848
 * @param pszDirname a directory of the filesystem to query.
3849
 * @return The free space in bytes. Or -1 in case of error.
3850
 * @since GDAL 2.1
3851
 */
3852
3853
GIntBig VSIGetDiskFreeSpace(const char *pszDirname)
3854
0
{
3855
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszDirname);
3856
3857
0
    return poFSHandler->GetDiskFreeSpace(pszDirname);
3858
0
}
3859
3860
/************************************************************************/
3861
/*                    VSIGetFileSystemsPrefixes()                       */
3862
/************************************************************************/
3863
3864
/**
3865
 * \brief Return the list of prefixes for virtual file system handlers
3866
 * currently registered.
3867
 *
3868
 * Typically: "", "/vsimem/", "/vsicurl/", etc
3869
 *
3870
 * @return a NULL terminated list of prefixes. Must be freed with CSLDestroy()
3871
 * @since GDAL 2.3
3872
 */
3873
3874
char **VSIGetFileSystemsPrefixes(void)
3875
0
{
3876
0
    return VSIFileManager::GetPrefixes();
3877
0
}
3878
3879
/************************************************************************/
3880
/*                     VSIGetFileSystemOptions()                        */
3881
/************************************************************************/
3882
3883
/**
3884
 * \brief Return the list of options associated with a virtual file system
3885
 * handler as a serialized XML string.
3886
 *
3887
 * Those options may be set as configuration options with CPLSetConfigOption().
3888
 *
3889
 * @param pszFilename a filename, or prefix of a virtual file system handler.
3890
 * @return a string, which must not be freed, or NULL if no options is declared.
3891
 * @since GDAL 2.3
3892
 */
3893
3894
const char *VSIGetFileSystemOptions(const char *pszFilename)
3895
0
{
3896
0
    VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
3897
3898
0
    return poFSHandler->GetOptions();
3899
0
}
3900
3901
/************************************************************************/
3902
/*                       VSISetPathSpecificOption()                     */
3903
/************************************************************************/
3904
3905
static std::mutex oMutexPathSpecificOptions;
3906
3907
// key is a path prefix
3908
// value is a map of key, value pair
3909
static std::map<std::string, std::map<std::string, std::string>>
3910
    oMapPathSpecificOptions;
3911
3912
/**
3913
 * \brief Set a credential (or more generally an option related to a
3914
 *        virtual file system) for a given path prefix.
3915
 * @deprecated in GDAL 3.6 for the better named VSISetPathSpecificOption()
3916
 * @see VSISetPathSpecificOption()
3917
 */
3918
void VSISetCredential(const char *pszPathPrefix, const char *pszKey,
3919
                      const char *pszValue)
3920
0
{
3921
0
    VSISetPathSpecificOption(pszPathPrefix, pszKey, pszValue);
3922
0
}
3923
3924
/**
3925
 * \brief Set a path specific option for a given path prefix.
3926
 *
3927
 * Such option is typically, but not limited to, a credential setting for a
3928
 * virtual file system.
3929
 *
3930
 * That option may also be set as a configuration option with
3931
 * CPLSetConfigOption(), but this function allows to specify them with a
3932
 * granularity at the level of a file path, which makes it easier if using the
3933
 * same virtual file system but with different credentials (e.g. different
3934
 * credentials for bucket "/vsis3/foo" and "/vsis3/bar")
3935
 *
3936
 * This is supported for the following virtual file systems:
3937
 * /vsis3/, /vsigs/, /vsiaz/, /vsioss/, /vsiwebhdfs, /vsiswift.
3938
 * Note: setting them for a path starting with /vsiXXX/ will also apply for
3939
 * /vsiXXX_streaming/ requests.
3940
 *
3941
 * Note that no particular care is taken to store them in RAM in a secure way.
3942
 * So they might accidentally hit persistent storage if swapping occurs, or
3943
 * someone with access to the memory allocated by the process may be able to
3944
 * read them.
3945
 *
3946
 * @param pszPathPrefix a path prefix of a virtual file system handler.
3947
 *                      Typically of the form "/vsiXXX/bucket". Must NOT be
3948
 * NULL. Should not include trailing slashes.
3949
 * @param pszKey        Option name. Must NOT be NULL.
3950
 * @param pszValue      Option value. May be NULL to erase it.
3951
 *
3952
 * @since GDAL 3.6
3953
 */
3954
3955
void VSISetPathSpecificOption(const char *pszPathPrefix, const char *pszKey,
3956
                              const char *pszValue)
3957
0
{
3958
0
    std::lock_guard<std::mutex> oLock(oMutexPathSpecificOptions);
3959
0
    auto oIter = oMapPathSpecificOptions.find(pszPathPrefix);
3960
0
    CPLString osKey(pszKey);
3961
0
    osKey.toupper();
3962
0
    if (oIter == oMapPathSpecificOptions.end())
3963
0
    {
3964
0
        if (pszValue != nullptr)
3965
0
            oMapPathSpecificOptions[pszPathPrefix][osKey] = pszValue;
3966
0
    }
3967
0
    else if (pszValue != nullptr)
3968
0
        oIter->second[osKey] = pszValue;
3969
0
    else
3970
0
        oIter->second.erase(osKey);
3971
0
}
3972
3973
/************************************************************************/
3974
/*                       VSIClearPathSpecificOptions()                  */
3975
/************************************************************************/
3976
3977
/**
3978
 * \brief Clear path specific options set with VSISetPathSpecificOption()
3979
 * @deprecated in GDAL 3.6 for the better named VSIClearPathSpecificOptions()
3980
 * @see VSIClearPathSpecificOptions()
3981
 */
3982
void VSIClearCredentials(const char *pszPathPrefix)
3983
0
{
3984
0
    return VSIClearPathSpecificOptions(pszPathPrefix);
3985
0
}
3986
3987
/**
3988
 * \brief Clear path specific options set with VSISetPathSpecificOption()
3989
 *
3990
 * Note that no particular care is taken to remove them from RAM in a secure
3991
 * way.
3992
 *
3993
 * @param pszPathPrefix If set to NULL, all path specific options are cleared.
3994
 *                      If set to not-NULL, only those set with
3995
 *                      VSISetPathSpecificOption(pszPathPrefix, ...) will be
3996
 * cleared.
3997
 *
3998
 * @since GDAL 3.6
3999
 */
4000
void VSIClearPathSpecificOptions(const char *pszPathPrefix)
4001
0
{
4002
0
    std::lock_guard<std::mutex> oLock(oMutexPathSpecificOptions);
4003
0
    if (pszPathPrefix == nullptr)
4004
0
    {
4005
0
        oMapPathSpecificOptions.clear();
4006
0
    }
4007
0
    else
4008
0
    {
4009
0
        oMapPathSpecificOptions.erase(pszPathPrefix);
4010
0
    }
4011
0
}
4012
4013
/************************************************************************/
4014
/*                        VSIGetPathSpecificOption()                    */
4015
/************************************************************************/
4016
4017
/**
4018
 * \brief Get the value of a credential (or more generally an option related to
4019
 * a virtual file system) for a given path.
4020
 * @deprecated in GDAL 3.6 for the better named VSIGetPathSpecificOption()
4021
 * @see VSIGetPathSpecificOption()
4022
 */
4023
const char *VSIGetCredential(const char *pszPath, const char *pszKey,
4024
                             const char *pszDefault)
4025
0
{
4026
0
    return VSIGetPathSpecificOption(pszPath, pszKey, pszDefault);
4027
0
}
4028
4029
/**
4030
 * \brief Get the value a path specific option.
4031
 *
4032
 * Such option is typically, but not limited to, a credential setting for a
4033
 * virtual file system.
4034
 *
4035
 * If no match occurs, CPLGetConfigOption(pszKey, pszDefault) is returned.
4036
 *
4037
 * Mostly to be used by virtual file system implementations.
4038
 *
4039
 * @since GDAL 3.6
4040
 * @see VSISetPathSpecificOption()
4041
 */
4042
const char *VSIGetPathSpecificOption(const char *pszPath, const char *pszKey,
4043
                                     const char *pszDefault)
4044
0
{
4045
0
    {
4046
0
        std::lock_guard<std::mutex> oLock(oMutexPathSpecificOptions);
4047
0
        for (auto it = oMapPathSpecificOptions.rbegin();
4048
0
             it != oMapPathSpecificOptions.rend(); ++it)
4049
0
        {
4050
0
            if (STARTS_WITH(pszPath, it->first.c_str()))
4051
0
            {
4052
0
                auto oIter = it->second.find(CPLString(pszKey).toupper());
4053
0
                if (oIter != it->second.end())
4054
0
                    return oIter->second.c_str();
4055
0
            }
4056
0
        }
4057
0
    }
4058
0
    return CPLGetConfigOption(pszKey, pszDefault);
4059
0
}
4060
4061
/************************************************************************/
4062
/*                      VSIDuplicateFileSystemHandler()                 */
4063
/************************************************************************/
4064
4065
/**
4066
 * \brief Duplicate an existing file system handler.
4067
 *
4068
 * A number of virtual file system for remote object stores use protocols
4069
 * identical or close to popular ones (typically AWS S3), but with slightly
4070
 * different settings (at the very least the endpoint).
4071
 *
4072
 * This functions allows to duplicate the source virtual file system handler
4073
 * as a new one with a different prefix (when the source virtual file system
4074
 * handler supports the duplication operation).
4075
 *
4076
 * VSISetPathSpecificOption() will typically be called afterwards to change
4077
 * configurable settings on the cloned file system handler (e.g. AWS_S3_ENDPOINT
4078
 * for a clone of /vsis3/).
4079
 *
4080
 * @since GDAL 3.7
4081
 */
4082
bool VSIDuplicateFileSystemHandler(const char *pszSourceFSName,
4083
                                   const char *pszNewFSName)
4084
0
{
4085
0
    VSIFilesystemHandler *poTargetFSHandler =
4086
0
        VSIFileManager::GetHandler(pszNewFSName);
4087
0
    if (poTargetFSHandler != VSIFileManager::GetHandler("/"))
4088
0
    {
4089
0
        CPLError(CE_Failure, CPLE_AppDefined,
4090
0
                 "%s is already a known virtual file system", pszNewFSName);
4091
0
        return false;
4092
0
    }
4093
4094
0
    VSIFilesystemHandler *poSourceFSHandler =
4095
0
        VSIFileManager::GetHandler(pszSourceFSName);
4096
0
    if (!poSourceFSHandler)
4097
0
    {
4098
0
        CPLError(CE_Failure, CPLE_AppDefined,
4099
0
                 "%s is not a known virtual file system", pszSourceFSName);
4100
0
        return false;
4101
0
    }
4102
4103
0
    poTargetFSHandler = poSourceFSHandler->Duplicate(pszNewFSName);
4104
0
    if (!poTargetFSHandler)
4105
0
        return false;
4106
4107
0
    VSIFileManager::InstallHandler(pszNewFSName, poTargetFSHandler);
4108
0
    return true;
4109
0
}
4110
4111
/************************************************************************/
4112
/* ==================================================================== */
4113
/*                           VSIFileManager()                           */
4114
/* ==================================================================== */
4115
/************************************************************************/
4116
4117
#ifndef DOXYGEN_SKIP
4118
4119
/*
4120
** Notes on Multithreading:
4121
**
4122
** The VSIFileManager maintains a list of file type handlers (mem, large
4123
** file, etc).  It should be thread safe.
4124
**/
4125
4126
/************************************************************************/
4127
/*                           VSIFileManager()                           */
4128
/************************************************************************/
4129
4130
3
VSIFileManager::VSIFileManager() : poDefaultHandler(nullptr)
4131
3
{
4132
3
}
4133
4134
/************************************************************************/
4135
/*                          ~VSIFileManager()                           */
4136
/************************************************************************/
4137
4138
VSIFileManager::~VSIFileManager()
4139
0
{
4140
0
    std::set<VSIFilesystemHandler *> oSetAlreadyDeleted;
4141
0
    for (std::map<std::string, VSIFilesystemHandler *>::const_iterator iter =
4142
0
             oHandlers.begin();
4143
0
         iter != oHandlers.end(); ++iter)
4144
0
    {
4145
0
        if (oSetAlreadyDeleted.find(iter->second) == oSetAlreadyDeleted.end())
4146
0
        {
4147
0
            oSetAlreadyDeleted.insert(iter->second);
4148
0
            delete iter->second;
4149
0
        }
4150
0
    }
4151
4152
0
    delete poDefaultHandler;
4153
0
}
4154
4155
/************************************************************************/
4156
/*                                Get()                                 */
4157
/************************************************************************/
4158
4159
static VSIFileManager *poManager = nullptr;
4160
static CPLMutex *hVSIFileManagerMutex = nullptr;
4161
4162
VSIFileManager *VSIFileManager::Get()
4163
128k
{
4164
128k
    CPLMutexHolder oHolder(&hVSIFileManagerMutex);
4165
128k
    if (poManager != nullptr)
4166
128k
    {
4167
128k
        return poManager;
4168
128k
    }
4169
4170
3
    poManager = new VSIFileManager;
4171
3
    VSIInstallLargeFileHandler();
4172
3
    VSIInstallSubFileHandler();
4173
3
    VSIInstallMemFileHandler();
4174
3
#ifdef HAVE_LIBZ
4175
3
    VSIInstallGZipFileHandler();
4176
3
    VSIInstallZipFileHandler();
4177
3
#endif
4178
#ifdef HAVE_LIBARCHIVE
4179
    VSIInstall7zFileHandler();
4180
    VSIInstallRarFileHandler();
4181
#endif
4182
#ifdef HAVE_CURL
4183
    VSIInstallCurlFileHandler();
4184
    VSIInstallCurlStreamingFileHandler();
4185
    VSIInstallS3FileHandler();
4186
    VSIInstallS3StreamingFileHandler();
4187
    VSIInstallGSFileHandler();
4188
    VSIInstallGSStreamingFileHandler();
4189
    VSIInstallAzureFileHandler();
4190
    VSIInstallAzureStreamingFileHandler();
4191
    VSIInstallADLSFileHandler();
4192
    VSIInstallOSSFileHandler();
4193
    VSIInstallOSSStreamingFileHandler();
4194
    VSIInstallSwiftFileHandler();
4195
    VSIInstallSwiftStreamingFileHandler();
4196
    VSIInstallWebHdfsHandler();
4197
#endif
4198
3
    VSIInstallStdinHandler();
4199
3
    VSIInstallHdfsHandler();
4200
3
    VSIInstallStdoutHandler();
4201
3
    VSIInstallSparseFileHandler();
4202
3
    VSIInstallTarFileHandler();
4203
3
    VSIInstallCachedFileHandler();
4204
3
    VSIInstallCryptFileHandler();
4205
4206
3
    return poManager;
4207
128k
}
4208
4209
/************************************************************************/
4210
/*                           GetPrefixes()                              */
4211
/************************************************************************/
4212
4213
char **VSIFileManager::GetPrefixes()
4214
0
{
4215
0
    CPLMutexHolder oHolder(&hVSIFileManagerMutex);
4216
0
    CPLStringList aosList;
4217
0
    for (const auto &oIter : Get()->oHandlers)
4218
0
    {
4219
0
        if (oIter.first != "/vsicurl?")
4220
0
        {
4221
0
            aosList.AddString(oIter.first.c_str());
4222
0
        }
4223
0
    }
4224
0
    return aosList.StealList();
4225
0
}
4226
4227
/************************************************************************/
4228
/*                             GetHandler()                             */
4229
/************************************************************************/
4230
4231
VSIFilesystemHandler *VSIFileManager::GetHandler(const char *pszPath)
4232
4233
128k
{
4234
128k
    VSIFileManager *poThis = Get();
4235
128k
    const size_t nPathLen = strlen(pszPath);
4236
4237
128k
    for (std::map<std::string, VSIFilesystemHandler *>::const_iterator iter =
4238
128k
             poThis->oHandlers.begin();
4239
1.11M
         iter != poThis->oHandlers.end(); ++iter)
4240
1.05M
    {
4241
1.05M
        const char *pszIterKey = iter->first.c_str();
4242
1.05M
        const size_t nIterKeyLen = iter->first.size();
4243
1.05M
        if (strncmp(pszPath, pszIterKey, nIterKeyLen) == 0)
4244
68.1k
            return iter->second;
4245
4246
        // "/vsimem\foo" should be handled as "/vsimem/foo".
4247
990k
        if (nIterKeyLen && nPathLen > nIterKeyLen &&
4248
990k
            pszIterKey[nIterKeyLen - 1] == '/' &&
4249
990k
            pszPath[nIterKeyLen - 1] == '\\' &&
4250
990k
            strncmp(pszPath, pszIterKey, nIterKeyLen - 1) == 0)
4251
113
            return iter->second;
4252
4253
        // /vsimem should be treated as a match for /vsimem/.
4254
990k
        if (nPathLen + 1 == nIterKeyLen &&
4255
990k
            strncmp(pszPath, pszIterKey, nPathLen) == 0)
4256
5.94k
            return iter->second;
4257
990k
    }
4258
4259
54.1k
    return poThis->poDefaultHandler;
4260
128k
}
4261
4262
/************************************************************************/
4263
/*                           InstallHandler()                           */
4264
/************************************************************************/
4265
4266
void VSIFileManager::InstallHandler(const std::string &osPrefix,
4267
                                    VSIFilesystemHandler *poHandler)
4268
4269
39
{
4270
39
    if (osPrefix == "")
4271
3
        Get()->poDefaultHandler = poHandler;
4272
36
    else
4273
36
        Get()->oHandlers[osPrefix] = poHandler;
4274
39
}
4275
4276
/************************************************************************/
4277
/*                          RemoveHandler()                             */
4278
/************************************************************************/
4279
4280
void VSIFileManager::RemoveHandler(const std::string &osPrefix)
4281
0
{
4282
0
    if (osPrefix == "")
4283
0
        Get()->poDefaultHandler = nullptr;
4284
0
    else
4285
0
        Get()->oHandlers.erase(osPrefix);
4286
0
}
4287
4288
/************************************************************************/
4289
/*                       VSICleanupFileManager()                        */
4290
/************************************************************************/
4291
4292
void VSICleanupFileManager()
4293
4294
0
{
4295
0
    if (poManager)
4296
0
    {
4297
0
        delete poManager;
4298
0
        poManager = nullptr;
4299
0
    }
4300
4301
0
    if (hVSIFileManagerMutex != nullptr)
4302
0
    {
4303
0
        CPLDestroyMutex(hVSIFileManagerMutex);
4304
0
        hVSIFileManagerMutex = nullptr;
4305
0
    }
4306
4307
#ifdef HAVE_CURL
4308
    VSICURLDestroyCacheFileProp();
4309
#endif
4310
0
}
4311
4312
/************************************************************************/
4313
/*                            Truncate()                                */
4314
/************************************************************************/
4315
4316
int VSIVirtualHandle::Truncate(vsi_l_offset nNewSize)
4317
0
{
4318
0
    const vsi_l_offset nOriginalPos = Tell();
4319
0
    if (Seek(0, SEEK_END) == 0 && nNewSize >= Tell())
4320
0
    {
4321
        // Fill with zeroes
4322
0
        std::vector<GByte> aoBytes(4096, 0);
4323
0
        vsi_l_offset nCurOffset = nOriginalPos;
4324
0
        while (nCurOffset < nNewSize)
4325
0
        {
4326
0
            constexpr vsi_l_offset nMaxOffset = 4096;
4327
0
            const int nSize =
4328
0
                static_cast<int>(std::min(nMaxOffset, nNewSize - nCurOffset));
4329
0
            if (Write(&aoBytes[0], nSize, 1) != 1)
4330
0
            {
4331
0
                Seek(nOriginalPos, SEEK_SET);
4332
0
                return -1;
4333
0
            }
4334
0
            nCurOffset += nSize;
4335
0
        }
4336
0
        return Seek(nOriginalPos, SEEK_SET) == 0 ? 0 : -1;
4337
0
    }
4338
4339
0
    CPLDebug("VSI", "Truncation is not supported in generic implementation "
4340
0
                    "of Truncate()");
4341
0
    Seek(nOriginalPos, SEEK_SET);
4342
0
    return -1;
4343
0
}
4344
4345
/************************************************************************/
4346
/*                           ReadMultiRange()                           */
4347
/************************************************************************/
4348
4349
int VSIVirtualHandle::ReadMultiRange(int nRanges, void **ppData,
4350
                                     const vsi_l_offset *panOffsets,
4351
                                     const size_t *panSizes)
4352
0
{
4353
0
    int nRet = 0;
4354
0
    const vsi_l_offset nCurOffset = Tell();
4355
0
    for (int i = 0; i < nRanges; i++)
4356
0
    {
4357
0
        if (Seek(panOffsets[i], SEEK_SET) < 0)
4358
0
        {
4359
0
            nRet = -1;
4360
0
            break;
4361
0
        }
4362
4363
0
        const size_t nRead = Read(ppData[i], 1, panSizes[i]);
4364
0
        if (panSizes[i] != nRead)
4365
0
        {
4366
0
            nRet = -1;
4367
0
            break;
4368
0
        }
4369
0
    }
4370
4371
0
    Seek(nCurOffset, SEEK_SET);
4372
4373
0
    return nRet;
4374
0
}
4375
4376
#endif  // #ifndef DOXYGEN_SKIP
4377
4378
/************************************************************************/
4379
/*                            HasPRead()                                */
4380
/************************************************************************/
4381
4382
/** Returns whether this file handle supports the PRead() method.
4383
 *
4384
 * @since GDAL 3.6
4385
 */
4386
bool VSIVirtualHandle::HasPRead() const
4387
0
{
4388
0
    return false;
4389
0
}
4390
4391
/************************************************************************/
4392
/*                             PRead()                                  */
4393
/************************************************************************/
4394
4395
/** Do a parallel-compatible read operation.
4396
 *
4397
 * This methods reads into pBuffer up to nSize bytes starting at offset nOffset
4398
 * in the file. The current file offset is not affected by this method.
4399
 *
4400
 * The implementation is thread-safe: several threads can issue PRead()
4401
 * concurrently on the same VSIVirtualHandle object.
4402
 *
4403
 * This method has the same semantics as pread() Linux operation. It is only
4404
 * available if HasPRead() returns true.
4405
 *
4406
 * @param pBuffer output buffer (must be at least nSize bytes large).
4407
 * @param nSize   number of bytes to read in the file.
4408
 * @param nOffset file offset from which to read.
4409
 * @return number of bytes read.
4410
 * @since GDAL 3.6
4411
 */
4412
size_t VSIVirtualHandle::PRead(CPL_UNUSED void *pBuffer,
4413
                               CPL_UNUSED size_t nSize,
4414
                               CPL_UNUSED vsi_l_offset nOffset) const
4415
0
{
4416
0
    return 0;
4417
0
}
4418
4419
#ifndef DOXYGEN_SKIP
4420
/************************************************************************/
4421
/*                  VSIProxyFileHandle::CancelCreation()                */
4422
/************************************************************************/
4423
4424
void VSIProxyFileHandle::CancelCreation()
4425
0
{
4426
0
    m_nativeHandle->CancelCreation();
4427
0
}
4428
#endif
4429
4430
/************************************************************************/
4431
/*                         VSIURIToVSIPath()                            */
4432
/************************************************************************/
4433
4434
/** Return a VSI compatible path from a URI / URL
4435
 *
4436
 * Substitute URI / URLs starting with s3://, gs://, etc. by their VSI
4437
 * prefix equivalent. If no known substitution is found, the input string is
4438
 * returned unmodified.
4439
 *
4440
 * @since GDAL 3.12
4441
 */
4442
std::string VSIURIToVSIPath(const std::string &osURI)
4443
0
{
4444
0
    static const struct
4445
0
    {
4446
0
        const char *pszFSSpecPrefix;
4447
0
        const char *pszVSIPrefix;
4448
0
    } substitutions[] = {
4449
0
        {"s3://", "/vsis3/"},
4450
0
        {"gs://", "/vsigs/"},
4451
0
        {"gcs://", "/vsigs/"},
4452
0
        {"az://", "/vsiaz/"},
4453
0
        {"azure://", "/vsiaz/"},
4454
0
        {"http://", "/vsicurl/http://"},
4455
0
        {"https://", "/vsicurl/https://"},
4456
0
        {"file://", ""},
4457
0
    };
4458
4459
0
    for (const auto &substitution : substitutions)
4460
0
    {
4461
0
        if (STARTS_WITH(osURI.c_str(), substitution.pszFSSpecPrefix))
4462
0
        {
4463
0
            return std::string(substitution.pszVSIPrefix)
4464
0
                .append(osURI.c_str() + strlen(substitution.pszFSSpecPrefix));
4465
0
        }
4466
0
    }
4467
4468
0
    return osURI;
4469
0
}