Remove all unnecessary HAVE_CONFIG_H
[alexxy/gromacs.git] / src / gromacs / utility / futil.cpp
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 "gromacs/utility/futil.h"
38
39 #include "config.h"
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #include <fcntl.h>
48
49 #ifdef HAVE_DIRENT_H
50 /* POSIX */
51 #include <dirent.h>
52 #endif
53
54 #ifdef HAVE_UNISTD_H
55 #include <unistd.h>
56 #endif
57
58 #ifdef GMX_NATIVE_WINDOWS
59 #include <direct.h>
60 #include <io.h>
61 #endif
62
63 /* Windows file stuff, only necessary for visual studio */
64 #ifdef _MSC_VER
65 #include <windows.h>
66 #endif
67
68 #include "thread_mpi/threads.h"
69
70 #include "gromacs/utility/cstringutil.h"
71 #include "gromacs/utility/exceptions.h"
72 #include "gromacs/utility/fatalerror.h"
73 #include "gromacs/utility/path.h"
74 #include "gromacs/utility/programcontext.h"
75 #include "gromacs/utility/smalloc.h"
76 #include "gromacs/utility/stringutil.h"
77
78 /* we keep a linked list of all files opened through pipes (i.e.
79    compressed or .gzipped files. This way we can distinguish between them
80    without having to change the semantics of reading from/writing to files)
81  */
82 typedef struct t_pstack {
83     FILE            *fp;
84     struct t_pstack *prev;
85 } t_pstack;
86
87 static t_pstack    *pstack      = NULL;
88 static bool         bUnbuffered = false;
89
90 /* this linked list is an intrinsically globally shared object, so we have
91    to protect it with mutexes */
92 static tMPI_Thread_mutex_t pstack_mutex = TMPI_THREAD_MUTEX_INITIALIZER;
93
94 void gmx_disable_file_buffering(void)
95 {
96     bUnbuffered = true;
97 }
98
99 void push_ps(FILE *fp)
100 {
101     t_pstack *ps;
102
103     tMPI_Thread_mutex_lock(&pstack_mutex);
104
105     snew(ps, 1);
106     ps->fp   = fp;
107     ps->prev = pstack;
108     pstack   = ps;
109
110     tMPI_Thread_mutex_unlock(&pstack_mutex);
111 }
112
113 #ifdef GMX_FAHCORE
114 /* don't use pipes!*/
115 #define popen fah_fopen
116 #define pclose fah_fclose
117 #define SKIP_FFOPS 1
118 #else
119 #ifdef gmx_ffclose
120 #undef gmx_ffclose
121 #endif
122 #if (!defined(HAVE_PIPES) && !defined(__native_client__))
123 static FILE *popen(const char *nm, const char *mode)
124 {
125     gmx_impl("Sorry no pipes...");
126
127     return NULL;
128 }
129
130 static int pclose(FILE *fp)
131 {
132     gmx_impl("Sorry no pipes...");
133
134     return 0;
135 }
136 #endif /* !defined(HAVE_PIPES) && !defined(__native_client__) */
137 #endif /* GMX_FAHCORE */
138
139 int gmx_ffclose(FILE *fp)
140 {
141 #ifdef SKIP_FFOPS
142     return fclose(fp);
143 #else
144     t_pstack *ps, *tmp;
145     int       ret = 0;
146
147     tMPI_Thread_mutex_lock(&pstack_mutex);
148
149     ps = pstack;
150     if (ps == NULL)
151     {
152         if (fp != NULL)
153         {
154             ret = fclose(fp);
155         }
156     }
157     else if (ps->fp == fp)
158     {
159         if (fp != NULL)
160         {
161             ret = pclose(fp);
162         }
163         pstack = pstack->prev;
164         sfree(ps);
165     }
166     else
167     {
168         while ((ps->prev != NULL) && (ps->prev->fp != fp))
169         {
170             ps = ps->prev;
171         }
172         if ((ps->prev != NULL) && ps->prev->fp == fp)
173         {
174             if (ps->prev->fp != NULL)
175             {
176                 ret = pclose(ps->prev->fp);
177             }
178             tmp      = ps->prev;
179             ps->prev = ps->prev->prev;
180             sfree(tmp);
181         }
182         else
183         {
184             if (fp != NULL)
185             {
186                 ret = fclose(fp);
187             }
188         }
189     }
190
191     tMPI_Thread_mutex_unlock(&pstack_mutex);
192     return ret;
193 #endif
194 }
195
196
197 void frewind(FILE *fp)
198 {
199     tMPI_Thread_mutex_lock(&pstack_mutex);
200
201     t_pstack *ps = pstack;
202     while (ps != NULL)
203     {
204         if (ps->fp == fp)
205         {
206             fprintf(stderr, "Cannot rewind compressed file!\n");
207             tMPI_Thread_mutex_unlock(&pstack_mutex);
208             return;
209         }
210         ps = ps->prev;
211     }
212     rewind(fp);
213     tMPI_Thread_mutex_unlock(&pstack_mutex);
214 }
215
216 int gmx_fseek(FILE *stream, gmx_off_t offset, int whence)
217 {
218 #ifdef HAVE_FSEEKO
219     return fseeko(stream, offset, whence);
220 #else
221 #ifdef HAVE__FSEEKI64
222     return _fseeki64(stream, offset, whence);
223 #else
224     return fseek(stream, offset, whence);
225 #endif
226 #endif
227 }
228
229 gmx_off_t gmx_ftell(FILE *stream)
230 {
231 #ifdef HAVE_FSEEKO
232     return ftello(stream);
233 #else
234 #ifdef HAVE__FSEEKI64
235     return _ftelli64(stream);
236 #else
237     return ftell(stream);
238 #endif
239 #endif
240 }
241
242 static FILE *uncompress(const char *fn, const char *mode)
243 {
244     FILE *fp;
245     char  buf[256];
246
247     sprintf(buf, "uncompress -c < %s", fn);
248     fprintf(stderr, "Going to execute '%s'\n", buf);
249     if ((fp = popen(buf, mode)) == NULL)
250     {
251         gmx_open(fn);
252     }
253     push_ps(fp);
254
255     return fp;
256 }
257
258 static FILE *gunzip(const char *fn, const char *mode)
259 {
260     FILE *fp;
261     char  buf[256];
262
263     sprintf(buf, "gunzip -c < %s", fn);
264     fprintf(stderr, "Going to execute '%s'\n", buf);
265     if ((fp = popen(buf, mode)) == NULL)
266     {
267         gmx_open(fn);
268     }
269     push_ps(fp);
270
271     return fp;
272 }
273
274 gmx_bool gmx_fexist(const char *fname)
275 {
276     FILE *test;
277
278     if (fname == NULL)
279     {
280         return FALSE;
281     }
282     test = fopen(fname, "r");
283     if (test == NULL)
284     {
285         /*Windows doesn't allow fopen of directory - so we need to check this seperately */
286         #ifdef GMX_NATIVE_WINDOWS
287         DWORD attr = GetFileAttributes(fname);
288         return (attr != INVALID_FILE_ATTRIBUTES) && (attr & FILE_ATTRIBUTE_DIRECTORY);
289         #else
290         return FALSE;
291         #endif
292     }
293     else
294     {
295         fclose(test);
296         return TRUE;
297     }
298 }
299
300 static char *backup_fn(const char *file, int count_max)
301 {
302     /* Use a reasonably low value for countmax; we might
303      * generate 4-5 files in each round, and we dont
304      * want to hit directory limits of 1024 or 2048 files.
305      */
306 #define COUNTMAX 99
307     int          i, count = 1;
308     char        *directory, *fn;
309     char        *buf;
310
311     if (count_max == -1)
312     {
313         count_max = COUNTMAX;
314     }
315
316     smalloc(buf, GMX_PATH_MAX);
317
318     for (i = strlen(file)-1; ((i > 0) && (file[i] != DIR_SEPARATOR)); i--)
319     {
320         ;
321     }
322     /* Must check whether i > 0, i.e. whether there is a directory
323      * in the file name. In that case we overwrite the / sign with
324      * a '\0' to end the directory string .
325      */
326     if (i > 0)
327     {
328         directory    = gmx_strdup(file);
329         directory[i] = '\0';
330         fn           = gmx_strdup(file+i+1);
331     }
332     else
333     {
334         directory    = gmx_strdup(".");
335         fn           = gmx_strdup(file);
336     }
337     do
338     {
339         sprintf(buf, "%s/#%s.%d#", directory, fn, count);
340         count++;
341     }
342     while ((count <= count_max) && gmx_fexist(buf));
343
344     /* Arbitrarily bail out */
345     if (count > count_max)
346     {
347         gmx_fatal(FARGS, "Won't make more than %d backups of %s for you.\n"
348                   "The env.var. GMX_MAXBACKUP controls this maximum, -1 disables backups.",
349                   count_max, fn);
350     }
351
352     sfree(directory);
353     sfree(fn);
354
355     return buf;
356 }
357
358 gmx_bool make_backup(const char * name)
359 {
360     char * env;
361     int    count_max;
362     char * backup;
363
364 #ifdef GMX_FAHCORE
365     return FALSE; /* skip making backups */
366 #else
367
368     if (gmx_fexist(name))
369     {
370         env = getenv("GMX_MAXBACKUP");
371         if (env != NULL)
372         {
373             count_max = strtol(env, NULL, 10);
374             if (count_max == -1)
375             {
376                 /* Do not make backups and possibly overwrite old files */
377                 return TRUE;
378             }
379         }
380         else
381         {
382             /* Use the default maximum */
383             count_max = -1;
384         }
385         backup = backup_fn(name, count_max);
386         if (rename(name, backup) == 0)
387         {
388             fprintf(stderr, "\nBack Off! I just backed up %s to %s\n",
389                     name, backup);
390         }
391         else
392         {
393             fprintf(stderr, "Sorry couldn't backup %s to %s\n", name, backup);
394             return FALSE;
395         }
396         sfree(backup);
397     }
398     return TRUE;
399 #endif
400 }
401
402 FILE *gmx_ffopen(const char *file, const char *mode)
403 {
404 #ifdef SKIP_FFOPS
405     return fopen(file, mode);
406 #else
407     FILE    *ff = NULL;
408     char     buf[256], *bufsize = 0, *ptr;
409     gmx_bool bRead;
410     int      bs;
411
412     if (file == NULL)
413     {
414         return NULL;
415     }
416
417     if (mode[0] == 'w')
418     {
419         make_backup(file);
420     }
421     where();
422
423     bRead = (mode[0] == 'r' && mode[1] != '+');
424     strcpy(buf, file);
425     if (!bRead || gmx_fexist(buf))
426     {
427         if ((ff = fopen(buf, mode)) == NULL)
428         {
429             gmx_file(buf);
430         }
431         where();
432         /* Check whether we should be using buffering (default) or not
433          * (for debugging)
434          */
435         if (bUnbuffered || ((bufsize = getenv("GMX_LOG_BUFFER")) != NULL))
436         {
437             /* Check whether to use completely unbuffered */
438             if (bUnbuffered)
439             {
440                 bs = 0;
441             }
442             else
443             {
444                 bs = strtol(bufsize, NULL, 10);
445             }
446             if (bs <= 0)
447             {
448                 setbuf(ff, NULL);
449             }
450             else
451             {
452                 snew(ptr, bs+8);
453                 if (setvbuf(ff, ptr, _IOFBF, bs) != 0)
454                 {
455                     gmx_file("Buffering File");
456                 }
457             }
458         }
459         where();
460     }
461     else
462     {
463         sprintf(buf, "%s.Z", file);
464         if (gmx_fexist(buf))
465         {
466             ff = uncompress(buf, mode);
467         }
468         else
469         {
470             sprintf(buf, "%s.gz", file);
471             if (gmx_fexist(buf))
472             {
473                 ff = gunzip(buf, mode);
474             }
475             else
476             {
477                 gmx_file(file);
478             }
479         }
480     }
481     return ff;
482 #endif
483 }
484
485 /* Our own implementation of dirent-like functionality to scan directories. */
486 struct gmx_directory
487 {
488 #ifdef HAVE_DIRENT_H
489     DIR  *               dirent_handle;
490 #elif (defined GMX_NATIVE_WINDOWS)
491     intptr_t             windows_handle;
492     struct _finddata_t   finddata;
493     int                  first;
494 #else
495     int                  dummy;
496 #endif
497 };
498
499
500 int
501 gmx_directory_open(gmx_directory_t *p_gmxdir, const char *dirname)
502 {
503     struct gmx_directory *  gmxdir;
504     int                     rc;
505
506     snew(gmxdir, 1);
507
508     *p_gmxdir = gmxdir;
509
510 #ifdef HAVE_DIRENT_H
511     if ( (gmxdir->dirent_handle = opendir(dirname)) != NULL)
512     {
513         rc = 0;
514     }
515     else
516     {
517         sfree(gmxdir);
518         *p_gmxdir = NULL;
519         rc        = EINVAL;
520     }
521 #elif (defined GMX_NATIVE_WINDOWS)
522
523     if (dirname != NULL && strlen(dirname) > 0)
524     {
525         char *     tmpname;
526         int        len;
527
528         len = strlen(dirname);
529         snew(tmpname, len+3);
530
531         strncpy(tmpname, dirname, len+1);
532
533         /* Remove possible trailing directory separator */
534         if (tmpname[len] == '/' || tmpname[len] == '\\')
535         {
536             tmpname[len] = '\0';
537         }
538
539         /* Add wildcard */
540         strcat(tmpname, "/*");
541
542         gmxdir->first = 1;
543         if ( (gmxdir->windows_handle = _findfirst(tmpname, &gmxdir->finddata)) > 0L)
544         {
545             rc = 0;
546         }
547         else
548         {
549             if (errno == EINVAL)
550             {
551                 sfree(gmxdir);
552                 *p_gmxdir = NULL;
553                 rc        = EINVAL;
554             }
555             else
556             {
557                 rc        = 0;
558             }
559         }
560     }
561     else
562     {
563         rc = EINVAL;
564     }
565 #else
566     gmx_fatal(FARGS,
567               "Source compiled without POSIX dirent or windows support - cannot scan directories.\n"
568               "In the very unlikely event this is not a compile-time mistake you could consider\n"
569               "implementing support for your platform in futil.c, but contact the developers\n"
570               "to make sure it's really necessary!\n");
571     rc = -1;
572 #endif
573     return rc;
574 }
575
576
577 int
578 gmx_directory_nextfile(gmx_directory_t gmxdir, char *name, int maxlength_name)
579 {
580     int                     rc;
581
582 #ifdef HAVE_DIRENT_H
583
584     struct dirent *         direntp_large;
585     struct dirent *         p;
586
587
588     if (gmxdir != NULL && gmxdir->dirent_handle != NULL)
589     {
590         /* On some platforms no space is present for d_name in dirent.
591          * Since d_name is guaranteed to be the last entry, allocating
592          * extra space for dirent will allow more size for d_name.
593          * GMX_MAX_PATH should always be >= the max possible d_name.
594          */
595         smalloc(direntp_large, sizeof(*direntp_large) + GMX_PATH_MAX);
596         rc = readdir_r(gmxdir->dirent_handle, direntp_large, &p);
597
598         if (p != NULL && rc == 0)
599         {
600             strncpy(name, direntp_large->d_name, maxlength_name);
601         }
602         else
603         {
604             name[0] = '\0';
605             rc      = ENOENT;
606         }
607         sfree(direntp_large);
608     }
609     else
610     {
611         name[0] = '\0';
612         rc      = EINVAL;
613     }
614
615 #elif (defined GMX_NATIVE_WINDOWS)
616
617     if (gmxdir != NULL)
618     {
619         if (gmxdir->windows_handle <= 0)
620         {
621
622             name[0] = '\0';
623             rc      = ENOENT;
624         }
625         else if (gmxdir->first == 1)
626         {
627             strncpy(name, gmxdir->finddata.name, maxlength_name);
628             rc            = 0;
629             gmxdir->first = 0;
630         }
631         else
632         {
633             if (_findnext(gmxdir->windows_handle, &gmxdir->finddata) == 0)
634             {
635                 strncpy(name, gmxdir->finddata.name, maxlength_name);
636                 rc      = 0;
637             }
638             else
639             {
640                 name[0] = '\0';
641                 rc      = ENOENT;
642             }
643         }
644     }
645
646 #else
647     gmx_fatal(FARGS,
648               "Source compiled without POSIX dirent or windows support - cannot scan directories.\n");
649     rc = -1;
650 #endif
651     return rc;
652 }
653
654
655 int
656 gmx_directory_close(gmx_directory_t gmxdir)
657 {
658     int                     rc;
659 #ifdef HAVE_DIRENT_H
660     rc = (gmxdir != NULL) ? closedir(gmxdir->dirent_handle) : EINVAL;
661 #elif (defined GMX_NATIVE_WINDOWS)
662     rc = (gmxdir != NULL) ? _findclose(gmxdir->windows_handle) : EINVAL;
663 #else
664     gmx_fatal(FARGS,
665               "Source compiled without POSIX dirent or windows support - cannot scan directories.\n");
666     rc = -1;
667 #endif
668
669     sfree(gmxdir);
670     return rc;
671 }
672
673
674 char *low_gmxlibfn(const char *file, gmx_bool bAddCWD, gmx_bool bFatal)
675 {
676     bool bEnvIsSet = false;
677     try
678     {
679         if (bAddCWD && gmx_fexist(file))
680         {
681             return gmx_strdup(file);
682         }
683         else
684         {
685             std::string  libpath;
686             // GMXLIB can be a path.
687             const char  *lib = getenv("GMXLIB");
688             if (lib != NULL)
689             {
690                 bEnvIsSet = true;
691                 libpath   = lib;
692             }
693             else
694             {
695                 libpath = gmx::getProgramContext().defaultLibraryDataPath();
696             }
697
698             std::vector<std::string>                 pathEntries;
699             gmx::Path::splitPathEnvironment(libpath, &pathEntries);
700             std::vector<std::string>::const_iterator i;
701             for (i = pathEntries.begin(); i != pathEntries.end(); ++i)
702             {
703                 std::string testPath = gmx::Path::join(*i, file);
704                 if (gmx::Path::exists(testPath))
705                 {
706                     return gmx_strdup(testPath.c_str());
707                 }
708             }
709         }
710     }
711     GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
712     if (bFatal)
713     {
714         if (bEnvIsSet)
715         {
716             gmx_fatal(FARGS,
717                       "Library file %s not found %sin your GMXLIB path.",
718                       file, bAddCWD ? "in current dir nor " : "");
719         }
720         else
721         {
722             gmx_fatal(FARGS,
723                       "Library file %s not found %sin default directories.\n"
724                       "(You can set the directories to search with the GMXLIB path variable)",
725                       file, bAddCWD ? "in current dir nor " : "");
726         }
727     }
728     return NULL;
729 }
730
731 FILE *low_libopen(const char *file, gmx_bool bFatal)
732 {
733     FILE *ff;
734     char *fn;
735
736     fn = low_gmxlibfn(file, TRUE, bFatal);
737
738     if (fn == NULL)
739     {
740         ff = NULL;
741     }
742     else
743     {
744         if (debug)
745         {
746             fprintf(debug, "Opening library file %s\n", fn);
747         }
748         ff = fopen(fn, "r");
749     }
750     sfree(fn);
751
752     return ff;
753 }
754
755 char *gmxlibfn(const char *file)
756 {
757     return low_gmxlibfn(file, TRUE, TRUE);
758 }
759
760 FILE *libopen(const char *file)
761 {
762     return low_libopen(file, TRUE);
763 }
764
765 void gmx_tmpnam(char *buf)
766 {
767     int i, len;
768
769     if ((len = strlen(buf)) < 7)
770     {
771         gmx_fatal(FARGS, "Buf passed to gmx_tmpnam must be at least 7 bytes long");
772     }
773     for (i = len-6; (i < len); i++)
774     {
775         buf[i] = 'X';
776     }
777     /* mktemp is dangerous and we should use mkstemp instead, but
778      * since windows doesnt support it we have to separate the cases.
779      * 20090307: mktemp deprecated, use iso c++ _mktemp instead.
780      */
781 #ifdef GMX_NATIVE_WINDOWS
782     _mktemp(buf);
783 #else
784     int fd = mkstemp(buf);
785
786     switch (fd)
787     {
788         case EINVAL:
789             gmx_fatal(FARGS, "Invalid template %s for mkstemp", buf);
790             break;
791         case EEXIST:
792             gmx_fatal(FARGS, "mkstemp created existing file", buf);
793             break;
794         case EACCES:
795             gmx_fatal(FARGS, "Permission denied for opening %s", buf);
796             break;
797         default:
798             break;
799     }
800     close(fd);
801 #endif
802     /* name in Buf should now be OK */
803 }
804
805 int gmx_file_rename(const char *oldname, const char *newname)
806 {
807 #ifndef GMX_NATIVE_WINDOWS
808     /* under unix, rename() is atomic (at least, it should be). */
809     return rename(oldname, newname);
810 #else
811     if (MoveFileEx(oldname, newname,
812                    MOVEFILE_REPLACE_EXISTING|MOVEFILE_WRITE_THROUGH))
813     {
814         return 0;
815     }
816     else
817     {
818         return 1;
819     }
820 #endif
821 }
822
823 int gmx_file_copy(const char *oldname, const char *newname, gmx_bool copy_if_empty)
824 {
825 /* the full copy buffer size: */
826 #define FILECOPY_BUFSIZE (1<<16)
827     FILE *in  = NULL;
828     FILE *out = NULL;
829     char *buf;
830
831     snew(buf, FILECOPY_BUFSIZE);
832
833     in = fopen(oldname, "rb");
834     if (!in)
835     {
836         goto error;
837     }
838
839     /* If we don't copy when empty, we postpone opening the file
840        until we're actually ready to write. */
841     if (copy_if_empty)
842     {
843         out = fopen(newname, "wb");
844         if (!out)
845         {
846             goto error;
847         }
848     }
849
850     while (!feof(in))
851     {
852         size_t nread;
853
854         nread = fread(buf, sizeof(char), FILECOPY_BUFSIZE, in);
855         if (nread > 0)
856         {
857             size_t ret;
858             if (!out)
859             {
860                 /* so this is where we open when copy_if_empty is false:
861                    here we know we read something. */
862                 out = fopen(newname, "wb");
863                 if (!out)
864                 {
865                     goto error;
866                 }
867             }
868             ret = fwrite(buf, sizeof(char), nread, out);
869             if (ret != nread)
870             {
871                 goto error;
872             }
873         }
874         if (ferror(in))
875         {
876             goto error;
877         }
878     }
879     sfree(buf);
880     fclose(in);
881     fclose(out);
882     return 0;
883 error:
884     sfree(buf);
885     if (in)
886     {
887         fclose(in);
888     }
889     if (out)
890     {
891         fclose(out);
892     }
893     return 1;
894 #undef FILECOPY_BUFSIZE
895 }
896
897
898 int gmx_fsync(FILE *fp)
899 {
900     int rc = 0;
901
902 #ifdef GMX_FAHCORE
903     /* the fahcore defines its own os-independent fsync */
904     rc = fah_fsync(fp);
905 #else /* GMX_FAHCORE */
906     {
907         int fn;
908
909         /* get the file number */
910 #if defined(HAVE_FILENO)
911         fn = fileno(fp);
912 #elif defined(HAVE__FILENO)
913         fn = _fileno(fp);
914 #else
915         fn = -1;
916 #endif
917
918         /* do the actual fsync */
919         if (fn >= 0)
920         {
921 #if (defined(HAVE_FSYNC))
922             rc = fsync(fn);
923 #elif (defined(HAVE__COMMIT))
924             rc = _commit(fn);
925 #endif
926         }
927     }
928 #endif /* GMX_FAHCORE */
929
930     /* We check for these error codes this way because POSIX requires them
931        to be defined, and using anything other than macros is unlikely: */
932 #ifdef EINTR
933     /* we don't want to report an error just because fsync() caught a signal.
934        For our purposes, we can just ignore this. */
935     if (rc && errno == EINTR)
936     {
937         rc = 0;
938     }
939 #endif
940 #ifdef EINVAL
941     /* we don't want to report an error just because we tried to fsync()
942        stdout, a socket or a pipe. */
943     if (rc && errno == EINVAL)
944     {
945         rc = 0;
946     }
947 #endif
948     return rc;
949 }
950
951 void gmx_chdir(const char *directory)
952 {
953 #ifdef GMX_NATIVE_WINDOWS
954     int rc = _chdir(directory);
955 #else
956     int rc = chdir(directory);
957 #endif
958     if (rc != 0)
959     {
960         gmx_fatal(FARGS, "Cannot change directory to '%s'. Reason: %s",
961                   directory, strerror(errno));
962     }
963 }
964
965 void gmx_getcwd(char *buffer, size_t size)
966 {
967 #ifdef GMX_NATIVE_WINDOWS
968     char *pdum = _getcwd(buffer, size);
969 #else
970     char *pdum = getcwd(buffer, size);
971 #endif
972     if (pdum == NULL)
973     {
974         gmx_fatal(FARGS, "Cannot get working directory. Reason: %s",
975                   strerror(errno));
976     }
977 }