/src/gdal/port/cpl_vsil.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | char **VSIReadDir(const char *pszPath) |
74 | 0 | { |
75 | 0 | return VSIReadDirEx(pszPath, 0); |
76 | 0 | } |
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 | | char **VSIReadDirEx(const char *pszPath, int nMaxFiles) |
108 | 0 | { |
109 | 0 | VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath); |
110 | |
|
111 | 0 | return poFSHandler->ReadDirEx(pszPath, nMaxFiles); |
112 | 0 | } |
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 | | char **VSISiblingFiles(const char *pszFilename) |
136 | 0 | { |
137 | 0 | VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename); |
138 | |
|
139 | 0 | return poFSHandler->SiblingFiles(pszFilename); |
140 | 0 | } |
141 | | |
142 | | /************************************************************************/ |
143 | | /* VSIFnMatch() */ |
144 | | /************************************************************************/ |
145 | | |
146 | | static bool VSIFnMatch(const char *pszPattern, const char *pszStr) |
147 | 0 | { |
148 | 0 | for (; *pszPattern && *pszStr; pszPattern++, pszStr++) |
149 | 0 | { |
150 | 0 | if (*pszPattern == '*') |
151 | 0 | { |
152 | 0 | if (pszPattern[1] == 0) |
153 | 0 | return true; |
154 | 0 | for (; *pszStr; ++pszStr) |
155 | 0 | { |
156 | 0 | if (VSIFnMatch(pszPattern + 1, pszStr)) |
157 | 0 | return true; |
158 | 0 | } |
159 | 0 | return false; |
160 | 0 | } |
161 | 0 | else if (*pszPattern == '?') |
162 | 0 | { |
163 | | // match single any char |
164 | 0 | } |
165 | 0 | else if (*pszPattern == '[') |
166 | 0 | { |
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 | 0 | const char *pszOpenBracket = pszPattern; |
176 | 0 | ++pszPattern; |
177 | 0 | const bool isNot = (*pszPattern == '!'); |
178 | 0 | if (isNot) |
179 | 0 | { |
180 | 0 | ++pszOpenBracket; |
181 | 0 | ++pszPattern; |
182 | 0 | } |
183 | 0 | bool res = false; |
184 | 0 | for (; *pszPattern; ++pszPattern) |
185 | 0 | { |
186 | 0 | if ((*pszPattern == ']' || *pszPattern == '-') && |
187 | 0 | pszPattern == pszOpenBracket + 1) |
188 | 0 | { |
189 | 0 | if (*pszStr == *pszPattern) |
190 | 0 | { |
191 | 0 | res = true; |
192 | 0 | } |
193 | 0 | } |
194 | 0 | else if (*pszPattern == ']') |
195 | 0 | { |
196 | 0 | break; |
197 | 0 | } |
198 | 0 | else if (pszPattern[1] == '-' && pszPattern[2] != 0 && |
199 | 0 | pszPattern[2] != ']') |
200 | 0 | { |
201 | 0 | if (*pszStr >= pszPattern[0] && *pszStr <= pszPattern[2]) |
202 | 0 | { |
203 | 0 | res = true; |
204 | 0 | } |
205 | 0 | pszPattern += 2; |
206 | 0 | } |
207 | 0 | else if (*pszStr == *pszPattern) |
208 | 0 | { |
209 | 0 | res = true; |
210 | 0 | } |
211 | 0 | } |
212 | 0 | if (*pszPattern == 0) |
213 | 0 | return false; |
214 | 0 | if (!res && !isNot) |
215 | 0 | return false; |
216 | 0 | if (res && isNot) |
217 | 0 | return false; |
218 | 0 | } |
219 | 0 | else if (*pszPattern != *pszStr) |
220 | 0 | { |
221 | 0 | return false; |
222 | 0 | } |
223 | 0 | } |
224 | 0 | return *pszPattern == 0 && *pszStr == 0; |
225 | 0 | } |
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 | | char **VSIGlob(const char *pszPattern, const char *const *papszOptions, |
293 | | GDALProgressFunc pProgressFunc, void *pProgressData) |
294 | 0 | { |
295 | 0 | CPL_IGNORE_RET_VAL(papszOptions); |
296 | |
|
297 | 0 | CPLStringList aosRes; |
298 | 0 | std::vector<std::pair<std::string, size_t>> candidates; |
299 | 0 | candidates.emplace_back(pszPattern, 0); |
300 | 0 | while (!candidates.empty()) |
301 | 0 | { |
302 | 0 | auto [osPattern, nPosStart] = candidates.back(); |
303 | 0 | pszPattern = osPattern.c_str() + nPosStart; |
304 | 0 | candidates.pop_back(); |
305 | |
|
306 | 0 | std::string osPath = osPattern.substr(0, nPosStart); |
307 | 0 | std::string osCurPath; |
308 | 0 | for (;; ++pszPattern) |
309 | 0 | { |
310 | 0 | if (*pszPattern == 0 || *pszPattern == '/' || *pszPattern == '\\') |
311 | 0 | { |
312 | 0 | struct VSIDirCloser |
313 | 0 | { |
314 | 0 | void operator()(VSIDIR *dir) |
315 | 0 | { |
316 | 0 | VSICloseDir(dir); |
317 | 0 | } |
318 | 0 | }; |
319 | |
|
320 | 0 | if (osCurPath == "**") |
321 | 0 | { |
322 | 0 | std::unique_ptr<VSIDIR, VSIDirCloser> psDir( |
323 | 0 | VSIOpenDir(osPath.c_str(), -1, nullptr)); |
324 | 0 | if (!psDir) |
325 | 0 | return nullptr; |
326 | 0 | while (const VSIDIREntry *psEntry = |
327 | 0 | VSIGetNextDirEntry(psDir.get())) |
328 | 0 | { |
329 | 0 | if (pProgressFunc && |
330 | 0 | !pProgressFunc(0, "", pProgressData)) |
331 | 0 | { |
332 | 0 | return nullptr; |
333 | 0 | } |
334 | 0 | { |
335 | 0 | std::string osCandidate(osPath); |
336 | 0 | osCandidate += psEntry->pszName; |
337 | 0 | nPosStart = osCandidate.size(); |
338 | 0 | if (*pszPattern) |
339 | 0 | { |
340 | 0 | osCandidate += pszPattern; |
341 | 0 | } |
342 | 0 | candidates.emplace_back(std::move(osCandidate), |
343 | 0 | nPosStart); |
344 | 0 | } |
345 | 0 | } |
346 | 0 | osPath.clear(); |
347 | 0 | break; |
348 | 0 | } |
349 | 0 | else if (osCurPath.find_first_of("*?[") != std::string::npos) |
350 | 0 | { |
351 | 0 | std::unique_ptr<VSIDIR, VSIDirCloser> psDir( |
352 | 0 | VSIOpenDir(osPath.c_str(), 0, nullptr)); |
353 | 0 | if (!psDir) |
354 | 0 | return nullptr; |
355 | 0 | while (const VSIDIREntry *psEntry = |
356 | 0 | VSIGetNextDirEntry(psDir.get())) |
357 | 0 | { |
358 | 0 | if (pProgressFunc && |
359 | 0 | !pProgressFunc(0, "", pProgressData)) |
360 | 0 | { |
361 | 0 | return nullptr; |
362 | 0 | } |
363 | 0 | if (VSIFnMatch(osCurPath.c_str(), psEntry->pszName)) |
364 | 0 | { |
365 | 0 | std::string osCandidate(osPath); |
366 | 0 | osCandidate += psEntry->pszName; |
367 | 0 | nPosStart = osCandidate.size(); |
368 | 0 | if (*pszPattern) |
369 | 0 | { |
370 | 0 | osCandidate += pszPattern; |
371 | 0 | } |
372 | 0 | candidates.emplace_back(std::move(osCandidate), |
373 | 0 | nPosStart); |
374 | 0 | } |
375 | 0 | } |
376 | 0 | osPath.clear(); |
377 | 0 | break; |
378 | 0 | } |
379 | 0 | else if (*pszPattern == 0) |
380 | 0 | { |
381 | 0 | osPath += osCurPath; |
382 | 0 | break; |
383 | 0 | } |
384 | 0 | else |
385 | 0 | { |
386 | 0 | osPath += osCurPath; |
387 | 0 | osPath += *pszPattern; |
388 | 0 | osCurPath.clear(); |
389 | 0 | } |
390 | 0 | } |
391 | 0 | else |
392 | 0 | { |
393 | 0 | osCurPath += *pszPattern; |
394 | 0 | } |
395 | 0 | } |
396 | 0 | if (!osPath.empty()) |
397 | 0 | { |
398 | 0 | VSIStatBufL sStat; |
399 | 0 | if (VSIStatL(osPath.c_str(), &sStat) == 0) |
400 | 0 | aosRes.AddString(osPath.c_str()); |
401 | 0 | } |
402 | 0 | } |
403 | | |
404 | 0 | return aosRes.StealList(); |
405 | 0 | } |
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 | | const char *VSIGetDirectorySeparator(const char *pszPath) |
420 | 0 | { |
421 | 0 | if (STARTS_WITH(pszPath, "http://") || STARTS_WITH(pszPath, "https://")) |
422 | 0 | return "/"; |
423 | | |
424 | 0 | VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath); |
425 | 0 | return poFSHandler->GetDirectorySeparator(pszPath); |
426 | 0 | } |
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 | | char **VSIReadDirRecursive(const char *pszPathIn) |
460 | 0 | { |
461 | 0 | const char SEP = VSIGetDirectorySeparator(pszPathIn)[0]; |
462 | |
|
463 | 0 | const char *const apszOptions[] = {"NAME_AND_TYPE_ONLY=YES", nullptr}; |
464 | 0 | VSIDIR *psDir = VSIOpenDir(pszPathIn, -1, apszOptions); |
465 | 0 | if (!psDir) |
466 | 0 | return nullptr; |
467 | 0 | CPLStringList oFiles; |
468 | 0 | while (auto psEntry = VSIGetNextDirEntry(psDir)) |
469 | 0 | { |
470 | 0 | if (VSI_ISDIR(psEntry->nMode) && psEntry->pszName[0] && |
471 | 0 | psEntry->pszName[strlen(psEntry->pszName) - 1] != SEP) |
472 | 0 | { |
473 | 0 | oFiles.AddString((std::string(psEntry->pszName) + SEP).c_str()); |
474 | 0 | } |
475 | 0 | else |
476 | 0 | { |
477 | 0 | oFiles.AddString(psEntry->pszName); |
478 | 0 | } |
479 | 0 | } |
480 | 0 | VSICloseDir(psDir); |
481 | |
|
482 | 0 | return oFiles.StealList(); |
483 | 0 | } |
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 | | char **CPLReadDir(const char *pszPath) |
498 | 0 | { |
499 | 0 | return VSIReadDir(pszPath); |
500 | 0 | } |
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 | | VSIDIR *VSIOpenDir(const char *pszPath, int nRecurseDepth, |
543 | | const char *const *papszOptions) |
544 | 0 | { |
545 | 0 | VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath); |
546 | |
|
547 | 0 | return poFSHandler->OpenDir(pszPath, nRecurseDepth, papszOptions); |
548 | 0 | } |
549 | | |
550 | | /************************************************************************/ |
551 | | /* VSIGetNextDirEntry() */ |
552 | | /************************************************************************/ |
553 | | |
554 | | /** |
555 | | * \brief Return the next entry of the directory |
556 | | * |
557 | | * This function is close to the POSIX readdir() function. It actually returns |
558 | | * more information (file size, last modification time), which on 'real' file |
559 | | * systems involve one 'stat' call per file. |
560 | | * |
561 | | * For filesystems that can have both a regular file and a directory name of |
562 | | * the same name (typically /vsis3/), when this situation of duplicate happens, |
563 | | * the directory name will be suffixed by a slash character. Otherwise directory |
564 | | * names are not suffixed by slash. |
565 | | * |
566 | | * The returned entry remains valid until the next call to VSINextDirEntry() |
567 | | * or VSICloseDir() with the same handle. |
568 | | * |
569 | | * Note: since GDAL 3.9, for recursive mode, the directory separator will no |
570 | | * longer be always forward slash, but will be the one returned by |
571 | | * VSIGetDirectorySeparator(pszPathIn), so potentially backslash on Windows |
572 | | * file systems. |
573 | | * |
574 | | * @param dir Directory handled returned by VSIOpenDir(). Must not be NULL. |
575 | | * |
576 | | * @return a entry, or NULL if there is no more entry in the directory. This |
577 | | * return value must not be freed. |
578 | | * @since GDAL 2.4 |
579 | | * |
580 | | */ |
581 | | |
582 | | const VSIDIREntry *VSIGetNextDirEntry(VSIDIR *dir) |
583 | 0 | { |
584 | 0 | return dir->NextDirEntry(); |
585 | 0 | } |
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 | | void VSICloseDir(VSIDIR *dir) |
602 | 0 | { |
603 | 0 | delete dir; |
604 | 0 | } |
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 | | int VSIMkdir(const char *pszPathname, long mode) |
627 | | |
628 | 0 | { |
629 | 0 | VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPathname); |
630 | |
|
631 | 0 | return poFSHandler->Mkdir(pszPathname, mode); |
632 | 0 | } |
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 | | int VSIMkdirRecursive(const char *pszPathname, long mode) |
649 | 5.68k | { |
650 | 5.68k | if (pszPathname == nullptr || pszPathname[0] == '\0' || |
651 | 5.68k | strncmp("/", pszPathname, 2) == 0) |
652 | 0 | { |
653 | 0 | return -1; |
654 | 0 | } |
655 | | |
656 | 5.68k | const CPLString osPathname(pszPathname); |
657 | 5.68k | VSIStatBufL sStat; |
658 | 5.68k | if (VSIStatL(osPathname, &sStat) == 0) |
659 | 5.68k | { |
660 | 5.68k | return VSI_ISDIR(sStat.st_mode) ? 0 : -1; |
661 | 5.68k | } |
662 | 0 | const std::string osParentPath(CPLGetPathSafe(osPathname)); |
663 | | |
664 | | // Prevent crazy paths from recursing forever. |
665 | 0 | if (osParentPath == osPathname || |
666 | 0 | osParentPath.length() >= osPathname.length()) |
667 | 0 | { |
668 | 0 | return -1; |
669 | 0 | } |
670 | | |
671 | 0 | if (!osParentPath.empty() && VSIStatL(osParentPath.c_str(), &sStat) != 0) |
672 | 0 | { |
673 | 0 | if (VSIMkdirRecursive(osParentPath.c_str(), mode) != 0) |
674 | 0 | return -1; |
675 | 0 | } |
676 | | |
677 | 0 | return VSIMkdir(osPathname, mode); |
678 | 0 | } |
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 | | int VSIUnlink(const char *pszFilename) |
700 | | |
701 | 5.68k | { |
702 | 5.68k | VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename); |
703 | | |
704 | 5.68k | return poFSHandler->Unlink(pszFilename); |
705 | 5.68k | } |
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 | | int *VSIUnlinkBatch(CSLConstList papszFiles) |
731 | 0 | { |
732 | 0 | VSIFilesystemHandler *poFSHandler = nullptr; |
733 | 0 | for (CSLConstList papszIter = papszFiles; papszIter && *papszIter; |
734 | 0 | ++papszIter) |
735 | 0 | { |
736 | 0 | auto poFSHandlerThisFile = VSIFileManager::GetHandler(*papszIter); |
737 | 0 | if (poFSHandler == nullptr) |
738 | 0 | poFSHandler = poFSHandlerThisFile; |
739 | 0 | else if (poFSHandler != poFSHandlerThisFile) |
740 | 0 | { |
741 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
742 | 0 | "Files belong to different file system handlers"); |
743 | 0 | poFSHandler = nullptr; |
744 | 0 | break; |
745 | 0 | } |
746 | 0 | } |
747 | 0 | if (poFSHandler == nullptr) |
748 | 0 | return nullptr; |
749 | 0 | return poFSHandler->UnlinkBatch(papszFiles); |
750 | 0 | } |
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. If 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 | | int VSIRename(const char *oldpath, const char *newpath) |
781 | | |
782 | 0 | { |
783 | 0 | VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(oldpath); |
784 | |
|
785 | 0 | return poFSHandler->Rename(oldpath, newpath, nullptr, nullptr); |
786 | 0 | } |
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 | | int VSIMove(const char *oldpath, const char *newpath, |
815 | | const char *const *papszOptions, GDALProgressFunc pProgressFunc, |
816 | | void *pProgressData) |
817 | 0 | { |
818 | |
|
819 | 0 | if (strcmp(oldpath, newpath) == 0) |
820 | 0 | return 0; |
821 | | |
822 | 0 | VSIFilesystemHandler *poOldFSHandler = VSIFileManager::GetHandler(oldpath); |
823 | 0 | VSIFilesystemHandler *poNewFSHandler = VSIFileManager::GetHandler(newpath); |
824 | |
|
825 | 0 | VSIStatBufL sStat; |
826 | 0 | if (VSIStatL(oldpath, &sStat) != 0) |
827 | 0 | { |
828 | 0 | CPLDebug("VSI", "%s is not a object", oldpath); |
829 | 0 | errno = ENOENT; |
830 | 0 | return -1; |
831 | 0 | } |
832 | | |
833 | 0 | std::string sNewpath(newpath); |
834 | 0 | VSIStatBufL sStatNew; |
835 | 0 | if (VSIStatL(newpath, &sStatNew) == 0 && VSI_ISDIR(sStatNew.st_mode)) |
836 | 0 | { |
837 | 0 | sNewpath = |
838 | 0 | CPLFormFilenameSafe(newpath, CPLGetFilename(oldpath), nullptr); |
839 | 0 | } |
840 | |
|
841 | 0 | int ret = 0; |
842 | |
|
843 | 0 | if (poOldFSHandler == poNewFSHandler) |
844 | 0 | { |
845 | 0 | ret = poOldFSHandler->Rename(oldpath, sNewpath.c_str(), pProgressFunc, |
846 | 0 | pProgressData); |
847 | 0 | if (ret == 0 && pProgressFunc) |
848 | 0 | ret = pProgressFunc(1.0, "", pProgressData) ? 0 : -1; |
849 | 0 | return ret; |
850 | 0 | } |
851 | | |
852 | 0 | if (VSI_ISDIR(sStat.st_mode)) |
853 | 0 | { |
854 | 0 | const CPLStringList aosList(VSIReadDir(oldpath)); |
855 | 0 | poNewFSHandler->Mkdir(sNewpath.c_str(), 0755); |
856 | 0 | bool bFoundFiles = false; |
857 | 0 | const int nListSize = aosList.size(); |
858 | 0 | for (int i = 0; ret == 0 && i < nListSize; i++) |
859 | 0 | { |
860 | 0 | if (strcmp(aosList[i], ".") != 0 && strcmp(aosList[i], "..") != 0) |
861 | 0 | { |
862 | 0 | bFoundFiles = true; |
863 | 0 | const std::string osSrc = |
864 | 0 | CPLFormFilenameSafe(oldpath, aosList[i], nullptr); |
865 | 0 | const std::string osTarget = |
866 | 0 | CPLFormFilenameSafe(sNewpath.c_str(), aosList[i], nullptr); |
867 | 0 | void *pScaledProgress = GDALCreateScaledProgress( |
868 | 0 | static_cast<double>(i) / nListSize, |
869 | 0 | static_cast<double>(i + 1) / nListSize, pProgressFunc, |
870 | 0 | pProgressData); |
871 | 0 | ret = VSIMove(osSrc.c_str(), osTarget.c_str(), papszOptions, |
872 | 0 | pScaledProgress ? GDALScaledProgress : nullptr, |
873 | 0 | pScaledProgress); |
874 | 0 | GDALDestroyScaledProgress(pScaledProgress); |
875 | 0 | } |
876 | 0 | } |
877 | 0 | if (!bFoundFiles) |
878 | 0 | ret = VSIStatL(sNewpath.c_str(), &sStat); |
879 | 0 | if (ret == 0) |
880 | 0 | ret = poOldFSHandler->Rmdir(oldpath); |
881 | 0 | } |
882 | 0 | else |
883 | 0 | { |
884 | 0 | ret = VSICopyFile(oldpath, sNewpath.c_str(), nullptr, sStat.st_size, |
885 | 0 | nullptr, pProgressFunc, pProgressData) == 0 && |
886 | 0 | VSIUnlink(oldpath) == 0 |
887 | 0 | ? 0 |
888 | 0 | : -1; |
889 | 0 | } |
890 | 0 | if (ret == 0 && pProgressFunc) |
891 | 0 | ret = pProgressFunc(1.0, "", pProgressData) ? 0 : -1; |
892 | 0 | return ret; |
893 | 0 | } |
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 | | 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 | 0 | { |
935 | 0 | if (!pszSource && !fpSource) |
936 | 0 | { |
937 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
938 | 0 | "pszSource == nullptr && fpSource == nullptr"); |
939 | 0 | return -1; |
940 | 0 | } |
941 | 0 | if (!pszTarget || pszTarget[0] == '\0') |
942 | 0 | { |
943 | 0 | return -1; |
944 | 0 | } |
945 | | |
946 | 0 | VSIFilesystemHandler *poFSHandlerTarget = |
947 | 0 | VSIFileManager::GetHandler(pszTarget); |
948 | 0 | return poFSHandlerTarget->CopyFile(pszSource, pszTarget, fpSource, |
949 | 0 | nSourceSize, papszOptions, pProgressFunc, |
950 | 0 | pProgressData); |
951 | 0 | } |
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 | | 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 | 0 | { |
1029 | 0 | if (!pszSource) |
1030 | 0 | { |
1031 | 0 | return -1; |
1032 | 0 | } |
1033 | 0 | if (!pszTarget || pszTarget[0] == '\0') |
1034 | 0 | { |
1035 | 0 | return -1; |
1036 | 0 | } |
1037 | 0 | if (!ppszOutputPayload) |
1038 | 0 | { |
1039 | 0 | return -1; |
1040 | 0 | } |
1041 | | |
1042 | 0 | VSIFilesystemHandler *poFSHandlerTarget = |
1043 | 0 | VSIFileManager::GetHandler(pszTarget); |
1044 | 0 | return poFSHandlerTarget->CopyFileRestartable( |
1045 | 0 | pszSource, pszTarget, pszInputPayload, ppszOutputPayload, papszOptions, |
1046 | 0 | pProgressFunc, pProgressData); |
1047 | 0 | } |
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 | | int VSISync(const char *pszSource, const char *pszTarget, |
1130 | | const char *const *papszOptions, GDALProgressFunc pProgressFunc, |
1131 | | void *pProgressData, char ***ppapszOutputs) |
1132 | | |
1133 | 0 | { |
1134 | 0 | if (pszSource[0] == '\0' || pszTarget[0] == '\0') |
1135 | 0 | { |
1136 | 0 | return FALSE; |
1137 | 0 | } |
1138 | | |
1139 | 0 | VSIFilesystemHandler *poFSHandlerSource = |
1140 | 0 | VSIFileManager::GetHandler(pszSource); |
1141 | 0 | VSIFilesystemHandler *poFSHandlerTarget = |
1142 | 0 | VSIFileManager::GetHandler(pszTarget); |
1143 | 0 | VSIFilesystemHandler *poFSHandlerLocal = VSIFileManager::GetHandler(""); |
1144 | 0 | VSIFilesystemHandler *poFSHandlerMem = |
1145 | 0 | VSIFileManager::GetHandler("/vsimem/"); |
1146 | 0 | VSIFilesystemHandler *poFSHandler = poFSHandlerSource; |
1147 | 0 | if (poFSHandlerTarget != poFSHandlerLocal && |
1148 | 0 | poFSHandlerTarget != poFSHandlerMem) |
1149 | 0 | { |
1150 | 0 | poFSHandler = poFSHandlerTarget; |
1151 | 0 | } |
1152 | |
|
1153 | 0 | return poFSHandler->Sync(pszSource, pszTarget, papszOptions, pProgressFunc, |
1154 | 0 | pProgressData, ppapszOutputs) |
1155 | 0 | ? TRUE |
1156 | 0 | : FALSE; |
1157 | 0 | } |
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 | | int VSIMultipartUploadGetCapabilities( |
1187 | | const char *pszFilename, int *pbNonSequentialUploadSupported, |
1188 | | int *pbParallelUploadSupported, int *pbAbortSupported, |
1189 | | size_t *pnMinPartSize, size_t *pnMaxPartSize, int *pnMaxPartCount) |
1190 | 0 | { |
1191 | 0 | VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename); |
1192 | |
|
1193 | 0 | return poFSHandler->MultipartUploadGetCapabilities( |
1194 | 0 | pbNonSequentialUploadSupported, pbParallelUploadSupported, |
1195 | 0 | pbAbortSupported, pnMinPartSize, pnMaxPartSize, pnMaxPartCount); |
1196 | 0 | } |
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 | | char *VSIMultipartUploadStart(const char *pszFilename, |
1236 | | CSLConstList papszOptions) |
1237 | 0 | { |
1238 | 0 | VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename); |
1239 | |
|
1240 | 0 | return poFSHandler->MultipartUploadStart(pszFilename, papszOptions); |
1241 | 0 | } |
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 | | 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 | 0 | { |
1278 | 0 | VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename); |
1279 | |
|
1280 | 0 | return poFSHandler->MultipartUploadAddPart(pszFilename, pszUploadId, |
1281 | 0 | nPartNumber, nFileOffset, pData, |
1282 | 0 | nDataLength, papszOptions); |
1283 | 0 | } |
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 | | int VSIMultipartUploadEnd(const char *pszFilename, const char *pszUploadId, |
1311 | | size_t nPartIdsCount, const char *const *apszPartIds, |
1312 | | vsi_l_offset nTotalSize, CSLConstList papszOptions) |
1313 | 0 | { |
1314 | 0 | VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename); |
1315 | |
|
1316 | 0 | return poFSHandler->MultipartUploadEnd(pszFilename, pszUploadId, |
1317 | 0 | nPartIdsCount, apszPartIds, |
1318 | 0 | nTotalSize, papszOptions); |
1319 | 0 | } |
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 | | int VSIMultipartUploadAbort(const char *pszFilename, const char *pszUploadId, |
1346 | | CSLConstList papszOptions) |
1347 | 0 | { |
1348 | 0 | VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename); |
1349 | |
|
1350 | 0 | return poFSHandler->MultipartUploadAbort(pszFilename, pszUploadId, |
1351 | 0 | papszOptions); |
1352 | 0 | } |
1353 | | |
1354 | | #ifndef DOXYGEN_SKIP |
1355 | | |
1356 | | /************************************************************************/ |
1357 | | /* MultipartUploadGetCapabilities() */ |
1358 | | /************************************************************************/ |
1359 | | |
1360 | | bool VSIFilesystemHandler::MultipartUploadGetCapabilities(int *, int *, int *, |
1361 | | size_t *, size_t *, |
1362 | | int *) |
1363 | 0 | { |
1364 | 0 | CPLError( |
1365 | 0 | CE_Failure, CPLE_NotSupported, |
1366 | 0 | "MultipartUploadGetCapabilities() not supported by this file system"); |
1367 | 0 | return false; |
1368 | 0 | } |
1369 | | |
1370 | | /************************************************************************/ |
1371 | | /* MultipartUploadStart() */ |
1372 | | /************************************************************************/ |
1373 | | |
1374 | | char *VSIFilesystemHandler::MultipartUploadStart(const char *, CSLConstList) |
1375 | 0 | { |
1376 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
1377 | 0 | "MultipartUploadStart() not supported by this file system"); |
1378 | 0 | return nullptr; |
1379 | 0 | } |
1380 | | |
1381 | | /************************************************************************/ |
1382 | | /* MultipartUploadAddPart() */ |
1383 | | /************************************************************************/ |
1384 | | |
1385 | | char *VSIFilesystemHandler::MultipartUploadAddPart(const char *, const char *, |
1386 | | int, vsi_l_offset, |
1387 | | const void *, size_t, |
1388 | | CSLConstList) |
1389 | 0 | { |
1390 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
1391 | 0 | "MultipartUploadAddPart() not supported by this file system"); |
1392 | 0 | return nullptr; |
1393 | 0 | } |
1394 | | |
1395 | | /************************************************************************/ |
1396 | | /* MultipartUploadEnd() */ |
1397 | | /************************************************************************/ |
1398 | | |
1399 | | bool VSIFilesystemHandler::MultipartUploadEnd(const char *, const char *, |
1400 | | size_t, const char *const *, |
1401 | | vsi_l_offset, CSLConstList) |
1402 | 0 | { |
1403 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
1404 | 0 | "MultipartUploadEnd() not supported by this file system"); |
1405 | 0 | return FALSE; |
1406 | 0 | } |
1407 | | |
1408 | | /************************************************************************/ |
1409 | | /* MultipartUploadAbort() */ |
1410 | | /************************************************************************/ |
1411 | | |
1412 | | bool VSIFilesystemHandler::MultipartUploadAbort(const char *, const char *, |
1413 | | CSLConstList) |
1414 | 0 | { |
1415 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
1416 | 0 | "MultipartUploadAbort() not supported by this file system"); |
1417 | 0 | return FALSE; |
1418 | 0 | } |
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 | | int VSIAbortPendingUploads(const char *pszFilename) |
1448 | 0 | { |
1449 | 0 | VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename); |
1450 | |
|
1451 | 0 | return poFSHandler->AbortPendingUploads(pszFilename); |
1452 | 0 | } |
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 | | int VSIRmdir(const char *pszDirname) |
1475 | | |
1476 | 0 | { |
1477 | 0 | VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszDirname); |
1478 | |
|
1479 | 0 | return poFSHandler->Rmdir(pszDirname); |
1480 | 0 | } |
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 | | int VSIRmdirRecursive(const char *pszDirname) |
1501 | 0 | { |
1502 | 0 | if (pszDirname == nullptr || pszDirname[0] == '\0' || |
1503 | 0 | strncmp("/", pszDirname, 2) == 0) |
1504 | 0 | { |
1505 | 0 | return -1; |
1506 | 0 | } |
1507 | 0 | VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszDirname); |
1508 | 0 | return poFSHandler->RmdirRecursive(pszDirname); |
1509 | 0 | } |
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 | | int VSIStatL(const char *pszFilename, VSIStatBufL *psStatBuf) |
1537 | | |
1538 | 5.91k | { |
1539 | 5.91k | return VSIStatExL(pszFilename, psStatBuf, 0); |
1540 | 5.91k | } |
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 | | int VSIStatExL(const char *pszFilename, VSIStatBufL *psStatBuf, int nFlags) |
1577 | | |
1578 | 5.91k | { |
1579 | 5.91k | char szAltPath[4] = {'\0'}; |
1580 | | |
1581 | | // Enable to work on "C:" as if it were "C:\". |
1582 | 5.91k | if (pszFilename[0] != '\0' && pszFilename[1] == ':' && |
1583 | 5.91k | pszFilename[2] == '\0') |
1584 | 0 | { |
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 | 0 | } |
1592 | | |
1593 | 5.91k | VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename); |
1594 | | |
1595 | 5.91k | if (nFlags == 0) |
1596 | 5.91k | nFlags = |
1597 | 5.91k | VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG | VSI_STAT_SIZE_FLAG; |
1598 | | |
1599 | 5.91k | return poFSHandler->Stat(pszFilename, psStatBuf, nFlags); |
1600 | 5.91k | } |
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 | | char **VSIGetFileMetadata(const char *pszFilename, const char *pszDomain, |
1655 | | CSLConstList papszOptions) |
1656 | 0 | { |
1657 | 0 | VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename); |
1658 | 0 | return poFSHandler->GetFileMetadata(pszFilename, pszDomain, papszOptions); |
1659 | 0 | } |
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 | | int VSISetFileMetadata(const char *pszFilename, CSLConstList papszMetadata, |
1725 | | const char *pszDomain, CSLConstList papszOptions) |
1726 | 0 | { |
1727 | 0 | VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename); |
1728 | 0 | return poFSHandler->SetFileMetadata(pszFilename, papszMetadata, pszDomain, |
1729 | 0 | papszOptions) |
1730 | 0 | ? 1 |
1731 | 0 | : 0; |
1732 | 0 | } |
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 | | int VSIIsCaseSensitiveFS(const char *pszFilename) |
1759 | 0 | { |
1760 | 0 | VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename); |
1761 | |
|
1762 | 0 | return poFSHandler->IsCaseSensitive(pszFilename); |
1763 | 0 | } |
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 | | int VSISupportsSparseFiles(const char *pszPath) |
1788 | 0 | { |
1789 | 0 | VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath); |
1790 | |
|
1791 | 0 | return poFSHandler->SupportsSparseFiles(pszPath); |
1792 | 0 | } |
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 | | bool VSIIsLocal(const char *pszPath) |
1816 | 0 | { |
1817 | 0 | VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath); |
1818 | |
|
1819 | 0 | return poFSHandler->IsLocal(pszPath); |
1820 | 0 | } |
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 | | char *VSIGetCanonicalFilename(const char *pszPath) |
1841 | 0 | { |
1842 | 0 | VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath); |
1843 | |
|
1844 | 0 | return CPLStrdup(poFSHandler->GetCanonicalFilename(pszPath).c_str()); |
1845 | 0 | } |
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 | | bool VSISupportsSequentialWrite(const char *pszPath, bool bAllowLocalTempFile) |
1865 | 0 | { |
1866 | 0 | VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath); |
1867 | |
|
1868 | 0 | return poFSHandler->SupportsSequentialWrite(pszPath, bAllowLocalTempFile); |
1869 | 0 | } |
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 | | bool VSISupportsRandomWrite(const char *pszPath, bool bAllowLocalTempFile) |
1889 | 0 | { |
1890 | 0 | VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath); |
1891 | |
|
1892 | 0 | return poFSHandler->SupportsRandomWrite(pszPath, bAllowLocalTempFile); |
1893 | 0 | } |
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 | | int VSIHasOptimizedReadMultiRange(const char *pszPath) |
1914 | 0 | { |
1915 | 0 | VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszPath); |
1916 | |
|
1917 | 0 | return poFSHandler->HasOptimizedReadMultiRange(pszPath); |
1918 | 0 | } |
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 | | const char *VSIGetActualURL(const char *pszFilename) |
1943 | 0 | { |
1944 | 0 | VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename); |
1945 | |
|
1946 | 0 | return poFSHandler->GetActualURL(pszFilename); |
1947 | 0 | } |
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 | | char *VSIGetSignedURL(const char *pszFilename, CSLConstList papszOptions) |
1987 | 0 | { |
1988 | 0 | VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename); |
1989 | |
|
1990 | 0 | return poFSHandler->GetSignedURL(pszFilename, papszOptions); |
1991 | 0 | } |
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 | | VSILFILE *VSIFOpenL(const char *pszFilename, const char *pszAccess) |
2024 | | |
2025 | 0 | { |
2026 | 0 | return VSIFOpenExL(pszFilename, pszAccess, false); |
2027 | 0 | } |
2028 | | |
2029 | | /************************************************************************/ |
2030 | | /* Open() */ |
2031 | | /************************************************************************/ |
2032 | | |
2033 | | #ifndef DOXYGEN_SKIP |
2034 | | |
2035 | | VSIVirtualHandle *VSIFilesystemHandler::Open(const char *pszFilename, |
2036 | | const char *pszAccess) |
2037 | 0 | { |
2038 | 0 | return Open(pszFilename, pszAccess, false, nullptr); |
2039 | 0 | } |
2040 | | |
2041 | | /************************************************************************/ |
2042 | | /* CopyFile() */ |
2043 | | /************************************************************************/ |
2044 | | |
2045 | | 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 | 0 | { |
2051 | 0 | VSIVirtualHandleUniquePtr poFileHandleAutoClose; |
2052 | 0 | if (!fpSource) |
2053 | 0 | { |
2054 | 0 | CPLAssert(pszSource); |
2055 | 0 | fpSource = VSIFOpenExL(pszSource, "rb", TRUE); |
2056 | 0 | if (!fpSource) |
2057 | 0 | { |
2058 | 0 | CPLError(CE_Failure, CPLE_FileIO, "Cannot open %s", pszSource); |
2059 | 0 | return -1; |
2060 | 0 | } |
2061 | 0 | poFileHandleAutoClose.reset(fpSource); |
2062 | 0 | } |
2063 | 0 | if (nSourceSize == static_cast<vsi_l_offset>(-1) && |
2064 | 0 | pProgressFunc != nullptr && pszSource != nullptr) |
2065 | 0 | { |
2066 | 0 | VSIStatBufL sStat; |
2067 | 0 | if (VSIStatL(pszSource, &sStat) == 0) |
2068 | 0 | { |
2069 | 0 | nSourceSize = sStat.st_size; |
2070 | 0 | } |
2071 | 0 | } |
2072 | |
|
2073 | 0 | VSILFILE *fpOut = VSIFOpenEx2L(pszTarget, "wb", TRUE, papszOptions); |
2074 | 0 | if (!fpOut) |
2075 | 0 | { |
2076 | 0 | CPLError(CE_Failure, CPLE_FileIO, "Cannot create %s", pszTarget); |
2077 | 0 | return -1; |
2078 | 0 | } |
2079 | | |
2080 | 0 | CPLString osMsg; |
2081 | 0 | if (pszSource) |
2082 | 0 | osMsg.Printf("Copying of %s", pszSource); |
2083 | 0 | else |
2084 | 0 | pszSource = "(unknown filename)"; |
2085 | |
|
2086 | 0 | int ret = 0; |
2087 | 0 | constexpr size_t nBufferSize = 10 * 4096; |
2088 | 0 | std::vector<GByte> abyBuffer(nBufferSize, 0); |
2089 | 0 | GUIntBig nOffset = 0; |
2090 | 0 | while (true) |
2091 | 0 | { |
2092 | 0 | const size_t nRead = VSIFReadL(&abyBuffer[0], 1, nBufferSize, fpSource); |
2093 | 0 | if (nRead < nBufferSize && VSIFErrorL(fpSource)) |
2094 | 0 | { |
2095 | 0 | CPLError( |
2096 | 0 | CE_Failure, CPLE_FileIO, |
2097 | 0 | "Copying of %s to %s failed: error while reading source file", |
2098 | 0 | pszSource, pszTarget); |
2099 | 0 | ret = -1; |
2100 | 0 | break; |
2101 | 0 | } |
2102 | 0 | if (nRead > 0) |
2103 | 0 | { |
2104 | 0 | const size_t nWritten = VSIFWriteL(&abyBuffer[0], 1, nRead, fpOut); |
2105 | 0 | if (nWritten != nRead) |
2106 | 0 | { |
2107 | 0 | CPLError(CE_Failure, CPLE_FileIO, |
2108 | 0 | "Copying of %s to %s failed: error while writing into " |
2109 | 0 | "target file", |
2110 | 0 | pszSource, pszTarget); |
2111 | 0 | ret = -1; |
2112 | 0 | break; |
2113 | 0 | } |
2114 | 0 | nOffset += nRead; |
2115 | 0 | if (pProgressFunc && |
2116 | 0 | !pProgressFunc( |
2117 | 0 | nSourceSize == 0 ? 1.0 |
2118 | 0 | : nSourceSize > 0 && |
2119 | 0 | nSourceSize != static_cast<vsi_l_offset>(-1) |
2120 | 0 | ? double(nOffset) / nSourceSize |
2121 | 0 | : 0.0, |
2122 | 0 | !osMsg.empty() ? osMsg.c_str() : nullptr, pProgressData)) |
2123 | 0 | { |
2124 | 0 | ret = -1; |
2125 | 0 | break; |
2126 | 0 | } |
2127 | 0 | } |
2128 | 0 | if (nRead < nBufferSize) |
2129 | 0 | { |
2130 | 0 | break; |
2131 | 0 | } |
2132 | 0 | } |
2133 | |
|
2134 | 0 | if (nSourceSize != static_cast<vsi_l_offset>(-1) && nOffset != nSourceSize) |
2135 | 0 | { |
2136 | 0 | CPLError(CE_Failure, CPLE_FileIO, |
2137 | 0 | "Copying of %s to %s failed: %" PRIu64 " bytes were copied " |
2138 | 0 | "whereas %" PRIu64 " were expected", |
2139 | 0 | pszSource, pszTarget, static_cast<uint64_t>(nOffset), |
2140 | 0 | static_cast<uint64_t>(nSourceSize)); |
2141 | 0 | ret = -1; |
2142 | 0 | } |
2143 | |
|
2144 | 0 | if (VSIFCloseL(fpOut) != 0) |
2145 | 0 | { |
2146 | 0 | ret = -1; |
2147 | 0 | } |
2148 | |
|
2149 | 0 | if (ret != 0) |
2150 | 0 | VSIUnlink(pszTarget); |
2151 | |
|
2152 | 0 | return ret; |
2153 | 0 | } |
2154 | | |
2155 | | /************************************************************************/ |
2156 | | /* CopyFileRestartable() */ |
2157 | | /************************************************************************/ |
2158 | | |
2159 | | 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 | 0 | { |
2165 | 0 | *ppszOutputPayload = nullptr; |
2166 | 0 | return CopyFile(pszSource, pszTarget, nullptr, |
2167 | 0 | static_cast<vsi_l_offset>(-1), papszOptions, pProgressFunc, |
2168 | 0 | pProgressData); |
2169 | 0 | } |
2170 | | |
2171 | | /************************************************************************/ |
2172 | | /* Sync() */ |
2173 | | /************************************************************************/ |
2174 | | |
2175 | | bool VSIFilesystemHandler::Sync(const char *pszSource, const char *pszTarget, |
2176 | | const char *const *papszOptions, |
2177 | | GDALProgressFunc pProgressFunc, |
2178 | | void *pProgressData, char ***ppapszOutputs) |
2179 | 0 | { |
2180 | 0 | const char SOURCE_SEP = VSIGetDirectorySeparator(pszSource)[0]; |
2181 | |
|
2182 | 0 | if (ppapszOutputs) |
2183 | 0 | { |
2184 | 0 | *ppapszOutputs = nullptr; |
2185 | 0 | } |
2186 | |
|
2187 | 0 | VSIStatBufL sSource; |
2188 | 0 | CPLString osSource(pszSource); |
2189 | 0 | CPLString osSourceWithoutSlash(pszSource); |
2190 | 0 | if (osSourceWithoutSlash.back() == '/' || |
2191 | 0 | osSourceWithoutSlash.back() == '\\') |
2192 | 0 | { |
2193 | 0 | osSourceWithoutSlash.pop_back(); |
2194 | 0 | } |
2195 | 0 | if (VSIStatL(osSourceWithoutSlash, &sSource) < 0) |
2196 | 0 | { |
2197 | 0 | CPLError(CE_Failure, CPLE_FileIO, "%s does not exist", pszSource); |
2198 | 0 | return false; |
2199 | 0 | } |
2200 | | |
2201 | 0 | if (VSI_ISDIR(sSource.st_mode)) |
2202 | 0 | { |
2203 | 0 | std::string osTargetDir(pszTarget); |
2204 | 0 | if (osSource.back() != '/' && osSource.back() != '\\') |
2205 | 0 | { |
2206 | 0 | osTargetDir = CPLFormFilenameSafe( |
2207 | 0 | osTargetDir.c_str(), CPLGetFilename(pszSource), nullptr); |
2208 | 0 | } |
2209 | |
|
2210 | 0 | VSIStatBufL sTarget; |
2211 | 0 | bool ret = true; |
2212 | 0 | if (VSIStatL(osTargetDir.c_str(), &sTarget) < 0) |
2213 | 0 | { |
2214 | 0 | if (VSIMkdirRecursive(osTargetDir.c_str(), 0755) < 0) |
2215 | 0 | { |
2216 | 0 | CPLError(CE_Failure, CPLE_FileIO, "Cannot create directory %s", |
2217 | 0 | osTargetDir.c_str()); |
2218 | 0 | return false; |
2219 | 0 | } |
2220 | 0 | } |
2221 | | |
2222 | 0 | if (!CPLFetchBool(papszOptions, "STOP_ON_DIR", false)) |
2223 | 0 | { |
2224 | 0 | CPLStringList aosChildOptions(CSLDuplicate(papszOptions)); |
2225 | 0 | if (!CPLFetchBool(papszOptions, "RECURSIVE", true)) |
2226 | 0 | { |
2227 | 0 | aosChildOptions.SetNameValue("RECURSIVE", nullptr); |
2228 | 0 | aosChildOptions.AddString("STOP_ON_DIR=TRUE"); |
2229 | 0 | } |
2230 | |
|
2231 | 0 | char **papszSrcFiles = VSIReadDir(osSourceWithoutSlash); |
2232 | 0 | int nFileCount = 0; |
2233 | 0 | for (auto iter = papszSrcFiles; iter && *iter; ++iter) |
2234 | 0 | { |
2235 | 0 | if (strcmp(*iter, ".") != 0 && strcmp(*iter, "..") != 0) |
2236 | 0 | { |
2237 | 0 | nFileCount++; |
2238 | 0 | } |
2239 | 0 | } |
2240 | 0 | int iFile = 0; |
2241 | 0 | const int nDenom = std::max(1, nFileCount); |
2242 | 0 | for (auto iter = papszSrcFiles; iter && *iter; ++iter, ++iFile) |
2243 | 0 | { |
2244 | 0 | if (strcmp(*iter, ".") == 0 || strcmp(*iter, "..") == 0) |
2245 | 0 | { |
2246 | 0 | continue; |
2247 | 0 | } |
2248 | 0 | const std::string osSubSource(CPLFormFilenameSafe( |
2249 | 0 | osSourceWithoutSlash.c_str(), *iter, nullptr)); |
2250 | 0 | const std::string osSubTarget( |
2251 | 0 | CPLFormFilenameSafe(osTargetDir.c_str(), *iter, nullptr)); |
2252 | 0 | void *pScaledProgress = GDALCreateScaledProgress( |
2253 | 0 | double(iFile) / nDenom, double(iFile + 1) / nDenom, |
2254 | 0 | pProgressFunc, pProgressData); |
2255 | 0 | ret = Sync((osSubSource + SOURCE_SEP).c_str(), |
2256 | 0 | osSubTarget.c_str(), aosChildOptions.List(), |
2257 | 0 | GDALScaledProgress, pScaledProgress, nullptr); |
2258 | 0 | GDALDestroyScaledProgress(pScaledProgress); |
2259 | 0 | if (!ret) |
2260 | 0 | { |
2261 | 0 | break; |
2262 | 0 | } |
2263 | 0 | } |
2264 | 0 | CSLDestroy(papszSrcFiles); |
2265 | 0 | } |
2266 | 0 | return ret; |
2267 | 0 | } |
2268 | | |
2269 | 0 | VSIStatBufL sTarget; |
2270 | 0 | std::string osTarget(pszTarget); |
2271 | 0 | if (VSIStatL(osTarget.c_str(), &sTarget) == 0) |
2272 | 0 | { |
2273 | 0 | bool bTargetIsFile = true; |
2274 | 0 | if (VSI_ISDIR(sTarget.st_mode)) |
2275 | 0 | { |
2276 | 0 | osTarget = CPLFormFilenameSafe(osTarget.c_str(), |
2277 | 0 | CPLGetFilename(pszSource), nullptr); |
2278 | 0 | bTargetIsFile = VSIStatL(osTarget.c_str(), &sTarget) == 0 && |
2279 | 0 | !CPL_TO_BOOL(VSI_ISDIR(sTarget.st_mode)); |
2280 | 0 | } |
2281 | 0 | if (bTargetIsFile) |
2282 | 0 | { |
2283 | 0 | if (sSource.st_size == sTarget.st_size && |
2284 | 0 | sSource.st_mtime == sTarget.st_mtime && sSource.st_mtime != 0) |
2285 | 0 | { |
2286 | 0 | CPLDebug("VSI", |
2287 | 0 | "%s and %s have same size and modification " |
2288 | 0 | "date. Skipping copying", |
2289 | 0 | osSourceWithoutSlash.c_str(), osTarget.c_str()); |
2290 | 0 | return true; |
2291 | 0 | } |
2292 | 0 | } |
2293 | 0 | } |
2294 | | |
2295 | 0 | VSILFILE *fpIn = VSIFOpenExL(osSourceWithoutSlash, "rb", TRUE); |
2296 | 0 | if (fpIn == nullptr) |
2297 | 0 | { |
2298 | 0 | CPLError(CE_Failure, CPLE_FileIO, "Cannot open %s", |
2299 | 0 | osSourceWithoutSlash.c_str()); |
2300 | 0 | return false; |
2301 | 0 | } |
2302 | | |
2303 | 0 | VSILFILE *fpOut = VSIFOpenExL(osTarget.c_str(), "wb", TRUE); |
2304 | 0 | if (fpOut == nullptr) |
2305 | 0 | { |
2306 | 0 | CPLError(CE_Failure, CPLE_FileIO, "Cannot create %s", osTarget.c_str()); |
2307 | 0 | VSIFCloseL(fpIn); |
2308 | 0 | return false; |
2309 | 0 | } |
2310 | | |
2311 | 0 | bool ret = true; |
2312 | 0 | constexpr size_t nBufferSize = 10 * 4096; |
2313 | 0 | std::vector<GByte> abyBuffer(nBufferSize, 0); |
2314 | 0 | GUIntBig nOffset = 0; |
2315 | 0 | CPLString osMsg; |
2316 | 0 | osMsg.Printf("Copying of %s", osSourceWithoutSlash.c_str()); |
2317 | 0 | while (true) |
2318 | 0 | { |
2319 | 0 | size_t nRead = VSIFReadL(&abyBuffer[0], 1, nBufferSize, fpIn); |
2320 | 0 | size_t nWritten = VSIFWriteL(&abyBuffer[0], 1, nRead, fpOut); |
2321 | 0 | if (nWritten != nRead) |
2322 | 0 | { |
2323 | 0 | CPLError(CE_Failure, CPLE_FileIO, "Copying of %s to %s failed", |
2324 | 0 | osSourceWithoutSlash.c_str(), osTarget.c_str()); |
2325 | 0 | ret = false; |
2326 | 0 | break; |
2327 | 0 | } |
2328 | 0 | nOffset += nRead; |
2329 | 0 | if (pProgressFunc && !pProgressFunc(double(nOffset) / sSource.st_size, |
2330 | 0 | osMsg.c_str(), pProgressData)) |
2331 | 0 | { |
2332 | 0 | ret = false; |
2333 | 0 | break; |
2334 | 0 | } |
2335 | 0 | if (nRead < nBufferSize) |
2336 | 0 | { |
2337 | 0 | break; |
2338 | 0 | } |
2339 | 0 | } |
2340 | |
|
2341 | 0 | VSIFCloseL(fpIn); |
2342 | 0 | if (VSIFCloseL(fpOut) != 0) |
2343 | 0 | { |
2344 | 0 | ret = false; |
2345 | 0 | } |
2346 | 0 | return ret; |
2347 | 0 | } |
2348 | | |
2349 | | /************************************************************************/ |
2350 | | /* VSIDIREntry() */ |
2351 | | /************************************************************************/ |
2352 | | |
2353 | | VSIDIREntry::VSIDIREntry() |
2354 | 0 | : pszName(nullptr), nMode(0), nSize(0), nMTime(0), bModeKnown(false), |
2355 | 0 | bSizeKnown(false), bMTimeKnown(false), papszExtra(nullptr) |
2356 | 0 | { |
2357 | 0 | } |
2358 | | |
2359 | | /************************************************************************/ |
2360 | | /* VSIDIREntry() */ |
2361 | | /************************************************************************/ |
2362 | | |
2363 | | VSIDIREntry::VSIDIREntry(const VSIDIREntry &other) |
2364 | 0 | : pszName(VSIStrdup(other.pszName)), nMode(other.nMode), nSize(other.nSize), |
2365 | 0 | nMTime(other.nMTime), bModeKnown(other.bModeKnown), |
2366 | 0 | bSizeKnown(other.bSizeKnown), bMTimeKnown(other.bMTimeKnown), |
2367 | 0 | papszExtra(CSLDuplicate(other.papszExtra)) |
2368 | 0 | { |
2369 | 0 | } |
2370 | | |
2371 | | /************************************************************************/ |
2372 | | /* ~VSIDIREntry() */ |
2373 | | /************************************************************************/ |
2374 | | |
2375 | | VSIDIREntry::~VSIDIREntry() |
2376 | 0 | { |
2377 | 0 | CPLFree(pszName); |
2378 | 0 | CSLDestroy(papszExtra); |
2379 | 0 | } |
2380 | | |
2381 | | /************************************************************************/ |
2382 | | /* ~VSIDIR() */ |
2383 | | /************************************************************************/ |
2384 | | |
2385 | | VSIDIR::~VSIDIR() |
2386 | 0 | { |
2387 | 0 | } |
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 | 0 | explicit VSIDIRGeneric(VSIFilesystemHandler *poFSIn) : poFS(poFSIn) |
2408 | 0 | { |
2409 | 0 | } |
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 | | VSIDIRGeneric::~VSIDIRGeneric() |
2424 | 0 | { |
2425 | 0 | while (!aoStackSubDir.empty()) |
2426 | 0 | { |
2427 | 0 | delete aoStackSubDir.back(); |
2428 | 0 | aoStackSubDir.pop_back(); |
2429 | 0 | } |
2430 | 0 | CSLDestroy(papszContent); |
2431 | 0 | } |
2432 | | |
2433 | | } // namespace |
2434 | | |
2435 | | /************************************************************************/ |
2436 | | /* OpenDir() */ |
2437 | | /************************************************************************/ |
2438 | | |
2439 | | VSIDIR *VSIFilesystemHandler::OpenDir(const char *pszPath, int nRecurseDepth, |
2440 | | const char *const *papszOptions) |
2441 | 0 | { |
2442 | 0 | char **papszContent = VSIReadDir(pszPath); |
2443 | 0 | VSIStatBufL sStatL; |
2444 | 0 | if (papszContent == nullptr && |
2445 | 0 | (VSIStatL(pszPath, &sStatL) != 0 || !VSI_ISDIR(sStatL.st_mode))) |
2446 | 0 | { |
2447 | 0 | return nullptr; |
2448 | 0 | } |
2449 | 0 | VSIDIRGeneric *dir = new VSIDIRGeneric(this); |
2450 | 0 | dir->osRootPath = pszPath; |
2451 | 0 | if (!dir->osRootPath.empty() && |
2452 | 0 | (dir->osRootPath.back() == '/' || dir->osRootPath.back() == '\\')) |
2453 | 0 | dir->osRootPath.pop_back(); |
2454 | 0 | dir->nRecurseDepth = nRecurseDepth; |
2455 | 0 | dir->papszContent = papszContent; |
2456 | 0 | dir->m_osFilterPrefix = CSLFetchNameValueDef(papszOptions, "PREFIX", ""); |
2457 | 0 | return dir; |
2458 | 0 | } |
2459 | | |
2460 | | /************************************************************************/ |
2461 | | /* NextDirEntry() */ |
2462 | | /************************************************************************/ |
2463 | | |
2464 | | const VSIDIREntry *VSIDIRGeneric::NextDirEntry() |
2465 | 0 | { |
2466 | 0 | const char SEP = VSIGetDirectorySeparator(osRootPath.c_str())[0]; |
2467 | |
|
2468 | 0 | begin: |
2469 | 0 | if (VSI_ISDIR(entry.nMode) && nRecurseDepth != 0) |
2470 | 0 | { |
2471 | 0 | CPLString osCurFile(osRootPath); |
2472 | 0 | if (!osCurFile.empty()) |
2473 | 0 | osCurFile += SEP; |
2474 | 0 | osCurFile += entry.pszName; |
2475 | 0 | auto subdir = |
2476 | 0 | static_cast<VSIDIRGeneric *>(poFS->VSIFilesystemHandler::OpenDir( |
2477 | 0 | osCurFile, nRecurseDepth - 1, nullptr)); |
2478 | 0 | if (subdir) |
2479 | 0 | { |
2480 | 0 | subdir->osRootPath = osRootPath; |
2481 | 0 | subdir->osBasePath = entry.pszName; |
2482 | 0 | subdir->m_osFilterPrefix = m_osFilterPrefix; |
2483 | 0 | aoStackSubDir.push_back(subdir); |
2484 | 0 | } |
2485 | 0 | entry.nMode = 0; |
2486 | 0 | } |
2487 | |
|
2488 | 0 | while (!aoStackSubDir.empty()) |
2489 | 0 | { |
2490 | 0 | auto l_entry = aoStackSubDir.back()->NextDirEntry(); |
2491 | 0 | if (l_entry) |
2492 | 0 | { |
2493 | 0 | return l_entry; |
2494 | 0 | } |
2495 | 0 | delete aoStackSubDir.back(); |
2496 | 0 | aoStackSubDir.pop_back(); |
2497 | 0 | } |
2498 | | |
2499 | 0 | if (papszContent == nullptr) |
2500 | 0 | { |
2501 | 0 | return nullptr; |
2502 | 0 | } |
2503 | | |
2504 | 0 | while (true) |
2505 | 0 | { |
2506 | 0 | if (!papszContent[nPos]) |
2507 | 0 | { |
2508 | 0 | return nullptr; |
2509 | 0 | } |
2510 | | // Skip . and ..entries |
2511 | 0 | if (papszContent[nPos][0] == '.' && |
2512 | 0 | (papszContent[nPos][1] == '\0' || |
2513 | 0 | (papszContent[nPos][1] == '.' && papszContent[nPos][2] == '\0'))) |
2514 | 0 | { |
2515 | 0 | nPos++; |
2516 | 0 | } |
2517 | 0 | else |
2518 | 0 | { |
2519 | 0 | CPLFree(entry.pszName); |
2520 | 0 | CPLString osName(osBasePath); |
2521 | 0 | if (!osName.empty()) |
2522 | 0 | osName += SEP; |
2523 | 0 | osName += papszContent[nPos]; |
2524 | 0 | nPos++; |
2525 | |
|
2526 | 0 | entry.pszName = CPLStrdup(osName); |
2527 | 0 | entry.nMode = 0; |
2528 | 0 | CPLString osCurFile(osRootPath); |
2529 | 0 | if (!osCurFile.empty()) |
2530 | 0 | osCurFile += SEP; |
2531 | 0 | osCurFile += entry.pszName; |
2532 | |
|
2533 | 0 | const auto StatFile = [&osCurFile, this]() |
2534 | 0 | { |
2535 | 0 | VSIStatBufL sStatL; |
2536 | 0 | if (VSIStatL(osCurFile, &sStatL) == 0) |
2537 | 0 | { |
2538 | 0 | entry.nMode = sStatL.st_mode; |
2539 | 0 | entry.nSize = sStatL.st_size; |
2540 | 0 | entry.nMTime = sStatL.st_mtime; |
2541 | 0 | entry.bModeKnown = true; |
2542 | 0 | entry.bSizeKnown = true; |
2543 | 0 | entry.bMTimeKnown = true; |
2544 | 0 | } |
2545 | 0 | else |
2546 | 0 | { |
2547 | 0 | entry.nMode = 0; |
2548 | 0 | entry.nSize = 0; |
2549 | 0 | entry.nMTime = 0; |
2550 | 0 | entry.bModeKnown = false; |
2551 | 0 | entry.bSizeKnown = false; |
2552 | 0 | entry.bMTimeKnown = false; |
2553 | 0 | } |
2554 | 0 | }; |
2555 | |
|
2556 | 0 | if (!m_osFilterPrefix.empty() && |
2557 | 0 | m_osFilterPrefix.size() > osName.size()) |
2558 | 0 | { |
2559 | 0 | if (STARTS_WITH(m_osFilterPrefix.c_str(), osName.c_str()) && |
2560 | 0 | m_osFilterPrefix[osName.size()] == SEP) |
2561 | 0 | { |
2562 | 0 | StatFile(); |
2563 | 0 | if (VSI_ISDIR(entry.nMode)) |
2564 | 0 | { |
2565 | 0 | goto begin; |
2566 | 0 | } |
2567 | 0 | } |
2568 | 0 | continue; |
2569 | 0 | } |
2570 | 0 | if (!m_osFilterPrefix.empty() && |
2571 | 0 | !STARTS_WITH(osName.c_str(), m_osFilterPrefix.c_str())) |
2572 | 0 | { |
2573 | 0 | continue; |
2574 | 0 | } |
2575 | | |
2576 | 0 | StatFile(); |
2577 | |
|
2578 | 0 | break; |
2579 | 0 | } |
2580 | 0 | } |
2581 | | |
2582 | 0 | return &(entry); |
2583 | 0 | } |
2584 | | |
2585 | | /************************************************************************/ |
2586 | | /* UnlinkBatch() */ |
2587 | | /************************************************************************/ |
2588 | | |
2589 | | int *VSIFilesystemHandler::UnlinkBatch(CSLConstList papszFiles) |
2590 | 0 | { |
2591 | 0 | int *panRet = |
2592 | 0 | static_cast<int *>(CPLMalloc(sizeof(int) * CSLCount(papszFiles))); |
2593 | 0 | for (int i = 0; papszFiles && papszFiles[i]; ++i) |
2594 | 0 | { |
2595 | 0 | panRet[i] = VSIUnlink(papszFiles[i]) == 0; |
2596 | 0 | } |
2597 | 0 | return panRet; |
2598 | 0 | } |
2599 | | |
2600 | | /************************************************************************/ |
2601 | | /* RmdirRecursive() */ |
2602 | | /************************************************************************/ |
2603 | | |
2604 | | int VSIFilesystemHandler::RmdirRecursive(const char *pszDirname) |
2605 | 0 | { |
2606 | 0 | CPLString osDirnameWithoutEndSlash(pszDirname); |
2607 | 0 | if (!osDirnameWithoutEndSlash.empty() && |
2608 | 0 | (osDirnameWithoutEndSlash.back() == '/' || |
2609 | 0 | osDirnameWithoutEndSlash.back() == '\\')) |
2610 | 0 | { |
2611 | 0 | osDirnameWithoutEndSlash.pop_back(); |
2612 | 0 | } |
2613 | |
|
2614 | 0 | const char SEP = VSIGetDirectorySeparator(pszDirname)[0]; |
2615 | |
|
2616 | 0 | CPLStringList aosOptions; |
2617 | 0 | auto poDir = |
2618 | 0 | std::unique_ptr<VSIDIR>(OpenDir(pszDirname, -1, aosOptions.List())); |
2619 | 0 | if (!poDir) |
2620 | 0 | return -1; |
2621 | 0 | std::vector<std::string> aosDirs; |
2622 | 0 | while (true) |
2623 | 0 | { |
2624 | 0 | auto entry = poDir->NextDirEntry(); |
2625 | 0 | if (!entry) |
2626 | 0 | break; |
2627 | | |
2628 | 0 | CPLString osFilename(osDirnameWithoutEndSlash + SEP + entry->pszName); |
2629 | 0 | if ((entry->nMode & S_IFDIR)) |
2630 | 0 | { |
2631 | 0 | aosDirs.push_back(std::move(osFilename)); |
2632 | 0 | } |
2633 | 0 | else |
2634 | 0 | { |
2635 | 0 | if (VSIUnlink(osFilename) != 0) |
2636 | 0 | return -1; |
2637 | 0 | } |
2638 | 0 | } |
2639 | | |
2640 | | // Sort in reverse order, so that inner-most directories are deleted first |
2641 | 0 | std::sort(aosDirs.begin(), aosDirs.end(), |
2642 | 0 | [](const std::string &a, const std::string &b) { return a > b; }); |
2643 | |
|
2644 | 0 | for (const auto &osDir : aosDirs) |
2645 | 0 | { |
2646 | 0 | if (VSIRmdir(osDir.c_str()) != 0) |
2647 | 0 | return -1; |
2648 | 0 | } |
2649 | | |
2650 | 0 | return VSIRmdir(pszDirname); |
2651 | 0 | } |
2652 | | |
2653 | | /************************************************************************/ |
2654 | | /* GetFileMetadata() */ |
2655 | | /************************************************************************/ |
2656 | | |
2657 | | char **VSIFilesystemHandler::GetFileMetadata(const char * /* pszFilename*/, |
2658 | | const char * /*pszDomain*/, |
2659 | | CSLConstList /*papszOptions*/) |
2660 | 0 | { |
2661 | 0 | return nullptr; |
2662 | 0 | } |
2663 | | |
2664 | | /************************************************************************/ |
2665 | | /* SetFileMetadata() */ |
2666 | | /************************************************************************/ |
2667 | | |
2668 | | bool VSIFilesystemHandler::SetFileMetadata(const char * /* pszFilename*/, |
2669 | | CSLConstList /* papszMetadata */, |
2670 | | const char * /* pszDomain */, |
2671 | | CSLConstList /* papszOptions */) |
2672 | 0 | { |
2673 | 0 | CPLError(CE_Failure, CPLE_NotSupported, "SetFileMetadata() not supported"); |
2674 | 0 | return false; |
2675 | 0 | } |
2676 | | |
2677 | | #endif |
2678 | | |
2679 | | /************************************************************************/ |
2680 | | /* VSIFOpenExL() */ |
2681 | | /************************************************************************/ |
2682 | | |
2683 | | /** |
2684 | | * \brief Open/create file. |
2685 | | * |
2686 | | * This function opens (or creates) a file with the desired access. |
2687 | | * Binary access is always implied and |
2688 | | * the "b" does not need to be included in the pszAccess string. |
2689 | | * |
2690 | | * Note that the "VSILFILE *" returned by this function is |
2691 | | * *NOT* a standard C library FILE *, and cannot be used with any functions |
2692 | | * other than the "VSI*L" family of functions. They aren't "real" FILE objects. |
2693 | | * |
2694 | | * On windows it is possible to define the configuration option |
2695 | | * GDAL_FILE_IS_UTF8 to have pszFilename treated as being in the local |
2696 | | * encoding instead of UTF-8, restoring the pre-1.8.0 behavior of VSIFOpenL(). |
2697 | | * |
2698 | | * This method goes through the VSIFileHandler virtualization and may |
2699 | | * work on unusual filesystems such as in memory. |
2700 | | * |
2701 | | * Analog of the POSIX fopen() function. |
2702 | | * |
2703 | | * @param pszFilename the file to open. UTF-8 encoded. |
2704 | | * @param pszAccess access requested (i.e. "r", "r+", "w") |
2705 | | * @param bSetError flag determining whether or not this open call |
2706 | | * should set VSIErrors on failure. |
2707 | | * |
2708 | | * @return NULL on failure, or the file handle. |
2709 | | * |
2710 | | * @since GDAL 2.1 |
2711 | | */ |
2712 | | |
2713 | | VSILFILE *VSIFOpenExL(const char *pszFilename, const char *pszAccess, |
2714 | | int bSetError) |
2715 | | |
2716 | 0 | { |
2717 | 0 | return VSIFOpenEx2L(pszFilename, pszAccess, bSetError, nullptr); |
2718 | 0 | } |
2719 | | |
2720 | | /************************************************************************/ |
2721 | | /* VSIFOpenEx2L() */ |
2722 | | /************************************************************************/ |
2723 | | |
2724 | | /** |
2725 | | * \brief Open/create file. |
2726 | | * |
2727 | | * This function opens (or creates) a file with the desired access. |
2728 | | * Binary access is always implied and |
2729 | | * the "b" does not need to be included in the pszAccess string. |
2730 | | * |
2731 | | * Note that the "VSILFILE *" returned by this function is |
2732 | | * *NOT* a standard C library FILE *, and cannot be used with any functions |
2733 | | * other than the "VSI*L" family of functions. They aren't "real" FILE objects. |
2734 | | * |
2735 | | * On windows it is possible to define the configuration option |
2736 | | * GDAL_FILE_IS_UTF8 to have pszFilename treated as being in the local |
2737 | | * encoding instead of UTF-8, restoring the pre-1.8.0 behavior of VSIFOpenL(). |
2738 | | * |
2739 | | * This method goes through the VSIFileHandler virtualization and may |
2740 | | * work on unusual filesystems such as in memory. |
2741 | | * |
2742 | | * The following options are supported: |
2743 | | * <ul> |
2744 | | * <li>MIME headers such as Content-Type and Content-Encoding |
2745 | | * are supported for the /vsis3/, /vsigs/, /vsiaz/, /vsiadls/ file systems.</li> |
2746 | | * <li>DISABLE_READDIR_ON_OPEN=YES/NO (GDAL >= 3.6) for /vsicurl/ and other |
2747 | | * network-based file systems. By default, directory file listing is done, |
2748 | | * unless YES is specified.</li> |
2749 | | * <li>WRITE_THROUGH=YES (GDAL >= 3.8) for the Windows regular files to |
2750 | | * set the FILE_FLAG_WRITE_THROUGH flag to the CreateFile() function. In that |
2751 | | * mode, the data is written to the system cache but is flushed to disk without |
2752 | | * delay.</li> |
2753 | | * </ul> |
2754 | | * |
2755 | | * Options specifics to /vsis3/, /vsigs/, /vsioss/ and /vsiaz/ in "w" mode: |
2756 | | * <ul> |
2757 | | * <li>CHUNK_SIZE=val in MiB. (GDAL >= 3.10) Size of a block. Default is 50 MiB. |
2758 | | * For /vsis3/, /vsigz/, /vsioss/, it can be up to 5000 MiB. |
2759 | | * For /vsiaz/, only taken into account when BLOB_TYPE=BLOCK. It can be up to 4000 MiB. |
2760 | | * </li> |
2761 | | * </ul> |
2762 | | * |
2763 | | * Options specifics to /vsiaz/ in "w" mode: |
2764 | | * <ul> |
2765 | | * <li>BLOB_TYPE=APPEND/BLOCK. (GDAL >= 3.10) Type of blob. Defaults to APPEND. |
2766 | | * Append blocks are limited to 195 GiB |
2767 | | * (however if the file size is below 4 MiB, a block blob will be created in a |
2768 | | * single PUT operation) |
2769 | | * </li> |
2770 | | * </ul> |
2771 | | * |
2772 | | * Analog of the POSIX fopen() function. |
2773 | | * |
2774 | | * @param pszFilename the file to open. UTF-8 encoded. |
2775 | | * @param pszAccess access requested (i.e. "r", "r+", "w") |
2776 | | * @param bSetError flag determining whether or not this open call |
2777 | | * should set VSIErrors on failure. |
2778 | | * @param papszOptions NULL or NULL-terminated list of strings. The content is |
2779 | | * highly file system dependent. |
2780 | | * |
2781 | | * |
2782 | | * @return NULL on failure, or the file handle. |
2783 | | * |
2784 | | * @since GDAL 3.3 |
2785 | | */ |
2786 | | |
2787 | | VSILFILE *VSIFOpenEx2L(const char *pszFilename, const char *pszAccess, |
2788 | | int bSetError, CSLConstList papszOptions) |
2789 | | |
2790 | 0 | { |
2791 | | // Too long filenames can cause excessive memory allocation due to |
2792 | | // recursion in some filesystem handlers |
2793 | 0 | constexpr size_t knMaxPath = 8192; |
2794 | 0 | if (CPLStrnlen(pszFilename, knMaxPath) == knMaxPath) |
2795 | 0 | return nullptr; |
2796 | | |
2797 | 0 | VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename); |
2798 | |
|
2799 | 0 | VSILFILE *fp = poFSHandler->Open(pszFilename, pszAccess, |
2800 | 0 | CPL_TO_BOOL(bSetError), papszOptions); |
2801 | |
|
2802 | 0 | VSIDebug4("VSIFOpenEx2L(%s,%s,%d) = %p", pszFilename, pszAccess, bSetError, |
2803 | 0 | fp); |
2804 | |
|
2805 | 0 | return fp; |
2806 | 0 | } |
2807 | | |
2808 | | /************************************************************************/ |
2809 | | /* VSIFCloseL() */ |
2810 | | /************************************************************************/ |
2811 | | |
2812 | | /** |
2813 | | * \fn VSIVirtualHandle::Close() |
2814 | | * \brief Close file. |
2815 | | * |
2816 | | * This function closes the indicated file. |
2817 | | * |
2818 | | * This method goes through the VSIFileHandler virtualization and may |
2819 | | * work on unusual filesystems such as in memory. |
2820 | | * |
2821 | | * Analog of the POSIX fclose() function. |
2822 | | * |
2823 | | * @return 0 on success or -1 on failure. |
2824 | | */ |
2825 | | |
2826 | | /** |
2827 | | * \brief Close file. |
2828 | | * |
2829 | | * This function closes the indicated file. |
2830 | | * |
2831 | | * This method goes through the VSIFileHandler virtualization and may |
2832 | | * work on unusual filesystems such as in memory. |
2833 | | * |
2834 | | * Analog of the POSIX fclose() function. |
2835 | | * |
2836 | | * @param fp file handle opened with VSIFOpenL(). Passing a nullptr produces |
2837 | | * undefined behavior. |
2838 | | * |
2839 | | * @return 0 on success or -1 on failure. |
2840 | | */ |
2841 | | |
2842 | | int VSIFCloseL(VSILFILE *fp) |
2843 | | |
2844 | 5.68k | { |
2845 | 5.68k | VSIDebug1("VSIFCloseL(%p)", fp); |
2846 | | |
2847 | 5.68k | const int nResult = fp->Close(); |
2848 | | |
2849 | 5.68k | delete fp; |
2850 | | |
2851 | 5.68k | return nResult; |
2852 | 5.68k | } |
2853 | | |
2854 | | /************************************************************************/ |
2855 | | /* VSIFSeekL() */ |
2856 | | /************************************************************************/ |
2857 | | |
2858 | | /** |
2859 | | * \fn int VSIVirtualHandle::Seek( vsi_l_offset nOffset, int nWhence ) |
2860 | | * \brief Seek to requested offset. |
2861 | | * |
2862 | | * Seek to the desired offset (nOffset) in the indicated file. |
2863 | | * |
2864 | | * This method goes through the VSIFileHandler virtualization and may |
2865 | | * work on unusual filesystems such as in memory. |
2866 | | * |
2867 | | * Analog of the POSIX fseek() call. |
2868 | | * |
2869 | | * Caution: vsi_l_offset is a unsigned type, so SEEK_CUR can only be used |
2870 | | * for positive seek. If negative seek is needed, use |
2871 | | * handle->Seek( handle->Tell() + negative_offset, SEEK_SET ). |
2872 | | * |
2873 | | * @param nOffset offset in bytes. |
2874 | | * @param nWhence one of SEEK_SET, SEEK_CUR or SEEK_END. |
2875 | | * |
2876 | | * @return 0 on success or -1 one failure. |
2877 | | */ |
2878 | | |
2879 | | /** |
2880 | | * \brief Seek to requested offset. |
2881 | | * |
2882 | | * Seek to the desired offset (nOffset) in the indicated file. |
2883 | | * |
2884 | | * This method goes through the VSIFileHandler virtualization and may |
2885 | | * work on unusual filesystems such as in memory. |
2886 | | * |
2887 | | * Analog of the POSIX fseek() call. |
2888 | | * |
2889 | | * Caution: vsi_l_offset is a unsigned type, so SEEK_CUR can only be used |
2890 | | * for positive seek. If negative seek is needed, use |
2891 | | * VSIFSeekL( fp, VSIFTellL(fp) + negative_offset, SEEK_SET ). |
2892 | | * |
2893 | | * @param fp file handle opened with VSIFOpenL(). |
2894 | | * @param nOffset offset in bytes. |
2895 | | * @param nWhence one of SEEK_SET, SEEK_CUR or SEEK_END. |
2896 | | * |
2897 | | * @return 0 on success or -1 one failure. |
2898 | | */ |
2899 | | |
2900 | | int VSIFSeekL(VSILFILE *fp, vsi_l_offset nOffset, int nWhence) |
2901 | | |
2902 | 336k | { |
2903 | 336k | return fp->Seek(nOffset, nWhence); |
2904 | 336k | } |
2905 | | |
2906 | | /************************************************************************/ |
2907 | | /* VSIFTellL() */ |
2908 | | /************************************************************************/ |
2909 | | |
2910 | | /** |
2911 | | * \fn VSIVirtualHandle::Tell() |
2912 | | * \brief Tell current file offset. |
2913 | | * |
2914 | | * Returns the current file read/write offset in bytes from the beginning of |
2915 | | * the file. |
2916 | | * |
2917 | | * This method goes through the VSIFileHandler virtualization and may |
2918 | | * work on unusual filesystems such as in memory. |
2919 | | * |
2920 | | * Analog of the POSIX ftell() call. |
2921 | | * |
2922 | | * @return file offset in bytes. |
2923 | | */ |
2924 | | |
2925 | | /** |
2926 | | * \brief Tell current file offset. |
2927 | | * |
2928 | | * Returns the current file read/write offset in bytes from the beginning of |
2929 | | * the file. |
2930 | | * |
2931 | | * This method goes through the VSIFileHandler virtualization and may |
2932 | | * work on unusual filesystems such as in memory. |
2933 | | * |
2934 | | * Analog of the POSIX ftell() call. |
2935 | | * |
2936 | | * @param fp file handle opened with VSIFOpenL(). |
2937 | | * |
2938 | | * @return file offset in bytes. |
2939 | | */ |
2940 | | |
2941 | | vsi_l_offset VSIFTellL(VSILFILE *fp) |
2942 | | |
2943 | 966 | { |
2944 | 966 | return fp->Tell(); |
2945 | 966 | } |
2946 | | |
2947 | | /************************************************************************/ |
2948 | | /* VSIRewindL() */ |
2949 | | /************************************************************************/ |
2950 | | |
2951 | | /** |
2952 | | * \brief Rewind the file pointer to the beginning of the file. |
2953 | | * |
2954 | | * This is equivalent to VSIFSeekL( fp, 0, SEEK_SET ) |
2955 | | * |
2956 | | * Analog of the POSIX rewind() call. |
2957 | | * |
2958 | | * @param fp file handle opened with VSIFOpenL(). |
2959 | | */ |
2960 | | |
2961 | | void VSIRewindL(VSILFILE *fp) |
2962 | | |
2963 | 0 | { |
2964 | 0 | CPL_IGNORE_RET_VAL(VSIFSeekL(fp, 0, SEEK_SET)); |
2965 | 0 | } |
2966 | | |
2967 | | /************************************************************************/ |
2968 | | /* VSIFFlushL() */ |
2969 | | /************************************************************************/ |
2970 | | |
2971 | | /** |
2972 | | * \fn VSIVirtualHandle::Flush() |
2973 | | * \brief Flush pending writes to disk. |
2974 | | * |
2975 | | * For files in write or update mode and on filesystem types where it is |
2976 | | * applicable, all pending output on the file is flushed to the physical disk. |
2977 | | * |
2978 | | * This method goes through the VSIFileHandler virtualization and may |
2979 | | * work on unusual filesystems such as in memory. |
2980 | | * |
2981 | | * Analog of the POSIX fflush() call. |
2982 | | * |
2983 | | * On Windows regular files, this method does nothing, unless the |
2984 | | * VSI_FLUSH configuration option is set to YES (and only when the file has |
2985 | | * *not* been opened with the WRITE_THROUGH option). |
2986 | | * |
2987 | | * @return 0 on success or -1 on error. |
2988 | | */ |
2989 | | |
2990 | | /** |
2991 | | * \brief Flush pending writes to disk. |
2992 | | * |
2993 | | * For files in write or update mode and on filesystem types where it is |
2994 | | * applicable, all pending output on the file is flushed to the physical disk. |
2995 | | * |
2996 | | * This method goes through the VSIFileHandler virtualization and may |
2997 | | * work on unusual filesystems such as in memory. |
2998 | | * |
2999 | | * Analog of the POSIX fflush() call. |
3000 | | * |
3001 | | * On Windows regular files, this method does nothing, unless the |
3002 | | * VSI_FLUSH configuration option is set to YES (and only when the file has |
3003 | | * *not* been opened with the WRITE_THROUGH option). |
3004 | | * |
3005 | | * @param fp file handle opened with VSIFOpenL(). |
3006 | | * |
3007 | | * @return 0 on success or -1 on error. |
3008 | | */ |
3009 | | |
3010 | | int VSIFFlushL(VSILFILE *fp) |
3011 | | |
3012 | 0 | { |
3013 | 0 | return fp->Flush(); |
3014 | 0 | } |
3015 | | |
3016 | | /************************************************************************/ |
3017 | | /* VSIFReadL() */ |
3018 | | /************************************************************************/ |
3019 | | |
3020 | | /** |
3021 | | * \fn VSIVirtualHandle::Read( void *pBuffer, size_t nSize, size_t nCount ) |
3022 | | * \brief Read bytes from file. |
3023 | | * |
3024 | | * Reads nCount objects of nSize bytes from the indicated file at the |
3025 | | * current offset into the indicated buffer. |
3026 | | * |
3027 | | * This method goes through the VSIFileHandler virtualization and may |
3028 | | * work on unusual filesystems such as in memory. |
3029 | | * |
3030 | | * Analog of the POSIX fread() call. |
3031 | | * |
3032 | | * @param pBuffer the buffer into which the data should be read (at least |
3033 | | * nCount * nSize bytes in size. |
3034 | | * @param nSize size of objects to read in bytes. |
3035 | | * @param nCount number of objects to read. |
3036 | | * |
3037 | | * @return number of objects successfully read. If that number is less than |
3038 | | * nCount, VSIFEofL() or VSIFErrorL() can be used to determine the reason for |
3039 | | * the short read. |
3040 | | */ |
3041 | | |
3042 | | /** |
3043 | | * \brief Read bytes from file. |
3044 | | * |
3045 | | * Reads nCount objects of nSize bytes from the indicated file at the |
3046 | | * current offset into the indicated buffer. |
3047 | | * |
3048 | | * This method goes through the VSIFileHandler virtualization and may |
3049 | | * work on unusual filesystems such as in memory. |
3050 | | * |
3051 | | * Analog of the POSIX fread() call. |
3052 | | * |
3053 | | * @param pBuffer the buffer into which the data should be read (at least |
3054 | | * nCount * nSize bytes in size. |
3055 | | * @param nSize size of objects to read in bytes. |
3056 | | * @param nCount number of objects to read. |
3057 | | * @param fp file handle opened with VSIFOpenL(). |
3058 | | * |
3059 | | * @return number of objects successfully read. If that number is less than |
3060 | | * nCount, VSIFEofL() or VSIFErrorL() can be used to determine the reason for |
3061 | | * the short read. |
3062 | | */ |
3063 | | |
3064 | | size_t VSIFReadL(void *pBuffer, size_t nSize, size_t nCount, VSILFILE *fp) |
3065 | | |
3066 | 340k | { |
3067 | 340k | return fp->Read(pBuffer, nSize, nCount); |
3068 | 340k | } |
3069 | | |
3070 | | /************************************************************************/ |
3071 | | /* VSIFReadMultiRangeL() */ |
3072 | | /************************************************************************/ |
3073 | | |
3074 | | /** |
3075 | | * \fn VSIVirtualHandle::ReadMultiRange( int nRanges, void ** ppData, |
3076 | | * const vsi_l_offset* panOffsets, |
3077 | | * const size_t* panSizes ) |
3078 | | * \brief Read several ranges of bytes from file. |
3079 | | * |
3080 | | * Reads nRanges objects of panSizes[i] bytes from the indicated file at the |
3081 | | * offset panOffsets[i] into the buffer ppData[i]. |
3082 | | * |
3083 | | * Ranges must be sorted in ascending start offset, and must not overlap each |
3084 | | * other. |
3085 | | * |
3086 | | * This method goes through the VSIFileHandler virtualization and may |
3087 | | * work on unusual filesystems such as in memory or /vsicurl/. |
3088 | | * |
3089 | | * @param nRanges number of ranges to read. |
3090 | | * @param ppData array of nRanges buffer into which the data should be read |
3091 | | * (ppData[i] must be at list panSizes[i] bytes). |
3092 | | * @param panOffsets array of nRanges offsets at which the data should be read. |
3093 | | * @param panSizes array of nRanges sizes of objects to read (in bytes). |
3094 | | * |
3095 | | * @return 0 in case of success, -1 otherwise. |
3096 | | * @since GDAL 1.9.0 |
3097 | | */ |
3098 | | |
3099 | | /** |
3100 | | * \brief Read several ranges of bytes from file. |
3101 | | * |
3102 | | * Reads nRanges objects of panSizes[i] bytes from the indicated file at the |
3103 | | * offset panOffsets[i] into the buffer ppData[i]. |
3104 | | * |
3105 | | * Ranges must be sorted in ascending start offset, and must not overlap each |
3106 | | * other. |
3107 | | * |
3108 | | * This method goes through the VSIFileHandler virtualization and may |
3109 | | * work on unusual filesystems such as in memory or /vsicurl/. |
3110 | | * |
3111 | | * @param nRanges number of ranges to read. |
3112 | | * @param ppData array of nRanges buffer into which the data should be read |
3113 | | * (ppData[i] must be at list panSizes[i] bytes). |
3114 | | * @param panOffsets array of nRanges offsets at which the data should be read. |
3115 | | * @param panSizes array of nRanges sizes of objects to read (in bytes). |
3116 | | * @param fp file handle opened with VSIFOpenL(). |
3117 | | * |
3118 | | * @return 0 in case of success, -1 otherwise. |
3119 | | * @since GDAL 1.9.0 |
3120 | | */ |
3121 | | |
3122 | | int VSIFReadMultiRangeL(int nRanges, void **ppData, |
3123 | | const vsi_l_offset *panOffsets, const size_t *panSizes, |
3124 | | VSILFILE *fp) |
3125 | 0 | { |
3126 | 0 | return fp->ReadMultiRange(nRanges, ppData, panOffsets, panSizes); |
3127 | 0 | } |
3128 | | |
3129 | | /************************************************************************/ |
3130 | | /* VSIFWriteL() */ |
3131 | | /************************************************************************/ |
3132 | | |
3133 | | /** |
3134 | | * \fn VSIVirtualHandle::Write( const void *pBuffer, |
3135 | | * size_t nSize, size_t nCount ) |
3136 | | * \brief Write bytes to file. |
3137 | | * |
3138 | | * Writes nCount objects of nSize bytes to the indicated file at the |
3139 | | * current offset into the indicated buffer. |
3140 | | * |
3141 | | * This method goes through the VSIFileHandler virtualization and may |
3142 | | * work on unusual filesystems such as in memory. |
3143 | | * |
3144 | | * Analog of the POSIX fwrite() call. |
3145 | | * |
3146 | | * @param pBuffer the buffer from which the data should be written (at least |
3147 | | * nCount * nSize bytes in size. |
3148 | | * @param nSize size of objects to write in bytes. |
3149 | | * @param nCount number of objects to write. |
3150 | | * |
3151 | | * @return number of objects successfully written. |
3152 | | */ |
3153 | | |
3154 | | /** |
3155 | | * \brief Write bytes to file. |
3156 | | * |
3157 | | * Writes nCount objects of nSize bytes to the indicated file at the |
3158 | | * current offset into the indicated buffer. |
3159 | | * |
3160 | | * This method goes through the VSIFileHandler virtualization and may |
3161 | | * work on unusual filesystems such as in memory. |
3162 | | * |
3163 | | * Analog of the POSIX fwrite() call. |
3164 | | * |
3165 | | * @param pBuffer the buffer from which the data should be written (at least |
3166 | | * nCount * nSize bytes in size. |
3167 | | * @param nSize size of objects to write in bytes. |
3168 | | * @param nCount number of objects to write. |
3169 | | * @param fp file handle opened with VSIFOpenL(). |
3170 | | * |
3171 | | * @return number of objects successfully written. |
3172 | | */ |
3173 | | |
3174 | | size_t VSIFWriteL(const void *pBuffer, size_t nSize, size_t nCount, |
3175 | | VSILFILE *fp) |
3176 | | |
3177 | 0 | { |
3178 | 0 | return fp->Write(pBuffer, nSize, nCount); |
3179 | 0 | } |
3180 | | |
3181 | | /************************************************************************/ |
3182 | | /* VSIFEofL() */ |
3183 | | /************************************************************************/ |
3184 | | |
3185 | | /** |
3186 | | * \fn VSIVirtualHandle::Eof() |
3187 | | * \brief Test for end of file. |
3188 | | * |
3189 | | * Returns TRUE (non-zero) if an end-of-file condition occurred during the |
3190 | | * previous read operation. The end-of-file flag is cleared by a successful |
3191 | | * VSIFSeekL() call, or a call to VSIFClearErrL(). |
3192 | | * |
3193 | | * This method goes through the VSIFileHandler virtualization and may |
3194 | | * work on unusual filesystems such as in memory. |
3195 | | * |
3196 | | * Analog of the POSIX feof() call. |
3197 | | * |
3198 | | * @return TRUE if at EOF, else FALSE. |
3199 | | */ |
3200 | | |
3201 | | /** |
3202 | | * \brief Test for end of file. |
3203 | | * |
3204 | | * Returns TRUE (non-zero) if an end-of-file condition occurred during the |
3205 | | * previous read operation. The end-of-file flag is cleared by a successful |
3206 | | * VSIFSeekL() call, or a call to VSIFClearErrL(). |
3207 | | * |
3208 | | * This method goes through the VSIFileHandler virtualization and may |
3209 | | * work on unusual filesystems such as in memory. |
3210 | | * |
3211 | | * Analog of the POSIX feof() call. |
3212 | | * |
3213 | | * @param fp file handle opened with VSIFOpenL(). |
3214 | | * |
3215 | | * @return TRUE if at EOF, else FALSE. |
3216 | | */ |
3217 | | |
3218 | | int VSIFEofL(VSILFILE *fp) |
3219 | | |
3220 | 0 | { |
3221 | 0 | return fp->Eof(); |
3222 | 0 | } |
3223 | | |
3224 | | /************************************************************************/ |
3225 | | /* VSIFErrorL() */ |
3226 | | /************************************************************************/ |
3227 | | |
3228 | | /** |
3229 | | * \fn VSIVirtualHandle::Error() |
3230 | | * \brief Test the error indicator. |
3231 | | * |
3232 | | * Returns TRUE (non-zero) if an error condition occurred during the |
3233 | | * previous read operation. The error indicator is cleared by a call to |
3234 | | * VSIFClearErrL(). Note that a end-of-file situation, reported by VSIFEofL(), |
3235 | | * is *not* an error reported by VSIFErrorL(). |
3236 | | * |
3237 | | * This method goes through the VSIFileHandler virtualization and may |
3238 | | * work on unusual filesystems such as in memory. |
3239 | | * |
3240 | | * Analog of the POSIX ferror() call. |
3241 | | * |
3242 | | * @return TRUE if the error indicator is set, else FALSE. |
3243 | | * @since 3.10 |
3244 | | */ |
3245 | | |
3246 | | /** |
3247 | | * \brief Test the error indicator. |
3248 | | * |
3249 | | * Returns TRUE (non-zero) if an error condition occurred during the |
3250 | | * previous read operation. The error indicator is cleared by a call to |
3251 | | * VSIFClearErrL(). Note that a end-of-file situation, reported by VSIFEofL(), |
3252 | | * is *not* an error reported by VSIFErrorL(). |
3253 | | * |
3254 | | * This method goes through the VSIFileHandler virtualization and may |
3255 | | * work on unusual filesystems such as in memory. |
3256 | | * |
3257 | | * Analog of the POSIX feof() call. |
3258 | | * |
3259 | | * @param fp file handle opened with VSIFOpenL(). |
3260 | | * |
3261 | | * @return TRUE if the error indicator is set, else FALSE. |
3262 | | * @since 3.10 |
3263 | | */ |
3264 | | |
3265 | | int VSIFErrorL(VSILFILE *fp) |
3266 | | |
3267 | 0 | { |
3268 | 0 | return fp->Error(); |
3269 | 0 | } |
3270 | | |
3271 | | /************************************************************************/ |
3272 | | /* VSIFClearErrL() */ |
3273 | | /************************************************************************/ |
3274 | | |
3275 | | /** |
3276 | | * \fn VSIVirtualHandle::ClearErr() |
3277 | | * \brief Reset the error and end-of-file indicators. |
3278 | | * |
3279 | | * This method goes through the VSIFileHandler virtualization and may |
3280 | | * work on unusual filesystems such as in memory. |
3281 | | * |
3282 | | * Analog of the POSIX clearerr() call. |
3283 | | * |
3284 | | * @since 3.10 |
3285 | | */ |
3286 | | |
3287 | | /** |
3288 | | * \brief Reset the error and end-of-file indicators. |
3289 | | * |
3290 | | * This method goes through the VSIFileHandler virtualization and may |
3291 | | * work on unusual filesystems such as in memory. |
3292 | | * |
3293 | | * Analog of the POSIX clearerr() call. |
3294 | | * |
3295 | | * @param fp file handle opened with VSIFOpenL(). |
3296 | | * |
3297 | | * @since 3.10 |
3298 | | */ |
3299 | | |
3300 | | void VSIFClearErrL(VSILFILE *fp) |
3301 | | |
3302 | 0 | { |
3303 | 0 | fp->ClearErr(); |
3304 | 0 | } |
3305 | | |
3306 | | /************************************************************************/ |
3307 | | /* VSIFTruncateL() */ |
3308 | | /************************************************************************/ |
3309 | | |
3310 | | /** |
3311 | | * \fn VSIVirtualHandle::Truncate( vsi_l_offset nNewSize ) |
3312 | | * \brief Truncate/expand the file to the specified size |
3313 | | |
3314 | | * This method goes through the VSIFileHandler virtualization and may |
3315 | | * work on unusual filesystems such as in memory. |
3316 | | * |
3317 | | * Analog of the POSIX ftruncate() call. |
3318 | | * |
3319 | | * @param nNewSize new size in bytes. |
3320 | | * |
3321 | | * @return 0 on success |
3322 | | * @since GDAL 1.9.0 |
3323 | | */ |
3324 | | |
3325 | | /** |
3326 | | * \brief Truncate/expand the file to the specified size |
3327 | | |
3328 | | * This method goes through the VSIFileHandler virtualization and may |
3329 | | * work on unusual filesystems such as in memory. |
3330 | | * |
3331 | | * Analog of the POSIX ftruncate() call. |
3332 | | * |
3333 | | * @param fp file handle opened with VSIFOpenL(). |
3334 | | * @param nNewSize new size in bytes. |
3335 | | * |
3336 | | * @return 0 on success |
3337 | | * @since GDAL 1.9.0 |
3338 | | */ |
3339 | | |
3340 | | int VSIFTruncateL(VSILFILE *fp, vsi_l_offset nNewSize) |
3341 | | |
3342 | 0 | { |
3343 | 0 | return fp->Truncate(nNewSize); |
3344 | 0 | } |
3345 | | |
3346 | | /************************************************************************/ |
3347 | | /* VSIFPrintfL() */ |
3348 | | /************************************************************************/ |
3349 | | |
3350 | | /** |
3351 | | * \brief Formatted write to file. |
3352 | | * |
3353 | | * Provides fprintf() style formatted output to a VSI*L file. This formats |
3354 | | * an internal buffer which is written using VSIFWriteL(). |
3355 | | * |
3356 | | * Analog of the POSIX fprintf() call. |
3357 | | * |
3358 | | * @param fp file handle opened with VSIFOpenL(). |
3359 | | * @param pszFormat the printf() style format string. |
3360 | | * |
3361 | | * @return the number of bytes written or -1 on an error. |
3362 | | */ |
3363 | | |
3364 | | int VSIFPrintfL(VSILFILE *fp, CPL_FORMAT_STRING(const char *pszFormat), ...) |
3365 | | |
3366 | 0 | { |
3367 | 0 | va_list args; |
3368 | |
|
3369 | 0 | va_start(args, pszFormat); |
3370 | 0 | CPLString osResult; |
3371 | 0 | osResult.vPrintf(pszFormat, args); |
3372 | 0 | va_end(args); |
3373 | |
|
3374 | 0 | return static_cast<int>( |
3375 | 0 | VSIFWriteL(osResult.c_str(), 1, osResult.length(), fp)); |
3376 | 0 | } |
3377 | | |
3378 | | /************************************************************************/ |
3379 | | /* VSIVirtualHandle::Printf() */ |
3380 | | /************************************************************************/ |
3381 | | |
3382 | | /** |
3383 | | * \brief Formatted write to file. |
3384 | | * |
3385 | | * Provides fprintf() style formatted output to a VSI*L file. This formats |
3386 | | * an internal buffer which is written using VSIFWriteL(). |
3387 | | * |
3388 | | * Analog of the POSIX fprintf() call. |
3389 | | * |
3390 | | * @param pszFormat the printf() style format string. |
3391 | | * |
3392 | | * @return the number of bytes written or -1 on an error. |
3393 | | */ |
3394 | | |
3395 | | int VSIVirtualHandle::Printf(CPL_FORMAT_STRING(const char *pszFormat), ...) |
3396 | 0 | { |
3397 | 0 | va_list args; |
3398 | |
|
3399 | 0 | va_start(args, pszFormat); |
3400 | 0 | CPLString osResult; |
3401 | 0 | osResult.vPrintf(pszFormat, args); |
3402 | 0 | va_end(args); |
3403 | |
|
3404 | 0 | return static_cast<int>(Write(osResult.c_str(), 1, osResult.length())); |
3405 | 0 | } |
3406 | | |
3407 | | /************************************************************************/ |
3408 | | /* VSIFPutcL() */ |
3409 | | /************************************************************************/ |
3410 | | |
3411 | | // TODO: should we put in conformance with POSIX regarding the return |
3412 | | // value. As of today (2015-08-29), no code in GDAL sources actually |
3413 | | // check the return value. |
3414 | | |
3415 | | /** |
3416 | | * \brief Write a single byte to the file |
3417 | | * |
3418 | | * Writes the character nChar, cast to an unsigned char, to file. |
3419 | | * |
3420 | | * Almost an analog of the POSIX fputc() call, except that it returns |
3421 | | * the number of character written (1 or 0), and not the (cast) |
3422 | | * character itself or EOF. |
3423 | | * |
3424 | | * @param nChar character to write. |
3425 | | * @param fp file handle opened with VSIFOpenL(). |
3426 | | * |
3427 | | * @return 1 in case of success, 0 on error. |
3428 | | */ |
3429 | | |
3430 | | int VSIFPutcL(int nChar, VSILFILE *fp) |
3431 | | |
3432 | 0 | { |
3433 | 0 | const unsigned char cChar = static_cast<unsigned char>(nChar); |
3434 | 0 | return static_cast<int>(VSIFWriteL(&cChar, 1, 1, fp)); |
3435 | 0 | } |
3436 | | |
3437 | | /************************************************************************/ |
3438 | | /* VSIFGetRangeStatusL() */ |
3439 | | /************************************************************************/ |
3440 | | |
3441 | | /** |
3442 | | * \fn VSIVirtualHandle::GetRangeStatus( vsi_l_offset nOffset, |
3443 | | * vsi_l_offset nLength ) |
3444 | | * \brief Return if a given file range contains data or holes filled with zeroes |
3445 | | * |
3446 | | * This uses the filesystem capabilities of querying which regions of |
3447 | | * a sparse file are allocated or not. This is currently only |
3448 | | * implemented for Linux (and no other Unix derivatives) and Windows. |
3449 | | * |
3450 | | * Note: A return of VSI_RANGE_STATUS_DATA doesn't exclude that the |
3451 | | * extent is filled with zeroes! It must be interpreted as "may |
3452 | | * contain non-zero data". |
3453 | | * |
3454 | | * @param nOffset offset of the start of the extent. |
3455 | | * @param nLength extent length. |
3456 | | * |
3457 | | * @return extent status: VSI_RANGE_STATUS_UNKNOWN, VSI_RANGE_STATUS_DATA or |
3458 | | * VSI_RANGE_STATUS_HOLE |
3459 | | * @since GDAL 2.2 |
3460 | | */ |
3461 | | |
3462 | | /** |
3463 | | * \brief Return if a given file range contains data or holes filled with zeroes |
3464 | | * |
3465 | | * This uses the filesystem capabilities of querying which regions of |
3466 | | * a sparse file are allocated or not. This is currently only |
3467 | | * implemented for Linux (and no other Unix derivatives) and Windows. |
3468 | | * |
3469 | | * Note: A return of VSI_RANGE_STATUS_DATA doesn't exclude that the |
3470 | | * extent is filled with zeroes! It must be interpreted as "may |
3471 | | * contain non-zero data". |
3472 | | * |
3473 | | * @param fp file handle opened with VSIFOpenL(). |
3474 | | * @param nOffset offset of the start of the extent. |
3475 | | * @param nLength extent length. |
3476 | | * |
3477 | | * @return extent status: VSI_RANGE_STATUS_UNKNOWN, VSI_RANGE_STATUS_DATA or |
3478 | | * VSI_RANGE_STATUS_HOLE |
3479 | | * @since GDAL 2.2 |
3480 | | */ |
3481 | | |
3482 | | VSIRangeStatus VSIFGetRangeStatusL(VSILFILE *fp, vsi_l_offset nOffset, |
3483 | | vsi_l_offset nLength) |
3484 | 0 | { |
3485 | 0 | return fp->GetRangeStatus(nOffset, nLength); |
3486 | 0 | } |
3487 | | |
3488 | | /************************************************************************/ |
3489 | | /* VSIIngestFile() */ |
3490 | | /************************************************************************/ |
3491 | | |
3492 | | /** |
3493 | | * \brief Ingest a file into memory. |
3494 | | * |
3495 | | * Read the whole content of a file into a memory buffer. |
3496 | | * |
3497 | | * Either fp or pszFilename can be NULL, but not both at the same time. |
3498 | | * |
3499 | | * If fp is passed non-NULL, it is the responsibility of the caller to |
3500 | | * close it. |
3501 | | * |
3502 | | * If non-NULL, the returned buffer is guaranteed to be NUL-terminated. |
3503 | | * |
3504 | | * @param fp file handle opened with VSIFOpenL(). |
3505 | | * @param pszFilename filename. |
3506 | | * @param ppabyRet pointer to the target buffer. *ppabyRet must be freed with |
3507 | | * VSIFree() |
3508 | | * @param pnSize pointer to variable to store the file size. May be NULL. |
3509 | | * @param nMaxSize maximum size of file allowed. If no limit, set to a negative |
3510 | | * value. |
3511 | | * |
3512 | | * @return TRUE in case of success. |
3513 | | * |
3514 | | * @since GDAL 1.11 |
3515 | | */ |
3516 | | |
3517 | | int VSIIngestFile(VSILFILE *fp, const char *pszFilename, GByte **ppabyRet, |
3518 | | vsi_l_offset *pnSize, GIntBig nMaxSize) |
3519 | 0 | { |
3520 | 0 | if (fp == nullptr && pszFilename == nullptr) |
3521 | 0 | return FALSE; |
3522 | 0 | if (ppabyRet == nullptr) |
3523 | 0 | return FALSE; |
3524 | | |
3525 | 0 | *ppabyRet = nullptr; |
3526 | 0 | if (pnSize != nullptr) |
3527 | 0 | *pnSize = 0; |
3528 | |
|
3529 | 0 | bool bFreeFP = false; |
3530 | 0 | if (nullptr == fp) |
3531 | 0 | { |
3532 | 0 | fp = VSIFOpenL(pszFilename, "rb"); |
3533 | 0 | if (nullptr == fp) |
3534 | 0 | { |
3535 | 0 | CPLError(CE_Failure, CPLE_FileIO, "Cannot open file '%s'", |
3536 | 0 | pszFilename); |
3537 | 0 | return FALSE; |
3538 | 0 | } |
3539 | 0 | bFreeFP = true; |
3540 | 0 | } |
3541 | 0 | else |
3542 | 0 | { |
3543 | 0 | if (VSIFSeekL(fp, 0, SEEK_SET) != 0) |
3544 | 0 | return FALSE; |
3545 | 0 | } |
3546 | | |
3547 | 0 | vsi_l_offset nDataLen = 0; |
3548 | |
|
3549 | 0 | if (pszFilename == nullptr || strcmp(pszFilename, "/vsistdin/") == 0) |
3550 | 0 | { |
3551 | 0 | vsi_l_offset nDataAlloc = 0; |
3552 | 0 | if (VSIFSeekL(fp, 0, SEEK_SET) != 0) |
3553 | 0 | { |
3554 | 0 | if (bFreeFP) |
3555 | 0 | CPL_IGNORE_RET_VAL(VSIFCloseL(fp)); |
3556 | 0 | return FALSE; |
3557 | 0 | } |
3558 | 0 | while (true) |
3559 | 0 | { |
3560 | 0 | if (nDataLen + 8192 + 1 > nDataAlloc) |
3561 | 0 | { |
3562 | 0 | nDataAlloc = (nDataAlloc * 4) / 3 + 8192 + 1; |
3563 | 0 | if (nDataAlloc > |
3564 | 0 | static_cast<vsi_l_offset>(static_cast<size_t>(nDataAlloc))) |
3565 | 0 | { |
3566 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
3567 | 0 | "Input file too large to be opened"); |
3568 | 0 | VSIFree(*ppabyRet); |
3569 | 0 | *ppabyRet = nullptr; |
3570 | 0 | if (bFreeFP) |
3571 | 0 | CPL_IGNORE_RET_VAL(VSIFCloseL(fp)); |
3572 | 0 | return FALSE; |
3573 | 0 | } |
3574 | 0 | GByte *pabyNew = static_cast<GByte *>( |
3575 | 0 | VSIRealloc(*ppabyRet, static_cast<size_t>(nDataAlloc))); |
3576 | 0 | if (pabyNew == nullptr) |
3577 | 0 | { |
3578 | 0 | CPLError(CE_Failure, CPLE_OutOfMemory, |
3579 | 0 | "Cannot allocate " CPL_FRMT_GIB " bytes", |
3580 | 0 | nDataAlloc); |
3581 | 0 | VSIFree(*ppabyRet); |
3582 | 0 | *ppabyRet = nullptr; |
3583 | 0 | if (bFreeFP) |
3584 | 0 | CPL_IGNORE_RET_VAL(VSIFCloseL(fp)); |
3585 | 0 | return FALSE; |
3586 | 0 | } |
3587 | 0 | *ppabyRet = pabyNew; |
3588 | 0 | } |
3589 | 0 | const int nRead = |
3590 | 0 | static_cast<int>(VSIFReadL(*ppabyRet + nDataLen, 1, 8192, fp)); |
3591 | 0 | nDataLen += nRead; |
3592 | |
|
3593 | 0 | if (nMaxSize >= 0 && nDataLen > static_cast<vsi_l_offset>(nMaxSize)) |
3594 | 0 | { |
3595 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
3596 | 0 | "Input file too large to be opened"); |
3597 | 0 | VSIFree(*ppabyRet); |
3598 | 0 | *ppabyRet = nullptr; |
3599 | 0 | if (pnSize != nullptr) |
3600 | 0 | *pnSize = 0; |
3601 | 0 | if (bFreeFP) |
3602 | 0 | CPL_IGNORE_RET_VAL(VSIFCloseL(fp)); |
3603 | 0 | return FALSE; |
3604 | 0 | } |
3605 | | |
3606 | 0 | if (pnSize != nullptr) |
3607 | 0 | *pnSize += nRead; |
3608 | 0 | (*ppabyRet)[nDataLen] = '\0'; |
3609 | 0 | if (nRead == 0) |
3610 | 0 | break; |
3611 | 0 | } |
3612 | 0 | } |
3613 | 0 | else |
3614 | 0 | { |
3615 | 0 | if (VSIFSeekL(fp, 0, SEEK_END) != 0) |
3616 | 0 | { |
3617 | 0 | if (bFreeFP) |
3618 | 0 | CPL_IGNORE_RET_VAL(VSIFCloseL(fp)); |
3619 | 0 | return FALSE; |
3620 | 0 | } |
3621 | 0 | nDataLen = VSIFTellL(fp); |
3622 | | |
3623 | | // With "large" VSI I/O API we can read data chunks larger than |
3624 | | // VSIMalloc could allocate. Catch it here. |
3625 | 0 | if (nDataLen != |
3626 | 0 | static_cast<vsi_l_offset>(static_cast<size_t>(nDataLen)) || |
3627 | 0 | nDataLen + 1 < nDataLen |
3628 | | // opening a directory returns nDataLen = INT_MAX (on 32bit) or |
3629 | | // INT64_MAX (on 64bit) |
3630 | 0 | || nDataLen + 1 > std::numeric_limits<size_t>::max() / 2 || |
3631 | 0 | (nMaxSize >= 0 && nDataLen > static_cast<vsi_l_offset>(nMaxSize))) |
3632 | 0 | { |
3633 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
3634 | 0 | "Input file too large to be opened"); |
3635 | 0 | if (bFreeFP) |
3636 | 0 | CPL_IGNORE_RET_VAL(VSIFCloseL(fp)); |
3637 | 0 | return FALSE; |
3638 | 0 | } |
3639 | | |
3640 | 0 | if (VSIFSeekL(fp, 0, SEEK_SET) != 0) |
3641 | 0 | { |
3642 | 0 | if (bFreeFP) |
3643 | 0 | CPL_IGNORE_RET_VAL(VSIFCloseL(fp)); |
3644 | 0 | return FALSE; |
3645 | 0 | } |
3646 | | |
3647 | 0 | *ppabyRet = |
3648 | 0 | static_cast<GByte *>(VSIMalloc(static_cast<size_t>(nDataLen + 1))); |
3649 | 0 | if (nullptr == *ppabyRet) |
3650 | 0 | { |
3651 | 0 | CPLError(CE_Failure, CPLE_OutOfMemory, |
3652 | 0 | "Cannot allocate " CPL_FRMT_GIB " bytes", nDataLen + 1); |
3653 | 0 | if (bFreeFP) |
3654 | 0 | CPL_IGNORE_RET_VAL(VSIFCloseL(fp)); |
3655 | 0 | return FALSE; |
3656 | 0 | } |
3657 | | |
3658 | 0 | (*ppabyRet)[nDataLen] = '\0'; |
3659 | 0 | if (nDataLen != |
3660 | 0 | VSIFReadL(*ppabyRet, 1, static_cast<size_t>(nDataLen), fp)) |
3661 | 0 | { |
3662 | 0 | CPLError(CE_Failure, CPLE_FileIO, |
3663 | 0 | "Cannot read " CPL_FRMT_GIB " bytes", nDataLen); |
3664 | 0 | VSIFree(*ppabyRet); |
3665 | 0 | *ppabyRet = nullptr; |
3666 | 0 | if (bFreeFP) |
3667 | 0 | CPL_IGNORE_RET_VAL(VSIFCloseL(fp)); |
3668 | 0 | return FALSE; |
3669 | 0 | } |
3670 | 0 | if (pnSize != nullptr) |
3671 | 0 | *pnSize = nDataLen; |
3672 | 0 | } |
3673 | 0 | if (bFreeFP) |
3674 | 0 | CPL_IGNORE_RET_VAL(VSIFCloseL(fp)); |
3675 | 0 | return TRUE; |
3676 | 0 | } |
3677 | | |
3678 | | /************************************************************************/ |
3679 | | /* VSIOverwriteFile() */ |
3680 | | /************************************************************************/ |
3681 | | |
3682 | | /** |
3683 | | * \brief Overwrite an existing file with content from another one |
3684 | | * |
3685 | | * @param fpTarget file handle opened with VSIFOpenL() with "rb+" flag. |
3686 | | * @param pszSourceFilename source filename |
3687 | | * |
3688 | | * @return TRUE in case of success. |
3689 | | * |
3690 | | * @since GDAL 3.1 |
3691 | | */ |
3692 | | |
3693 | | int VSIOverwriteFile(VSILFILE *fpTarget, const char *pszSourceFilename) |
3694 | 0 | { |
3695 | 0 | VSILFILE *fpSource = VSIFOpenL(pszSourceFilename, "rb"); |
3696 | 0 | if (fpSource == nullptr) |
3697 | 0 | { |
3698 | 0 | CPLError(CE_Failure, CPLE_FileIO, "Cannot open %s", pszSourceFilename); |
3699 | 0 | return false; |
3700 | 0 | } |
3701 | | |
3702 | 0 | const size_t nBufferSize = 4096; |
3703 | 0 | void *pBuffer = CPLMalloc(nBufferSize); |
3704 | 0 | VSIFSeekL(fpTarget, 0, SEEK_SET); |
3705 | 0 | bool bRet = true; |
3706 | 0 | while (true) |
3707 | 0 | { |
3708 | 0 | size_t nRead = VSIFReadL(pBuffer, 1, nBufferSize, fpSource); |
3709 | 0 | size_t nWritten = VSIFWriteL(pBuffer, 1, nRead, fpTarget); |
3710 | 0 | if (nWritten != nRead) |
3711 | 0 | { |
3712 | 0 | bRet = false; |
3713 | 0 | break; |
3714 | 0 | } |
3715 | 0 | if (nRead < nBufferSize) |
3716 | 0 | break; |
3717 | 0 | } |
3718 | |
|
3719 | 0 | if (bRet) |
3720 | 0 | { |
3721 | 0 | bRet = VSIFTruncateL(fpTarget, VSIFTellL(fpTarget)) == 0; |
3722 | 0 | if (!bRet) |
3723 | 0 | { |
3724 | 0 | CPLError(CE_Failure, CPLE_FileIO, "Truncation failed"); |
3725 | 0 | } |
3726 | 0 | } |
3727 | |
|
3728 | 0 | CPLFree(pBuffer); |
3729 | 0 | VSIFCloseL(fpSource); |
3730 | 0 | return bRet; |
3731 | 0 | } |
3732 | | |
3733 | | /************************************************************************/ |
3734 | | /* VSIFGetNativeFileDescriptorL() */ |
3735 | | /************************************************************************/ |
3736 | | |
3737 | | /** |
3738 | | * \fn VSIVirtualHandle::GetNativeFileDescriptor() |
3739 | | * \brief Returns the "native" file descriptor for the virtual handle. |
3740 | | * |
3741 | | * This will only return a non-NULL value for "real" files handled by the |
3742 | | * operating system (to be opposed to GDAL virtual file systems). |
3743 | | * |
3744 | | * On POSIX systems, this will be a integer value ("fd") cast as a void*. |
3745 | | * On Windows systems, this will be the HANDLE. |
3746 | | * |
3747 | | * @return the native file descriptor, or NULL. |
3748 | | */ |
3749 | | |
3750 | | /** |
3751 | | * \brief Returns the "native" file descriptor for the virtual handle. |
3752 | | * |
3753 | | * This will only return a non-NULL value for "real" files handled by the |
3754 | | * operating system (to be opposed to GDAL virtual file systems). |
3755 | | * |
3756 | | * On POSIX systems, this will be a integer value ("fd") cast as a void*. |
3757 | | * On Windows systems, this will be the HANDLE. |
3758 | | * |
3759 | | * @param fp file handle opened with VSIFOpenL(). |
3760 | | * |
3761 | | * @return the native file descriptor, or NULL. |
3762 | | */ |
3763 | | |
3764 | | void *VSIFGetNativeFileDescriptorL(VSILFILE *fp) |
3765 | 0 | { |
3766 | 0 | return fp->GetNativeFileDescriptor(); |
3767 | 0 | } |
3768 | | |
3769 | | /************************************************************************/ |
3770 | | /* VSIGetDiskFreeSpace() */ |
3771 | | /************************************************************************/ |
3772 | | |
3773 | | /** |
3774 | | * \brief Return free disk space available on the filesystem. |
3775 | | * |
3776 | | * This function returns the free disk space available on the filesystem. |
3777 | | * |
3778 | | * @param pszDirname a directory of the filesystem to query. |
3779 | | * @return The free space in bytes. Or -1 in case of error. |
3780 | | * @since GDAL 2.1 |
3781 | | */ |
3782 | | |
3783 | | GIntBig VSIGetDiskFreeSpace(const char *pszDirname) |
3784 | 0 | { |
3785 | 0 | VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszDirname); |
3786 | |
|
3787 | 0 | return poFSHandler->GetDiskFreeSpace(pszDirname); |
3788 | 0 | } |
3789 | | |
3790 | | /************************************************************************/ |
3791 | | /* VSIGetFileSystemsPrefixes() */ |
3792 | | /************************************************************************/ |
3793 | | |
3794 | | /** |
3795 | | * \brief Return the list of prefixes for virtual file system handlers |
3796 | | * currently registered. |
3797 | | * |
3798 | | * Typically: "", "/vsimem/", "/vsicurl/", etc |
3799 | | * |
3800 | | * @return a NULL terminated list of prefixes. Must be freed with CSLDestroy() |
3801 | | * @since GDAL 2.3 |
3802 | | */ |
3803 | | |
3804 | | char **VSIGetFileSystemsPrefixes(void) |
3805 | 0 | { |
3806 | 0 | return VSIFileManager::GetPrefixes(); |
3807 | 0 | } |
3808 | | |
3809 | | /************************************************************************/ |
3810 | | /* VSIGetFileSystemOptions() */ |
3811 | | /************************************************************************/ |
3812 | | |
3813 | | /** |
3814 | | * \brief Return the list of options associated with a virtual file system |
3815 | | * handler as a serialized XML string. |
3816 | | * |
3817 | | * Those options may be set as configuration options with CPLSetConfigOption(). |
3818 | | * |
3819 | | * @param pszFilename a filename, or prefix of a virtual file system handler. |
3820 | | * @return a string, which must not be freed, or NULL if no options is declared. |
3821 | | * @since GDAL 2.3 |
3822 | | */ |
3823 | | |
3824 | | const char *VSIGetFileSystemOptions(const char *pszFilename) |
3825 | 0 | { |
3826 | 0 | VSIFilesystemHandler *poFSHandler = VSIFileManager::GetHandler(pszFilename); |
3827 | |
|
3828 | 0 | return poFSHandler->GetOptions(); |
3829 | 0 | } |
3830 | | |
3831 | | /************************************************************************/ |
3832 | | /* VSISetPathSpecificOption() */ |
3833 | | /************************************************************************/ |
3834 | | |
3835 | | static std::mutex oMutexPathSpecificOptions; |
3836 | | |
3837 | | // key is a path prefix |
3838 | | // value is a map of key, value pair |
3839 | | static std::map<std::string, std::map<std::string, std::string>> |
3840 | | oMapPathSpecificOptions; |
3841 | | |
3842 | | /** |
3843 | | * \brief Set a credential (or more generally an option related to a |
3844 | | * virtual file system) for a given path prefix. |
3845 | | * @deprecated in GDAL 3.6 for the better named VSISetPathSpecificOption() |
3846 | | * @see VSISetPathSpecificOption() |
3847 | | */ |
3848 | | void VSISetCredential(const char *pszPathPrefix, const char *pszKey, |
3849 | | const char *pszValue) |
3850 | 0 | { |
3851 | 0 | VSISetPathSpecificOption(pszPathPrefix, pszKey, pszValue); |
3852 | 0 | } |
3853 | | |
3854 | | /** |
3855 | | * \brief Set a path specific option for a given path prefix. |
3856 | | * |
3857 | | * Such option is typically, but not limited to, a credential setting for a |
3858 | | * virtual file system. |
3859 | | * |
3860 | | * That option may also be set as a configuration option with |
3861 | | * CPLSetConfigOption(), but this function allows to specify them with a |
3862 | | * granularity at the level of a file path, which makes it easier if using the |
3863 | | * same virtual file system but with different credentials (e.g. different |
3864 | | * credentials for bucket "/vsis3/foo" and "/vsis3/bar") |
3865 | | * |
3866 | | * This is supported for the following virtual file systems: |
3867 | | * /vsis3/, /vsigs/, /vsiaz/, /vsioss/, /vsiwebhdfs, /vsiswift. |
3868 | | * Note: setting them for a path starting with /vsiXXX/ will also apply for |
3869 | | * /vsiXXX_streaming/ requests. |
3870 | | * |
3871 | | * Note that no particular care is taken to store them in RAM in a secure way. |
3872 | | * So they might accidentally hit persistent storage if swapping occurs, or |
3873 | | * someone with access to the memory allocated by the process may be able to |
3874 | | * read them. |
3875 | | * |
3876 | | * @param pszPathPrefix a path prefix of a virtual file system handler. |
3877 | | * Typically of the form "/vsiXXX/bucket". Must NOT be |
3878 | | * NULL. Should not include trailing slashes. |
3879 | | * @param pszKey Option name. Must NOT be NULL. |
3880 | | * @param pszValue Option value. May be NULL to erase it. |
3881 | | * |
3882 | | * @since GDAL 3.6 |
3883 | | */ |
3884 | | |
3885 | | void VSISetPathSpecificOption(const char *pszPathPrefix, const char *pszKey, |
3886 | | const char *pszValue) |
3887 | 0 | { |
3888 | 0 | std::lock_guard<std::mutex> oLock(oMutexPathSpecificOptions); |
3889 | 0 | auto oIter = oMapPathSpecificOptions.find(pszPathPrefix); |
3890 | 0 | CPLString osKey(pszKey); |
3891 | 0 | osKey.toupper(); |
3892 | 0 | if (oIter == oMapPathSpecificOptions.end()) |
3893 | 0 | { |
3894 | 0 | if (pszValue != nullptr) |
3895 | 0 | oMapPathSpecificOptions[pszPathPrefix][osKey] = pszValue; |
3896 | 0 | } |
3897 | 0 | else if (pszValue != nullptr) |
3898 | 0 | oIter->second[osKey] = pszValue; |
3899 | 0 | else |
3900 | 0 | oIter->second.erase(osKey); |
3901 | 0 | } |
3902 | | |
3903 | | /************************************************************************/ |
3904 | | /* VSIClearPathSpecificOptions() */ |
3905 | | /************************************************************************/ |
3906 | | |
3907 | | /** |
3908 | | * \brief Clear path specific options set with VSISetPathSpecificOption() |
3909 | | * @deprecated in GDAL 3.6 for the better named VSIClearPathSpecificOptions() |
3910 | | * @see VSIClearPathSpecificOptions() |
3911 | | */ |
3912 | | void VSIClearCredentials(const char *pszPathPrefix) |
3913 | 0 | { |
3914 | 0 | return VSIClearPathSpecificOptions(pszPathPrefix); |
3915 | 0 | } |
3916 | | |
3917 | | /** |
3918 | | * \brief Clear path specific options set with VSISetPathSpecificOption() |
3919 | | * |
3920 | | * Note that no particular care is taken to remove them from RAM in a secure |
3921 | | * way. |
3922 | | * |
3923 | | * @param pszPathPrefix If set to NULL, all path specific options are cleared. |
3924 | | * If set to not-NULL, only those set with |
3925 | | * VSISetPathSpecificOption(pszPathPrefix, ...) will be |
3926 | | * cleared. |
3927 | | * |
3928 | | * @since GDAL 3.6 |
3929 | | */ |
3930 | | void VSIClearPathSpecificOptions(const char *pszPathPrefix) |
3931 | 0 | { |
3932 | 0 | std::lock_guard<std::mutex> oLock(oMutexPathSpecificOptions); |
3933 | 0 | if (pszPathPrefix == nullptr) |
3934 | 0 | { |
3935 | 0 | oMapPathSpecificOptions.clear(); |
3936 | 0 | } |
3937 | 0 | else |
3938 | 0 | { |
3939 | 0 | oMapPathSpecificOptions.erase(pszPathPrefix); |
3940 | 0 | } |
3941 | 0 | } |
3942 | | |
3943 | | /************************************************************************/ |
3944 | | /* VSIGetPathSpecificOption() */ |
3945 | | /************************************************************************/ |
3946 | | |
3947 | | /** |
3948 | | * \brief Get the value of a credential (or more generally an option related to |
3949 | | * a virtual file system) for a given path. |
3950 | | * @deprecated in GDAL 3.6 for the better named VSIGetPathSpecificOption() |
3951 | | * @see VSIGetPathSpecificOption() |
3952 | | */ |
3953 | | const char *VSIGetCredential(const char *pszPath, const char *pszKey, |
3954 | | const char *pszDefault) |
3955 | 0 | { |
3956 | 0 | return VSIGetPathSpecificOption(pszPath, pszKey, pszDefault); |
3957 | 0 | } |
3958 | | |
3959 | | /** |
3960 | | * \brief Get the value a path specific option. |
3961 | | * |
3962 | | * Such option is typically, but not limited to, a credential setting for a |
3963 | | * virtual file system. |
3964 | | * |
3965 | | * If no match occurs, CPLGetConfigOption(pszKey, pszDefault) is returned. |
3966 | | * |
3967 | | * Mostly to be used by virtual file system implementations. |
3968 | | * |
3969 | | * @since GDAL 3.6 |
3970 | | * @see VSISetPathSpecificOption() |
3971 | | */ |
3972 | | const char *VSIGetPathSpecificOption(const char *pszPath, const char *pszKey, |
3973 | | const char *pszDefault) |
3974 | 0 | { |
3975 | 0 | { |
3976 | 0 | std::lock_guard<std::mutex> oLock(oMutexPathSpecificOptions); |
3977 | 0 | for (auto it = oMapPathSpecificOptions.rbegin(); |
3978 | 0 | it != oMapPathSpecificOptions.rend(); ++it) |
3979 | 0 | { |
3980 | 0 | if (STARTS_WITH(pszPath, it->first.c_str())) |
3981 | 0 | { |
3982 | 0 | auto oIter = it->second.find(CPLString(pszKey).toupper()); |
3983 | 0 | if (oIter != it->second.end()) |
3984 | 0 | return oIter->second.c_str(); |
3985 | 0 | } |
3986 | 0 | } |
3987 | 0 | } |
3988 | 0 | return CPLGetConfigOption(pszKey, pszDefault); |
3989 | 0 | } |
3990 | | |
3991 | | /************************************************************************/ |
3992 | | /* VSIDuplicateFileSystemHandler() */ |
3993 | | /************************************************************************/ |
3994 | | |
3995 | | /** |
3996 | | * \brief Duplicate an existing file system handler. |
3997 | | * |
3998 | | * A number of virtual file system for remote object stores use protocols |
3999 | | * identical or close to popular ones (typically AWS S3), but with slightly |
4000 | | * different settings (at the very least the endpoint). |
4001 | | * |
4002 | | * This functions allows to duplicate the source virtual file system handler |
4003 | | * as a new one with a different prefix (when the source virtual file system |
4004 | | * handler supports the duplication operation). |
4005 | | * |
4006 | | * VSISetPathSpecificOption() will typically be called afterwards to change |
4007 | | * configurable settings on the cloned file system handler (e.g. AWS_S3_ENDPOINT |
4008 | | * for a clone of /vsis3/). |
4009 | | * |
4010 | | * @since GDAL 3.7 |
4011 | | */ |
4012 | | bool VSIDuplicateFileSystemHandler(const char *pszSourceFSName, |
4013 | | const char *pszNewFSName) |
4014 | 0 | { |
4015 | 0 | VSIFilesystemHandler *poTargetFSHandler = |
4016 | 0 | VSIFileManager::GetHandler(pszNewFSName); |
4017 | 0 | if (poTargetFSHandler != VSIFileManager::GetHandler("/")) |
4018 | 0 | { |
4019 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
4020 | 0 | "%s is already a known virtual file system", pszNewFSName); |
4021 | 0 | return false; |
4022 | 0 | } |
4023 | | |
4024 | 0 | VSIFilesystemHandler *poSourceFSHandler = |
4025 | 0 | VSIFileManager::GetHandler(pszSourceFSName); |
4026 | 0 | if (!poSourceFSHandler) |
4027 | 0 | { |
4028 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
4029 | 0 | "%s is not a known virtual file system", pszSourceFSName); |
4030 | 0 | return false; |
4031 | 0 | } |
4032 | | |
4033 | 0 | poTargetFSHandler = poSourceFSHandler->Duplicate(pszNewFSName); |
4034 | 0 | if (!poTargetFSHandler) |
4035 | 0 | return false; |
4036 | | |
4037 | 0 | VSIFileManager::InstallHandler(pszNewFSName, poTargetFSHandler); |
4038 | 0 | return true; |
4039 | 0 | } |
4040 | | |
4041 | | /************************************************************************/ |
4042 | | /* ==================================================================== */ |
4043 | | /* VSIFileManager() */ |
4044 | | /* ==================================================================== */ |
4045 | | /************************************************************************/ |
4046 | | |
4047 | | #ifndef DOXYGEN_SKIP |
4048 | | |
4049 | | /* |
4050 | | ** Notes on Multithreading: |
4051 | | ** |
4052 | | ** The VSIFileManager maintains a list of file type handlers (mem, large |
4053 | | ** file, etc). It should be thread safe. |
4054 | | **/ |
4055 | | |
4056 | | /************************************************************************/ |
4057 | | /* VSIFileManager() */ |
4058 | | /************************************************************************/ |
4059 | | |
4060 | 1 | VSIFileManager::VSIFileManager() : poDefaultHandler(nullptr) |
4061 | 1 | { |
4062 | 1 | } |
4063 | | |
4064 | | /************************************************************************/ |
4065 | | /* ~VSIFileManager() */ |
4066 | | /************************************************************************/ |
4067 | | |
4068 | | VSIFileManager::~VSIFileManager() |
4069 | 0 | { |
4070 | 0 | std::set<VSIFilesystemHandler *> oSetAlreadyDeleted; |
4071 | 0 | for (std::map<std::string, VSIFilesystemHandler *>::const_iterator iter = |
4072 | 0 | oHandlers.begin(); |
4073 | 0 | iter != oHandlers.end(); ++iter) |
4074 | 0 | { |
4075 | 0 | if (oSetAlreadyDeleted.find(iter->second) == oSetAlreadyDeleted.end()) |
4076 | 0 | { |
4077 | 0 | oSetAlreadyDeleted.insert(iter->second); |
4078 | 0 | delete iter->second; |
4079 | 0 | } |
4080 | 0 | } |
4081 | |
|
4082 | 0 | delete poDefaultHandler; |
4083 | 0 | } |
4084 | | |
4085 | | /************************************************************************/ |
4086 | | /* Get() */ |
4087 | | /************************************************************************/ |
4088 | | |
4089 | | static VSIFileManager *poManager = nullptr; |
4090 | | static CPLMutex *hVSIFileManagerMutex = nullptr; |
4091 | | |
4092 | | VSIFileManager *VSIFileManager::Get() |
4093 | 28.6k | { |
4094 | 28.6k | CPLMutexHolder oHolder(&hVSIFileManagerMutex); |
4095 | 28.6k | if (poManager != nullptr) |
4096 | 28.6k | { |
4097 | 28.6k | return poManager; |
4098 | 28.6k | } |
4099 | | |
4100 | 1 | poManager = new VSIFileManager; |
4101 | 1 | VSIInstallLargeFileHandler(); |
4102 | 1 | VSIInstallSubFileHandler(); |
4103 | 1 | VSIInstallMemFileHandler(); |
4104 | 1 | #ifdef HAVE_LIBZ |
4105 | 1 | VSIInstallGZipFileHandler(); |
4106 | 1 | VSIInstallZipFileHandler(); |
4107 | 1 | #endif |
4108 | | #ifdef HAVE_LIBARCHIVE |
4109 | | VSIInstall7zFileHandler(); |
4110 | | VSIInstallRarFileHandler(); |
4111 | | #endif |
4112 | | #ifdef HAVE_CURL |
4113 | | VSIInstallCurlFileHandler(); |
4114 | | VSIInstallCurlStreamingFileHandler(); |
4115 | | VSIInstallS3FileHandler(); |
4116 | | VSIInstallS3StreamingFileHandler(); |
4117 | | VSIInstallGSFileHandler(); |
4118 | | VSIInstallGSStreamingFileHandler(); |
4119 | | VSIInstallAzureFileHandler(); |
4120 | | VSIInstallAzureStreamingFileHandler(); |
4121 | | VSIInstallADLSFileHandler(); |
4122 | | VSIInstallOSSFileHandler(); |
4123 | | VSIInstallOSSStreamingFileHandler(); |
4124 | | VSIInstallSwiftFileHandler(); |
4125 | | VSIInstallSwiftStreamingFileHandler(); |
4126 | | VSIInstallWebHdfsHandler(); |
4127 | | #endif |
4128 | 1 | VSIInstallStdinHandler(); |
4129 | 1 | VSIInstallHdfsHandler(); |
4130 | 1 | VSIInstallStdoutHandler(); |
4131 | 1 | VSIInstallSparseFileHandler(); |
4132 | 1 | VSIInstallTarFileHandler(); |
4133 | 1 | VSIInstallCachedFileHandler(); |
4134 | 1 | VSIInstallCryptFileHandler(); |
4135 | | |
4136 | 1 | return poManager; |
4137 | 28.6k | } |
4138 | | |
4139 | | /************************************************************************/ |
4140 | | /* GetPrefixes() */ |
4141 | | /************************************************************************/ |
4142 | | |
4143 | | char **VSIFileManager::GetPrefixes() |
4144 | 0 | { |
4145 | 0 | CPLMutexHolder oHolder(&hVSIFileManagerMutex); |
4146 | 0 | CPLStringList aosList; |
4147 | 0 | for (const auto &oIter : Get()->oHandlers) |
4148 | 0 | { |
4149 | 0 | if (oIter.first != "/vsicurl?") |
4150 | 0 | { |
4151 | 0 | aosList.AddString(oIter.first.c_str()); |
4152 | 0 | } |
4153 | 0 | } |
4154 | 0 | return aosList.StealList(); |
4155 | 0 | } |
4156 | | |
4157 | | /************************************************************************/ |
4158 | | /* GetHandler() */ |
4159 | | /************************************************************************/ |
4160 | | |
4161 | | VSIFilesystemHandler *VSIFileManager::GetHandler(const char *pszPath) |
4162 | | |
4163 | 28.6k | { |
4164 | 28.6k | VSIFileManager *poThis = Get(); |
4165 | 28.6k | const size_t nPathLen = strlen(pszPath); |
4166 | | |
4167 | 28.6k | for (std::map<std::string, VSIFilesystemHandler *>::const_iterator iter = |
4168 | 28.6k | poThis->oHandlers.begin(); |
4169 | 165k | iter != poThis->oHandlers.end(); ++iter) |
4170 | 160k | { |
4171 | 160k | const char *pszIterKey = iter->first.c_str(); |
4172 | 160k | const size_t nIterKeyLen = iter->first.size(); |
4173 | 160k | if (strncmp(pszPath, pszIterKey, nIterKeyLen) == 0) |
4174 | 17.2k | return iter->second; |
4175 | | |
4176 | | // "/vsimem\foo" should be handled as "/vsimem/foo". |
4177 | 142k | if (nIterKeyLen && nPathLen > nIterKeyLen && |
4178 | 142k | pszIterKey[nIterKeyLen - 1] == '/' && |
4179 | 142k | pszPath[nIterKeyLen - 1] == '\\' && |
4180 | 142k | strncmp(pszPath, pszIterKey, nIterKeyLen - 1) == 0) |
4181 | 0 | return iter->second; |
4182 | | |
4183 | | // /vsimem should be treated as a match for /vsimem/. |
4184 | 142k | if (nPathLen + 1 == nIterKeyLen && |
4185 | 142k | strncmp(pszPath, pszIterKey, nPathLen) == 0) |
4186 | 5.68k | return iter->second; |
4187 | 142k | } |
4188 | | |
4189 | 5.68k | return poThis->poDefaultHandler; |
4190 | 28.6k | } |
4191 | | |
4192 | | /************************************************************************/ |
4193 | | /* InstallHandler() */ |
4194 | | /************************************************************************/ |
4195 | | |
4196 | | void VSIFileManager::InstallHandler(const std::string &osPrefix, |
4197 | | VSIFilesystemHandler *poHandler) |
4198 | | |
4199 | 13 | { |
4200 | 13 | if (osPrefix == "") |
4201 | 1 | Get()->poDefaultHandler = poHandler; |
4202 | 12 | else |
4203 | 12 | Get()->oHandlers[osPrefix] = poHandler; |
4204 | 13 | } |
4205 | | |
4206 | | /************************************************************************/ |
4207 | | /* RemoveHandler() */ |
4208 | | /************************************************************************/ |
4209 | | |
4210 | | void VSIFileManager::RemoveHandler(const std::string &osPrefix) |
4211 | 0 | { |
4212 | 0 | if (osPrefix == "") |
4213 | 0 | Get()->poDefaultHandler = nullptr; |
4214 | 0 | else |
4215 | 0 | Get()->oHandlers.erase(osPrefix); |
4216 | 0 | } |
4217 | | |
4218 | | /************************************************************************/ |
4219 | | /* VSICleanupFileManager() */ |
4220 | | /************************************************************************/ |
4221 | | |
4222 | | void VSICleanupFileManager() |
4223 | | |
4224 | 0 | { |
4225 | 0 | if (poManager) |
4226 | 0 | { |
4227 | 0 | delete poManager; |
4228 | 0 | poManager = nullptr; |
4229 | 0 | } |
4230 | |
|
4231 | 0 | if (hVSIFileManagerMutex != nullptr) |
4232 | 0 | { |
4233 | 0 | CPLDestroyMutex(hVSIFileManagerMutex); |
4234 | 0 | hVSIFileManagerMutex = nullptr; |
4235 | 0 | } |
4236 | |
|
4237 | | #ifdef HAVE_CURL |
4238 | | VSICURLDestroyCacheFileProp(); |
4239 | | #endif |
4240 | 0 | } |
4241 | | |
4242 | | /************************************************************************/ |
4243 | | /* Truncate() */ |
4244 | | /************************************************************************/ |
4245 | | |
4246 | | int VSIVirtualHandle::Truncate(vsi_l_offset nNewSize) |
4247 | 0 | { |
4248 | 0 | const vsi_l_offset nOriginalPos = Tell(); |
4249 | 0 | if (Seek(0, SEEK_END) == 0 && nNewSize >= Tell()) |
4250 | 0 | { |
4251 | | // Fill with zeroes |
4252 | 0 | std::vector<GByte> aoBytes(4096, 0); |
4253 | 0 | vsi_l_offset nCurOffset = nOriginalPos; |
4254 | 0 | while (nCurOffset < nNewSize) |
4255 | 0 | { |
4256 | 0 | constexpr vsi_l_offset nMaxOffset = 4096; |
4257 | 0 | const int nSize = |
4258 | 0 | static_cast<int>(std::min(nMaxOffset, nNewSize - nCurOffset)); |
4259 | 0 | if (Write(&aoBytes[0], nSize, 1) != 1) |
4260 | 0 | { |
4261 | 0 | Seek(nOriginalPos, SEEK_SET); |
4262 | 0 | return -1; |
4263 | 0 | } |
4264 | 0 | nCurOffset += nSize; |
4265 | 0 | } |
4266 | 0 | return Seek(nOriginalPos, SEEK_SET) == 0 ? 0 : -1; |
4267 | 0 | } |
4268 | | |
4269 | 0 | CPLDebug("VSI", "Truncation is not supported in generic implementation " |
4270 | 0 | "of Truncate()"); |
4271 | 0 | Seek(nOriginalPos, SEEK_SET); |
4272 | 0 | return -1; |
4273 | 0 | } |
4274 | | |
4275 | | /************************************************************************/ |
4276 | | /* ReadMultiRange() */ |
4277 | | /************************************************************************/ |
4278 | | |
4279 | | int VSIVirtualHandle::ReadMultiRange(int nRanges, void **ppData, |
4280 | | const vsi_l_offset *panOffsets, |
4281 | | const size_t *panSizes) |
4282 | 0 | { |
4283 | 0 | int nRet = 0; |
4284 | 0 | const vsi_l_offset nCurOffset = Tell(); |
4285 | 0 | for (int i = 0; i < nRanges; i++) |
4286 | 0 | { |
4287 | 0 | if (Seek(panOffsets[i], SEEK_SET) < 0) |
4288 | 0 | { |
4289 | 0 | nRet = -1; |
4290 | 0 | break; |
4291 | 0 | } |
4292 | | |
4293 | 0 | const size_t nRead = Read(ppData[i], 1, panSizes[i]); |
4294 | 0 | if (panSizes[i] != nRead) |
4295 | 0 | { |
4296 | 0 | nRet = -1; |
4297 | 0 | break; |
4298 | 0 | } |
4299 | 0 | } |
4300 | |
|
4301 | 0 | Seek(nCurOffset, SEEK_SET); |
4302 | |
|
4303 | 0 | return nRet; |
4304 | 0 | } |
4305 | | |
4306 | | #endif // #ifndef DOXYGEN_SKIP |
4307 | | |
4308 | | /************************************************************************/ |
4309 | | /* HasPRead() */ |
4310 | | /************************************************************************/ |
4311 | | |
4312 | | /** Returns whether this file handle supports the PRead() method. |
4313 | | * |
4314 | | * @since GDAL 3.6 |
4315 | | */ |
4316 | | bool VSIVirtualHandle::HasPRead() const |
4317 | 0 | { |
4318 | 0 | return false; |
4319 | 0 | } |
4320 | | |
4321 | | /************************************************************************/ |
4322 | | /* PRead() */ |
4323 | | /************************************************************************/ |
4324 | | |
4325 | | /** Do a parallel-compatible read operation. |
4326 | | * |
4327 | | * This methods reads into pBuffer up to nSize bytes starting at offset nOffset |
4328 | | * in the file. The current file offset is not affected by this method. |
4329 | | * |
4330 | | * The implementation is thread-safe: several threads can issue PRead() |
4331 | | * concurrently on the same VSIVirtualHandle object. |
4332 | | * |
4333 | | * This method has the same semantics as pread() Linux operation. It is only |
4334 | | * available if HasPRead() returns true. |
4335 | | * |
4336 | | * @param pBuffer output buffer (must be at least nSize bytes large). |
4337 | | * @param nSize number of bytes to read in the file. |
4338 | | * @param nOffset file offset from which to read. |
4339 | | * @return number of bytes read. |
4340 | | * @since GDAL 3.6 |
4341 | | */ |
4342 | | size_t VSIVirtualHandle::PRead(CPL_UNUSED void *pBuffer, |
4343 | | CPL_UNUSED size_t nSize, |
4344 | | CPL_UNUSED vsi_l_offset nOffset) const |
4345 | 0 | { |
4346 | 0 | return 0; |
4347 | 0 | } |