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