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