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, 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.
49 #include <sys/types.h>
54 #ifdef GMX_NATIVE_WINDOWS
55 #include <direct.h> // For _chdir() and _getcwd()
60 #include "thread_mpi/threads.h"
62 #include "gromacs/utility/cstringutil.h"
63 #include "gromacs/utility/datafilefinder.h"
64 #include "gromacs/utility/dir_separator.h"
65 #include "gromacs/utility/exceptions.h"
66 #include "gromacs/utility/fatalerror.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"
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)
76 typedef struct t_pstack {
78 struct t_pstack *prev;
81 static t_pstack *pstack = NULL;
82 static bool bUnbuffered = false;
83 static int s_maxBackupCount = 0;
85 /* this linked list is an intrinsically globally shared object, so we have
86 to protect it with mutexes */
87 static tMPI_Thread_mutex_t pstack_mutex = TMPI_THREAD_MUTEX_INITIALIZER;
93 //! Global library file finder; stores the object set with setLibraryFileFinder().
94 const DataFileFinder *g_libFileFinder;
95 //! Default library file finder if nothing is set.
96 const DataFileFinder g_defaultLibFileFinder;
99 const DataFileFinder &getLibraryFileFinder()
101 if (g_libFileFinder != NULL)
103 return *g_libFileFinder;
105 return g_defaultLibFileFinder;
108 void setLibraryFileFinder(const DataFileFinder *finder)
110 g_libFileFinder = finder;
115 void gmx_disable_file_buffering(void)
120 void gmx_set_max_backup_count(int count)
124 const char *env = getenv("GMX_MAXBACKUP");
127 // TODO: Check that the value is converted properly.
128 count = strtol(env, NULL, 10);
136 // Use a reasonably low value for countmax; we might
137 // generate 4-5 files in each round, and we don't
138 // want to hit directory limits of 1024 or 2048 files.
142 s_maxBackupCount = count;
145 void push_ps(FILE *fp)
149 tMPI_Thread_mutex_lock(&pstack_mutex);
156 tMPI_Thread_mutex_unlock(&pstack_mutex);
160 /* don't use pipes!*/
161 #define popen fah_fopen
162 #define pclose fah_fclose
168 #if (!HAVE_PIPES && !defined(__native_client__))
169 static FILE *popen(const char *nm, const char *mode)
171 gmx_impl("Sorry no pipes...");
176 static int pclose(FILE *fp)
178 gmx_impl("Sorry no pipes...");
182 #endif /* !HAVE_PIPES && !defined(__native_client__) */
183 #endif /* GMX_FAHCORE */
185 int gmx_ffclose(FILE *fp)
193 tMPI_Thread_mutex_lock(&pstack_mutex);
203 else if (ps->fp == fp)
209 pstack = pstack->prev;
214 while ((ps->prev != NULL) && (ps->prev->fp != fp))
218 if ((ps->prev != NULL) && ps->prev->fp == fp)
220 if (ps->prev->fp != NULL)
222 ret = pclose(ps->prev->fp);
225 ps->prev = ps->prev->prev;
237 tMPI_Thread_mutex_unlock(&pstack_mutex);
243 void frewind(FILE *fp)
245 tMPI_Thread_mutex_lock(&pstack_mutex);
247 t_pstack *ps = pstack;
252 fprintf(stderr, "Cannot rewind compressed file!\n");
253 tMPI_Thread_mutex_unlock(&pstack_mutex);
259 tMPI_Thread_mutex_unlock(&pstack_mutex);
262 int gmx_fseek(FILE *stream, gmx_off_t offset, int whence)
265 return fseeko(stream, offset, whence);
267 #ifdef HAVE__FSEEKI64
268 return _fseeki64(stream, offset, whence);
270 return fseek(stream, offset, whence);
275 gmx_off_t gmx_ftell(FILE *stream)
278 return ftello(stream);
280 #ifdef HAVE__FSEEKI64
282 return _ftelli64(stream);
284 return ftello64(stream);
287 return ftell(stream);
292 int gmx_truncate(const char *filename, gmx_off_t length)
294 #ifdef GMX_NATIVE_WINDOWS
295 FILE *fp = fopen(filename, "rb+");
301 int rc = _chsize_s(fileno(fp), length);
303 int rc = _chsize(fileno(fp), length);
308 return truncate(filename, length);
312 static FILE *uncompress(const char *fn, const char *mode)
317 sprintf(buf, "uncompress -c < %s", fn);
318 fprintf(stderr, "Going to execute '%s'\n", buf);
319 if ((fp = popen(buf, mode)) == NULL)
328 static FILE *gunzip(const char *fn, const char *mode)
333 sprintf(buf, "gunzip -c < %s", fn);
334 fprintf(stderr, "Going to execute '%s'\n", buf);
335 if ((fp = popen(buf, mode)) == NULL)
344 gmx_bool gmx_fexist(const char *fname)
352 test = fopen(fname, "r");
355 /*Windows doesn't allow fopen of directory - so we need to check this seperately */
356 #ifdef GMX_NATIVE_WINDOWS
357 DWORD attr = GetFileAttributes(fname);
358 return (attr != INVALID_FILE_ATTRIBUTES) && (attr & FILE_ATTRIBUTE_DIRECTORY);
370 static char *backup_fn(const char *file)
373 char *directory, *fn;
376 smalloc(buf, GMX_PATH_MAX);
378 for (i = strlen(file)-1; ((i > 0) && (file[i] != DIR_SEPARATOR)); i--)
382 /* Must check whether i > 0, i.e. whether there is a directory
383 * in the file name. In that case we overwrite the / sign with
384 * a '\0' to end the directory string .
388 directory = gmx_strdup(file);
390 fn = gmx_strdup(file+i+1);
394 directory = gmx_strdup(".");
395 fn = gmx_strdup(file);
399 sprintf(buf, "%s/#%s.%d#", directory, fn, count);
402 while ((count <= s_maxBackupCount) && gmx_fexist(buf));
404 /* Arbitrarily bail out */
405 if (count > s_maxBackupCount)
407 /* TODO: The error message is only accurate for code that starts with
408 * Gromacs command-line interface. */
409 gmx_fatal(FARGS, "Won't make more than %d backups of %s for you.\n"
410 "The env.var. GMX_MAXBACKUP controls this maximum, -1 disables backups.",
411 s_maxBackupCount, fn);
420 void make_backup(const char *name)
422 if (s_maxBackupCount <= 0)
426 if (gmx_fexist(name))
428 char *backup = backup_fn(name);
429 if (rename(name, backup) == 0)
431 fprintf(stderr, "\nBack Off! I just backed up %s to %s\n",
436 fprintf(stderr, "\nSorry couldn't backup %s to %s\n", name, backup);
442 FILE *gmx_ffopen(const char *file, const char *mode)
445 return fopen(file, mode);
448 char buf[256], *bufsize = 0, *ptr;
463 bRead = (mode[0] == 'r' && mode[1] != '+');
465 if (!bRead || gmx_fexist(buf))
467 if ((ff = fopen(buf, mode)) == NULL)
472 /* Check whether we should be using buffering (default) or not
475 if (bUnbuffered || ((bufsize = getenv("GMX_LOG_BUFFER")) != NULL))
477 /* Check whether to use completely unbuffered */
484 bs = strtol(bufsize, NULL, 10);
493 if (setvbuf(ff, ptr, _IOFBF, bs) != 0)
495 gmx_file("Buffering File");
503 sprintf(buf, "%s.Z", file);
506 ff = uncompress(buf, mode);
510 sprintf(buf, "%s.gz", file);
513 ff = gunzip(buf, mode);
526 char *low_gmxlibfn(const char *file, gmx_bool bAddCWD, gmx_bool bFatal)
530 const gmx::DataFileFinder &finder = gmx::getLibraryFileFinder();
532 finder.findFile(gmx::DataFileOptions(file)
533 .includeCurrentDir(bAddCWD)
534 .throwIfNotFound(bFatal));
537 return gmx_strdup(result.c_str());
540 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
544 FILE *low_libopen(const char *file, gmx_bool bFatal)
548 const gmx::DataFileFinder &finder = gmx::getLibraryFileFinder();
550 finder.openFile(gmx::DataFileOptions(file)
551 .includeCurrentDir(true)
552 .throwIfNotFound(bFatal));
555 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
559 char *gmxlibfn(const char *file)
561 return low_gmxlibfn(file, TRUE, TRUE);
564 FILE *libopen(const char *file)
566 return low_libopen(file, TRUE);
569 void gmx_tmpnam(char *buf)
573 if ((len = strlen(buf)) < 7)
575 gmx_fatal(FARGS, "Buf passed to gmx_tmpnam must be at least 7 bytes long");
577 for (i = len-6; (i < len); i++)
581 /* mktemp is dangerous and we should use mkstemp instead, but
582 * since windows doesnt support it we have to separate the cases.
583 * 20090307: mktemp deprecated, use iso c++ _mktemp instead.
585 #ifdef GMX_NATIVE_WINDOWS
588 int fd = mkstemp(buf);
592 gmx_fatal(FARGS, "Creating temporary file %s: %s", buf,
597 /* name in Buf should now be OK */
600 int gmx_file_rename(const char *oldname, const char *newname)
602 #ifndef GMX_NATIVE_WINDOWS
603 /* under unix, rename() is atomic (at least, it should be). */
604 return rename(oldname, newname);
606 if (MoveFileEx(oldname, newname,
607 MOVEFILE_REPLACE_EXISTING|MOVEFILE_WRITE_THROUGH))
618 int gmx_file_copy(const char *oldname, const char *newname, gmx_bool copy_if_empty)
620 /* the full copy buffer size: */
621 #define FILECOPY_BUFSIZE (1<<16)
626 snew(buf, FILECOPY_BUFSIZE);
628 in = fopen(oldname, "rb");
634 /* If we don't copy when empty, we postpone opening the file
635 until we're actually ready to write. */
638 out = fopen(newname, "wb");
649 nread = fread(buf, sizeof(char), FILECOPY_BUFSIZE, in);
655 /* so this is where we open when copy_if_empty is false:
656 here we know we read something. */
657 out = fopen(newname, "wb");
663 ret = fwrite(buf, sizeof(char), nread, out);
689 #undef FILECOPY_BUFSIZE
693 int gmx_fsync(FILE *fp)
698 /* the fahcore defines its own os-independent fsync */
700 #else /* GMX_FAHCORE */
704 /* get the file number */
705 #if defined(HAVE_FILENO)
707 #elif defined(HAVE__FILENO)
713 /* do the actual fsync */
716 #if (defined(HAVE_FSYNC))
718 #elif (defined(HAVE__COMMIT))
723 #endif /* GMX_FAHCORE */
725 /* We check for these error codes this way because POSIX requires them
726 to be defined, and using anything other than macros is unlikely: */
728 /* we don't want to report an error just because fsync() caught a signal.
729 For our purposes, we can just ignore this. */
730 if (rc && errno == EINTR)
736 /* we don't want to report an error just because we tried to fsync()
737 stdout, a socket or a pipe. */
738 if (rc && errno == EINVAL)
746 void gmx_chdir(const char *directory)
748 #ifdef GMX_NATIVE_WINDOWS
749 int rc = _chdir(directory);
751 int rc = chdir(directory);
755 gmx_fatal(FARGS, "Cannot change directory to '%s'. Reason: %s",
756 directory, strerror(errno));
760 void gmx_getcwd(char *buffer, size_t size)
762 #ifdef GMX_NATIVE_WINDOWS
763 char *pdum = _getcwd(buffer, size);
765 char *pdum = getcwd(buffer, size);
769 gmx_fatal(FARGS, "Cannot get working directory. Reason: %s",