63b0fcd3b692ba41e06dd1a0ad6086918c3e1f63
[pspp-builds.git] / src / data / casefile.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 2004 Free Software Foundation, Inc.
3    Written by Ben Pfaff <blp@gnu.org>.
4
5    This program is free software; you can redistribute it and/or
6    modify it under the terms of the GNU General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18    02110-1301, USA. */
19
20 #include <config.h>
21 #include "casefile.h"
22 #include <assert.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include "alloc.h"
30 #include "case.h"
31 #include "message.h"
32 #include "full-read.h"
33 #include "full-write.h"
34 #include "misc.h"
35 #include "make-file.h"
36 #include "settings.h"
37 #include "variable.h"
38
39 #include "gettext.h"
40 #define _(msgid) gettext (msgid)
41
42 #define IO_BUF_SIZE (8192 / sizeof (union value))
43
44 /* A casefile represents a sequentially accessible stream of
45    immutable cases.
46
47    If workspace allows, a casefile is maintained in memory.  If
48    workspace overflows, then the casefile is pushed to disk.  In
49    either case the interface presented to callers is kept the
50    same.
51
52    The life cycle of a casefile consists of up to three phases:
53
54        1. Writing.  The casefile initially contains no cases.  In
55           this phase, any number of cases may be appended to the
56           end of a casefile.  (Cases are never inserted in the
57           middle or before the beginning of a casefile.)
58
59           Use casefile_append() or casefile_append_xfer() to
60           append a case to a casefile.
61
62        2. Reading.  The casefile may be read sequentially,
63           starting from the beginning, by "casereaders".  Any
64           number of casereaders may be created, at any time,
65           during the reading phase.  Each casereader has an
66           independent position in the casefile.
67
68           Casereaders may only move forward.  They cannot move
69           backward to arbitrary records or seek randomly.
70           Cloning casereaders is possible, but it is not yet
71           implemented.
72
73           Use casefile_get_reader() to create a casereader for
74           use in phase 2.  This also transitions from phase 1 to
75           phase 2.  Calling casefile_mode_reader() makes the same
76           transition, without creating a casereader.
77
78           Use casereader_read() or casereader_read_xfer() to read
79           a case from a casereader.  Use casereader_destroy() to
80           discard a casereader when it is no longer needed.
81
82        3. Destruction.  This phase is optional.  The casefile is
83           also read with casereaders in this phase, but the
84           ability to create new casereaders is curtailed.
85
86           In this phase, casereaders could still be cloned (once
87           we eventually implement cloning).
88
89           To transition from phase 1 or 2 to phase 3 and create a
90           casereader, call casefile_get_destructive_reader().
91           The same functions apply to the casereader obtained
92           this way as apply to casereaders obtained in phase 2.
93           
94           After casefile_get_destructive_reader() is called, no
95           more casereaders may be created with
96           casefile_get_reader() or
97           casefile_get_destructive_reader().  (If cloning of
98           casereaders were implemented, it would still be
99           possible.)
100
101           The purpose of the limitations applied to casereaders
102           in phase 3 is to allow in-memory casefiles to fully
103           transfer ownership of cases to the casereaders,
104           avoiding the need for extra copies of case data.  For
105           relatively static data sets with many variables, I
106           suspect (without evidence) that this may be a big
107           performance boost.
108
109    When a casefile is no longer needed, it may be destroyed with
110    casefile_destroy().  This function will also destroy any
111    remaining casereaders. */
112
113 /* In-memory cases are arranged in an array of arrays.  The top
114    level is variable size and the size of each bottom level array
115    is fixed at the number of cases defined here.  */
116 #define CASES_PER_BLOCK 128             
117
118 /* A casefile. */
119 struct casefile 
120   {
121     /* Basic data. */
122     struct casefile *next, *prev;       /* Next, prev in global list. */
123     size_t value_cnt;                   /* Case size in `union value's. */
124     size_t case_acct_size;              /* Case size for accounting. */
125     unsigned long case_cnt;             /* Number of cases stored. */
126     enum { MEMORY, DISK } storage;      /* Where cases are stored. */
127     enum { WRITE, READ } mode;          /* Is writing or reading allowed? */
128     struct casereader *readers;         /* List of our readers. */
129     int being_destroyed;                /* Does a destructive reader exist? */
130     bool ok;                            /* False after I/O error. */
131
132     /* Memory storage. */
133     struct ccase **cases;               /* Pointer to array of cases. */
134
135     /* Disk storage. */
136     int fd;                             /* File descriptor, -1 if none. */
137     char *filename;                     /* Filename. */
138     union value *buffer;                /* I/O buffer, NULL if none. */
139     size_t buffer_used;                 /* Number of values used in buffer. */
140     size_t buffer_size;                 /* Buffer size in values. */
141   };
142
143 /* For reading out the cases in a casefile. */
144 struct casereader 
145   {
146     struct casereader *next, *prev;     /* Next, prev in casefile's list. */
147     struct casefile *cf;                /* Our casefile. */
148     unsigned long case_idx;             /* Case number of current case. */
149     int destructive;                    /* Is this a destructive reader? */
150
151     /* Disk storage. */
152     int fd;                             /* File descriptor. */
153     union value *buffer;                /* I/O buffer. */
154     size_t buffer_pos;                  /* Offset of buffer position. */
155     struct ccase c;                     /* Current case. */
156   };
157
158 /* Return the case number of the current case */
159 unsigned long
160 casereader_cnum(const struct casereader *r)
161 {
162   return r->case_idx;
163 }
164
165 /* Doubly linked list of all casefiles. */
166 static struct casefile *casefiles;
167
168 /* Number of bytes of case allocated in in-memory casefiles. */
169 static size_t case_bytes;
170
171 static void register_atexit (void);
172 static void exit_handler (void);
173
174 static void reader_open_file (struct casereader *reader);
175 static void write_case_to_disk (struct casefile *cf, const struct ccase *c);
176 static void flush_buffer (struct casefile *cf);
177 static bool fill_buffer (struct casereader *reader);
178
179 static void io_error (struct casefile *, const char *, ...)
180      PRINTF_FORMAT (2, 3);
181 static int safe_open (const char *filename, int flags);
182 static int safe_close (int fd);
183
184 /* Creates and returns a casefile to store cases of VALUE_CNT
185    `union value's each. */
186 struct casefile *
187 casefile_create (size_t value_cnt) 
188 {
189   struct casefile *cf = xmalloc (sizeof *cf);
190   cf->next = casefiles;
191   cf->prev = NULL;
192   if (cf->next != NULL)
193     cf->next->prev = cf;
194   casefiles = cf;
195   cf->value_cnt = value_cnt;
196   cf->case_acct_size = (cf->value_cnt + 4) * sizeof *cf->buffer;
197   cf->case_cnt = 0;
198   cf->storage = MEMORY;
199   cf->mode = WRITE;
200   cf->readers = NULL;
201   cf->being_destroyed = 0;
202   cf->ok = true;
203   cf->cases = NULL;
204   cf->fd = -1;
205   cf->filename = NULL;
206   cf->buffer = NULL;
207   cf->buffer_size = ROUND_UP (cf->value_cnt, IO_BUF_SIZE);
208   if (cf->value_cnt > 0 && cf->buffer_size % cf->value_cnt > 64)
209     cf->buffer_size = cf->value_cnt;
210   cf->buffer_used = 0;
211   register_atexit ();
212   return cf;
213 }
214
215 /* Destroys casefile CF. */
216 void
217 casefile_destroy (struct casefile *cf) 
218 {
219   if (cf != NULL) 
220     {
221       if (cf->next != NULL)
222         cf->next->prev = cf->prev;
223       if (cf->prev != NULL)
224         cf->prev->next = cf->next;
225       if (casefiles == cf)
226         casefiles = cf->next;
227
228       while (cf->readers != NULL) 
229         casereader_destroy (cf->readers);
230
231       if (cf->cases != NULL) 
232         {
233           size_t idx, block_cnt;
234
235           case_bytes -= cf->case_cnt * cf->case_acct_size;
236           for (idx = 0; idx < cf->case_cnt; idx++)
237             {
238               size_t block_idx = idx / CASES_PER_BLOCK;
239               size_t case_idx = idx % CASES_PER_BLOCK;
240               struct ccase *c = &cf->cases[block_idx][case_idx];
241               case_destroy (c);
242             }
243
244           block_cnt = DIV_RND_UP (cf->case_cnt, CASES_PER_BLOCK);
245           for (idx = 0; idx < block_cnt; idx++)
246             free (cf->cases[idx]);
247
248           free (cf->cases);
249         }
250
251       if (cf->fd != -1)
252         safe_close (cf->fd);
253           
254       if (cf->filename != NULL && remove (cf->filename) == -1) 
255         io_error (cf, _("%s: Removing temporary file: %s."),
256                   cf->filename, strerror (errno));
257       free (cf->filename);
258
259       free (cf->buffer);
260
261       free (cf);
262     }
263 }
264
265 /* Returns true if an I/O error has occurred in casefile CF. */
266 bool
267 casefile_error (const struct casefile *cf) 
268 {
269   return !cf->ok;
270 }
271
272 /* Returns nonzero only if casefile CF is stored in memory (instead of on
273    disk). */
274 int
275 casefile_in_core (const struct casefile *cf) 
276 {
277   assert (cf != NULL);
278
279   return cf->storage == MEMORY;
280 }
281
282 /* Puts a casefile to "sleep", that is, minimizes the resources
283    needed for it by closing its file descriptor and freeing its
284    buffer.  This is useful if we need so many casefiles that we
285    might not have enough memory and file descriptors to go
286    around.
287
288    For simplicity, this implementation always converts the
289    casefile to reader mode.  If this turns out to be a problem,
290    with a little extra work we could also support sleeping
291    writers.
292
293    Returns true if successful, false if an I/O error occurred. */
294 bool
295 casefile_sleep (const struct casefile *cf_) 
296 {
297   struct casefile *cf = (struct casefile *) cf_;
298   assert (cf != NULL);
299
300   casefile_mode_reader (cf);
301   casefile_to_disk (cf);
302   flush_buffer (cf);
303
304   if (cf->fd != -1) 
305     {
306       safe_close (cf->fd);
307       cf->fd = -1;
308     }
309   if (cf->buffer != NULL) 
310     {
311       free (cf->buffer);
312       cf->buffer = NULL;
313     }
314
315   return cf->ok;
316 }
317
318 /* Returns the number of `union value's in a case for CF. */
319 size_t
320 casefile_get_value_cnt (const struct casefile *cf) 
321 {
322   assert (cf != NULL);
323
324   return cf->value_cnt;
325 }
326
327 /* Returns the number of cases in casefile CF. */
328 unsigned long
329 casefile_get_case_cnt (const struct casefile *cf) 
330 {
331   assert (cf != NULL);
332
333   return cf->case_cnt;
334 }
335
336 /* Appends a copy of case C to casefile CF.  Not valid after any
337    reader for CF has been created.
338    Returns true if successful, false if an I/O error occurred. */
339 bool
340 casefile_append (struct casefile *cf, const struct ccase *c) 
341 {
342   assert (cf != NULL);
343   assert (c != NULL);
344   assert (cf->mode == WRITE);
345
346   /* Try memory first. */
347   if (cf->storage == MEMORY) 
348     {
349       if (case_bytes < get_workspace ())
350         {
351           size_t block_idx = cf->case_cnt / CASES_PER_BLOCK;
352           size_t case_idx = cf->case_cnt % CASES_PER_BLOCK;
353           struct ccase new_case;
354
355           case_bytes += cf->case_acct_size;
356           case_clone (&new_case, c);
357           if (case_idx == 0) 
358             {
359               if ((block_idx & (block_idx - 1)) == 0) 
360                 {
361                   size_t block_cap = block_idx == 0 ? 1 : block_idx * 2;
362                   cf->cases = xnrealloc (cf->cases,
363                                          block_cap, sizeof *cf->cases);
364                 }
365
366               cf->cases[block_idx] = xnmalloc (CASES_PER_BLOCK,
367                                                sizeof **cf->cases);
368             }
369
370           case_move (&cf->cases[block_idx][case_idx], &new_case);
371         }
372       else
373         {
374           casefile_to_disk (cf);
375           assert (cf->storage == DISK);
376           write_case_to_disk (cf, c);
377         }
378     }
379   else
380     write_case_to_disk (cf, c);
381
382   cf->case_cnt++;
383   return cf->ok;
384 }
385
386 /* Appends case C to casefile CF, which takes over ownership of
387    C.  Not valid after any reader for CF has been created.
388    Returns true if successful, false if an I/O error occurred. */
389 bool
390 casefile_append_xfer (struct casefile *cf, struct ccase *c) 
391 {
392   casefile_append (cf, c);
393   case_destroy (c);
394   return cf->ok;
395 }
396
397 /* Writes case C to casefile CF's disk buffer, first flushing the buffer to
398    disk if it would otherwise overflow.
399    Returns true if successful, false if an I/O error occurred. */
400 static void
401 write_case_to_disk (struct casefile *cf, const struct ccase *c) 
402 {
403   if (!cf->ok)
404     return;
405   
406   case_to_values (c, cf->buffer + cf->buffer_used, cf->value_cnt);
407   cf->buffer_used += cf->value_cnt;
408   if (cf->buffer_used + cf->value_cnt > cf->buffer_size)
409     flush_buffer (cf);
410 }
411
412 /* If any bytes in CF's output buffer are used, flush them to
413    disk. */
414 static void
415 flush_buffer (struct casefile *cf) 
416 {
417   if (cf->ok && cf->buffer_used > 0) 
418     {
419       if (!full_write (cf->fd, cf->buffer,
420                        cf->buffer_size * sizeof *cf->buffer))
421         io_error (cf, _("Error writing temporary file: %s."),
422                   strerror (errno));
423
424
425       cf->buffer_used = 0;
426     }
427 }
428
429 /* If CF is currently stored in memory, writes it to disk.  Readers, if any,
430    retain their current positions.
431    Returns true if successful, false if an I/O error occurred. */
432 bool
433 casefile_to_disk (const struct casefile *cf_) 
434 {
435   struct casefile *cf = (struct casefile *) cf_;
436   struct casereader *reader;
437   
438   assert (cf != NULL);
439
440   if (cf->storage == MEMORY)
441     {
442       size_t idx, block_cnt;
443       
444       assert (cf->filename == NULL);
445       assert (cf->fd == -1);
446       assert (cf->buffer_used == 0);
447
448       if (!make_temp_file (&cf->fd, &cf->filename))
449         {
450           cf->ok = false;
451           return false;
452         }
453       cf->storage = DISK;
454
455       cf->buffer = xnmalloc (cf->buffer_size, sizeof *cf->buffer);
456       memset (cf->buffer, 0, cf->buffer_size * sizeof *cf->buffer);
457
458       case_bytes -= cf->case_cnt * cf->case_acct_size;
459       for (idx = 0; idx < cf->case_cnt; idx++)
460         {
461           size_t block_idx = idx / CASES_PER_BLOCK;
462           size_t case_idx = idx % CASES_PER_BLOCK;
463           struct ccase *c = &cf->cases[block_idx][case_idx];
464           write_case_to_disk (cf, c);
465           case_destroy (c);
466         }
467
468       block_cnt = DIV_RND_UP (cf->case_cnt, CASES_PER_BLOCK);
469       for (idx = 0; idx < block_cnt; idx++)
470         free (cf->cases[idx]);
471
472       free (cf->cases);
473       cf->cases = NULL;
474
475       if (cf->mode == READ)
476         flush_buffer (cf);
477
478       for (reader = cf->readers; reader != NULL; reader = reader->next)
479         reader_open_file (reader);
480     }
481   return cf->ok;
482 }
483
484 /* Changes CF to reader mode, ensuring that no more cases may be
485    added.  Creating a casereader for CF has the same effect. */
486 void
487 casefile_mode_reader (struct casefile *cf) 
488 {
489   assert (cf != NULL);
490   cf->mode = READ;
491 }
492
493 /* Creates and returns a casereader for CF.  A casereader can be used to
494    sequentially read the cases in a casefile. */
495 struct casereader *
496 casefile_get_reader (const struct casefile *cf_) 
497 {
498   struct casefile *cf = (struct casefile *) cf_;
499   struct casereader *reader;
500
501   assert (cf != NULL);
502   assert (!cf->being_destroyed);
503
504   /* Flush the buffer to disk if it's not empty. */
505   if (cf->mode == WRITE && cf->storage == DISK)
506     flush_buffer (cf);
507   
508   cf->mode = READ;
509
510   reader = xmalloc (sizeof *reader);
511   reader->next = cf->readers;
512   if (cf->readers != NULL)
513     reader->next->prev = reader;
514   cf->readers = reader;
515   reader->prev = NULL;
516   reader->cf = cf;
517   reader->case_idx = 0;
518   reader->destructive = 0;
519   reader->fd = -1;
520   reader->buffer = NULL;
521   reader->buffer_pos = 0;
522   case_nullify (&reader->c);
523
524   if (reader->cf->storage == DISK) 
525     reader_open_file (reader);
526
527   return reader;
528 }
529
530 /* Creates and returns a destructive casereader for CF.  Like a
531    normal casereader, a destructive casereader sequentially reads
532    the cases in a casefile.  Unlike a normal casereader, a
533    destructive reader cannot operate concurrently with any other
534    reader.  (This restriction could be relaxed in a few ways, but
535    it is so far unnecessary for other code.) */
536 struct casereader *
537 casefile_get_destructive_reader (struct casefile *cf) 
538 {
539   struct casereader *reader;
540   
541   assert (cf->readers == NULL);
542   reader = casefile_get_reader (cf);
543   reader->destructive = 1;
544   cf->being_destroyed = 1;
545   return reader;
546 }
547
548 /* Opens a disk file for READER and seeks to the current position as indicated
549    by case_idx.  Normally the current position is the beginning of the file,
550    but casefile_to_disk may cause the file to be opened at a different
551    position. */
552 static void
553 reader_open_file (struct casereader *reader) 
554 {
555   struct casefile *cf = reader->cf;
556   off_t file_ofs;
557
558   if (!cf->ok || reader->case_idx >= cf->case_cnt)
559     return;
560
561   if (cf->fd != -1) 
562     {
563       reader->fd = cf->fd;
564       cf->fd = -1;
565     }
566   else 
567     {
568       reader->fd = safe_open (cf->filename, O_RDONLY);
569       if (reader->fd < 0)
570         io_error (cf, _("%s: Opening temporary file: %s."),
571                   cf->filename, strerror (errno));
572     }
573
574   if (cf->buffer != NULL) 
575     {
576       reader->buffer = cf->buffer;
577       cf->buffer = NULL; 
578     }
579   else 
580     {
581       reader->buffer = xnmalloc (cf->buffer_size, sizeof *cf->buffer);
582       memset (reader->buffer, 0, cf->buffer_size * sizeof *cf->buffer); 
583     }
584
585   if (cf->value_cnt != 0) 
586     {
587       size_t buffer_case_cnt = cf->buffer_size / cf->value_cnt;
588       file_ofs = ((off_t) reader->case_idx / buffer_case_cnt
589                   * cf->buffer_size * sizeof *cf->buffer);
590       reader->buffer_pos = (reader->case_idx % buffer_case_cnt
591                             * cf->value_cnt);
592     }
593   else 
594     file_ofs = 0;
595   if (lseek (reader->fd, file_ofs, SEEK_SET) != file_ofs)
596     io_error (cf, _("%s: Seeking temporary file: %s."),
597               cf->filename, strerror (errno));
598
599   if (cf->case_cnt > 0 && cf->value_cnt > 0)
600     fill_buffer (reader);
601
602   case_create (&reader->c, cf->value_cnt);
603 }
604
605 /* Fills READER's buffer by reading a block from disk. */
606 static bool
607 fill_buffer (struct casereader *reader)
608 {
609   if (reader->cf->ok) 
610     {
611       int bytes = full_read (reader->fd, reader->buffer,
612                              reader->cf->buffer_size * sizeof *reader->buffer);
613       if (bytes < 0) 
614         io_error (reader->cf, _("%s: Reading temporary file: %s."),
615                   reader->cf->filename, strerror (errno));
616       else if (bytes != reader->cf->buffer_size * sizeof *reader->buffer) 
617         io_error (reader->cf, _("%s: Temporary file ended unexpectedly."),
618                   reader->cf->filename); 
619     }
620   return reader->cf->ok;
621 }
622
623 /* Returns the casefile that READER reads. */
624 const struct casefile *
625 casereader_get_casefile (const struct casereader *reader) 
626 {
627   assert (reader != NULL);
628   
629   return reader->cf;
630 }
631
632 /* Reads a copy of the next case from READER into C.
633    Caller is responsible for destroying C.
634    Returns true if successful, false at end of file. */
635 int
636 casereader_read (struct casereader *reader, struct ccase *c) 
637 {
638   assert (reader != NULL);
639   
640   if (!reader->cf->ok || reader->case_idx >= reader->cf->case_cnt) 
641     return 0;
642
643   if (reader->cf->storage == MEMORY) 
644     {
645       size_t block_idx = reader->case_idx / CASES_PER_BLOCK;
646       size_t case_idx = reader->case_idx % CASES_PER_BLOCK;
647
648       case_clone (c, &reader->cf->cases[block_idx][case_idx]);
649       reader->case_idx++;
650       return 1;
651     }
652   else 
653     {
654       if (reader->buffer_pos + reader->cf->value_cnt > reader->cf->buffer_size)
655         {
656           if (!fill_buffer (reader))
657             return 0;
658           reader->buffer_pos = 0;
659         }
660
661       case_from_values (&reader->c, reader->buffer + reader->buffer_pos,
662                         reader->cf->value_cnt);
663       reader->buffer_pos += reader->cf->value_cnt;
664       reader->case_idx++;
665
666       case_clone (c, &reader->c);
667       return 1;
668     }
669 }
670
671 /* Reads the next case from READER into C and transfers ownership
672    to the caller.  Caller is responsible for destroying C.
673    Returns true if successful, false at end of file or on I/O
674    error. */
675 int
676 casereader_read_xfer (struct casereader *reader, struct ccase *c)
677 {
678   assert (reader != NULL);
679
680   if (reader->destructive == 0
681       || reader->case_idx >= reader->cf->case_cnt
682       || reader->cf->storage == DISK) 
683     return casereader_read (reader, c);
684   else 
685     {
686       size_t block_idx = reader->case_idx / CASES_PER_BLOCK;
687       size_t case_idx = reader->case_idx % CASES_PER_BLOCK;
688       struct ccase *read_case = &reader->cf->cases[block_idx][case_idx];
689
690       case_move (c, read_case);
691       reader->case_idx++;
692       return 1;
693     }
694 }
695
696 /* Destroys READER. */
697 void
698 casereader_destroy (struct casereader *reader)
699 {
700   assert (reader != NULL);
701
702   if (reader->next != NULL)
703     reader->next->prev = reader->prev;
704   if (reader->prev != NULL)
705     reader->prev->next = reader->next;
706   if (reader->cf->readers == reader)
707     reader->cf->readers = reader->next;
708
709   if (reader->cf->buffer == NULL)
710     reader->cf->buffer = reader->buffer;
711   else
712     free (reader->buffer);
713
714   if (reader->fd != -1) 
715     {
716       if (reader->cf->fd == -1)
717         reader->cf->fd = reader->fd;
718       else
719         safe_close (reader->fd);
720     }
721   
722   case_destroy (&reader->c);
723
724   free (reader);
725 }
726
727 /* Marks CF as having encountered an I/O error.
728    If this is the first error on CF, reports FORMAT to the user,
729    doing printf()-style substitutions. */
730 static void
731 io_error (struct casefile *cf, const char *format, ...)
732 {
733   if (cf->ok) 
734     {
735       struct error e;
736       va_list args;
737
738       e.class = ME;
739       e.where.filename = NULL;
740       e.where.line_number = -1;
741       e.title = NULL;
742
743       va_start (args, format);
744       err_vmsg (&e, format, args);
745       va_end (args);
746     }
747   cf->ok = false;
748 }
749
750 /* Calls open(), passing FILENAME and FLAGS, repeating as necessary
751    to deal with interrupted calls. */
752 static int
753 safe_open (const char *filename, int flags) 
754 {
755   int fd;
756
757   do 
758     {
759       fd = open (filename, flags);
760     }
761   while (fd == -1 && errno == EINTR);
762
763   return fd;
764 }
765
766 /* Calls close(), passing FD, repeating as necessary to deal with
767    interrupted calls. */
768 static int safe_close (int fd) 
769 {
770   int retval;
771
772   do 
773     {
774       retval = close (fd);
775     }
776   while (retval == -1 && errno == EINTR);
777
778   return retval;
779 }
780
781 /* Registers our exit handler with atexit() if it has not already
782    been registered. */
783 static void
784 register_atexit (void) 
785 {
786   static int registered = 0;
787   if (!registered) 
788     {
789       registered = 1;
790       atexit (exit_handler);
791     }
792 }
793
794
795
796 /* atexit() handler that closes and deletes our temporary
797    files. */
798 static void
799 exit_handler (void) 
800 {
801   while (casefiles != NULL)
802     casefile_destroy (casefiles);
803 }