*
* Copyright (c) 1991-2000, University of Groningen, The Netherlands.
* Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015,2016,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016,2017, The GROMACS development team.
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
* Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
* and including many others, as listed in the AUTHORS file in the
* top-level source directory and at http://www.gromacs.org.
#include <cstdlib>
#include <cstring>
+#include <mutex>
#include <tuple>
#include <fcntl.h>
#include "gromacs/utility/dir_separator.h"
#include "gromacs/utility/exceptions.h"
#include "gromacs/utility/fatalerror.h"
-#include "gromacs/utility/mutex.h"
#include "gromacs/utility/path.h"
#include "gromacs/utility/programcontext.h"
#include "gromacs/utility/smalloc.h"
struct t_pstack* prev;
} t_pstack;
-static t_pstack* pstack = nullptr;
-static bool bUnbuffered = false;
-static int s_maxBackupCount = 0;
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+static t_pstack* pstack = nullptr;
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+static bool bUnbuffered = false;
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+static int s_maxBackupCount = 0;
/* this linked list is an intrinsically globally shared object, so we have
to protect it with mutexes */
-static gmx::Mutex pstack_mutex;
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+static std::mutex pstack_mutex;
-using Lock = gmx::lock_guard<gmx::Mutex>;
+using Lock = std::lock_guard<std::mutex>;
namespace gmx
{
namespace
{
//! Global library file finder; stores the object set with setLibraryFileFinder().
-const DataFileFinder* g_libFileFinder;
+const DataFileFinder* g_libFileFinder; //NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
//! Default library file finder if nothing is set.
const DataFileFinder g_defaultLibFileFinder;
} // namespace
static void push_ps(FILE* fp)
{
- t_pstack* ps;
+ t_pstack* ps = nullptr;
Lock pstackLock(pstack_mutex);
}
#if GMX_FAHCORE
-/* don't use pipes!*/
-# define popen fah_fopen
-# define pclose fah_fclose
-# define SKIP_FFOPS 1
-#else
# ifdef gmx_ffclose
# undef gmx_ffclose
# endif
-# if (!HAVE_PIPES && !defined(__native_client__))
-static FILE* popen(const char* nm, const char* mode)
+#endif
+#if (!HAVE_PIPES && !defined(__native_client__))
+static FILE* popen(const char* /* nm */, const char* /* mode */)
{
gmx_impl("Sorry no pipes...");
return NULL;
}
-static int pclose(FILE* fp)
+static int pclose(FILE* /* fp */)
{
gmx_impl("Sorry no pipes...");
return 0;
}
-# endif /* !HAVE_PIPES && !defined(__native_client__) */
-#endif /* GMX_FAHCORE */
+#endif /* !HAVE_PIPES && !defined(__native_client__) */
int gmx_ffclose(FILE* fp)
{
-#ifdef SKIP_FFOPS
- return fclose(fp);
-#else
- t_pstack *ps, *tmp;
- int ret = 0;
+ int ret = 0;
Lock pstackLock(pstack_mutex);
- ps = pstack;
+ t_pstack* ps = pstack;
if (ps == nullptr)
{
if (fp != nullptr)
{
ret = pclose(ps->prev->fp);
}
- tmp = ps->prev;
- ps->prev = ps->prev->prev;
+ t_pstack* tmp = ps->prev;
+ ps->prev = ps->prev->prev;
sfree(tmp);
}
else
}
return ret;
-#endif
}
int gmx_truncate(const std::string& filename, gmx_off_t length)
{
-#if GMX_NATIVE_WINDOWS
+#if GMX_NATIVE_WINDOWS && !GMX_FAHCORE
FILE* fp = fopen(filename.c_str(), "rb+");
if (fp == NULL)
{
static FILE* uncompress(const std::string& fn, const char* mode)
{
- FILE* fp;
+ FILE* fp = nullptr;
std::string buf = "uncompress -c < " + fn;
fprintf(stderr, "Going to execute '%s'\n", buf.c_str());
if ((fp = popen(buf.c_str(), mode)) == nullptr)
static FILE* gunzip(const std::string& fn, const char* mode)
{
- FILE* fp;
+ FILE* fp = nullptr;
std::string buf = "gunzip -c < ";
buf += fn;
fprintf(stderr, "Going to execute '%s'\n", buf.c_str());
gmx_bool gmx_fexist(const std::string& fname)
{
- FILE* test;
-
if (fname.empty())
{
return FALSE;
}
- test = fopen(fname.c_str(), "r");
+ FILE* test = fopen(fname.c_str(), "r");
if (test == nullptr)
{
-/*Windows doesn't allow fopen of directory - so we need to check this seperately */
+/*Windows doesn't allow fopen of directory - so we need to check this separately */
#if GMX_NATIVE_WINDOWS
DWORD attr = GetFileAttributes(fname.c_str());
return (attr != INVALID_FILE_ATTRIBUTES) && (attr & FILE_ATTRIBUTE_DIRECTORY);
gmx_fatal(FARGS,
"Won't make more than %d backups of %s for you.\n"
"The env.var. GMX_MAXBACKUP controls this maximum, -1 disables backups.",
- s_maxBackupCount, fn.c_str());
+ s_maxBackupCount,
+ fn.c_str());
}
return buf;
FILE* gmx_ffopen(const std::string& file, const char* mode)
{
-#ifdef SKIP_FFOPS
- return fopen(file, mode);
-#else
- FILE* ff = nullptr;
- gmx_bool bRead;
- int bs;
+ FILE* ff = nullptr;
if (file.empty())
{
make_backup(file);
}
- bRead = (mode[0] == 'r' && mode[1] != '+');
+ bool bRead = (mode[0] == 'r' && mode[1] != '+');
if (!bRead || gmx_fexist(file))
{
if ((ff = fopen(file.c_str(), mode)) == nullptr)
if (bUnbuffered || ((bufsize = getenv("GMX_LOG_BUFFER")) != nullptr))
{
/* Check whether to use completely unbuffered */
- if (bUnbuffered)
- {
- bs = 0;
- }
- else
- {
- bs = strtol(bufsize, nullptr, 10);
- }
+ const int bs = bUnbuffered ? 0 : strtol(bufsize, nullptr, 10);
if (bs <= 0)
{
setbuf(ff, nullptr);
}
else
{
- char* ptr;
+ char* ptr = nullptr;
snew(ptr, bs + 8);
if (setvbuf(ff, ptr, _IOFBF, bs) != 0)
{
}
}
return ff;
-#endif
}
namespace gmx
/*! \brief Use mkstemp (or similar function to make a new temporary
* file and (on non-Windows systems) return a file descriptor to it.
*
+ * Note: not thread-safe on non-Windows systems
+ *
* \todo Use std::string and std::vector<char>. */
static int makeTemporaryFilename(char* buf)
{
- int len;
+ int len = 0;
if ((len = strlen(buf)) < 7)
{
* since windows doesnt support it we have to separate the cases.
* 20090307: mktemp deprecated, use iso c++ _mktemp instead.
*/
- int fd;
#if GMX_NATIVE_WINDOWS
_mktemp(buf);
if (buf == NULL)
{
gmx_fatal(FARGS, "Error creating temporary file %s: %s", buf, strerror(errno));
}
- fd = 0;
+ int fd = 0;
#else
- fd = mkstemp(buf);
+ int fd = mkstemp(buf);
+
+ /* mkstemp creates 0600 files - respect umask instead */
+ mode_t currUmask = umask(0);
+ umask(currUmask);
+ fchmod(fd, 0666 & ~currUmask);
if (fd < 0)
{
return fpout;
}
-int gmx_file_rename(const char* oldname, const char* newname)
+void gmx_file_rename(const char* oldname, const char* newname)
{
+ int code;
#if !GMX_NATIVE_WINDOWS
/* under unix, rename() is atomic (at least, it should be). */
- return rename(oldname, newname);
+ code = rename(oldname, newname);
#else
if (MoveFileEx(oldname, newname, MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH))
{
- return 0;
+# if GMX_FAHCORE
+ /* This just lets the F@H checksumming system know about the rename */
+ fcRename(oldname, newname);
+# endif
+ code = 0;
}
else
{
- return 1;
+ code = 1;
}
#endif
+ if (code != 0)
+ {
+ auto errorMsg = gmx::formatString("Failed to rename %s to %s.", oldname, newname);
+ GMX_THROW(gmx::FileIOError(errorMsg));
+ }
}
int gmx_file_copy(const char* oldname, const char* newname, gmx_bool copy_if_empty)
while (!feof(in.get()))
{
- size_t nread;
-
- nread = fread(buf.data(), sizeof(char), FILECOPY_BUFSIZE, in.get());
+ size_t nread = fread(buf.data(), sizeof(char), FILECOPY_BUFSIZE, in.get());
if (nread > 0)
{
- size_t ret;
+ size_t ret = 0;
if (!out)
{
/* so this is where we open when copy_if_empty is false:
{
int rc = 0;
-#if GMX_FAHCORE
- /* the fahcore defines its own os-independent fsync */
- rc = fah_fsync(fp);
-#else /* GMX_FAHCORE */
{
- int fn;
-
/* get the file number */
-# if HAVE_FILENO
- fn = fileno(fp);
-# elif HAVE__FILENO
- fn = _fileno(fp);
-# else
- fn = -1;
-# endif
+#if HAVE_FILENO
+ int fn = fileno(fp);
+#elif HAVE__FILENO
+ int fn = _fileno(fp);
+#else
+ GMX_UNUSED_VALUE(fp);
+ int fn = -1;
+#endif
/* do the actual fsync */
if (fn >= 0)
{
-# if HAVE_FSYNC
+#if HAVE_FSYNC
rc = fsync(fn);
-# elif HAVE__COMMIT
+#elif HAVE__COMMIT
rc = _commit(fn);
-# endif
+#endif
}
}
-#endif /* GMX_FAHCORE */
/* We check for these error codes this way because POSIX requires them
to be defined, and using anything other than macros is unlikely: */
#endif
if (rc != 0)
{
- gmx_fatal(FARGS, "Cannot change directory to '%s'. Reason: %s", directory, strerror(errno));
+ auto message = gmx::formatString(
+ "Cannot change directory to '%s'. Reason: %s", directory, strerror(errno));
+ GMX_THROW(gmx::FileIOError(message));
}
}