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