1/*
2 * Copyright (c) 2015, Intel Corporation
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation and/or
13 * other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors
16 * may be used to endorse or promote products derived from this software without
17 * specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30#pragma once
31
32#include <exception>
33#include <fstream>
34#include <string>
35#include <array>
36
37#include <cerrno>
38#include <cstring>
39
40namespace parameterFramework
41{
42namespace utility
43{
44
45/** Create a temporary file with the given content. */
46class TmpFile
47{
48public:
49    TmpFile(std::string content) : mPath(mktmp())
50    {
51        std::ofstream file(mPath);
52        file.exceptions(std::ofstream::failbit | std::ofstream::badbit);
53        file << content;
54        // Close explicitly to detect errors (fstream destructor does not throw)
55        file.close();
56    }
57
58    TmpFile(TmpFile &&right) : mPath(std::move(right.mPath)) { right.mPath.clear(); }
59
60    /** Forbid copy semantic as sharing the tmp file is not needed.
61     * @{ */
62    TmpFile(const TmpFile &right) = delete;
63    TmpFile &operator=(const TmpFile &right) = delete;
64    /** @} */
65
66    TmpFile &operator=(TmpFile &&right)
67    {
68        remove();
69        mPath = std::move(right.mPath);
70        right.mPath.clear();
71        return *this;
72    }
73
74    ~TmpFile() { remove(); }
75
76    /** @return the path to the temporary file.
77     *          "" if the file was moved from.
78     */
79    const std::string &getPath() const { return mPath; }
80private:
81    /** @return a valid unique file name. */
82    std::string mktmp();
83
84    /** Throw an std::runtime_error with a message constructed from the context and std::errno.
85     *
86     * Call it after a c standard function failure.
87     */
88    static void throwErrnoError(std::string context)
89    {
90        auto message = context + ": (" + std::to_string(errno) + ") " + std::strerror(errno);
91        throw std::runtime_error(message);
92    }
93
94    void remove()
95    {
96        if (not mPath.empty()) {
97            if (std::remove(mPath.c_str()) != 0) {
98                throwErrnoError("Could not delete tmpfile");
99            }
100        }
101    }
102    std::string mPath;
103};
104
105} // utility
106} // parameterFramework
107