Allow inserting parts of /dev/urandom with insert-file-contents

* doc/lispref/files.texi (Reading from Files): Document it.
* src/fileio.c (Finsert_file_contents): Allow specifying END for
special files (bug#18370).
This commit is contained in:
Lars Ingebrigtsen 2022-06-11 14:39:54 +02:00
parent 3675809696
commit cb4579ed6b
3 changed files with 34 additions and 13 deletions

View file

@ -581,9 +581,12 @@ contents of the file. This is better than simply deleting the buffer
contents and inserting the whole file, because (1) it preserves some
marker positions and (2) it puts less data in the undo list.
It is possible to read a special file (such as a FIFO or an I/O device)
with @code{insert-file-contents}, as long as @var{replace} and
@var{visit} are @code{nil}.
It is possible to read a special file (such as a FIFO or an I/O
device) with @code{insert-file-contents}, as long as @var{replace},
and @var{visit} and @var{beg} are @code{nil}. However, you should
normally use an @var{end} argument for these files to avoid inserting
(potentially) unlimited data into the buffer (for instance, when
inserting data from @file{/dev/urandom}).
@end defun
@defun insert-file-contents-literally filename &optional visit beg end replace

View file

@ -3898,6 +3898,10 @@ The optional third and fourth arguments BEG and END specify what portion
of the file to insert. These arguments count bytes in the file, not
characters in the buffer. If VISIT is non-nil, BEG and END must be nil.
When inserting data from a special file (e.g., /dev/urandom), you
can't specify VISIT or BEG, and END should be specified to avoid
inserting unlimited data into the buffer.
If optional fifth argument REPLACE is non-nil, replace the current
buffer contents (in the accessible portion) with the file contents.
This is better than simply deleting and inserting the whole thing
@ -3925,7 +3929,7 @@ by calling `format-decode', which see. */)
Lisp_Object handler, val, insval, orig_filename, old_undo;
Lisp_Object p;
ptrdiff_t total = 0;
bool not_regular = 0;
bool regular = true;
int save_errno = 0;
char read_buf[READ_BUF_SIZE];
struct coding_system coding;
@ -3948,6 +3952,7 @@ by calling `format-decode', which see. */)
/* SAME_AT_END_CHARPOS counts characters, because
restore_window_points needs the old character count. */
ptrdiff_t same_at_end_charpos = ZV;
bool seekable = true;
if (current_buffer->base_buffer && ! NILP (visit))
error ("Cannot do file visiting in an indirect buffer");
@ -4021,7 +4026,8 @@ by calling `format-decode', which see. */)
least signal an error. */
if (!S_ISREG (st.st_mode))
{
not_regular = 1;
regular = false;
seekable = lseek (fd, 0, SEEK_CUR) < 0;
if (! NILP (visit))
{
@ -4029,7 +4035,12 @@ by calling `format-decode', which see. */)
goto notfound;
}
if (! NILP (replace) || ! NILP (beg) || ! NILP (end))
if (!NILP (beg) && !seekable)
xsignal2 (Qfile_error,
build_string ("trying to use a start positing in a non-seekable file"),
orig_filename);
if (!NILP (replace))
xsignal2 (Qfile_error,
build_string ("not a regular file"), orig_filename);
}
@ -4051,7 +4062,7 @@ by calling `format-decode', which see. */)
end_offset = file_offset (end);
else
{
if (not_regular)
if (!regular)
end_offset = TYPE_MAXIMUM (off_t);
else
{
@ -4073,7 +4084,7 @@ by calling `format-decode', which see. */)
/* Check now whether the buffer will become too large,
in the likely case where the file's length is not changing.
This saves a lot of needless work before a buffer overflow. */
if (! not_regular)
if (regular)
{
/* The likely offset where we will stop reading. We could read
more (or less), if the file grows (or shrinks) as we read it. */
@ -4111,7 +4122,7 @@ by calling `format-decode', which see. */)
{
/* Don't try looking inside a file for a coding system
specification if it is not seekable. */
if (! not_regular && ! NILP (Vset_auto_coding_function))
if (regular && !NILP (Vset_auto_coding_function))
{
/* Find a coding system specified in the heading two
lines or in the tailing several lines of the file.
@ -4573,7 +4584,7 @@ by calling `format-decode', which see. */)
goto handled;
}
if (! not_regular)
if (seekable || !NILP (end))
total = end_offset - beg_offset;
else
/* For a special file, all we can do is guess. */
@ -4619,7 +4630,7 @@ by calling `format-decode', which see. */)
ptrdiff_t trytry = min (total - how_much, READ_BUF_SIZE);
ptrdiff_t this;
if (not_regular)
if (!seekable && NILP (end))
{
Lisp_Object nbytes;
@ -4670,7 +4681,7 @@ by calling `format-decode', which see. */)
For a special file, where TOTAL is just a buffer size,
so don't bother counting in HOW_MUCH.
(INSERTED is where we count the number of characters inserted.) */
if (! not_regular)
if (seekable || !NILP (end))
how_much += this;
inserted += this;
}
@ -4848,7 +4859,7 @@ by calling `format-decode', which see. */)
Funlock_file (BVAR (current_buffer, file_truename));
Funlock_file (filename);
}
if (not_regular)
if (!regular)
xsignal2 (Qfile_error,
build_string ("not a regular file"), orig_filename);
}

View file

@ -193,4 +193,11 @@ Also check that an encoding error can appear in a symlink."
(should (equal (file-name-concat "" "bar") "bar"))
(should (equal (file-name-concat "" "") "")))
(defun test-non-regular-insert ()
(skip-unless (file-exists-p "/dev/urandom"))
(with-temp-buffer
(should-error (insert-file-contents "/dev/urandom" nil 5 10))
(insert-file-contents "/dev/urandom" nil nil 10)
(should (= (point-max) 10))))
;;; fileio-tests.el ends here