1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2007 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/>. */
19 #include <data/case-tmpfile.h>
25 #include <libpspp/assertion.h>
26 #include <libpspp/taint.h>
32 #define _(msgid) gettext (msgid)
34 /* A temporary file that stores an array of cases. */
37 struct taint *taint; /* Taint. */
38 FILE *file; /* Underlying file. */
39 size_t value_cnt; /* Number of `union value's per case. */
41 /* Current byte offset in file. We track this manually,
42 instead of using ftello, because in glibc ftello flushes
43 the stream buffer, making the common case of sequential
44 access to cases unreasonably slow. */
48 /* Creates and returns a new case_tmpfile. */
50 case_tmpfile_create (size_t value_cnt)
52 struct case_tmpfile *ctf = xmalloc (sizeof *ctf);
53 ctf->taint = taint_create ();
54 ctf->file = tmpfile ();
55 if (ctf->file == NULL)
57 error (0, errno, _("failed to create temporary file"));
58 taint_set_taint (ctf->taint);
60 ctf->value_cnt = value_cnt;
65 /* Destroys case_tmpfile CTF.
66 Returns true if CTF was tainted, which is caused by an I/O
67 error on case_tmpfile access or by taint propagation to the
70 case_tmpfile_destroy (struct case_tmpfile *ctf)
75 struct taint *taint = ctf->taint;
76 if (ctf->file != NULL)
79 ok = taint_destroy (taint);
84 /* Returns true if CTF is tainted, which is caused by an I/O
85 error on case_tmpfile access or by taint propagation to the
88 case_tmpfile_error (const struct case_tmpfile *ctf)
90 return taint_is_tainted (ctf->taint);
93 /* Marks CTF as tainted. */
95 case_tmpfile_force_error (struct case_tmpfile *ctf)
97 taint_set_taint (ctf->taint);
100 /* Returns CTF's taint object. */
102 case_tmpfile_get_taint (const struct case_tmpfile *ctf)
107 /* Seeks CTF's underlying file to the start of `union value'
108 VALUE_IDX within case CASE_IDX.
109 Returns true if the seek is successful and CTF is not
110 otherwise tainted, false otherwise. */
112 do_seek (const struct case_tmpfile *ctf_,
113 casenumber case_idx, size_t value_idx)
115 struct case_tmpfile *ctf = (struct case_tmpfile *) ctf_;
117 if (!case_tmpfile_error (ctf))
119 off_t value_ofs = value_idx + (off_t) ctf->value_cnt * case_idx;
120 off_t byte_ofs = sizeof (union value) * value_ofs;
122 if (ctf->position == byte_ofs)
124 else if (fseeko (ctf->file, byte_ofs, SEEK_SET) == 0)
126 ctf->position = byte_ofs;
131 error (0, errno, _("seeking in temporary file"));
132 case_tmpfile_force_error (ctf);
139 /* Reads BYTES bytes from CTF's underlying file into BUFFER.
140 CTF must not be tainted upon entry into this function.
141 Returns true if successful, false upon an I/O error (in which
142 case CTF is marked tainted). */
144 do_read (const struct case_tmpfile *ctf_, size_t bytes, void *buffer)
146 struct case_tmpfile *ctf = (struct case_tmpfile *) ctf_;
148 assert (!case_tmpfile_error (ctf));
149 if (fread (buffer, bytes, 1, ctf->file) != 1)
151 case_tmpfile_force_error (ctf);
152 if (ferror (ctf->file))
153 error (0, errno, _("reading temporary file"));
154 else if (feof (ctf->file))
155 error (0, 0, _("unexpected end of file reading temporary file"));
160 ctf->position += bytes;
164 /* Writes BYTES bytes from BUFFER into CTF's underlying file.
165 CTF must not be tainted upon entry into this function.
166 Returns true if successful, false upon an I/O error (in which
167 case CTF is marked tainted). */
169 do_write (struct case_tmpfile *ctf, size_t bytes, const void *buffer)
171 assert (!case_tmpfile_error (ctf));
172 if (fwrite (buffer, bytes, 1, ctf->file) != 1)
174 case_tmpfile_force_error (ctf);
175 error (0, errno, _("writing to temporary file"));
178 ctf->position += bytes;
182 /* Reads VALUE_CNT values into VALUES, from the case numbered
183 CASE_IDX starting START_VALUE values into that case.
184 Returns true if successful, false if CTF is tainted or an I/O
185 error occurs during the operation.
187 The results of this function are undefined if any of the
188 values read have not been previously written to CTF. */
190 case_tmpfile_get_values (const struct case_tmpfile *ctf,
191 casenumber case_idx, size_t start_value,
192 union value values[], size_t value_cnt)
194 assert (value_cnt <= ctf->value_cnt);
195 assert (value_cnt + start_value <= ctf->value_cnt);
197 return (do_seek (ctf, case_idx, start_value)
198 && do_read (ctf, sizeof *values * value_cnt, values));
201 /* Reads the case numbered CASE_IDX from CTF into C.
202 Returns true if successful, false if CTF is tainted or an I/O
203 error occurs during the operation.
205 The results of this function are undefined if the case read
206 from CTF had not previously been written. */
208 case_tmpfile_get_case (const struct case_tmpfile *ctf, casenumber case_idx,
211 case_create (c, ctf->value_cnt);
212 if (case_tmpfile_get_values (ctf, case_idx, 0,
213 case_data_all_rw (c), ctf->value_cnt))
223 /* Writes VALUE_CNT values from VALUES, into the case numbered
224 CASE_IDX starting START_VALUE values into that case.
225 Returns true if successful, false if CTF is tainted or an I/O
226 error occurs during the operation. */
228 case_tmpfile_put_values (struct case_tmpfile *ctf,
229 casenumber case_idx, size_t start_value,
230 const union value values[], size_t value_cnt)
233 assert (value_cnt <= ctf->value_cnt);
234 assert (value_cnt + start_value <= ctf->value_cnt);
236 return (do_seek (ctf, case_idx, start_value)
237 && do_write (ctf, sizeof *values * value_cnt, values));
240 /* Writes C to CTF as the case numbered CASE_IDX.
241 Returns true if successful, false if CTF is tainted or an I/O
242 error occurs during the operation. */
244 case_tmpfile_put_case (struct case_tmpfile *ctf, casenumber case_idx,
247 bool ok = case_tmpfile_put_values (ctf, case_idx, 0,
248 case_data_all (c), ctf->value_cnt);