2 * This file is part of the GROMACS molecular simulation package.
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.
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.
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.
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.
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.
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.
52 #include <sys/types.h>
57 #if GMX_NATIVE_WINDOWS
58 #include <direct.h> // For _chdir() and _getcwd()
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"
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)
78 typedef struct t_pstack {
80 struct t_pstack *prev;
83 static t_pstack *pstack = nullptr;
84 static bool bUnbuffered = false;
85 static int s_maxBackupCount = 0;
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;
91 using Lock = gmx::lock_guard<gmx::Mutex>;
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;
103 const DataFileFinder &getLibraryFileFinder()
105 if (g_libFileFinder != nullptr)
107 return *g_libFileFinder;
109 return g_defaultLibFileFinder;
112 void setLibraryFileFinder(const DataFileFinder *finder)
114 g_libFileFinder = finder;
119 void gmx_disable_file_buffering()
124 void gmx_set_max_backup_count(int count)
128 const char *env = getenv("GMX_MAXBACKUP");
131 // TODO: Check that the value is converted properly.
132 count = strtol(env, nullptr, 10);
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.
146 s_maxBackupCount = count;
149 static void push_ps(FILE *fp)
153 Lock pstackLock(pstack_mutex);
162 /* don't use pipes!*/
163 #define popen fah_fopen
164 #define pclose fah_fclose
170 #if (!HAVE_PIPES && !defined(__native_client__))
171 static FILE *popen(const char *nm, const char *mode)
173 gmx_impl("Sorry no pipes...");
178 static int pclose(FILE *fp)
180 gmx_impl("Sorry no pipes...");
184 #endif /* !HAVE_PIPES && !defined(__native_client__) */
185 #endif /* GMX_FAHCORE */
187 int gmx_ffclose(FILE *fp)
195 Lock pstackLock(pstack_mutex);
205 else if (ps->fp == fp)
211 pstack = pstack->prev;
216 while ((ps->prev != nullptr) && (ps->prev->fp != fp))
220 if ((ps->prev != nullptr) && ps->prev->fp == fp)
222 if (ps->prev->fp != nullptr)
224 ret = pclose(ps->prev->fp);
227 ps->prev = ps->prev->prev;
244 void frewind(FILE *fp)
246 Lock pstackLock(pstack_mutex);
248 t_pstack *ps = pstack;
249 while (ps != nullptr)
253 fprintf(stderr, "Cannot rewind compressed file!\n");
261 int gmx_fseek(FILE *stream, gmx_off_t offset, int whence)
264 return fseeko(stream, offset, whence);
267 return _fseeki64(stream, offset, whence);
269 return fseek(stream, offset, whence);
274 gmx_off_t gmx_ftell(FILE *stream)
277 return ftello(stream);
281 return _ftelli64(stream);
283 return ftello64(stream);
286 return ftell(stream);
291 int gmx_truncate(const std::string &filename, gmx_off_t length)
293 #if GMX_NATIVE_WINDOWS
294 FILE *fp = fopen(filename.c_str(), "rb+");
300 int rc = _chsize_s(fileno(fp), length);
302 int rc = _chsize(fileno(fp), length);
307 return truncate(filename.c_str(), length);
311 static FILE *uncompress(const std::string &fn, const char *mode)
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)
325 static FILE *gunzip(const std::string &fn, const char *mode)
328 std::string buf = "gunzip -c < ";
330 fprintf(stderr, "Going to execute '%s'\n", buf.c_str());
331 if ((fp = popen(buf.c_str(), mode)) == nullptr)
340 gmx_bool gmx_fexist(const std::string &fname)
348 test = fopen(fname.c_str(), "r");
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);
366 static std::string backup_fn(const std::string &file)
370 std::string directory, fn, buf;
371 std::tie(directory, fn) = gmx::Path::getParentPathAndBasename(file);
372 if (directory.empty())
378 buf = gmx::formatString("%s/#%s.%d#", directory.c_str(), fn.c_str(), count);
381 while ((count <= s_maxBackupCount) && gmx_fexist(buf));
383 /* Arbitrarily bail out */
384 if (count > s_maxBackupCount)
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());
396 void make_backup(const std::string &name)
398 if (s_maxBackupCount <= 0)
402 if (gmx_fexist(name))
404 auto backup = backup_fn(name);
405 if (rename(name.c_str(), backup.c_str()) == 0)
407 fprintf(stderr, "\nBack Off! I just backed up %s to %s\n",
408 name.c_str(), backup.c_str());
412 fprintf(stderr, "\nSorry couldn't backup %s to %s\n", name.c_str(), backup.c_str());
417 FILE *gmx_ffopen(const std::string &file, const char *mode)
420 return fopen(file, mode);
436 bRead = (mode[0] == 'r' && mode[1] != '+');
437 if (!bRead || gmx_fexist(file))
439 if ((ff = fopen(file.c_str(), mode)) == nullptr)
443 /* Check whether we should be using buffering (default) or not
446 const char *bufsize = nullptr;
447 if (bUnbuffered || ((bufsize = getenv("GMX_LOG_BUFFER")) != nullptr))
449 /* Check whether to use completely unbuffered */
456 bs = strtol(bufsize, nullptr, 10);
466 if (setvbuf(ff, ptr, _IOFBF, bs) != 0)
468 gmx_file("Buffering File");
475 std::string compressedFileName = file;
476 compressedFileName += ".Z";
477 if (gmx_fexist(compressedFileName))
479 ff = uncompress(compressedFileName, mode);
483 compressedFileName = file;
484 compressedFileName += ".gz";
485 if (gmx_fexist(compressedFileName))
487 ff = gunzip(compressedFileName, mode);
502 std::string findLibraryFile(const std::string &filename, bool bAddCWD, bool bFatal)
507 const DataFileFinder &finder = getLibraryFileFinder();
508 result = finder.findFile(DataFileOptions(filename)
509 .includeCurrentDir(bAddCWD)
510 .throwIfNotFound(bFatal));
512 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
516 std::string findLibraryFile(const char *filename, bool bAddCWD, bool bFatal)
518 return findLibraryFile(std::string(filename), bAddCWD, bFatal);
521 FilePtr openLibraryFile(const std::string &filename, bool bAddCWD, bool bFatal)
526 const DataFileFinder &finder = getLibraryFileFinder();
527 fp = finder.openFile(DataFileOptions(filename)
528 .includeCurrentDir(bAddCWD)
529 .throwIfNotFound(bFatal));
531 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
535 FilePtr openLibraryFile(const char *filename, bool bAddCWD, bool bFatal)
537 return openLibraryFile(std::string(filename), bAddCWD, bFatal);
542 void gmx_tmpnam(char *buf)
546 if ((len = strlen(buf)) < 7)
548 gmx_fatal(FARGS, "Buf passed to gmx_tmpnam must be at least 7 bytes long");
550 for (i = len-6; (i < len); i++)
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.
558 #if GMX_NATIVE_WINDOWS
562 gmx_fatal(FARGS, "Error creating temporary file %s: %s", buf,
566 int fd = mkstemp(buf);
570 gmx_fatal(FARGS, "Error creating temporary file %s: %s", buf,
575 /* name in Buf should now be OK and file is CLOSED */
578 FILE *gmx_fopen_temporary(char *buf)
581 FILE *fpout = nullptr;
583 if ((len = strlen(buf)) < 7)
585 gmx_fatal(FARGS, "Buf passed to gmx_fopentmp must be at least 7 bytes long");
587 for (i = len-6; (i < len); i++)
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.
595 #if GMX_NATIVE_WINDOWS
599 gmx_fatal(FARGS, "Error creating temporary file %s: %s", buf,
602 if ((fpout = fopen(buf, "w")) == NULL)
604 gmx_fatal(FARGS, "Cannot open temporary file %s", buf);
607 int fd = mkstemp(buf);
610 gmx_fatal(FARGS, "Error creating temporary file %s: %s", buf,
613 if ((fpout = fdopen(fd, "w")) == nullptr)
615 gmx_fatal(FARGS, "Cannot open temporary file %s", buf);
618 /* name in Buf should now be OK and file is open */
623 int gmx_file_rename(const char *oldname, const char *newname)
625 #if !GMX_NATIVE_WINDOWS
626 /* under unix, rename() is atomic (at least, it should be). */
627 return rename(oldname, newname);
629 if (MoveFileEx(oldname, newname,
630 MOVEFILE_REPLACE_EXISTING|MOVEFILE_WRITE_THROUGH))
641 int gmx_file_copy(const char *oldname, const char *newname, gmx_bool copy_if_empty)
643 gmx::FilePtr in(fopen(oldname, "rb"));
649 /* If we don't copy when empty, we postpone opening the file
650 until we're actually ready to write. */
654 out.reset(fopen(newname, "wb"));
661 /* the full copy buffer size: */
662 constexpr int FILECOPY_BUFSIZE = 1<<16;
663 std::vector<char> buf(FILECOPY_BUFSIZE);
665 while (!feof(in.get()))
669 nread = fread(buf.data(), sizeof(char), FILECOPY_BUFSIZE, in.get());
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"));
683 ret = fwrite(buf.data(), sizeof(char), nread, out.get());
689 if (ferror(in.get()))
698 int gmx_fsync(FILE *fp)
703 /* the fahcore defines its own os-independent fsync */
705 #else /* GMX_FAHCORE */
709 /* get the file number */
718 /* do the actual fsync */
728 #endif /* GMX_FAHCORE */
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: */
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)
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)
751 void gmx_chdir(const char *directory)
753 #if GMX_NATIVE_WINDOWS
754 int rc = _chdir(directory);
756 int rc = chdir(directory);
760 gmx_fatal(FARGS, "Cannot change directory to '%s'. Reason: %s",
761 directory, strerror(errno));
765 void gmx_getcwd(char *buffer, size_t size)
767 #if GMX_NATIVE_WINDOWS
768 char *pdum = _getcwd(buffer, size);
770 char *pdum = getcwd(buffer, size);
774 gmx_fatal(FARGS, "Cannot get working directory. Reason: %s",