Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: CPL - Common Portability Library
4 : * Purpose: Declarations for /vsicurl/ and related file systems
5 : * Author: Even Rouault, even.rouault at spatialys.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2010-2018, Even Rouault <even.rouault at spatialys.com>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #ifndef CPL_VSIL_CURL_CLASS_H_INCLUDED
14 : #define CPL_VSIL_CURL_CLASS_H_INCLUDED
15 :
16 : #ifdef HAVE_CURL
17 :
18 : #include "cpl_aws.h"
19 : #include "cpl_azure.h"
20 : #include "cpl_port.h"
21 : #include "cpl_json.h"
22 : #include "cpl_http.h"
23 : #include "cpl_string.h"
24 : #include "cpl_vsil_curl_priv.h"
25 : #include "cpl_mem_cache.h"
26 : #include "cpl_multiproc.h"
27 :
28 : #include "cpl_curl_priv.h"
29 :
30 : #include <algorithm>
31 : #include <atomic>
32 : #include <condition_variable>
33 : #include <set>
34 : #include <map>
35 : #include <memory>
36 : #include <mutex>
37 : #include <thread>
38 : #include <utility>
39 :
40 : // To avoid aliasing to CopyFile to CopyFileA on Windows
41 : #ifdef CopyFile
42 : #undef CopyFile
43 : #endif
44 :
45 : //! @cond Doxygen_Suppress
46 :
47 : // Leave it for backward compatibility, but deprecate.
48 : #define HAVE_CURLINFO_REDIRECT_URL
49 :
50 : void VSICurlStreamingClearCache(void); // from cpl_vsil_curl_streaming.cpp
51 :
52 : struct curl_slist *VSICurlSetContentTypeFromExt(struct curl_slist *polist,
53 : const char *pszPath);
54 :
55 : struct curl_slist *VSICurlSetCreationHeadersFromOptions(
56 : struct curl_slist *headers, CSLConstList papszOptions, const char *pszPath);
57 :
58 : namespace cpl
59 : {
60 :
61 : typedef enum
62 : {
63 : EXIST_UNKNOWN = -1,
64 : EXIST_NO,
65 : EXIST_YES,
66 : } ExistStatus;
67 :
68 : class FileProp
69 : {
70 : public:
71 : unsigned int nGenerationAuthParameters = 0;
72 : ExistStatus eExists = EXIST_UNKNOWN;
73 : int nHTTPCode = 0;
74 : vsi_l_offset fileSize = 0;
75 : time_t mTime = 0;
76 : time_t nExpireTimestampLocal = 0;
77 : std::string osRedirectURL{};
78 : bool bHasComputedFileSize = false;
79 : bool bIsDirectory = false;
80 : bool bIsAzureFolder = false;
81 : int nMode = 0; // st_mode member of struct stat
82 : bool bS3LikeRedirect = false;
83 : std::string ETag{};
84 : };
85 :
86 : struct CachedDirList
87 : {
88 : bool bGotFileList = false;
89 : unsigned int nGenerationAuthParameters = 0;
90 : CPLStringList oFileList{}; /* only file name without path */
91 : };
92 :
93 : struct WriteFuncStruct
94 : {
95 : char *pBuffer = nullptr;
96 : size_t nSize = 0;
97 : bool bIsHTTP = false;
98 : bool bMultiRange = false;
99 : vsi_l_offset nStartOffset = 0;
100 : vsi_l_offset nEndOffset = 0;
101 : int nHTTPCode = 0; // potentially after redirect
102 : int nFirstHTTPCode = 0; // the one of the redirect
103 : vsi_l_offset nContentLength = 0;
104 : bool bFoundContentRange = false;
105 : bool bError = false;
106 : bool bInterruptDownload = false;
107 : bool bDetectRangeDownloadingError = false;
108 : GIntBig nTimestampDate = 0; // Corresponds to Date: header field
109 :
110 : VSILFILE *fp = nullptr;
111 : VSICurlReadCbkFunc pfnReadCbk = nullptr;
112 : void *pReadCbkUserData = nullptr;
113 : bool bInterrupted = false;
114 : };
115 :
116 : struct PutData
117 : {
118 : const GByte *pabyData = nullptr;
119 : size_t nOff = 0;
120 : size_t nTotalSize = 0;
121 :
122 35 : static size_t ReadCallBackBuffer(char *buffer, size_t size, size_t nitems,
123 : void *instream)
124 : {
125 35 : PutData *poThis = static_cast<PutData *>(instream);
126 35 : const size_t nSizeMax = size * nitems;
127 : const size_t nSizeToWrite =
128 35 : std::min(nSizeMax, poThis->nTotalSize - poThis->nOff);
129 35 : memcpy(buffer, poThis->pabyData + poThis->nOff, nSizeToWrite);
130 35 : poThis->nOff += nSizeToWrite;
131 35 : return nSizeToWrite;
132 : }
133 : };
134 :
135 : /************************************************************************/
136 : /* VSICurlFilesystemHandler */
137 : /************************************************************************/
138 :
139 : class VSICurlHandle;
140 :
141 : class VSICurlFilesystemHandlerBase : public VSIFilesystemHandler
142 : {
143 : CPL_DISALLOW_COPY_ASSIGN(VSICurlFilesystemHandlerBase)
144 :
145 : friend class RunThreadUser;
146 : enum class HandleState
147 : {
148 : Ready,
149 : Running,
150 : Interrupted,
151 : Done
152 : };
153 :
154 : /// Handle Information.
155 717 : struct Handle
156 : {
157 1499 : explicit Handle(CURL *curl) : m_curl(curl), m_state(HandleState::Ready)
158 : {
159 1499 : }
160 :
161 1531 : Handle(const Handle &) = default;
162 : Handle &operator=(const Handle &) = default;
163 :
164 : CURL *m_curl{nullptr};
165 : HandleState m_state{HandleState::Ready};
166 : using DebugInfo = std::pair<std::string, std::string>;
167 : std::vector<DebugInfo> m_debug{};
168 : };
169 :
170 : struct FilenameOffsetPair
171 : {
172 : std::string filename_;
173 : vsi_l_offset offset_;
174 :
175 183707 : FilenameOffsetPair(const std::string &filename, vsi_l_offset offset)
176 183707 : : filename_(filename), offset_(offset)
177 : {
178 183707 : }
179 :
180 157520 : bool operator==(const FilenameOffsetPair &other) const
181 : {
182 157520 : return filename_ == other.filename_ && offset_ == other.offset_;
183 : }
184 : };
185 :
186 : struct FilenameOffsetPairHasher
187 : {
188 201713 : std::size_t operator()(const FilenameOffsetPair &k) const
189 : {
190 201713 : return std::hash<std::string>()(k.filename_) ^
191 201713 : std::hash<vsi_l_offset>()(k.offset_);
192 : }
193 : };
194 :
195 : using RegionCacheType = lru11::Cache<
196 : FilenameOffsetPair, std::shared_ptr<std::string>, lru11::NullLock,
197 : std::unordered_map<
198 : FilenameOffsetPair,
199 : typename std::list<lru11::KeyValuePair<
200 : FilenameOffsetPair, std::shared_ptr<std::string>>>::iterator,
201 : FilenameOffsetPairHasher>>;
202 :
203 : std::unique_ptr<RegionCacheType>
204 : m_poRegionCacheDoNotUseDirectly{}; // do not access directly. Use
205 : // GetRegionCache();
206 : RegionCacheType *GetRegionCache();
207 :
208 : int nCachedFilesInDirList = 0;
209 : lru11::Cache<std::string, CachedDirList> oCacheDirList;
210 :
211 : char **ParseHTMLFileList(const char *pszFilename, int nMaxFiles,
212 : char *pszData, bool *pbGotFileList);
213 :
214 : // Data structure and map to store regions that are in progress, to
215 : // avoid simultaneous downloads of the same region in different threads
216 : // Cf https://github.com/OSGeo/gdal/issues/8041
217 : struct RegionInDownload
218 : {
219 : std::mutex oMutex{};
220 : std::condition_variable oCond{};
221 : bool bDownloadInProgress = false;
222 : int nWaiters = 0;
223 : std::string osData{};
224 : };
225 :
226 : std::mutex m_useMutex{}; // Protects the use count
227 : int m_useCount = 0; // Count of users of the run thread.
228 : std::atomic<bool> m_stop{false};
229 : std::condition_variable m_runCv{};
230 : std::unique_ptr<std::thread> m_runThread{};
231 : std::mutex m_runMutex{}; // Protects data associated with the run thread.
232 : std::vector<Handle> m_handles{};
233 : CURLM *m_multi = nullptr;
234 :
235 : void Run();
236 : void StartRunThread();
237 : void StopRunThread();
238 : int HandleReady();
239 : bool HandleInterrupted();
240 : bool HandleCompleted();
241 : bool HandleFailure();
242 : void HandleDebug(CURL *easyHandle);
243 : bool RemoveDoneHandle(CURL *easyHandle);
244 : void IncUseCount();
245 : void DecUseCount();
246 : void CurlDebug(CURL *handle, curl_infotype type, std::string_view msg);
247 :
248 : std::mutex m_oMutex{}; // Map region mutex.
249 : std::map<std::string, std::unique_ptr<RegionInDownload>>
250 : m_oMapRegionInDownload{};
251 :
252 : protected:
253 : CPLMutex *hMutex = nullptr;
254 :
255 : virtual VSICurlHandle *CreateFileHandle(const char *pszFilename);
256 : virtual char **GetFileList(const char *pszFilename, int nMaxFiles,
257 : bool *pbGotFileList);
258 :
259 : void RegisterEmptyDir(const std::string &osDirname);
260 :
261 : bool
262 : AnalyseS3FileList(const std::string &osBaseURL, const char *pszXML,
263 : CPLStringList &osFileList, int nMaxFiles,
264 : const std::set<std::string> &oSetIgnoredStorageClasses,
265 : bool &bIsTruncated);
266 :
267 : void AnalyseSwiftFileList(const std::string &osBaseURL,
268 : const std::string &osPrefix, const char *pszJson,
269 : CPLStringList &osFileList, int nMaxFilesThisQuery,
270 : int nMaxFiles, bool &bIsTruncated,
271 : std::string &osNextMarker);
272 :
273 : VSICurlFilesystemHandlerBase();
274 :
275 : public:
276 : ~VSICurlFilesystemHandlerBase() override;
277 :
278 : static bool IsAllowedFilename(const char *pszFilename);
279 :
280 : VSIVirtualHandleUniquePtr Open(const char *pszFilename,
281 : const char *pszAccess, bool bSetError,
282 : CSLConstList /* papszOptions */) override;
283 :
284 : int Stat(const char *pszFilename, VSIStatBufL *pStatBuf,
285 : int nFlags) override;
286 : char **ReadDirEx(const char *pszDirname, int nMaxFiles) override;
287 : char **SiblingFiles(const char *pszFilename) override;
288 :
289 19 : int HasOptimizedReadMultiRange(const char * /* pszPath */) override
290 : {
291 19 : return true;
292 : }
293 :
294 : const char *GetActualURL(const char *pszFilename) override;
295 :
296 : const char *GetOptions() override;
297 :
298 : char **GetFileMetadata(const char *pszFilename, const char *pszDomain,
299 : CSLConstList papszOptions) override;
300 :
301 : char **ReadDirInternal(const char *pszDirname, int nMaxFiles,
302 : bool *pbGotFileList);
303 : void InvalidateDirContent(const std::string &osDirname);
304 :
305 : virtual const char *GetDebugKey() const = 0;
306 :
307 : virtual std::string GetFSPrefix() const = 0;
308 : virtual bool AllowCachedDataFor(const char *pszFilename);
309 :
310 8 : bool IsLocal(const char * /* pszPath */) const override
311 : {
312 8 : return false;
313 : }
314 :
315 : virtual bool
316 2 : SupportsSequentialWrite(const char * /* pszPath */,
317 : bool /* bAllowLocalTempFile */) override
318 : {
319 2 : return false;
320 : }
321 :
322 1 : virtual bool SupportsRandomWrite(const char * /* pszPath */,
323 : bool /* bAllowLocalTempFile */) override
324 : {
325 1 : return false;
326 : }
327 :
328 : std::shared_ptr<std::string> GetRegion(const char *pszURL,
329 : vsi_l_offset nFileOffsetStart);
330 :
331 : void AddRegion(const char *pszURL, vsi_l_offset nFileOffsetStart,
332 : size_t nSize, const char *pData);
333 :
334 : std::pair<bool, std::string>
335 : NotifyStartDownloadRegion(const std::string &osURL,
336 : vsi_l_offset startOffset, int nBlocks);
337 : void NotifyStopDownloadRegion(const std::string &osURL,
338 : vsi_l_offset startOffset, int nBlocks,
339 : const std::string &osData);
340 :
341 : static bool GetCachedFileProp(const char *pszURL, FileProp &oFileProp);
342 : static void SetCachedFileProp(const char *pszURL, FileProp &oFileProp);
343 : void InvalidateCachedData(const char *pszURL);
344 :
345 : virtual void ClearCache();
346 : virtual void PartialClearCache(const char *pszFilename);
347 :
348 : bool GetCachedDirList(const char *pszURL, CachedDirList &oCachedDirList);
349 : void SetCachedDirList(const char *pszURL, CachedDirList &oCachedDirList);
350 : bool ExistsInCacheDirList(const std::string &osDirname, bool *pbIsDir);
351 :
352 : virtual std::string GetURLFromFilename(const std::string &osFilename) const;
353 :
354 : std::string
355 : GetStreamingFilename(const std::string &osFilename) const override = 0;
356 : struct curl_slist *SetOptions(CURL *hCurlHandle, const char *pszURL,
357 : const char *const *papszOptions);
358 :
359 : void Interrupt(CURL *easyHandle);
360 : void Perform(CURL *easyHandle);
361 : void Perform(std::vector<CURL *> easyHandles);
362 :
363 : static std::set<std::string> GetS3IgnoredStorageClasses();
364 :
365 : static int CurlDebugStatic(CURL *handle, curl_infotype type, char *data,
366 : size_t size, void *userp);
367 : static const char *GetOptionsStatic();
368 : };
369 :
370 : class VSICurlFilesystemHandler final : public VSICurlFilesystemHandlerBase
371 : {
372 : CPL_DISALLOW_COPY_ASSIGN(VSICurlFilesystemHandler)
373 :
374 : public:
375 2101 : VSICurlFilesystemHandler() = default;
376 :
377 1219 : const char *GetDebugKey() const override
378 : {
379 1219 : return "VSICURL";
380 : }
381 :
382 175386 : std::string GetFSPrefix() const override
383 : {
384 175386 : return "/vsicurl/";
385 : }
386 :
387 : std::string
388 : GetStreamingFilename(const std::string &osFilename) const override;
389 :
390 : std::string
391 : GetHintForPotentiallyRecognizedPath(const std::string &osPath) override;
392 : };
393 :
394 : /************************************************************************/
395 : /* VSICurlHandle */
396 : /************************************************************************/
397 :
398 : class VSICurlHandle /* non final*/ : public VSIVirtualHandle
399 : {
400 : CPL_DISALLOW_COPY_ASSIGN(VSICurlHandle)
401 :
402 : protected:
403 : VSICurlFilesystemHandlerBase *poFS = nullptr;
404 :
405 : bool m_bCached = true;
406 :
407 : mutable FileProp oFileProp{};
408 :
409 : mutable std::mutex m_oMutex{};
410 : std::string m_osFilename{}; // e.g "/vsicurl/http://example.com/foo"
411 : char *m_pszURL = nullptr; // e.g "http://example.com/foo"
412 : mutable std::string m_osQueryString{}; // e.g. an Azure SAS
413 :
414 : CPLStringList m_aosHTTPOptions{};
415 : CPLHTTPRetryParameters
416 : m_oRetryParameters; // must be initialized in constructor
417 :
418 : vsi_l_offset lastDownloadedOffset = VSI_L_OFFSET_MAX;
419 : int nBlocksToDownload = 1;
420 :
421 : bool bStopOnInterruptUntilUninstall = false;
422 : bool bInterrupted = false;
423 : VSICurlReadCbkFunc pfnReadCbk = nullptr;
424 : void *pReadCbkUserData = nullptr;
425 :
426 : CPLStringList m_aosHeaders{};
427 :
428 : void DownloadRegionPostProcess(const vsi_l_offset startOffset,
429 : const int nBlocks, const char *pBuffer,
430 : size_t nSize);
431 :
432 : private:
433 : vsi_l_offset curOffset = 0;
434 :
435 : bool bEOF = false;
436 : bool bError = false;
437 :
438 : virtual std::string DownloadRegion(vsi_l_offset startOffset, int nBlocks);
439 :
440 : bool m_bUseHead = false;
441 : bool m_bUseRedirectURLIfNoQueryStringParams = false;
442 : bool m_bInterrupt = false;
443 : // Makes sure the FilesystemHandler run thread is started on construction and
444 : // torn down at last use.
445 : RunThreadUser m_runThreadUser;
446 :
447 : // Specific to Planetary Computer signing:
448 : // https://planetarycomputer.microsoft.com/docs/concepts/sas/
449 : mutable bool m_bPlanetaryComputerURLSigning = false;
450 : mutable std::string m_osPlanetaryComputerCollection{};
451 : void ManagePlanetaryComputerSigning() const;
452 :
453 : void UpdateQueryString() const;
454 :
455 : int ReadMultiRangeSingleGet(int nRanges, void **ppData,
456 : const vsi_l_offset *panOffsets,
457 : const size_t *panSizes);
458 : std::string GetRedirectURLIfValid(bool &bHasExpired,
459 : CPLStringList &aosHTTPOptions) const;
460 :
461 : void UpdateRedirectInfo(CURL *hCurlHandle,
462 : const WriteFuncStruct &sWriteFuncHeaderData);
463 :
464 : // Used by AdviseRead()
465 : struct AdviseReadRange
466 : {
467 : bool bDone = false;
468 : bool bToRetry = true;
469 : double dfSleepDelay = 0.0;
470 : std::mutex oMutex{};
471 : std::condition_variable oCV{};
472 : vsi_l_offset nStartOffset = 0;
473 : size_t nSize = 0;
474 : std::vector<GByte> abyData{};
475 : CPLHTTPRetryContext retryContext;
476 :
477 6 : explicit AdviseReadRange(const CPLHTTPRetryParameters &oRetryParameters)
478 6 : : retryContext(oRetryParameters)
479 : {
480 6 : }
481 :
482 : AdviseReadRange(const AdviseReadRange &) = delete;
483 : AdviseReadRange &operator=(const AdviseReadRange &) = delete;
484 : AdviseReadRange(AdviseReadRange &&) = delete;
485 : AdviseReadRange &operator=(AdviseReadRange &&) = delete;
486 : };
487 :
488 : std::vector<std::unique_ptr<AdviseReadRange>> m_aoAdviseReadRanges{};
489 : std::thread m_oThreadAdviseRead{};
490 : CURLM *m_hCurlMultiHandleForAdviseRead = nullptr;
491 :
492 : protected:
493 689 : virtual struct curl_slist *GetCurlHeaders(const std::string & /*osVerb*/,
494 : struct curl_slist *psHeaders)
495 : {
496 689 : return psHeaders;
497 : }
498 :
499 757 : virtual bool AllowAutomaticRedirection()
500 : {
501 757 : return true;
502 : }
503 :
504 156 : virtual bool CanRestartOnError(const char *, const char *, bool)
505 : {
506 156 : return false;
507 : }
508 :
509 527 : virtual bool UseLimitRangeGetInsteadOfHead()
510 : {
511 527 : return false;
512 : }
513 :
514 325 : virtual bool IsDirectoryFromExists(const char * /*pszVerb*/,
515 : int /*response_code*/)
516 : {
517 325 : return false;
518 : }
519 :
520 153 : virtual void ProcessGetFileSizeResult(const char * /* pszContent */)
521 : {
522 153 : }
523 :
524 : void SetURL(const char *pszURL);
525 :
526 0 : virtual bool Authenticate(const char * /* pszFilename */)
527 : {
528 0 : return false;
529 : }
530 :
531 : public:
532 : VSICurlHandle(VSICurlFilesystemHandlerBase *poFS, const char *pszFilename,
533 : const char *pszURLIn = nullptr);
534 : ~VSICurlHandle() override;
535 :
536 : int Seek(vsi_l_offset nOffset, int nWhence) override;
537 : vsi_l_offset Tell() override;
538 : size_t Read(void *pBuffer, size_t nBytes) override;
539 : int ReadMultiRange(int nRanges, void **ppData,
540 : const vsi_l_offset *panOffsets,
541 : const size_t *panSizes) override;
542 : size_t Write(const void *pBuffer, size_t nBytes) override;
543 : void ClearErr() override;
544 : int Eof() override;
545 : int Error() override;
546 : int Flush() override;
547 : int Close() override;
548 :
549 0 : void Interrupt() override
550 : {
551 0 : poFS->Interrupt(this);
552 0 : m_bInterrupt = true;
553 0 : }
554 :
555 18 : bool HasPRead() const override
556 : {
557 18 : return true;
558 : }
559 :
560 : size_t PRead(void *pBuffer, size_t nSize,
561 : vsi_l_offset nOffset) const override;
562 :
563 : void AdviseRead(int nRanges, const vsi_l_offset *panOffsets,
564 : const size_t *panSizes) override;
565 :
566 : size_t GetAdviseReadTotalBytesLimit() const override;
567 :
568 1126 : bool IsKnownFileSize() const
569 : {
570 1126 : return oFileProp.bHasComputedFileSize;
571 : }
572 :
573 : vsi_l_offset GetFileSizeOrHeaders(bool bSetError, bool bGetHeaders);
574 :
575 2025 : virtual vsi_l_offset GetFileSize(bool bSetError)
576 : {
577 2025 : return GetFileSizeOrHeaders(bSetError, false);
578 : }
579 :
580 : bool Exists(bool bSetError);
581 :
582 1280 : bool IsDirectory() const
583 : {
584 1280 : return oFileProp.bIsDirectory;
585 : }
586 :
587 1126 : int GetMode() const
588 : {
589 1126 : return oFileProp.nMode;
590 : }
591 :
592 1126 : time_t GetMTime() const
593 : {
594 1126 : return oFileProp.mTime;
595 : }
596 :
597 4 : const CPLStringList &GetHeaders()
598 : {
599 4 : return m_aosHeaders;
600 : }
601 :
602 : int InstallReadCbk(VSICurlReadCbkFunc pfnReadCbk, void *pfnUserData,
603 : int bStopOnInterruptUntilUninstall);
604 : int UninstallReadCbk();
605 :
606 5 : const char *GetURL() const
607 : {
608 5 : return m_pszURL;
609 : }
610 :
611 : //! Whether caching of file content and metadata should persist after file closing
612 878 : void SetCache(bool bCache)
613 : {
614 878 : m_bCached = bCache;
615 878 : }
616 : };
617 :
618 : /************************************************************************/
619 : /* VSICurlFilesystemHandlerBaseWritable */
620 : /************************************************************************/
621 :
622 : class VSICurlFilesystemHandlerBaseWritable /* non final */
623 : : public VSICurlFilesystemHandlerBase
624 : {
625 : CPL_DISALLOW_COPY_ASSIGN(VSICurlFilesystemHandlerBaseWritable)
626 :
627 : protected:
628 14707 : VSICurlFilesystemHandlerBaseWritable() = default;
629 :
630 : virtual VSIVirtualHandleUniquePtr
631 : CreateWriteHandle(const char *pszFilename, CSLConstList papszOptions) = 0;
632 :
633 : public:
634 : VSIVirtualHandleUniquePtr Open(const char *pszFilename,
635 : const char *pszAccess, bool bSetError,
636 : CSLConstList /* papszOptions */) override;
637 :
638 1 : bool SupportsSequentialWrite(const char * /* pszPath */,
639 : bool /* bAllowLocalTempFile */) override
640 : {
641 1 : return true;
642 : }
643 :
644 : bool SupportsRandomWrite(const char * /* pszPath */,
645 : bool /* bAllowLocalTempFile */) override;
646 : };
647 :
648 : /************************************************************************/
649 : /* IVSIS3LikeFSHandler */
650 : /************************************************************************/
651 :
652 : class IVSIS3LikeFSHandler /* non final */
653 : : public VSICurlFilesystemHandlerBaseWritable
654 : {
655 : CPL_DISALLOW_COPY_ASSIGN(IVSIS3LikeFSHandler)
656 :
657 : virtual int MkdirInternal(const char *pszDirname, long nMode,
658 : bool bDoStatCheck);
659 :
660 : protected:
661 : char **GetFileList(const char *pszFilename, int nMaxFiles,
662 : bool *pbGotFileList) override;
663 :
664 : virtual IVSIS3LikeHandleHelper *CreateHandleHelper(const char *pszURI,
665 : bool bAllowNoObject) = 0;
666 :
667 : virtual int CopyObject(const char *oldpath, const char *newpath,
668 : CSLConstList papszMetadata);
669 :
670 : int RmdirRecursiveInternal(const char *pszDirname, int nBatchSize);
671 :
672 : virtual bool
673 0 : IsAllowedHeaderForObjectCreation(const char * /* pszHeaderName */)
674 : {
675 0 : return false;
676 : }
677 :
678 12606 : IVSIS3LikeFSHandler() = default;
679 :
680 : public:
681 : int Unlink(const char *pszFilename) override;
682 : int Mkdir(const char *pszDirname, long nMode) override;
683 : int Rmdir(const char *pszDirname) override;
684 : int Stat(const char *pszFilename, VSIStatBufL *pStatBuf,
685 : int nFlags) override;
686 : int Rename(const char *oldpath, const char *newpath, GDALProgressFunc,
687 : void *) override;
688 :
689 : virtual int CopyFile(const char *pszSource, const char *pszTarget,
690 : VSILFILE *fpSource, vsi_l_offset nSourceSize,
691 : const char *const *papszOptions,
692 : GDALProgressFunc pProgressFunc,
693 : void *pProgressData) override;
694 :
695 : virtual int DeleteObject(const char *pszFilename);
696 :
697 : virtual int *DeleteObjectBatch(CSLConstList papszFilesOrDirs);
698 :
699 : bool Sync(const char *pszSource, const char *pszTarget,
700 : const char *const *papszOptions, GDALProgressFunc pProgressFunc,
701 : void *pProgressData, char ***ppapszOutputs) override;
702 :
703 : VSIDIR *OpenDir(const char *pszPath, int nRecurseDepth,
704 : const char *const *papszOptions) override;
705 : };
706 :
707 : /************************************************************************/
708 : /* IVSIS3LikeFSHandlerWithMultipartUpload */
709 : /************************************************************************/
710 :
711 : class IVSIS3LikeFSHandlerWithMultipartUpload /* non final */
712 : : public IVSIS3LikeFSHandler
713 : {
714 : CPL_DISALLOW_COPY_ASSIGN(IVSIS3LikeFSHandlerWithMultipartUpload)
715 :
716 : protected:
717 10505 : IVSIS3LikeFSHandlerWithMultipartUpload() = default;
718 :
719 : public:
720 5 : virtual bool SupportsNonSequentialMultipartUpload() const
721 : {
722 5 : return true;
723 : }
724 :
725 36 : virtual bool SupportsParallelMultipartUpload() const
726 : {
727 36 : return true;
728 : }
729 :
730 : virtual bool SupportsMultipartAbort() const = 0;
731 :
732 : size_t GetUploadChunkSizeInBytes(const char *pszFilename,
733 : const char *pszSpecifiedValInBytes);
734 :
735 : virtual int CopyFileRestartable(const char *pszSource,
736 : const char *pszTarget,
737 : const char *pszInputPayload,
738 : char **ppszOutputPayload,
739 : CSLConstList papszOptions,
740 : GDALProgressFunc pProgressFunc,
741 : void *pProgressData) override;
742 :
743 : //! Maximum number of parts for multipart upload
744 : // Limit currently used by S3 and GS.
745 : // Cf https://docs.aws.amazon.com/AmazonS3/latest/userguide/qfacts.html
746 : // and https://cloud.google.com/storage/quotas#requests
747 11 : virtual int GetMaximumPartCount()
748 : {
749 11 : return 10000;
750 : }
751 :
752 : //! Minimum size of a part for multipart upload (except last one), in MiB.
753 : // Limit currently used by S3 and GS.
754 : // Cf https://docs.aws.amazon.com/AmazonS3/latest/userguide/qfacts.html
755 : // and https://cloud.google.com/storage/quotas#requests
756 5 : virtual int GetMinimumPartSizeInMiB()
757 : {
758 5 : return 5;
759 : }
760 :
761 : //! Maximum size of a part for multipart upload, in MiB.
762 : // Limit currently used by S3 and GS.
763 : // Cf https://docs.aws.amazon.com/AmazonS3/latest/userguide/qfacts.html
764 : // and https://cloud.google.com/storage/quotas#requests
765 50 : virtual int GetMaximumPartSizeInMiB()
766 : {
767 : #if SIZEOF_VOIDP == 8
768 50 : return 5 * 1024;
769 : #else
770 : // Cannot be larger than 4, otherwise integer overflow would occur
771 : // 1 GiB is the maximum reasonable value on a 32-bit machine
772 : return 1 * 1024;
773 : #endif
774 : }
775 :
776 : //! Default size of a part for multipart upload, in MiB.
777 47 : virtual int GetDefaultPartSizeInMiB()
778 : {
779 47 : return 50;
780 : }
781 :
782 : virtual std::string
783 : InitiateMultipartUpload(const std::string &osFilename,
784 : IVSIS3LikeHandleHelper *poS3HandleHelper,
785 : const CPLHTTPRetryParameters &oRetryParameters,
786 : CSLConstList papszOptions);
787 :
788 : virtual std::string
789 : UploadPart(const std::string &osFilename, int nPartNumber,
790 : const std::string &osUploadID, vsi_l_offset nPosition,
791 : const void *pabyBuffer, size_t nBufferSize,
792 : IVSIS3LikeHandleHelper *poS3HandleHelper,
793 : const CPLHTTPRetryParameters &oRetryParameters,
794 : CSLConstList papszOptions);
795 :
796 : virtual bool CompleteMultipart(
797 : const std::string &osFilename, const std::string &osUploadID,
798 : const std::vector<std::string> &aosEtags, vsi_l_offset nTotalSize,
799 : IVSIS3LikeHandleHelper *poS3HandleHelper,
800 : const CPLHTTPRetryParameters &oRetryParameters);
801 :
802 : virtual bool AbortMultipart(const std::string &osFilename,
803 : const std::string &osUploadID,
804 : IVSIS3LikeHandleHelper *poS3HandleHelper,
805 : const CPLHTTPRetryParameters &oRetryParameters);
806 :
807 : bool AbortPendingUploads(const char *pszFilename) override;
808 :
809 : bool MultipartUploadGetCapabilities(int *pbNonSequentialUploadSupported,
810 : int *pbParallelUploadSupported,
811 : int *pbAbortSupported,
812 : size_t *pnMinPartSize,
813 : size_t *pnMaxPartSize,
814 : int *pnMaxPartCount) override;
815 :
816 : char *MultipartUploadStart(const char *pszFilename,
817 : CSLConstList papszOptions) override;
818 :
819 : char *MultipartUploadAddPart(const char *pszFilename,
820 : const char *pszUploadId, int nPartNumber,
821 : vsi_l_offset nFileOffset, const void *pData,
822 : size_t nDataLength,
823 : CSLConstList papszOptions) override;
824 :
825 : bool MultipartUploadEnd(const char *pszFilename, const char *pszUploadId,
826 : size_t nPartIdsCount,
827 : const char *const *apszPartIds,
828 : vsi_l_offset nTotalSize,
829 : CSLConstList papszOptions) override;
830 :
831 : bool MultipartUploadAbort(const char *pszFilename, const char *pszUploadId,
832 : CSLConstList papszOptions) override;
833 : };
834 :
835 : /************************************************************************/
836 : /* IVSIS3LikeHandle */
837 : /************************************************************************/
838 :
839 372 : class IVSIS3LikeHandle /* non final */ : public VSICurlHandle
840 : {
841 : CPL_DISALLOW_COPY_ASSIGN(IVSIS3LikeHandle)
842 :
843 : protected:
844 163 : bool UseLimitRangeGetInsteadOfHead() override
845 : {
846 163 : return true;
847 : }
848 :
849 117 : bool IsDirectoryFromExists(const char *pszVerb, int response_code) override
850 : {
851 : // A bit dirty, but on S3, a GET on a existing directory returns a 416
852 121 : return response_code == 416 && EQUAL(pszVerb, "GET") &&
853 121 : std::string(m_pszURL).back() == '/';
854 : }
855 :
856 55 : void ProcessGetFileSizeResult(const char *pszContent) override
857 : {
858 55 : oFileProp.bIsDirectory =
859 55 : strstr(pszContent, "ListBucketResult") != nullptr;
860 55 : }
861 :
862 : public:
863 372 : IVSIS3LikeHandle(VSICurlFilesystemHandlerBase *poFSIn,
864 : const char *pszFilename, const char *pszURLIn)
865 372 : : VSICurlHandle(poFSIn, pszFilename, pszURLIn)
866 : {
867 372 : }
868 :
869 : ~IVSIS3LikeHandle() override;
870 : };
871 :
872 : /************************************************************************/
873 : /* VSIMultipartWriteHandle */
874 : /************************************************************************/
875 :
876 : class VSIMultipartWriteHandle final : public VSIVirtualHandle
877 : {
878 : CPL_DISALLOW_COPY_ASSIGN(VSIMultipartWriteHandle)
879 :
880 : IVSIS3LikeFSHandlerWithMultipartUpload *m_poFS = nullptr;
881 : std::string m_osFilename{};
882 : IVSIS3LikeHandleHelper *m_poS3HandleHelper = nullptr;
883 : CPLStringList m_aosOptions{};
884 : CPLStringList m_aosHTTPOptions{};
885 : CPLHTTPRetryParameters m_oRetryParameters;
886 :
887 : vsi_l_offset m_nCurOffset = 0;
888 : size_t m_nBufferOff = 0;
889 : size_t m_nBufferSize = 0;
890 : bool m_bClosed = false;
891 : GByte *m_pabyBuffer = nullptr;
892 : std::string m_osUploadID{};
893 : int m_nPartNumber = 0;
894 : std::vector<std::string> m_aosEtags{};
895 : bool m_bError = false;
896 :
897 : WriteFuncStruct m_sWriteFuncHeaderData{};
898 :
899 : bool UploadPart();
900 : bool DoSinglePartPUT();
901 :
902 : void InvalidateParentDirectory();
903 :
904 : public:
905 : VSIMultipartWriteHandle(IVSIS3LikeFSHandlerWithMultipartUpload *poFS,
906 : const char *pszFilename,
907 : IVSIS3LikeHandleHelper *poS3HandleHelper,
908 : CSLConstList papszOptions);
909 : ~VSIMultipartWriteHandle() override;
910 :
911 : int Seek(vsi_l_offset nOffset, int nWhence) override;
912 : vsi_l_offset Tell() override;
913 : size_t Read(void *pBuffer, size_t nBytes) override;
914 : size_t Write(const void *pBuffer, size_t nBytes) override;
915 :
916 0 : void ClearErr() override
917 : {
918 0 : }
919 :
920 0 : int Error() override
921 : {
922 0 : return FALSE;
923 : }
924 :
925 0 : int Eof() override
926 : {
927 0 : return FALSE;
928 : }
929 :
930 : int Close() override;
931 :
932 31 : bool IsOK()
933 : {
934 31 : return m_pabyBuffer != nullptr;
935 : }
936 : };
937 :
938 : /************************************************************************/
939 : /* VSIChunkedWriteHandle() */
940 : /************************************************************************/
941 :
942 : /** Class with Write() append-only implementation using
943 : * "Transfer-Encoding: chunked" writing
944 : */
945 : class VSIChunkedWriteHandle final : public VSIVirtualHandle
946 : {
947 : CPL_DISALLOW_COPY_ASSIGN(VSIChunkedWriteHandle)
948 :
949 : IVSIS3LikeFSHandler *m_poFS = nullptr;
950 : std::string m_osFilename{};
951 : IVSIS3LikeHandleHelper *m_poS3HandleHelper = nullptr;
952 : CPLStringList m_aosOptions{};
953 : CPLStringList m_aosHTTPOptions{};
954 : CPLHTTPRetryParameters m_oRetryParameters;
955 :
956 : vsi_l_offset m_nCurOffset = 0;
957 : size_t m_nBufferOff = 0;
958 : bool m_bError = false;
959 : bool m_bClosed = false;
960 :
961 : CURLM *m_hCurlMulti = nullptr;
962 : CURL *m_hCurl = nullptr;
963 : const void *m_pBuffer = nullptr;
964 : std::string m_osCurlErrBuf{};
965 : size_t m_nChunkedBufferOff = 0;
966 : size_t m_nChunkedBufferSize = 0;
967 : size_t m_nWrittenInPUT = 0;
968 :
969 : WriteFuncStruct m_sWriteFuncHeaderData{};
970 :
971 : static size_t ReadCallBackBufferChunked(char *buffer, size_t size,
972 : size_t nitems, void *instream);
973 : int FinishChunkedTransfer();
974 :
975 : bool DoEmptyPUT();
976 :
977 : void InvalidateParentDirectory();
978 :
979 : public:
980 : VSIChunkedWriteHandle(IVSIS3LikeFSHandler *poFS, const char *pszFilename,
981 : IVSIS3LikeHandleHelper *poS3HandleHelper,
982 : CSLConstList papszOptions);
983 : ~VSIChunkedWriteHandle() override;
984 :
985 : int Seek(vsi_l_offset nOffset, int nWhence) override;
986 : vsi_l_offset Tell() override;
987 : size_t Read(void *pBuffer, size_t nBytes) override;
988 : size_t Write(const void *pBuffer, size_t nBytes) override;
989 :
990 0 : void ClearErr() override
991 : {
992 0 : }
993 :
994 0 : int Error() override
995 : {
996 0 : return FALSE;
997 : }
998 :
999 0 : int Eof() override
1000 : {
1001 0 : return FALSE;
1002 : }
1003 :
1004 : int Close() override;
1005 : };
1006 :
1007 : /************************************************************************/
1008 : /* VSIAppendWriteHandle */
1009 : /************************************************************************/
1010 :
1011 : class VSIAppendWriteHandle CPL_NON_FINAL : public VSIVirtualHandle
1012 : {
1013 : CPL_DISALLOW_COPY_ASSIGN(VSIAppendWriteHandle)
1014 :
1015 : protected:
1016 : VSICurlFilesystemHandlerBase *m_poFS = nullptr;
1017 : std::string m_osFSPrefix{};
1018 : std::string m_osFilename{};
1019 : CPLHTTPRetryParameters m_oRetryParameters{};
1020 :
1021 : vsi_l_offset m_nCurOffset = 0;
1022 : int m_nBufferOff = 0;
1023 : int m_nBufferSize = 0;
1024 : int m_nBufferOffReadCallback = 0;
1025 : bool m_bClosed = false;
1026 : GByte *m_pabyBuffer = nullptr;
1027 : bool m_bError = false;
1028 :
1029 : static size_t ReadCallBackBuffer(char *buffer, size_t size, size_t nitems,
1030 : void *instream);
1031 : virtual bool Send(bool bIsLastBlock) = 0;
1032 :
1033 : public:
1034 : VSIAppendWriteHandle(VSICurlFilesystemHandlerBase *poFS,
1035 : const char *pszFSPrefix, const char *pszFilename,
1036 : int nChunkSize);
1037 : ~VSIAppendWriteHandle() override;
1038 :
1039 : int Seek(vsi_l_offset nOffset, int nWhence) override;
1040 : vsi_l_offset Tell() override;
1041 : size_t Read(void *pBuffer, size_t nBytes) override;
1042 : size_t Write(const void *pBuffer, size_t nBytes) override;
1043 :
1044 0 : void ClearErr() override
1045 : {
1046 0 : }
1047 :
1048 0 : int Error() override
1049 : {
1050 0 : return FALSE;
1051 : }
1052 :
1053 0 : int Eof() override
1054 : {
1055 0 : return FALSE;
1056 : }
1057 :
1058 : int Close() override;
1059 :
1060 10 : bool IsOK()
1061 : {
1062 10 : return m_pabyBuffer != nullptr;
1063 : }
1064 : };
1065 :
1066 : /************************************************************************/
1067 : /* VSIDIRWithMissingDirSynthesis */
1068 : /************************************************************************/
1069 :
1070 138 : struct VSIDIRWithMissingDirSynthesis /* non final */ : public VSIDIR
1071 : {
1072 : std::vector<std::unique_ptr<VSIDIREntry>> aoEntries{};
1073 :
1074 : protected:
1075 : ~VSIDIRWithMissingDirSynthesis() override;
1076 :
1077 : std::vector<std::string> m_aosSubpathsStack{};
1078 :
1079 : void SynthetizeMissingDirectories(const std::string &osCurSubdir,
1080 : bool bAddEntryForThisSubdir);
1081 : };
1082 :
1083 : /************************************************************************/
1084 : /* VSIDIRS3Like */
1085 : /************************************************************************/
1086 :
1087 : struct VSIDIRS3Like /* non final */ : public VSIDIRWithMissingDirSynthesis
1088 : {
1089 : const std::string m_osDirName;
1090 :
1091 : int nRecurseDepth = 0;
1092 :
1093 : std::string osNextMarker{};
1094 : int nPos = 0;
1095 :
1096 : std::string osBucket{};
1097 : std::string osObjectKey{};
1098 : VSICurlFilesystemHandlerBase *poFS = nullptr;
1099 : IVSIS3LikeFSHandler *poS3FS = nullptr;
1100 : std::unique_ptr<IVSIS3LikeHandleHelper> poHandleHelper{};
1101 : int nMaxFiles = 0;
1102 : bool bCacheEntries = true;
1103 : bool m_bSynthetizeMissingDirectories = false;
1104 : std::string m_osFilterPrefix{};
1105 :
1106 : // used when listing only the file system prefix
1107 : std::unique_ptr<VSIDIR, decltype(&VSICloseDir)> m_subdir{nullptr,
1108 138 : VSICloseDir};
1109 :
1110 138 : VSIDIRS3Like(const std::string &osDirName, IVSIS3LikeFSHandler *poFSIn)
1111 138 : : m_osDirName(osDirName), poFS(poFSIn), poS3FS(poFSIn)
1112 : {
1113 138 : }
1114 :
1115 0 : VSIDIRS3Like(const std::string &osDirName,
1116 : VSICurlFilesystemHandlerBase *poFSIn)
1117 0 : : m_osDirName(osDirName), poFS(poFSIn)
1118 : {
1119 0 : }
1120 :
1121 : VSIDIRS3Like(const VSIDIRS3Like &) = delete;
1122 : VSIDIRS3Like &operator=(const VSIDIRS3Like &) = delete;
1123 :
1124 : const VSIDIREntry *NextDirEntry() override;
1125 :
1126 : virtual bool IssueListDir() = 0;
1127 : void clear();
1128 : };
1129 :
1130 : /************************************************************************/
1131 : /* CurlRequestHelper */
1132 : /************************************************************************/
1133 :
1134 : struct CurlRequestHelper
1135 : {
1136 : WriteFuncStruct sWriteFuncData{};
1137 : WriteFuncStruct sWriteFuncHeaderData{};
1138 : char szCurlErrBuf[CURL_ERROR_SIZE + 1] = {};
1139 :
1140 : CurlRequestHelper();
1141 : ~CurlRequestHelper();
1142 : long perform(CURL *hCurlHandle,
1143 : struct curl_slist *headers, // ownership transferred
1144 : VSICurlFilesystemHandlerBase *poFS,
1145 : IVSIS3LikeHandleHelper *poS3HandleHelper);
1146 : };
1147 :
1148 : /************************************************************************/
1149 : /* NetworkStatisticsLogger */
1150 : /************************************************************************/
1151 :
1152 : class NetworkStatisticsLogger
1153 : {
1154 : static int gnEnabled;
1155 : static NetworkStatisticsLogger gInstance;
1156 :
1157 1923 : NetworkStatisticsLogger() = default;
1158 :
1159 : std::mutex m_mutex{};
1160 :
1161 : struct Counters
1162 : {
1163 : GIntBig nHEAD = 0;
1164 : GIntBig nGET = 0;
1165 : GIntBig nPUT = 0;
1166 : GIntBig nPOST = 0;
1167 : GIntBig nDELETE = 0;
1168 : GIntBig nGETDownloadedBytes = 0;
1169 : GIntBig nPUTUploadedBytes = 0;
1170 : GIntBig nPOSTDownloadedBytes = 0;
1171 : GIntBig nPOSTUploadedBytes = 0;
1172 : };
1173 :
1174 : enum class ContextPathType
1175 : {
1176 : FILESYSTEM,
1177 : FILE,
1178 : ACTION,
1179 : };
1180 :
1181 : struct ContextPathItem
1182 : {
1183 : ContextPathType eType;
1184 : std::string osName;
1185 :
1186 3 : ContextPathItem(ContextPathType eTypeIn, const std::string &osNameIn)
1187 3 : : eType(eTypeIn), osName(osNameIn)
1188 : {
1189 3 : }
1190 :
1191 0 : bool operator<(const ContextPathItem &other) const
1192 : {
1193 0 : if (static_cast<int>(eType) < static_cast<int>(other.eType))
1194 0 : return true;
1195 0 : if (static_cast<int>(eType) > static_cast<int>(other.eType))
1196 0 : return false;
1197 0 : return osName < other.osName;
1198 : }
1199 : };
1200 :
1201 : struct Stats
1202 : {
1203 : Counters counters{};
1204 : std::map<ContextPathItem, Stats> children{};
1205 :
1206 : void AsJSON(CPLJSONObject &oJSON) const;
1207 : };
1208 :
1209 : // Workaround bug in Coverity Scan
1210 : // coverity[generated_default_constructor_used_in_field_initializer]
1211 : Stats m_stats{};
1212 : std::map<GIntBig, std::vector<ContextPathItem>>
1213 : m_mapThreadIdToContextPath{};
1214 :
1215 : static void ReadEnabled();
1216 :
1217 : std::vector<Counters *> GetCountersForContext();
1218 :
1219 : public:
1220 904901 : static inline bool IsEnabled()
1221 : {
1222 904901 : if (gnEnabled < 0)
1223 : {
1224 7 : ReadEnabled();
1225 : }
1226 904901 : return gnEnabled == TRUE;
1227 : }
1228 :
1229 : static void EnterFileSystem(const char *pszName);
1230 :
1231 : static void LeaveFileSystem();
1232 :
1233 : static void EnterFile(const char *pszName);
1234 :
1235 : static void LeaveFile();
1236 :
1237 : static void EnterAction(const char *pszName);
1238 :
1239 : static void LeaveAction();
1240 :
1241 : static void LogHEAD();
1242 :
1243 : static void LogGET(size_t nDownloadedBytes);
1244 :
1245 : static void LogPUT(size_t nUploadedBytes);
1246 :
1247 : static void LogPOST(size_t nUploadedBytes, size_t nDownloadedBytes);
1248 :
1249 : static void LogDELETE();
1250 :
1251 : static void Reset();
1252 :
1253 : static std::string GetReportAsSerializedJSON();
1254 : };
1255 :
1256 : struct NetworkStatisticsFileSystem
1257 : {
1258 151324 : inline explicit NetworkStatisticsFileSystem(const char *pszName)
1259 : {
1260 151324 : NetworkStatisticsLogger::EnterFileSystem(pszName);
1261 151324 : }
1262 :
1263 151324 : inline ~NetworkStatisticsFileSystem()
1264 : {
1265 151324 : NetworkStatisticsLogger::LeaveFileSystem();
1266 151324 : }
1267 : };
1268 :
1269 : struct NetworkStatisticsFile
1270 : {
1271 149061 : inline explicit NetworkStatisticsFile(const char *pszName)
1272 : {
1273 149061 : NetworkStatisticsLogger::EnterFile(pszName);
1274 149061 : }
1275 :
1276 149061 : inline ~NetworkStatisticsFile()
1277 : {
1278 149061 : NetworkStatisticsLogger::LeaveFile();
1279 149061 : }
1280 : };
1281 :
1282 : struct NetworkStatisticsAction
1283 : {
1284 151324 : inline explicit NetworkStatisticsAction(const char *pszName)
1285 : {
1286 151324 : NetworkStatisticsLogger::EnterAction(pszName);
1287 151324 : }
1288 :
1289 151324 : inline ~NetworkStatisticsAction()
1290 : {
1291 151324 : NetworkStatisticsLogger::LeaveAction();
1292 151324 : }
1293 : };
1294 :
1295 : } // namespace cpl
1296 :
1297 : int VSICURLGetDownloadChunkSize();
1298 :
1299 : void VSICURLInitWriteFuncStruct(cpl::WriteFuncStruct *psStruct, VSILFILE *fp,
1300 : VSICurlReadCbkFunc pfnReadCbk,
1301 : void *pReadCbkUserData);
1302 : size_t VSICurlHandleWriteFunc(void *buffer, size_t count, size_t nmemb,
1303 : void *req);
1304 : void VSICURLMultiPerform(CURLM *hCurlMultiHandle, CURL *hEasyHandle = nullptr,
1305 : std::atomic<bool> *pbInterrupt = nullptr);
1306 : void VSICURLResetHeaderAndWriterFunctions(CURL *hCurlHandle);
1307 :
1308 : int VSICurlParseUnixPermissions(const char *pszPermissions);
1309 :
1310 : // Cache of file properties (size, etc.)
1311 : bool VSICURLGetCachedFileProp(const char *pszURL, cpl::FileProp &oFileProp);
1312 : void VSICURLSetCachedFileProp(const char *pszURL, cpl::FileProp &oFileProp);
1313 : void VSICURLInvalidateCachedFileProp(const char *pszURL);
1314 : void VSICURLInvalidateCachedFilePropPrefix(const char *pszURL);
1315 : void VSICURLDestroyCacheFileProp();
1316 :
1317 : void VSICURLMultiCleanup(CURLM *hCurlMultiHandle);
1318 :
1319 : //! @endcond
1320 :
1321 : #endif // HAVE_CURL
1322 :
1323 : #endif // CPL_VSIL_CURL_CLASS_H_INCLUDED
|