/****************************************************************************** * $Id$ * * Project: VSI Virtual File System * Purpose: Declarations for classes related to the virtual filesystem. * These would only be normally required by applications implementing * their own virtual file system classes which should be rare. * The class interface may be fragile through versions. * Author: Frank Warmerdam, warmerdam@pobox.com * ****************************************************************************** * Copyright (c) 2005, Frank Warmerdam * Copyright (c) 2010-2014, Even Rouault * * SPDX-License-Identifier: MIT ****************************************************************************/ #ifndef CPL_VSI_VIRTUAL_H_INCLUDED #define CPL_VSI_VIRTUAL_H_INCLUDED #include "cpl_vsi.h" #include "cpl_vsi_error.h" #include "cpl_string.h" #include "cpl_multiproc.h" #include #include #include #include // To avoid aliasing to GetDiskFreeSpace to GetDiskFreeSpaceA on Windows #ifdef GetDiskFreeSpace #undef GetDiskFreeSpace #endif // To avoid aliasing to CopyFile to CopyFileA on Windows #ifdef CopyFile #undef CopyFile #endif /************************************************************************/ /* VSIVirtualHandle */ /************************************************************************/ /** Virtual file handle */ struct CPL_DLL VSIVirtualHandle { public: virtual int Seek(vsi_l_offset nOffset, int nWhence) = 0; virtual vsi_l_offset Tell() = 0; virtual size_t Read(void *pBuffer, size_t nSize, size_t nCount) = 0; virtual int ReadMultiRange(int nRanges, void **ppData, const vsi_l_offset *panOffsets, const size_t *panSizes); /** This method is called when code plans to access soon one or several * ranges in a file. Some file systems may be able to use this hint to * for example asynchronously start such requests. * * Offsets may be given in a non-increasing order, and may potentially * overlap. * * @param nRanges Size of the panOffsets and panSizes arrays. * @param panOffsets Array containing the start offset of each range. * @param panSizes Array containing the size (in bytes) of each range. * @since GDAL 3.7 */ virtual void AdviseRead(CPL_UNUSED int nRanges, CPL_UNUSED const vsi_l_offset *panOffsets, CPL_UNUSED const size_t *panSizes) { } /** Return the total maximum number of bytes that AdviseRead() can handle * at once. * * Some AdviseRead() implementations may give up if the sum of the values * in the panSizes[] array provided to AdviseRead() exceeds a limit. * * Callers might use that threshold to optimize the efficiency of * AdviseRead(). * * A returned value of 0 indicates a unknown limit. * @since GDAL 3.9 */ virtual size_t GetAdviseReadTotalBytesLimit() const { return 0; } virtual size_t Write(const void *pBuffer, size_t nSize, size_t nCount) = 0; int Printf(CPL_FORMAT_STRING(const char *pszFormat), ...) CPL_PRINT_FUNC_FORMAT(2, 3); virtual void ClearErr() = 0; virtual int Eof() = 0; virtual int Error() = 0; virtual int Flush() { return 0; } virtual int Close() = 0; // Base implementation that only supports file extension. virtual int Truncate(vsi_l_offset nNewSize); virtual void *GetNativeFileDescriptor() { return nullptr; } virtual VSIRangeStatus GetRangeStatus(CPL_UNUSED vsi_l_offset nOffset, CPL_UNUSED vsi_l_offset nLength) { return VSI_RANGE_STATUS_UNKNOWN; } virtual bool HasPRead() const; virtual size_t PRead(void *pBuffer, size_t nSize, vsi_l_offset nOffset) const; /** Ask current operations to be interrupted. * Implementations must be thread-safe, as this will typically be called * from another thread than the active one for this file. */ virtual void Interrupt() { } // NOTE: when adding new methods, besides the "actual" implementations, // also consider the VSICachedFile one. virtual ~VSIVirtualHandle() { } }; /************************************************************************/ /* VSIVirtualHandleCloser */ /************************************************************************/ /** Helper close to use with a std:unique_ptr, * such as VSIVirtualHandleUniquePtr. */ struct VSIVirtualHandleCloser { /** Operator () that closes and deletes the file handle. */ void operator()(VSIVirtualHandle *poHandle) { if (poHandle) { poHandle->Close(); delete poHandle; } } }; /** Unique pointer of VSIVirtualHandle that calls the Close() method */ typedef std::unique_ptr VSIVirtualHandleUniquePtr; /************************************************************************/ /* VSIFilesystemHandler */ /************************************************************************/ #ifndef DOXYGEN_SKIP class CPL_DLL VSIFilesystemHandler { public: virtual ~VSIFilesystemHandler() { } VSIVirtualHandle *Open(const char *pszFilename, const char *pszAccess); virtual VSIVirtualHandle *Open(const char *pszFilename, const char *pszAccess, bool bSetError, CSLConstList papszOptions) = 0; virtual int Stat(const char *pszFilename, VSIStatBufL *pStatBuf, int nFlags) = 0; virtual int Unlink(const char *pszFilename) { (void)pszFilename; errno = ENOENT; return -1; } virtual int *UnlinkBatch(CSLConstList papszFiles); virtual int Mkdir(const char *pszDirname, long nMode) { (void)pszDirname; (void)nMode; errno = ENOENT; return -1; } virtual int Rmdir(const char *pszDirname) { (void)pszDirname; errno = ENOENT; return -1; } virtual int RmdirRecursive(const char *pszDirname); char **ReadDir(const char *pszDirname) { return ReadDirEx(pszDirname, 0); } virtual char **ReadDirEx(const char * /*pszDirname*/, int /* nMaxFiles */) { return nullptr; } virtual char **SiblingFiles(const char * /*pszFilename*/) { return nullptr; } virtual int Rename(const char *oldpath, const char *newpath) { (void)oldpath; (void)newpath; errno = ENOENT; return -1; } virtual int IsCaseSensitive(const char *pszFilename) { (void)pszFilename; return TRUE; } virtual GIntBig GetDiskFreeSpace(const char * /* pszDirname */) { return -1; } virtual int SupportsSparseFiles(const char * /* pszPath */) { return FALSE; } virtual int HasOptimizedReadMultiRange(const char * /* pszPath */) { return FALSE; } virtual const char *GetActualURL(const char * /*pszFilename*/) { return nullptr; } virtual const char *GetOptions() { return nullptr; } virtual char *GetSignedURL(const char * /*pszFilename*/, CSLConstList /* papszOptions */) { return nullptr; } virtual bool Sync(const char *pszSource, const char *pszTarget, const char *const *papszOptions, GDALProgressFunc pProgressFunc, void *pProgressData, char ***ppapszOutputs); virtual int CopyFile(const char *pszSource, const char *pszTarget, VSILFILE *fpSource, vsi_l_offset nSourceSize, const char *const *papszOptions, GDALProgressFunc pProgressFunc, void *pProgressData); virtual int CopyFileRestartable(const char *pszSource, const char *pszTarget, const char *pszInputPayload, char **ppszOutputPayload, CSLConstList papszOptions, GDALProgressFunc pProgressFunc, void *pProgressData); virtual VSIDIR *OpenDir(const char *pszPath, int nRecurseDepth, const char *const *papszOptions); virtual char **GetFileMetadata(const char *pszFilename, const char *pszDomain, CSLConstList papszOptions); virtual bool SetFileMetadata(const char *pszFilename, CSLConstList papszMetadata, const char *pszDomain, CSLConstList papszOptions); virtual bool MultipartUploadGetCapabilities(int *pbNonSequentialUploadSupported, int *pbParallelUploadSupported, int *pbAbortSupported, size_t *pnMinPartSize, size_t *pnMaxPartSize, int *pnMaxPartCount); virtual char *MultipartUploadStart(const char *pszFilename, CSLConstList papszOptions); virtual char *MultipartUploadAddPart(const char *pszFilename, const char *pszUploadId, int nPartNumber, vsi_l_offset nFileOffset, const void *pData, size_t nDataLength, CSLConstList papszOptions); virtual bool MultipartUploadEnd(const char *pszFilename, const char *pszUploadId, size_t nPartIdsCount, const char *const *apszPartIds, vsi_l_offset nTotalSize, CSLConstList papszOptions); virtual bool MultipartUploadAbort(const char *pszFilename, const char *pszUploadId, CSLConstList papszOptions); virtual bool AbortPendingUploads(const char * /*pszFilename*/) { return true; } virtual std::string GetStreamingFilename(const std::string &osFilename) const { return osFilename; } virtual std::string GetNonStreamingFilename(const std::string &osFilename) const { return osFilename; } /** Return the canonical filename. * * May be implemented by case-insensitive filesystems * (currently Win32 and MacOSX) * to return the filename with its actual case (i.e. the one that would * be used when listing the content of the directory). */ virtual std::string GetCanonicalFilename(const std::string &osFilename) const { return osFilename; } virtual bool IsLocal(const char * /* pszPath */) { return true; } virtual bool SupportsSequentialWrite(const char * /* pszPath */, bool /* bAllowLocalTempFile */) { return true; } virtual bool SupportsRandomWrite(const char * /* pszPath */, bool /* bAllowLocalTempFile */) { return true; } virtual bool SupportsRead(const char * /* pszPath */) { return true; } virtual VSIFilesystemHandler *Duplicate(const char * /* pszPrefix */) { CPLError(CE_Failure, CPLE_NotSupported, "Duplicate() not supported on this file system"); return nullptr; } /** Return the directory separator. * * Default is forward slash. The only exception currently is the Windows * file system which returns anti-slash, unless the specified path is of the * form "{drive_letter}:/{rest_of_the_path}". */ virtual const char *GetDirectorySeparator(CPL_UNUSED const char *pszPath) { return "/"; } }; #endif /* #ifndef DOXYGEN_SKIP */ /************************************************************************/ /* VSIFileManager */ /************************************************************************/ #ifndef DOXYGEN_SKIP class CPL_DLL VSIFileManager { private: VSIFilesystemHandler *poDefaultHandler = nullptr; std::map oHandlers{}; VSIFileManager(); static VSIFileManager *Get(); CPL_DISALLOW_COPY_ASSIGN(VSIFileManager) public: ~VSIFileManager(); static VSIFilesystemHandler *GetHandler(const char *); static void InstallHandler(const std::string &osPrefix, VSIFilesystemHandler *); static void RemoveHandler(const std::string &osPrefix); static char **GetPrefixes(); }; #endif /* #ifndef DOXYGEN_SKIP */ /************************************************************************/ /* ==================================================================== */ /* VSIArchiveFilesystemHandler */ /* ==================================================================== */ /************************************************************************/ #ifndef DOXYGEN_SKIP class VSIArchiveEntryFileOffset { public: virtual ~VSIArchiveEntryFileOffset(); }; typedef struct { char *fileName; vsi_l_offset uncompressed_size; VSIArchiveEntryFileOffset *file_pos; int bIsDir; GIntBig nModifiedTime; } VSIArchiveEntry; class VSIArchiveContent { public: time_t mTime = 0; vsi_l_offset nFileSize = 0; int nEntries = 0; VSIArchiveEntry *entries = nullptr; ~VSIArchiveContent(); }; class VSIArchiveReader { public: virtual ~VSIArchiveReader(); virtual int GotoFirstFile() = 0; virtual int GotoNextFile() = 0; virtual VSIArchiveEntryFileOffset *GetFileOffset() = 0; virtual GUIntBig GetFileSize() = 0; virtual CPLString GetFileName() = 0; virtual GIntBig GetModifiedTime() = 0; virtual int GotoFileOffset(VSIArchiveEntryFileOffset *pOffset) = 0; }; class VSIArchiveFilesystemHandler : public VSIFilesystemHandler { CPL_DISALLOW_COPY_ASSIGN(VSIArchiveFilesystemHandler) protected: CPLMutex *hMutex = nullptr; /* We use a cache that contains the list of files contained in a VSIArchive * file as */ /* unarchive.c is quite inefficient in listing them. This speeds up access * to VSIArchive files */ /* containing ~1000 files like a CADRG product */ std::map oFileList{}; virtual const char *GetPrefix() = 0; virtual std::vector GetExtensions() = 0; virtual VSIArchiveReader *CreateReader(const char *pszArchiveFileName) = 0; public: VSIArchiveFilesystemHandler(); virtual ~VSIArchiveFilesystemHandler(); int Stat(const char *pszFilename, VSIStatBufL *pStatBuf, int nFlags) override; int Unlink(const char *pszFilename) override; int Rename(const char *oldpath, const char *newpath) override; int Mkdir(const char *pszDirname, long nMode) override; int Rmdir(const char *pszDirname) override; char **ReadDirEx(const char *pszDirname, int nMaxFiles) override; virtual const VSIArchiveContent * GetContentOfArchive(const char *archiveFilename, VSIArchiveReader *poReader = nullptr); virtual char *SplitFilename(const char *pszFilename, CPLString &osFileInArchive, int bCheckMainFileExists); virtual VSIArchiveReader *OpenArchiveFile(const char *archiveFilename, const char *fileInArchiveName); virtual int FindFileInArchive(const char *archiveFilename, const char *fileInArchiveName, const VSIArchiveEntry **archiveEntry); virtual bool IsLocal(const char *pszPath) override; virtual bool SupportsSequentialWrite(const char * /* pszPath */, bool /* bAllowLocalTempFile */) override { return false; } virtual bool SupportsRandomWrite(const char * /* pszPath */, bool /* bAllowLocalTempFile */) override { return false; } }; /************************************************************************/ /* VSIDIR */ /************************************************************************/ struct CPL_DLL VSIDIR { VSIDIR() = default; virtual ~VSIDIR(); virtual const VSIDIREntry *NextDirEntry() = 0; private: VSIDIR(const VSIDIR &) = delete; VSIDIR &operator=(const VSIDIR &) = delete; }; #endif /* #ifndef DOXYGEN_SKIP */ VSIVirtualHandle CPL_DLL * VSICreateBufferedReaderHandle(VSIVirtualHandle *poBaseHandle); VSIVirtualHandle * VSICreateBufferedReaderHandle(VSIVirtualHandle *poBaseHandle, const GByte *pabyBeginningContent, vsi_l_offset nCheatFileSize); constexpr int VSI_CACHED_DEFAULT_CHUNK_SIZE = 32768; VSIVirtualHandle CPL_DLL * VSICreateCachedFile(VSIVirtualHandle *poBaseHandle, size_t nChunkSize = VSI_CACHED_DEFAULT_CHUNK_SIZE, size_t nCacheSize = 0); const int CPL_DEFLATE_TYPE_GZIP = 0; const int CPL_DEFLATE_TYPE_ZLIB = 1; const int CPL_DEFLATE_TYPE_RAW_DEFLATE = 2; VSIVirtualHandle CPL_DLL *VSICreateGZipWritable(VSIVirtualHandle *poBaseHandle, int nDeflateType, int bAutoCloseBaseHandle); VSIVirtualHandle *VSICreateGZipWritable(VSIVirtualHandle *poBaseHandle, int nDeflateType, bool bAutoCloseBaseHandle, int nThreads, size_t nChunkSize, size_t nSOZIPIndexEltSize, std::vector *panSOZIPIndex); VSIVirtualHandle * VSICreateUploadOnCloseFile(VSIVirtualHandleUniquePtr &&poWritableHandle, VSIVirtualHandleUniquePtr &&poTmpFile, const std::string &osTmpFilename); #endif /* ndef CPL_VSI_VIRTUAL_H_INCLUDED */