emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 3fb2c174d3a 1/3: Enable visiting FIFOs as files


From: Po Lu
Subject: master 3fb2c174d3a 1/3: Enable visiting FIFOs as files
Date: Tue, 8 Aug 2023 01:50:12 -0400 (EDT)

branch: master
commit 3fb2c174d3a73ee5a2670b438538a5c32ad9d7ac
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Enable visiting FIFOs as files
    
    * doc/lispref/files.texi (Reading from Files): Document new
    `if-regular' value of REPLACE.
    
    * etc/NEWS: Announce the new value.
    
    * lisp/files.el (basic-save-buffer-2): Demote errors saving
    backup files, since FIFOs cannot be copied.
    (revert-buffer-insert-file-contents--default-function): Supply
    `if-regular' instead of t as REPLACE.
    
    * src/fileio.c (selinux_enabled_p): New function.
    (Fcopy_file, Ffile_selinux_context, Fset_file_selinux_context):
    Call that function to ascertain if SELinux applies to a file.
    (read_non_regular): Don't assume `emacs_fd_read' always returns
    int.
    (Finsert_file_contents): If REPLACE is if-regular and FILENAME
    is a special non-seekable file, fall back to erasing the buffer
    before inserting the contents of that file.
    (syms_of_fileio) <Qif_regular>: New symbol.
---
 doc/lispref/files.texi |  11 ++--
 etc/NEWS               |   6 +++
 lisp/files.el          |  10 ++--
 src/fileio.c           | 141 ++++++++++++++++++++++++++++++++++---------------
 4 files changed, 116 insertions(+), 52 deletions(-)

diff --git a/doc/lispref/files.texi b/doc/lispref/files.texi
index aaab4e455a0..afedf776c86 100644
--- a/doc/lispref/files.texi
+++ b/doc/lispref/files.texi
@@ -582,11 +582,12 @@ 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} 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}).
+device) with @code{insert-file-contents}, as long as @var{replace} is
+@code{nil} or @code{if-regular}, 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
diff --git a/etc/NEWS b/etc/NEWS
index 6cdeeacc158..ee1ce72db98 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -743,6 +743,12 @@ The compatibility aliases 'x-defined-colors', 
'x-color-defined-p',
 See (info "(elisp)Porting Old Advice") for help converting them
 to use `advice-add` or `define-advice instead.
 
++++
+** New value 'if-regular' for the REPLACE argument to 'insert-file-contents'.
+It results in 'insert-file-contents' erasing the buffer instead of
+preserving markers if the file being inserted is not a regular file,
+rather than signaling an error.
+
 +++
 ** New variable 'current-key-remap-sequence'.
 It is bound to the key sequence that caused a call to a function bound
diff --git a/lisp/files.el b/lisp/files.el
index 58014665fbc..685eb5fc957 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -5871,8 +5871,10 @@ Before and after saving the buffer, this function runs
                     buffer-file-name)))
                  (setq tempsetmodes t)
                (error "Attempt to save to a file that you aren't allowed to 
write"))))))
-    (or buffer-backed-up
-       (setq setmodes (backup-buffer)))
+    (with-demoted-errors
+        "Backing up buffer: %s"
+      (or buffer-backed-up
+         (setq setmodes (backup-buffer))))
     (let* ((dir (file-name-directory buffer-file-name))
            (dir-writable (file-writable-p dir)))
       (if (or (and file-precious-flag dir-writable)
@@ -6894,9 +6896,9 @@ an auto-save file."
       (if revert-buffer-preserve-modes
           (let ((buffer-file-format buffer-file-format))
             (insert-file-contents file-name (not auto-save-p)
-                                  nil nil t))
+                                  nil nil 'if-regular))
         (insert-file-contents file-name (not auto-save-p)
-                              nil nil t))))))
+                              nil nil 'if-regular))))))
 
 (defvar revert-buffer-with-fine-grain-max-seconds 2.0
   "Maximum time that `revert-buffer-with-fine-grain' should use.
diff --git a/src/fileio.c b/src/fileio.c
index b5c3add836e..26b7e193f0a 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -200,6 +200,25 @@ check_vfs_filename (Lisp_Object encoded, const char 
*reason)
 #endif /* defined HAVE_ANDROID && !defined ANDROID_STUBIFY */
 }
 
+#ifdef HAVE_LIBSELINUX
+
+/* Return whether SELinux is enabled and pertinent to FILE.  Provide
+   for cases where FILE is or is a constitutent of a special
+   directory, such as /assets or /content on Android.  */
+
+static bool
+selinux_enabled_p (const char *file)
+{
+  return (is_selinux_enabled ()
+#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
+         && !android_is_special_directory (file, "/assets")
+         && !android_is_special_directory (file, "/content")
+#endif /* defined HAVE_ANDROID && !defined ANDROID_STUBIFY */
+         );
+}
+
+#endif /* HAVE_LIBSELINUX */
+
 
 /* Test whether FILE is accessible for AMODE.
    Return true if successful, false (setting errno) otherwise.  */
@@ -2311,7 +2330,7 @@ permissions.  */)
   if (!NILP (preserve_permissions))
     {
 #if HAVE_LIBSELINUX
-      if (is_selinux_enabled ()
+      if (selinux_enabled_p (SSDATA (encoded_file))
          && emacs_fd_to_int (ifd) != -1)
        {
          conlength = fgetfilecon (emacs_fd_to_int (ifd),
@@ -2319,7 +2338,7 @@ permissions.  */)
          if (conlength == -1)
            report_file_error ("Doing fgetfilecon", file);
        }
-#endif
+#endif /* HAVE_LIBSELINUX */
     }
 
   /* We can copy only regular files.  */
@@ -3353,6 +3372,7 @@ or if SELinux is disabled, or if Emacs lacks SELinux 
support.  */)
 {
   Lisp_Object user = Qnil, role = Qnil, type = Qnil, range = Qnil;
   Lisp_Object absname = expand_and_dir_to_file (filename);
+  const char *file;
 
   /* If the file name has special constructs in it,
      call the corresponding file name handler.  */
@@ -3361,11 +3381,13 @@ or if SELinux is disabled, or if Emacs lacks SELinux 
support.  */)
   if (!NILP (handler))
     return call2 (handler, Qfile_selinux_context, absname);
 
+  file = SSDATA (ENCODE_FILE (absname));
+
 #if HAVE_LIBSELINUX
-  if (is_selinux_enabled ())
+  if (selinux_enabled_p (file))
     {
       char *con;
-      int conlength = lgetfilecon (SSDATA (ENCODE_FILE (absname)), &con);
+      int conlength = lgetfilecon (file, &con);
       if (conlength > 0)
        {
          context_t context = context_new (con);
@@ -3384,7 +3406,7 @@ or if SELinux is disabled, or if Emacs lacks SELinux 
support.  */)
                  || errno == ENOTSUP))
        report_file_error ("getting SELinux context", absname);
     }
-#endif
+#endif /* HAVE_LIBSELINUX */
 
   return list4 (user, role, type, range);
 }
@@ -3410,10 +3432,11 @@ or if Emacs was not compiled with SELinux support.  */)
   Lisp_Object type = CAR_SAFE (CDR_SAFE (CDR_SAFE (context)));
   Lisp_Object range = CAR_SAFE (CDR_SAFE (CDR_SAFE (CDR_SAFE (context))));
   char *con;
+  const char *name;
   bool fail;
   int conlength;
   context_t parsed_con;
-#endif
+#endif /* HAVE_LIBSELINUX */
 
   absname = Fexpand_file_name (filename, BVAR (current_buffer, directory));
 
@@ -3424,11 +3447,13 @@ or if Emacs was not compiled with SELinux support.  */)
     return call3 (handler, Qset_file_selinux_context, absname, context);
 
 #if HAVE_LIBSELINUX
-  if (is_selinux_enabled ())
+  encoded_absname = ENCODE_FILE (absname);
+  name = SSDATA (encoded_absname);
+
+  if (selinux_enabled_p (name))
     {
       /* Get current file context. */
-      encoded_absname = ENCODE_FILE (absname);
-      conlength = lgetfilecon (SSDATA (encoded_absname), &con);
+      conlength = lgetfilecon (name, &con);
       if (conlength > 0)
        {
          parsed_con = context_new (con);
@@ -3469,7 +3494,7 @@ or if Emacs was not compiled with SELinux support.  */)
       else
        report_file_error ("Doing lgetfilecon", absname);
     }
-#endif
+#endif /* HAVE_LIBSELINUX */
 
   return Qnil;
 }
@@ -3860,11 +3885,12 @@ static Lisp_Object
 read_non_regular (Lisp_Object state)
 {
   union read_non_regular *data = XFIXNUMPTR (state);
-  int nbytes = emacs_fd_read (data->s.fd,
-                             ((char *) BEG_ADDR + PT_BYTE - BEG_BYTE
-                              + data->s.inserted),
-                             data->s.trytry);
-  return make_fixnum (nbytes);
+  intmax_t nbytes
+    = emacs_fd_read (data->s.fd,
+                    ((char *) BEG_ADDR + PT_BYTE - BEG_BYTE
+                     + data->s.inserted),
+                    data->s.trytry);
+  return make_int (nbytes);
 }
 
 
@@ -4002,13 +4028,19 @@ at the start and end of the buffer) and (2) it puts 
less data in the
 undo list.  When REPLACE is non-nil, the second return value is the
 number of characters that replace previous buffer contents.
 
+If REPLACE is the symbol `if-regular', then eschew preserving marker
+positions or the undo list if REPLACE is nil if FILENAME is not a
+regular file.  Otherwise, signal an error if REPLACE is non-nil and
+FILENAME is not a regular file.
+
 This function does code conversion according to the value of
 `coding-system-for-read' or `file-coding-system-alist', and sets the
 variable `last-coding-system-used' to the coding system actually used.
 
 In addition, this function decodes the inserted text from known formats
 by calling `format-decode', which see.  */)
-  (Lisp_Object filename, Lisp_Object visit, Lisp_Object beg, Lisp_Object end, 
Lisp_Object replace)
+  (Lisp_Object filename, Lisp_Object visit, Lisp_Object beg, Lisp_Object end,
+   Lisp_Object replace)
 {
   struct stat st;
   struct timespec mtime;
@@ -4123,24 +4155,27 @@ by calling `format-decode', which see.  */)
     report_file_error ("Input file status", orig_filename);
   mtime = get_stat_mtime (&st);
 
-  /* This code will need to be changed in order to work on named
-     pipes, and it's probably just not worth it.  So we should at
-     least signal an error.  */
+  /* The REPLACE code will need to be changed in order to work on
+     named pipes, and it's probably just not worth it.  So we should
+     at least signal an error.  */
+
   if (!S_ISREG (st.st_mode))
     {
       regular = false;
 
-      if (! NILP (visit))
-        {
-          eassert (inserted == 0);
-         goto notfound;
-        }
-
       if (!NILP (replace))
-       xsignal2 (Qfile_error,
-                 build_string ("not a regular file"), orig_filename);
+       {
+         if (!EQ (replace, Qif_regular))
+           xsignal2 (Qfile_error,
+                     build_string ("not a regular file"), orig_filename);
+         else
+           /* Set REPLACE to Qunbound, indicating that we are trying
+              to replace the buffer contents with that of a
+              non-regular file.  */
+           replace = Qunbound;
+       }
 
-      seekable = emacs_fd_lseek (fd, 0, SEEK_CUR) < 0;
+      seekable = emacs_fd_lseek (fd, 0, SEEK_CUR) != (off_t) -1;
       if (!NILP (beg) && !seekable)
        xsignal2 (Qfile_error,
                  build_string ("cannot use a start position in a non-seekable 
file/device"),
@@ -4316,7 +4351,8 @@ by calling `format-decode', which see.  */)
      method and hope for the best.
      But if we discover the need for conversion, we give up on this method
      and let the following if-statement handle the replace job.  */
-  if (!NILP (replace)
+  if ((!NILP (replace)
+       && !BASE_EQ (replace, Qunbound))
       && BEGV < ZV
       && (NILP (coding_system)
          || ! CODING_REQUIRE_DECODING (&coding)))
@@ -4503,7 +4539,9 @@ by calling `format-decode', which see.  */)
      is needed, in a simple way that needs a lot of memory.
      The preceding if-statement handles the case of no conversion
      in a more optimized way.  */
-  if (!NILP (replace) && ! replace_handled && BEGV < ZV)
+  if ((!NILP (replace)
+       && !BASE_EQ (replace, Qunbound))
+      && ! replace_handled && BEGV < ZV)
     {
       ptrdiff_t same_at_start_charpos;
       ptrdiff_t inserted_chars;
@@ -4688,6 +4726,12 @@ by calling `format-decode', which see.  */)
       prepare_to_modify_buffer (PT, PT, NULL);
     }
 
+  /* If REPLACE is Qunbound, buffer contents are being replaced with
+     text read from a FIFO.  Erase the entire buffer.  */
+
+  if (BASE_EQ (replace, Qunbound))
+    del_range (BEG, Z);
+
   move_gap_both (PT, PT_BYTE);
 
   /* Ensure the gap is at least one byte larger than needed for the
@@ -4696,7 +4740,8 @@ by calling `format-decode', which see.  */)
   if (GAP_SIZE <= total)
     make_gap (total - GAP_SIZE + 1);
 
-  if (beg_offset != 0 || !NILP (replace))
+  if (beg_offset != 0 || (!NILP (replace)
+                         && !EQ (replace, Qunbound)))
     {
       if (emacs_fd_lseek (fd, beg_offset, SEEK_SET) < 0)
        report_file_error ("Setting file position", orig_filename);
@@ -4729,6 +4774,7 @@ by calling `format-decode', which see.  */)
        if (!seekable && NILP (end))
          {
            Lisp_Object nbytes;
+           intmax_t number;
 
            /* Read from the file, capturing `quit'.  When an
               error occurs, end the loop, and arrange for a quit
@@ -4744,18 +4790,20 @@ by calling `format-decode', which see.  */)
                break;
              }
 
-           this = XFIXNUM (nbytes);
+           if (!integer_to_intmax (nbytes, &number)
+               && number > PTRDIFF_MAX)
+             buffer_overflow ();
+
+           this = number;
          }
        else
-         {
-           /* Allow quitting out of the actual I/O.  We don't make text
-              part of the buffer until all the reading is done, so a C-g
-              here doesn't do any harm.  */
-           this = emacs_fd_read (fd,
-                                 ((char *) BEG_ADDR + PT_BYTE - BEG_BYTE
-                                  + inserted),
-                                 trytry);
-         }
+         /* Allow quitting out of the actual I/O.  We don't make text
+            part of the buffer until all the reading is done, so a
+            C-g here doesn't do any harm.  */
+         this = emacs_fd_read (fd,
+                               ((char *) BEG_ADDR + PT_BYTE - BEG_BYTE
+                                + inserted),
+                               trytry);
 
        if (this <= 0)
          {
@@ -4940,9 +4988,14 @@ by calling `format-decode', which see.  */)
            Funlock_file (BVAR (current_buffer, file_truename));
          Funlock_file (filename);
        }
+
+#if !defined HAVE_ANDROID || defined ANDROID_STUBIFY
+      /* Under Android, modtime and st.st_size can be valid even if FD
+        is not a regular file.  */
       if (!regular)
        xsignal2 (Qfile_error,
                  build_string ("not a regular file"), orig_filename);
+#endif /* !defined HAVE_ANDROID || defined ANDROID_STUBIFY */
     }
 
   if (set_coding_system)
@@ -6810,9 +6863,11 @@ This includes interactive calls to `delete-file' and
 
 #ifndef DOS_NT
   defsubr (&Sfile_system_info);
-#endif
+#endif /* DOS_NT */
 
 #ifdef HAVE_SYNC
   defsubr (&Sunix_sync);
-#endif
+#endif /* HAVE_SYNC */
+
+  DEFSYM (Qif_regular, "if-regular");
 }



reply via email to

[Prev in Thread] Current Thread [Next in Thread]