-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
/
Copy pathcpl_vsil.cpp
3970 lines (3525 loc) · 136 KB
/
cpl_vsil.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/******************************************************************************
*
* Project: VSI Virtual File System
* Purpose: Implementation VSI*L File API and other file system access
* methods going through file virtualization.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2005, Frank Warmerdam <warmerdam@pobox.com>
* Copyright (c) 2008-2014, Even Rouault <even dot rouault at spatialys.com>
*
* SPDX-License-Identifier: MIT
****************************************************************************/
#include "cpl_port.h"
#include "cpl_vsi.h"
#include <cassert>
#include <cinttypes>
#include <cstdarg>
#include <cstddef>
#include <cstring>
#if HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include <algorithm>
#include <limits>
#include <map>
#include <memory>
#include <mutex>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include "cpl_conv.h"
#include "cpl_error.h"
#include "cpl_multiproc.h"
#include "cpl_string.h"
#include "cpl_vsi_virtual.h"
#include "cpl_vsil_curl_class.h"
// To avoid aliasing to GetDiskFreeSpace to GetDiskFreeSpaceA on Windows
#ifdef GetDiskFreeSpace
#undef GetDiskFreeSpace
#endif
/************************************************************************/
/* VSIReadDir() */
/************************************************************************/
/**
* \brief Read names in a directory.
*
* This function abstracts access to directory contains. It returns a
* list of strings containing the names of files, and directories in this
* directory. The resulting string list becomes the responsibility of the
* application and should be freed with CSLDestroy() when no longer needed.
*
* Note that no error is issued via CPLError() if the directory path is
* invalid, though NULL is returned.
*
* This function used to be known as CPLReadDir(), but the old name is now
* deprecated.
*
* @param pszPath the relative, or absolute path of a directory to read.
* UTF-8 encoded.
* @return The list of entries in the directory, or NULL if the directory
* doesn't exist. Filenames are returned in UTF-8 encoding.
*/
char **VSIReadDir(const char *pszPath)
{
return VSIReadDirEx(pszPath, 0);
}
/************************************************************************/
/* VSIReadDirEx() */
/************************************************************************/
/**
* \brief Read names in a directory.
*
* This function abstracts access to directory contains. It returns a
* list of strings containing the names of files, and directories in this
* directory. The resulting string list becomes the responsibility of the
* application and should be freed with CSLDestroy() when no longer needed.
*
* Note that no error is issued via CPLError() if the directory path is
* invalid, though NULL is returned.
*
* If nMaxFiles is set to a positive number, directory listing will stop after
* that limit has been reached. Note that to indicate truncate, at least one
* element more than the nMaxFiles limit will be returned. If CSLCount() on the
* result is lesser or equal to nMaxFiles, then no truncation occurred.
*
* @param pszPath the relative, or absolute path of a directory to read.
* UTF-8 encoded.
* @param nMaxFiles maximum number of files after which to stop, or 0 for no
* limit.
* @return The list of entries in the directory, or NULL if the directory
* doesn't exist. Filenames are returned in UTF-8 encoding.
* @since GDAL 2.1
*/
char **VSIReadDirEx(const char *pszPath, int nMaxFiles)
{
VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath);
return poFSHandler->ReadDirEx(pszPath, nMaxFiles);
}
/************************************************************************/
/* VSISiblingFiles() */
/************************************************************************/
/**
* \brief Return related filenames
*
* This function is essentially meant at being used by GDAL internals.
*
* @param pszFilename the path of a filename to inspect
* UTF-8 encoded.
* @return The list of entries, relative to the directory, of all sidecar
* files available or NULL if the list is not known.
* Filenames are returned in UTF-8 encoding.
* Most implementations will return NULL, and a subsequent ReadDir will
* list all files available in the file's directory. This function will be
* overridden by VSI FilesystemHandlers that wish to force e.g. an empty list
* to avoid opening non-existent files on slow filesystems. The return value
* shall be destroyed with CSLDestroy()
* @since GDAL 3.2
*/
char **VSISiblingFiles(const char *pszFilename)
{
VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
return poFSHandler->SiblingFiles(pszFilename);
}
/************************************************************************/
/* VSIGetDirectorySeparator() */
/************************************************************************/
/** Return the directory separator for the specified path.
*
* Default is forward slash. The only exception currently is the Windows
* file system which returns backslash, unless the specified path is of the
* form "{drive_letter}:/{rest_of_the_path}".
*
* @since 3.9
*/
const char *VSIGetDirectorySeparator(const char *pszPath)
{
if (STARTS_WITH(pszPath, "http://") || STARTS_WITH(pszPath, "https://"))
return "/";
VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath);
return poFSHandler->GetDirectorySeparator(pszPath);
}
/************************************************************************/
/* VSIReadRecursive() */
/************************************************************************/
/**
* \brief Read names in a directory recursively.
*
* This function abstracts access to directory contents and subdirectories.
* It returns a list of strings containing the names of files and directories
* in this directory and all subdirectories. The resulting string list becomes
* the responsibility of the application and should be freed with CSLDestroy()
* when no longer needed.
*
* Note that no error is issued via CPLError() if the directory path is
* invalid, though NULL is returned.
*
* Note: since GDAL 3.9, for recursive mode, the directory separator will no
* longer be always forward slash, but will be the one returned by
* VSIGetDirectorySeparator(pszPathIn), so potentially backslash on Windows
* file systems.
*
* @param pszPathIn the relative, or absolute path of a directory to read.
* UTF-8 encoded.
*
* @return The list of entries in the directory and subdirectories
* or NULL if the directory doesn't exist. Filenames are returned in UTF-8
* encoding.
* @since GDAL 1.10.0
*
*/
char **VSIReadDirRecursive(const char *pszPathIn)
{
const char SEP = VSIGetDirectorySeparator(pszPathIn)[0];
const char *const apszOptions[] = {"NAME_AND_TYPE_ONLY=YES", nullptr};
VSIDIR *psDir = VSIOpenDir(pszPathIn, -1, apszOptions);
if (!psDir)
return nullptr;
CPLStringList oFiles;
while (auto psEntry = VSIGetNextDirEntry(psDir))
{
if (VSI_ISDIR(psEntry->nMode) && psEntry->pszName[0] &&
psEntry->pszName[strlen(psEntry->pszName) - 1] != SEP)
{
oFiles.AddString((std::string(psEntry->pszName) + SEP).c_str());
}
else
{
oFiles.AddString(psEntry->pszName);
}
}
VSICloseDir(psDir);
return oFiles.StealList();
}
/************************************************************************/
/* CPLReadDir() */
/* */
/* This is present only to provide ABI compatibility with older */
/* versions. */
/************************************************************************/
#undef CPLReadDir
CPL_C_START
char CPL_DLL **CPLReadDir(const char *pszPath);
CPL_C_END
char **CPLReadDir(const char *pszPath)
{
return VSIReadDir(pszPath);
}
/************************************************************************/
/* VSIOpenDir() */
/************************************************************************/
/**
* \brief Open a directory to read its entries.
*
* This function is close to the POSIX opendir() function.
*
* For /vsis3/, /vsigs/, /vsioss/, /vsiaz/ and /vsiadls/, this function has an
* efficient implementation, minimizing the number of network requests, when
* invoked with nRecurseDepth <= 0.
*
* Entries are read by calling VSIGetNextDirEntry() on the handled returned by
* that function, until it returns NULL. VSICloseDir() must be called once done
* with the returned directory handle.
*
* @param pszPath the relative, or absolute path of a directory to read.
* UTF-8 encoded.
* @param nRecurseDepth 0 means do not recurse in subdirectories, 1 means
* recurse only in the first level of subdirectories, etc. -1 means unlimited
* recursion level
* @param papszOptions NULL terminated list of options, or NULL. The following
* options are implemented:
* <ul>
* <li>PREFIX=string: (GDAL >= 3.4) Filter to select filenames only starting
* with the specified prefix. Implemented efficiently for /vsis3/, /vsigs/,
* and /vsiaz/ (but not /vsiadls/)
* </li>
* <li>NAME_AND_TYPE_ONLY=YES/NO: (GDAL >= 3.4) Defaults to NO. If set to YES,
* only the pszName and nMode members of VSIDIR are guaranteed to be set.
* This is implemented efficiently for the Unix virtual file system.
* </li>
* </ul>
*
* @return a handle, or NULL in case of error
* @since GDAL 2.4
*
*/
VSIDIR *VSIOpenDir(const char *pszPath, int nRecurseDepth,
const char *const *papszOptions)
{
VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath);
return poFSHandler->OpenDir(pszPath, nRecurseDepth, papszOptions);
}
/************************************************************************/
/* VSIGetNextDirEntry() */
/************************************************************************/
/**
* \brief Return the next entry of the directory
*
* This function is close to the POSIX readdir() function. It actually returns
* more information (file size, last modification time), which on 'real' file
* systems involve one 'stat' call per file.
*
* For filesystems that can have both a regular file and a directory name of
* the same name (typically /vsis3/), when this situation of duplicate happens,
* the directory name will be suffixed by a slash character. Otherwise directory
* names are not suffixed by slash.
*
* The returned entry remains valid until the next call to VSINextDirEntry()
* or VSICloseDir() with the same handle.
*
* Note: since GDAL 3.9, for recursive mode, the directory separator will no
* longer be always forward slash, but will be the one returned by
* VSIGetDirectorySeparator(pszPathIn), so potentially backslash on Windows
* file systems.
*
* @param dir Directory handled returned by VSIOpenDir(). Must not be NULL.
*
* @return a entry, or NULL if there is no more entry in the directory. This
* return value must not be freed.
* @since GDAL 2.4
*
*/
const VSIDIREntry *VSIGetNextDirEntry(VSIDIR *dir)
{
return dir->NextDirEntry();
}
/************************************************************************/
/* VSICloseDir() */
/************************************************************************/
/**
* \brief Close a directory
*
* This function is close to the POSIX closedir() function.
*
* @param dir Directory handled returned by VSIOpenDir().
*
* @since GDAL 2.4
*/
void VSICloseDir(VSIDIR *dir)
{
delete dir;
}
/************************************************************************/
/* VSIMkdir() */
/************************************************************************/
/**
* \brief Create a directory.
*
* Create a new directory with the indicated mode. For POSIX-style systems,
* the mode is modified by the file creation mask (umask). However, some
* file systems and platforms may not use umask, or they may ignore the mode
* completely. So a reasonable cross-platform default mode value is 0755.
*
* Analog of the POSIX mkdir() function.
*
* @param pszPathname the path to the directory to create. UTF-8 encoded.
* @param mode the permissions mode.
*
* @return 0 on success or -1 on an error.
*/
int VSIMkdir(const char *pszPathname, long mode)
{
VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPathname);
return poFSHandler->Mkdir(pszPathname, mode);
}
/************************************************************************/
/* VSIMkdirRecursive() */
/************************************************************************/
/**
* \brief Create a directory and all its ancestors
*
* @param pszPathname the path to the directory to create. UTF-8 encoded.
* @param mode the permissions mode.
*
* @return 0 on success or -1 on an error.
* @since GDAL 2.3
*/
int VSIMkdirRecursive(const char *pszPathname, long mode)
{
if (pszPathname == nullptr || pszPathname[0] == '\0' ||
strncmp("/", pszPathname, 2) == 0)
{
return -1;
}
const CPLString osPathname(pszPathname);
VSIStatBufL sStat;
if (VSIStatL(osPathname, &sStat) == 0)
{
return VSI_ISDIR(sStat.st_mode) ? 0 : -1;
}
const CPLString osParentPath(CPLGetPath(osPathname));
// Prevent crazy paths from recursing forever.
if (osParentPath == osPathname ||
osParentPath.length() >= osPathname.length())
{
return -1;
}
if (VSIStatL(osParentPath, &sStat) != 0)
{
if (VSIMkdirRecursive(osParentPath, mode) != 0)
return -1;
}
return VSIMkdir(osPathname, mode);
}
/************************************************************************/
/* VSIUnlink() */
/************************************************************************/
/**
* \brief Delete a file.
*
* Deletes a file object from the file system.
*
* This method goes through the VSIFileHandler virtualization and may
* work on unusual filesystems such as in memory.
*
* Analog of the POSIX unlink() function.
*
* @param pszFilename the path of the file to be deleted. UTF-8 encoded.
*
* @return 0 on success or -1 on an error.
*/
int VSIUnlink(const char *pszFilename)
{
VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
return poFSHandler->Unlink(pszFilename);
}
/************************************************************************/
/* VSIUnlinkBatch() */
/************************************************************************/
/**
* \brief Delete several files, possibly in a batch.
*
* All files should belong to the same file system handler.
*
* This is implemented efficiently for /vsis3/ and /vsigs/ (provided for /vsigs/
* that OAuth2 authentication is used).
*
* @param papszFiles NULL terminated list of files. UTF-8 encoded.
*
* @return an array of size CSLCount(papszFiles), whose values are TRUE or FALSE
* depending on the success of deletion of the corresponding file. The array
* should be freed with VSIFree().
* NULL might be return in case of a more general error (for example,
* files belonging to different file system handlers)
*
* @since GDAL 3.1
*/
int *VSIUnlinkBatch(CSLConstList papszFiles)
{
VSIFilesystemHandler *poFSHandler = nullptr;
for (CSLConstList papszIter = papszFiles; papszIter && *papszIter;
++papszIter)
{
auto poFSHandlerThisFile = VSIFileManager::GetHandler(*papszIter);
if (poFSHandler == nullptr)
poFSHandler = poFSHandlerThisFile;
else if (poFSHandler != poFSHandlerThisFile)
{
CPLError(CE_Failure, CPLE_AppDefined,
"Files belong to different file system handlers");
poFSHandler = nullptr;
break;
}
}
if (poFSHandler == nullptr)
return nullptr;
return poFSHandler->UnlinkBatch(papszFiles);
}
/************************************************************************/
/* VSIRename() */
/************************************************************************/
/**
* \brief Rename a file.
*
* Renames a file object in the file system. It should be possible
* to rename a file onto a new filesystem, but it is safest if this
* function is only used to rename files that remain in the same directory.
*
* This method goes through the VSIFileHandler virtualization and may
* work on unusual filesystems such as in memory.
*
* Analog of the POSIX rename() function.
*
* @param oldpath the name of the file to be renamed. UTF-8 encoded.
* @param newpath the name the file should be given. UTF-8 encoded.
*
* @return 0 on success or -1 on an error.
*/
int VSIRename(const char *oldpath, const char *newpath)
{
VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(oldpath);
return poFSHandler->Rename(oldpath, newpath);
}
/************************************************************************/
/* VSICopyFile() */
/************************************************************************/
/**
* \brief Copy a source file into a target file.
*
* For a /vsizip/foo.zip/bar target, the options available are those of
* CPLAddFileInZip()
*
* The following copies are made fully on the target server, without local
* download from source and upload to target:
* - /vsis3/ -> /vsis3/
* - /vsigs/ -> /vsigs/
* - /vsiaz/ -> /vsiaz/
* - /vsiadls/ -> /vsiadls/
* - any of the above or /vsicurl/ -> /vsiaz/ (starting with GDAL 3.8)
*
* @param pszSource Source filename. UTF-8 encoded. May be NULL if fpSource is
* not NULL.
* @param pszTarget Target filename. UTF-8 encoded. Must not be NULL
* @param fpSource File handle on the source file. May be NULL if pszSource is
* not NULL.
* @param nSourceSize Size of the source file. Pass -1 if unknown.
* If set to -1, and progress callback is used, VSIStatL() will be used on
* pszSource to retrieve the source size.
* @param papszOptions Null terminated list of options, or NULL.
* @param pProgressFunc Progress callback, or NULL.
* @param pProgressData User data of progress callback, or NULL.
*
* @return 0 on success.
* @since GDAL 3.7
*/
int VSICopyFile(const char *pszSource, const char *pszTarget,
VSILFILE *fpSource, vsi_l_offset nSourceSize,
const char *const *papszOptions, GDALProgressFunc pProgressFunc,
void *pProgressData)
{
if (!pszSource && !fpSource)
{
CPLError(CE_Failure, CPLE_AppDefined,
"pszSource == nullptr && fpSource == nullptr");
return -1;
}
if (!pszTarget || pszTarget[0] == '\0')
{
return -1;
}
VSIFilesystemHandler *poFSHandlerTarget =
VSIFileManager::GetHandler(pszTarget);
return poFSHandlerTarget->CopyFile(pszSource, pszTarget, fpSource,
nSourceSize, papszOptions, pProgressFunc,
pProgressData);
}
/************************************************************************/
/* VSICopyFileRestartable() */
/************************************************************************/
/**
\brief Copy a source file into a target file in a way that can (potentially)
be restarted.
This function provides the possibility of efficiently restarting upload of
large files to cloud storage that implements upload in a chunked way,
such as /vsis3/ and /vsigs/.
For other destination file systems, this function may fallback to
VSICopyFile() and not provide any smart restartable implementation.
Example of a potential workflow:
@code{.cpp}
char* pszOutputPayload = NULL;
int ret = VSICopyFileRestartable(pszSource, pszTarget, NULL,
&pszOutputPayload, NULL, NULL, NULL);
while( ret == 1 ) // add also a limiting counter to avoid potentiall endless looping
{
// TODO: wait for some time
char* pszOutputPayloadNew = NULL;
const char* pszInputPayload = pszOutputPayload;
ret = VSICopyFileRestartable(pszSource, pszTarget, pszInputPayload,
&pszOutputPayloadNew, NULL, NULL, NULL);
VSIFree(pszOutputPayload);
pszOutputPayload = pszOutputPayloadNew;
}
VSIFree(pszOutputPayload);
@endcode
@param pszSource Source filename. UTF-8 encoded. Must not be NULL
@param pszTarget Target filename. UTF-8 encoded. Must not be NULL
@param pszInputPayload NULL at the first invocation. When doing a retry,
should be the content of *ppszOutputPayload from a
previous invocation.
@param[out] ppszOutputPayload Pointer to an output string that will be set to
a value that can be provided as pszInputPayload
for a next call to VSICopyFileRestartable().
ppszOutputPayload must not be NULL.
The string set in *ppszOutputPayload, if not NULL,
is JSON-encoded, and can be re-used in another
process instance. It must be freed with VSIFree()
when no longer needed.
@param papszOptions Null terminated list of options, or NULL.
Currently accepted options are:
<ul>
<li>NUM_THREADS=integer or ALL_CPUS. Number of threads to use for parallel
file copying. Only use for when /vsis3/, /vsigs/, /vsiaz/ or /vsiadls/ is in
source or target. The default is 10.
</li>
<li>CHUNK_SIZE=integer. Maximum size of chunk (in bytes) to use
to split large objects. For upload to /vsis3/, this chunk size must be set at
least to 5 MB. The default is 50 MB.
</li>
</ul>
@param pProgressFunc Progress callback, or NULL.
@param pProgressData User data of progress callback, or NULL.
@return 0 on success,
-1 on (non-restartable) failure,
1 if VSICopyFileRestartable() can be called again in a restartable way
@since GDAL 3.10
@see VSIAbortPendingUploads()
*/
int VSICopyFileRestartable(const char *pszSource, const char *pszTarget,
const char *pszInputPayload,
char **ppszOutputPayload,
const char *const *papszOptions,
GDALProgressFunc pProgressFunc, void *pProgressData)
{
if (!pszSource)
{
return -1;
}
if (!pszTarget || pszTarget[0] == '\0')
{
return -1;
}
if (!ppszOutputPayload)
{
return -1;
}
VSIFilesystemHandler *poFSHandlerTarget =
VSIFileManager::GetHandler(pszTarget);
return poFSHandlerTarget->CopyFileRestartable(
pszSource, pszTarget, pszInputPayload, ppszOutputPayload, papszOptions,
pProgressFunc, pProgressData);
}
/************************************************************************/
/* VSISync() */
/************************************************************************/
/**
* \brief Synchronize a source file/directory with a target file/directory.
*
* This is a analog of the 'rsync' utility. In the current implementation,
* rsync would be more efficient for local file copying, but VSISync() main
* interest is when the source or target is a remote
* file system like /vsis3/ or /vsigs/, in which case it can take into account
* the timestamps of the files (or optionally the ETag/MD5Sum) to avoid
* unneeded copy operations.
*
* This is only implemented efficiently for:
* <ul>
* <li> local filesystem <--> remote filesystem.</li>
* <li> remote filesystem <--> remote filesystem (starting with GDAL 3.1).
* Where the source and target remote filesystems are the same and one of
* /vsis3/, /vsigs/ or /vsiaz/. Or when the target is /vsiaz/ and the source
* is /vsis3/, /vsigs/, /vsiadls/ or /vsicurl/ (starting with GDAL 3.8)</li>
* </ul>
*
* Similarly to rsync behavior, if the source filename ends with a slash,
* it means that the content of the directory must be copied, but not the
* directory name. For example, assuming "/home/even/foo" contains a file "bar",
* VSISync("/home/even/foo/", "/mnt/media", ...) will create a "/mnt/media/bar"
* file. Whereas VSISync("/home/even/foo", "/mnt/media", ...) will create a
* "/mnt/media/foo" directory which contains a bar file.
*
* @param pszSource Source file or directory. UTF-8 encoded.
* @param pszTarget Target file or directory. UTF-8 encoded.
* @param papszOptions Null terminated list of options, or NULL.
* Currently accepted options are:
* <ul>
* <li>RECURSIVE=NO (the default is YES)</li>
* <li>SYNC_STRATEGY=TIMESTAMP/ETAG/OVERWRITE.
*
* Determines which criterion is used to determine if a target file must be
* replaced when it already exists and has the same file size as the source.
* Only applies for a source or target being a network filesystem.
*
* The default is TIMESTAMP (similarly to how 'aws s3 sync' works), that is
* to say that for an upload operation, a remote file is
* replaced if it has a different size or if it is older than the source.
* For a download operation, a local file is replaced if it has a different
* size or if it is newer than the remote file.
*
* The ETAG strategy assumes that the ETag metadata of the remote file is
* the MD5Sum of the file content, which is only true in the case of /vsis3/
* for files not using KMS server side encryption and uploaded in a single
* PUT operation (so smaller than 50 MB given the default used by GDAL).
* Only to be used for /vsis3/, /vsigs/ or other filesystems using a
* MD5Sum as ETAG.
*
* The OVERWRITE strategy (GDAL >= 3.2) will always overwrite the target
* file with the source one.
* </li>
* <li>NUM_THREADS=integer. (GDAL >= 3.1) Number of threads to use for parallel
* file copying. Only use for when /vsis3/, /vsigs/, /vsiaz/ or /vsiadls/ is in
* source or target. The default is 10 since GDAL 3.3</li>
* <li>CHUNK_SIZE=integer. (GDAL >= 3.1) Maximum size of chunk (in bytes) to use
* to split large objects when downloading them from /vsis3/, /vsigs/, /vsiaz/
* or /vsiadls/ to local file system, or for upload to /vsis3/, /vsiaz/ or
* /vsiadls/ from local file system. Only used if NUM_THREADS > 1. For upload to
* /vsis3/, this chunk size must be set at least to 5 MB. The default is 8 MB
* since GDAL 3.3</li> <li>x-amz-KEY=value. (GDAL >= 3.5) MIME header to pass
* during creation of a /vsis3/ object.</li> <li>x-goog-KEY=value. (GDAL >= 3.5)
* MIME header to pass during creation of a /vsigs/ object.</li>
* <li>x-ms-KEY=value. (GDAL >= 3.5) MIME header to pass during creation of a
* /vsiaz/ or /vsiadls/ object.</li>
* </ul>
* @param pProgressFunc Progress callback, or NULL.
* @param pProgressData User data of progress callback, or NULL.
* @param ppapszOutputs Unused. Should be set to NULL for now.
*
* @return TRUE on success or FALSE on an error.
* @since GDAL 2.4
*/
int VSISync(const char *pszSource, const char *pszTarget,
const char *const *papszOptions, GDALProgressFunc pProgressFunc,
void *pProgressData, char ***ppapszOutputs)
{
if (pszSource[0] == '\0' || pszTarget[0] == '\0')
{
return FALSE;
}
VSIFilesystemHandler *poFSHandlerSource =
VSIFileManager::GetHandler(pszSource);
VSIFilesystemHandler *poFSHandlerTarget =
VSIFileManager::GetHandler(pszTarget);
VSIFilesystemHandler *poFSHandlerLocal = VSIFileManager::GetHandler("");
VSIFilesystemHandler *poFSHandlerMem =
VSIFileManager::GetHandler("/vsimem/");
VSIFilesystemHandler *poFSHandler = poFSHandlerSource;
if (poFSHandlerTarget != poFSHandlerLocal &&
poFSHandlerTarget != poFSHandlerMem)
{
poFSHandler = poFSHandlerTarget;
}
return poFSHandler->Sync(pszSource, pszTarget, papszOptions, pProgressFunc,
pProgressData, ppapszOutputs)
? TRUE
: FALSE;
}
/************************************************************************/
/* VSIMultipartUploadGetCapabilities() */
/************************************************************************/
/**
* \brief Return capabilities for multiple part file upload.
*
* @param pszFilename Filename, or virtual file system prefix, onto which
* capabilities should apply.
* @param[out] pbNonSequentialUploadSupported If not null,
* the pointed value is set if parts can be uploaded in a non-sequential way.
* @param[out] pbParallelUploadSupported If not null,
* the pointed value is set if parts can be uploaded in a parallel way.
* (implies *pbNonSequentialUploadSupported = true)
* @param[out] pbAbortSupported If not null,
* the pointed value is set if VSIMultipartUploadAbort() is implemented.
* @param[out] pnMinPartSize If not null, the pointed value is set to the minimum
* size of parts (but the last one), in MiB.
* @param[out] pnMaxPartSize If not null, the pointed value is set to the maximum
* size of parts, in MiB.
* @param[out] pnMaxPartCount If not null, the pointed value is set to the
* maximum number of parts that can be uploaded.
*
* @return TRUE in case of success, FALSE otherwise.
*
* @since 3.10
*/
int VSIMultipartUploadGetCapabilities(
const char *pszFilename, int *pbNonSequentialUploadSupported,
int *pbParallelUploadSupported, int *pbAbortSupported,
size_t *pnMinPartSize, size_t *pnMaxPartSize, int *pnMaxPartCount)
{
VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
return poFSHandler->MultipartUploadGetCapabilities(
pbNonSequentialUploadSupported, pbParallelUploadSupported,
pbAbortSupported, pnMinPartSize, pnMaxPartSize, pnMaxPartCount);
}
/************************************************************************/
/* VSIMultipartUploadStart() */
/************************************************************************/
/**
* \brief Initiates the upload a (big) file in a piece-wise way.
*
* Using this API directly is generally not needed, but in very advanced cases,
* as VSIFOpenL(..., "wb") + VSIFWriteL(), VSISync(), VSICopyFile() or
* VSICopyFileRestartable() may be able to leverage it when needed.
*
* This is only implemented for the /vsis3/, /vsigs/, /vsiaz/, /vsiadls/ and
* /vsioss/ virtual file systems.
*
* The typical workflow is to do :
* - VSIMultipartUploadStart()
* - VSIMultipartUploadAddPart(): several times
* - VSIMultipartUploadEnd()
*
* If VSIMultipartUploadAbort() is supported by the filesystem (VSIMultipartUploadGetCapabilities()
* can be used to determine it), this function should be called to cancel an
* upload. This can be needed to avoid extra billing for some cloud storage
* providers.
*
* The following options are supported:
* <ul>
* <li>MIME headers such as Content-Type and Content-Encoding
* are supported for the /vsis3/, /vsigs/, /vsiaz/, /vsiadls/ file systems.</li>
* </ul>
*
* @param pszFilename Filename to create
* @param papszOptions NULL or null-terminated list of options.
* @return an upload ID to pass to other VSIMultipartUploadXXXXX() functions,
* and to free with CPLFree() once done, or nullptr in case of error.
*
* @since 3.10
*/
char *VSIMultipartUploadStart(const char *pszFilename,
CSLConstList papszOptions)
{
VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
return poFSHandler->MultipartUploadStart(pszFilename, papszOptions);
}
/************************************************************************/
/* VSIMultipartUploadAddPart() */
/************************************************************************/
/**
* \brief Uploads a new part to a multi-part uploaded file.
*
* Cf VSIMultipartUploadStart().
*
* VSIMultipartUploadGetCapabilities() returns hints on the constraints that
* apply to the upload, in terms of minimum/maximum size of each part, maximum
* number of parts, and whether non-sequential or parallel uploads are
* supported.
*
* @param pszFilename Filename to which to append the new part. Should be the
* same as the one used for VSIMultipartUploadStart()
* @param pszUploadId Value returned by VSIMultipartUploadStart()
* @param nPartNumber Part number, starting at 1.
* @param nFileOffset Offset within the file at which (starts at 0) the passed
* data starts.
* @param pData Pointer to an array of nDataLength bytes.
* @param nDataLength Size in bytes of pData.
* @param papszOptions Unused. Should be nullptr.
*
* @return a part identifier that must be passed into the apszPartIds[] array of
* VSIMultipartUploadEnd(), and to free with CPLFree() once done, or nullptr in
* case of error.
*
* @since 3.10
*/
char *VSIMultipartUploadAddPart(const char *pszFilename,
const char *pszUploadId, int nPartNumber,
vsi_l_offset nFileOffset, const void *pData,
size_t nDataLength, CSLConstList papszOptions)
{
VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
return poFSHandler->MultipartUploadAddPart(pszFilename, pszUploadId,
nPartNumber, nFileOffset, pData,
nDataLength, papszOptions);
}
/************************************************************************/
/* VSIMultipartUploadEnd() */
/************************************************************************/
/**
* \brief Completes a multi-part file upload.
*
* Cf VSIMultipartUploadStart().
*
* @param pszFilename Filename for which multipart upload should be completed.
* Should be the same as the one used for
* VSIMultipartUploadStart()
* @param pszUploadId Value returned by VSIMultipartUploadStart()
* @param nPartIdsCount Number of parts, andsize of apszPartIds
* @param apszPartIds Array of part identifiers (as returned by
* VSIMultipartUploadAddPart()), that must be ordered in
* the sequential order of parts, and of size nPartIdsCount.
* @param nTotalSize Total size of the file in bytes (must be equal to the sum
* of nDataLength passed to VSIMultipartUploadAddPart())
* @param papszOptions Unused. Should be nullptr.
*
* @return TRUE in case of success, FALSE in case of failure.
*
* @since 3.10
*/
int VSIMultipartUploadEnd(const char *pszFilename, const char *pszUploadId,
size_t nPartIdsCount, const char *const *apszPartIds,
vsi_l_offset nTotalSize, CSLConstList papszOptions)
{
VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
return poFSHandler->MultipartUploadEnd(pszFilename, pszUploadId,
nPartIdsCount, apszPartIds,
nTotalSize, papszOptions);
}
/************************************************************************/
/* VSIMultipartUploadAbort() */
/************************************************************************/
/**
* \brief Aborts a multi-part file upload.
*
* Cf VSIMultipartUploadStart().
*
* This function is not implemented for all virtual file systems.
* Use VSIMultipartUploadGetCapabilities() to determine if it is supported.
*
* This can be needed to avoid extra billing for some cloud storage providers.
*
* @param pszFilename Filename for which multipart upload should be completed.
* Should be the same as the one used for
* VSIMultipartUploadStart()
* @param pszUploadId Value returned by VSIMultipartUploadStart()
* @param papszOptions Unused. Should be nullptr.
*
* @return TRUE in case of success, FALSE in case of failure.
*
* @since 3.10
*/
int VSIMultipartUploadAbort(const char *pszFilename, const char *pszUploadId,
CSLConstList papszOptions)
{
VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename);
return poFSHandler->MultipartUploadAbort(pszFilename, pszUploadId,
papszOptions);
}
#ifndef DOXYGEN_SKIP
/************************************************************************/
/* MultipartUploadGetCapabilities() */
/************************************************************************/
bool VSIFilesystemHandler::MultipartUploadGetCapabilities(int *, int *, int *,
size_t *, size_t *,
int *)
{
CPLError(
CE_Failure, CPLE_NotSupported,
"MultipartUploadGetCapabilities() not supported by this file system");
return false;
}
/************************************************************************/
/* MultipartUploadStart() */
/************************************************************************/
char *VSIFilesystemHandler::MultipartUploadStart(const char *, CSLConstList)
{
CPLError(CE_Failure, CPLE_NotSupported,
"MultipartUploadStart() not supported by this file system");
return nullptr;