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