Coverage Report

Created: 2026-02-14 06:52

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