| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // Copyright Contributors to the OpenVDB Project | ||
| 2 | // SPDX-License-Identifier: MPL-2.0 | ||
| 3 | |||
| 4 | /// @file TempFile.cc | ||
| 5 | |||
| 6 | #include "TempFile.h" | ||
| 7 | |||
| 8 | #include <openvdb/Exceptions.h> | ||
| 9 | #ifndef _WIN32 | ||
| 10 | #include <boost/iostreams/stream.hpp> | ||
| 11 | #include <boost/iostreams/device/file_descriptor.hpp> | ||
| 12 | #include <cstdlib> // for std::getenv(), mkstemp() | ||
| 13 | #include <sys/types.h> // for mode_t | ||
| 14 | #include <sys/stat.h> // for mkdir(), umask() | ||
| 15 | #include <unistd.h> // for access() | ||
| 16 | #else | ||
| 17 | #include <fstream> // for std::filebuf | ||
| 18 | #endif | ||
| 19 | #include <cstdio> // for std::tmpnam(), L_tmpnam, P_tmpdir | ||
| 20 | #include <iostream> | ||
| 21 | #include <sstream> | ||
| 22 | #include <string> | ||
| 23 | #include <vector> | ||
| 24 | |||
| 25 | |||
| 26 | namespace openvdb { | ||
| 27 | OPENVDB_USE_VERSION_NAMESPACE | ||
| 28 | namespace OPENVDB_VERSION_NAME { | ||
| 29 | namespace io { | ||
| 30 | |||
| 31 | struct TempFile::TempFileImpl | ||
| 32 | { | ||
| 33 | 61 | const std::string& filename() const { return mPath; } | |
| 34 | |||
| 35 | bool is_open() const { return mBuffer.is_open(); } | ||
| 36 | |||
| 37 | /// @internal boost::filesystem::unique_path(), etc. might be useful here, | ||
| 38 | /// but as of 9/2014, Houdini ships without the Boost.Filesystem library, | ||
| 39 | /// which makes it much less convenient to use that library. | ||
| 40 | #ifndef _WIN32 | ||
| 41 |
2/4✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 61 times.
✗ Branch 6 not taken.
|
61 | TempFileImpl(std::ostream& os): mFileDescr(-1) { this->init(os); } |
| 42 | |||
| 43 | 61 | void init(std::ostream& os) | |
| 44 | { | ||
| 45 |
2/4✓ Branch 2 taken 61 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 61 times.
✗ Branch 6 not taken.
|
122 | std::string fn = this->getTempDir() + "/openvdb_temp_XXXXXX"; |
| 46 |
1/2✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
|
61 | std::vector<char> fnbuf(fn.begin(), fn.end()); |
| 47 |
2/6✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 61 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
61 | fnbuf.push_back(char(0)); |
| 48 | |||
| 49 | //const mode_t savedMode = ::umask(~(S_IRUSR | S_IWUSR)); | ||
| 50 |
1/2✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
|
61 | mFileDescr = ::mkstemp(&fnbuf[0]); |
| 51 | //::umask(savedMode); | ||
| 52 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 61 times.
|
61 | if (mFileDescr < 0) { |
| 53 | ✗ | OPENVDB_THROW(IoError, "failed to generate temporary file"); | |
| 54 | } | ||
| 55 | |||
| 56 |
1/2✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
|
61 | mPath.assign(&fnbuf[0]); |
| 57 | |||
| 58 |
1/2✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
|
61 | mDevice = DeviceType(mFileDescr, boost::iostreams::never_close_handle); |
| 59 |
1/2✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
|
61 | mBuffer.open(mDevice); |
| 60 |
1/2✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
|
61 | os.rdbuf(&mBuffer); |
| 61 | |||
| 62 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 61 times.
|
61 | if (!os.good()) { |
| 63 | ✗ | OPENVDB_THROW(IoError, "failed to open temporary file " + mPath); | |
| 64 | } | ||
| 65 | 61 | } | |
| 66 | |||
| 67 |
1/2✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
|
62 | void close() { mBuffer.close(); if (mFileDescr >= 0) ::close(mFileDescr); } |
| 68 | |||
| 69 | 61 | static std::string getTempDir() | |
| 70 | { | ||
| 71 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 61 times.
|
61 | if (const char* dir = std::getenv("OPENVDB_TEMP_DIR")) { |
| 72 | ✗ | if (0 != ::access(dir, F_OK)) { | |
| 73 | #ifdef _WIN32 | ||
| 74 | ::mkdir(dir); | ||
| 75 | #else | ||
| 76 | ✗ | ::mkdir(dir, S_IRUSR | S_IWUSR | S_IXUSR); | |
| 77 | #endif | ||
| 78 | ✗ | if (0 != ::access(dir, F_OK)) { | |
| 79 | ✗ | OPENVDB_THROW(IoError, | |
| 80 | "failed to create OPENVDB_TEMP_DIR (" + std::string(dir) + ")"); | ||
| 81 | } | ||
| 82 | } | ||
| 83 | ✗ | return dir; | |
| 84 | } | ||
| 85 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 61 times.
|
61 | if (const char* dir = std::getenv("TMPDIR")) return dir; |
| 86 | 61 | return P_tmpdir; | |
| 87 | } | ||
| 88 | |||
| 89 | using DeviceType = boost::iostreams::file_descriptor_sink; | ||
| 90 | using BufferType = boost::iostreams::stream_buffer<boost::iostreams::file_descriptor_sink>; | ||
| 91 | |||
| 92 | std::string mPath; | ||
| 93 | DeviceType mDevice; | ||
| 94 | BufferType mBuffer; | ||
| 95 | int mFileDescr; | ||
| 96 | #else // _WIN32 | ||
| 97 | // Use only standard library routines; no POSIX. | ||
| 98 | |||
| 99 | TempFileImpl(std::ostream& os) { this->init(os); } | ||
| 100 | |||
| 101 | void init(std::ostream& os) | ||
| 102 | { | ||
| 103 | char fnbuf[L_tmpnam]; | ||
| 104 | const char* filename = std::tmpnam(fnbuf); | ||
| 105 | if (!filename) { | ||
| 106 | OPENVDB_THROW(IoError, "failed to generate name for temporary file"); | ||
| 107 | } | ||
| 108 | /// @todo This is not safe, since another process could open a file | ||
| 109 | /// with this name before we do. Unfortunately, there is no safe, | ||
| 110 | /// portable way to create a temporary file. | ||
| 111 | mPath = filename; | ||
| 112 | |||
| 113 | const std::ios_base::openmode mode = (std::ios_base::out | std::ios_base::binary); | ||
| 114 | os.rdbuf(mBuffer.open(mPath.c_str(), mode)); | ||
| 115 | if (!os.good()) { | ||
| 116 | OPENVDB_THROW(IoError, "failed to open temporary file " + mPath); | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | void close() { mBuffer.close(); } | ||
| 121 | |||
| 122 | std::string mPath; | ||
| 123 | std::filebuf mBuffer; | ||
| 124 | #endif // _WIN32 | ||
| 125 | |||
| 126 | private: | ||
| 127 | TempFileImpl(const TempFileImpl&); // disable copying | ||
| 128 | TempFileImpl& operator=(const TempFileImpl&); // disable assignment | ||
| 129 | }; | ||
| 130 | |||
| 131 | |||
| 132 |
3/6✓ Branch 2 taken 61 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 61 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 61 times.
✗ Branch 9 not taken.
|
122 | TempFile::TempFile(): std::ostream(nullptr), mImpl(new TempFileImpl(*this)) {} |
| 133 | 128 | TempFile::~TempFile() { this->close(); } | |
| 134 | 61 | const std::string& TempFile::filename() const { return mImpl->filename(); } | |
| 135 | ✗ | bool TempFile::is_open() const { return mImpl->is_open(); } | |
| 136 | 62 | void TempFile::close() { mImpl->close(); } | |
| 137 | |||
| 138 | } // namespace io | ||
| 139 | } // namespace OPENVDB_VERSION_NAME | ||
| 140 | } // namespace openvdb | ||
| 141 |