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