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, 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.
50 #include <sys/types.h>
55 #if GMX_NATIVE_WINDOWS
56 #include <direct.h> // For _chdir() and _getcwd()
61 #include "thread_mpi/threads.h"
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/path.h"
69 #include "gromacs/utility/programcontext.h"
70 #include "gromacs/utility/smalloc.h"
71 #include "gromacs/utility/stringutil.h"
73 /* we keep a linked list of all files opened through pipes (i.e.
74 compressed or .gzipped files. This way we can distinguish between them
75 without having to change the semantics of reading from/writing to files)
77 typedef struct t_pstack {
79 struct t_pstack *prev;
82 static t_pstack *pstack = NULL;
83 static bool bUnbuffered = false;
84 static int s_maxBackupCount = 0;
86 /* this linked list is an intrinsically globally shared object, so we have
87 to protect it with mutexes */
88 static tMPI_Thread_mutex_t pstack_mutex = TMPI_THREAD_MUTEX_INITIALIZER;
94 //! Global library file finder; stores the object set with setLibraryFileFinder().
95 const DataFileFinder *g_libFileFinder;
96 //! Default library file finder if nothing is set.
97 const DataFileFinder g_defaultLibFileFinder;
100 const DataFileFinder &getLibraryFileFinder()
102 if (g_libFileFinder != NULL)
104 return *g_libFileFinder;
106 return g_defaultLibFileFinder;
109 void setLibraryFileFinder(const DataFileFinder *finder)
111 g_libFileFinder = finder;
116 void gmx_disable_file_buffering(void)
121 void gmx_set_max_backup_count(int count)
125 const char *env = getenv("GMX_MAXBACKUP");
128 // TODO: Check that the value is converted properly.
129 count = strtol(env, NULL, 10);
137 // Use a reasonably low value for countmax; we might
138 // generate 4-5 files in each round, and we don't
139 // want to hit directory limits of 1024 or 2048 files.
143 s_maxBackupCount = count;
146 void push_ps(FILE *fp)
150 tMPI_Thread_mutex_lock(&pstack_mutex);
157 tMPI_Thread_mutex_unlock(&pstack_mutex);
161 /* don't use pipes!*/
162 #define popen fah_fopen
163 #define pclose fah_fclose
169 #if (!HAVE_PIPES && !defined(__native_client__))
170 static FILE *popen(const char *nm, const char *mode)
172 gmx_impl("Sorry no pipes...");
177 static int pclose(FILE *fp)
179 gmx_impl("Sorry no pipes...");
183 #endif /* !HAVE_PIPES && !defined(__native_client__) */
184 #endif /* GMX_FAHCORE */
186 int gmx_ffclose(FILE *fp)
194 tMPI_Thread_mutex_lock(&pstack_mutex);
204 else if (ps->fp == fp)
210 pstack = pstack->prev;
215 while ((ps->prev != NULL) && (ps->prev->fp != fp))
219 if ((ps->prev != NULL) && ps->prev->fp == fp)
221 if (ps->prev->fp != NULL)
223 ret = pclose(ps->prev->fp);
226 ps->prev = ps->prev->prev;
238 tMPI_Thread_mutex_unlock(&pstack_mutex);
244 void frewind(FILE *fp)
246 tMPI_Thread_mutex_lock(&pstack_mutex);
248 t_pstack *ps = pstack;
253 fprintf(stderr, "Cannot rewind compressed file!\n");
254 tMPI_Thread_mutex_unlock(&pstack_mutex);
260 tMPI_Thread_mutex_unlock(&pstack_mutex);
263 int gmx_fseek(FILE *stream, gmx_off_t offset, int whence)
266 return fseeko(stream, offset, whence);
269 return _fseeki64(stream, offset, whence);
271 return fseek(stream, offset, whence);
276 gmx_off_t gmx_ftell(FILE *stream)
279 return ftello(stream);
283 return _ftelli64(stream);
285 return ftello64(stream);
288 return ftell(stream);
293 int gmx_truncate(const char *filename, gmx_off_t length)
295 #if GMX_NATIVE_WINDOWS
296 FILE *fp = fopen(filename, "rb+");
302 int rc = _chsize_s(fileno(fp), length);
304 int rc = _chsize(fileno(fp), length);
309 return truncate(filename, length);
313 static FILE *uncompress(const char *fn, const char *mode)
318 sprintf(buf, "uncompress -c < %s", fn);
319 fprintf(stderr, "Going to execute '%s'\n", buf);
320 if ((fp = popen(buf, mode)) == NULL)
329 static FILE *gunzip(const char *fn, const char *mode)
334 sprintf(buf, "gunzip -c < %s", fn);
335 fprintf(stderr, "Going to execute '%s'\n", buf);
336 if ((fp = popen(buf, mode)) == NULL)
345 gmx_bool gmx_fexist(const char *fname)
353 test = fopen(fname, "r");
356 /*Windows doesn't allow fopen of directory - so we need to check this seperately */
357 #if GMX_NATIVE_WINDOWS
358 DWORD attr = GetFileAttributes(fname);
359 return (attr != INVALID_FILE_ATTRIBUTES) && (attr & FILE_ATTRIBUTE_DIRECTORY);
371 static char *backup_fn(const char *file)
374 char *directory, *fn;
377 smalloc(buf, GMX_PATH_MAX);
379 for (i = strlen(file)-1; ((i > 0) && (file[i] != DIR_SEPARATOR)); i--)
383 /* Must check whether i > 0, i.e. whether there is a directory
384 * in the file name. In that case we overwrite the / sign with
385 * a '\0' to end the directory string .
389 directory = gmx_strdup(file);
391 fn = gmx_strdup(file+i+1);
395 directory = gmx_strdup(".");
396 fn = gmx_strdup(file);
400 sprintf(buf, "%s/#%s.%d#", directory, fn, count);
403 while ((count <= s_maxBackupCount) && gmx_fexist(buf));
405 /* Arbitrarily bail out */
406 if (count > s_maxBackupCount)
408 /* TODO: The error message is only accurate for code that starts with
409 * Gromacs command-line interface. */
410 gmx_fatal(FARGS, "Won't make more than %d backups of %s for you.\n"
411 "The env.var. GMX_MAXBACKUP controls this maximum, -1 disables backups.",
412 s_maxBackupCount, fn);
421 void make_backup(const char *name)
423 if (s_maxBackupCount <= 0)
427 if (gmx_fexist(name))
429 char *backup = backup_fn(name);
430 if (rename(name, backup) == 0)
432 fprintf(stderr, "\nBack Off! I just backed up %s to %s\n",
437 fprintf(stderr, "\nSorry couldn't backup %s to %s\n", name, backup);
443 FILE *gmx_ffopen(const char *file, const char *mode)
446 return fopen(file, mode);
449 char buf[256], *bufsize = 0, *ptr;
464 bRead = (mode[0] == 'r' && mode[1] != '+');
466 if (!bRead || gmx_fexist(buf))
468 if ((ff = fopen(buf, mode)) == NULL)
473 /* Check whether we should be using buffering (default) or not
476 if (bUnbuffered || ((bufsize = getenv("GMX_LOG_BUFFER")) != NULL))
478 /* Check whether to use completely unbuffered */
485 bs = strtol(bufsize, NULL, 10);
494 if (setvbuf(ff, ptr, _IOFBF, bs) != 0)
496 gmx_file("Buffering File");
504 sprintf(buf, "%s.Z", file);
507 ff = uncompress(buf, mode);
511 sprintf(buf, "%s.gz", file);
514 ff = gunzip(buf, mode);
527 char *low_gmxlibfn(const char *file, gmx_bool bAddCWD, gmx_bool bFatal)
531 const gmx::DataFileFinder &finder = gmx::getLibraryFileFinder();
533 finder.findFile(gmx::DataFileOptions(file)
534 .includeCurrentDir(bAddCWD)
535 .throwIfNotFound(bFatal));
538 return gmx_strdup(result.c_str());
541 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
545 FILE *low_libopen(const char *file, gmx_bool bFatal)
549 const gmx::DataFileFinder &finder = gmx::getLibraryFileFinder();
551 finder.openFile(gmx::DataFileOptions(file)
552 .includeCurrentDir(true)
553 .throwIfNotFound(bFatal));
556 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
560 char *gmxlibfn(const char *file)
562 return low_gmxlibfn(file, TRUE, TRUE);
565 FILE *libopen(const char *file)
567 return low_libopen(file, TRUE);
570 void gmx_tmpnam(char *buf)
574 if ((len = strlen(buf)) < 7)
576 gmx_fatal(FARGS, "Buf passed to gmx_tmpnam must be at least 7 bytes long");
578 for (i = len-6; (i < len); i++)
582 /* mktemp is dangerous and we should use mkstemp instead, but
583 * since windows doesnt support it we have to separate the cases.
584 * 20090307: mktemp deprecated, use iso c++ _mktemp instead.
586 #if GMX_NATIVE_WINDOWS
590 gmx_fatal(FARGS, "Error creating temporary file %s: %s", buf,
594 int fd = mkstemp(buf);
598 gmx_fatal(FARGS, "Error creating temporary file %s: %s", buf,
605 /* name in Buf should now be OK and file is CLOSED */
610 FILE *gmx_fopen_temporary(char *buf)
615 if ((len = strlen(buf)) < 7)
617 gmx_fatal(FARGS, "Buf passed to gmx_fopentmp must be at least 7 bytes long");
619 for (i = len-6; (i < len); i++)
623 /* mktemp is dangerous and we should use mkstemp instead, but
624 * since windows doesnt support it we have to separate the cases.
625 * 20090307: mktemp deprecated, use iso c++ _mktemp instead.
627 #if GMX_NATIVE_WINDOWS
631 gmx_fatal(FARGS, "Error creating temporary file %s: %s", buf,
634 if ((fpout = fopen(buf, "w")) == NULL)
636 gmx_fatal(FARGS, "Cannot open temporary file %s", buf);
639 int fd = mkstemp(buf);
642 gmx_fatal(FARGS, "Error creating temporary file %s: %s", buf,
645 if ((fpout = fdopen(fd, "w")) == NULL)
647 gmx_fatal(FARGS, "Cannot open temporary file %s", buf);
650 /* name in Buf should now be OK and file is open */
655 int gmx_file_rename(const char *oldname, const char *newname)
657 #if !GMX_NATIVE_WINDOWS
658 /* under unix, rename() is atomic (at least, it should be). */
659 return rename(oldname, newname);
661 if (MoveFileEx(oldname, newname,
662 MOVEFILE_REPLACE_EXISTING|MOVEFILE_WRITE_THROUGH))
673 int gmx_file_copy(const char *oldname, const char *newname, gmx_bool copy_if_empty)
675 /* the full copy buffer size: */
676 #define FILECOPY_BUFSIZE (1<<16)
681 snew(buf, FILECOPY_BUFSIZE);
683 in = fopen(oldname, "rb");
689 /* If we don't copy when empty, we postpone opening the file
690 until we're actually ready to write. */
693 out = fopen(newname, "wb");
704 nread = fread(buf, sizeof(char), FILECOPY_BUFSIZE, in);
710 /* so this is where we open when copy_if_empty is false:
711 here we know we read something. */
712 out = fopen(newname, "wb");
718 ret = fwrite(buf, sizeof(char), nread, out);
744 #undef FILECOPY_BUFSIZE
748 int gmx_fsync(FILE *fp)
753 /* the fahcore defines its own os-independent fsync */
755 #else /* GMX_FAHCORE */
759 /* get the file number */
768 /* do the actual fsync */
778 #endif /* GMX_FAHCORE */
780 /* We check for these error codes this way because POSIX requires them
781 to be defined, and using anything other than macros is unlikely: */
783 /* we don't want to report an error just because fsync() caught a signal.
784 For our purposes, we can just ignore this. */
785 if (rc && errno == EINTR)
791 /* we don't want to report an error just because we tried to fsync()
792 stdout, a socket or a pipe. */
793 if (rc && errno == EINVAL)
801 void gmx_chdir(const char *directory)
803 #if GMX_NATIVE_WINDOWS
804 int rc = _chdir(directory);
806 int rc = chdir(directory);
810 gmx_fatal(FARGS, "Cannot change directory to '%s'. Reason: %s",
811 directory, strerror(errno));
815 void gmx_getcwd(char *buffer, size_t size)
817 #if GMX_NATIVE_WINDOWS
818 char *pdum = _getcwd(buffer, size);
820 char *pdum = getcwd(buffer, size);
824 gmx_fatal(FARGS, "Cannot get working directory. Reason: %s",