Merge branch release-5-1
[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_UNISTD_H
52 #include <unistd.h>
53 #endif
54 #ifdef GMX_NATIVE_WINDOWS
55 #include <direct.h>   // For _chdir() and _getcwd()
56 #include <io.h>
57 #include <windows.h>
58 #endif
59
60 #include "thread_mpi/threads.h"
61
62 #include "gromacs/utility/cstringutil.h"
63 #include "gromacs/utility/datafilefinder.h"
64 #include "gromacs/utility/dir_separator.h"
65 #include "gromacs/utility/exceptions.h"
66 #include "gromacs/utility/fatalerror.h"
67 #include "gromacs/utility/path.h"
68 #include "gromacs/utility/programcontext.h"
69 #include "gromacs/utility/smalloc.h"
70 #include "gromacs/utility/stringutil.h"
71
72 /* we keep a linked list of all files opened through pipes (i.e.
73    compressed or .gzipped files. This way we can distinguish between them
74    without having to change the semantics of reading from/writing to files)
75  */
76 typedef struct t_pstack {
77     FILE            *fp;
78     struct t_pstack *prev;
79 } t_pstack;
80
81 static t_pstack    *pstack           = NULL;
82 static bool         bUnbuffered      = false;
83 static int          s_maxBackupCount = 0;
84
85 /* this linked list is an intrinsically globally shared object, so we have
86    to protect it with mutexes */
87 static tMPI_Thread_mutex_t pstack_mutex = TMPI_THREAD_MUTEX_INITIALIZER;
88
89 namespace gmx
90 {
91 namespace
92 {
93 //! Global library file finder; stores the object set with setLibraryFileFinder().
94 const DataFileFinder *g_libFileFinder;
95 //! Default library file finder if nothing is set.
96 const DataFileFinder  g_defaultLibFileFinder;
97 }   // namespace
98
99 const DataFileFinder &getLibraryFileFinder()
100 {
101     if (g_libFileFinder != NULL)
102     {
103         return *g_libFileFinder;
104     }
105     return g_defaultLibFileFinder;
106 }
107
108 void setLibraryFileFinder(const DataFileFinder *finder)
109 {
110     g_libFileFinder = finder;
111 }
112
113 } // namespace gmx
114
115 void gmx_disable_file_buffering(void)
116 {
117     bUnbuffered = true;
118 }
119
120 void gmx_set_max_backup_count(int count)
121 {
122     if (count < 0)
123     {
124         const char *env = getenv("GMX_MAXBACKUP");
125         if (env != NULL)
126         {
127             // TODO: Check that the value is converted properly.
128             count = strtol(env, NULL, 10);
129             if (count < 0)
130             {
131                 count = 0;
132             }
133         }
134         else
135         {
136             // Use a reasonably low value for countmax; we might
137             // generate 4-5 files in each round, and we don't
138             // want to hit directory limits of 1024 or 2048 files.
139             count = 99;
140         }
141     }
142     s_maxBackupCount = count;
143 }
144
145 void push_ps(FILE *fp)
146 {
147     t_pstack *ps;
148
149     tMPI_Thread_mutex_lock(&pstack_mutex);
150
151     snew(ps, 1);
152     ps->fp   = fp;
153     ps->prev = pstack;
154     pstack   = ps;
155
156     tMPI_Thread_mutex_unlock(&pstack_mutex);
157 }
158
159 #ifdef GMX_FAHCORE
160 /* don't use pipes!*/
161 #define popen fah_fopen
162 #define pclose fah_fclose
163 #define SKIP_FFOPS 1
164 #else
165 #ifdef gmx_ffclose
166 #undef gmx_ffclose
167 #endif
168 #if (!HAVE_PIPES && !defined(__native_client__))
169 static FILE *popen(const char *nm, const char *mode)
170 {
171     gmx_impl("Sorry no pipes...");
172
173     return NULL;
174 }
175
176 static int pclose(FILE *fp)
177 {
178     gmx_impl("Sorry no pipes...");
179
180     return 0;
181 }
182 #endif /* !HAVE_PIPES && !defined(__native_client__) */
183 #endif /* GMX_FAHCORE */
184
185 int gmx_ffclose(FILE *fp)
186 {
187 #ifdef SKIP_FFOPS
188     return fclose(fp);
189 #else
190     t_pstack *ps, *tmp;
191     int       ret = 0;
192
193     tMPI_Thread_mutex_lock(&pstack_mutex);
194
195     ps = pstack;
196     if (ps == NULL)
197     {
198         if (fp != NULL)
199         {
200             ret = fclose(fp);
201         }
202     }
203     else if (ps->fp == fp)
204     {
205         if (fp != NULL)
206         {
207             ret = pclose(fp);
208         }
209         pstack = pstack->prev;
210         sfree(ps);
211     }
212     else
213     {
214         while ((ps->prev != NULL) && (ps->prev->fp != fp))
215         {
216             ps = ps->prev;
217         }
218         if ((ps->prev != NULL) && ps->prev->fp == fp)
219         {
220             if (ps->prev->fp != NULL)
221             {
222                 ret = pclose(ps->prev->fp);
223             }
224             tmp      = ps->prev;
225             ps->prev = ps->prev->prev;
226             sfree(tmp);
227         }
228         else
229         {
230             if (fp != NULL)
231             {
232                 ret = fclose(fp);
233             }
234         }
235     }
236
237     tMPI_Thread_mutex_unlock(&pstack_mutex);
238     return ret;
239 #endif
240 }
241
242
243 void frewind(FILE *fp)
244 {
245     tMPI_Thread_mutex_lock(&pstack_mutex);
246
247     t_pstack *ps = pstack;
248     while (ps != NULL)
249     {
250         if (ps->fp == fp)
251         {
252             fprintf(stderr, "Cannot rewind compressed file!\n");
253             tMPI_Thread_mutex_unlock(&pstack_mutex);
254             return;
255         }
256         ps = ps->prev;
257     }
258     rewind(fp);
259     tMPI_Thread_mutex_unlock(&pstack_mutex);
260 }
261
262 int gmx_fseek(FILE *stream, gmx_off_t offset, int whence)
263 {
264 #ifdef HAVE_FSEEKO
265     return fseeko(stream, offset, whence);
266 #else
267 #ifdef HAVE__FSEEKI64
268     return _fseeki64(stream, offset, whence);
269 #else
270     return fseek(stream, offset, whence);
271 #endif
272 #endif
273 }
274
275 gmx_off_t gmx_ftell(FILE *stream)
276 {
277 #ifdef HAVE_FSEEKO
278     return ftello(stream);
279 #else
280 #ifdef HAVE__FSEEKI64
281 #ifndef __MINGW32__
282     return _ftelli64(stream);
283 #else
284     return ftello64(stream);
285 #endif
286 #else
287     return ftell(stream);
288 #endif
289 #endif
290 }
291
292 int gmx_truncate(const char *filename, gmx_off_t length)
293 {
294 #ifdef GMX_NATIVE_WINDOWS
295     FILE *fp = fopen(filename, "rb+");
296     if (fp == NULL)
297     {
298         return -1;
299     }
300 #ifdef _MSC_VER
301     int rc = _chsize_s(fileno(fp), length);
302 #else
303     int rc = _chsize(fileno(fp), length);
304 #endif
305     fclose(fp);
306     return rc;
307 #else
308     return truncate(filename, length);
309 #endif
310 }
311
312 static FILE *uncompress(const char *fn, const char *mode)
313 {
314     FILE *fp;
315     char  buf[256];
316
317     sprintf(buf, "uncompress -c < %s", fn);
318     fprintf(stderr, "Going to execute '%s'\n", buf);
319     if ((fp = popen(buf, mode)) == NULL)
320     {
321         gmx_open(fn);
322     }
323     push_ps(fp);
324
325     return fp;
326 }
327
328 static FILE *gunzip(const char *fn, const char *mode)
329 {
330     FILE *fp;
331     char  buf[256];
332
333     sprintf(buf, "gunzip -c < %s", fn);
334     fprintf(stderr, "Going to execute '%s'\n", buf);
335     if ((fp = popen(buf, mode)) == NULL)
336     {
337         gmx_open(fn);
338     }
339     push_ps(fp);
340
341     return fp;
342 }
343
344 gmx_bool gmx_fexist(const char *fname)
345 {
346     FILE *test;
347
348     if (fname == NULL)
349     {
350         return FALSE;
351     }
352     test = fopen(fname, "r");
353     if (test == NULL)
354     {
355         /*Windows doesn't allow fopen of directory - so we need to check this seperately */
356         #ifdef GMX_NATIVE_WINDOWS
357         DWORD attr = GetFileAttributes(fname);
358         return (attr != INVALID_FILE_ATTRIBUTES) && (attr & FILE_ATTRIBUTE_DIRECTORY);
359         #else
360         return FALSE;
361         #endif
362     }
363     else
364     {
365         fclose(test);
366         return TRUE;
367     }
368 }
369
370 static char *backup_fn(const char *file)
371 {
372     int          i, count = 1;
373     char        *directory, *fn;
374     char        *buf;
375
376     smalloc(buf, GMX_PATH_MAX);
377
378     for (i = strlen(file)-1; ((i > 0) && (file[i] != DIR_SEPARATOR)); i--)
379     {
380         ;
381     }
382     /* Must check whether i > 0, i.e. whether there is a directory
383      * in the file name. In that case we overwrite the / sign with
384      * a '\0' to end the directory string .
385      */
386     if (i > 0)
387     {
388         directory    = gmx_strdup(file);
389         directory[i] = '\0';
390         fn           = gmx_strdup(file+i+1);
391     }
392     else
393     {
394         directory    = gmx_strdup(".");
395         fn           = gmx_strdup(file);
396     }
397     do
398     {
399         sprintf(buf, "%s/#%s.%d#", directory, fn, count);
400         count++;
401     }
402     while ((count <= s_maxBackupCount) && gmx_fexist(buf));
403
404     /* Arbitrarily bail out */
405     if (count > s_maxBackupCount)
406     {
407         /* TODO: The error message is only accurate for code that starts with
408          * Gromacs command-line interface. */
409         gmx_fatal(FARGS, "Won't make more than %d backups of %s for you.\n"
410                   "The env.var. GMX_MAXBACKUP controls this maximum, -1 disables backups.",
411                   s_maxBackupCount, fn);
412     }
413
414     sfree(directory);
415     sfree(fn);
416
417     return buf;
418 }
419
420 void make_backup(const char *name)
421 {
422     if (s_maxBackupCount <= 0)
423     {
424         return;
425     }
426     if (gmx_fexist(name))
427     {
428         char *backup = backup_fn(name);
429         if (rename(name, backup) == 0)
430         {
431             fprintf(stderr, "\nBack Off! I just backed up %s to %s\n",
432                     name, backup);
433         }
434         else
435         {
436             fprintf(stderr, "\nSorry couldn't backup %s to %s\n", name, backup);
437         }
438         sfree(backup);
439     }
440 }
441
442 FILE *gmx_ffopen(const char *file, const char *mode)
443 {
444 #ifdef SKIP_FFOPS
445     return fopen(file, mode);
446 #else
447     FILE    *ff = NULL;
448     char     buf[256], *bufsize = 0, *ptr;
449     gmx_bool bRead;
450     int      bs;
451
452     if (file == NULL)
453     {
454         return NULL;
455     }
456
457     if (mode[0] == 'w')
458     {
459         make_backup(file);
460     }
461     where();
462
463     bRead = (mode[0] == 'r' && mode[1] != '+');
464     strcpy(buf, file);
465     if (!bRead || gmx_fexist(buf))
466     {
467         if ((ff = fopen(buf, mode)) == NULL)
468         {
469             gmx_file(buf);
470         }
471         where();
472         /* Check whether we should be using buffering (default) or not
473          * (for debugging)
474          */
475         if (bUnbuffered || ((bufsize = getenv("GMX_LOG_BUFFER")) != NULL))
476         {
477             /* Check whether to use completely unbuffered */
478             if (bUnbuffered)
479             {
480                 bs = 0;
481             }
482             else
483             {
484                 bs = strtol(bufsize, NULL, 10);
485             }
486             if (bs <= 0)
487             {
488                 setbuf(ff, NULL);
489             }
490             else
491             {
492                 snew(ptr, bs+8);
493                 if (setvbuf(ff, ptr, _IOFBF, bs) != 0)
494                 {
495                     gmx_file("Buffering File");
496                 }
497             }
498         }
499         where();
500     }
501     else
502     {
503         sprintf(buf, "%s.Z", file);
504         if (gmx_fexist(buf))
505         {
506             ff = uncompress(buf, mode);
507         }
508         else
509         {
510             sprintf(buf, "%s.gz", file);
511             if (gmx_fexist(buf))
512             {
513                 ff = gunzip(buf, mode);
514             }
515             else
516             {
517                 gmx_file(file);
518             }
519         }
520     }
521     return ff;
522 #endif
523 }
524
525
526 char *low_gmxlibfn(const char *file, gmx_bool bAddCWD, gmx_bool bFatal)
527 {
528     try
529     {
530         const gmx::DataFileFinder &finder = gmx::getLibraryFileFinder();
531         std::string                result =
532             finder.findFile(gmx::DataFileOptions(file)
533                                 .includeCurrentDir(bAddCWD)
534                                 .throwIfNotFound(bFatal));
535         if (!result.empty())
536         {
537             return gmx_strdup(result.c_str());
538         }
539     }
540     GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
541     return NULL;
542 }
543
544 FILE *low_libopen(const char *file, gmx_bool bFatal)
545 {
546     try
547     {
548         const gmx::DataFileFinder &finder = gmx::getLibraryFileFinder();
549         FILE *fp =
550             finder.openFile(gmx::DataFileOptions(file)
551                                 .includeCurrentDir(true)
552                                 .throwIfNotFound(bFatal));
553         return fp;
554     }
555     GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
556     return NULL;
557 }
558
559 char *gmxlibfn(const char *file)
560 {
561     return low_gmxlibfn(file, TRUE, TRUE);
562 }
563
564 FILE *libopen(const char *file)
565 {
566     return low_libopen(file, TRUE);
567 }
568
569 void gmx_tmpnam(char *buf)
570 {
571     int i, len;
572
573     if ((len = strlen(buf)) < 7)
574     {
575         gmx_fatal(FARGS, "Buf passed to gmx_tmpnam must be at least 7 bytes long");
576     }
577     for (i = len-6; (i < len); i++)
578     {
579         buf[i] = 'X';
580     }
581     /* mktemp is dangerous and we should use mkstemp instead, but
582      * since windows doesnt support it we have to separate the cases.
583      * 20090307: mktemp deprecated, use iso c++ _mktemp instead.
584      */
585 #ifdef GMX_NATIVE_WINDOWS
586     _mktemp(buf);
587 #else
588     int fd = mkstemp(buf);
589
590     if (fd < 0)
591     {
592         gmx_fatal(FARGS, "Creating temporary file %s: %s", buf,
593                   strerror(errno));
594     }
595     close(fd);
596 #endif
597     /* name in Buf should now be OK */
598 }
599
600 int gmx_file_rename(const char *oldname, const char *newname)
601 {
602 #ifndef GMX_NATIVE_WINDOWS
603     /* under unix, rename() is atomic (at least, it should be). */
604     return rename(oldname, newname);
605 #else
606     if (MoveFileEx(oldname, newname,
607                    MOVEFILE_REPLACE_EXISTING|MOVEFILE_WRITE_THROUGH))
608     {
609         return 0;
610     }
611     else
612     {
613         return 1;
614     }
615 #endif
616 }
617
618 int gmx_file_copy(const char *oldname, const char *newname, gmx_bool copy_if_empty)
619 {
620 /* the full copy buffer size: */
621 #define FILECOPY_BUFSIZE (1<<16)
622     FILE *in  = NULL;
623     FILE *out = NULL;
624     char *buf;
625
626     snew(buf, FILECOPY_BUFSIZE);
627
628     in = fopen(oldname, "rb");
629     if (!in)
630     {
631         goto error;
632     }
633
634     /* If we don't copy when empty, we postpone opening the file
635        until we're actually ready to write. */
636     if (copy_if_empty)
637     {
638         out = fopen(newname, "wb");
639         if (!out)
640         {
641             goto error;
642         }
643     }
644
645     while (!feof(in))
646     {
647         size_t nread;
648
649         nread = fread(buf, sizeof(char), FILECOPY_BUFSIZE, in);
650         if (nread > 0)
651         {
652             size_t ret;
653             if (!out)
654             {
655                 /* so this is where we open when copy_if_empty is false:
656                    here we know we read something. */
657                 out = fopen(newname, "wb");
658                 if (!out)
659                 {
660                     goto error;
661                 }
662             }
663             ret = fwrite(buf, sizeof(char), nread, out);
664             if (ret != nread)
665             {
666                 goto error;
667             }
668         }
669         if (ferror(in))
670         {
671             goto error;
672         }
673     }
674     sfree(buf);
675     fclose(in);
676     fclose(out);
677     return 0;
678 error:
679     sfree(buf);
680     if (in)
681     {
682         fclose(in);
683     }
684     if (out)
685     {
686         fclose(out);
687     }
688     return 1;
689 #undef FILECOPY_BUFSIZE
690 }
691
692
693 int gmx_fsync(FILE *fp)
694 {
695     int rc = 0;
696
697 #ifdef GMX_FAHCORE
698     /* the fahcore defines its own os-independent fsync */
699     rc = fah_fsync(fp);
700 #else /* GMX_FAHCORE */
701     {
702         int fn;
703
704         /* get the file number */
705 #if defined(HAVE_FILENO)
706         fn = fileno(fp);
707 #elif defined(HAVE__FILENO)
708         fn = _fileno(fp);
709 #else
710         fn = -1;
711 #endif
712
713         /* do the actual fsync */
714         if (fn >= 0)
715         {
716 #if (defined(HAVE_FSYNC))
717             rc = fsync(fn);
718 #elif (defined(HAVE__COMMIT))
719             rc = _commit(fn);
720 #endif
721         }
722     }
723 #endif /* GMX_FAHCORE */
724
725     /* We check for these error codes this way because POSIX requires them
726        to be defined, and using anything other than macros is unlikely: */
727 #ifdef EINTR
728     /* we don't want to report an error just because fsync() caught a signal.
729        For our purposes, we can just ignore this. */
730     if (rc && errno == EINTR)
731     {
732         rc = 0;
733     }
734 #endif
735 #ifdef EINVAL
736     /* we don't want to report an error just because we tried to fsync()
737        stdout, a socket or a pipe. */
738     if (rc && errno == EINVAL)
739     {
740         rc = 0;
741     }
742 #endif
743     return rc;
744 }
745
746 void gmx_chdir(const char *directory)
747 {
748 #ifdef GMX_NATIVE_WINDOWS
749     int rc = _chdir(directory);
750 #else
751     int rc = chdir(directory);
752 #endif
753     if (rc != 0)
754     {
755         gmx_fatal(FARGS, "Cannot change directory to '%s'. Reason: %s",
756                   directory, strerror(errno));
757     }
758 }
759
760 void gmx_getcwd(char *buffer, size_t size)
761 {
762 #ifdef GMX_NATIVE_WINDOWS
763     char *pdum = _getcwd(buffer, size);
764 #else
765     char *pdum = getcwd(buffer, size);
766 #endif
767     if (pdum == NULL)
768     {
769         gmx_fatal(FARGS, "Cannot get working directory. Reason: %s",
770                   strerror(errno));
771     }
772 }