Merge branch 'release-4-6'
[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, efTNG, efMTX, efCPT };
88 static const int ftpASC[] =
89 { efTPA, efGRO, efPDB };
90 static const int ftpBIN[] =
91 { efTPB, efTRJ, efTNG };
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             if (fn2ftp(fn) == efTNG)
517             {
518                 gmx_incons("gmx_fio_open may not be used to open TNG files");
519             }
520             /* Open the file */
521             fio->fp = ffopen(fn, newmode);
522
523             /* determine the XDR direction */
524             if (newmode[0] == 'w' || newmode[0] == 'a')
525             {
526                 fio->xdrmode = XDR_ENCODE;
527             }
528             else
529             {
530                 fio->xdrmode = XDR_DECODE;
531             }
532
533             snew(fio->xdr, 1);
534             xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
535         }
536         else
537         {
538             /* If it is not, open it as a regular file */
539             fio->fp = ffopen(fn, newmode);
540         }
541
542         /* for appending seek to end of file to make sure ftell gives correct position
543          * important for checkpointing */
544         if (newmode[0] == 'a')
545         {
546             gmx_fseek(fio->fp, 0, SEEK_END);
547         }
548     }
549     else
550     {
551         /* Use stdin/stdout for I/O */
552         fio->iFTP   = efTPA;
553         fio->fp     = bRead ? stdin : stdout;
554         fio->fn     = strdup("STDIO");
555         fio->bStdio = TRUE;
556     }
557     fio->bRead             = bRead;
558     fio->bReadWrite        = bReadWrite;
559     fio->bDouble           = (sizeof(real) == sizeof(double));
560     fio->bDebug            = FALSE;
561     fio->bOpen             = TRUE;
562
563     /* set the reader/writer functions */
564     gmx_fio_set_iotype(fio);
565
566     /* and now insert this file into the list of open files. */
567     gmx_fio_insert(fio);
568     return fio;
569 }
570
571 static int gmx_fio_close_locked(t_fileio *fio)
572 {
573     int rc = 0;
574
575     if (!fio->bOpen)
576     {
577         gmx_fatal(FARGS, "File %s closed twice!\n", fio->fn);
578     }
579
580     if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
581     {
582         xdr_destroy(fio->xdr);
583         sfree(fio->xdr);
584     }
585
586     /* Don't close stdin and stdout! */
587     if (!fio->bStdio && fio->fp != NULL)
588     {
589         rc = ffclose(fio->fp); /* fclose returns 0 if happy */
590
591     }
592     fio->bOpen = FALSE;
593
594     return rc;
595 }
596
597 int gmx_fio_close(t_fileio *fio)
598 {
599     int rc = 0;
600
601     /* first lock the big open_files mutex. */
602     /* We don't want two processes operating on the list at the same time */
603     tMPI_Thread_mutex_lock(&open_file_mutex);
604
605     if (fio->iFTP == efTNG)
606     {
607         gmx_incons("gmx_fio_close should not be called on a TNG file");
608     }
609     gmx_fio_lock(fio);
610     /* first remove it from the list */
611     gmx_fio_remove(fio);
612     rc = gmx_fio_close_locked(fio);
613     gmx_fio_unlock(fio);
614
615     sfree(fio->fn);
616     sfree(fio);
617
618     tMPI_Thread_mutex_unlock(&open_file_mutex);
619
620     return rc;
621 }
622
623 /* close only fp but keep FIO entry. */
624 int gmx_fio_fp_close(t_fileio *fio)
625 {
626     int rc = 0;
627     gmx_fio_lock(fio);
628     if (!in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR) && !fio->bStdio)
629     {
630         rc      = ffclose(fio->fp); /* fclose returns 0 if happy */
631         fio->fp = NULL;
632     }
633     gmx_fio_unlock(fio);
634
635     return rc;
636 }
637
638 FILE * gmx_fio_fopen(const char *fn, const char *mode)
639 {
640     FILE     *fp, *ret;
641     t_fileio *fio;
642
643     fio = gmx_fio_open(fn, mode);
644     gmx_fio_lock(fio);
645     ret = fio->fp;
646     gmx_fio_unlock(fio);
647
648     return ret;
649 }
650
651 int gmx_fio_fclose(FILE *fp)
652 {
653     t_fileio *cur;
654     t_fileio *found = NULL;
655     int       rc    = -1;
656
657     cur = gmx_fio_get_first();
658     while (cur)
659     {
660         if (cur->fp == fp)
661         {
662             rc = gmx_fio_close_locked(cur);
663             gmx_fio_remove(cur);
664             gmx_fio_stop_getting_next(cur);
665             sfree(cur->fn);
666             sfree(cur);
667             break;
668         }
669         cur = gmx_fio_get_next(cur);
670     }
671
672     return rc;
673 }
674
675 /* internal variant of get_file_md5 that operates on a locked file */
676 static int gmx_fio_int_get_file_md5(t_fileio *fio, gmx_off_t offset,
677                                     unsigned char digest[])
678 {
679     /*1MB: large size important to catch almost identical files */
680 #define CPT_CHK_LEN  1048576
681     md5_state_t   state;
682     unsigned char buf[CPT_CHK_LEN];
683     gmx_off_t     read_len;
684     gmx_off_t     seek_offset;
685     int           ret = -1;
686
687     seek_offset = offset - CPT_CHK_LEN;
688     if (seek_offset < 0)
689     {
690         seek_offset = 0;
691     }
692     read_len = offset - seek_offset;
693
694
695     if (fio->fp && fio->bReadWrite)
696     {
697         ret = gmx_fseek(fio->fp, seek_offset, SEEK_SET);
698         if (ret)
699         {
700             gmx_fseek(fio->fp, 0, SEEK_END);
701         }
702     }
703     if (ret) /*either no fp, not readwrite, or fseek not successful */
704     {
705         return -1;
706     }
707
708     /* the read puts the file position back to offset */
709     if ((gmx_off_t)fread(buf, 1, read_len, fio->fp) != read_len)
710     {
711         /* not fatal: md5sum check to prevent overwriting files
712          * works (less safe) without
713          * */
714         if (ferror(fio->fp))
715         {
716             fprintf(stderr, "\nTrying to get md5sum: %s: %s\n", fio->fn,
717                     strerror(errno));
718         }
719         else if (feof(fio->fp))
720         {
721             /*
722              * For long runs that checkpoint frequently but write e.g. logs
723              * infrequently we don't want to issue lots of warnings before we
724              * have written anything to the log.
725              */
726             if (0)
727             {
728                 fprintf(stderr, "\nTrying to get md5sum: EOF: %s\n", fio->fn);
729             }
730         }
731         else
732         {
733             fprintf(
734                     stderr,
735                     "\nTrying to get md5sum: Unknown reason for short read: %s\n",
736                     fio->fn);
737         }
738
739         gmx_fseek(fio->fp, 0, SEEK_END);
740
741         ret = -1;
742     }
743     gmx_fseek(fio->fp, 0, SEEK_END); /*is already at end, but under windows
744                                         it gives problems otherwise*/
745
746     if (debug)
747     {
748         fprintf(debug, "chksum %s readlen %ld\n", fio->fn, (long int)read_len);
749     }
750
751     if (!ret)
752     {
753         md5_init(&state);
754         md5_append(&state, buf, read_len);
755         md5_finish(&state, digest);
756         return read_len;
757     }
758     else
759     {
760         return ret;
761     }
762 }
763
764
765 /*
766  * fio: file to compute md5 for
767  * offset: starting pointer of region to use for md5
768  * digest: return array of md5 sum
769  */
770 int gmx_fio_get_file_md5(t_fileio *fio, gmx_off_t offset,
771                          unsigned char digest[])
772 {
773     int ret;
774
775     gmx_fio_lock(fio);
776     ret = gmx_fio_int_get_file_md5(fio, offset, digest);
777     gmx_fio_unlock(fio);
778
779     return ret;
780 }
781
782 /* The fio_mutex should ALWAYS be locked when this function is called */
783 static int gmx_fio_int_get_file_position(t_fileio *fio, gmx_off_t *offset)
784 {
785     char buf[STRLEN];
786
787     /* Flush the file, so we are sure it is written */
788     if (gmx_fio_int_flush(fio))
789     {
790         char buf[STRLEN];
791         sprintf(
792                 buf,
793                 "Cannot write file '%s'; maybe you are out of disk space?",
794                 fio->fn);
795         gmx_file(buf);
796     }
797
798     /* We cannot count on XDR being able to write 64-bit integers,
799        so separate into high/low 32-bit values.
800        In case the filesystem has 128-bit offsets we only care
801        about the first 64 bits - we'll have to fix
802        this when exabyte-size output files are common...
803      */
804     *offset = gmx_ftell(fio->fp);
805
806     return 0;
807 }
808
809 int gmx_fio_get_output_file_positions(gmx_file_position_t **p_outputfiles,
810                                       int                  *p_nfiles)
811 {
812     int                   i, nfiles, rc, nalloc;
813     int                   pos_hi, pos_lo;
814     long                  pos;
815     gmx_file_position_t * outputfiles;
816     char                  buf[STRLEN];
817     t_fileio             *cur;
818
819     nfiles = 0;
820
821     /* pre-allocate 100 files */
822     nalloc = 100;
823     snew(outputfiles, nalloc);
824
825     cur = gmx_fio_get_first();
826     while (cur)
827     {
828         /* Skip the checkpoint files themselves, since they could be open when
829            we call this routine... */
830         /* also skip debug files (shoud be the only iFTP==efNR) */
831         if (cur->bOpen &&
832             !cur->bRead &&
833             !cur->bStdio &&
834             cur->iFTP != efCPT &&
835             cur->iFTP != efNR)
836         {
837             int ret;
838             /* This is an output file currently open for writing, add it */
839             if (nfiles == nalloc)
840             {
841                 nalloc += 100;
842                 srenew(outputfiles, nalloc);
843             }
844
845             strncpy(outputfiles[nfiles].filename, cur->fn, STRLEN - 1);
846
847             /* Get the file position */
848             gmx_fio_int_get_file_position(cur, &outputfiles[nfiles].offset);
849 #ifndef GMX_FAHCORE
850             outputfiles[nfiles].chksum_size
851                 = gmx_fio_int_get_file_md5(cur,
852                                            outputfiles[nfiles].offset,
853                                            outputfiles[nfiles].chksum);
854 #endif
855             nfiles++;
856         }
857
858         cur = gmx_fio_get_next(cur);
859     }
860     *p_nfiles      = nfiles;
861     *p_outputfiles = outputfiles;
862
863     return 0;
864 }
865
866
867 void gmx_fio_checktype(t_fileio *fio)
868 {
869     if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR))
870     {
871         return;
872     }
873     else if (in_ftpset(fio->iFTP, asize(ftpASC), ftpASC))
874     {
875         return;
876     }
877     else if (in_ftpset(fio->iFTP, asize(ftpBIN), ftpBIN))
878     {
879         return;
880     }
881 #ifdef HAVE_XMl
882     else if (in_ftpset(fio->iFTP, asize(ftpXML), ftpXML))
883     {
884         return;
885     }
886 #endif
887     else
888     {
889         gmx_fatal(FARGS, "Can not read/write topologies to file type %s",
890                   ftp2ext(fio->iFTP));
891     }
892
893 }
894
895
896 void gmx_fio_setprecision(t_fileio *fio, gmx_bool bDouble)
897 {
898     gmx_fio_lock(fio);
899     fio->bDouble = bDouble;
900     gmx_fio_unlock(fio);
901 }
902
903 gmx_bool gmx_fio_getdebug(t_fileio *fio)
904 {
905     gmx_bool ret;
906
907     gmx_fio_lock(fio);
908     ret = fio->bDebug;
909     gmx_fio_unlock(fio);
910
911     return ret;
912 }
913
914 void gmx_fio_setdebug(t_fileio *fio, gmx_bool bDebug)
915 {
916     gmx_fio_lock(fio);
917     fio->bDebug = bDebug;
918     gmx_fio_unlock(fio);
919 }
920
921 char *gmx_fio_getname(t_fileio *fio)
922 {
923     char *ret;
924     gmx_fio_lock(fio);
925     ret = fio->fn;
926     gmx_fio_unlock(fio);
927
928     return ret;
929 }
930
931 int gmx_fio_getftp(t_fileio* fio)
932 {
933     int ret;
934
935     gmx_fio_lock(fio);
936     ret = fio->iFTP;
937     gmx_fio_unlock(fio);
938
939     return ret;
940 }
941
942 void gmx_fio_rewind(t_fileio* fio)
943 {
944     gmx_fio_lock(fio);
945
946     if (fio->xdr)
947     {
948         xdr_destroy(fio->xdr);
949         frewind(fio->fp);
950         xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode);
951     }
952     else
953     {
954         frewind(fio->fp);
955     }
956     gmx_fio_unlock(fio);
957 }
958
959
960 int gmx_fio_flush(t_fileio* fio)
961 {
962     int ret;
963
964     gmx_fio_lock(fio);
965     ret = gmx_fio_int_flush(fio);
966     gmx_fio_unlock(fio);
967
968     return ret;
969 }
970
971
972
973 static int gmx_fio_int_fsync(t_fileio *fio)
974 {
975     int rc    = 0;
976     int filen = -1;
977
978
979     if (fio->fp)
980     {
981         rc = gmx_fsync(fio->fp);
982     }
983     else if (fio->xdr) /* this should normally not happen */
984     {
985         rc = gmx_fsync((FILE*) fio->xdr->x_private);
986         /* ^ is this actually OK? */
987     }
988
989     return rc;
990 }
991
992
993 int gmx_fio_fsync(t_fileio *fio)
994 {
995     int rc;
996
997     gmx_fio_lock(fio);
998     rc = gmx_fio_int_fsync(fio);
999     gmx_fio_unlock(fio);
1000
1001     return rc;
1002 }
1003
1004
1005
1006 t_fileio *gmx_fio_all_output_fsync(void)
1007 {
1008     t_fileio *ret = NULL;
1009     t_fileio *cur;
1010
1011     cur = gmx_fio_get_first();
1012     while (cur)
1013     {
1014         /* skip debug files (shoud be the only iFTP==efNR) */
1015         if (cur->bOpen &&
1016             !cur->bRead &&
1017             !cur->bStdio &&
1018             cur->iFTP != efNR)
1019         {
1020             /* if any of them fails, return failure code */
1021             int rc = gmx_fio_int_fsync(cur);
1022             if (rc != 0 && !ret)
1023             {
1024                 ret = cur;
1025             }
1026         }
1027         cur = gmx_fio_get_next(cur);
1028     }
1029
1030     /* in addition, we force these to be written out too, if they're being
1031        redirected. We don't check for errors because errors most likely mean
1032        that they're not redirected. */
1033     fflush(stdout);
1034     fflush(stderr);
1035 #if (defined(HAVE_FSYNC))
1036     /* again, fahcore defines HAVE_FSYNC and fsync() */
1037     fsync(STDOUT_FILENO);
1038     fsync(STDERR_FILENO);
1039 #endif
1040
1041     return ret;
1042 }
1043
1044
1045 gmx_off_t gmx_fio_ftell(t_fileio* fio)
1046 {
1047     gmx_off_t ret = 0;
1048
1049     gmx_fio_lock(fio);
1050     if (fio->fp)
1051     {
1052         ret = gmx_ftell(fio->fp);
1053     }
1054     gmx_fio_unlock(fio);
1055     return ret;
1056 }
1057
1058 int gmx_fio_seek(t_fileio* fio, gmx_off_t fpos)
1059 {
1060     int rc;
1061
1062     gmx_fio_lock(fio);
1063     if (fio->fp)
1064     {
1065         rc = gmx_fseek(fio->fp, fpos, SEEK_SET);
1066     }
1067     else
1068     {
1069         gmx_file(fio->fn);
1070         rc = -1;
1071     }
1072     gmx_fio_unlock(fio);
1073     return rc;
1074 }
1075
1076 FILE *gmx_fio_getfp(t_fileio *fio)
1077 {
1078     FILE *ret = NULL;
1079
1080     gmx_fio_lock(fio);
1081     if (fio->fp)
1082     {
1083         ret = fio->fp;
1084     }
1085     gmx_fio_unlock(fio);
1086     return ret;
1087 }
1088
1089 XDR *gmx_fio_getxdr(t_fileio* fio)
1090 {
1091     XDR *ret = NULL;
1092
1093     gmx_fio_lock(fio);
1094     if (fio->xdr)
1095     {
1096         ret = fio->xdr;
1097     }
1098     gmx_fio_unlock(fio);
1099
1100     return ret;
1101 }
1102
1103 gmx_bool gmx_fio_getread(t_fileio* fio)
1104 {
1105     gmx_bool ret;
1106
1107     gmx_fio_lock(fio);
1108     ret = fio->bRead;
1109     gmx_fio_unlock(fio);
1110
1111     return ret;
1112 }
1113
1114 int xtc_seek_frame(t_fileio *fio, int frame, int natoms)
1115 {
1116     int ret;
1117
1118     gmx_fio_lock(fio);
1119     ret = xdr_xtc_seek_frame(frame, fio->fp, fio->xdr, natoms);
1120     gmx_fio_unlock(fio);
1121
1122     return ret;
1123 }
1124
1125 int xtc_seek_time(t_fileio *fio, real time, int natoms, gmx_bool bSeekForwardOnly)
1126 {
1127     int ret;
1128
1129     gmx_fio_lock(fio);
1130     ret = xdr_xtc_seek_time(time, fio->fp, fio->xdr, natoms, bSeekForwardOnly);
1131     gmx_fio_unlock(fio);
1132
1133     return ret;
1134 }