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  * Permission is hereby granted, free of charge, to any person obtaining a
13  * copy of this software and associated documentation files (the "Software"),
14  * to deal in the Software without restriction, including without limitation
15  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16  * and/or sell copies of the Software, and to permit persons to whom the
17  * Software is furnished to do so, subject to the following conditions:
18  *
19  * The above copyright notice and this permission notice shall be included
20  * in all copies or substantial portions of the Software.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28  * DEALINGS IN THE SOFTWARE.
29  ****************************************************************************/
30 
31 #include "cpl_port.h"
32 #include "cpl_vsi.h"
33 
34 #include <cassert>
35 #include <cstdarg>
36 #include <cstddef>
37 #include <cstring>
38 #if HAVE_FCNTL_H
39 #include <fcntl.h>
40 #endif
41 
42 #include <algorithm>
43 #include <limits>
44 #include <map>
45 #include <memory>
46 #include <set>
47 #include <string>
48 #include <utility>
49 #include <vector>
50 
51 #include "cpl_conv.h"
52 #include "cpl_error.h"
53 #include "cpl_multiproc.h"
54 #include "cpl_string.h"
55 #include "cpl_vsi_virtual.h"
56 
57 
58 CPL_CVSID("$Id: cpl_vsil.cpp fa752ad6eabafaf630a704e1892a9d837d683cb3 2021-03-06 17:04:38 +0100 Even Rouault $")
59 
60 /************************************************************************/
61 /*                             VSIReadDir()                             */
62 /************************************************************************/
63 
64 /**
65  * \brief Read names in a directory.
66  *
67  * This function abstracts access to directory contains.  It returns a
68  * list of strings containing the names of files, and directories in this
69  * directory.  The resulting string list becomes the responsibility of the
70  * application and should be freed with CSLDestroy() when no longer needed.
71  *
72  * Note that no error is issued via CPLError() if the directory path is
73  * invalid, though NULL is returned.
74  *
75  * This function used to be known as CPLReadDir(), but the old name is now
76  * deprecated.
77  *
78  * @param pszPath the relative, or absolute path of a directory to read.
79  * UTF-8 encoded.
80  * @return The list of entries in the directory, or NULL if the directory
81  * doesn't exist.  Filenames are returned in UTF-8 encoding.
82  */
83 
VSIReadDir(const char * pszPath)84 char **VSIReadDir( const char *pszPath )
85 {
86     return VSIReadDirEx(pszPath, 0);
87 }
88 
89 /************************************************************************/
90 /*                             VSIReadDirEx()                           */
91 /************************************************************************/
92 
93 /**
94  * \brief Read names in a directory.
95  *
96  * This function abstracts access to directory contains.  It returns a
97  * list of strings containing the names of files, and directories in this
98  * directory.  The resulting string list becomes the responsibility of the
99  * application and should be freed with CSLDestroy() when no longer needed.
100  *
101  * Note that no error is issued via CPLError() if the directory path is
102  * invalid, though NULL is returned.
103  *
104  * If nMaxFiles is set to a positive number, directory listing will stop after
105  * that limit has been reached. Note that to indicate truncate, at least one
106  * element more than the nMaxFiles limit will be returned. If CSLCount() on the
107  * result is lesser or equal to nMaxFiles, then no truncation occurred.
108  *
109  * @param pszPath the relative, or absolute path of a directory to read.
110  * UTF-8 encoded.
111  * @param nMaxFiles maximum number of files after which to stop, or 0 for no
112  * limit.
113  * @return The list of entries in the directory, or NULL if the directory
114  * doesn't exist.  Filenames are returned in UTF-8 encoding.
115  * @since GDAL 2.1
116  */
117 
VSIReadDirEx(const char * pszPath,int nMaxFiles)118 char **VSIReadDirEx( const char *pszPath, int nMaxFiles )
119 {
120     VSIFilesystemHandler *poFSHandler =
121         VSIFileManager::GetHandler( pszPath );
122 
123     return poFSHandler->ReadDirEx( pszPath, nMaxFiles );
124 }
125 
126 /************************************************************************/
127 /*                             VSISiblingFiles()                        */
128 /************************************************************************/
129 
130 /**
131  * \brief Return related filenames
132   *
133   * This function is essentially meant at being used by GDAL internals.
134  *
135  * @param pszFilename the path of a filename to inspect
136  * UTF-8 encoded.
137  * @return The list of entries, relative to the directory, of all sidecar
138  * files available or NULL if the list is not known.
139  * Filenames are returned in UTF-8 encoding.
140  * Most implementations will return NULL, and a subsequent ReadDir will
141  * list all files available in the file's directory. This function will be
142  * overridden by VSI FilesystemHandlers that wish to force e.g. an empty list
143  * to avoid opening non-existent files on slow filesystems. The return value shall be destroyed with CSLDestroy()
144  * @since GDAL 3.2
145  */
VSISiblingFiles(const char * pszFilename)146 char **VSISiblingFiles( const char *pszFilename)
147 {
148     VSIFilesystemHandler *poFSHandler =
149         VSIFileManager::GetHandler( pszFilename );
150 
151     return poFSHandler->SiblingFiles( pszFilename );
152 }
153 
154 /************************************************************************/
155 /*                             VSIReadRecursive()                       */
156 /************************************************************************/
157 
158 typedef struct
159 {
160     char **papszFiles;
161     int nCount;
162     int i;
163     char* pszPath;
164     char* pszDisplayedPath;
165 } VSIReadDirRecursiveTask;
166 
167 /**
168  * \brief Read names in a directory recursively.
169  *
170  * This function abstracts access to directory contents and subdirectories.
171  * It returns a list of strings containing the names of files and directories
172  * in this directory and all subdirectories.  The resulting string list becomes
173  * the responsibility of the application and should be freed with CSLDestroy()
174  *  when no longer needed.
175  *
176  * Note that no error is issued via CPLError() if the directory path is
177  * invalid, though NULL is returned.
178  *
179  * @param pszPathIn the relative, or absolute path of a directory to read.
180  * UTF-8 encoded.
181  *
182  * @return The list of entries in the directory and subdirectories
183  * or NULL if the directory doesn't exist.  Filenames are returned in UTF-8
184  * encoding.
185  * @since GDAL 1.10.0
186  *
187  */
188 
VSIReadDirRecursive(const char * pszPathIn)189 char **VSIReadDirRecursive( const char *pszPathIn )
190 {
191     CPLStringList oFiles;
192     char **papszFiles = nullptr;
193     VSIStatBufL psStatBuf;
194     CPLString osTemp1;
195     CPLString osTemp2;
196     int i = 0;
197     int nCount = -1;
198 
199     std::vector<VSIReadDirRecursiveTask> aoStack;
200     char* pszPath = CPLStrdup(pszPathIn);
201     char* pszDisplayedPath = nullptr;
202 
203     while( true )
204     {
205         if( nCount < 0 )
206         {
207             // Get listing.
208             papszFiles = VSIReadDir( pszPath );
209 
210             // Get files and directories inside listing.
211             nCount = papszFiles ? CSLCount( papszFiles ) : 0;
212             i = 0;
213         }
214 
215         for( ; i < nCount; i++ )
216         {
217             // Do not recurse up the tree.
218             if( EQUAL(".", papszFiles[i]) || EQUAL("..", papszFiles[i]) )
219               continue;
220 
221             // Build complete file name for stat.
222             osTemp1.clear();
223             osTemp1.append( pszPath );
224             if( !osTemp1.empty() && osTemp1.back() != '/' )
225                 osTemp1.append( "/" );
226             osTemp1.append( papszFiles[i] );
227 
228             // If is file, add it.
229             if( VSIStatL( osTemp1.c_str(), &psStatBuf ) != 0 )
230                 continue;
231 
232             if( VSI_ISREG( psStatBuf.st_mode ) )
233             {
234                 if( pszDisplayedPath )
235                 {
236                     osTemp1.clear();
237                     osTemp1.append( pszDisplayedPath );
238                     if( !osTemp1.empty() && osTemp1.back() != '/' )
239                         osTemp1.append( "/" );
240                     osTemp1.append( papszFiles[i] );
241                     oFiles.AddString( osTemp1 );
242                 }
243                 else
244                     oFiles.AddString( papszFiles[i] );
245             }
246             else if( VSI_ISDIR( psStatBuf.st_mode ) )
247             {
248                 // Add directory entry.
249                 osTemp2.clear();
250                 if( pszDisplayedPath )
251                 {
252                     osTemp2.append( pszDisplayedPath );
253                     osTemp2.append( "/" );
254                 }
255                 osTemp2.append( papszFiles[i] );
256                 if( !osTemp2.empty() && osTemp2.back() != '/' )
257                     osTemp2.append( "/" );
258                 oFiles.AddString( osTemp2.c_str() );
259 
260                 VSIReadDirRecursiveTask sTask;
261                 sTask.papszFiles = papszFiles;
262                 sTask.nCount = nCount;
263                 sTask.i = i;
264                 sTask.pszPath = CPLStrdup(pszPath);
265                 sTask.pszDisplayedPath =
266                     pszDisplayedPath ? CPLStrdup(pszDisplayedPath) : nullptr;
267                 aoStack.push_back(sTask);
268 
269                 CPLFree(pszPath);
270                 pszPath = CPLStrdup( osTemp1.c_str() );
271 
272                 char* pszDisplayedPathNew = nullptr;
273                 if( pszDisplayedPath )
274                 {
275                     pszDisplayedPathNew =
276                         CPLStrdup(
277                             CPLSPrintf("%s/%s",
278                                        pszDisplayedPath, papszFiles[i]));
279                 }
280                 else
281                 {
282                     pszDisplayedPathNew = CPLStrdup( papszFiles[i] );
283                 }
284                 CPLFree(pszDisplayedPath);
285                 pszDisplayedPath = pszDisplayedPathNew;
286 
287                 i = 0;
288                 papszFiles = nullptr;
289                 nCount = -1;
290 
291                 break;
292             }
293         }
294 
295         if( nCount >= 0 )
296         {
297             CSLDestroy( papszFiles );
298 
299             if( !aoStack.empty() )
300             {
301                 const int iLast = static_cast<int>(aoStack.size()) - 1;
302                 CPLFree(pszPath);
303                 CPLFree(pszDisplayedPath);
304                 nCount = aoStack[iLast].nCount;
305                 papszFiles = aoStack[iLast].papszFiles;
306                 i = aoStack[iLast].i + 1;
307                 pszPath = aoStack[iLast].pszPath;
308                 pszDisplayedPath = aoStack[iLast].pszDisplayedPath;
309 
310                 aoStack.resize(iLast);
311             }
312             else
313             {
314                 break;
315             }
316         }
317     }
318 
319     CPLFree(pszPath);
320     CPLFree(pszDisplayedPath);
321 
322     return oFiles.StealList();
323 }
324 
325 /************************************************************************/
326 /*                             CPLReadDir()                             */
327 /*                                                                      */
328 /*      This is present only to provide ABI compatibility with older    */
329 /*      versions.                                                       */
330 /************************************************************************/
331 #undef CPLReadDir
332 
333 CPL_C_START
334 char CPL_DLL **CPLReadDir( const char *pszPath );
335 CPL_C_END
336 
CPLReadDir(const char * pszPath)337 char **CPLReadDir( const char *pszPath )
338 {
339     return VSIReadDir( pszPath );
340 }
341 
342 /************************************************************************/
343 /*                             VSIOpenDir()                             */
344 /************************************************************************/
345 
346 /**
347  * \brief Open a directory to read its entries.
348  *
349  * This function is close to the POSIX opendir() function.
350  *
351  * For /vsis3/, /vsigs/, /vsioss/, /vsiaz/ and /vsiadls/, this function has an efficient
352  * implementation, minimizing the number of network requests, when invoked with
353  * nRecurseDepth <= 0.
354  *
355  * Entries are read by calling VSIGetNextDirEntry() on the handled returned by
356  * that function, until it returns NULL. VSICloseDir() must be called once done
357  * with the returned directory handle.
358  *
359  * @param pszPath the relative, or absolute path of a directory to read.
360  * UTF-8 encoded.
361  * @param nRecurseDepth 0 means do not recurse in subdirectories, 1 means
362  * recurse only in the first level of subdirectories, etc. -1 means unlimited
363  * recursion level
364  * @param papszOptions NULL terminated list of options, or NULL.
365  *
366  * @return a handle, or NULL in case of error
367  * @since GDAL 2.4
368  *
369  */
370 
VSIOpenDir(const char * pszPath,int nRecurseDepth,const char * const * papszOptions)371 VSIDIR *VSIOpenDir( const char *pszPath,
372                     int nRecurseDepth,
373                     const char* const *papszOptions)
374 {
375     VSIFilesystemHandler *poFSHandler =
376         VSIFileManager::GetHandler( pszPath );
377 
378     return poFSHandler->OpenDir( pszPath, nRecurseDepth, papszOptions );
379 }
380 
381 /************************************************************************/
382 /*                          VSIGetNextDirEntry()                        */
383 /************************************************************************/
384 
385 /**
386  * \brief Return the next entry of the directory
387  *
388  * This function is close to the POSIX readdir() function. It actually returns
389  * more information (file size, last modification time), which on 'real' file
390  * systems involve one 'stat' call per file.
391  *
392  * For filesystems that can have both a regular file and a directory name of
393  * the same name (typically /vsis3/), when this situation of duplicate happens,
394  * the directory name will be suffixed by a slash character. Otherwise directory
395  * names are not suffixed by slash.
396  *
397  * The returned entry remains valid until the next call to VSINextDirEntry()
398  * or VSICloseDir() with the same handle.
399  *
400  * @param dir Directory handled returned by VSIOpenDir(). Must not be NULL.
401  *
402  * @return a entry, or NULL if there is no more entry in the directory. This
403  * return value must not be freed.
404  * @since GDAL 2.4
405  *
406  */
407 
VSIGetNextDirEntry(VSIDIR * dir)408 const VSIDIREntry *VSIGetNextDirEntry(VSIDIR* dir)
409 {
410     return dir->NextDirEntry();
411 }
412 
413 /************************************************************************/
414 /*                             VSICloseDir()                            */
415 /************************************************************************/
416 
417 /**
418  * \brief Close a directory
419  *
420  * This function is close to the POSIX closedir() function.
421  *
422  * @param dir Directory handled returned by VSIOpenDir().
423  *
424  * @since GDAL 2.4
425  */
426 
VSICloseDir(VSIDIR * dir)427 void VSICloseDir(VSIDIR* dir)
428 {
429     delete dir;
430 }
431 
432 /************************************************************************/
433 /*                              VSIMkdir()                              */
434 /************************************************************************/
435 
436 /**
437  * \brief Create a directory.
438  *
439  * Create a new directory with the indicated mode. For POSIX-style systems,
440  * the mode is modified by the file creation mask (umask). However, some
441  * file systems and platforms may not use umask, or they may ignore the mode
442  * completely. So a reasonable cross-platform default mode value is 0755.
443  *
444  * Analog of the POSIX mkdir() function.
445  *
446  * @param pszPathname the path to the directory to create. UTF-8 encoded.
447  * @param mode the permissions mode.
448  *
449  * @return 0 on success or -1 on an error.
450  */
451 
VSIMkdir(const char * pszPathname,long mode)452 int VSIMkdir( const char *pszPathname, long mode )
453 
454 {
455     VSIFilesystemHandler *poFSHandler =
456         VSIFileManager::GetHandler( pszPathname );
457 
458     return poFSHandler->Mkdir( pszPathname, mode );
459 }
460 
461 /************************************************************************/
462 /*                       VSIMkdirRecursive()                            */
463 /************************************************************************/
464 
465 /**
466  * \brief Create a directory and all its ancestors
467  *
468  * @param pszPathname the path to the directory to create. UTF-8 encoded.
469  * @param mode the permissions mode.
470  *
471  * @return 0 on success or -1 on an error.
472  * @since GDAL 2.3
473  */
474 
VSIMkdirRecursive(const char * pszPathname,long mode)475 int VSIMkdirRecursive( const char *pszPathname, long mode )
476 {
477     if( pszPathname == nullptr || pszPathname[0] == '\0' ||
478         strncmp("/", pszPathname, 2) == 0 )
479     {
480         return -1;
481     }
482 
483     const CPLString osPathname(pszPathname);
484     VSIStatBufL sStat;
485     if( VSIStatL(osPathname, &sStat) == 0 &&
486         VSI_ISDIR(sStat.st_mode) )
487     {
488         return 0;
489     }
490     const CPLString osParentPath(CPLGetPath(osPathname));
491 
492     // Prevent crazy paths from recursing forever.
493     if( osParentPath == osPathname ||
494         osParentPath.length() >= osPathname.length() )
495     {
496         return -1;
497     }
498 
499     if( VSIStatL(osParentPath, &sStat) != 0 )
500     {
501         if( VSIMkdirRecursive(osParentPath, mode) != 0 )
502             return -1;
503     }
504 
505     return VSIMkdir(osPathname, mode);
506 }
507 
508 /************************************************************************/
509 /*                             VSIUnlink()                              */
510 /************************************************************************/
511 
512 /**
513  * \brief Delete a file.
514  *
515  * Deletes a file object from the file system.
516  *
517  * This method goes through the VSIFileHandler virtualization and may
518  * work on unusual filesystems such as in memory.
519  *
520  * Analog of the POSIX unlink() function.
521  *
522  * @param pszFilename the path of the file to be deleted. UTF-8 encoded.
523  *
524  * @return 0 on success or -1 on an error.
525  */
526 
VSIUnlink(const char * pszFilename)527 int VSIUnlink( const char * pszFilename )
528 
529 {
530     VSIFilesystemHandler *poFSHandler =
531         VSIFileManager::GetHandler( pszFilename );
532 
533     return poFSHandler->Unlink( pszFilename );
534 }
535 
536 /************************************************************************/
537 /*                           VSIUnlinkBatch()                           */
538 /************************************************************************/
539 
540 /**
541  * \brief Delete several files, possibly in a batch.
542  *
543  * All files should belong to the same file system handler.
544  *
545  * @param papszFiles NULL terminated list of files. UTF-8 encoded.
546  *
547  * @return an array of size CSLCount(papszFiles), whose values are TRUE or FALSE
548  * depending on the success of deletion of the corresponding file. The array
549  * should be freed with VSIFree().
550  * NULL might be return in case of a more general error (for example,
551  * files belonging to different file system handlers)
552  *
553  * @since GDAL 3.1
554  */
555 
VSIUnlinkBatch(CSLConstList papszFiles)556 int *VSIUnlinkBatch( CSLConstList papszFiles )
557 {
558     VSIFilesystemHandler *poFSHandler = nullptr;
559     for( CSLConstList papszIter = papszFiles;
560             papszIter && *papszIter; ++papszIter )
561     {
562         auto poFSHandlerThisFile = VSIFileManager::GetHandler( *papszIter );
563         if( poFSHandler == nullptr )
564             poFSHandler = poFSHandlerThisFile;
565         else if( poFSHandler != poFSHandlerThisFile )
566         {
567             CPLError(CE_Failure, CPLE_AppDefined,
568                      "Files belong to different file system handlers");
569             poFSHandler = nullptr;
570             break;
571         }
572     }
573     if( poFSHandler == nullptr )
574         return nullptr;
575     return poFSHandler->UnlinkBatch(papszFiles);
576 }
577 
578 /************************************************************************/
579 /*                             VSIRename()                              */
580 /************************************************************************/
581 
582 /**
583  * \brief Rename a file.
584  *
585  * Renames a file object in the file system.  It should be possible
586  * to rename a file onto a new filesystem, but it is safest if this
587  * function is only used to rename files that remain in the same directory.
588  *
589  * This method goes through the VSIFileHandler virtualization and may
590  * work on unusual filesystems such as in memory.
591  *
592  * Analog of the POSIX rename() function.
593  *
594  * @param oldpath the name of the file to be renamed.  UTF-8 encoded.
595  * @param newpath the name the file should be given.  UTF-8 encoded.
596  *
597  * @return 0 on success or -1 on an error.
598  */
599 
VSIRename(const char * oldpath,const char * newpath)600 int VSIRename( const char * oldpath, const char * newpath )
601 
602 {
603     VSIFilesystemHandler *poFSHandler =
604         VSIFileManager::GetHandler( oldpath );
605 
606     return poFSHandler->Rename( oldpath, newpath );
607 }
608 
609 /************************************************************************/
610 /*                             VSISync()                                */
611 /************************************************************************/
612 
613 /**
614  * \brief Synchronize a source file/directory with a target file/directory.
615  *
616  * This is a analog of the 'rsync' utility. In the current implementation,
617  * rsync would be more efficient for local file copying, but VSISync() main
618  * interest is when the source or target is a remote
619  * file system like /vsis3/ or /vsigs/, in which case it can take into account
620  * the timestamps of the files (or optionally the ETag/MD5Sum) to avoid
621  * unneeded copy operations.
622  *
623  * This is only implemented efficiently for:
624  * <ul>
625  * <li> local filesystem <--> remote filesystem.</li>
626  * <li> remote filesystem <--> remote filesystem (starting with GDAL 3.1).
627  * Where the source and target remote filesystems are the same and one of
628  * /vsis3/, /vsigs/ or /vsiaz/</li>
629  * </ul>
630  *
631  * Similarly to rsync behavior, if the source filename ends with a slash,
632  * it means that the content of the directory must be copied, but not the
633  * directory name. For example, assuming "/home/even/foo" contains a file "bar",
634  * VSISync("/home/even/foo/", "/mnt/media", ...) will create a "/mnt/media/bar"
635  * file. Whereas VSISync("/home/even/foo", "/mnt/media", ...) will create a
636  * "/mnt/media/foo" directory which contains a bar file.
637  *
638  * @param pszSource Source file or directory.  UTF-8 encoded.
639  * @param pszTarget Target file or directory.  UTF-8 encoded.
640  * @param papszOptions Null terminated list of options, or NULL.
641  * Currently accepted options are:
642  * <ul>
643  * <li>RECURSIVE=NO (the default is YES)</li>
644  * <li>SYNC_STRATEGY=TIMESTAMP/ETAG/OVERWRITE. Determines which criterion is used to
645  *     determine if a target file must be replaced when it already exists and
646  *     has the same file size as the source.
647  *     Only applies for a source or target being a network filesystem.
648  *
649  *     The default is TIMESTAMP (similarly to how 'aws s3 sync' works), that is
650  *     to say that for an upload operation, a remote file is
651  *     replaced if it has a different size or if it is older than the source.
652  *     For a download operation, a local file is  replaced if it has a different
653  *     size or if it is newer than the remote file.
654  *
655  *     The ETAG strategy assumes that the ETag metadata of the remote file is
656  *     the MD5Sum of the file content, which is only true in the case of /vsis3/
657  *     for files not using KMS server side encryption and uploaded in a single
658  *     PUT operation (so smaller than 50 MB given the default used by GDAL).
659  *     Only to be used for /vsis3/, /vsigs/ or other filesystems using a
660  *     MD5Sum as ETAG.
661  *
662  *     The OVERWRITE strategy (GDAL >= 3.2) will always overwrite the target file
663  *     with the source one.
664  * </li>
665  * <li>NUM_THREADS=integer. (GDAL >= 3.1) Number of threads to use for parallel file copying.
666  *     Only use for when /vsis3/, /vsigs/, /vsiaz/ or /vsiadls/ is in source or target.
667  *     The default is 10 since GDAL 3.3</li>
668  * <li>CHUNK_SIZE=integer. (GDAL >= 3.1) Maximum size of chunk (in bytes) to use to split
669  *     large objects when downloading them from /vsis3/, /vsigs/, /vsiaz/ or /vsiadls/ to
670  *     local file system, or for upload to /vsis3/, /vsiaz/ or /vsiadls/ from local file system.
671  *     Only used if NUM_THREADS > 1.
672  *     For upload to /vsis3/, this chunk size must be set at least to 5 MB.
673  *     The default is 8 MB since GDAL 3.3</li>
674  * </ul>
675  * @param pProgressFunc Progress callback, or NULL.
676  * @param pProgressData User data of progress callback, or NULL.
677  * @param ppapszOutputs Unused. Should be set to NULL for now.
678  *
679  * @return TRUE on success or FALSE on an error.
680  * @since GDAL 2.4
681  */
682 
VSISync(const char * pszSource,const char * pszTarget,const char * const * papszOptions,GDALProgressFunc pProgressFunc,void * pProgressData,char *** ppapszOutputs)683 int VSISync( const char* pszSource, const char* pszTarget,
684               const char* const * papszOptions,
685               GDALProgressFunc pProgressFunc,
686               void *pProgressData,
687               char*** ppapszOutputs  )
688 
689 {
690     if( pszSource[0] == '\0' || pszTarget[0] == '\0' )
691     {
692         return FALSE;
693     }
694 
695     VSIFilesystemHandler *poFSHandlerSource =
696         VSIFileManager::GetHandler( pszSource );
697     VSIFilesystemHandler *poFSHandlerTarget =
698         VSIFileManager::GetHandler( pszTarget );
699     VSIFilesystemHandler *poFSHandlerLocal =
700         VSIFileManager::GetHandler( "" );
701     VSIFilesystemHandler *poFSHandlerMem =
702         VSIFileManager::GetHandler( "/vsimem/" );
703     VSIFilesystemHandler* poFSHandler = poFSHandlerSource;
704     if( poFSHandlerTarget != poFSHandlerLocal &&
705         poFSHandlerTarget != poFSHandlerMem )
706     {
707         poFSHandler = poFSHandlerTarget;
708     }
709 
710     return poFSHandler->Sync( pszSource, pszTarget, papszOptions,
711                                pProgressFunc, pProgressData, ppapszOutputs ) ?
712                 TRUE : FALSE;
713 }
714 
715 /************************************************************************/
716 /*                              VSIRmdir()                              */
717 /************************************************************************/
718 
719 /**
720  * \brief Delete a directory.
721  *
722  * Deletes a directory object from the file system.  On some systems
723  * the directory must be empty before it can be deleted.
724  *
725  * This method goes through the VSIFileHandler virtualization and may
726  * work on unusual filesystems such as in memory.
727  *
728  * Analog of the POSIX rmdir() function.
729  *
730  * @param pszDirname the path of the directory to be deleted.  UTF-8 encoded.
731  *
732  * @return 0 on success or -1 on an error.
733  */
734 
VSIRmdir(const char * pszDirname)735 int VSIRmdir( const char * pszDirname )
736 
737 {
738     VSIFilesystemHandler *poFSHandler =
739         VSIFileManager::GetHandler( pszDirname );
740 
741     return poFSHandler->Rmdir( pszDirname );
742 }
743 
744 /************************************************************************/
745 /*                         VSIRmdirRecursive()                          */
746 /************************************************************************/
747 
748 /**
749  * \brief Delete a directory recursively
750  *
751  * Deletes a directory object and its content from the file system.
752  *
753  * Starting with GDAL 3.1, /vsis3/ has an efficient implementation of this
754  * function.
755  *
756  * @return 0 on success or -1 on an error.
757  * @since GDAL 2.3
758  */
759 
VSIRmdirRecursive(const char * pszDirname)760 int VSIRmdirRecursive( const char* pszDirname )
761 {
762     if( pszDirname == nullptr || pszDirname[0] == '\0' ||
763         strncmp("/", pszDirname, 2) == 0 )
764     {
765         return -1;
766     }
767     VSIFilesystemHandler *poFSHandler =
768         VSIFileManager::GetHandler( pszDirname );
769     return poFSHandler->RmdirRecursive( pszDirname );
770 }
771 
772 /************************************************************************/
773 /*                              VSIStatL()                              */
774 /************************************************************************/
775 
776 /**
777  * \brief Get filesystem object info.
778  *
779  * Fetches status information about a filesystem object (file, directory, etc).
780  * The returned information is placed in the VSIStatBufL structure.   For
781  * portability, only use the st_size (size in bytes) and st_mode (file type).
782  * This method is similar to VSIStat(), but will work on large files on
783  * systems where this requires special calls.
784  *
785  * This method goes through the VSIFileHandler virtualization and may
786  * work on unusual filesystems such as in memory.
787  *
788  * Analog of the POSIX stat() function.
789  *
790  * @param pszFilename the path of the filesystem object to be queried.
791  * UTF-8 encoded.
792  * @param psStatBuf the structure to load with information.
793  *
794  * @return 0 on success or -1 on an error.
795  */
796 
VSIStatL(const char * pszFilename,VSIStatBufL * psStatBuf)797 int VSIStatL( const char * pszFilename, VSIStatBufL *psStatBuf )
798 
799 {
800     return VSIStatExL(pszFilename, psStatBuf, 0);
801 }
802 
803 /************************************************************************/
804 /*                            VSIStatExL()                              */
805 /************************************************************************/
806 
807 /**
808  * \brief Get filesystem object info.
809  *
810  * Fetches status information about a filesystem object (file, directory, etc).
811  * The returned information is placed in the VSIStatBufL structure.   For
812  * portability, only use the st_size (size in bytes) and st_mode (file type).
813  * This method is similar to VSIStat(), but will work on large files on
814  * systems where this requires special calls.
815  *
816  * This method goes through the VSIFileHandler virtualization and may
817  * work on unusual filesystems such as in memory.
818  *
819  * Analog of the POSIX stat() function, with an extra parameter to
820  * specify which information is needed, which offers a potential for
821  * speed optimizations on specialized and potentially slow virtual
822  * filesystem objects (/vsigzip/, /vsicurl/)
823  *
824  * @param pszFilename the path of the filesystem object to be queried.
825  * UTF-8 encoded.
826  * @param psStatBuf the structure to load with information.
827  * @param nFlags 0 to get all information, or VSI_STAT_EXISTS_FLAG,
828  *                  VSI_STAT_NATURE_FLAG or VSI_STAT_SIZE_FLAG, or a
829  *                  combination of those to get partial info.
830  *
831  * @return 0 on success or -1 on an error.
832  *
833  * @since GDAL 1.8.0
834  */
835 
VSIStatExL(const char * pszFilename,VSIStatBufL * psStatBuf,int nFlags)836 int VSIStatExL( const char * pszFilename, VSIStatBufL *psStatBuf, int nFlags )
837 
838 {
839     char szAltPath[4] = { '\0' };
840 
841     // Enable to work on "C:" as if it were "C:\".
842     if( pszFilename[0] != '\0' && pszFilename[1] == ':' &&
843         pszFilename[2] == '\0' )
844     {
845         szAltPath[0] = pszFilename[0];
846         szAltPath[1] = pszFilename[1];
847         szAltPath[2] = '\\';
848         szAltPath[3] = '\0';
849 
850         pszFilename = szAltPath;
851     }
852 
853     VSIFilesystemHandler *poFSHandler =
854         VSIFileManager::GetHandler( pszFilename );
855 
856     if( nFlags == 0 )
857         nFlags = VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG |
858             VSI_STAT_SIZE_FLAG;
859 
860     return poFSHandler->Stat( pszFilename, psStatBuf, nFlags );
861 }
862 
863 
864 /************************************************************************/
865 /*                       VSIGetFileMetadata()                           */
866 /************************************************************************/
867 
868 /**
869  * \brief Get metadata on files.
870  *
871  * Implemented currently only for network-like filesystems.
872  *
873  * @param pszFilename the path of the filesystem object to be queried.
874  * UTF-8 encoded.
875  * @param pszDomain Metadata domain to query. Depends on the file system.
876  * The following are supported:
877  * <ul>
878  * <li>HEADERS: to get HTTP headers for network-like filesystems (/vsicurl/, /vsis3/, etc)</li>
879  * <li>TAGS:
880  *    <ul>
881  *      <li>/vsis3/: to get S3 Object tagging information</li>
882  *      <li>/vsiaz/: to get blob tags. Refer to https://docs.microsoft.com/en-us/rest/api/storageservices/get-blob-tags</li>
883  *    </ul>
884  * </li>
885  * <li>STATUS: specific to /vsiadls/: returns all system defined properties for a path (seems in practice to be a subset of HEADERS)</li>
886  * <li>ACL: specific to /vsiadls/: returns the access control list for a path.</li>
887  * <li>METADATA: specific to /vsiaz/: to set blob metadata. Refer to https://docs.microsoft.com/en-us/rest/api/storageservices/get-blob-metadata. Note: this will be a subset of what pszDomain=HEADERS returns</li>
888  * </ul>
889  * @param papszOptions Unused. Should be set to NULL.
890  *
891  * @return a NULL-terminated list of key=value strings, to be freed with CSLDestroy()
892  * or NULL in case of error / empty list.
893  *
894  * @since GDAL 3.1.0
895  */
896 
VSIGetFileMetadata(const char * pszFilename,const char * pszDomain,CSLConstList papszOptions)897 char** VSIGetFileMetadata( const char * pszFilename, const char* pszDomain,
898                            CSLConstList papszOptions )
899 {
900     VSIFilesystemHandler *poFSHandler =
901         VSIFileManager::GetHandler( pszFilename );
902     return poFSHandler->GetFileMetadata( pszFilename, pszDomain, papszOptions );
903 }
904 
905 /************************************************************************/
906 /*                       VSISetFileMetadata()                           */
907 /************************************************************************/
908 
909 /**
910  * \brief Set metadata on files.
911  *
912  * Implemented currently only for /vsis3/, /vsiaz/ and /vsiadls/
913  *
914  * @param pszFilename the path of the filesystem object to be set.
915  * UTF-8 encoded.
916  * @param papszMetadata NULL-terminated list of key=value strings.
917  * @param pszDomain Metadata domain to set. Depends on the file system.
918  * The following are supported:
919  * <ul>
920  * <li>HEADERS: specific to /vsis3/: to set HTTP headers</li>
921  * <li>TAGS: Content of papszMetadata should be KEY=VALUE pairs.
922  *    <ul>
923  *      <li>/vsis3/: to set S3 Object tagging information</li>
924  *      <li>/vsiaz/: to set blob tags. Refer to https://docs.microsoft.com/en-us/rest/api/storageservices/set-blob-tags. Note: storageV2 must be enabled on the account</li>
925  *    </ul>
926  * </li>
927  * <li>PROPERTIES:
928  *    <ul>
929  *      <li>to /vsiaz/: to set properties. Refer to https://docs.microsoft.com/en-us/rest/api/storageservices/set-blob-properties.</li>
930  *      <li>to /vsiadls/: to set properties. Refer to https://docs.microsoft.com/en-us/rest/api/storageservices/datalakestoragegen2/path/update for headers valid for action=setProperties.</li>
931  *    </ul>
932  * </li>
933  * <li>ACL: specific to /vsiadls/: to set access control list. Refer to https://docs.microsoft.com/en-us/rest/api/storageservices/datalakestoragegen2/path/update for headers valid for action=setAccessControl or setAccessControlRecursive. In setAccessControlRecursive, x-ms-acl must be specified in papszMetadata</li>
934  * <li>METADATA: specific to /vsiaz/: to set blob metadata. Refer to https://docs.microsoft.com/en-us/rest/api/storageservices/set-blob-metadata. Content of papszMetadata should be strings in the form x-ms-meta-name=value</li>
935  * </ul>
936  * @param papszOptions NULL or NULL terminated list of options.
937  *                     For /vsiadls/ and pszDomain=ACL, "RECURSIVE=TRUE" can be
938  *                     set to set the access control list recursively. When
939  *                     RECURSIVE=TRUE is set, MODE should also be set to one of
940  *                     "set", "modify" or "remove".
941  *
942  * @return TRUE in case of success.
943  *
944  * @since GDAL 3.1.0
945  */
946 
VSISetFileMetadata(const char * pszFilename,CSLConstList papszMetadata,const char * pszDomain,CSLConstList papszOptions)947 int VSISetFileMetadata( const char * pszFilename,
948                            CSLConstList papszMetadata,
949                            const char* pszDomain,
950                            CSLConstList papszOptions )
951 {
952     VSIFilesystemHandler *poFSHandler =
953         VSIFileManager::GetHandler( pszFilename );
954     return poFSHandler->SetFileMetadata( pszFilename, papszMetadata, pszDomain,
955                                          papszOptions ) ? 1 : 0;
956 }
957 
958 
959 /************************************************************************/
960 /*                       VSIIsCaseSensitiveFS()                         */
961 /************************************************************************/
962 
963 /**
964  * \brief Returns if the filenames of the filesystem are case sensitive.
965  *
966  * This method retrieves to which filesystem belongs the passed filename
967  * and return TRUE if the filenames of that filesystem are case sensitive.
968  *
969  * Currently, this will return FALSE only for Windows real filenames. Other
970  * VSI virtual filesystems are case sensitive.
971  *
972  * This methods avoid ugly \#ifndef WIN32 / \#endif code, that is wrong when
973  * dealing with virtual filenames.
974  *
975  * @param pszFilename the path of the filesystem object to be tested.
976  * UTF-8 encoded.
977  *
978  * @return TRUE if the filenames of the filesystem are case sensitive.
979  *
980  * @since GDAL 1.8.0
981  */
982 
VSIIsCaseSensitiveFS(const char * pszFilename)983 int VSIIsCaseSensitiveFS( const char * pszFilename )
984 {
985     VSIFilesystemHandler *poFSHandler =
986         VSIFileManager::GetHandler( pszFilename );
987 
988     return poFSHandler->IsCaseSensitive( pszFilename );
989 }
990 
991 /************************************************************************/
992 /*                       VSISupportsSparseFiles()                       */
993 /************************************************************************/
994 
995 /**
996  * \brief Returns if the filesystem supports sparse files.
997  *
998  * Only supported on Linux (and no other Unix derivatives) and
999  * Windows.  On Linux, the answer depends on a few hardcoded
1000  * signatures for common filesystems. Other filesystems will be
1001  * considered as not supporting sparse files.
1002  *
1003  * @param pszPath the path of the filesystem object to be tested.
1004  * UTF-8 encoded.
1005  *
1006  * @return TRUE if the file system is known to support sparse files. FALSE may
1007  *              be returned both in cases where it is known to not support them,
1008  *              or when it is unknown.
1009  *
1010  * @since GDAL 2.2
1011  */
1012 
VSISupportsSparseFiles(const char * pszPath)1013 int VSISupportsSparseFiles( const char* pszPath )
1014 {
1015     VSIFilesystemHandler *poFSHandler =
1016         VSIFileManager::GetHandler( pszPath );
1017 
1018     return poFSHandler->SupportsSparseFiles( pszPath );
1019 }
1020 
1021 /************************************************************************/
1022 /*                     VSIHasOptimizedReadMultiRange()                  */
1023 /************************************************************************/
1024 
1025 /**
1026  * \brief Returns if the filesystem supports efficient multi-range reading.
1027  *
1028  * Currently only returns TRUE for /vsicurl/ and derived file systems.
1029  *
1030  * @param pszPath the path of the filesystem object to be tested.
1031  * UTF-8 encoded.
1032  *
1033  * @return TRUE if the file system is known to have an efficient multi-range
1034  * reading.
1035  *
1036  * @since GDAL 2.3
1037  */
1038 
VSIHasOptimizedReadMultiRange(const char * pszPath)1039 int VSIHasOptimizedReadMultiRange( const char* pszPath )
1040 {
1041     VSIFilesystemHandler *poFSHandler =
1042         VSIFileManager::GetHandler( pszPath );
1043 
1044     return poFSHandler->HasOptimizedReadMultiRange( pszPath );
1045 }
1046 
1047 /************************************************************************/
1048 /*                        VSIGetActualURL()                             */
1049 /************************************************************************/
1050 
1051 /**
1052  * \brief Returns the actual URL of a supplied filename.
1053  *
1054  * Currently only returns a non-NULL value for network-based virtual file systems.
1055  * For example "/vsis3/bucket/filename" will be expanded as
1056  * "https://bucket.s3.amazon.com/filename"
1057  *
1058  * Note that the lifetime of the returned string, is short, and may be
1059  * invalidated by any following GDAL functions.
1060  *
1061  * @param pszFilename the path of the filesystem object. UTF-8 encoded.
1062  *
1063  * @return the actual URL corresponding to the supplied filename, or NULL. Should not
1064  * be freed.
1065  *
1066  * @since GDAL 2.3
1067  */
1068 
VSIGetActualURL(const char * pszFilename)1069 const char* VSIGetActualURL( const char* pszFilename )
1070 {
1071     VSIFilesystemHandler *poFSHandler =
1072         VSIFileManager::GetHandler( pszFilename );
1073 
1074     return poFSHandler->GetActualURL( pszFilename );
1075 }
1076 
1077 /************************************************************************/
1078 /*                        VSIGetSignedURL()                             */
1079 /************************************************************************/
1080 
1081 /**
1082  * \brief Returns a signed URL of a supplied filename.
1083  *
1084  * Currently only returns a non-NULL value for /vsis3/, /vsigs/, /vsiaz/ and /vsioss/
1085  * For example "/vsis3/bucket/filename" will be expanded as
1086  * "https://bucket.s3.amazon.com/filename?X-Amz-Algorithm=AWS4-HMAC-SHA256..."
1087  * Configuration options that apply for file opening (typically to provide
1088  * credentials), and are returned by VSIGetFileSystemOptions(), are also valid
1089  * in that context.
1090  *
1091  * @param pszFilename the path of the filesystem object. UTF-8 encoded.
1092  * @param papszOptions list of options, or NULL. Depend on file system handler.
1093  * For /vsis3/, /vsigs/, /vsiaz/ and /vsioss/, the following options are supported:
1094  * <ul>
1095  * <li>START_DATE=YYMMDDTHHMMSSZ: date and time in UTC following ISO 8601
1096  *     standard, corresponding to the start of validity of the URL.
1097  *     If not specified, current date time.</li>
1098  * <li>EXPIRATION_DELAY=number_of_seconds: number between 1 and 604800 (seven days)
1099  * for the validity of the signed URL. Defaults to 3600 (one hour)</li>
1100  * <li>VERB=GET/HEAD/DELETE/PUT/POST: HTTP VERB for which the request will be
1101  * used. Default to GET.</li>
1102  * </ul>
1103  *
1104  * /vsiaz/ supports additional options:
1105  * <ul>
1106  * <li>SIGNEDIDENTIFIER=value: to relate the given shared access signature
1107  * to a corresponding stored access policy.</li>
1108  * <li>SIGNEDPERMISSIONS=r|w: permissions associated with the shared access
1109  * signature. Normally deduced from VERB.</li>
1110  * </ul>
1111  *
1112  * @return a signed URL, or NULL. Should be freed with CPLFree().
1113  * @since GDAL 2.3
1114  */
1115 
VSIGetSignedURL(const char * pszFilename,CSLConstList papszOptions)1116 char* VSIGetSignedURL( const char* pszFilename, CSLConstList papszOptions )
1117 {
1118     VSIFilesystemHandler *poFSHandler =
1119         VSIFileManager::GetHandler( pszFilename );
1120 
1121     return poFSHandler->GetSignedURL( pszFilename, papszOptions );
1122 }
1123 
1124 /************************************************************************/
1125 /*                             VSIFOpenL()                              */
1126 /************************************************************************/
1127 
1128 /**
1129  * \brief Open file.
1130  *
1131  * This function opens a file with the desired access.  Large files (larger
1132  * than 2GB) should be supported.  Binary access is always implied and
1133  * the "b" does not need to be included in the pszAccess string.
1134  *
1135  * Note that the "VSILFILE *" returned since GDAL 1.8.0 by this function is
1136  * *NOT* a standard C library FILE *, and cannot be used with any functions
1137  * other than the "VSI*L" family of functions.  They aren't "real" FILE objects.
1138  *
1139  * On windows it is possible to define the configuration option
1140  * GDAL_FILE_IS_UTF8 to have pszFilename treated as being in the local
1141  * encoding instead of UTF-8, restoring the pre-1.8.0 behavior of VSIFOpenL().
1142  *
1143  * This method goes through the VSIFileHandler virtualization and may
1144  * work on unusual filesystems such as in memory.
1145  *
1146  * Analog of the POSIX fopen() function.
1147  *
1148  * @param pszFilename the file to open.  UTF-8 encoded.
1149  * @param pszAccess access requested (i.e. "r", "r+", "w")
1150  *
1151  * @return NULL on failure, or the file handle.
1152  */
1153 
VSIFOpenL(const char * pszFilename,const char * pszAccess)1154 VSILFILE *VSIFOpenL( const char * pszFilename, const char * pszAccess )
1155 
1156 {
1157     return VSIFOpenExL(pszFilename, pszAccess, false);
1158 }
1159 
1160 /************************************************************************/
1161 /*                               Open()                                 */
1162 /************************************************************************/
1163 
1164 #ifndef DOXYGEN_SKIP
1165 
Open(const char * pszFilename,const char * pszAccess)1166 VSIVirtualHandle *VSIFilesystemHandler::Open( const char *pszFilename,
1167                                               const char *pszAccess )
1168 {
1169     return Open(pszFilename, pszAccess, false, nullptr);
1170 }
1171 
1172 /************************************************************************/
1173 /*                               Sync()                                 */
1174 /************************************************************************/
1175 
Sync(const char * pszSource,const char * pszTarget,const char * const * papszOptions,GDALProgressFunc pProgressFunc,void * pProgressData,char *** ppapszOutputs)1176 bool VSIFilesystemHandler::Sync( const char* pszSource, const char* pszTarget,
1177                             const char* const * papszOptions,
1178                             GDALProgressFunc pProgressFunc,
1179                             void *pProgressData,
1180                             char*** ppapszOutputs  )
1181 {
1182     if( ppapszOutputs )
1183     {
1184         *ppapszOutputs = nullptr;
1185     }
1186 
1187     VSIStatBufL sSource;
1188     CPLString osSource(pszSource);
1189     CPLString osSourceWithoutSlash(pszSource);
1190     if( osSourceWithoutSlash.back() == '/' )
1191     {
1192         osSourceWithoutSlash.resize(osSourceWithoutSlash.size()-1);
1193     }
1194     if( VSIStatL(osSourceWithoutSlash, &sSource) < 0 )
1195     {
1196         CPLError(CE_Failure, CPLE_FileIO, "%s does not exist", pszSource);
1197         return false;
1198     }
1199 
1200     if( VSI_ISDIR(sSource.st_mode) )
1201     {
1202         CPLString osTargetDir(pszTarget);
1203         if( osSource.back() != '/' )
1204         {
1205             osTargetDir = CPLFormFilename(osTargetDir,
1206                                           CPLGetFilename(pszSource), nullptr);
1207         }
1208 
1209         VSIStatBufL sTarget;
1210         bool ret = true;
1211         if( VSIStatL(osTargetDir, &sTarget) < 0 )
1212         {
1213             if( VSIMkdirRecursive(osTargetDir, 0755) < 0 )
1214             {
1215                 CPLError(CE_Failure, CPLE_FileIO,
1216                          "Cannot create directory %s", osTargetDir.c_str());
1217                 return false;
1218             }
1219         }
1220 
1221         if( !CPLFetchBool(papszOptions, "STOP_ON_DIR", false) )
1222         {
1223             CPLStringList aosChildOptions(CSLDuplicate(papszOptions));
1224             if( !CPLFetchBool(papszOptions, "RECURSIVE", true) )
1225             {
1226                 aosChildOptions.SetNameValue("RECURSIVE", nullptr);
1227                 aosChildOptions.AddString("STOP_ON_DIR=TRUE");
1228             }
1229 
1230             char** papszSrcFiles = VSIReadDir(osSourceWithoutSlash);
1231             int nFileCount = 0;
1232             for( auto iter = papszSrcFiles ; iter && *iter; ++iter )
1233             {
1234                 if( strcmp(*iter, ".") != 0 && strcmp(*iter, "..") != 0 )
1235                 {
1236                     nFileCount ++;
1237                 }
1238             }
1239             int iFile = 0;
1240             for( auto iter = papszSrcFiles ; iter && *iter; ++iter, ++iFile )
1241             {
1242                 if( strcmp(*iter, ".") == 0 || strcmp(*iter, "..") == 0 )
1243                 {
1244                     continue;
1245                 }
1246                 CPLString osSubSource(
1247                     CPLFormFilename(osSourceWithoutSlash, *iter, nullptr) );
1248                 CPLString osSubTarget(
1249                     CPLFormFilename(osTargetDir, *iter, nullptr) );
1250                 // coverity[divide_by_zero]
1251                 void* pScaledProgress = GDALCreateScaledProgress(
1252                     double(iFile) / nFileCount, double(iFile + 1) / nFileCount,
1253                     pProgressFunc, pProgressData);
1254                 ret = Sync( (osSubSource + '/').c_str(), osSubTarget,
1255                             aosChildOptions.List(),
1256                             GDALScaledProgress, pScaledProgress,
1257                             nullptr );
1258                 GDALDestroyScaledProgress(pScaledProgress);
1259                 if( !ret )
1260                 {
1261                     break;
1262                 }
1263             }
1264             CSLDestroy(papszSrcFiles);
1265         }
1266         return ret;
1267     }
1268 
1269     VSIStatBufL sTarget;
1270     CPLString osTarget(pszTarget);
1271     if( VSIStatL(osTarget, &sTarget) == 0 )
1272     {
1273         bool bTargetIsFile = true;
1274         if ( VSI_ISDIR(sTarget.st_mode) )
1275         {
1276             osTarget = CPLFormFilename(osTarget,
1277                                        CPLGetFilename(pszSource), nullptr);
1278             bTargetIsFile = VSIStatL(osTarget, &sTarget) == 0 &&
1279                             !CPL_TO_BOOL(VSI_ISDIR(sTarget.st_mode));
1280         }
1281         if( bTargetIsFile )
1282         {
1283             if( sSource.st_size == sTarget.st_size &&
1284                 sSource.st_mtime == sTarget.st_mtime &&
1285                 sSource.st_mtime != 0 )
1286             {
1287                 CPLDebug("VSI", "%s and %s have same size and modification "
1288                          "date. Skipping copying",
1289                          osSourceWithoutSlash.c_str(),
1290                          osTarget.c_str());
1291                 return true;
1292             }
1293         }
1294     }
1295 
1296     VSILFILE* fpIn = VSIFOpenExL(osSourceWithoutSlash, "rb", TRUE);
1297     if( fpIn == nullptr )
1298     {
1299         CPLError(CE_Failure, CPLE_FileIO, "Cannot open %s",
1300                  osSourceWithoutSlash.c_str());
1301         return false;
1302     }
1303 
1304     VSILFILE* fpOut = VSIFOpenExL(osTarget.c_str(), "wb", TRUE);
1305     if( fpOut == nullptr )
1306     {
1307         CPLError(CE_Failure, CPLE_FileIO, "Cannot create %s", osTarget.c_str());
1308         VSIFCloseL(fpIn);
1309         return false;
1310     }
1311 
1312     bool ret = true;
1313     constexpr size_t nBufferSize = 10 * 4096;
1314     std::vector<GByte> abyBuffer(nBufferSize, 0);
1315     GUIntBig nOffset = 0;
1316     CPLString osMsg;
1317     osMsg.Printf("Copying of %s", osSourceWithoutSlash.c_str());
1318     while( true )
1319     {
1320         size_t nRead = VSIFReadL(&abyBuffer[0], 1, nBufferSize, fpIn);
1321         size_t nWritten = VSIFWriteL(&abyBuffer[0], 1, nRead, fpOut);
1322         if( nWritten != nRead )
1323         {
1324             CPLError(CE_Failure, CPLE_FileIO,
1325                      "Copying of %s to %s failed",
1326                      osSourceWithoutSlash.c_str(), osTarget.c_str());
1327             ret = false;
1328             break;
1329         }
1330         nOffset += nRead;
1331         if( pProgressFunc && !pProgressFunc(
1332                 double(nOffset) / sSource.st_size, osMsg.c_str(),
1333                 pProgressData) )
1334         {
1335             ret = false;
1336             break;
1337         }
1338         if( nRead < nBufferSize )
1339         {
1340             break;
1341         }
1342     }
1343 
1344     VSIFCloseL(fpIn);
1345     if( VSIFCloseL(fpOut) != 0 )
1346     {
1347         ret = false;
1348     }
1349     return ret;
1350 }
1351 
1352 /************************************************************************/
1353 /*                            VSIDIREntry()                             */
1354 /************************************************************************/
1355 
VSIDIREntry()1356 VSIDIREntry::VSIDIREntry(): pszName(nullptr), nMode(0), nSize(0), nMTime(0),
1357                    bModeKnown(false), bSizeKnown(false), bMTimeKnown(false),
1358                    papszExtra(nullptr)
1359 {
1360 }
1361 
1362 /************************************************************************/
1363 /*                            VSIDIREntry()                             */
1364 /************************************************************************/
1365 
VSIDIREntry(const VSIDIREntry & other)1366 VSIDIREntry::VSIDIREntry(const VSIDIREntry& other):
1367     pszName(VSIStrdup(other.pszName)),
1368     nMode(other.nMode),
1369     nSize(other.nSize),
1370     nMTime(other.nMTime),
1371     bModeKnown(other.bModeKnown),
1372     bSizeKnown(other.bSizeKnown),
1373     bMTimeKnown(other.bMTimeKnown),
1374     papszExtra(CSLDuplicate(other.papszExtra))
1375 {}
1376 
1377 /************************************************************************/
1378 /*                           ~VSIDIREntry()                             */
1379 /************************************************************************/
1380 
~VSIDIREntry()1381 VSIDIREntry::~VSIDIREntry()
1382 {
1383     CPLFree(pszName);
1384     CSLDestroy(papszExtra);
1385 }
1386 
1387 /************************************************************************/
1388 /*                              ~VSIDIR()                               */
1389 /************************************************************************/
1390 
~VSIDIR()1391 VSIDIR::~VSIDIR()
1392 {
1393 }
1394 
1395 /************************************************************************/
1396 /*                            VSIDIRGeneric                             */
1397 /************************************************************************/
1398 
1399 namespace {
1400 struct VSIDIRGeneric: public VSIDIR
1401 {
1402     CPLString osRootPath{};
1403     CPLString osBasePath{};
1404     char** papszContent = nullptr;
1405     int nRecurseDepth = 0;
1406     int nPos = 0;
1407     VSIDIREntry entry{};
1408     std::vector<VSIDIRGeneric*> aoStackSubDir{};
1409     VSIFilesystemHandler* poFS = nullptr;
1410 
VSIDIRGeneric__anon7b0ed2550211::VSIDIRGeneric1411     explicit VSIDIRGeneric(VSIFilesystemHandler* poFSIn): poFS(poFSIn) {}
1412     ~VSIDIRGeneric();
1413 
1414     const VSIDIREntry* NextDirEntry() override;
1415 
1416     VSIDIRGeneric(const VSIDIRGeneric&) = delete;
1417     VSIDIRGeneric& operator=(const VSIDIRGeneric&) = delete;
1418 };
1419 
1420 /************************************************************************/
1421 /*                         ~VSIDIRGeneric()                             */
1422 /************************************************************************/
1423 
~VSIDIRGeneric()1424 VSIDIRGeneric::~VSIDIRGeneric()
1425 {
1426     while( !aoStackSubDir.empty() )
1427     {
1428         delete aoStackSubDir.back();
1429         aoStackSubDir.pop_back();
1430     }
1431     CSLDestroy(papszContent);
1432 }
1433 
1434 }
1435 
1436 /************************************************************************/
1437 /*                            OpenDir()                                 */
1438 /************************************************************************/
1439 
OpenDir(const char * pszPath,int nRecurseDepth,const char * const *)1440 VSIDIR* VSIFilesystemHandler::OpenDir( const char *pszPath,
1441                                        int nRecurseDepth,
1442                                        const char* const *)
1443 {
1444     char** papszContent = VSIReadDir(pszPath);
1445     VSIStatBufL sStatL;
1446     if( papszContent == nullptr &&
1447         (VSIStatL(pszPath, &sStatL) != 0 || !VSI_ISDIR(sStatL.st_mode)) )
1448     {
1449         return nullptr;
1450     }
1451     VSIDIRGeneric* dir = new VSIDIRGeneric(this);
1452     dir->osRootPath = pszPath;
1453     dir->nRecurseDepth = nRecurseDepth;
1454     dir->papszContent = papszContent;
1455     return dir;
1456 }
1457 
1458 /************************************************************************/
1459 /*                           NextDirEntry()                             */
1460 /************************************************************************/
1461 
NextDirEntry()1462 const VSIDIREntry* VSIDIRGeneric::NextDirEntry()
1463 {
1464     if( VSI_ISDIR(entry.nMode) && nRecurseDepth != 0 )
1465     {
1466         CPLString osCurFile(osRootPath);
1467         if( !osCurFile.empty() )
1468             osCurFile += '/';
1469         osCurFile += entry.pszName;
1470         auto subdir = static_cast<VSIDIRGeneric*>(
1471             poFS->VSIFilesystemHandler::OpenDir(osCurFile,
1472                 nRecurseDepth - 1, nullptr));
1473         if( subdir )
1474         {
1475             subdir->osRootPath = osRootPath;
1476             subdir->osBasePath = entry.pszName;
1477             aoStackSubDir.push_back(subdir);
1478         }
1479         entry.nMode = 0;
1480     }
1481 
1482     while( !aoStackSubDir.empty() )
1483     {
1484         auto l_entry = aoStackSubDir.back()->NextDirEntry();
1485         if( l_entry )
1486         {
1487             return l_entry;
1488         }
1489         delete aoStackSubDir.back();
1490         aoStackSubDir.pop_back();
1491     }
1492 
1493     if( papszContent == nullptr )
1494     {
1495         return nullptr;
1496     }
1497 
1498     while( true )
1499     {
1500         if( !papszContent[nPos] )
1501         {
1502             return nullptr;
1503         }
1504         // Skip . and ..entries
1505         if( papszContent[nPos][0] == '.' &&
1506             (papszContent[nPos][1] == '\0' ||
1507              (papszContent[nPos][1] == '.' &&
1508               papszContent[nPos][2] == '\0')) )
1509         {
1510             nPos ++;
1511         }
1512         else
1513         {
1514             break;
1515         }
1516     }
1517 
1518     CPLFree(entry.pszName);
1519     CPLString osName(osBasePath);
1520     if( !osName.empty() )
1521         osName += '/';
1522     osName += papszContent[nPos];
1523     entry.pszName = CPLStrdup(osName);
1524     VSIStatBufL sStatL;
1525     CPLString osCurFile(osRootPath);
1526     if( !osCurFile.empty() )
1527         osCurFile += '/';
1528     osCurFile += entry.pszName;
1529     if( VSIStatL(osCurFile, &sStatL) == 0 )
1530     {
1531         entry.nMode = sStatL.st_mode;
1532         entry.nSize = sStatL.st_size;
1533         entry.nMTime = sStatL.st_mtime;
1534         entry.bModeKnown = true;
1535         entry.bSizeKnown = true;
1536         entry.bMTimeKnown = true;
1537     }
1538     else
1539     {
1540         entry.nMode = 0;
1541         entry.nSize = 0;
1542         entry.nMTime = 0;
1543         entry.bModeKnown = false;
1544         entry.bSizeKnown = false;
1545         entry.bMTimeKnown = false;
1546     }
1547     nPos ++;
1548 
1549     return &(entry);
1550 }
1551 
1552 /************************************************************************/
1553 /*                           UnlinkBatch()                              */
1554 /************************************************************************/
1555 
UnlinkBatch(CSLConstList papszFiles)1556 int* VSIFilesystemHandler::UnlinkBatch( CSLConstList papszFiles )
1557 {
1558     int* panRet = static_cast<int*>(
1559         CPLMalloc(sizeof(int) * CSLCount(papszFiles)));
1560     for( int i = 0; papszFiles && papszFiles[i]; ++i )
1561     {
1562         panRet[i] = VSIUnlink(papszFiles[i]) == 0;
1563     }
1564     return panRet;
1565 }
1566 
1567 /************************************************************************/
1568 /*                          RmdirRecursive()                            */
1569 /************************************************************************/
1570 
RmdirRecursive(const char * pszDirname)1571 int VSIFilesystemHandler::RmdirRecursive( const char* pszDirname )
1572 {
1573     CPLString osDirnameWithoutEndSlash(pszDirname);
1574     if( !osDirnameWithoutEndSlash.empty() && osDirnameWithoutEndSlash.back() == '/' )
1575         osDirnameWithoutEndSlash.resize( osDirnameWithoutEndSlash.size() - 1 );
1576 
1577     CPLStringList aosOptions;
1578     auto poDir = std::unique_ptr<VSIDIR>(OpenDir(pszDirname, -1, aosOptions.List()));
1579     if( !poDir )
1580         return -1;
1581     std::vector<std::string> aosDirs;
1582     while( true )
1583     {
1584         auto entry = poDir->NextDirEntry();
1585         if( !entry )
1586             break;
1587 
1588         const CPLString osFilename(osDirnameWithoutEndSlash + '/' + entry->pszName);
1589         if( (entry->nMode & S_IFDIR) )
1590         {
1591             aosDirs.push_back(osFilename);
1592         }
1593         else
1594         {
1595             if( VSIUnlink(osFilename) != 0 )
1596                 return -1;
1597         }
1598     }
1599 
1600     // Sort in reverse order, so that inner-most directories are deleted first
1601     std::sort(aosDirs.begin(), aosDirs.end(),
1602               [](const std::string& a, const std::string& b) {return a > b; });
1603 
1604     for(const auto& osDir: aosDirs )
1605     {
1606         if( VSIRmdir(osDir.c_str()) != 0 )
1607             return -1;
1608     }
1609 
1610     return VSIRmdir(pszDirname);
1611 }
1612 
1613 /************************************************************************/
1614 /*                          GetFileMetadata()                           */
1615 /************************************************************************/
1616 
GetFileMetadata(const char *,const char *,CSLConstList)1617 char** VSIFilesystemHandler::GetFileMetadata( const char * /* pszFilename*/, const char* /*pszDomain*/,
1618                                     CSLConstList /*papszOptions*/ )
1619 {
1620     return nullptr;
1621 }
1622 
1623 /************************************************************************/
1624 /*                          SetFileMetadata()                           */
1625 /************************************************************************/
1626 
SetFileMetadata(const char *,CSLConstList,const char *,CSLConstList)1627 bool VSIFilesystemHandler::SetFileMetadata( const char * /* pszFilename*/,
1628                                     CSLConstList /* papszMetadata */,
1629                                     const char* /* pszDomain */,
1630                                     CSLConstList /* papszOptions */ )
1631 {
1632     CPLError(CE_Failure, CPLE_NotSupported, "SetFileMetadata() not supported");
1633     return false;
1634 }
1635 
1636 #endif
1637 
1638 /************************************************************************/
1639 /*                             VSIFOpenExL()                            */
1640 /************************************************************************/
1641 
1642 /**
1643  * \brief Open file.
1644  *
1645  * This function opens a file with the desired access.  Large files (larger
1646  * than 2GB) should be supported.  Binary access is always implied and
1647  * the "b" does not need to be included in the pszAccess string.
1648  *
1649  * Note that the "VSILFILE *" returned by this function is
1650  * *NOT* a standard C library FILE *, and cannot be used with any functions
1651  * other than the "VSI*L" family of functions.  They aren't "real" FILE objects.
1652  *
1653  * On windows it is possible to define the configuration option
1654  * GDAL_FILE_IS_UTF8 to have pszFilename treated as being in the local
1655  * encoding instead of UTF-8, restoring the pre-1.8.0 behavior of VSIFOpenL().
1656  *
1657  * This method goes through the VSIFileHandler virtualization and may
1658  * work on unusual filesystems such as in memory.
1659  *
1660  * Analog of the POSIX fopen() function.
1661  *
1662  * @param pszFilename the file to open.  UTF-8 encoded.
1663  * @param pszAccess access requested (i.e. "r", "r+", "w")
1664  * @param bSetError flag determining whether or not this open call
1665  * should set VSIErrors on failure.
1666  *
1667  * @return NULL on failure, or the file handle.
1668  *
1669  * @since GDAL 2.1
1670  */
1671 
VSIFOpenExL(const char * pszFilename,const char * pszAccess,int bSetError)1672 VSILFILE *VSIFOpenExL( const char * pszFilename, const char * pszAccess,
1673                        int bSetError )
1674 
1675 {
1676     return VSIFOpenEx2L(pszFilename, pszAccess, bSetError, nullptr);
1677 }
1678 
1679 /************************************************************************/
1680 /*                            VSIFOpenEx2L()                            */
1681 /************************************************************************/
1682 
1683 /**
1684  * \brief Open file.
1685  *
1686  * This function opens a file with the desired access.  Large files (larger
1687  * than 2GB) should be supported.  Binary access is always implied and
1688  * the "b" does not need to be included in the pszAccess string.
1689  *
1690  * Note that the "VSILFILE *" returned by this function is
1691  * *NOT* a standard C library FILE *, and cannot be used with any functions
1692  * other than the "VSI*L" family of functions.  They aren't "real" FILE objects.
1693  *
1694  * On windows it is possible to define the configuration option
1695  * GDAL_FILE_IS_UTF8 to have pszFilename treated as being in the local
1696  * encoding instead of UTF-8, restoring the pre-1.8.0 behavior of VSIFOpenL().
1697  *
1698  * This method goes through the VSIFileHandler virtualization and may
1699  * work on unusual filesystems such as in memory.
1700  *
1701  * Analog of the POSIX fopen() function.
1702  *
1703  * @param pszFilename the file to open.  UTF-8 encoded.
1704  * @param pszAccess access requested (i.e. "r", "r+", "w")
1705  * @param bSetError flag determining whether or not this open call
1706  * should set VSIErrors on failure.
1707  * @param papszOptions NULL or NULL-terminated list of strings. The content is
1708  *                     highly file system dependent. Currently only MIME headers
1709  *                     such as Content-Type and Content-Encoding are supported
1710  *                     for the /vsis3/, /vsigs/, /vsiaz/, /vsiadls/ file systems.
1711  *
1712  * @return NULL on failure, or the file handle.
1713  *
1714  * @since GDAL 3.3
1715  */
1716 
VSIFOpenEx2L(const char * pszFilename,const char * pszAccess,int bSetError,CSLConstList papszOptions)1717 VSILFILE *VSIFOpenEx2L( const char * pszFilename, const char * pszAccess,
1718                         int bSetError, CSLConstList papszOptions )
1719 
1720 {
1721     // Too long filenames can cause excessive memory allocation due to
1722     // recursion in some filesystem handlers
1723     constexpr size_t knMaxPath = 8192;
1724     if( CPLStrnlen(pszFilename, knMaxPath) == knMaxPath )
1725         return nullptr;
1726 
1727     VSIFilesystemHandler *poFSHandler =
1728         VSIFileManager::GetHandler( pszFilename );
1729 
1730     VSILFILE* fp = reinterpret_cast<VSILFILE *>(
1731         poFSHandler->Open( pszFilename, pszAccess, CPL_TO_BOOL(bSetError), papszOptions ) );
1732 
1733     VSIDebug4( "VSIFOpenEx2L(%s,%s,%d) = %p",
1734                pszFilename, pszAccess, bSetError, fp );
1735 
1736     return fp;
1737 }
1738 
1739 /************************************************************************/
1740 /*                             VSIFCloseL()                             */
1741 /************************************************************************/
1742 
1743 /**
1744  * \fn VSIVirtualHandle::Close()
1745  * \brief Close file.
1746  *
1747  * This function closes the indicated file.
1748  *
1749  * This method goes through the VSIFileHandler virtualization and may
1750  * work on unusual filesystems such as in memory.
1751  *
1752  * Analog of the POSIX fclose() function.
1753  *
1754  * @return 0 on success or -1 on failure.
1755  */
1756 
1757 /**
1758  * \brief Close file.
1759  *
1760  * This function closes the indicated file.
1761  *
1762  * This method goes through the VSIFileHandler virtualization and may
1763  * work on unusual filesystems such as in memory.
1764  *
1765  * Analog of the POSIX fclose() function.
1766  *
1767  * @param fp file handle opened with VSIFOpenL().  Passing a nullptr produces
1768  * undefined behavior.
1769  *
1770  * @return 0 on success or -1 on failure.
1771  */
1772 
VSIFCloseL(VSILFILE * fp)1773 int VSIFCloseL( VSILFILE * fp )
1774 
1775 {
1776     VSIVirtualHandle *poFileHandle = reinterpret_cast<VSIVirtualHandle *>( fp );
1777 
1778     VSIDebug1( "VSIFCloseL(%p)", fp );
1779 
1780     const int nResult = poFileHandle->Close();
1781 
1782     delete poFileHandle;
1783 
1784     return nResult;
1785 }
1786 
1787 /************************************************************************/
1788 /*                             VSIFSeekL()                              */
1789 /************************************************************************/
1790 
1791 /**
1792  * \fn int VSIVirtualHandle::Seek( vsi_l_offset nOffset, int nWhence )
1793  * \brief Seek to requested offset.
1794  *
1795  * Seek to the desired offset (nOffset) in the indicated file.
1796  *
1797  * This method goes through the VSIFileHandler virtualization and may
1798  * work on unusual filesystems such as in memory.
1799  *
1800  * Analog of the POSIX fseek() call.
1801  *
1802  * Caution: vsi_l_offset is a unsigned type, so SEEK_CUR can only be used
1803  * for positive seek. If negative seek is needed, use
1804  * handle->Seek( handle->Tell() + negative_offset, SEEK_SET ).
1805  *
1806  * @param nOffset offset in bytes.
1807  * @param nWhence one of SEEK_SET, SEEK_CUR or SEEK_END.
1808  *
1809  * @return 0 on success or -1 one failure.
1810  */
1811 
1812 /**
1813  * \brief Seek to requested offset.
1814  *
1815  * Seek to the desired offset (nOffset) in the indicated file.
1816  *
1817  * This method goes through the VSIFileHandler virtualization and may
1818  * work on unusual filesystems such as in memory.
1819  *
1820  * Analog of the POSIX fseek() call.
1821  *
1822  * Caution: vsi_l_offset is a unsigned type, so SEEK_CUR can only be used
1823  * for positive seek. If negative seek is needed, use
1824  * VSIFSeekL( fp, VSIFTellL(fp) + negative_offset, SEEK_SET ).
1825  *
1826  * @param fp file handle opened with VSIFOpenL().
1827  * @param nOffset offset in bytes.
1828  * @param nWhence one of SEEK_SET, SEEK_CUR or SEEK_END.
1829  *
1830  * @return 0 on success or -1 one failure.
1831  */
1832 
VSIFSeekL(VSILFILE * fp,vsi_l_offset nOffset,int nWhence)1833 int VSIFSeekL( VSILFILE * fp, vsi_l_offset nOffset, int nWhence )
1834 
1835 {
1836     VSIVirtualHandle *poFileHandle = reinterpret_cast<VSIVirtualHandle *>(fp);
1837 
1838     return poFileHandle->Seek( nOffset, nWhence );
1839 }
1840 
1841 /************************************************************************/
1842 /*                             VSIFTellL()                              */
1843 /************************************************************************/
1844 
1845 /**
1846  * \fn VSIVirtualHandle::Tell()
1847  * \brief Tell current file offset.
1848  *
1849  * Returns the current file read/write offset in bytes from the beginning of
1850  * the file.
1851  *
1852  * This method goes through the VSIFileHandler virtualization and may
1853  * work on unusual filesystems such as in memory.
1854  *
1855  * Analog of the POSIX ftell() call.
1856  *
1857  * @return file offset in bytes.
1858  */
1859 
1860 /**
1861  * \brief Tell current file offset.
1862  *
1863  * Returns the current file read/write offset in bytes from the beginning of
1864  * the file.
1865  *
1866  * This method goes through the VSIFileHandler virtualization and may
1867  * work on unusual filesystems such as in memory.
1868  *
1869  * Analog of the POSIX ftell() call.
1870  *
1871  * @param fp file handle opened with VSIFOpenL().
1872  *
1873  * @return file offset in bytes.
1874  */
1875 
VSIFTellL(VSILFILE * fp)1876 vsi_l_offset VSIFTellL( VSILFILE * fp )
1877 
1878 {
1879     VSIVirtualHandle *poFileHandle = reinterpret_cast<VSIVirtualHandle *>( fp );
1880 
1881     return poFileHandle->Tell();
1882 }
1883 
1884 /************************************************************************/
1885 /*                             VSIRewindL()                             */
1886 /************************************************************************/
1887 
1888 /**
1889  * \brief Rewind the file pointer to the beginning of the file.
1890  *
1891  * This is equivalent to VSIFSeekL( fp, 0, SEEK_SET )
1892  *
1893  * Analog of the POSIX rewind() call.
1894  *
1895  * @param fp file handle opened with VSIFOpenL().
1896  */
1897 
VSIRewindL(VSILFILE * fp)1898 void VSIRewindL( VSILFILE * fp )
1899 
1900 {
1901     CPL_IGNORE_RET_VAL(VSIFSeekL( fp, 0, SEEK_SET ));
1902 }
1903 
1904 /************************************************************************/
1905 /*                             VSIFFlushL()                             */
1906 /************************************************************************/
1907 
1908 /**
1909  * \fn VSIVirtualHandle::Flush()
1910  * \brief Flush pending writes to disk.
1911  *
1912  * For files in write or update mode and on filesystem types where it is
1913  * applicable, all pending output on the file is flushed to the physical disk.
1914  *
1915  * This method goes through the VSIFileHandler virtualization and may
1916  * work on unusual filesystems such as in memory.
1917  *
1918  * Analog of the POSIX fflush() call.
1919  *
1920  * @return 0 on success or -1 on error.
1921  */
1922 
1923 /**
1924  * \brief Flush pending writes to disk.
1925  *
1926  * For files in write or update mode and on filesystem types where it is
1927  * applicable, all pending output on the file is flushed to the physical disk.
1928  *
1929  * This method goes through the VSIFileHandler virtualization and may
1930  * work on unusual filesystems such as in memory.
1931  *
1932  * Analog of the POSIX fflush() call.
1933  *
1934  * @param fp file handle opened with VSIFOpenL().
1935  *
1936  * @return 0 on success or -1 on error.
1937  */
1938 
VSIFFlushL(VSILFILE * fp)1939 int VSIFFlushL( VSILFILE * fp )
1940 
1941 {
1942     VSIVirtualHandle *poFileHandle = reinterpret_cast<VSIVirtualHandle *>( fp );
1943 
1944     return poFileHandle->Flush();
1945 }
1946 
1947 /************************************************************************/
1948 /*                             VSIFReadL()                              */
1949 /************************************************************************/
1950 
1951 /**
1952  * \fn VSIVirtualHandle::Read( void *pBuffer, size_t nSize, size_t nCount )
1953  * \brief Read bytes from file.
1954  *
1955  * Reads nCount objects of nSize bytes from the indicated file at the
1956  * current offset into the indicated buffer.
1957  *
1958  * This method goes through the VSIFileHandler virtualization and may
1959  * work on unusual filesystems such as in memory.
1960  *
1961  * Analog of the POSIX fread() call.
1962  *
1963  * @param pBuffer the buffer into which the data should be read (at least
1964  * nCount * nSize bytes in size.
1965  * @param nSize size of objects to read in bytes.
1966  * @param nCount number of objects to read.
1967  *
1968  * @return number of objects successfully read.
1969  */
1970 
1971 /**
1972  * \brief Read bytes from file.
1973  *
1974  * Reads nCount objects of nSize bytes from the indicated file at the
1975  * current offset into the indicated buffer.
1976  *
1977  * This method goes through the VSIFileHandler virtualization and may
1978  * work on unusual filesystems such as in memory.
1979  *
1980  * Analog of the POSIX fread() call.
1981  *
1982  * @param pBuffer the buffer into which the data should be read (at least
1983  * nCount * nSize bytes in size.
1984  * @param nSize size of objects to read in bytes.
1985  * @param nCount number of objects to read.
1986  * @param fp file handle opened with VSIFOpenL().
1987  *
1988  * @return number of objects successfully read.
1989  */
1990 
VSIFReadL(void * pBuffer,size_t nSize,size_t nCount,VSILFILE * fp)1991 size_t VSIFReadL( void * pBuffer, size_t nSize, size_t nCount, VSILFILE * fp )
1992 
1993 {
1994     VSIVirtualHandle *poFileHandle = reinterpret_cast<VSIVirtualHandle *>( fp );
1995 
1996     return poFileHandle->Read( pBuffer, nSize, nCount );
1997 }
1998 
1999 /************************************************************************/
2000 /*                       VSIFReadMultiRangeL()                          */
2001 /************************************************************************/
2002 
2003 /**
2004  * \fn VSIVirtualHandle::ReadMultiRange( int nRanges, void ** ppData,
2005  *                                       const vsi_l_offset* panOffsets,
2006  *                                       const size_t* panSizes )
2007  * \brief Read several ranges of bytes from file.
2008  *
2009  * Reads nRanges objects of panSizes[i] bytes from the indicated file at the
2010  * offset panOffsets[i] into the buffer ppData[i].
2011  *
2012  * Ranges must be sorted in ascending start offset, and must not overlap each
2013  * other.
2014  *
2015  * This method goes through the VSIFileHandler virtualization and may
2016  * work on unusual filesystems such as in memory or /vsicurl/.
2017  *
2018  * @param nRanges number of ranges to read.
2019  * @param ppData array of nRanges buffer into which the data should be read
2020  *               (ppData[i] must be at list panSizes[i] bytes).
2021  * @param panOffsets array of nRanges offsets at which the data should be read.
2022  * @param panSizes array of nRanges sizes of objects to read (in bytes).
2023  *
2024  * @return 0 in case of success, -1 otherwise.
2025  * @since GDAL 1.9.0
2026  */
2027 
2028 /**
2029  * \brief Read several ranges of bytes from file.
2030  *
2031  * Reads nRanges objects of panSizes[i] bytes from the indicated file at the
2032  * offset panOffsets[i] into the buffer ppData[i].
2033  *
2034  * Ranges must be sorted in ascending start offset, and must not overlap each
2035  * other.
2036  *
2037  * This method goes through the VSIFileHandler virtualization and may
2038  * work on unusual filesystems such as in memory or /vsicurl/.
2039  *
2040  * @param nRanges number of ranges to read.
2041  * @param ppData array of nRanges buffer into which the data should be read
2042  *               (ppData[i] must be at list panSizes[i] bytes).
2043  * @param panOffsets array of nRanges offsets at which the data should be read.
2044  * @param panSizes array of nRanges sizes of objects to read (in bytes).
2045  * @param fp file handle opened with VSIFOpenL().
2046  *
2047  * @return 0 in case of success, -1 otherwise.
2048  * @since GDAL 1.9.0
2049  */
2050 
VSIFReadMultiRangeL(int nRanges,void ** ppData,const vsi_l_offset * panOffsets,const size_t * panSizes,VSILFILE * fp)2051 int VSIFReadMultiRangeL( int nRanges, void ** ppData,
2052                          const vsi_l_offset* panOffsets,
2053                          const size_t* panSizes, VSILFILE * fp )
2054 {
2055     VSIVirtualHandle *poFileHandle = reinterpret_cast<VSIVirtualHandle *>(fp);
2056 
2057     return poFileHandle->ReadMultiRange(nRanges, ppData, panOffsets, panSizes);
2058 }
2059 
2060 /************************************************************************/
2061 /*                             VSIFWriteL()                             */
2062 /************************************************************************/
2063 
2064 /**
2065  * \fn VSIVirtualHandle::Write( const void *pBuffer,
2066  *                              size_t nSize, size_t nCount )
2067  * \brief Write bytes to file.
2068  *
2069  * Writess nCount objects of nSize bytes to the indicated file at the
2070  * current offset into the indicated buffer.
2071  *
2072  * This method goes through the VSIFileHandler virtualization and may
2073  * work on unusual filesystems such as in memory.
2074  *
2075  * Analog of the POSIX fwrite() call.
2076  *
2077  * @param pBuffer the buffer from which the data should be written (at least
2078  * nCount * nSize bytes in size.
2079  * @param nSize size of objects to read in bytes.
2080  * @param nCount number of objects to read.
2081  *
2082  * @return number of objects successfully written.
2083  */
2084 
2085 /**
2086  * \brief Write bytes to file.
2087  *
2088  * Writess nCount objects of nSize bytes to the indicated file at the
2089  * current offset into the indicated buffer.
2090  *
2091  * This method goes through the VSIFileHandler virtualization and may
2092  * work on unusual filesystems such as in memory.
2093  *
2094  * Analog of the POSIX fwrite() call.
2095  *
2096  * @param pBuffer the buffer from which the data should be written (at least
2097  * nCount * nSize bytes in size.
2098  * @param nSize size of objects to read in bytes.
2099  * @param nCount number of objects to read.
2100  * @param fp file handle opened with VSIFOpenL().
2101  *
2102  * @return number of objects successfully written.
2103  */
2104 
VSIFWriteL(const void * pBuffer,size_t nSize,size_t nCount,VSILFILE * fp)2105 size_t VSIFWriteL( const void *pBuffer, size_t nSize, size_t nCount,
2106                    VSILFILE *fp )
2107 
2108 {
2109     VSIVirtualHandle *poFileHandle = reinterpret_cast<VSIVirtualHandle *>( fp );
2110 
2111     return poFileHandle->Write( pBuffer, nSize, nCount );
2112 }
2113 
2114 /************************************************************************/
2115 /*                              VSIFEofL()                              */
2116 /************************************************************************/
2117 
2118 /**
2119  * \fn VSIVirtualHandle::Eof()
2120  * \brief Test for end of file.
2121  *
2122  * Returns TRUE (non-zero) if an end-of-file condition occurred during the
2123  * previous read operation. The end-of-file flag is cleared by a successful
2124  * VSIFSeekL() call.
2125  *
2126  * This method goes through the VSIFileHandler virtualization and may
2127  * work on unusual filesystems such as in memory.
2128  *
2129  * Analog of the POSIX feof() call.
2130  *
2131  * @return TRUE if at EOF else FALSE.
2132  */
2133 
2134 /**
2135  * \brief Test for end of file.
2136  *
2137  * Returns TRUE (non-zero) if an end-of-file condition occurred during the
2138  * previous read operation. The end-of-file flag is cleared by a successful
2139  * VSIFSeekL() call.
2140  *
2141  * This method goes through the VSIFileHandler virtualization and may
2142  * work on unusual filesystems such as in memory.
2143  *
2144  * Analog of the POSIX feof() call.
2145  *
2146  * @param fp file handle opened with VSIFOpenL().
2147  *
2148  * @return TRUE if at EOF else FALSE.
2149  */
2150 
VSIFEofL(VSILFILE * fp)2151 int VSIFEofL( VSILFILE * fp )
2152 
2153 {
2154     VSIVirtualHandle *poFileHandle = reinterpret_cast<VSIVirtualHandle *>( fp );
2155 
2156     return poFileHandle->Eof();
2157 }
2158 
2159 /************************************************************************/
2160 /*                            VSIFTruncateL()                           */
2161 /************************************************************************/
2162 
2163 /**
2164  * \fn VSIVirtualHandle::Truncate( vsi_l_offset nNewSize )
2165  * \brief Truncate/expand the file to the specified size
2166 
2167  * This method goes through the VSIFileHandler virtualization and may
2168  * work on unusual filesystems such as in memory.
2169  *
2170  * Analog of the POSIX ftruncate() call.
2171  *
2172  * @param nNewSize new size in bytes.
2173  *
2174  * @return 0 on success
2175  * @since GDAL 1.9.0
2176  */
2177 
2178 /**
2179  * \brief Truncate/expand the file to the specified size
2180 
2181  * This method goes through the VSIFileHandler virtualization and may
2182  * work on unusual filesystems such as in memory.
2183  *
2184  * Analog of the POSIX ftruncate() call.
2185  *
2186  * @param fp file handle opened with VSIFOpenL().
2187  * @param nNewSize new size in bytes.
2188  *
2189  * @return 0 on success
2190  * @since GDAL 1.9.0
2191  */
2192 
VSIFTruncateL(VSILFILE * fp,vsi_l_offset nNewSize)2193 int VSIFTruncateL( VSILFILE * fp, vsi_l_offset nNewSize )
2194 
2195 {
2196     VSIVirtualHandle *poFileHandle = reinterpret_cast<VSIVirtualHandle *>( fp );
2197 
2198     return poFileHandle->Truncate(nNewSize);
2199 }
2200 
2201 /************************************************************************/
2202 /*                            VSIFPrintfL()                             */
2203 /************************************************************************/
2204 
2205 /**
2206  * \brief Formatted write to file.
2207  *
2208  * Provides fprintf() style formatted output to a VSI*L file.  This formats
2209  * an internal buffer which is written using VSIFWriteL().
2210  *
2211  * Analog of the POSIX fprintf() call.
2212  *
2213  * @param fp file handle opened with VSIFOpenL().
2214  * @param pszFormat the printf() style format string.
2215  *
2216  * @return the number of bytes written or -1 on an error.
2217  */
2218 
VSIFPrintfL(VSILFILE * fp,CPL_FORMAT_STRING (const char * pszFormat),...)2219 int VSIFPrintfL( VSILFILE *fp, CPL_FORMAT_STRING(const char *pszFormat), ... )
2220 
2221 {
2222     va_list args;
2223 
2224     va_start( args, pszFormat );
2225     CPLString osResult;
2226     osResult.vPrintf( pszFormat, args );
2227     va_end( args );
2228 
2229     return static_cast<int>(
2230         VSIFWriteL( osResult.c_str(), 1, osResult.length(), fp ));
2231 }
2232 
2233 /************************************************************************/
2234 /*                              VSIFPutcL()                              */
2235 /************************************************************************/
2236 
2237 // TODO: should we put in conformance with POSIX regarding the return
2238 // value. As of today (2015-08-29), no code in GDAL sources actually
2239 // check the return value.
2240 
2241 /**
2242  * \brief Write a single byte to the file
2243  *
2244  * Writes the character nChar, cast to an unsigned char, to file.
2245  *
2246  * Almost an analog of the POSIX  fputc() call, except that it returns
2247  * the  number of  character  written (1  or 0),  and  not the  (cast)
2248  * character itself or EOF.
2249  *
2250  * @param nChar character to write.
2251  * @param fp file handle opened with VSIFOpenL().
2252  *
2253  * @return 1 in case of success, 0 on error.
2254  */
2255 
VSIFPutcL(int nChar,VSILFILE * fp)2256 int VSIFPutcL( int nChar, VSILFILE * fp )
2257 
2258 {
2259     const unsigned char cChar = static_cast<unsigned char>(nChar);
2260     return static_cast<int>(VSIFWriteL(&cChar, 1, 1, fp));
2261 }
2262 
2263 /************************************************************************/
2264 /*                        VSIFGetRangeStatusL()                        */
2265 /************************************************************************/
2266 
2267 /**
2268  * \fn VSIVirtualHandle::GetRangeStatus( vsi_l_offset nOffset,
2269  *                                       vsi_l_offset nLength )
2270  * \brief Return if a given file range contains data or holes filled with zeroes
2271  *
2272  * This uses the filesystem capabilities of querying which regions of
2273  * a sparse file are allocated or not. This is currently only
2274  * implemented for Linux (and no other Unix derivatives) and Windows.
2275  *
2276  * Note: A return of VSI_RANGE_STATUS_DATA doesn't exclude that the
2277  * extent is filled with zeroes! It must be interpreted as "may
2278  * contain non-zero data".
2279  *
2280  * @param nOffset offset of the start of the extent.
2281  * @param nLength extent length.
2282  *
2283  * @return extent status: VSI_RANGE_STATUS_UNKNOWN, VSI_RANGE_STATUS_DATA or
2284  *         VSI_RANGE_STATUS_HOLE
2285  * @since GDAL 2.2
2286  */
2287 
2288 /**
2289  * \brief Return if a given file range contains data or holes filled with zeroes
2290  *
2291  * This uses the filesystem capabilities of querying which regions of
2292  * a sparse file are allocated or not. This is currently only
2293  * implemented for Linux (and no other Unix derivatives) and Windows.
2294  *
2295  * Note: A return of VSI_RANGE_STATUS_DATA doesn't exclude that the
2296  * extent is filled with zeroes! It must be interpreted as "may
2297  * contain non-zero data".
2298  *
2299  * @param fp file handle opened with VSIFOpenL().
2300  * @param nOffset offset of the start of the extent.
2301  * @param nLength extent length.
2302  *
2303  * @return extent status: VSI_RANGE_STATUS_UNKNOWN, VSI_RANGE_STATUS_DATA or
2304  *         VSI_RANGE_STATUS_HOLE
2305  * @since GDAL 2.2
2306  */
2307 
VSIFGetRangeStatusL(VSILFILE * fp,vsi_l_offset nOffset,vsi_l_offset nLength)2308 VSIRangeStatus VSIFGetRangeStatusL( VSILFILE * fp, vsi_l_offset nOffset,
2309                                     vsi_l_offset nLength )
2310 {
2311     VSIVirtualHandle *poFileHandle = reinterpret_cast<VSIVirtualHandle *>( fp );
2312 
2313     return poFileHandle->GetRangeStatus(nOffset, nLength);
2314 }
2315 
2316 /************************************************************************/
2317 /*                           VSIIngestFile()                            */
2318 /************************************************************************/
2319 
2320 /**
2321  * \brief Ingest a file into memory.
2322  *
2323  * Read the whole content of a file into a memory buffer.
2324  *
2325  * Either fp or pszFilename can be NULL, but not both at the same time.
2326  *
2327  * If fp is passed non-NULL, it is the responsibility of the caller to
2328  * close it.
2329  *
2330  * If non-NULL, the returned buffer is guaranteed to be NUL-terminated.
2331  *
2332  * @param fp file handle opened with VSIFOpenL().
2333  * @param pszFilename filename.
2334  * @param ppabyRet pointer to the target buffer. *ppabyRet must be freed with
2335  *                 VSIFree()
2336  * @param pnSize pointer to variable to store the file size. May be NULL.
2337  * @param nMaxSize maximum size of file allowed. If no limit, set to a negative
2338  *                 value.
2339  *
2340  * @return TRUE in case of success.
2341  *
2342  * @since GDAL 1.11
2343  */
2344 
VSIIngestFile(VSILFILE * fp,const char * pszFilename,GByte ** ppabyRet,vsi_l_offset * pnSize,GIntBig nMaxSize)2345 int VSIIngestFile( VSILFILE* fp,
2346                    const char* pszFilename,
2347                    GByte** ppabyRet,
2348                    vsi_l_offset* pnSize,
2349                    GIntBig nMaxSize )
2350 {
2351     if( fp == nullptr && pszFilename == nullptr )
2352         return FALSE;
2353     if( ppabyRet == nullptr )
2354         return FALSE;
2355 
2356     *ppabyRet = nullptr;
2357     if( pnSize != nullptr )
2358         *pnSize = 0;
2359 
2360     bool bFreeFP = false;
2361     if( nullptr == fp )
2362     {
2363         fp = VSIFOpenL( pszFilename, "rb" );
2364         if( nullptr == fp )
2365         {
2366             CPLError( CE_Failure, CPLE_FileIO,
2367                       "Cannot open file '%s'", pszFilename );
2368             return FALSE;
2369         }
2370         bFreeFP = true;
2371     }
2372     else
2373     {
2374         if( VSIFSeekL(fp, 0, SEEK_SET) != 0 )
2375             return FALSE;
2376     }
2377 
2378     vsi_l_offset nDataLen = 0;
2379 
2380     if( pszFilename == nullptr ||
2381         strcmp(pszFilename, "/vsistdin/") == 0 )
2382     {
2383         vsi_l_offset nDataAlloc = 0;
2384         if( VSIFSeekL( fp, 0, SEEK_SET ) != 0 )
2385         {
2386             if( bFreeFP )
2387                 CPL_IGNORE_RET_VAL(VSIFCloseL( fp ));
2388             return FALSE;
2389         }
2390         while( true )
2391         {
2392             if( nDataLen + 8192 + 1 > nDataAlloc )
2393             {
2394                 nDataAlloc = (nDataAlloc * 4) / 3 + 8192 + 1;
2395                 if( nDataAlloc >
2396                     static_cast<vsi_l_offset>(static_cast<size_t>(nDataAlloc)) )
2397                 {
2398                     CPLError( CE_Failure, CPLE_AppDefined,
2399                               "Input file too large to be opened" );
2400                     VSIFree( *ppabyRet );
2401                     *ppabyRet = nullptr;
2402                     if( bFreeFP )
2403                         CPL_IGNORE_RET_VAL(VSIFCloseL( fp ));
2404                     return FALSE;
2405                 }
2406                 GByte* pabyNew = static_cast<GByte *>(
2407                     VSIRealloc(*ppabyRet, static_cast<size_t>(nDataAlloc)) );
2408                 if( pabyNew == nullptr )
2409                 {
2410                     CPLError( CE_Failure, CPLE_OutOfMemory,
2411                               "Cannot allocate " CPL_FRMT_GIB " bytes",
2412                               nDataAlloc );
2413                     VSIFree( *ppabyRet );
2414                     *ppabyRet = nullptr;
2415                     if( bFreeFP )
2416                         CPL_IGNORE_RET_VAL(VSIFCloseL( fp ));
2417                     return FALSE;
2418                 }
2419                 *ppabyRet = pabyNew;
2420             }
2421             const int nRead = static_cast<int>(
2422                 VSIFReadL( *ppabyRet + nDataLen, 1, 8192, fp ) );
2423             nDataLen += nRead;
2424 
2425             if( nMaxSize >= 0 &&
2426                 nDataLen > static_cast<vsi_l_offset>(nMaxSize) )
2427             {
2428                 CPLError( CE_Failure, CPLE_AppDefined,
2429                           "Input file too large to be opened" );
2430                 VSIFree( *ppabyRet );
2431                 *ppabyRet = nullptr;
2432                 if( pnSize != nullptr )
2433                     *pnSize = 0;
2434                 if( bFreeFP )
2435                     CPL_IGNORE_RET_VAL(VSIFCloseL( fp ));
2436                 return FALSE;
2437             }
2438 
2439             if( pnSize != nullptr )
2440                 *pnSize += nRead;
2441             (*ppabyRet)[nDataLen] = '\0';
2442             if( nRead == 0 )
2443                 break;
2444         }
2445     }
2446     else
2447     {
2448         if( VSIFSeekL( fp, 0, SEEK_END ) != 0 )
2449         {
2450             if( bFreeFP )
2451                 CPL_IGNORE_RET_VAL(VSIFCloseL( fp ));
2452             return FALSE;
2453         }
2454         nDataLen = VSIFTellL( fp );
2455 
2456         // With "large" VSI I/O API we can read data chunks larger than
2457         // VSIMalloc could allocate. Catch it here.
2458         if( nDataLen != static_cast<vsi_l_offset>(static_cast<size_t>(nDataLen))
2459             || nDataLen + 1 < nDataLen
2460             // opening a directory returns nDataLen = INT_MAX (on 32bit) or INT64_MAX (on 64bit)
2461             || nDataLen + 1 > std::numeric_limits<size_t>::max() / 2
2462             || (nMaxSize >= 0 &&
2463                 nDataLen > static_cast<vsi_l_offset>(nMaxSize)) )
2464         {
2465             CPLError( CE_Failure, CPLE_AppDefined,
2466                       "Input file too large to be opened" );
2467             if( bFreeFP )
2468                 CPL_IGNORE_RET_VAL(VSIFCloseL( fp ));
2469             return FALSE;
2470         }
2471 
2472         if( VSIFSeekL( fp, 0, SEEK_SET ) != 0 )
2473         {
2474             if( bFreeFP )
2475                 CPL_IGNORE_RET_VAL(VSIFCloseL( fp ));
2476             return FALSE;
2477         }
2478 
2479         *ppabyRet = static_cast<GByte *>(
2480             VSIMalloc(static_cast<size_t>(nDataLen + 1)) );
2481         if( nullptr == *ppabyRet )
2482         {
2483             CPLError( CE_Failure, CPLE_OutOfMemory,
2484                       "Cannot allocate " CPL_FRMT_GIB " bytes",
2485                       nDataLen + 1 );
2486             if( bFreeFP )
2487                 CPL_IGNORE_RET_VAL(VSIFCloseL( fp ));
2488             return FALSE;
2489         }
2490 
2491         (*ppabyRet)[nDataLen] = '\0';
2492         if( nDataLen !=
2493             VSIFReadL(*ppabyRet, 1, static_cast<size_t>(nDataLen), fp) )
2494         {
2495             CPLError( CE_Failure, CPLE_FileIO,
2496                       "Cannot read " CPL_FRMT_GIB " bytes",
2497                       nDataLen );
2498             VSIFree( *ppabyRet );
2499             *ppabyRet = nullptr;
2500             if( bFreeFP )
2501                 CPL_IGNORE_RET_VAL(VSIFCloseL( fp ));
2502             return FALSE;
2503         }
2504         if( pnSize != nullptr )
2505             *pnSize = nDataLen;
2506     }
2507     if( bFreeFP )
2508         CPL_IGNORE_RET_VAL(VSIFCloseL( fp ));
2509     return TRUE;
2510 }
2511 
2512 
2513 /************************************************************************/
2514 /*                         VSIOverwriteFile()                           */
2515 /************************************************************************/
2516 
2517 /**
2518  * \brief Overwrite an existing file with content from another one
2519  *
2520  * @param fpTarget file handle opened with VSIFOpenL() with "rb+" flag.
2521  * @param pszSourceFilename source filename
2522  *
2523  * @return TRUE in case of success.
2524  *
2525  * @since GDAL 3.1
2526  */
2527 
VSIOverwriteFile(VSILFILE * fpTarget,const char * pszSourceFilename)2528 int VSIOverwriteFile( VSILFILE* fpTarget, const char* pszSourceFilename )
2529 {
2530     VSILFILE* fpSource = VSIFOpenL(pszSourceFilename, "rb");
2531     if( fpSource == nullptr )
2532     {
2533         CPLError(CE_Failure, CPLE_FileIO,
2534                  "Cannot open %s", pszSourceFilename);
2535         return false;
2536     }
2537 
2538     const size_t nBufferSize = 4096;
2539     void* pBuffer = CPLMalloc(nBufferSize);
2540     VSIFSeekL( fpTarget, 0, SEEK_SET );
2541     bool bRet = true;
2542     while( true )
2543     {
2544         size_t nRead = VSIFReadL( pBuffer, 1, nBufferSize, fpSource );
2545         size_t nWritten = VSIFWriteL( pBuffer, 1, nRead, fpTarget );
2546         if( nWritten != nRead )
2547         {
2548             bRet = false;
2549             break;
2550         }
2551         if( nRead < nBufferSize )
2552             break;
2553     }
2554 
2555     if( bRet )
2556     {
2557         bRet = VSIFTruncateL( fpTarget, VSIFTellL(fpTarget) ) == 0;
2558         if( !bRet )
2559         {
2560             CPLError(CE_Failure, CPLE_FileIO, "Truncation failed");
2561         }
2562     }
2563 
2564     CPLFree(pBuffer);
2565     VSIFCloseL(fpSource);
2566     return bRet;
2567 }
2568 
2569 /************************************************************************/
2570 /*                        VSIFGetNativeFileDescriptorL()                */
2571 /************************************************************************/
2572 
2573 /**
2574  * \fn VSIVirtualHandle::GetNativeFileDescriptor()
2575  * \brief Returns the "native" file descriptor for the virtual handle.
2576  *
2577  * This will only return a non-NULL value for "real" files handled by the
2578  * operating system (to be opposed to GDAL virtual file systems).
2579  *
2580  * On POSIX systems, this will be a integer value ("fd") cast as a void*.
2581  * On Windows systems, this will be the HANDLE.
2582  *
2583  * @return the native file descriptor, or NULL.
2584  */
2585 
2586 /**
2587  * \brief Returns the "native" file descriptor for the virtual handle.
2588  *
2589  * This will only return a non-NULL value for "real" files handled by the
2590  * operating system (to be opposed to GDAL virtual file systems).
2591  *
2592  * On POSIX systems, this will be a integer value ("fd") cast as a void*.
2593  * On Windows systems, this will be the HANDLE.
2594  *
2595  * @param fp file handle opened with VSIFOpenL().
2596  *
2597  * @return the native file descriptor, or NULL.
2598  */
2599 
VSIFGetNativeFileDescriptorL(VSILFILE * fp)2600 void *VSIFGetNativeFileDescriptorL( VSILFILE* fp )
2601 {
2602     VSIVirtualHandle *poFileHandle = reinterpret_cast<VSIVirtualHandle *>( fp );
2603 
2604     return poFileHandle->GetNativeFileDescriptor();
2605 }
2606 
2607 /************************************************************************/
2608 /*                      VSIGetDiskFreeSpace()                           */
2609 /************************************************************************/
2610 
2611 /**
2612  * \brief Return free disk space available on the filesystem.
2613  *
2614  * This function returns the free disk space available on the filesystem.
2615  *
2616  * @param pszDirname a directory of the filesystem to query.
2617  * @return The free space in bytes. Or -1 in case of error.
2618  * @since GDAL 2.1
2619  */
2620 
VSIGetDiskFreeSpace(const char * pszDirname)2621 GIntBig VSIGetDiskFreeSpace( const char *pszDirname )
2622 {
2623     VSIFilesystemHandler *poFSHandler =
2624         VSIFileManager::GetHandler( pszDirname );
2625 
2626     return poFSHandler->GetDiskFreeSpace( pszDirname );
2627 }
2628 
2629 /************************************************************************/
2630 /*                    VSIGetFileSystemsPrefixes()                       */
2631 /************************************************************************/
2632 
2633 /**
2634  * \brief Return the list of prefixes for virtual file system handlers
2635  * currently registered.
2636  *
2637  * Typically: "", "/vsimem/", "/vsicurl/", etc
2638  *
2639  * @return a NULL terminated list of prefixes. Must be freed with CSLDestroy()
2640  * @since GDAL 2.3
2641  */
2642 
VSIGetFileSystemsPrefixes(void)2643 char **VSIGetFileSystemsPrefixes( void )
2644 {
2645     return VSIFileManager::GetPrefixes();
2646 }
2647 
2648 /************************************************************************/
2649 /*                     VSIGetFileSystemOptions()                        */
2650 /************************************************************************/
2651 
2652 /**
2653  * \brief Return the list of options associated with a virtual file system handler
2654  * as a serialized XML string.
2655  *
2656  * Those options may be set as configuration options with CPLSetConfigOption().
2657  *
2658  * @param pszFilename a filename, or prefix of a virtual file system handler.
2659  * @return a string, which must not be freed, or NULL if no options is declared.
2660  * @since GDAL 2.3
2661  */
2662 
VSIGetFileSystemOptions(const char * pszFilename)2663 const char* VSIGetFileSystemOptions( const char* pszFilename )
2664 {
2665     VSIFilesystemHandler *poFSHandler =
2666         VSIFileManager::GetHandler( pszFilename );
2667 
2668     return poFSHandler->GetOptions();
2669 }
2670 
2671 /************************************************************************/
2672 /* ==================================================================== */
2673 /*                           VSIFileManager()                           */
2674 /* ==================================================================== */
2675 /************************************************************************/
2676 
2677 #ifndef DOXYGEN_SKIP
2678 
2679 /*
2680 ** Notes on Multithreading:
2681 **
2682 ** The VSIFileManager maintains a list of file type handlers (mem, large
2683 ** file, etc).  It should be thread safe.
2684 **/
2685 
2686 /************************************************************************/
2687 /*                           VSIFileManager()                           */
2688 /************************************************************************/
2689 
VSIFileManager()2690 VSIFileManager::VSIFileManager() :
2691     poDefaultHandler(nullptr)
2692 {}
2693 
2694 /************************************************************************/
2695 /*                          ~VSIFileManager()                           */
2696 /************************************************************************/
2697 
~VSIFileManager()2698 VSIFileManager::~VSIFileManager()
2699 {
2700     std::set<VSIFilesystemHandler*> oSetAlreadyDeleted;
2701     for( std::map<std::string, VSIFilesystemHandler*>::const_iterator iter =
2702              oHandlers.begin();
2703          iter != oHandlers.end();
2704          ++iter )
2705     {
2706         if( oSetAlreadyDeleted.find(iter->second) == oSetAlreadyDeleted.end() )
2707         {
2708             oSetAlreadyDeleted.insert(iter->second);
2709             delete iter->second;
2710         }
2711     }
2712 
2713     delete poDefaultHandler;
2714 }
2715 
2716 /************************************************************************/
2717 /*                                Get()                                 */
2718 /************************************************************************/
2719 
2720 static VSIFileManager *poManager = nullptr;
2721 static CPLMutex* hVSIFileManagerMutex = nullptr;
2722 
Get()2723 VSIFileManager *VSIFileManager::Get()
2724 {
2725       CPLMutexHolder oHolder(&hVSIFileManagerMutex);
2726       if ( poManager != nullptr ) {
2727         return poManager;
2728       }
2729 
2730       poManager = new VSIFileManager;
2731       VSIInstallLargeFileHandler();
2732       VSIInstallSubFileHandler();
2733       VSIInstallMemFileHandler();
2734 #ifdef HAVE_LIBZ
2735       VSIInstallGZipFileHandler();
2736       VSIInstallZipFileHandler();
2737 #endif
2738 #ifdef HAVE_CURL
2739       VSIInstallCurlFileHandler();
2740       VSIInstallCurlStreamingFileHandler();
2741       VSIInstallS3FileHandler();
2742       VSIInstallS3StreamingFileHandler();
2743       VSIInstallGSFileHandler();
2744       VSIInstallGSStreamingFileHandler();
2745       VSIInstallAzureFileHandler();
2746       VSIInstallAzureStreamingFileHandler();
2747       VSIInstallADLSFileHandler();
2748       VSIInstallOSSFileHandler();
2749       VSIInstallOSSStreamingFileHandler();
2750       VSIInstallSwiftFileHandler();
2751       VSIInstallSwiftStreamingFileHandler();
2752       VSIInstallWebHdfsHandler();
2753 #endif
2754       VSIInstallStdinHandler();
2755       VSIInstallHdfsHandler();
2756       VSIInstallStdoutHandler();
2757       VSIInstallSparseFileHandler();
2758       VSIInstallTarFileHandler();
2759       VSIInstallCryptFileHandler();
2760 
2761       return poManager;
2762 
2763 }
2764 
2765 /************************************************************************/
2766 /*                           GetPrefixes()                              */
2767 /************************************************************************/
2768 
GetPrefixes()2769 char ** VSIFileManager::GetPrefixes()
2770 {
2771     CPLMutexHolder oHolder( &hVSIFileManagerMutex );
2772     CPLStringList aosList;
2773     for( const auto& oIter: Get()->oHandlers )
2774     {
2775         if( oIter.first != "/vsicurl?" )
2776         {
2777             aosList.AddString( oIter.first.c_str() );
2778         }
2779     }
2780     return aosList.StealList();
2781 }
2782 
2783 /************************************************************************/
2784 /*                             GetHandler()                             */
2785 /************************************************************************/
2786 
GetHandler(const char * pszPath)2787 VSIFilesystemHandler *VSIFileManager::GetHandler( const char *pszPath )
2788 
2789 {
2790     VSIFileManager *poThis = Get();
2791     const size_t nPathLen = strlen(pszPath);
2792 
2793     for( std::map<std::string, VSIFilesystemHandler*>::const_iterator iter =
2794              poThis->oHandlers.begin();
2795          iter != poThis->oHandlers.end();
2796          ++iter )
2797     {
2798         const char* pszIterKey = iter->first.c_str();
2799         const size_t nIterKeyLen = iter->first.size();
2800         if( strncmp(pszPath, pszIterKey, nIterKeyLen) == 0 )
2801             return iter->second;
2802 
2803         // "/vsimem\foo" should be handled as "/vsimem/foo".
2804         if( nIterKeyLen && nPathLen > nIterKeyLen &&
2805             pszIterKey[nIterKeyLen-1] == '/' &&
2806             pszPath[nIterKeyLen-1] == '\\' &&
2807             strncmp(pszPath, pszIterKey, nIterKeyLen - 1) == 0 )
2808             return iter->second;
2809 
2810         // /vsimem should be treated as a match for /vsimem/.
2811         if( nPathLen + 1 == nIterKeyLen
2812             && strncmp(pszPath, pszIterKey, nPathLen) == 0 )
2813             return iter->second;
2814     }
2815 
2816     return poThis->poDefaultHandler;
2817 }
2818 
2819 /************************************************************************/
2820 /*                           InstallHandler()                           */
2821 /************************************************************************/
2822 
InstallHandler(const std::string & osPrefix,VSIFilesystemHandler * poHandler)2823 void VSIFileManager::InstallHandler( const std::string& osPrefix,
2824                                      VSIFilesystemHandler *poHandler )
2825 
2826 {
2827     if( osPrefix == "" )
2828         Get()->poDefaultHandler = poHandler;
2829     else
2830         Get()->oHandlers[osPrefix] = poHandler;
2831 }
2832 
2833 /************************************************************************/
2834 /*                       VSICleanupFileManager()                        */
2835 /************************************************************************/
2836 
VSICleanupFileManager()2837 void VSICleanupFileManager()
2838 
2839 {
2840     if( poManager )
2841     {
2842         delete poManager;
2843         poManager = nullptr;
2844     }
2845 
2846     if( hVSIFileManagerMutex != nullptr )
2847     {
2848         CPLDestroyMutex(hVSIFileManagerMutex);
2849         hVSIFileManagerMutex = nullptr;
2850     }
2851 }
2852 
2853 /************************************************************************/
2854 /*                            Truncate()                                */
2855 /************************************************************************/
2856 
Truncate(vsi_l_offset nNewSize)2857 int VSIVirtualHandle::Truncate( vsi_l_offset nNewSize )
2858 {
2859     const vsi_l_offset nOriginalPos = Tell();
2860     if( Seek(0, SEEK_END) == 0 && nNewSize >= Tell() )
2861     {
2862         // Fill with zeroes
2863         std::vector<GByte> aoBytes(4096, 0);
2864         vsi_l_offset nCurOffset = nOriginalPos;
2865         while( nCurOffset < nNewSize )
2866         {
2867             constexpr vsi_l_offset nMaxOffset = 4096;
2868             const int nSize =
2869                 static_cast<int>(
2870                     std::min(nMaxOffset, nNewSize - nCurOffset));
2871             if( Write(&aoBytes[0], nSize, 1) != 1 )
2872             {
2873                 Seek( nOriginalPos, SEEK_SET );
2874                 return -1;
2875             }
2876             nCurOffset += nSize;
2877         }
2878         return Seek(nOriginalPos, SEEK_SET) == 0 ? 0 : -1;
2879     }
2880 
2881     CPLDebug("VSI",
2882              "Truncation is not supported in generic implementation "
2883              "of Truncate()");
2884     Seek( nOriginalPos, SEEK_SET );
2885     return -1;
2886 }
2887 
2888 /************************************************************************/
2889 /*                           ReadMultiRange()                           */
2890 /************************************************************************/
2891 
ReadMultiRange(int nRanges,void ** ppData,const vsi_l_offset * panOffsets,const size_t * panSizes)2892 int VSIVirtualHandle::ReadMultiRange( int nRanges, void ** ppData,
2893                                       const vsi_l_offset* panOffsets,
2894                                       const size_t* panSizes )
2895 {
2896     int nRet = 0;
2897     const vsi_l_offset nCurOffset = Tell();
2898     for( int i=0; i<nRanges; i++ )
2899     {
2900         if( Seek(panOffsets[i], SEEK_SET) < 0 )
2901         {
2902             nRet = -1;
2903             break;
2904         }
2905 
2906         const size_t nRead = Read(ppData[i], 1, panSizes[i]);
2907         if( panSizes[i] != nRead )
2908         {
2909             nRet = -1;
2910             break;
2911         }
2912     }
2913 
2914     Seek(nCurOffset, SEEK_SET);
2915 
2916     return nRet;
2917 }
2918 
2919 #endif  // #ifndef DOXYGEN_SKIP
2920