#include <ctype.h>
#include <errno.h>
-#include <fcntl.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <time.h>
-#include <unistd.h>
-#include <libpspp/alloc.h>
#include <libpspp/float-format.h>
#include <libpspp/integer-format.h>
-#include <libpspp/magic.h>
#include <libpspp/message.h>
#include <libpspp/misc.h>
#include <libpspp/str.h>
#include <data/casewriter.h>
#include <data/dictionary.h>
#include <data/file-handle-def.h>
+#include <data/file-name.h>
#include <data/format.h>
+#include <data/make-file.h>
#include <data/missing-values.h>
#include <data/settings.h>
#include <data/short-names.h>
#include "minmax.h"
#include "unlocked-io.h"
+#include "xalloc.h"
#include "gettext.h"
#define _(msgid) gettext (msgid)
+#define N_(msgid) (msgid)
/* Compression bias used by PSPP. Values between (1 -
COMPRESSION_BIAS) and (251 - COMPRESSION_BIAS) inclusive can be
struct sfm_writer
{
struct file_handle *fh; /* File handle. */
+ struct fh_lock *lock; /* Mutual exclusion for file. */
FILE *file; /* File stream. */
+ struct replace_file *rf; /* Ticket for replacing output file. */
bool compress; /* 1=compressed, 0=not compressed. */
casenumber case_cnt; /* Number of cases written so far. */
for long string variables. */
};
-static struct casewriter_class sys_file_casewriter_class;
+static const struct casewriter_class sys_file_casewriter_class;
static void write_header (struct sfm_writer *, const struct dictionary *);
static void write_variable (struct sfm_writer *, const struct variable *);
{
struct sfm_write_options opts;
opts.create_writeable = true;
- opts.compress = get_scompression ();
+ opts.compress = settings_get_scompression ();
opts.version = 3;
return opts;
}
sfm_open_writer (struct file_handle *fh, struct dictionary *d,
struct sfm_write_options opts)
{
- struct sfm_writer *w = NULL;
+ struct sfm_writer *w;
mode_t mode;
- int fd;
int idx;
int i;
opts.version = 3;
}
- /* Create file. */
- mode = S_IRUSR | S_IRGRP | S_IROTH;
- if (opts.create_writeable)
- mode |= S_IWUSR | S_IWGRP | S_IWOTH;
- fd = open (fh_get_file_name (fh), O_WRONLY | O_CREAT | O_TRUNC, mode);
- if (fd < 0)
- goto open_error;
-
- /* Open file handle. */
- if (!fh_open (fh, FH_REF_FILE, "system file", "we"))
- goto error;
-
/* Create and initialize writer. */
w = xmalloc (sizeof *w);
- w->fh = fh;
- w->file = fdopen (fd, "w");
+ w->fh = fh_ref (fh);
+ w->lock = NULL;
+ w->file = NULL;
+ w->rf = NULL;
w->compress = opts.compress;
w->case_cnt = 0;
w->segment_cnt = sfm_dictionary_to_sfm_vars (d, &w->sfm_vars,
&w->sfm_var_cnt);
- /* Check that file create succeeded. */
- if (w->file == NULL)
+ /* Open file handle as an exclusive writer. */
+ /* TRANSLATORS: this fragment will be interpolated into
+ messages in fh_lock() that identify types of files. */
+ w->lock = fh_lock (fh, FH_REF_FILE, N_("system file"), FH_ACC_WRITE, true);
+ if (w->lock == NULL)
+ goto error;
+
+ /* Create the file on disk. */
+ mode = S_IRUSR | S_IRGRP | S_IROTH;
+ if (opts.create_writeable)
+ mode |= S_IWUSR | S_IWGRP | S_IWOTH;
+ w->rf = replace_file_start (fh_get_file_name (fh), "wb", mode,
+ &w->file, NULL);
+ if (w->rf == NULL)
{
- close (fd);
- goto open_error;
+ msg (ME, _("Error opening \"%s\" for writing as a system file: %s."),
+ fh_get_file_name (fh), strerror (errno));
+ goto error;
}
/* Write the file header. */
write_int (w, 0);
if (write_error (w))
- goto error;
+ {
+ close_writer (w);
+ return NULL;
+ }
- return casewriter_create (&sys_file_casewriter_class, w);
+ return casewriter_create (dict_get_next_value_idx (d),
+ &sys_file_casewriter_class, w);
- error:
+error:
close_writer (w);
return NULL;
-
- open_error:
- msg (ME, _("Error opening \"%s\" for writing as a system file: %s."),
- fh_get_file_name (fh), strerror (errno));
- goto error;
}
/* Returns value of X truncated to two least-significant digits. */
}
else
{
- static const char *month_name[12] =
+ static const char *const month_name[12] =
{
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
/* Number of missing values. If there is a range, then the
range counts as 2 missing values and causes the number to be
negated. */
- write_int (w, mv_has_range (mv) ? 2 - mv_n_values (mv) : mv_n_values (mv));
+ write_int (w, mv_has_range (mv) ? -2 - mv_n_values (mv) : mv_n_values (mv));
/* Print and write formats. */
write_format (w, *var_get_print_format (v), seg0_width);
if (mv_has_range (mv))
{
double x, y;
- mv_peek_range (mv, &x, &y);
+ mv_get_range (mv, &x, &y);
write_float (w, x);
write_float (w, y);
}
for (i = 0; i < mv_n_values (mv); i++)
{
union value value;
- mv_peek_value (mv, &value, i);
+ mv_get_value (mv, &value, i);
write_value (w, &value, seg0_width);
}
if (!ok)
msg (ME, _("An I/O error occurred writing system file \"%s\"."),
fh_get_file_name (w->fh));
+
+ if (ok ? !replace_file_commit (w->rf) : !replace_file_abort (w->rf))
+ ok = false;
}
- fh_close (w->fh, "system file", "we");
+ fh_unlock (w->lock);
+ fh_unref (w->fh);
free (w->sfm_vars);
free (w);
}
/* System file writer casewriter class. */
-static struct casewriter_class sys_file_casewriter_class =
+static const struct casewriter_class sys_file_casewriter_class =
{
sys_file_casewriter_write,
sys_file_casewriter_destroy,