Remove .tpa, .tpb, .tpx, .trj files. Part of #1500.
[alexxy/gromacs.git] / src / gromacs / fileio / gmxfio.c
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5  * Copyright (c) 2001-2004, The GROMACS development team.
6  * Copyright (c) 2013,2014, by the GROMACS development team, led by
7  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8  * and including many others, as listed in the AUTHORS file in the
9  * top-level source directory and at http://www.gromacs.org.
10  *
11  * GROMACS is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public License
13  * as published by the Free Software Foundation; either version 2.1
14  * of the License, or (at your option) any later version.
15  *
16  * GROMACS is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with GROMACS; if not, see
23  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
25  *
26  * If you want to redistribute modifications to GROMACS, please
27  * consider that scientific software is very special. Version
28  * control is crucial - bugs must be traceable. We will be happy to
29  * consider code for inclusion in the official distribution, but
30  * derived work must not be called official GROMACS. Details are found
31  * in the README & COPYING files - if they are missing, get the
32  * official version at http://www.gromacs.org.
33  *
34  * To help us fund GROMACS development, we humbly ask that you cite
35  * the research papers on the package. Check out http://www.gromacs.org.
36  */
37 #include "gmxpre.h"
38
39 #include "config.h"
40
41 #include <errno.h>
42 #include <stdio.h>
43 #include <string.h>
44 #ifdef HAVE_IO_H
45 #include <io.h>
46 #endif
47 #ifdef HAVE_UNISTD_H
48 #include <unistd.h>
49 #endif
50
51 #include "thread_mpi/threads.h"
52
53 #include "gromacs/utility/fatalerror.h"
54 #include "gromacs/legacyheaders/macros.h"
55 #include "gromacs/utility/smalloc.h"
56 #include "gromacs/utility/futil.h"
57 #include "filenm.h"
58 #include "gromacs/utility/cstringutil.h"
59 #include "gmxfio.h"
60 #include "md5.h"
61
62 #include "gmxfio_int.h"
63
64 /* This is the new improved and thread safe version of gmxfio. */
65
66
67
68 /* the list of open files is a linked list, with a dummy element at its head;
69        it is initialized when the first file is opened. */
70 static t_fileio *open_files = NULL;
71
72
73 /* this mutex locks the open_files structure so that no two threads can
74    modify it.
75
76    For now, we use this as a coarse grained lock on all file
77    insertion/deletion operations because it makes avoiding deadlocks
78    easier, and adds almost no overhead: the only overhead is during
79    opening and closing of files, or during global operations like
80    iterating along all open files. All these cases should be rare
81    during the simulation. */
82 static tMPI_Thread_mutex_t open_file_mutex = TMPI_THREAD_MUTEX_INITIALIZER;
83
84
85 /* These simple lists define the I/O type for these files */
86 static const int ftpXDR[] =
87 { efTPR, efTRR, efEDR, efXTC, efTNG, efMTX, efCPT };
88 static const int ftpASC[] =
89 { efGRO, efPDB, efG96 };
90 static const int ftpBIN[] =
91 { efTNG };
92 #ifdef HAVE_XML
93 static const int ftpXML[] =
94 {   efXML};
95 #endif
96
97 const char *eioNames[eioNR] =
98 {
99     "REAL", "INT", "GMX_STE_T", "UCHAR", "NUCHAR", "USHORT", "RVEC", "NRVEC",
100     "IVEC", "STRING"
101 };
102
103 /******************************************************************
104  *
105  * Internal functions:
106  *
107  ******************************************************************/
108
109 static int gmx_fio_int_flush(t_fileio* fio)
110 {
111     int rc = 0;
112
113     if (fio->fp)
114     {
115         rc = fflush(fio->fp);
116     }
117     else if (fio->xdr)
118     {
119         rc = fflush((FILE *) fio->xdr->x_private);
120     }
121
122     return rc;
123 }
124
125 /* returns TRUE if the file type ftp is in the set set */
126 static gmx_bool in_ftpset(int ftp, int nset, const int set[])
127 {
128     int      i;
129     gmx_bool bResult;
130
131     bResult = FALSE;
132     for (i = 0; (i < nset); i++)
133     {
134         if (ftp == set[i])
135         {
136             bResult = TRUE;
137         }
138     }
139
140     return bResult;
141 }
142
143
144
145 extern void gmx_fio_set_comment(t_fileio *fio, const char *comment)
146 {
147     fio->comment = comment;
148 }
149
150 extern void gmx_fio_unset_comment(t_fileio *fio)
151 {
152     fio->comment = NULL;
153 }
154
155
156 const char *gmx_fio_dbgstr(t_fileio *fio, const char *desc, char *buf)
157 {
158     if (!fio->bDebug)
159     {
160         /* set to empty string */
161         buf[0] = 0;
162     }
163     else
164     {
165         snprintf(buf, GMX_FIO_BUFLEN, "  ; %s %s", fio->comment ? fio->comment : "", desc);
166     }
167     return buf;
168 }
169
170
171 /* check the number of items given against the type */
172 void gmx_fio_check_nitem(int eio, int nitem, const char *file, int line)
173 {
174     if ((nitem != 1) && !((eio == eioNRVEC) || (eio == eioNUCHAR)))
175     {
176         gmx_fatal(FARGS,
177                   "nitem (%d) may differ from 1 only for %s or %s, not   for %s"
178                   "(%s, %d)", nitem, eioNames[eioNUCHAR], eioNames[eioNRVEC],
179                   eioNames[eio], file, line);
180     }
181 }
182
183
184 /* output a data type error. */
185 void gmx_fio_fe(t_fileio *fio, int eio, const char *desc,
186                 const char *srcfile, int line)
187 {
188
189     gmx_fatal(FARGS, "Trying to %s %s type %d (%s), src %s, line %d",
190               fio->bRead ? "read" : "write", desc, eio,
191               ((eio >= 0) && (eio < eioNR)) ? eioNames[eio] : "unknown",
192               srcfile, line);
193 }
194
195
196 /* set the reader/writer functions based on the file type */
197 static void gmx_fio_set_iotype(t_fileio *fio)
198 {
199     if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
200     {
201 #ifdef USE_XDR
202         fio->iotp = &xdr_iotype;
203 #else
204         gmx_fatal(FARGS, "Sorry, no XDR");
205 #endif
206     }
207     else if (in_ftpset(fio->iFTP, asize(ftpASC), ftpASC))
208     {
209         fio->iotp = &asc_iotype;
210     }
211     else if (in_ftpset(fio->iFTP, asize(ftpBIN), ftpBIN))
212     {
213         fio->iotp = &bin_iotype;
214     }
215 #ifdef HAVE_XMl
216     else if (in_ftpset(fio->iFTP, asize(ftpXML), ftpXML))
217     {
218         fio->iotp = &dummy_iotype;
219     }
220 #endif
221     else
222     {
223         fio->iotp = &dummy_iotype;
224     }
225 }
226
227
228 /* lock the mutex associated with this fio. This needs to be done for every
229    type of access to the fio's elements. */
230 void gmx_fio_lock(t_fileio *fio)
231 {
232     tMPI_Lock_lock(&(fio->mtx));
233 }
234 /* unlock the mutex associated with this fio.  */
235 void gmx_fio_unlock(t_fileio *fio)
236 {
237     tMPI_Lock_unlock(&(fio->mtx));
238 }
239
240 /* make a dummy head element, assuming we locked everything. */
241 static void gmx_fio_make_dummy(void)
242 {
243     if (!open_files)
244     {
245         snew(open_files, 1);
246         open_files->fp   = NULL;
247         open_files->fn   = NULL;
248         open_files->next = open_files;
249         open_files->prev = open_files;
250         tMPI_Lock_init(&(open_files->mtx));
251     }
252 }
253
254
255
256
257
258
259
260 /***********************************************************************
261  *
262  * FILE LIST OPERATIONS
263  *
264  ***********************************************************************/
265
266
267 /* insert a new t_fileio into the list */
268 static void gmx_fio_insert(t_fileio *fio)
269 {
270     t_fileio *prev;
271     /* first lock the big open_files mutex. */
272     tMPI_Thread_mutex_lock(&open_file_mutex);
273     /* now check whether the dummy element has been allocated,
274        and allocate it if it hasn't */
275     gmx_fio_make_dummy();
276
277     /* and lock the fio we got and the list's head **/
278     gmx_fio_lock(fio);
279     gmx_fio_lock(open_files);
280     prev = open_files->prev;
281     /* lock the element after the current one */
282     if (prev != open_files)
283     {
284         gmx_fio_lock(prev);
285     }
286
287     /* now do the actual insertion: */
288     fio->next        = open_files;
289     open_files->prev = fio;
290     prev->next       = fio;
291     fio->prev        = prev;
292
293     /* now unlock all our locks */
294     if (prev != open_files)
295     {
296         gmx_fio_unlock(prev);
297     }
298     gmx_fio_unlock(open_files);
299     gmx_fio_unlock(fio);
300
301     /* now unlock the big open_files mutex.  */
302     tMPI_Thread_mutex_unlock(&open_file_mutex);
303 }
304
305 /* remove a t_fileio into the list. We assume the fio is locked, and we leave
306    it locked.
307    NOTE: We also assume that the open_file_mutex has been locked */
308 static void gmx_fio_remove(t_fileio *fio)
309 {
310     t_fileio *prev;
311
312     /* lock prev, because we're changing it */
313     gmx_fio_lock(fio->prev);
314
315     /* now set the prev's pointer */
316     fio->prev->next = fio->next;
317     gmx_fio_unlock(fio->prev);
318
319     /* with the next ptr, we can simply lock while the original was locked */
320     gmx_fio_lock(fio->next);
321     fio->next->prev = fio->prev;
322     gmx_fio_unlock(fio->next);
323
324     /* and make sure we point nowhere in particular */
325     fio->next = fio->prev = fio;
326 }
327
328
329 /* get the first open file, or NULL if there is none.
330    Returns a locked fio. */
331 static t_fileio *gmx_fio_get_first(void)
332 {
333     t_fileio *ret;
334     /* first lock the big open_files mutex and the dummy's mutex */
335
336     /* first lock the big open_files mutex. */
337     tMPI_Thread_mutex_lock(&open_file_mutex);
338     gmx_fio_make_dummy();
339
340     gmx_fio_lock(open_files);
341     ret = open_files->next;
342
343
344     /* check whether there were any to begin with */
345     if (ret == open_files)
346     {
347         /* after this, the open_file pointer should never change */
348         ret = NULL;
349     }
350     else
351     {
352         gmx_fio_lock(open_files->next);
353     }
354     gmx_fio_unlock(open_files);
355
356
357     return ret;
358 }
359
360 /* get the next open file, or NULL if there is none.
361    Unlocks the previous fio and locks the next one. */
362 static t_fileio *gmx_fio_get_next(t_fileio *fio)
363 {
364     t_fileio *ret;
365
366     ret = fio->next;
367     /* check if that was the last one */
368     if (fio->next == open_files)
369     {
370         ret = NULL;
371         tMPI_Thread_mutex_unlock(&open_file_mutex);
372     }
373     else
374     {
375         gmx_fio_lock(ret);
376     }
377     gmx_fio_unlock(fio);
378
379     return ret;
380 }
381
382 /* Stop looping through the open_files.  Unlocks the global lock. */
383 static void gmx_fio_stop_getting_next(t_fileio *fio)
384 {
385     gmx_fio_unlock(fio);
386     tMPI_Thread_mutex_unlock(&open_file_mutex);
387 }
388
389
390
391
392 /*****************************************************************
393  *
394  *                     EXPORTED SECTION
395  *
396  *****************************************************************/
397 t_fileio *gmx_fio_open(const char *fn, const char *mode)
398 {
399     t_fileio *fio = NULL;
400     int       i;
401     char      newmode[5];
402     gmx_bool  bRead, bReadWrite;
403     int       xdrid;
404
405     /* sanitize the mode string */
406     if (strncmp(mode, "r+", 2) == 0)
407     {
408         strcpy(newmode, "r+");
409     }
410     else if (mode[0] == 'r')
411     {
412         strcpy(newmode, "r");
413     }
414     else if (strncmp(mode, "w+", 2) == 0)
415     {
416         strcpy(newmode, "w+");
417     }
418     else if (mode[0] == 'w')
419     {
420         strcpy(newmode, "w");
421     }
422     else if (strncmp(mode, "a+", 2) == 0)
423     {
424         strcpy(newmode, "a+");
425     }
426     else if (mode[0] == 'a')
427     {
428         strcpy(newmode, "a");
429     }
430     else
431     {
432         gmx_fatal(FARGS, "DEATH HORROR in gmx_fio_open, mode is '%s'", mode);
433     }
434
435     /* Check if it should be opened as a binary file */
436     if (strncmp(ftp2ftype(fn2ftp(fn)), "ASCII", 5))
437     {
438         /* Not ascii, add b to file mode */
439         if ((strchr(newmode, 'b') == NULL) && (strchr(newmode, 'B') == NULL))
440         {
441             strcat(newmode, "b");
442         }
443     }
444
445     snew(fio, 1);
446     tMPI_Lock_init(&(fio->mtx));
447     bRead      = (newmode[0] == 'r' && newmode[1] != '+');
448     bReadWrite = (newmode[1] == '+');
449     fio->fp    = NULL;
450     fio->xdr   = NULL;
451     if (fn)
452     {
453         fio->iFTP   = fn2ftp(fn);
454         fio->fn     = gmx_strdup(fn);
455         fio->bStdio = FALSE;
456
457         /* If this file type is in the list of XDR files, open it like that */
458         if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
459         {
460             /* First check whether we have to make a backup,
461              * only for writing, not for read or append.
462              */
463             if (newmode[0] == 'w')
464             {
465 #ifndef GMX_FAHCORE
466                 /* only make backups for normal gromacs */
467                 make_backup(fn);
468 #endif
469             }
470             else
471             {
472                 /* Check whether file exists */
473                 if (!gmx_fexist(fn))
474                 {
475                     gmx_open(fn);
476                 }
477             }
478             if (fn2ftp(fn) == efTNG)
479             {
480                 gmx_incons("gmx_fio_open may not be used to open TNG files");
481             }
482             /* Open the file */
483             fio->fp = gmx_ffopen(fn, newmode);
484
485             /* determine the XDR direction */
486             if (newmode[0] == 'w' || newmode[0] == 'a')
487             {
488                 fio->xdrmode = XDR_ENCODE;
489             }
490             else
491             {
492                 fio->xdrmode = XDR_DECODE;
493             }
494
495             snew(fio->xdr, 1);
496             xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
497         }
498         else
499         {
500             /* If it is not, open it as a regular file */
501             fio->fp = gmx_ffopen(fn, newmode);
502         }
503
504         /* for appending seek to end of file to make sure ftell gives correct position
505          * important for checkpointing */
506         if (newmode[0] == 'a')
507         {
508             gmx_fseek(fio->fp, 0, SEEK_END);
509         }
510     }
511     fio->bRead             = bRead;
512     fio->bReadWrite        = bReadWrite;
513     fio->bDouble           = (sizeof(real) == sizeof(double));
514     fio->bDebug            = FALSE;
515     fio->bOpen             = TRUE;
516
517     /* set the reader/writer functions */
518     gmx_fio_set_iotype(fio);
519
520     /* and now insert this file into the list of open files. */
521     gmx_fio_insert(fio);
522     return fio;
523 }
524
525 static int gmx_fio_close_locked(t_fileio *fio)
526 {
527     int rc = 0;
528
529     if (!fio->bOpen)
530     {
531         gmx_fatal(FARGS, "File %s closed twice!\n", fio->fn);
532     }
533
534     if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
535     {
536         xdr_destroy(fio->xdr);
537         sfree(fio->xdr);
538     }
539
540     /* Don't close stdin and stdout! */
541     if (!fio->bStdio && fio->fp != NULL)
542     {
543         rc = gmx_ffclose(fio->fp); /* fclose returns 0 if happy */
544
545     }
546     fio->bOpen = FALSE;
547
548     return rc;
549 }
550
551 int gmx_fio_close(t_fileio *fio)
552 {
553     int rc = 0;
554
555     /* first lock the big open_files mutex. */
556     /* We don't want two processes operating on the list at the same time */
557     tMPI_Thread_mutex_lock(&open_file_mutex);
558
559     if (fio->iFTP == efTNG)
560     {
561         gmx_incons("gmx_fio_close should not be called on a TNG file");
562     }
563     gmx_fio_lock(fio);
564     /* first remove it from the list */
565     gmx_fio_remove(fio);
566     rc = gmx_fio_close_locked(fio);
567     gmx_fio_unlock(fio);
568
569     sfree(fio->fn);
570     sfree(fio);
571
572     tMPI_Thread_mutex_unlock(&open_file_mutex);
573
574     return rc;
575 }
576
577 /* close only fp but keep FIO entry. */
578 int gmx_fio_fp_close(t_fileio *fio)
579 {
580     int rc = 0;
581     gmx_fio_lock(fio);
582     if (!in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR) && !fio->bStdio)
583     {
584         rc      = gmx_ffclose(fio->fp); /* fclose returns 0 if happy */
585         fio->fp = NULL;
586     }
587     gmx_fio_unlock(fio);
588
589     return rc;
590 }
591
592 FILE * gmx_fio_fopen(const char *fn, const char *mode)
593 {
594     FILE     *fp, *ret;
595     t_fileio *fio;
596
597     fio = gmx_fio_open(fn, mode);
598     gmx_fio_lock(fio);
599     ret = fio->fp;
600     gmx_fio_unlock(fio);
601
602     return ret;
603 }
604
605 int gmx_fio_fclose(FILE *fp)
606 {
607     t_fileio *cur;
608     t_fileio *found = NULL;
609     int       rc    = -1;
610
611     cur = gmx_fio_get_first();
612     while (cur)
613     {
614         if (cur->fp == fp)
615         {
616             rc = gmx_fio_close_locked(cur);
617             gmx_fio_remove(cur);
618             gmx_fio_stop_getting_next(cur);
619             sfree(cur->fn);
620             sfree(cur);
621             break;
622         }
623         cur = gmx_fio_get_next(cur);
624     }
625
626     return rc;
627 }
628
629 /* internal variant of get_file_md5 that operates on a locked file */
630 static int gmx_fio_int_get_file_md5(t_fileio *fio, gmx_off_t offset,
631                                     unsigned char digest[])
632 {
633     /*1MB: large size important to catch almost identical files */
634 #define CPT_CHK_LEN  1048576
635     md5_state_t    state;
636     unsigned char *buf;
637     gmx_off_t      read_len;
638     gmx_off_t      seek_offset;
639     int            ret = -1;
640
641     seek_offset = offset - CPT_CHK_LEN;
642     if (seek_offset < 0)
643     {
644         seek_offset = 0;
645     }
646     read_len = offset - seek_offset;
647
648
649     if (fio->fp && fio->bReadWrite)
650     {
651         ret = gmx_fseek(fio->fp, seek_offset, SEEK_SET);
652         if (ret)
653         {
654             gmx_fseek(fio->fp, 0, SEEK_END);
655         }
656     }
657     if (ret) /*either no fp, not readwrite, or fseek not successful */
658     {
659         return -1;
660     }
661
662     snew(buf, CPT_CHK_LEN);
663     /* the read puts the file position back to offset */
664     if ((gmx_off_t)fread(buf, 1, read_len, fio->fp) != read_len)
665     {
666         /* not fatal: md5sum check to prevent overwriting files
667          * works (less safe) without
668          * */
669         if (ferror(fio->fp))
670         {
671             fprintf(stderr, "\nTrying to get md5sum: %s: %s\n", fio->fn,
672                     strerror(errno));
673         }
674         else if (feof(fio->fp))
675         {
676             /*
677              * For long runs that checkpoint frequently but write e.g. logs
678              * infrequently we don't want to issue lots of warnings before we
679              * have written anything to the log.
680              */
681             if (0)
682             {
683                 fprintf(stderr, "\nTrying to get md5sum: EOF: %s\n", fio->fn);
684             }
685         }
686         else
687         {
688             fprintf(
689                     stderr,
690                     "\nTrying to get md5sum: Unknown reason for short read: %s\n",
691                     fio->fn);
692         }
693
694         gmx_fseek(fio->fp, 0, SEEK_END);
695
696         ret = -1;
697     }
698     gmx_fseek(fio->fp, 0, SEEK_END); /*is already at end, but under windows
699                                         it gives problems otherwise*/
700
701     if (debug)
702     {
703         fprintf(debug, "chksum %s readlen %ld\n", fio->fn, (long int)read_len);
704     }
705
706     if (!ret)
707     {
708         gmx_md5_init(&state);
709         gmx_md5_append(&state, buf, read_len);
710         gmx_md5_finish(&state, digest);
711         ret = read_len;
712     }
713     sfree(buf);
714     return ret;
715 }
716
717
718 /*
719  * fio: file to compute md5 for
720  * offset: starting pointer of region to use for md5
721  * digest: return array of md5 sum
722  */
723 int gmx_fio_get_file_md5(t_fileio *fio, gmx_off_t offset,
724                          unsigned char digest[])
725 {
726     int ret;
727
728     gmx_fio_lock(fio);
729     ret = gmx_fio_int_get_file_md5(fio, offset, digest);
730     gmx_fio_unlock(fio);
731
732     return ret;
733 }
734
735 /* The fio_mutex should ALWAYS be locked when this function is called */
736 static int gmx_fio_int_get_file_position(t_fileio *fio, gmx_off_t *offset)
737 {
738     char buf[STRLEN];
739
740     /* Flush the file, so we are sure it is written */
741     if (gmx_fio_int_flush(fio))
742     {
743         char buf[STRLEN];
744         sprintf(
745                 buf,
746                 "Cannot write file '%s'; maybe you are out of disk space?",
747                 fio->fn);
748         gmx_file(buf);
749     }
750
751     /* We cannot count on XDR being able to write 64-bit integers,
752        so separate into high/low 32-bit values.
753        In case the filesystem has 128-bit offsets we only care
754        about the first 64 bits - we'll have to fix
755        this when exabyte-size output files are common...
756      */
757     *offset = gmx_ftell(fio->fp);
758
759     return 0;
760 }
761
762 int gmx_fio_get_output_file_positions(gmx_file_position_t **p_outputfiles,
763                                       int                  *p_nfiles)
764 {
765     int                   i, nfiles, rc, nalloc;
766     int                   pos_hi, pos_lo;
767     long                  pos;
768     gmx_file_position_t * outputfiles;
769     char                  buf[STRLEN];
770     t_fileio             *cur;
771
772     nfiles = 0;
773
774     /* pre-allocate 100 files */
775     nalloc = 100;
776     snew(outputfiles, nalloc);
777
778     cur = gmx_fio_get_first();
779     while (cur)
780     {
781         /* Skip the checkpoint files themselves, since they could be open when
782            we call this routine... */
783         /* also skip debug files (shoud be the only iFTP==efNR) */
784         if (cur->bOpen &&
785             !cur->bRead &&
786             !cur->bStdio &&
787             cur->iFTP != efCPT &&
788             cur->iFTP != efNR)
789         {
790             int ret;
791             /* This is an output file currently open for writing, add it */
792             if (nfiles == nalloc)
793             {
794                 nalloc += 100;
795                 srenew(outputfiles, nalloc);
796             }
797
798             strncpy(outputfiles[nfiles].filename, cur->fn, STRLEN - 1);
799
800             /* Get the file position */
801             gmx_fio_int_get_file_position(cur, &outputfiles[nfiles].offset);
802 #ifndef GMX_FAHCORE
803             outputfiles[nfiles].chksum_size
804                 = gmx_fio_int_get_file_md5(cur,
805                                            outputfiles[nfiles].offset,
806                                            outputfiles[nfiles].chksum);
807 #endif
808             nfiles++;
809         }
810
811         cur = gmx_fio_get_next(cur);
812     }
813     *p_nfiles      = nfiles;
814     *p_outputfiles = outputfiles;
815
816     return 0;
817 }
818
819
820 void gmx_fio_checktype(t_fileio *fio)
821 {
822     if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
823     {
824         return;
825     }
826     else if (in_ftpset(fio->iFTP, asize(ftpASC), ftpASC))
827     {
828         return;
829     }
830     else if (in_ftpset(fio->iFTP, asize(ftpBIN), ftpBIN))
831     {
832         return;
833     }
834 #ifdef HAVE_XMl
835     else if (in_ftpset(fio->iFTP, asize(ftpXML), ftpXML))
836     {
837         return;
838     }
839 #endif
840     else
841     {
842         gmx_fatal(FARGS, "Can not read/write topologies to file type %s",
843                   ftp2ext(fio->iFTP));
844     }
845
846 }
847
848
849 void gmx_fio_setprecision(t_fileio *fio, gmx_bool bDouble)
850 {
851     gmx_fio_lock(fio);
852     fio->bDouble = bDouble;
853     gmx_fio_unlock(fio);
854 }
855
856 gmx_bool gmx_fio_getdebug(t_fileio *fio)
857 {
858     gmx_bool ret;
859
860     gmx_fio_lock(fio);
861     ret = fio->bDebug;
862     gmx_fio_unlock(fio);
863
864     return ret;
865 }
866
867 void gmx_fio_setdebug(t_fileio *fio, gmx_bool bDebug)
868 {
869     gmx_fio_lock(fio);
870     fio->bDebug = bDebug;
871     gmx_fio_unlock(fio);
872 }
873
874 char *gmx_fio_getname(t_fileio *fio)
875 {
876     char *ret;
877     gmx_fio_lock(fio);
878     ret = fio->fn;
879     gmx_fio_unlock(fio);
880
881     return ret;
882 }
883
884 int gmx_fio_getftp(t_fileio* fio)
885 {
886     int ret;
887
888     gmx_fio_lock(fio);
889     ret = fio->iFTP;
890     gmx_fio_unlock(fio);
891
892     return ret;
893 }
894
895 void gmx_fio_rewind(t_fileio* fio)
896 {
897     gmx_fio_lock(fio);
898
899     if (fio->xdr)
900     {
901         xdr_destroy(fio->xdr);
902         frewind(fio->fp);
903         xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
904     }
905     else
906     {
907         frewind(fio->fp);
908     }
909     gmx_fio_unlock(fio);
910 }
911
912
913 int gmx_fio_flush(t_fileio* fio)
914 {
915     int ret;
916
917     gmx_fio_lock(fio);
918     ret = gmx_fio_int_flush(fio);
919     gmx_fio_unlock(fio);
920
921     return ret;
922 }
923
924
925
926 static int gmx_fio_int_fsync(t_fileio *fio)
927 {
928     int rc    = 0;
929     int filen = -1;
930
931
932     if (fio->fp)
933     {
934         rc = gmx_fsync(fio->fp);
935     }
936     else if (fio->xdr) /* this should normally not happen */
937     {
938         rc = gmx_fsync((FILE*) fio->xdr->x_private);
939         /* ^ is this actually OK? */
940     }
941
942     return rc;
943 }
944
945
946 int gmx_fio_fsync(t_fileio *fio)
947 {
948     int rc;
949
950     gmx_fio_lock(fio);
951     rc = gmx_fio_int_fsync(fio);
952     gmx_fio_unlock(fio);
953
954     return rc;
955 }
956
957
958
959 t_fileio *gmx_fio_all_output_fsync(void)
960 {
961     t_fileio *ret = NULL;
962     t_fileio *cur;
963
964     cur = gmx_fio_get_first();
965     while (cur)
966     {
967         /* skip debug files (shoud be the only iFTP==efNR) */
968         if (cur->bOpen &&
969             !cur->bRead &&
970             !cur->bStdio &&
971             cur->iFTP != efNR)
972         {
973             /* if any of them fails, return failure code */
974             int rc = gmx_fio_int_fsync(cur);
975             if (rc != 0 && !ret)
976             {
977                 ret = cur;
978             }
979         }
980         cur = gmx_fio_get_next(cur);
981     }
982
983     /* in addition, we force these to be written out too, if they're being
984        redirected. We don't check for errors because errors most likely mean
985        that they're not redirected. */
986     fflush(stdout);
987     fflush(stderr);
988 #if (defined(HAVE_FSYNC))
989     /* again, fahcore defines HAVE_FSYNC and fsync() */
990     fsync(STDOUT_FILENO);
991     fsync(STDERR_FILENO);
992 #endif
993
994     return ret;
995 }
996
997
998 gmx_off_t gmx_fio_ftell(t_fileio* fio)
999 {
1000     gmx_off_t ret = 0;
1001
1002     gmx_fio_lock(fio);
1003     if (fio->fp)
1004     {
1005         ret = gmx_ftell(fio->fp);
1006     }
1007     gmx_fio_unlock(fio);
1008     return ret;
1009 }
1010
1011 int gmx_fio_seek(t_fileio* fio, gmx_off_t fpos)
1012 {
1013     int rc;
1014
1015     gmx_fio_lock(fio);
1016     if (fio->fp)
1017     {
1018         rc = gmx_fseek(fio->fp, fpos, SEEK_SET);
1019     }
1020     else
1021     {
1022         gmx_file(fio->fn);
1023         rc = -1;
1024     }
1025     gmx_fio_unlock(fio);
1026     return rc;
1027 }
1028
1029 FILE *gmx_fio_getfp(t_fileio *fio)
1030 {
1031     FILE *ret = NULL;
1032
1033     gmx_fio_lock(fio);
1034     if (fio->fp)
1035     {
1036         ret = fio->fp;
1037     }
1038     gmx_fio_unlock(fio);
1039     return ret;
1040 }
1041
1042 XDR *gmx_fio_getxdr(t_fileio* fio)
1043 {
1044     XDR *ret = NULL;
1045
1046     gmx_fio_lock(fio);
1047     if (fio->xdr)
1048     {
1049         ret = fio->xdr;
1050     }
1051     gmx_fio_unlock(fio);
1052
1053     return ret;
1054 }
1055
1056 gmx_bool gmx_fio_getread(t_fileio* fio)
1057 {
1058     gmx_bool ret;
1059
1060     gmx_fio_lock(fio);
1061     ret = fio->bRead;
1062     gmx_fio_unlock(fio);
1063
1064     return ret;
1065 }
1066
1067 int xtc_seek_frame(t_fileio *fio, int frame, int natoms)
1068 {
1069     int ret;
1070
1071     gmx_fio_lock(fio);
1072     ret = xdr_xtc_seek_frame(frame, fio->fp, fio->xdr, natoms);
1073     gmx_fio_unlock(fio);
1074
1075     return ret;
1076 }
1077
1078 int xtc_seek_time(t_fileio *fio, real time, int natoms, gmx_bool bSeekForwardOnly)
1079 {
1080     int ret;
1081
1082     gmx_fio_lock(fio);
1083     ret = xdr_xtc_seek_time(time, fio->fp, fio->xdr, natoms, bSeekForwardOnly);
1084     gmx_fio_unlock(fio);
1085
1086     return ret;
1087 }