Throw on failure in gmx_file_rename
[alexxy/gromacs.git] / src / gromacs / utility / futil.cpp
index c7d0a40521895531393841ce4c5aa1034f3bbcc5..34467e1f1d120f3adfefee22f4a11fb9c06cc4ea 100644 (file)
@@ -3,7 +3,8 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015,2016,2017, 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 "config.h"
 
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+#include <cerrno>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+#include <mutex>
+#include <tuple>
 
 #include <fcntl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 
 #ifdef HAVE_UNISTD_H
-#include <unistd.h>
+#    include <unistd.h>
 #endif
 #if GMX_NATIVE_WINDOWS
-#include <direct.h>   // For _chdir() and _getcwd()
-#include <io.h>
-#include <windows.h>
+#    include <direct.h> // For _chdir() and _getcwd()
+#    include <io.h>
+#    include <windows.h>
 #endif
 
 #include "gromacs/utility/cstringutil.h"
@@ -63,7 +67,6 @@
 #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"
    compressed or .gzipped files. This way we can distinguish between them
    without having to change the semantics of reading from/writing to files)
  */
-typedef struct t_pstack {
-    FILE            *fp;
-    struct t_pstack *prev;
+typedef struct t_pstack
+{
+    FILE*            fp;
+    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
+const DataFileFinder g_defaultLibFileFinder;
+} // namespace
 
-const DataFileFinder &getLibraryFileFinder()
+const DataFileFindergetLibraryFileFinder()
 {
     if (g_libFileFinder != nullptr)
     {
@@ -107,14 +115,14 @@ const DataFileFinder &getLibraryFileFinder()
     return g_defaultLibFileFinder;
 }
 
-void setLibraryFileFinder(const DataFileFinder *finder)
+void setLibraryFileFinder(const DataFileFinderfinder)
 {
     g_libFileFinder = finder;
 }
 
 } // namespace gmx
 
-void gmx_disable_file_buffering(void)
+void gmx_disable_file_buffering()
 {
     bUnbuffered = true;
 }
@@ -123,7 +131,7 @@ void gmx_set_max_backup_count(int count)
 {
     if (count < 0)
     {
-        const char *env = getenv("GMX_MAXBACKUP");
+        const charenv = getenv("GMX_MAXBACKUP");
         if (env != nullptr)
         {
             // TODO: Check that the value is converted properly.
@@ -144,11 +152,11 @@ void gmx_set_max_backup_count(int count)
     s_maxBackupCount = count;
 }
 
-static void push_ps(FILE *fp)
+static void push_ps(FILEfp)
 {
-    t_pstack *ps;
+    t_pstack* ps = nullptr;
 
-    Lock      pstackLock(pstack_mutex);
+    Lock pstackLock(pstack_mutex);
 
     snew(ps, 1);
     ps->fp   = fp;
@@ -156,43 +164,34 @@ static void push_ps(FILE *fp)
     pstack   = ps;
 }
 
-#ifdef 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
+#if GMX_FAHCORE
+#    ifdef gmx_ffclose
+#        undef gmx_ffclose
+#    endif
 #endif
 #if (!HAVE_PIPES && !defined(__native_client__))
-static FILE *popen(const char *nm, const char *mode)
+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 */
 
-int gmx_ffclose(FILE *fp)
+int gmx_ffclose(FILEfp)
 {
-#ifdef SKIP_FFOPS
-    return fclose(fp);
-#else
-    t_pstack *ps, *tmp;
-    int       ret = 0;
+    int ret = 0;
 
-    Lock      pstackLock(pstack_mutex);
+    Lock pstackLock(pstack_mutex);
 
-    ps = pstack;
+    t_pstack* ps = pstack;
     if (ps == nullptr)
     {
         if (fp != nullptr)
@@ -221,8 +220,8 @@ int gmx_ffclose(FILE *fp)
             {
                 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
@@ -235,15 +234,14 @@ int gmx_ffclose(FILE *fp)
     }
 
     return ret;
-#endif
 }
 
 
-void frewind(FILE *fp)
+void frewind(FILEfp)
 {
-    Lock      pstackLock(pstack_mutex);
+    Lock pstackLock(pstack_mutex);
 
-    t_pstack *ps = pstack;
+    t_pstackps = pstack;
     while (ps != nullptr)
     {
         if (ps->fp == fp)
@@ -256,64 +254,62 @@ void frewind(FILE *fp)
     rewind(fp);
 }
 
-int gmx_fseek(FILE *stream, gmx_off_t offset, int whence)
+int gmx_fseek(FILEstream, gmx_off_t offset, int whence)
 {
 #if HAVE_FSEEKO
     return fseeko(stream, offset, whence);
 #else
-#if HAVE__FSEEKI64
+#    if HAVE__FSEEKI64
     return _fseeki64(stream, offset, whence);
-#else
+#    else
     return fseek(stream, offset, whence);
-#endif
+#    endif
 #endif
 }
 
-gmx_off_t gmx_ftell(FILE *stream)
+gmx_off_t gmx_ftell(FILEstream)
 {
 #if HAVE_FSEEKO
     return ftello(stream);
 #else
-#if HAVE__FSEEKI64
-#ifndef __MINGW32__
+#    if HAVE__FSEEKI64
+#        ifndef __MINGW32__
     return _ftelli64(stream);
-#else
+#        else
     return ftello64(stream);
-#endif
-#else
+#        endif
+#    else
     return ftell(stream);
-#endif
+#    endif
 #endif
 }
 
-int gmx_truncate(const char *filename, gmx_off_t length)
+int gmx_truncate(const std::string& filename, gmx_off_t length)
 {
-#if GMX_NATIVE_WINDOWS
-    FILE *fp = fopen(filename, "rb+");
+#if GMX_NATIVE_WINDOWS && !GMX_FAHCORE
+    FILE* fp = fopen(filename.c_str(), "rb+");
     if (fp == NULL)
     {
         return -1;
     }
-#ifdef _MSC_VER
+#    ifdef _MSC_VER
     int rc = _chsize_s(fileno(fp), length);
-#else
+#    else
     int rc = _chsize(fileno(fp), length);
-#endif
+#    endif
     fclose(fp);
     return rc;
 #else
-    return truncate(filename, length);
+    return truncate(filename.c_str(), length);
 #endif
 }
 
-static FILE *uncompress(const char *fn, const char *mode)
+static FILE* uncompress(const std::string& fn, const char* mode)
 {
-    FILE *fp;
-    char  buf[256];
-
-    sprintf(buf, "uncompress -c < %s", fn);
-    fprintf(stderr, "Going to execute '%s'\n", buf);
-    if ((fp = popen(buf, mode)) == nullptr)
+    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)
     {
         gmx_open(fn);
     }
@@ -322,14 +318,13 @@ static FILE *uncompress(const char *fn, const char *mode)
     return fp;
 }
 
-static FILE *gunzip(const char *fn, const char *mode)
+static FILE* gunzip(const std::string& fn, const char* mode)
 {
-    FILE *fp;
-    char  buf[256];
-
-    sprintf(buf, "gunzip -c < %s", fn);
-    fprintf(stderr, "Going to execute '%s'\n", buf);
-    if ((fp = popen(buf, mode)) == nullptr)
+    FILE*       fp  = nullptr;
+    std::string buf = "gunzip -c < ";
+    buf += fn;
+    fprintf(stderr, "Going to execute '%s'\n", buf.c_str());
+    if ((fp = popen(buf.c_str(), mode)) == nullptr)
     {
         gmx_open(fn);
     }
@@ -338,24 +333,22 @@ static FILE *gunzip(const char *fn, const char *mode)
     return fp;
 }
 
-gmx_bool gmx_fexist(const char *fname)
+gmx_bool gmx_fexist(const std::string& fname)
 {
-    FILE *test;
-
-    if (fname == nullptr)
+    if (fname.empty())
     {
         return FALSE;
     }
-    test = fopen(fname, "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 */
-        #if GMX_NATIVE_WINDOWS
-        DWORD attr = GetFileAttributes(fname);
+/*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);
-        #else
+#else
         return FALSE;
-        #endif
+#endif
     }
     else
     {
@@ -364,57 +357,39 @@ gmx_bool gmx_fexist(const char *fname)
     }
 }
 
-static char *backup_fn(const char *file)
+static std::string backup_fn(const std::string& file)
 {
-    int          i, count = 1;
-    char        *directory, *fn;
-    char        *buf;
+    int count = 1;
 
-    smalloc(buf, GMX_PATH_MAX);
-
-    for (i = strlen(file)-1; ((i > 0) && (file[i] != DIR_SEPARATOR)); i--)
-    {
-        ;
-    }
-    /* Must check whether i > 0, i.e. whether there is a directory
-     * in the file name. In that case we overwrite the / sign with
-     * a '\0' to end the directory string .
-     */
-    if (i > 0)
-    {
-        directory    = gmx_strdup(file);
-        directory[i] = '\0';
-        fn           = gmx_strdup(file+i+1);
-    }
-    else
+    std::string directory = gmx::Path::getParentPath(file);
+    std::string fn        = gmx::Path::getFilename(file);
+    std::string buf;
+    if (directory.empty())
     {
-        directory    = gmx_strdup(".");
-        fn           = gmx_strdup(file);
+        directory = ".";
     }
     do
     {
-        sprintf(buf, "%s/#%s.%d#", directory, fn, count);
+        buf = gmx::formatString("%s/#%s.%d#", directory.c_str(), fn.c_str(), count);
         count++;
-    }
-    while ((count <= s_maxBackupCount) && gmx_fexist(buf));
+    } while ((count <= s_maxBackupCount) && gmx_fexist(buf));
 
     /* Arbitrarily bail out */
     if (count > s_maxBackupCount)
     {
         /* TODO: The error message is only accurate for code that starts with
          * Gromacs command-line interface. */
-        gmx_fatal(FARGS, "Won't make more than %d backups of %s for you.\n"
+        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);
+                  s_maxBackupCount,
+                  fn.c_str());
     }
 
-    sfree(directory);
-    sfree(fn);
-
     return buf;
 }
 
-void make_backup(const char *name)
+void make_backup(const std::string& name)
 {
     if (s_maxBackupCount <= 0)
     {
@@ -422,31 +397,23 @@ void make_backup(const char *name)
     }
     if (gmx_fexist(name))
     {
-        char *backup = backup_fn(name);
-        if (rename(name, backup) == 0)
+        auto backup = backup_fn(name);
+        if (rename(name.c_str(), backup.c_str()) == 0)
         {
-            fprintf(stderr, "\nBack Off! I just backed up %s to %s\n",
-                    name, backup);
+            fprintf(stderr, "\nBack Off! I just backed up %s to %s\n", name.c_str(), backup.c_str());
         }
         else
         {
-            fprintf(stderr, "\nSorry couldn't backup %s to %s\n", name, backup);
+            fprintf(stderr, "\nSorry couldn't backup %s to %s\n", name.c_str(), backup.c_str());
         }
-        sfree(backup);
     }
 }
 
-FILE *gmx_ffopen(const char *file, const char *mode)
+FILE* gmx_ffopen(const std::string& file, const char* mode)
 {
-#ifdef SKIP_FFOPS
-    return fopen(file, mode);
-#else
-    FILE    *ff = nullptr;
-    char     buf[256], *bufsize = nullptr, *ptr;
-    gmx_bool bRead;
-    int      bs;
+    FILE* ff = nullptr;
 
-    if (file == nullptr)
+    if (file.empty())
     {
         return nullptr;
     }
@@ -455,59 +422,52 @@ FILE *gmx_ffopen(const char *file, const char *mode)
     {
         make_backup(file);
     }
-    where();
 
-    bRead = (mode[0] == 'r' && mode[1] != '+');
-    strcpy(buf, file);
-    if (!bRead || gmx_fexist(buf))
+    bool bRead = (mode[0] == 'r' && mode[1] != '+');
+    if (!bRead || gmx_fexist(file))
     {
-        if ((ff = fopen(buf, mode)) == nullptr)
+        if ((ff = fopen(file.c_str(), mode)) == nullptr)
         {
-            gmx_file(buf);
+            gmx_file(file);
         }
-        where();
         /* Check whether we should be using buffering (default) or not
          * (for debugging)
          */
+        const char* bufsize = 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
             {
-                snew(ptr, bs+8);
+                char* ptr = nullptr;
+                snew(ptr, bs + 8);
                 if (setvbuf(ff, ptr, _IOFBF, bs) != 0)
                 {
                     gmx_file("Buffering File");
                 }
             }
         }
-        where();
     }
     else
     {
-        sprintf(buf, "%s.Z", file);
-        if (gmx_fexist(buf))
+        std::string compressedFileName = file;
+        compressedFileName += ".Z";
+        if (gmx_fexist(compressedFileName))
         {
-            ff = uncompress(buf, mode);
+            ff = uncompress(compressedFileName, mode);
         }
         else
         {
-            sprintf(buf, "%s.gz", file);
-            if (gmx_fexist(buf))
+            compressedFileName = file;
+            compressedFileName += ".gz";
+            if (gmx_fexist(compressedFileName))
             {
-                ff = gunzip(buf, mode);
+                ff = gunzip(compressedFileName, mode);
             }
             else
             {
@@ -516,62 +476,63 @@ FILE *gmx_ffopen(const char *file, const char *mode)
         }
     }
     return ff;
-#endif
 }
 
+namespace gmx
+{
 
-char *low_gmxlibfn(const char *file, gmx_bool bAddCWD, gmx_bool bFatal)
+std::string findLibraryFile(const std::string& filename, bool bAddCWD, bool bFatal)
 {
+    std::string result;
     try
     {
-        const gmx::DataFileFinder &finder = gmx::getLibraryFileFinder();
-        std::string                result =
-            finder.findFile(gmx::DataFileOptions(file)
-                                .includeCurrentDir(bAddCWD)
-                                .throwIfNotFound(bFatal));
-        if (!result.empty())
-        {
-            return gmx_strdup(result.c_str());
-        }
+        const DataFileFinder& finder = getLibraryFileFinder();
+        result                       = finder.findFile(
+                DataFileOptions(filename).includeCurrentDir(bAddCWD).throwIfNotFound(bFatal));
     }
-    GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
-    return nullptr;
+    GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
+    return result;
 }
 
-FILE *low_libopen(const char *file, gmx_bool bFatal)
+std::string findLibraryFile(const char* filename, bool bAddCWD, bool bFatal)
 {
+    return findLibraryFile(std::string(filename), bAddCWD, bFatal);
+}
+
+FilePtr openLibraryFile(const std::string& filename, bool bAddCWD, bool bFatal)
+{
+    FilePtr fp;
     try
     {
-        const gmx::DataFileFinder &finder = gmx::getLibraryFileFinder();
-        FILE *fp =
-            finder.openFile(gmx::DataFileOptions(file)
-                                .includeCurrentDir(true)
-                                .throwIfNotFound(bFatal));
-        return fp;
+        const DataFileFinder& finder = getLibraryFileFinder();
+        fp = finder.openFile(DataFileOptions(filename).includeCurrentDir(bAddCWD).throwIfNotFound(bFatal));
     }
-    GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
-    return nullptr;
+    GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
+    return fp;
 }
 
-char *gmxlibfn(const char *file)
+FilePtr openLibraryFile(const char* filename, bool bAddCWD, bool bFatal)
 {
-    return low_gmxlibfn(file, TRUE, TRUE);
+    return openLibraryFile(std::string(filename), bAddCWD, bFatal);
 }
 
-FILE *libopen(const char *file)
-{
-    return low_libopen(file, TRUE);
-}
+} // namespace gmx
 
-void gmx_tmpnam(char *buf)
+/*! \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 i, len;
+    int len = 0;
 
     if ((len = strlen(buf)) < 7)
     {
         gmx_fatal(FARGS, "Buf passed to gmx_tmpnam must be at least 7 bytes long");
     }
-    for (i = len-6; (i < len); i++)
+    for (int i = len - 6; (i < len); i++)
     {
         buf[i] = 'X';
     }
@@ -583,182 +544,149 @@ void gmx_tmpnam(char *buf)
     _mktemp(buf);
     if (buf == NULL)
     {
-        gmx_fatal(FARGS, "Error creating temporary file %s: %s", buf,
-                  strerror(errno));
+        gmx_fatal(FARGS, "Error creating temporary file %s: %s", buf, strerror(errno));
     }
+    int fd = 0;
 #else
     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)
     {
-        gmx_fatal(FARGS, "Error creating temporary file %s: %s", buf,
-                  strerror(errno));
+        gmx_fatal(FARGS, "Error creating temporary file %s: %s", buf, strerror(errno));
     }
+#endif
+    return fd;
+}
+// TODO use std::string
+void gmx_tmpnam(char* buf)
+{
+    int fd = makeTemporaryFilename(buf);
+#if !GMX_NATIVE_WINDOWS
     close(fd);
-
 #endif
-
-    /* name in Buf should now be OK and file is CLOSED */
-
-    return;
 }
 
-FILE *gmx_fopen_temporary(char *buf)
+// TODO use std::string
+FILE* gmx_fopen_temporary(char* buf)
 {
-    int   i, len;
-    FILE *fpout = nullptr;
+    FILE* fpout = nullptr;
+    int   fd    = makeTemporaryFilename(buf);
 
-    if ((len = strlen(buf)) < 7)
-    {
-        gmx_fatal(FARGS, "Buf passed to gmx_fopentmp must be at least 7 bytes long");
-    }
-    for (i = len-6; (i < len); i++)
-    {
-        buf[i] = 'X';
-    }
-    /* mktemp is dangerous and we should use mkstemp instead, but
-     * since windows doesnt support it we have to separate the cases.
-     * 20090307: mktemp deprecated, use iso c++ _mktemp instead.
-     */
 #if GMX_NATIVE_WINDOWS
-    _mktemp(buf);
-    if (buf == NULL)
-    {
-        gmx_fatal(FARGS, "Error creating temporary file %s: %s", buf,
-                  strerror(errno));
-    }
     if ((fpout = fopen(buf, "w")) == NULL)
     {
         gmx_fatal(FARGS, "Cannot open temporary file %s", buf);
     }
 #else
-    int fd = mkstemp(buf);
-    if (fd < 0)
-    {
-        gmx_fatal(FARGS, "Error creating temporary file %s: %s", buf,
-                  strerror(errno));
-    }
     if ((fpout = fdopen(fd, "w")) == nullptr)
     {
         gmx_fatal(FARGS, "Cannot open temporary file %s", buf);
     }
 #endif
-    /* name in Buf should now be OK and file is open */
 
     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))
+    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)
+int gmx_file_copy(const char* oldname, const char* newname, gmx_bool copy_if_empty)
 {
-/* the full copy buffer size: */
-#define FILECOPY_BUFSIZE (1<<16)
-    FILE *in  = nullptr;
-    FILE *out = nullptr;
-    char *buf;
-
-    snew(buf, FILECOPY_BUFSIZE);
-
-    in = fopen(oldname, "rb");
+    gmx::FilePtr in(fopen(oldname, "rb"));
     if (!in)
     {
-        goto error;
+        return 1;
     }
 
     /* If we don't copy when empty, we postpone opening the file
        until we're actually ready to write. */
+    gmx::FilePtr out;
     if (copy_if_empty)
     {
-        out = fopen(newname, "wb");
+        out.reset(fopen(newname, "wb"));
         if (!out)
         {
-            goto error;
+            return 1;
         }
     }
 
-    while (!feof(in))
-    {
-        size_t nread;
+    /* the full copy buffer size: */
+    constexpr int     FILECOPY_BUFSIZE = 1 << 16;
+    std::vector<char> buf(FILECOPY_BUFSIZE);
 
-        nread = fread(buf, sizeof(char), FILECOPY_BUFSIZE, in);
+    while (!feof(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:
                    here we know we read something. */
-                out = fopen(newname, "wb");
+                out.reset(fopen(newname, "wb"));
                 if (!out)
                 {
-                    goto error;
+                    return 1;
                 }
             }
-            ret = fwrite(buf, sizeof(char), nread, out);
+            ret = fwrite(buf.data(), sizeof(char), nread, out.get());
             if (ret != nread)
             {
-                goto error;
+                return 1;
             }
         }
-        if (ferror(in))
+        if (ferror(in.get()))
         {
-            goto error;
+            return 1;
         }
     }
-    sfree(buf);
-    fclose(in);
-    fclose(out);
     return 0;
-error:
-    sfree(buf);
-    if (in)
-    {
-        fclose(in);
-    }
-    if (out)
-    {
-        fclose(out);
-    }
-    return 1;
-#undef FILECOPY_BUFSIZE
 }
 
 
-int gmx_fsync(FILE *fp)
+int gmx_fsync(FILEfp)
 {
     int rc = 0;
 
-#ifdef 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);
+        int fn = fileno(fp);
 #elif HAVE__FILENO
-        fn = _fileno(fp);
+        int fn = _fileno(fp);
 #else
-        fn = -1;
+        GMX_UNUSED_VALUE(fp);
+        int fn = -1;
 #endif
 
         /* do the actual fsync */
@@ -771,7 +699,6 @@ int gmx_fsync(FILE *fp)
 #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: */
@@ -794,30 +721,30 @@ int gmx_fsync(FILE *fp)
     return rc;
 }
 
-void gmx_chdir(const char *directory)
+void gmx_chdir(const chardirectory)
 {
 #if GMX_NATIVE_WINDOWS
     int rc = _chdir(directory);
 #else
-    int rc = chdir(directory);
+    int   rc   = chdir(directory);
 #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));
     }
 }
 
-void gmx_getcwd(char *buffer, size_t size)
+void gmx_getcwd(charbuffer, size_t size)
 {
 #if GMX_NATIVE_WINDOWS
-    char *pdum = _getcwd(buffer, size);
+    charpdum = _getcwd(buffer, size);
 #else
-    char *pdum = getcwd(buffer, size);
+    charpdum = getcwd(buffer, size);
 #endif
     if (pdum == nullptr)
     {
-        gmx_fatal(FARGS, "Cannot get working directory. Reason: %s",
-                  strerror(errno));
+        gmx_fatal(FARGS, "Cannot get working directory. Reason: %s", strerror(errno));
     }
 }