]> git.eshelyaron.com Git - emacs.git/commitdiff
Allow inserting parts of /dev/urandom with insert-file-contents
authorLars Ingebrigtsen <larsi@gnus.org>
Sat, 11 Jun 2022 12:39:54 +0000 (14:39 +0200)
committerLars Ingebrigtsen <larsi@gnus.org>
Sat, 11 Jun 2022 12:39:54 +0000 (14:39 +0200)
* doc/lispref/files.texi (Reading from Files): Document it.
* src/fileio.c (Finsert_file_contents): Allow specifying END for
special files (bug#18370).

doc/lispref/files.texi
src/fileio.c
test/src/fileio-tests.el

index d473261026236d57878d1a150428588c342a6ff7..ea8683a6d8e0e524080f89cc4efa0c332de1fe3c 100644 (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
index 094516bfef51e5fb28aeb2ebcfbeaeae3d2f1010..94cbc14371d5e49a7d98e48b74028ab42283f770 100644 (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);
     }
index 511490c57452d84122a72d53af7879e682d45c37..a9a43781d499187001de4c76dd1ff118f1df829b 100644 (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