Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Project: CPL - Common Portability Library 4 : * Purpose: File handler that uses a temporary file, and upload file on close 5 : * Author: Even Rouault, even.rouault at spatialys.com 6 : * 7 : ****************************************************************************** 8 : * Copyright (c) 2020, Even Rouault <even.rouault at spatialys.com> 9 : * 10 : * SPDX-License-Identifier: MIT 11 : ****************************************************************************/ 12 : 13 : #include "cpl_vsi_virtual.h" 14 : 15 : #include <algorithm> 16 : #include <vector> 17 : 18 : /************************************************************************/ 19 : /* VSIUploadOnCloseHandle */ 20 : /************************************************************************/ 21 : 22 : class VSIUploadOnCloseHandle final : public VSIVirtualHandle 23 : { 24 : VSIVirtualHandleUniquePtr m_poWritableHandle; 25 : std::string m_osTmpFilename; 26 : VSIVirtualHandleUniquePtr m_fpTemp; 27 : 28 : VSIUploadOnCloseHandle(const VSIUploadOnCloseHandle &) = delete; 29 : VSIUploadOnCloseHandle &operator=(const VSIUploadOnCloseHandle &) = delete; 30 : 31 : public: 32 5 : VSIUploadOnCloseHandle(VSIVirtualHandleUniquePtr &&poWritableHandle, 33 : const std::string &osTmpFilename, 34 : VSIVirtualHandleUniquePtr &&fpTemp) 35 10 : : m_poWritableHandle(std::move(poWritableHandle)), 36 5 : m_osTmpFilename(osTmpFilename), m_fpTemp(std::move(fpTemp)) 37 : { 38 5 : } 39 : 40 : ~VSIUploadOnCloseHandle() override; 41 : 42 31 : int Seek(vsi_l_offset nOffset, int nWhence) override 43 : { 44 31 : return m_fpTemp->Seek(nOffset, nWhence); 45 : } 46 : 47 27 : vsi_l_offset Tell() override 48 : { 49 27 : return m_fpTemp->Tell(); 50 : } 51 : 52 35 : size_t Read(void *pBuffer, size_t nSize, size_t nCount) override 53 : { 54 35 : return m_fpTemp->Read(pBuffer, nSize, nCount); 55 : } 56 : 57 13 : size_t Write(const void *pBuffer, size_t nSize, size_t nCount) override 58 : { 59 13 : return m_fpTemp->Write(pBuffer, nSize, nCount); 60 : } 61 : 62 0 : void ClearErr() override 63 : { 64 0 : } 65 : 66 0 : int Error() override 67 : { 68 0 : return 0; 69 : } 70 : 71 1 : int Eof() override 72 : { 73 1 : return m_fpTemp->Eof(); 74 : } 75 : 76 0 : int Flush() override 77 : { 78 0 : return m_fpTemp->Flush(); 79 : } 80 : 81 : int Close() override; 82 : 83 0 : int Truncate(vsi_l_offset nNewSize) override 84 : { 85 0 : return m_fpTemp->Truncate(nNewSize); 86 : } 87 : 88 0 : VSIRangeStatus GetRangeStatus(vsi_l_offset nOffset, 89 : vsi_l_offset nLength) override 90 : { 91 0 : return m_fpTemp->GetRangeStatus(nOffset, nLength); 92 : } 93 : }; 94 : 95 : /************************************************************************/ 96 : /* ~VSIUploadOnCloseHandle() */ 97 : /************************************************************************/ 98 : 99 10 : VSIUploadOnCloseHandle::~VSIUploadOnCloseHandle() 100 : { 101 5 : VSIUploadOnCloseHandle::Close(); 102 5 : if (!m_osTmpFilename.empty()) 103 0 : VSIUnlink(m_osTmpFilename.c_str()); 104 10 : } 105 : 106 : /************************************************************************/ 107 : /* Close() */ 108 : /************************************************************************/ 109 : 110 10 : int VSIUploadOnCloseHandle::Close() 111 : { 112 10 : if (m_fpTemp == nullptr) 113 5 : return -1; 114 : 115 : // Copy temporary files to m_poWritableHandle 116 5 : if (m_fpTemp->Seek(0, SEEK_END) != 0) 117 : { 118 0 : m_fpTemp.reset(); 119 0 : return -1; 120 : } 121 5 : const auto nSize = m_fpTemp->Tell(); 122 5 : m_fpTemp->Seek(0, SEEK_SET); 123 5 : constexpr size_t CHUNK_SIZE = 1024 * 1024; 124 5 : vsi_l_offset nOffset = 0; 125 15 : std::vector<GByte> abyBuffer(CHUNK_SIZE); 126 8 : while (nOffset < nSize) 127 : { 128 : size_t nToRead = static_cast<size_t>( 129 4 : std::min(nSize - nOffset, static_cast<vsi_l_offset>(CHUNK_SIZE))); 130 8 : if (m_fpTemp->Read(&abyBuffer[0], nToRead, 1) != 1 || 131 4 : m_poWritableHandle->Write(&abyBuffer[0], nToRead, 1) != 1) 132 : { 133 1 : m_fpTemp.reset(); 134 1 : return -1; 135 : } 136 3 : nOffset += nToRead; 137 : } 138 4 : m_fpTemp.reset(); 139 4 : return m_poWritableHandle->Close(); 140 : } 141 : 142 : /************************************************************************/ 143 : /* VSICreateUploadOnCloseFile() */ 144 : /************************************************************************/ 145 : 146 : VSIVirtualHandle * 147 5 : VSICreateUploadOnCloseFile(VSIVirtualHandleUniquePtr &&poWritableHandle, 148 : VSIVirtualHandleUniquePtr &&poTmpFile, 149 : const std::string &osTmpFilename) 150 : { 151 5 : const bool deleted = VSIUnlink(osTmpFilename.c_str()) == 0; 152 5 : return new VSIUploadOnCloseHandle(std::move(poWritableHandle), 153 10 : deleted ? std::string() : osTmpFilename, 154 10 : std::move(poTmpFile)); 155 : }