OpenCoverage

histfile.c

Absolute File Name:/home/opencoverage/opencoverage/guest-scripts/bash/src/lib/readline/histfile.c
Source codeSwitch to Preprocessed file
LineSourceCount
1/* histfile.c - functions to manipulate the history file. */-
2-
3/* Copyright (C) 1989-2017 Free Software Foundation, Inc.-
4-
5 This file contains the GNU History Library (History), a set of-
6 routines for managing the text of previously typed lines.-
7-
8 History is free software: you can redistribute it and/or modify-
9 it under the terms of the GNU General Public License as published by-
10 the Free Software Foundation, either version 3 of the License, or-
11 (at your option) any later version.-
12-
13 History is distributed in the hope that it will be useful,-
14 but WITHOUT ANY WARRANTY; without even the implied warranty of-
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the-
16 GNU General Public License for more details.-
17-
18 You should have received a copy of the GNU General Public License-
19 along with History. If not, see <http://www.gnu.org/licenses/>.-
20*/-
21-
22/* The goal is to make the implementation transparent, so that you-
23 don't have to know what data types are used, just what functions-
24 you can call. I think I have done that. */-
25-
26#define READLINE_LIBRARY-
27-
28#if defined (__TANDEM)-
29# include <floss.h>-
30#endif-
31-
32#if defined (HAVE_CONFIG_H)-
33# include <config.h>-
34#endif-
35-
36#include <stdio.h>-
37-
38#if defined (HAVE_LIMITS_H)-
39# include <limits.h>-
40#endif-
41-
42#include <sys/types.h>-
43#if ! defined (_MINIX) && defined (HAVE_SYS_FILE_H)-
44# include <sys/file.h>-
45#endif-
46#include "posixstat.h"-
47#include <fcntl.h>-
48-
49#if defined (HAVE_STDLIB_H)-
50# include <stdlib.h>-
51#else-
52# include "ansi_stdlib.h"-
53#endif /* HAVE_STDLIB_H */-
54-
55#if defined (HAVE_UNISTD_H)-
56# include <unistd.h>-
57#endif-
58-
59#include <ctype.h>-
60-
61#if defined (__EMX__)-
62# undef HAVE_MMAP-
63#endif-
64-
65#ifdef HISTORY_USE_MMAP-
66# include <sys/mman.h>-
67-
68# ifdef MAP_FILE-
69# define MAP_RFLAGS (MAP_FILE|MAP_PRIVATE)-
70# define MAP_WFLAGS (MAP_FILE|MAP_SHARED)-
71# else-
72# define MAP_RFLAGS MAP_PRIVATE-
73# define MAP_WFLAGS MAP_SHARED-
74# endif-
75-
76# ifndef MAP_FAILED-
77# define MAP_FAILED ((void *)-1)-
78# endif-
79-
80#endif /* HISTORY_USE_MMAP */-
81-
82/* If we're compiling for __EMX__ (OS/2) or __CYGWIN__ (cygwin32 environment-
83 on win 95/98/nt), we want to open files with O_BINARY mode so that there-
84 is no \n -> \r\n conversion performed. On other systems, we don't want to-
85 mess around with O_BINARY at all, so we ensure that it's defined to 0. */-
86#if defined (__EMX__) || defined (__CYGWIN__)-
87# ifndef O_BINARY-
88# define O_BINARY 0-
89# endif-
90#else /* !__EMX__ && !__CYGWIN__ */-
91# undef O_BINARY-
92# define O_BINARY 0-
93#endif /* !__EMX__ && !__CYGWIN__ */-
94-
95#include <errno.h>-
96#if !defined (errno)-
97extern int errno;-
98#endif /* !errno */-
99-
100#include "history.h"-
101#include "histlib.h"-
102-
103#include "rlshell.h"-
104#include "xmalloc.h"-
105-
106#if !defined (PATH_MAX)-
107# define PATH_MAX 1024 /* default */-
108#endif-
109-
110extern void _hs_append_history_line PARAMS((int, const char *));-
111-
112/* history file version; currently unused */-
113int history_file_version = 1;-
114-
115/* If non-zero, we write timestamps to the history file in history_do_write() */-
116int history_write_timestamps = 0;-
117-
118/* If non-zero, we assume that a history file that starts with a timestamp-
119 uses timestamp-delimited entries and can include multi-line history-
120 entries. Used by read_history_range */-
121int history_multiline_entries = 0;-
122-
123/* Immediately after a call to read_history() or read_history_range(), this-
124 will return the number of lines just read from the history file in that-
125 call. */-
126int history_lines_read_from_file = 0;-
127-
128/* Immediately after a call to write_history() or history_do_write(), this-
129 will return the number of lines just written to the history file in that-
130 call. This also works with history_truncate_file. */-
131int history_lines_written_to_file = 0;-
132-
133/* Does S look like the beginning of a history timestamp entry? Placeholder-
134 for more extensive tests. */-
135#define HIST_TIMESTAMP_START(s) (*(s) == history_comment_char && isdigit ((unsigned char)(s)[1]) )-
136-
137static char *history_backupfile PARAMS((const char *));-
138static char *history_tempfile PARAMS((const char *));-
139static int histfile_backup PARAMS((const char *, const char *));-
140static int histfile_restore PARAMS((const char *, const char *));-
141-
142/* Return the string that should be used in the place of this-
143 filename. This only matters when you don't specify the-
144 filename to read_history (), or write_history (). */-
145static char *-
146history_filename (const char *filename)-
147{-
148 char *return_val;-
149 const char *home;-
150 int home_len;-
151-
152 return_val = filename ? savestring (filename) : (char *)NULL;
filenameDescription
TRUEevaluated 35 times by 1 test
Evaluated by:
  • Self test
FALSEevaluated 15 times by 1 test
Evaluated by:
  • Self test
15-35
153-
154 if (return_val)
return_valDescription
TRUEevaluated 35 times by 1 test
Evaluated by:
  • Self test
FALSEevaluated 15 times by 1 test
Evaluated by:
  • Self test
15-35
155 return (return_val);
executed 35 times by 1 test: return (return_val);
Executed by:
  • Self test
35
156 -
157 home = sh_get_env_value ("HOME");-
158#if defined (_WIN32)-
159 if (home == 0)-
160 home = sh_get_env_value ("APPDATA");-
161#endif-
162-
163 if (home == 0)
home == 0Description
TRUEnever evaluated
FALSEevaluated 15 times by 1 test
Evaluated by:
  • Self test
0-15
164 return (NULL);
never executed: return ( ((void *)0) );
0
165 else-
166 home_len = strlen (home);
executed 15 times by 1 test: home_len = strlen (home);
Executed by:
  • Self test
15
167-
168 return_val = (char *)xmalloc (2 + home_len + 8); /* strlen(".history") == 8 */-
169 strcpy (return_val, home);-
170 return_val[home_len] = '/';-
171#if defined (__MSDOS__)-
172 strcpy (return_val + home_len + 1, "_history");-
173#else-
174 strcpy (return_val + home_len + 1, ".history");-
175#endif-
176-
177 return (return_val);
executed 15 times by 1 test: return (return_val);
Executed by:
  • Self test
15
178}-
179-
180static char *-
181history_backupfile (const char *filename)-
182{-
183 const char *fn;-
184 char *ret, linkbuf[PATH_MAX+1];-
185 size_t len;-
186 ssize_t n;-
187 struct stat fs;-
188-
189 fn = filename; -
190#if defined (HAVE_READLINK)-
191 /* Follow symlink to avoid backing up symlink itself; call will fail if-
192 not a symlink */-
193 if ((n = readlink (filename, linkbuf, sizeof (linkbuf) - 1)) > 0)
(n = readlink ...buf) - 1)) > 0Description
TRUEnever evaluated
FALSEnever evaluated
0
194 {-
195 linkbuf[n] = '\0';-
196 fn = linkbuf;-
197 }
never executed: end of block
0
198#endif-
199 -
200 len = strlen (fn);-
201 ret = xmalloc (len + 2);-
202 strcpy (ret, fn);-
203 ret[len] = '-';-
204 ret[len+1] = '\0';-
205 return ret;
never executed: return ret;
0
206}-
207 -
208static char *-
209history_tempfile (const char *filename)-
210{-
211 const char *fn;-
212 char *ret, linkbuf[PATH_MAX+1];-
213 size_t len;-
214 ssize_t n;-
215 struct stat fs;-
216 int pid;-
217-
218 fn = filename; -
219#if defined (HAVE_READLINK)-
220 /* Follow symlink so tempfile created in the same directory as any symlinked-
221 history file; call will fail if not a symlink */-
222 if ((n = readlink (filename, linkbuf, sizeof (linkbuf) - 1)) > 0)
(n = readlink ...buf) - 1)) > 0Description
TRUEnever evaluated
FALSEevaluated 2 times by 1 test
Evaluated by:
  • Self test
0-2
223 {-
224 linkbuf[n] = '\0';-
225 fn = linkbuf;-
226 }
never executed: end of block
0
227#endif-
228 -
229 len = strlen (fn);-
230 ret = xmalloc (len + 11);-
231 strcpy (ret, fn);-
232-
233 pid = (int)getpid ();-
234-
235 /* filename-PID.tmp */-
236 ret[len] = '-';-
237 ret[len+1] = (pid / 10000 % 10) + '0';-
238 ret[len+2] = (pid / 1000 % 10) + '0';-
239 ret[len+3] = (pid / 100 % 10) + '0';-
240 ret[len+4] = (pid / 10 % 10) + '0';-
241 ret[len+5] = (pid % 10) + '0';-
242 strcpy (ret + len + 6, ".tmp");-
243-
244 return ret;
executed 2 times by 1 test: return ret;
Executed by:
  • Self test
2
245}-
246 -
247/* Add the contents of FILENAME to the history list, a line at a time.-
248 If FILENAME is NULL, then read from ~/.history. Returns 0 if-
249 successful, or errno if not. */-
250int-
251read_history (const char *filename)-
252{-
253 return (read_history_range (filename, 0, -1));
executed 4 times by 1 test: return (read_history_range (filename, 0, -1));
Executed by:
  • Self test
4
254}-
255-
256/* Read a range of lines from FILENAME, adding them to the history list.-
257 Start reading at the FROM'th line and end at the TO'th. If FROM-
258 is zero, start at the beginning. If TO is less than FROM, read-
259 until the end of the file. If FILENAME is NULL, then read from-
260 ~/.history. Returns 0 if successful, or errno if not. */-
261int-
262read_history_range (const char *filename, int from, int to)-
263{-
264 register char *line_start, *line_end, *p;-
265 char *input, *buffer, *bufend, *last_ts;-
266 int file, current_line, chars_read, has_timestamps, reset_comment_char;-
267 struct stat finfo;-
268 size_t file_size;-
269#if defined (EFBIG)-
270 int overflow_errno = EFBIG;-
271#elif defined (EOVERFLOW)-
272 int overflow_errno = EOVERFLOW;-
273#else-
274 int overflow_errno = EIO;-
275#endif-
276-
277 history_lines_read_from_file = 0;-
278-
279 buffer = last_ts = (char *)NULL;-
280 input = history_filename (filename);-
281 file = input ? open (input, O_RDONLY|O_BINARY, 0666) : -1;
inputDescription
TRUEevaluated 5 times by 1 test
Evaluated by:
  • Self test
FALSEnever evaluated
0-5
282-
283 if ((file < 0) || (fstat (file, &finfo) == -1))
(file < 0)Description
TRUEnever evaluated
FALSEevaluated 5 times by 1 test
Evaluated by:
  • Self test
(fstat (file, &finfo) == -1)Description
TRUEnever evaluated
FALSEevaluated 5 times by 1 test
Evaluated by:
  • Self test
0-5
284 goto error_and_exit;
never executed: goto error_and_exit;
0
285-
286 if (S_ISREG (finfo.st_mode) == 0)
(((( finfo.st_...0100000)) == 0Description
TRUEevaluated 2 times by 1 test
Evaluated by:
  • Self test
FALSEevaluated 3 times by 1 test
Evaluated by:
  • Self test
2-3
287 {-
288#ifdef EFTYPE-
289 errno = EFTYPE;-
290#else-
291 errno = EINVAL;-
292#endif-
293 goto error_and_exit;
executed 2 times by 1 test: goto error_and_exit;
Executed by:
  • Self test
2
294 }-
295-
296 file_size = (size_t)finfo.st_size;-
297-
298 /* check for overflow on very large files */-
299 if (file_size != finfo.st_size || file_size + 1 < file_size)
file_size != finfo.st_sizeDescription
TRUEnever evaluated
FALSEevaluated 3 times by 1 test
Evaluated by:
  • Self test
file_size + 1 < file_sizeDescription
TRUEnever evaluated
FALSEevaluated 3 times by 1 test
Evaluated by:
  • Self test
0-3
300 {-
301 errno = overflow_errno;-
302 goto error_and_exit;
never executed: goto error_and_exit;
0
303 }-
304-
305 if (file_size == 0)
file_size == 0Description
TRUEnever evaluated
FALSEevaluated 3 times by 1 test
Evaluated by:
  • Self test
0-3
306 {-
307 free (input);-
308 return 0; /* don't waste time if we don't have to */
never executed: return 0;
0
309 }-
310-
311#ifdef HISTORY_USE_MMAP-
312 /* We map read/write and private so we can change newlines to NULs without-
313 affecting the underlying object. */-
314 buffer = (char *)mmap (0, file_size, PROT_READ|PROT_WRITE, MAP_RFLAGS, file, 0);-
315 if ((void *)buffer == MAP_FAILED)-
316 {-
317 errno = overflow_errno;-
318 goto error_and_exit;-
319 }-
320 chars_read = file_size;-
321#else-
322 buffer = (char *)malloc (file_size + 1);-
323 if (buffer == 0)
buffer == 0Description
TRUEnever evaluated
FALSEevaluated 3 times by 1 test
Evaluated by:
  • Self test
0-3
324 {-
325 errno = overflow_errno;-
326 goto error_and_exit;
never executed: goto error_and_exit;
0
327 }-
328-
329 chars_read = read (file, buffer, file_size);-
330#endif-
331 if (chars_read < 0)
chars_read < 0Description
TRUEnever evaluated
FALSEevaluated 3 times by 1 test
Evaluated by:
  • Self test
0-3
332 {-
333 error_and_exit:-
334 if (errno != 0)
(*__errno_location ()) != 0Description
TRUEevaluated 2 times by 1 test
Evaluated by:
  • Self test
FALSEnever evaluated
0-2
335 chars_read = errno;
executed 2 times by 1 test: chars_read = (*__errno_location ()) ;
Executed by:
  • Self test
2
336 else-
337 chars_read = EIO;
never executed: chars_read = 5 ;
0
338 if (file >= 0)
file >= 0Description
TRUEevaluated 2 times by 1 test
Evaluated by:
  • Self test
FALSEnever evaluated
0-2
339 close (file);
executed 2 times by 1 test: close (file);
Executed by:
  • Self test
2
340-
341 FREE (input);
executed 2 times by 1 test: free (input);
Executed by:
  • Self test
inputDescription
TRUEevaluated 2 times by 1 test
Evaluated by:
  • Self test
FALSEnever evaluated
0-2
342#ifndef HISTORY_USE_MMAP-
343 FREE (buffer);
never executed: free (buffer);
bufferDescription
TRUEnever evaluated
FALSEevaluated 2 times by 1 test
Evaluated by:
  • Self test
0-2
344#endif-
345-
346 return (chars_read);
executed 2 times by 1 test: return (chars_read);
Executed by:
  • Self test
2
347 }-
348-
349 close (file);-
350-
351 /* Set TO to larger than end of file if negative. */-
352 if (to < 0)
to < 0Description
TRUEevaluated 3 times by 1 test
Evaluated by:
  • Self test
FALSEnever evaluated
0-3
353 to = chars_read;
executed 3 times by 1 test: to = chars_read;
Executed by:
  • Self test
3
354-
355 /* Start at beginning of file, work to end. */-
356 bufend = buffer + chars_read;-
357 *bufend = '\0'; /* null-terminate buffer for timestamp checks */-
358 current_line = 0;-
359-
360 /* Heuristic: the history comment character rarely changes, so assume we-
361 have timestamps if the buffer starts with `#[:digit:]' and temporarily-
362 set history_comment_char so timestamp parsing works right */-
363 reset_comment_char = 0;-
364 if (history_comment_char == '\0' && buffer[0] == '#' && isdigit ((unsigned char)buffer[1]))
history_comment_char == '\0'Description
TRUEevaluated 1 time by 1 test
Evaluated by:
  • Self test
FALSEevaluated 2 times by 1 test
Evaluated by:
  • Self test
buffer[0] == '#'Description
TRUEnever evaluated
FALSEevaluated 1 time by 1 test
Evaluated by:
  • Self test
((*__ctype_b_l...int) _ISdigit)Description
TRUEnever evaluated
FALSEnever evaluated
0-2
365 {-
366 history_comment_char = '#';-
367 reset_comment_char = 1;-
368 }
never executed: end of block
0
369-
370 has_timestamps = HIST_TIMESTAMP_START (buffer);
*(buffer) == h...y_comment_charDescription
TRUEnever evaluated
FALSEevaluated 3 times by 1 test
Evaluated by:
  • Self test
((*__ctype_b_l...int) _ISdigit)Description
TRUEnever evaluated
FALSEnever evaluated
0-3
371 history_multiline_entries += has_timestamps && history_write_timestamps;
has_timestampsDescription
TRUEnever evaluated
FALSEevaluated 3 times by 1 test
Evaluated by:
  • Self test
history_write_timestampsDescription
TRUEnever evaluated
FALSEnever evaluated
0-3
372-
373 /* Skip lines until we are at FROM. */-
374 for (line_start = line_end = buffer; line_end < bufend && current_line < from; line_end++)
line_end < bufendDescription
TRUEevaluated 3 times by 1 test
Evaluated by:
  • Self test
FALSEnever evaluated
current_line < fromDescription
TRUEnever evaluated
FALSEevaluated 3 times by 1 test
Evaluated by:
  • Self test
0-3
375 if (*line_end == '\n')
*line_end == '\n'Description
TRUEnever evaluated
FALSEnever evaluated
0
376 {-
377 p = line_end + 1;-
378 /* If we see something we think is a timestamp, continue with this-
379 line. We should check more extensively here... */-
380 if (HIST_TIMESTAMP_START(p) == 0)
(*(p) == histo...Sdigit) ) == 0Description
TRUEnever evaluated
FALSEnever evaluated
*(p) == history_comment_charDescription
TRUEnever evaluated
FALSEnever evaluated
((*__ctype_b_l...int) _ISdigit)Description
TRUEnever evaluated
FALSEnever evaluated
0
381 current_line++;
never executed: current_line++;
0
382 line_start = p;-
383 }
never executed: end of block
0
384-
385 /* If there are lines left to gobble, then gobble them now. */-
386 for (line_end = line_start; line_end < bufend; line_end++)
line_end < bufendDescription
TRUEevaluated 360 times by 1 test
Evaluated by:
  • Self test
FALSEevaluated 3 times by 1 test
Evaluated by:
  • Self test
3-360
387 if (*line_end == '\n')
*line_end == '\n'Description
TRUEevaluated 17 times by 1 test
Evaluated by:
  • Self test
FALSEevaluated 343 times by 1 test
Evaluated by:
  • Self test
17-343
388 {-
389 /* Change to allow Windows-like \r\n end of line delimiter. */-
390 if (line_end > line_start && line_end[-1] == '\r')
line_end > line_startDescription
TRUEevaluated 17 times by 1 test
Evaluated by:
  • Self test
FALSEnever evaluated
line_end[-1] == '\r'Description
TRUEnever evaluated
FALSEevaluated 17 times by 1 test
Evaluated by:
  • Self test
0-17
391 line_end[-1] = '\0';
never executed: line_end[-1] = '\0';
0
392 else-
393 *line_end = '\0';
executed 17 times by 1 test: *line_end = '\0';
Executed by:
  • Self test
17
394-
395 if (*line_start)
*line_startDescription
TRUEevaluated 17 times by 1 test
Evaluated by:
  • Self test
FALSEnever evaluated
0-17
396 {-
397 if (HIST_TIMESTAMP_START(line_start) == 0)
(*(line_start)...Sdigit) ) == 0Description
TRUEevaluated 17 times by 1 test
Evaluated by:
  • Self test
FALSEnever evaluated
*(line_start) ...y_comment_charDescription
TRUEnever evaluated
FALSEevaluated 17 times by 1 test
Evaluated by:
  • Self test
((*__ctype_b_l...int) _ISdigit)Description
TRUEnever evaluated
FALSEnever evaluated
0-17
398 {-
399 if (last_ts == NULL && history_multiline_entries)
last_ts == ((void *)0)Description
TRUEevaluated 17 times by 1 test
Evaluated by:
  • Self test
FALSEnever evaluated
history_multiline_entriesDescription
TRUEnever evaluated
FALSEevaluated 17 times by 1 test
Evaluated by:
  • Self test
0-17
400 _hs_append_history_line (history_length - 1, line_start);
never executed: _hs_append_history_line (history_length - 1, line_start);
0
401 else-
402 add_history (line_start);
executed 17 times by 1 test: add_history (line_start);
Executed by:
  • Self test
17
403 if (last_ts)
last_tsDescription
TRUEnever evaluated
FALSEevaluated 17 times by 1 test
Evaluated by:
  • Self test
0-17
404 {-
405 add_history_time (last_ts);-
406 last_ts = NULL;-
407 }
never executed: end of block
0
408 }
executed 17 times by 1 test: end of block
Executed by:
  • Self test
17
409 else-
410 {-
411 last_ts = line_start;-
412 current_line--;-
413 }
never executed: end of block
0
414 }-
415-
416 current_line++;-
417-
418 if (current_line >= to)
current_line >= toDescription
TRUEnever evaluated
FALSEevaluated 17 times by 1 test
Evaluated by:
  • Self test
0-17
419 break;
never executed: break;
0
420-
421 line_start = line_end + 1;-
422 }
executed 17 times by 1 test: end of block
Executed by:
  • Self test
17
423-
424 history_lines_read_from_file = current_line;-
425 if (reset_comment_char)
reset_comment_charDescription
TRUEnever evaluated
FALSEevaluated 3 times by 1 test
Evaluated by:
  • Self test
0-3
426 history_comment_char = '\0';
never executed: history_comment_char = '\0';
0
427-
428 FREE (input);
executed 3 times by 1 test: free (input);
Executed by:
  • Self test
inputDescription
TRUEevaluated 3 times by 1 test
Evaluated by:
  • Self test
FALSEnever evaluated
0-3
429#ifndef HISTORY_USE_MMAP-
430 FREE (buffer);
executed 3 times by 1 test: free (buffer);
Executed by:
  • Self test
bufferDescription
TRUEevaluated 3 times by 1 test
Evaluated by:
  • Self test
FALSEnever evaluated
0-3
431#else-
432 munmap (buffer, file_size);-
433#endif-
434-
435 return (0);
executed 3 times by 1 test: return (0);
Executed by:
  • Self test
3
436}-
437-
438/* Save FILENAME to BACK, handling case where FILENAME is a symlink-
439 (e.g., ~/.bash_history -> .histfiles/.bash_history.$HOSTNAME) */-
440static int-
441histfile_backup (const char *filename, const char *back)-
442{-
443#if defined (HAVE_READLINK)-
444 char linkbuf[PATH_MAX+1];-
445 ssize_t n;-
446-
447 /* Follow to target of symlink to avoid renaming symlink itself */-
448 if ((n = readlink (filename, linkbuf, sizeof (linkbuf) - 1)) > 0)
(n = readlink ...buf) - 1)) > 0Description
TRUEnever evaluated
FALSEnever evaluated
0
449 {-
450 linkbuf[n] = '\0';-
451 return (rename (linkbuf, back));
never executed: return (rename (linkbuf, back));
0
452 }-
453#endif-
454 return (rename (filename, back));
never executed: return (rename (filename, back));
0
455}-
456-
457/* Restore ORIG from BACKUP handling case where ORIG is a symlink-
458 (e.g., ~/.bash_history -> .histfiles/.bash_history.$HOSTNAME) */-
459static int-
460histfile_restore (const char *backup, const char *orig)-
461{-
462#if defined (HAVE_READLINK)-
463 char linkbuf[PATH_MAX+1];-
464 ssize_t n;-
465-
466 /* Follow to target of symlink to avoid renaming symlink itself */-
467 if ((n = readlink (orig, linkbuf, sizeof (linkbuf) - 1)) > 0)
(n = readlink ...buf) - 1)) > 0Description
TRUEnever evaluated
FALSEevaluated 2 times by 1 test
Evaluated by:
  • Self test
0-2
468 {-
469 linkbuf[n] = '\0';-
470 return (rename (backup, linkbuf));
never executed: return (rename (backup, linkbuf));
0
471 }-
472#endif-
473 return (rename (backup, orig));
executed 2 times by 1 test: return (rename (backup, orig));
Executed by:
  • Self test
2
474}-
475-
476/* Truncate the history file FNAME, leaving only LINES trailing lines.-
477 If FNAME is NULL, then use ~/.history. Writes a new file and renames-
478 it to the original name. Returns 0 on success, errno on failure. */-
479int-
480history_truncate_file (const char *fname, int lines)-
481{-
482 char *buffer, *filename, *tempname, *bp, *bp1; /* bp1 == bp+1 */-
483 int file, chars_read, rv, orig_lines, exists, r;-
484 struct stat finfo;-
485 size_t file_size;-
486-
487 history_lines_written_to_file = 0;-
488-
489 buffer = (char *)NULL;-
490 filename = history_filename (fname);-
491 tempname = 0;-
492 file = filename ? open (filename, O_RDONLY|O_BINARY, 0666) : -1;
filenameDescription
TRUEevaluated 38 times by 1 test
Evaluated by:
  • Self test
FALSEnever evaluated
0-38
493 rv = exists = 0;-
494-
495 /* Don't try to truncate non-regular files. */-
496 if (file == -1 || fstat (file, &finfo) == -1)
file == -1Description
TRUEevaluated 30 times by 1 test
Evaluated by:
  • Self test
FALSEevaluated 8 times by 1 test
Evaluated by:
  • Self test
fstat (file, &finfo) == -1Description
TRUEnever evaluated
FALSEevaluated 8 times by 1 test
Evaluated by:
  • Self test
0-30
497 {-
498 rv = errno;-
499 if (file != -1)
file != -1Description
TRUEnever evaluated
FALSEevaluated 30 times by 1 test
Evaluated by:
  • Self test
0-30
500 close (file);
never executed: close (file);
0
501 goto truncate_exit;
executed 30 times by 1 test: goto truncate_exit;
Executed by:
  • Self test
30
502 }-
503 exists = 1;-
504-
505 if (S_ISREG (finfo.st_mode) == 0)
(((( finfo.st_...0100000)) == 0Description
TRUEevaluated 1 time by 1 test
Evaluated by:
  • Self test
FALSEevaluated 7 times by 1 test
Evaluated by:
  • Self test
1-7
506 {-
507 close (file);-
508#ifdef EFTYPE-
509 rv = EFTYPE;-
510#else-
511 rv = EINVAL;-
512#endif-
513 goto truncate_exit;
executed 1 time by 1 test: goto truncate_exit;
Executed by:
  • Self test
1
514 }-
515-
516 file_size = (size_t)finfo.st_size;-
517-
518 /* check for overflow on very large files */-
519 if (file_size != finfo.st_size || file_size + 1 < file_size)
file_size != finfo.st_sizeDescription
TRUEnever evaluated
FALSEevaluated 7 times by 1 test
Evaluated by:
  • Self test
file_size + 1 < file_sizeDescription
TRUEnever evaluated
FALSEevaluated 7 times by 1 test
Evaluated by:
  • Self test
0-7
520 {-
521 close (file);-
522#if defined (EFBIG)-
523 rv = errno = EFBIG;-
524#elif defined (EOVERFLOW)-
525 rv = errno = EOVERFLOW;-
526#else-
527 rv = errno = EINVAL;-
528#endif-
529 goto truncate_exit;
never executed: goto truncate_exit;
0
530 }-
531-
532 buffer = (char *)malloc (file_size + 1);-
533 if (buffer == 0)
buffer == 0Description
TRUEnever evaluated
FALSEevaluated 7 times by 1 test
Evaluated by:
  • Self test
0-7
534 {-
535 rv = errno;-
536 close (file);-
537 goto truncate_exit;
never executed: goto truncate_exit;
0
538 }-
539-
540 chars_read = read (file, buffer, file_size);-
541 close (file);-
542-
543 if (chars_read <= 0)
chars_read <= 0Description
TRUEnever evaluated
FALSEevaluated 7 times by 1 test
Evaluated by:
  • Self test
0-7
544 {-
545 rv = (chars_read < 0) ? errno : 0;
(chars_read < 0)Description
TRUEnever evaluated
FALSEnever evaluated
0
546 goto truncate_exit;
never executed: goto truncate_exit;
0
547 }-
548-
549 orig_lines = lines;-
550 /* Count backwards from the end of buffer until we have passed-
551 LINES lines. bp1 is set funny initially. But since bp[1] can't-
552 be a comment character (since it's off the end) and *bp can't be-
553 both a newline and the history comment character, it should be OK. */-
554 for (bp1 = bp = buffer + chars_read - 1; lines && bp > buffer; bp--)
linesDescription
TRUEevaluated 966 times by 1 test
Evaluated by:
  • Self test
FALSEnever evaluated
bp > bufferDescription
TRUEevaluated 959 times by 1 test
Evaluated by:
  • Self test
FALSEevaluated 7 times by 1 test
Evaluated by:
  • Self test
0-966
555 {-
556 if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0)
*bp == '\n'Description
TRUEevaluated 57 times by 1 test
Evaluated by:
  • Self test
FALSEevaluated 902 times by 1 test
Evaluated by:
  • Self test
(*(bp1) == his...Sdigit) ) == 0Description
TRUEevaluated 57 times by 1 test
Evaluated by:
  • Self test
FALSEnever evaluated
*(bp1) == history_comment_charDescription
TRUEnever evaluated
FALSEevaluated 57 times by 1 test
Evaluated by:
  • Self test
((*__ctype_b_l...int) _ISdigit)Description
TRUEnever evaluated
FALSEnever evaluated
0-902
557 lines--;
executed 57 times by 1 test: lines--;
Executed by:
  • Self test
57
558 bp1 = bp;-
559 }
executed 959 times by 1 test: end of block
Executed by:
  • Self test
959
560-
561 /* If this is the first line, then the file contains exactly the-
562 number of lines we want to truncate to, so we don't need to do-
563 anything. It's the first line if we don't find a newline between-
564 the current value of i and 0. Otherwise, write from the start of-
565 this line until the end of the buffer. */-
566 for ( ; bp > buffer; bp--)
bp > bufferDescription
TRUEnever evaluated
FALSEevaluated 7 times by 1 test
Evaluated by:
  • Self test
0-7
567 {-
568 if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0)
*bp == '\n'Description
TRUEnever evaluated
FALSEnever evaluated
(*(bp1) == his...Sdigit) ) == 0Description
TRUEnever evaluated
FALSEnever evaluated
*(bp1) == history_comment_charDescription
TRUEnever evaluated
FALSEnever evaluated
((*__ctype_b_l...int) _ISdigit)Description
TRUEnever evaluated
FALSEnever evaluated
0
569 {-
570 bp++;-
571 break;
never executed: break;
0
572 }-
573 bp1 = bp;-
574 }
never executed: end of block
0
575-
576 /* Write only if there are more lines in the file than we want to-
577 truncate to. */-
578 if (bp <= buffer)
bp <= bufferDescription
TRUEevaluated 7 times by 1 test
Evaluated by:
  • Self test
FALSEnever evaluated
0-7
579 {-
580 rv = 0;-
581 /* No-op if LINES == 0 at this point */-
582 history_lines_written_to_file = orig_lines - lines;-
583 goto truncate_exit;
executed 7 times by 1 test: goto truncate_exit;
Executed by:
  • Self test
7
584 }-
585-
586 tempname = history_tempfile (filename);-
587-
588 if ((file = open (tempname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0600)) != -1)
(file = open (..., 0600)) != -1Description
TRUEnever evaluated
FALSEnever evaluated
0
589 {-
590 if (write (file, bp, chars_read - (bp - buffer)) < 0)
write (file, b...- buffer)) < 0Description
TRUEnever evaluated
FALSEnever evaluated
0
591 rv = errno;
never executed: rv = (*__errno_location ()) ;
0
592-
593 if (close (file) < 0 && rv == 0)
close (file) < 0Description
TRUEnever evaluated
FALSEnever evaluated
rv == 0Description
TRUEnever evaluated
FALSEnever evaluated
0
594 rv = errno;
never executed: rv = (*__errno_location ()) ;
0
595 }
never executed: end of block
0
596 else-
597 rv = errno;
never executed: rv = (*__errno_location ()) ;
0
598-
599 truncate_exit:
code before this statement never executed: truncate_exit:
0
600 FREE (buffer);
executed 7 times by 1 test: free (buffer);
Executed by:
  • Self test
bufferDescription
TRUEevaluated 7 times by 1 test
Evaluated by:
  • Self test
FALSEevaluated 31 times by 1 test
Evaluated by:
  • Self test
7-31
601-
602 history_lines_written_to_file = orig_lines - lines;-
603-
604 if (rv == 0 && filename && tempname)
rv == 0Description
TRUEevaluated 7 times by 1 test
Evaluated by:
  • Self test
FALSEevaluated 31 times by 1 test
Evaluated by:
  • Self test
filenameDescription
TRUEevaluated 7 times by 1 test
Evaluated by:
  • Self test
FALSEnever evaluated
tempnameDescription
TRUEnever evaluated
FALSEevaluated 7 times by 1 test
Evaluated by:
  • Self test
0-31
605 rv = histfile_restore (tempname, filename);
never executed: rv = histfile_restore (tempname, filename);
0
606-
607 if (rv != 0)
rv != 0Description
TRUEevaluated 31 times by 1 test
Evaluated by:
  • Self test
FALSEevaluated 7 times by 1 test
Evaluated by:
  • Self test
7-31
608 {-
609 if (tempname)
tempnameDescription
TRUEnever evaluated
FALSEevaluated 31 times by 1 test
Evaluated by:
  • Self test
0-31
610 unlink (tempname);
never executed: unlink (tempname);
0
611 history_lines_written_to_file = 0;-
612 }
executed 31 times by 1 test: end of block
Executed by:
  • Self test
31
613-
614#if defined (HAVE_CHOWN)-
615 /* Make sure the new filename is owned by the same user as the old. If one-
616 user is running this, it's a no-op. If the shell is running after sudo-
617 with a shared history file, we don't want to leave the history file-
618 owned by root. */-
619 if (rv == 0 && exists)
rv == 0Description
TRUEevaluated 7 times by 1 test
Evaluated by:
  • Self test
FALSEevaluated 31 times by 1 test
Evaluated by:
  • Self test
existsDescription
TRUEevaluated 7 times by 1 test
Evaluated by:
  • Self test
FALSEnever evaluated
0-31
620 r = chown (filename, finfo.st_uid, finfo.st_gid);
executed 7 times by 1 test: r = chown (filename, finfo.st_uid, finfo.st_gid);
Executed by:
  • Self test
7
621#endif-
622-
623 xfree (filename);-
624 FREE (tempname);
never executed: free (tempname);
tempnameDescription
TRUEnever evaluated
FALSEevaluated 38 times by 1 test
Evaluated by:
  • Self test
0-38
625-
626 return rv;
executed 38 times by 1 test: return rv;
Executed by:
  • Self test
38
627}-
628-
629/* Workhorse function for writing history. Writes the last NELEMENT entries-
630 from the history list to FILENAME. OVERWRITE is non-zero if you-
631 wish to replace FILENAME with the entries. */-
632static int-
633history_do_write (const char *filename, int nelements, int overwrite)-
634{-
635 register int i;-
636 char *output, *tempname, *histname;-
637 int file, mode, rv, exists;-
638 struct stat finfo;-
639#ifdef HISTORY_USE_MMAP-
640 size_t cursize;-
641-
642 history_lines_written_to_file = 0;-
643-
644 mode = overwrite ? O_RDWR|O_CREAT|O_TRUNC|O_BINARY : O_RDWR|O_APPEND|O_BINARY;-
645#else-
646 mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY;
overwriteDescription
TRUEevaluated 2 times by 1 test
Evaluated by:
  • Self test
FALSEevaluated 5 times by 1 test
Evaluated by:
  • Self test
2-5
647#endif-
648 histname = history_filename (filename);-
649 exists = histname ? (stat (histname, &finfo) == 0) : 0;
histnameDescription
TRUEevaluated 7 times by 1 test
Evaluated by:
  • Self test
FALSEnever evaluated
0-7
650-
651 tempname = (overwrite && exists && S_ISREG (finfo.st_mode)) ? history_tempfile (histname) : 0;
overwriteDescription
TRUEevaluated 2 times by 1 test
Evaluated by:
  • Self test
FALSEevaluated 5 times by 1 test
Evaluated by:
  • Self test
existsDescription
TRUEevaluated 2 times by 1 test
Evaluated by:
  • Self test
FALSEnever evaluated
(((( finfo.st_... == (0100000))Description
TRUEevaluated 2 times by 1 test
Evaluated by:
  • Self test
FALSEnever evaluated
0-5
652 output = tempname ? tempname : histname;
tempnameDescription
TRUEevaluated 2 times by 1 test
Evaluated by:
  • Self test
FALSEevaluated 5 times by 1 test
Evaluated by:
  • Self test
2-5
653-
654 file = output ? open (output, mode, 0600) : -1;
outputDescription
TRUEevaluated 7 times by 1 test
Evaluated by:
  • Self test
FALSEnever evaluated
0-7
655 rv = 0;-
656-
657 if (file == -1)
file == -1Description
TRUEnever evaluated
FALSEevaluated 7 times by 1 test
Evaluated by:
  • Self test
0-7
658 {-
659 rv = errno;-
660 FREE (histname);
never executed: free (histname);
histnameDescription
TRUEnever evaluated
FALSEnever evaluated
0
661 FREE (tempname);
never executed: free (tempname);
tempnameDescription
TRUEnever evaluated
FALSEnever evaluated
0
662 return (rv);
never executed: return (rv);
0
663 }-
664-
665#ifdef HISTORY_USE_MMAP-
666 cursize = overwrite ? 0 : lseek (file, 0, SEEK_END);-
667#endif-
668-
669 if (nelements > history_length)
nelements > history_lengthDescription
TRUEnever evaluated
FALSEevaluated 7 times by 1 test
Evaluated by:
  • Self test
0-7
670 nelements = history_length;
never executed: nelements = history_length;
0
671-
672 /* Build a buffer of all the lines to write, and write them in one syscall.-
673 Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */-
674 {-
675 HIST_ENTRY **the_history; /* local */-
676 register int j;-
677 int buffer_size;-
678 char *buffer;-
679-
680 the_history = history_list ();-
681 /* Calculate the total number of bytes to write. */-
682 for (buffer_size = 0, i = history_length - nelements; i < history_length; i++)
i < history_lengthDescription
TRUEevaluated 27 times by 1 test
Evaluated by:
  • Self test
FALSEevaluated 7 times by 1 test
Evaluated by:
  • Self test
7-27
683#if 0-
684 buffer_size += 2 + HISTENT_BYTES (the_history[i]);-
685#else-
686 {-
687 if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0])
history_write_timestampsDescription
TRUEnever evaluated
FALSEevaluated 27 times by 1 test
Evaluated by:
  • Self test
the_history[i]->timestampDescription
TRUEnever evaluated
FALSEnever evaluated
the_history[i]->timestamp[0]Description
TRUEnever evaluated
FALSEnever evaluated
0-27
688 buffer_size += strlen (the_history[i]->timestamp) + 1;
never executed: buffer_size += strlen (the_history[i]->timestamp) + 1;
0
689 buffer_size += strlen (the_history[i]->line) + 1;-
690 }
executed 27 times by 1 test: end of block
Executed by:
  • Self test
27
691#endif-
692-
693 /* Allocate the buffer, and fill it. */-
694#ifdef HISTORY_USE_MMAP-
695 if (ftruncate (file, buffer_size+cursize) == -1)-
696 goto mmap_error;-
697 buffer = (char *)mmap (0, buffer_size, PROT_READ|PROT_WRITE, MAP_WFLAGS, file, cursize);-
698 if ((void *)buffer == MAP_FAILED)-
699 {-
700mmap_error:-
701 rv = errno;-
702 close (file);-
703 if (tempname)-
704 unlink (tempname);-
705 FREE (histname);-
706 FREE (tempname);-
707 return rv;-
708 }-
709#else -
710 buffer = (char *)malloc (buffer_size);-
711 if (buffer == 0)
buffer == 0Description
TRUEnever evaluated
FALSEevaluated 7 times by 1 test
Evaluated by:
  • Self test
0-7
712 {-
713 rv = errno;-
714 close (file);-
715 if (tempname)
tempnameDescription
TRUEnever evaluated
FALSEnever evaluated
0
716 unlink (tempname);
never executed: unlink (tempname);
0
717 FREE (histname);
never executed: free (histname);
histnameDescription
TRUEnever evaluated
FALSEnever evaluated
0
718 FREE (tempname);
never executed: free (tempname);
tempnameDescription
TRUEnever evaluated
FALSEnever evaluated
0
719 return rv;
never executed: return rv;
0
720 }-
721#endif-
722-
723 for (j = 0, i = history_length - nelements; i < history_length; i++)
i < history_lengthDescription
TRUEevaluated 27 times by 1 test
Evaluated by:
  • Self test
FALSEevaluated 7 times by 1 test
Evaluated by:
  • Self test
7-27
724 {-
725 if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0])
history_write_timestampsDescription
TRUEnever evaluated
FALSEevaluated 27 times by 1 test
Evaluated by:
  • Self test
the_history[i]->timestampDescription
TRUEnever evaluated
FALSEnever evaluated
the_history[i]->timestamp[0]Description
TRUEnever evaluated
FALSEnever evaluated
0-27
726 {-
727 strcpy (buffer + j, the_history[i]->timestamp);-
728 j += strlen (the_history[i]->timestamp);-
729 buffer[j++] = '\n';-
730 }
never executed: end of block
0
731 strcpy (buffer + j, the_history[i]->line);-
732 j += strlen (the_history[i]->line);-
733 buffer[j++] = '\n';-
734 }
executed 27 times by 1 test: end of block
Executed by:
  • Self test
27
735-
736#ifdef HISTORY_USE_MMAP-
737 if (msync (buffer, buffer_size, MS_ASYNC) != 0 || munmap (buffer, buffer_size) != 0)-
738 rv = errno;-
739#else-
740 if (write (file, buffer, buffer_size) < 0)
write (file, b...ffer_size) < 0Description
TRUEnever evaluated
FALSEevaluated 7 times by 1 test
Evaluated by:
  • Self test
0-7
741 rv = errno;
never executed: rv = (*__errno_location ()) ;
0
742 xfree (buffer);-
743#endif-
744 }-
745-
746 history_lines_written_to_file = nelements;-
747-
748 if (close (file) < 0 && rv == 0)
close (file) < 0Description
TRUEnever evaluated
FALSEevaluated 7 times by 1 test
Evaluated by:
  • Self test
rv == 0Description
TRUEnever evaluated
FALSEnever evaluated
0-7
749 rv = errno;
never executed: rv = (*__errno_location ()) ;
0
750-
751 if (rv == 0 && histname && tempname)
rv == 0Description
TRUEevaluated 7 times by 1 test
Evaluated by:
  • Self test
FALSEnever evaluated
histnameDescription
TRUEevaluated 7 times by 1 test
Evaluated by:
  • Self test
FALSEnever evaluated
tempnameDescription
TRUEevaluated 2 times by 1 test
Evaluated by:
  • Self test
FALSEevaluated 5 times by 1 test
Evaluated by:
  • Self test
0-7
752 rv = histfile_restore (tempname, histname);
executed 2 times by 1 test: rv = histfile_restore (tempname, histname);
Executed by:
  • Self test
2
753-
754 if (rv != 0)
rv != 0Description
TRUEnever evaluated
FALSEevaluated 7 times by 1 test
Evaluated by:
  • Self test
0-7
755 {-
756 if (tempname)
tempnameDescription
TRUEnever evaluated
FALSEnever evaluated
0
757 unlink (tempname);
never executed: unlink (tempname);
0
758 history_lines_written_to_file = 0;-
759 }
never executed: end of block
0
760-
761#if defined (HAVE_CHOWN)-
762 /* Make sure the new filename is owned by the same user as the old. If one-
763 user is running this, it's a no-op. If the shell is running after sudo-
764 with a shared history file, we don't want to leave the history file-
765 owned by root. */-
766 if (rv == 0 && exists)
rv == 0Description
TRUEevaluated 7 times by 1 test
Evaluated by:
  • Self test
FALSEnever evaluated
existsDescription
TRUEevaluated 7 times by 1 test
Evaluated by:
  • Self test
FALSEnever evaluated
0-7
767 mode = chown (histname, finfo.st_uid, finfo.st_gid);
executed 7 times by 1 test: mode = chown (histname, finfo.st_uid, finfo.st_gid);
Executed by:
  • Self test
7
768#endif-
769-
770 FREE (histname);
executed 7 times by 1 test: free (histname);
Executed by:
  • Self test
histnameDescription
TRUEevaluated 7 times by 1 test
Evaluated by:
  • Self test
FALSEnever evaluated
0-7
771 FREE (tempname);
executed 2 times by 1 test: free (tempname);
Executed by:
  • Self test
tempnameDescription
TRUEevaluated 2 times by 1 test
Evaluated by:
  • Self test
FALSEevaluated 5 times by 1 test
Evaluated by:
  • Self test
2-5
772-
773 return (rv);
executed 7 times by 1 test: return (rv);
Executed by:
  • Self test
7
774}-
775-
776/* Append NELEMENT entries to FILENAME. The entries appended are from-
777 the end of the list minus NELEMENTs up to the end of the list. */-
778int-
779append_history (int nelements, const char *filename)-
780{-
781 return (history_do_write (filename, nelements, HISTORY_APPEND));
executed 5 times by 1 test: return (history_do_write (filename, nelements, 0));
Executed by:
  • Self test
5
782}-
783-
784/* Overwrite FILENAME with the current history. If FILENAME is NULL,-
785 then write the history list to ~/.history. Values returned-
786 are as in read_history ().*/-
787int-
788write_history (const char *filename)-
789{-
790 return (history_do_write (filename, history_length, HISTORY_OVERWRITE));
executed 2 times by 1 test: return (history_do_write (filename, history_length, 1));
Executed by:
  • Self test
2
791}-
Source codeSwitch to Preprocessed file

Generated by Squish Coco 4.1.2