1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2007, 2009 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.
202 Returns the case if successful or a null pointer if CTF is
203 tainted or an I/O 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)
210 struct ccase *c = case_create (ctf->value_cnt);
211 if (case_tmpfile_get_values (ctf, case_idx, 0,
212 case_data_all_rw (c), ctf->value_cnt))
221 /* Writes VALUE_CNT values from VALUES, into the case numbered
222 CASE_IDX starting START_VALUE values into that case.
223 Returns true if successful, false if CTF is tainted or an I/O
224 error occurs during the operation. */
226 case_tmpfile_put_values (struct case_tmpfile *ctf,
227 casenumber case_idx, size_t start_value,
228 const union value values[], size_t value_cnt)
231 assert (value_cnt <= ctf->value_cnt);
232 assert (value_cnt + start_value <= ctf->value_cnt);
234 return (do_seek (ctf, case_idx, start_value)
235 && do_write (ctf, sizeof *values * value_cnt, values));
238 /* Writes C to CTF as the case numbered CASE_IDX.
239 Returns true if successful, false if CTF is tainted or an I/O
240 error occurs during the operation. */
242 case_tmpfile_put_case (struct case_tmpfile *ctf, casenumber case_idx,
245 bool ok = case_tmpfile_put_values (ctf, case_idx, 0,
246 case_data_all (c), ctf->value_cnt);