GCC Code Coverage Report


Directory: ./
File: openvdb/openvdb/io/TempFile.cc
Date: 2022-07-25 17:40:05
Exec Total Coverage
Lines: 23 31 74.2%
Functions: 8 9 88.9%
Branches: 20 72 27.8%

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