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