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