1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2004 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
27 #include <data/file-name.h>
28 #include <data/make-file.h>
29 #include <libpspp/ll.h>
30 #include <libpspp/message.h>
32 #include "fatal-signal.h"
37 #define _(msgid) gettext (msgid)
39 /* Non ansi compilers may set this */
41 #define P_tmpdir "/tmp"
44 /* Creates a temporary file and stores its name in *FILE_NAME and
45 a file descriptor for it in *FD. Returns success. Caller is
46 responsible for freeing *FILE_NAME. */
48 make_temp_file (int *fd, char **file_name)
50 const char *parent_dir;
52 assert (file_name != NULL);
55 if (getenv ("TMPDIR") != NULL)
56 parent_dir = getenv ("TMPDIR");
58 parent_dir = P_tmpdir;
60 *file_name = xmalloc (strlen (parent_dir) + 32);
61 sprintf (*file_name, "%s/psppXXXXXX", parent_dir);
62 *fd = mkstemp (*file_name);
65 msg (ME, _("%s: Creating temporary file: %s."),
66 *file_name, strerror (errno));
75 /* Creates a temporary file and stores its name in *FILE_NAME and
76 a file stream for it in *FP. Returns success. Caller is
77 responsible for freeing *FILE_NAME and for closing *FP */
79 make_unique_file_stream (FILE **fp, char **file_name)
81 static int serial = 0;
82 const char *parent_dir;
86 Need to check for pre-existing file name.
87 Need also to pass in the directory instead of using /tmp
90 assert (file_name != NULL);
93 if (getenv ("TMPDIR") != NULL)
94 parent_dir = getenv ("TMPDIR");
96 parent_dir = P_tmpdir;
98 *file_name = xmalloc (strlen (parent_dir) + 32);
101 sprintf (*file_name, "%s/pspp%d.png", parent_dir, serial++);
103 *fp = fopen(*file_name, "w");
107 msg (ME, _("%s: Creating file: %s."), *file_name, strerror (errno));
123 static struct ll_list all_files = LL_INITIALIZER (all_files);
125 static void free_replace_file (struct replace_file *);
126 static void unlink_replace_files (void);
128 struct replace_file *
129 replace_file_start (const char *file_name, const char *mode,
130 mode_t permissions, FILE **fp, char **tmp_name)
132 static bool registered;
134 struct replace_file *rf;
137 /* If FILE_NAME represents a special file, write to it directly
138 instead of trying to replace it. */
139 if (stat (file_name, &s) == 0 && !S_ISREG (s.st_mode))
141 /* Open file descriptor. */
142 fd = open (file_name, O_WRONLY);
145 msg (ME, _("Opening %s for writing: %s."),
146 file_name, strerror (errno));
150 /* Open file as stream. */
151 *fp = fdopen (fd, mode);
154 msg (ME, _("Opening stream for %s: %s."),
155 file_name, strerror (errno));
160 rf = xmalloc (sizeof *rf);
161 rf->file_name = NULL;
162 rf->tmp_name = xstrdup (file_name);
163 if (tmp_name != NULL)
164 *tmp_name = rf->tmp_name;
170 at_fatal_signal (unlink_replace_files);
173 block_fatal_signals ();
175 rf = xmalloc (sizeof *rf);
176 rf->file_name = xstrdup (file_name);
179 /* Generate unique temporary file name. */
180 rf->tmp_name = xasprintf ("%s.tmpXXXXXX", file_name);
181 if (gen_tempname (rf->tmp_name, 0, 0600, GT_NOCREATE) < 0)
183 msg (ME, _("Creating temporary file to replace %s: %s."),
184 rf->file_name, strerror (errno));
188 /* Create file by that name. */
189 fd = open (rf->tmp_name, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, permissions);
194 msg (ME, _("Creating temporary file %s: %s."),
195 rf->tmp_name, strerror (errno));
202 /* Open file as stream. */
203 *fp = fdopen (fd, mode);
206 msg (ME, _("Opening stream for temporary file %s: %s."),
207 rf->tmp_name, strerror (errno));
209 unlink (rf->tmp_name);
213 /* Register file for deletion. */
214 ll_push_head (&all_files, &rf->ll);
215 unblock_fatal_signals ();
217 if (tmp_name != NULL)
218 *tmp_name = rf->tmp_name;
223 unblock_fatal_signals ();
224 free_replace_file (rf);
226 if (tmp_name != NULL)
232 replace_file_commit (struct replace_file *rf)
236 if (rf->file_name != NULL)
240 block_fatal_signals ();
241 ok = rename (rf->tmp_name, rf->file_name) == 0;
244 unblock_fatal_signals ();
247 msg (ME, _("Replacing %s by %s: %s."),
248 rf->tmp_name, rf->file_name, strerror (save_errno));
252 /* Special file: no temporary file to rename. */
254 free_replace_file (rf);
260 replace_file_abort (struct replace_file *rf)
264 if (rf->file_name != NULL)
268 block_fatal_signals ();
269 ok = unlink (rf->tmp_name) == 0;
272 unblock_fatal_signals ();
275 msg (ME, _("Removing %s: %s."), rf->tmp_name, strerror (save_errno));
279 /* Special file: no temporary file to unlink. */
281 free_replace_file (rf);
287 free_replace_file (struct replace_file *rf)
289 free (rf->file_name);
295 unlink_replace_files (void)
297 struct replace_file *rf;
299 block_fatal_signals ();
300 ll_for_each (rf, struct replace_file, ll, &all_files)
302 /* We don't free_replace_file(RF) because calling free is unsafe
303 from an asynchronous signal handler. */
304 unlink (rf->tmp_name);
307 unblock_fatal_signals ();