bes  Updated for version 3.20.6
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 <sys/stat.h>
26 #include <unistd.h>
27 #include <signal.h>
28 #include <sys/wait.h> // for wait
29 
30 #include <cstdlib>
31 #include <cstring>
32 #include <cerrno>
33 #include <vector>
34 #include <string>
35 
36 #include <BESInternalError.h>
37 #include <BESInternalFatalError.h>
38 
39 #include "TempFile.h"
40 #include "BESLog.h"
41 
42 using namespace std;
43 
44 namespace bes {
45 
46 std::map<string, int> *TempFile::open_files = new std::map<string, int>;
47 struct sigaction TempFile::cached_sigpipe_handler;
48 
54 void TempFile::sigpipe_handler(int sig)
55 {
56  if (sig == SIGPIPE) {
57  std::map<string, int>::iterator it;
58  for (it = open_files->begin(); it != open_files->end(); ++it) {
59  if (unlink((it->first).c_str()) == -1)
60  ERROR(string("Error unlinking temporary file: '").append(it->first).append("': ").append(strerror(errno)).append("\n"));
61  }
62  // Files cleaned up? Sweet! Time to bail...
63  sigaction(SIGPIPE, &cached_sigpipe_handler, 0);
64  // signal(SIGPIPE, SIG_DFL);
65  raise(SIGPIPE);
66  }
67 }
68 
82 TempFile::TempFile(const std::string &path_template, bool keep_temps)
83  : d_keep_temps(keep_temps)
84 {
85  char tmp_name[path_template.length() + 1];
86  std::string::size_type len = path_template.copy(tmp_name, path_template.length());
87  tmp_name[len] = '\0';
88 
89  // cover the case where older versions of mkstemp() create the file using
90  // a mode of 666.
91  mode_t original_mode = umask(077);
92  d_fd = mkstemp(tmp_name);
93  umask(original_mode);
94 
95  if (d_fd == -1) throw BESInternalError("Failed to open the temporary file.", __FILE__, __LINE__);
96 
97  d_fname.assign(tmp_name);
98 
99  // only register the SIGPIPE handler once. First time, size() is zero.
100  if (open_files->size() == 0) {
101  struct sigaction act;
102  sigemptyset(&act.sa_mask);
103  sigaddset(&act.sa_mask, SIGPIPE);
104  act.sa_flags = 0;
105 
106  act.sa_handler = bes::TempFile::sigpipe_handler;
107 
108  if (sigaction(SIGPIPE, &act, &cached_sigpipe_handler)) {
109  throw BESInternalFatalError("Could not register a handler to catch SIGPIPE.", __FILE__, __LINE__);
110  }
111  }
112 
113  open_files->insert(std::pair<string, int>(d_fname, d_fd));
114 }
115 
122 {
123  try {
124  if (close(d_fd) == -1) {
125  ERROR(string("Error closing temporary file: '").append(d_fname).append("': ").append(strerror(errno)).append("\n"));
126  }
127  if (!d_keep_temps) {
128  if (unlink(d_fname.c_str()) == -1) {
129  ERROR(string("Error unlinking temporary file: '").append(d_fname).append("': ").append(strerror(errno)).append("\n"));
130  }
131  }
132  }
133  catch (BESError &e) {
134  // This protects against BESLog (i.e., ERROR) throwing an exception.
135  // If BESLog has failed, we cannot log the error, punt and write to stderr.
136  cerr << "Could not close temporary file '" << d_fname << "' due to an error in BESlog (" << e.get_verbose_message() << ").";
137  }
138  catch (...) {
139  cerr << "Could not close temporary file '" << d_fname << "' due to an error in BESlog.";
140  }
141 
142  open_files->erase(d_fname);
143 
144  if (open_files->size() == 0) {
145  if (sigaction(SIGPIPE, &cached_sigpipe_handler, 0)) {
146  ERROR(string("Could not register a handler to catch SIGPIPE. ").append("(").append(strerror(errno)).append(")"));
147  }
148  }
149 }
150 
151 } // namespace bes
152 
BESInternalFatalError
exception thrown if an internal error is found and is fatal to the BES
Definition: BESInternalFatalError.h:43
bes::TempFile::~TempFile
~TempFile()
Free the temporary file.
Definition: TempFile.cc:121
BESInternalError
exception thrown if internal error encountered
Definition: BESInternalError.h:43
bes::TempFile::sigpipe_handler
static void sigpipe_handler(int signal)
Definition: TempFile.cc:54
BESError
Abstract exception class for the BES with basic string message.
Definition: BESError.h:58