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