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