Coverage Report

Created: 2025-08-11 09:23

/src/gdal/port/cpl_vsil_uploadonclose.cpp
Line
Count
Source (jump to first uncovered line)
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
    VSIUploadOnCloseHandle(VSIVirtualHandleUniquePtr &&poWritableHandle,
33
                           const std::string &osTmpFilename,
34
                           VSIVirtualHandleUniquePtr &&fpTemp)
35
0
        : m_poWritableHandle(std::move(poWritableHandle)),
36
0
          m_osTmpFilename(osTmpFilename), m_fpTemp(std::move(fpTemp))
37
0
    {
38
0
    }
39
40
    ~VSIUploadOnCloseHandle() override;
41
42
    int Seek(vsi_l_offset nOffset, int nWhence) override
43
0
    {
44
0
        return m_fpTemp->Seek(nOffset, nWhence);
45
0
    }
46
47
    vsi_l_offset Tell() override
48
0
    {
49
0
        return m_fpTemp->Tell();
50
0
    }
51
52
    size_t Read(void *pBuffer, size_t nSize, size_t nCount) override
53
0
    {
54
0
        return m_fpTemp->Read(pBuffer, nSize, nCount);
55
0
    }
56
57
    size_t Write(const void *pBuffer, size_t nSize, size_t nCount) override
58
0
    {
59
0
        return m_fpTemp->Write(pBuffer, nSize, nCount);
60
0
    }
61
62
    void ClearErr() override
63
0
    {
64
0
    }
65
66
    int Error() override
67
0
    {
68
0
        return 0;
69
0
    }
70
71
    int Eof() override
72
0
    {
73
0
        return m_fpTemp->Eof();
74
0
    }
75
76
    int Flush() override
77
0
    {
78
0
        return m_fpTemp->Flush();
79
0
    }
80
81
    int Close() override;
82
83
    int Truncate(vsi_l_offset nNewSize) override
84
0
    {
85
0
        return m_fpTemp->Truncate(nNewSize);
86
0
    }
87
88
    VSIRangeStatus GetRangeStatus(vsi_l_offset nOffset,
89
                                  vsi_l_offset nLength) override
90
0
    {
91
0
        return m_fpTemp->GetRangeStatus(nOffset, nLength);
92
0
    }
93
};
94
95
/************************************************************************/
96
/*                      ~VSIUploadOnCloseHandle()                       */
97
/************************************************************************/
98
99
VSIUploadOnCloseHandle::~VSIUploadOnCloseHandle()
100
0
{
101
0
    VSIUploadOnCloseHandle::Close();
102
0
    if (!m_osTmpFilename.empty())
103
0
        VSIUnlink(m_osTmpFilename.c_str());
104
0
}
105
106
/************************************************************************/
107
/*                              Close()                                 */
108
/************************************************************************/
109
110
int VSIUploadOnCloseHandle::Close()
111
0
{
112
0
    if (m_fpTemp == nullptr)
113
0
        return -1;
114
115
    // Copy temporary files to m_poWritableHandle
116
0
    if (m_fpTemp->Seek(0, SEEK_END) != 0)
117
0
    {
118
0
        m_fpTemp.reset();
119
0
        return -1;
120
0
    }
121
0
    const auto nSize = m_fpTemp->Tell();
122
0
    m_fpTemp->Seek(0, SEEK_SET);
123
0
    constexpr size_t CHUNK_SIZE = 1024 * 1024;
124
0
    vsi_l_offset nOffset = 0;
125
0
    std::vector<GByte> abyBuffer(CHUNK_SIZE);
126
0
    while (nOffset < nSize)
127
0
    {
128
0
        size_t nToRead = static_cast<size_t>(
129
0
            std::min(nSize - nOffset, static_cast<vsi_l_offset>(CHUNK_SIZE)));
130
0
        if (m_fpTemp->Read(&abyBuffer[0], nToRead, 1) != 1 ||
131
0
            m_poWritableHandle->Write(&abyBuffer[0], nToRead, 1) != 1)
132
0
        {
133
0
            m_fpTemp.reset();
134
0
            return -1;
135
0
        }
136
0
        nOffset += nToRead;
137
0
    }
138
0
    m_fpTemp.reset();
139
0
    return m_poWritableHandle->Close();
140
0
}
141
142
/************************************************************************/
143
/*                    VSICreateUploadOnCloseFile()                      */
144
/************************************************************************/
145
146
VSIVirtualHandle *
147
VSICreateUploadOnCloseFile(VSIVirtualHandleUniquePtr &&poWritableHandle,
148
                           VSIVirtualHandleUniquePtr &&poTmpFile,
149
                           const std::string &osTmpFilename)
150
0
{
151
0
    const bool deleted = VSIUnlink(osTmpFilename.c_str()) == 0;
152
0
    return new VSIUploadOnCloseHandle(std::move(poWritableHandle),
153
0
                                      deleted ? std::string() : osTmpFilename,
154
0
                                      std::move(poTmpFile));
155
0
}