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