bes Updated for version 3.20.10
TempFile.cc
1// -*- mode: c++; c-basic-offset:4 -*-
2
3// This file is part of the BES, A C++ implementation of the OPeNDAP Data
4// Access Protocol.
5
6// Copyright (c) 2018 OPeNDAP, Inc.
7// Author: Nathan Potter <ndp@opendap.org>
8//
9// This library is free software; you can redistribute it and/or
10// modify it under the terms of the GNU Lesser General Public
11// License as published by the Free Software Foundation; either
12// version 2.1 of the License, or (at your option) any later version.
13//
14// This library is distributed in the hope that it will be useful,
15// but WITHOUT ANY WARRANTY; without even the implied warranty of
16// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17// Lesser General Public License for more details.
18//
19// You should have received a copy of the GNU Lesser General Public
20// License along with this library; if not, write to the Free Software
21// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22//
23// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
24
25#include "config.h"
26
27#include <sys/stat.h>
28#include <unistd.h>
29#include <signal.h>
30#include <sys/wait.h> // for wait
31
32#include <cstdlib>
33#include <cstring>
34#include <cerrno>
35#include <vector>
36#include <string>
37
38#include <BESInternalError.h>
39#include <BESInternalFatalError.h>
40
41#include "TempFile.h"
42#include "BESLog.h"
43
44using namespace std;
45
46namespace bes {
47
48std::map<string, int> *TempFile::open_files = new std::map<string, int>;
49struct sigaction TempFile::cached_sigpipe_handler;
50
57{
58 if (sig == SIGPIPE) {
59 std::map<string, int>::iterator it;
60 for (it = open_files->begin(); it != open_files->end(); ++it) {
61 if (unlink((it->first).c_str()) == -1)
62 ERROR_LOG(string("Error unlinking temporary file: '").append(it->first).append("': ").append(strerror(errno)).append("\n"));
63 }
64 // Files cleaned up? Sweet! Time to bail...
65 sigaction(SIGPIPE, &cached_sigpipe_handler, 0);
66 // signal(SIGPIPE, SIG_DFL);
67 raise(SIGPIPE);
68 }
69}
70
84TempFile::TempFile(const std::string &path_template, bool keep_temps)
85 : d_keep_temps(keep_temps)
86{
87 char tmp_name[path_template.length() + 1];
88 std::string::size_type len = path_template.copy(tmp_name, path_template.length());
89 tmp_name[len] = '\0';
90
91 // cover the case where older versions of mkstemp() create the file using
92 // a mode of 666.
93 mode_t original_mode = umask(077);
94 d_fd = mkstemp(tmp_name);
95 umask(original_mode);
96
97 if (d_fd == -1) throw BESInternalError("Failed to open the temporary file.", __FILE__, __LINE__);
98
99 d_fname.assign(tmp_name);
100
101 // only register the SIGPIPE handler once. First time, size() is zero.
102 if (open_files->size() == 0) {
103 struct sigaction act;
104 sigemptyset(&act.sa_mask);
105 sigaddset(&act.sa_mask, SIGPIPE);
106 act.sa_flags = 0;
107
108 act.sa_handler = bes::TempFile::sigpipe_handler;
109
110 if (sigaction(SIGPIPE, &act, &cached_sigpipe_handler)) {
111 throw BESInternalFatalError("Could not register a handler to catch SIGPIPE.", __FILE__, __LINE__);
112 }
113 }
114
115 open_files->insert(std::pair<string, int>(d_fname, d_fd));
116}
117
124{
125 try {
126 if (close(d_fd) == -1) {
127 ERROR_LOG(string("Error closing temporary file: '").append(d_fname).append("': ").append(strerror(errno)).append("\n"));
128 }
129 if (!d_keep_temps) {
130 if (unlink(d_fname.c_str()) == -1) {
131 ERROR_LOG(string("Error unlinking temporary file: '").append(d_fname).append("': ").append(strerror(errno)).append("\n"));
132 }
133 }
134 }
135 catch (BESError &e) {
136 // This protects against BESLog (i.e., ERROR) throwing an exception.
137 // If BESLog has failed, we cannot log the error, punt and write to stderr.
138 cerr << "Could not close temporary file '" << d_fname << "' due to an error in BESlog (" << e.get_verbose_message() << ").";
139 }
140 catch (...) {
141 cerr << "Could not close temporary file '" << d_fname << "' due to an error in BESlog.";
142 }
143
144 open_files->erase(d_fname);
145
146 if (open_files->size() == 0) {
147 if (sigaction(SIGPIPE, &cached_sigpipe_handler, 0)) {
148 ERROR_LOG(string("Could not register a handler to catch SIGPIPE. ").append("(").append(strerror(errno)).append(")"));
149 }
150 }
151}
152
153} // namespace bes
154
Abstract exception class for the BES with basic string message.
Definition: BESError.h:58
exception thrown if internal error encountered
exception thrown if an internal error is found and is fatal to the BES
~TempFile()
Free the temporary file.
Definition: TempFile.cc:123
TempFile(const std::string &path_template=default_tmp_file_template, bool keep_temps=false)
Get a new temporary file.
Definition: TempFile.cc:84
static void sigpipe_handler(int signal)
Definition: TempFile.cc:56