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