Diff for /embedaddon/readline/histfile.c between versions 1.1 and 1.1.1.2

version 1.1, 2014/07/30 08:16:45 version 1.1.1.2, 2021/03/17 01:01:01
Line 1 Line 1
 /* histfile.c - functions to manipulate the history file. */  /* histfile.c - functions to manipulate the history file. */
   
/* Copyright (C) 1989-2010 Free Software Foundation, Inc./* Copyright (C) 1989-2019 Free Software Foundation, Inc.
   
    This file contains the GNU History Library (History), a set of     This file contains the GNU History Library (History), a set of
    routines for managing the text of previously typed lines.     routines for managing the text of previously typed lines.
Line 26 Line 26
 #define READLINE_LIBRARY  #define READLINE_LIBRARY
   
 #if defined (__TANDEM)  #if defined (__TANDEM)
   #  define _XOPEN_SOURCE_EXTENDED 1
   #  include <unistd.h>
 #  include <floss.h>  #  include <floss.h>
 #endif  #endif
   
Line 35 Line 37
   
 #include <stdio.h>  #include <stdio.h>
   
   #if defined (HAVE_LIMITS_H)
   #  include <limits.h>
   #endif
   
 #include <sys/types.h>  #include <sys/types.h>
 #if ! defined (_MINIX) && defined (HAVE_SYS_FILE_H)  #if ! defined (_MINIX) && defined (HAVE_SYS_FILE_H)
 #  include <sys/file.h>  #  include <sys/file.h>
Line 75 Line 81
   
 #endif /* HISTORY_USE_MMAP */  #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  /* 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     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     is no \n -> \r\n conversion performed.  On other systems, we don't want to
Line 99  extern int errno; Line 110  extern int errno;
 #include "rlshell.h"  #include "rlshell.h"
 #include "xmalloc.h"  #include "xmalloc.h"
   
   #if !defined (PATH_MAX)
   #  define PATH_MAX      1024    /* default */
   #endif
   
   extern void _hs_append_history_line PARAMS((int, const char *));
   
   /* history file version; currently unused */
   int history_file_version = 1;
   
 /* If non-zero, we write timestamps to the history file in history_do_write() */  /* If non-zero, we write timestamps to the history file in history_do_write() */
 int history_write_timestamps = 0;  int history_write_timestamps = 0;
   
   /* If non-zero, we assume that a history file that starts with a timestamp
      uses timestamp-delimited entries and can include multi-line history
      entries. Used by read_history_range */
   int history_multiline_entries = 0;
   
   /* Immediately after a call to read_history() or read_history_range(), this
      will return the number of lines just read from the history file in that
      call. */
   int history_lines_read_from_file = 0;
   
   /* Immediately after a call to write_history() or history_do_write(), this
      will return the number of lines just written to the history file in that
      call.  This also works with history_truncate_file. */
   int history_lines_written_to_file = 0;
   
 /* Does S look like the beginning of a history timestamp entry?  Placeholder  /* Does S look like the beginning of a history timestamp entry?  Placeholder
    for more extensive tests. */     for more extensive tests. */
#define HIST_TIMESTAMP_START(s)         (*(s) == history_comment_char && isdigit ((s)[1]) )#define HIST_TIMESTAMP_START(s)         (*(s) == history_comment_char && isdigit ((unsigned char)(s)[1]) )
   
   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  /* Return the string that should be used in the place of this
    filename.  This only matters when you don't specify the     filename.  This only matters when you don't specify the
    filename to read_history (), or write_history (). */     filename to read_history (), or write_history (). */
 static char *  static char *
history_filename (filename)history_filename (const char *filename)
     const char *filename; 
 {  {
   char *return_val;    char *return_val;
   const char *home;    const char *home;
Line 123  history_filename (filename) Line 163  history_filename (filename)
     return (return_val);      return (return_val);
       
   home = sh_get_env_value ("HOME");    home = sh_get_env_value ("HOME");
   #if defined (_WIN32)
     if (home == 0)
       home = sh_get_env_value ("APPDATA");
   #endif
   
   if (home == 0)    if (home == 0)
     return (NULL);      return (NULL);
Line 142  history_filename (filename) Line 186  history_filename (filename)
 }  }
   
 static char *  static char *
history_backupfile (filename)history_backupfile (const char *filename)
     const char *filename; 
 {  {
  char *ret;  const char *fn;
   char *ret, linkbuf[PATH_MAX+1];
   size_t len;    size_t len;
     ssize_t n;
     struct stat fs;
   
  len = strlen (filename);  fn = filename;  
 #if defined (HAVE_READLINK)
   /* Follow symlink to avoid backing up symlink itself; call will fail if
      not a symlink */
   if ((n = readlink (filename, linkbuf, sizeof (linkbuf) - 1)) > 0)
     {
       linkbuf[n] = '\0';
       fn = linkbuf;
     }
 #endif
       
   len = strlen (fn);
   ret = xmalloc (len + 2);    ret = xmalloc (len + 2);
  strcpy (ret, filename);  strcpy (ret, fn);
   ret[len] = '-';    ret[len] = '-';
   ret[len+1] = '\0';    ret[len+1] = '\0';
   return ret;    return ret;
 }  }
       
   static char *
   history_tempfile (const char *filename)
   {
     const char *fn;
     char *ret, linkbuf[PATH_MAX+1];
     size_t len;
     ssize_t n;
     struct stat fs;
     int pid;
   
     fn = filename;  
   #if defined (HAVE_READLINK)
     /* Follow symlink so tempfile created in the same directory as any symlinked
        history file; call will fail if not a symlink */
     if ((n = readlink (filename, linkbuf, sizeof (linkbuf) - 1)) > 0)
       {
         linkbuf[n] = '\0';
         fn = linkbuf;
       }
   #endif
         
     len = strlen (fn);
     ret = xmalloc (len + 11);
     strcpy (ret, fn);
   
     pid = (int)getpid ();
   
     /* filename-PID.tmp */
     ret[len] = '-';
     ret[len+1] = (pid / 10000 % 10) + '0';
     ret[len+2] = (pid / 1000 % 10) + '0';
     ret[len+3] = (pid / 100 % 10) + '0';
     ret[len+4] = (pid / 10 % 10) + '0';
     ret[len+5] = (pid % 10) + '0';
     strcpy (ret + len + 6, ".tmp");
   
     return ret;
   }
     
 /* Add the contents of FILENAME to the history list, a line at a time.  /* Add the contents of FILENAME to the history list, a line at a time.
    If FILENAME is NULL, then read from ~/.history.  Returns 0 if     If FILENAME is NULL, then read from ~/.history.  Returns 0 if
    successful, or errno if not. */     successful, or errno if not. */
 int  int
read_history (filename)read_history (const char *filename)
     const char *filename; 
 {  {
   return (read_history_range (filename, 0, -1));    return (read_history_range (filename, 0, -1));
 }  }
Line 172  read_history (filename) Line 267  read_history (filename)
    until the end of the file.  If FILENAME is NULL, then read from     until the end of the file.  If FILENAME is NULL, then read from
    ~/.history.  Returns 0 if successful, or errno if not. */     ~/.history.  Returns 0 if successful, or errno if not. */
 int  int
read_history_range (filename, from, to)read_history_range (const char *filename, int from, int to)
     const char *filename; 
     int from, to; 
 {  {
   register char *line_start, *line_end, *p;    register char *line_start, *line_end, *p;
   char *input, *buffer, *bufend, *last_ts;    char *input, *buffer, *bufend, *last_ts;
  int file, current_line, chars_read;  int file, current_line, chars_read, has_timestamps, reset_comment_char;
   struct stat finfo;    struct stat finfo;
   size_t file_size;    size_t file_size;
 #if defined (EFBIG)  #if defined (EFBIG)
Line 189  read_history_range (filename, from, to) Line 282  read_history_range (filename, from, to)
   int overflow_errno = EIO;    int overflow_errno = EIO;
 #endif  #endif
   
     history_lines_read_from_file = 0;
   
   buffer = last_ts = (char *)NULL;    buffer = last_ts = (char *)NULL;
   input = history_filename (filename);    input = history_filename (filename);
   file = input ? open (input, O_RDONLY|O_BINARY, 0666) : -1;    file = input ? open (input, O_RDONLY|O_BINARY, 0666) : -1;
Line 196  read_history_range (filename, from, to) Line 291  read_history_range (filename, from, to)
   if ((file < 0) || (fstat (file, &finfo) == -1))    if ((file < 0) || (fstat (file, &finfo) == -1))
     goto error_and_exit;      goto error_and_exit;
   
     if (S_ISREG (finfo.st_mode) == 0)
       {
   #ifdef EFTYPE
         errno = EFTYPE;
   #else
         errno = EINVAL;
   #endif
         goto error_and_exit;
       }
   
   file_size = (size_t)finfo.st_size;    file_size = (size_t)finfo.st_size;
   
   /* check for overflow on very large files */    /* check for overflow on very large files */
Line 205  read_history_range (filename, from, to) Line 310  read_history_range (filename, from, to)
       goto error_and_exit;        goto error_and_exit;
     }      }
   
     if (file_size == 0)
       {
         free (input);
         close (file);
         return 0; /* don't waste time if we don't have to */
       }
   
 #ifdef HISTORY_USE_MMAP  #ifdef HISTORY_USE_MMAP
   /* We map read/write and private so we can change newlines to NULs without    /* We map read/write and private so we can change newlines to NULs without
      affecting the underlying object. */       affecting the underlying object. */
Line 251  read_history_range (filename, from, to) Line 363  read_history_range (filename, from, to)
   
   /* Start at beginning of file, work to end. */    /* Start at beginning of file, work to end. */
   bufend = buffer + chars_read;    bufend = buffer + chars_read;
     *bufend = '\0';               /* null-terminate buffer for timestamp checks */
   current_line = 0;    current_line = 0;
   
     /* Heuristic: the history comment character rarely changes, so assume we
        have timestamps if the buffer starts with `#[:digit:]' and temporarily
        set history_comment_char so timestamp parsing works right */
     reset_comment_char = 0;
     if (history_comment_char == '\0' && buffer[0] == '#' && isdigit ((unsigned char)buffer[1]))
       {
         history_comment_char = '#';
         reset_comment_char = 1;
       }
   
     has_timestamps = HIST_TIMESTAMP_START (buffer);
     history_multiline_entries += has_timestamps && history_write_timestamps;
   
   /* Skip lines until we are at FROM. */    /* Skip lines until we are at FROM. */
     if (has_timestamps)
       last_ts = buffer;
   for (line_start = line_end = buffer; line_end < bufend && current_line < from; line_end++)    for (line_start = line_end = buffer; line_end < bufend && current_line < from; line_end++)
     if (*line_end == '\n')      if (*line_end == '\n')
       {        {
Line 262  read_history_range (filename, from, to) Line 390  read_history_range (filename, from, to)
            line.  We should check more extensively here... */             line.  We should check more extensively here... */
         if (HIST_TIMESTAMP_START(p) == 0)          if (HIST_TIMESTAMP_START(p) == 0)
           current_line++;            current_line++;
           else
             last_ts = p;
         line_start = p;          line_start = p;
           /* If we are at the last line (current_line == from) but we have
              timestamps (has_timestamps), then line_start points to the
              text of the last command, and we need to skip to its end. */
           if (current_line >= from && has_timestamps)
             {
               for (line_end = p; line_end < bufend && *line_end != '\n'; line_end++)
                 ;
               line_start = (*line_end == '\n') ? line_end + 1 : line_end;
             }
       }        }
   
   /* If there are lines left to gobble, then gobble them now. */    /* If there are lines left to gobble, then gobble them now. */
Line 279  read_history_range (filename, from, to) Line 418  read_history_range (filename, from, to)
           {            {
             if (HIST_TIMESTAMP_START(line_start) == 0)              if (HIST_TIMESTAMP_START(line_start) == 0)
               {                {
                add_history (line_start);                if (last_ts == NULL && history_length > 0 && history_multiline_entries)
                   _hs_append_history_line (history_length - 1, line_start);
                 else
                   add_history (line_start);
                 if (last_ts)                  if (last_ts)
                   {                    {
                     add_history_time (last_ts);                      add_history_time (last_ts);
Line 301  read_history_range (filename, from, to) Line 443  read_history_range (filename, from, to)
         line_start = line_end + 1;          line_start = line_end + 1;
       }        }
   
     history_lines_read_from_file = current_line;
     if (reset_comment_char)
       history_comment_char = '\0';
   
   FREE (input);    FREE (input);
 #ifndef HISTORY_USE_MMAP  #ifndef HISTORY_USE_MMAP
   FREE (buffer);    FREE (buffer);
Line 311  read_history_range (filename, from, to) Line 457  read_history_range (filename, from, to)
   return (0);    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
   histfile_backup (const char *filename, const char *back)
   {
   #if defined (HAVE_READLINK)
     char linkbuf[PATH_MAX+1];
     ssize_t n;
   
     /* Follow to target of symlink to avoid renaming symlink itself */
     if ((n = readlink (filename, linkbuf, sizeof (linkbuf) - 1)) > 0)
       {
         linkbuf[n] = '\0';
         return (history_rename (linkbuf, back));
       }
   #endif
     return (history_rename (filename, back));
   }
   
   /* Restore ORIG from BACKUP handling case where ORIG is a symlink
      (e.g., ~/.bash_history -> .histfiles/.bash_history.$HOSTNAME) */
   static int
   histfile_restore (const char *backup, const char *orig)
   {
   #if defined (HAVE_READLINK)
     char linkbuf[PATH_MAX+1];
     ssize_t n;
   
     /* Follow to target of symlink to avoid renaming symlink itself */
     if ((n = readlink (orig, linkbuf, sizeof (linkbuf) - 1)) > 0)
       {
         linkbuf[n] = '\0';
         return (history_rename (backup, linkbuf));
       }
   #endif
     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.  /* Truncate the history file FNAME, leaving only LINES trailing lines.
   If FNAME is NULL, then use ~/.history.  Returns 0 on success, errno   If FNAME is NULL, then use ~/.history.  Writes a new file and renames
   on failure. */   it to the original name.  Returns 0 on success, errno on failure. */
 int  int
history_truncate_file (fname, lines)history_truncate_file (const char *fname, int lines)
     const char *fname; 
     int lines; 
 {  {
  char *buffer, *filename, *bp, *bp1;                /* bp1 == bp+1 */  char *buffer, *filename, *tempname, *bp, *bp1;                /* bp1 == bp+1 */
  int file, chars_read, rv;  int file, chars_read, rv, orig_lines, exists, r;
  struct stat finfo;  struct stat finfo, nfinfo;
   size_t file_size;    size_t file_size;
   
     history_lines_written_to_file = 0;
   
   buffer = (char *)NULL;    buffer = (char *)NULL;
   filename = history_filename (fname);    filename = history_filename (fname);
     tempname = 0;
   file = filename ? open (filename, O_RDONLY|O_BINARY, 0666) : -1;    file = filename ? open (filename, O_RDONLY|O_BINARY, 0666) : -1;
  rv = 0;  rv = exists = 0;
   
   /* Don't try to truncate non-regular files. */    /* Don't try to truncate non-regular files. */
   if (file == -1 || fstat (file, &finfo) == -1)    if (file == -1 || fstat (file, &finfo) == -1)
Line 337  history_truncate_file (fname, lines) Line 540  history_truncate_file (fname, lines)
         close (file);          close (file);
       goto truncate_exit;        goto truncate_exit;
     }      }
     exists = 1;
   
     nfinfo.st_uid = finfo.st_uid;
     nfinfo.st_gid = finfo.st_gid;
   
   if (S_ISREG (finfo.st_mode) == 0)    if (S_ISREG (finfo.st_mode) == 0)
     {      {
       close (file);        close (file);
Line 368  history_truncate_file (fname, lines) Line 575  history_truncate_file (fname, lines)
   buffer = (char *)malloc (file_size + 1);    buffer = (char *)malloc (file_size + 1);
   if (buffer == 0)    if (buffer == 0)
     {      {
         rv = errno;
       close (file);        close (file);
       goto truncate_exit;        goto truncate_exit;
     }      }
Line 381  history_truncate_file (fname, lines) Line 589  history_truncate_file (fname, lines)
       goto truncate_exit;        goto truncate_exit;
     }      }
   
     orig_lines = lines;
   /* Count backwards from the end of buffer until we have passed    /* Count backwards from the end of buffer until we have passed
      LINES lines.  bp1 is set funny initially.  But since bp[1] can't       LINES lines.  bp1 is set funny initially.  But since bp[1] can't
      be a comment character (since it's off the end) and *bp can't be       be a comment character (since it's off the end) and *bp can't be
Line 409  history_truncate_file (fname, lines) Line 618  history_truncate_file (fname, lines)
   
   /* Write only if there are more lines in the file than we want to    /* Write only if there are more lines in the file than we want to
      truncate to. */       truncate to. */
  if (bp > buffer && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1))  if (bp <= buffer)
     {      {
         rv = 0;
         /* No-op if LINES == 0 at this point */
         history_lines_written_to_file = orig_lines - lines;
         goto truncate_exit;
       }
   
     tempname = history_tempfile (filename);
   
     if ((file = open (tempname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0600)) != -1)
       {
       if (write (file, bp, chars_read - (bp - buffer)) < 0)        if (write (file, bp, chars_read - (bp - buffer)) < 0)
         rv = errno;          rv = errno;
   
#if defined (__BEOS__)      if (fstat (file, &nfinfo) < 0 && rv == 0)
      /* BeOS ignores O_TRUNC. */        rv = errno;
      ftruncate (file, chars_read - (bp - buffer)); 
#endif 
   
       if (close (file) < 0 && rv == 0)        if (close (file) < 0 && rv == 0)
         rv = errno;          rv = errno;
     }      }
     else
       rv = errno;
   
  truncate_exit:   truncate_exit:
   
   FREE (buffer);    FREE (buffer);
   
     history_lines_written_to_file = orig_lines - lines;
   
     if (rv == 0 && filename && tempname)
       rv = histfile_restore (tempname, filename);
   
     if (rv != 0)
       {
         rv = errno;
         if (tempname)
           unlink (tempname);
         history_lines_written_to_file = 0;
       }
   
   #if defined (HAVE_CHOWN)
     /* Make sure the new filename is owned by the same user as the old.  If one
        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 && SHOULD_CHOWN (finfo, nfinfo))
       r = chown (filename, finfo.st_uid, finfo.st_gid);
   #endif
   
   xfree (filename);    xfree (filename);
     FREE (tempname);
   
   return rv;    return rv;
 }  }
   
/* Workhorse function for writing history.  Writes NELEMENT entries/* Workhorse function for writing history.  Writes the last NELEMENT entries
    from the history list to FILENAME.  OVERWRITE is non-zero if you     from the history list to FILENAME.  OVERWRITE is non-zero if you
    wish to replace FILENAME with the entries. */     wish to replace FILENAME with the entries. */
 static int  static int
history_do_write (filename, nelements, overwrite)history_do_write (const char *filename, int nelements, int overwrite)
     const char *filename; 
     int nelements, overwrite; 
 {  {
   register int i;    register int i;
  char *output, *bakname;  char *output, *tempname, *histname;
  int file, mode, rv;  int file, mode, rv, exists;
   struct stat finfo, nfinfo;
 #ifdef HISTORY_USE_MMAP  #ifdef HISTORY_USE_MMAP
   size_t cursize;    size_t cursize;
   
     history_lines_written_to_file = 0;
   
   mode = overwrite ? O_RDWR|O_CREAT|O_TRUNC|O_BINARY : O_RDWR|O_APPEND|O_BINARY;    mode = overwrite ? O_RDWR|O_CREAT|O_TRUNC|O_BINARY : O_RDWR|O_APPEND|O_BINARY;
 #else  #else
   mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY;    mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY;
 #endif  #endif
  output = history_filename (filename);  histname = history_filename (filename);
  bakname = (overwrite && output) ? history_backupfile (output) : 0;  exists = histname ? (stat (histname, &finfo) == 0) : 0;
   
  if (output && bakname)  tempname = (overwrite && exists && S_ISREG (finfo.st_mode)) ? history_tempfile (histname) : 0;
    rename (output, bakname);  output = tempname ? tempname : histname;
   
   file = output ? open (output, mode, 0600) : -1;    file = output ? open (output, mode, 0600) : -1;
   rv = 0;    rv = 0;
Line 461  history_do_write (filename, nelements, overwrite) Line 704  history_do_write (filename, nelements, overwrite)
   if (file == -1)    if (file == -1)
     {      {
       rv = errno;        rv = errno;
      if (output && bakname)      FREE (histname);
        rename (bakname, output);      FREE (tempname);
      FREE (output); 
      FREE (bakname); 
       return (rv);        return (rv);
     }      }
   
Line 486  history_do_write (filename, nelements, overwrite) Line 727  history_do_write (filename, nelements, overwrite)
     the_history = history_list ();      the_history = history_list ();
     /* Calculate the total number of bytes to write. */      /* Calculate the total number of bytes to write. */
     for (buffer_size = 0, i = history_length - nelements; i < history_length; i++)      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])          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]->timestamp) + 1;
         buffer_size += strlen (the_history[i]->line) + 1;          buffer_size += strlen (the_history[i]->line) + 1;
       }        }
 #endif  
   
     /* Allocate the buffer, and fill it. */      /* Allocate the buffer, and fill it. */
 #ifdef HISTORY_USE_MMAP  #ifdef HISTORY_USE_MMAP
Line 506  history_do_write (filename, nelements, overwrite) Line 743  history_do_write (filename, nelements, overwrite)
 mmap_error:  mmap_error:
         rv = errno;          rv = errno;
         close (file);          close (file);
        if (output && bakname)        if (tempname)
          rename (bakname, output);          unlink (tempname);
        FREE (output);        FREE (histname);
        FREE (bakname);        FREE (tempname);
         return rv;          return rv;
       }        }
 #else      #else    
Line 518  mmap_error: Line 755  mmap_error:
       {        {
         rv = errno;          rv = errno;
         close (file);          close (file);
        if (output && bakname)        if (tempname)
          rename (bakname, output);          unlink (tempname);
        FREE (output);        FREE (histname);
        FREE (bakname);        FREE (tempname);
         return rv;          return rv;
       }        }
 #endif  #endif
Line 540  mmap_error: Line 777  mmap_error:
       }        }
   
 #ifdef HISTORY_USE_MMAP  #ifdef HISTORY_USE_MMAP
    if (msync (buffer, buffer_size, 0) != 0 || munmap (buffer, buffer_size) != 0)    if (msync (buffer, buffer_size, MS_ASYNC) != 0 || munmap (buffer, buffer_size) != 0)
       rv = errno;        rv = errno;
 #else  #else
     if (write (file, buffer, buffer_size) < 0)      if (write (file, buffer, buffer_size) < 0)
Line 549  mmap_error: Line 786  mmap_error:
 #endif  #endif
   }    }
   
     history_lines_written_to_file = nelements;
   
   if (close (file) < 0 && rv == 0)    if (close (file) < 0 && rv == 0)
     rv = errno;      rv = errno;
   
  if (rv != 0 && output && bakname)  if (rv == 0 && histname && tempname)
    rename (bakname, output);    rv = histfile_restore (tempname, histname);
  else if (rv == 0 && bakname) 
    unlink (bakname); 
   
  FREE (output);  if (rv != 0)
  FREE (bakname);    {
       rv = errno;
       if (tempname)
         unlink (tempname);
       history_lines_written_to_file = 0;
     }
   
   #if defined (HAVE_CHOWN)
     /* Make sure the new filename is owned by the same user as the old.  If one
        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)
       mode = chown (histname, finfo.st_uid, finfo.st_gid);
   #endif
   
     FREE (histname);
     FREE (tempname);
   
   return (rv);    return (rv);
 }  }
   
 /* Append NELEMENT entries to FILENAME.  The entries appended are from  /* Append NELEMENT entries to FILENAME.  The entries appended are from
    the end of the list minus NELEMENTs up to the end of the list. */     the end of the list minus NELEMENTs up to the end of the list. */
 int  int
append_history (nelements, filename)append_history (int nelements, const char *filename)
     int nelements; 
     const char *filename; 
 {  {
   return (history_do_write (filename, nelements, HISTORY_APPEND));    return (history_do_write (filename, nelements, HISTORY_APPEND));
 }  }
Line 577  append_history (nelements, filename) Line 829  append_history (nelements, filename)
    then write the history list to ~/.history.  Values returned     then write the history list to ~/.history.  Values returned
    are as in read_history ().*/     are as in read_history ().*/
 int  int
write_history (filename)write_history (const char *filename)
     const char *filename; 
 {  {
   return (history_do_write (filename, history_length, HISTORY_OVERWRITE));    return (history_do_write (filename, history_length, HISTORY_OVERWRITE));
 }  }

Removed from v.1.1  
changed lines
  Added in v.1.1.1.2


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>