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