Coverage Report

Created: 2025-06-13 06:29

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