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