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