Coverage Report

Created: 2025-11-16 06:25

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