summaryrefslogtreecommitdiff
path: root/readline/readline/histfile.c
diff options
context:
space:
mode:
Diffstat (limited to 'readline/readline/histfile.c')
-rw-r--r--readline/readline/histfile.c52
1 files changed, 40 insertions, 12 deletions
diff --git a/readline/readline/histfile.c b/readline/readline/histfile.c
index 8eb34966875..f0fa5ce15fe 100644
--- a/readline/readline/histfile.c
+++ b/readline/readline/histfile.c
@@ -1,6 +1,6 @@
/* histfile.c - functions to manipulate the history file. */
-/* Copyright (C) 1989-2018 Free Software Foundation, Inc.
+/* Copyright (C) 1989-2019 Free Software Foundation, Inc.
This file contains the GNU History Library (History), a set of
routines for managing the text of previously typed lines.
@@ -26,6 +26,8 @@
#define READLINE_LIBRARY
#if defined (__TANDEM)
+# define _XOPEN_SOURCE_EXTENDED 1
+# include <unistd.h>
# include <floss.h>
#endif
@@ -79,6 +81,11 @@
#endif /* HISTORY_USE_MMAP */
+#if defined(_WIN32)
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+#endif
+
/* If we're compiling for __EMX__ (OS/2) or __CYGWIN__ (cygwin32 environment
on win 95/98/nt), we want to open files with O_BINARY mode so that there
is no \n -> \r\n conversion performed. On other systems, we don't want to
@@ -138,6 +145,7 @@ static char *history_backupfile PARAMS((const char *));
static char *history_tempfile PARAMS((const char *));
static int histfile_backup PARAMS((const char *, const char *));
static int histfile_restore PARAMS((const char *, const char *));
+static int history_rename PARAMS((const char *, const char *));
/* Return the string that should be used in the place of this
filename. This only matters when you don't specify the
@@ -449,6 +457,18 @@ read_history_range (const char *filename, int from, int to)
return (0);
}
+/* We need a special version for WIN32 because Windows rename() refuses to
+ overwrite an existing file. */
+static int
+history_rename (const char *old, const char *new)
+{
+#if defined (_WIN32)
+ return (MoveFileEx (old, new, MOVEFILE_REPLACE_EXISTING) == 0 ? -1 : 0);
+#else
+ return (rename (old, new));
+#endif
+}
+
/* Save FILENAME to BACK, handling case where FILENAME is a symlink
(e.g., ~/.bash_history -> .histfiles/.bash_history.$HOSTNAME) */
static int
@@ -462,10 +482,10 @@ histfile_backup (const char *filename, const char *back)
if ((n = readlink (filename, linkbuf, sizeof (linkbuf) - 1)) > 0)
{
linkbuf[n] = '\0';
- return (rename (linkbuf, back));
+ return (history_rename (linkbuf, back));
}
#endif
- return (rename (filename, back));
+ return (history_rename (filename, back));
}
/* Restore ORIG from BACKUP handling case where ORIG is a symlink
@@ -481,12 +501,18 @@ histfile_restore (const char *backup, const char *orig)
if ((n = readlink (orig, linkbuf, sizeof (linkbuf) - 1)) > 0)
{
linkbuf[n] = '\0';
- return (rename (backup, linkbuf));
+ return (history_rename (backup, linkbuf));
}
#endif
- return (rename (backup, orig));
+ return (history_rename (backup, orig));
}
+/* Should we call chown, based on whether finfo and nfinfo describe different
+ files with different owners? */
+
+#define SHOULD_CHOWN(finfo, nfinfo) \
+ (finfo.st_uid != nfinfo.st_uid || finfo.st_gid != nfinfo.st_gid)
+
/* Truncate the history file FNAME, leaving only LINES trailing lines.
If FNAME is NULL, then use ~/.history. Writes a new file and renames
it to the original name. Returns 0 on success, errno on failure. */
@@ -495,7 +521,7 @@ history_truncate_file (const char *fname, int lines)
{
char *buffer, *filename, *tempname, *bp, *bp1; /* bp1 == bp+1 */
int file, chars_read, rv, orig_lines, exists, r;
- struct stat finfo;
+ struct stat finfo, nfinfo;
size_t file_size;
history_lines_written_to_file = 0;
@@ -516,6 +542,9 @@ history_truncate_file (const char *fname, int lines)
}
exists = 1;
+ nfinfo.st_uid = finfo.st_uid;
+ nfinfo.st_gid = finfo.st_gid;
+
if (S_ISREG (finfo.st_mode) == 0)
{
close (file);
@@ -604,6 +633,9 @@ history_truncate_file (const char *fname, int lines)
if (write (file, bp, chars_read - (bp - buffer)) < 0)
rv = errno;
+ if (fstat (file, &nfinfo) < 0 && rv == 0)
+ rv = errno;
+
if (close (file) < 0 && rv == 0)
rv = errno;
}
@@ -631,7 +663,7 @@ history_truncate_file (const char *fname, int lines)
user is running this, it's a no-op. If the shell is running after sudo
with a shared history file, we don't want to leave the history file
owned by root. */
- if (rv == 0 && exists)
+ if (rv == 0 && exists && SHOULD_CHOWN (finfo, nfinfo))
r = chown (filename, finfo.st_uid, finfo.st_gid);
#endif
@@ -650,7 +682,7 @@ history_do_write (const char *filename, int nelements, int overwrite)
register int i;
char *output, *tempname, *histname;
int file, mode, rv, exists;
- struct stat finfo;
+ struct stat finfo, nfinfo;
#ifdef HISTORY_USE_MMAP
size_t cursize;
@@ -695,15 +727,11 @@ history_do_write (const char *filename, int nelements, int overwrite)
the_history = history_list ();
/* Calculate the total number of bytes to write. */
for (buffer_size = 0, i = history_length - nelements; i < history_length; i++)
-#if 0
- buffer_size += 2 + HISTENT_BYTES (the_history[i]);
-#else
{
if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0])
buffer_size += strlen (the_history[i]->timestamp) + 1;
buffer_size += strlen (the_history[i]->line) + 1;
}
-#endif
/* Allocate the buffer, and fill it. */
#ifdef HISTORY_USE_MMAP