bes  Updated for version 3.20.8
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 
44 using namespace std;
45 
46 namespace bes {
47 
48 std::map<string, int> *TempFile::open_files = new std::map<string, int>;
49 struct sigaction TempFile::cached_sigpipe_handler;
50 
56 void TempFile::sigpipe_handler(int sig)
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 
84 TempFile::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
static void sigpipe_handler(int signal)
Definition: TempFile.cc:56