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 |