emacs-diffs
[Top][All Lists]
Advanced

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

master d35ead5bd8a 2/3: Utilize more frequently supported file access mo


From: Po Lu
Subject: master d35ead5bd8a 2/3: Utilize more frequently supported file access modes
Date: Tue, 8 Aug 2023 01:50:12 -0400 (EDT)

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

    Utilize more frequently supported file access modes
    
    * java/org/gnu/emacs/EmacsSafThread.java (openDocument1): Use
    plain r or w where possible, as the fileio stuff is now better
    prepared for FIFOs.
    (openDocument): New argument READ.
    * java/org/gnu/emacs/EmacsService.java (openDocument): New
    argument READ.
    * src/android.c (android_init_emacs_service): Adjust
    correspondingly.
    * src/androidvfs.c (android_saf_file_open): Don't support
    O_APPEND.  Pass read as well as trunc and write.
---
 java/org/gnu/emacs/EmacsSafThread.java | 58 ++++++++++++++++++++--------------
 java/org/gnu/emacs/EmacsService.java   | 20 ++++++------
 src/android.c                          |  2 +-
 src/androidvfs.c                       | 46 ++++++++++++++++++++++++---
 4 files changed, 85 insertions(+), 41 deletions(-)

diff --git a/java/org/gnu/emacs/EmacsSafThread.java 
b/java/org/gnu/emacs/EmacsSafThread.java
index 3ae3c0839ce..9f5d7f3d0cf 100644
--- a/java/org/gnu/emacs/EmacsSafThread.java
+++ b/java/org/gnu/emacs/EmacsSafThread.java
@@ -1565,8 +1565,9 @@ public final class EmacsSafThread extends HandlerThread
      signal.  */
 
   public ParcelFileDescriptor
-  openDocument1 (String uri, String documentId, boolean write,
-                boolean truncate, CancellationSignal signal)
+  openDocument1 (String uri, String documentId, boolean read,
+                boolean write, boolean truncate,
+                CancellationSignal signal)
     throws Throwable
   {
     Uri treeUri, documentUri;
@@ -1586,10 +1587,19 @@ public final class EmacsSafThread extends HandlerThread
 
     if (write)
       {
-       if (truncate)
-         mode = "rwt";
+       if (read)
+         {
+           if (truncate)
+             mode = "rwt";
+           else
+             mode = "rw";
+         }
        else
-         mode = "rw";
+         /* Set mode to w when WRITE && !READ, disregarding TRUNCATE.
+            In contradiction with the ContentResolver documentation,
+            document providers seem to truncate files whenever w is
+            specified, at least superficially.  */
+         mode = "w";
       }
     else
       mode = "r";
@@ -1597,14 +1607,15 @@ public final class EmacsSafThread extends HandlerThread
     fileDescriptor
       = resolver.openFileDescriptor (documentUri, mode,
                                     signal);
+    Log.d (TAG, "openDocument1: " + mode + " " + fileDescriptor);
 
-    /* If a writable file descriptor is requested and TRUNCATE is set,
-       then probe the file descriptor to detect if it is actually
-       readable.  If not, close this file descriptor and reopen it
-       with MODE set to rw; some document providers granting access to
-       Samba shares don't implement rwt, but these document providers
-       invariably truncate the file opened even when the mode is
-       merely rw.
+    /* If a writable on-disk file descriptor is requested and TRUNCATE
+       is set, then probe the file descriptor to detect if it is
+       actually readable.  If not, close this file descriptor and
+       reopen it with MODE set to rw; some document providers granting
+       access to Samba shares don't implement rwt, but these document
+       providers invariably truncate the file opened even when the
+       mode is merely w.
 
        This may be ascribed to a mix-up in Android's documentation
        regardin DocumentsProvider: the `openDocument' function is only
@@ -1612,7 +1623,7 @@ public final class EmacsSafThread extends HandlerThread
        implementation of the `openFile' function (which documents rwt)
        delegates to `openDocument'.  */
 
-    if (write && truncate && fileDescriptor != null
+    if (read && write && truncate && fileDescriptor != null
        && !EmacsNative.ftruncate (fileDescriptor.getFd ()))
       {
        try
@@ -1647,15 +1658,13 @@ public final class EmacsSafThread extends HandlerThread
      TRUNCATE and the document already exists, truncate its contents
      before returning.
 
-     On Android 9.0 and earlier, always open the document in
-     ``read-write'' mode; this instructs the document provider to
-     return a seekable file that is stored on disk and returns correct
-     file status.
+     If READ && WRITE, open the file under either the `rw' or `rwt'
+     access mode, which implies that the value must be a seekable
+     on-disk file.  If WRITE && !READ or TRUNC && WRITE, also truncate
+     the file after it is opened.
 
-     Under newer versions of Android, open the document in a
-     non-writable mode if WRITE is false.  This is possible because
-     these versions allow Emacs to explicitly request a seekable
-     on-disk file.
+     If only READ or WRITE is set, value may be a non-seekable FIFO or
+     one end of a socket pair.
 
      Value is NULL upon failure or a parcel file descriptor upon
      success.  Call `ParcelFileDescriptor.close' on this file
@@ -1667,7 +1676,8 @@ public final class EmacsSafThread extends HandlerThread
 
   public ParcelFileDescriptor
   openDocument (final String uri, final String documentId,
-               final boolean write, final boolean truncate)
+               final boolean read, final boolean write,
+               final boolean truncate)
   {
     Object tem;
 
@@ -1677,8 +1687,8 @@ public final class EmacsSafThread extends HandlerThread
        runObject (CancellationSignal signal)
          throws Throwable
        {
-         return openDocument1 (uri, documentId, write, truncate,
-                               signal);
+         return openDocument1 (uri, documentId, read,
+                               write, truncate, signal);
        }
       });
 
diff --git a/java/org/gnu/emacs/EmacsService.java 
b/java/org/gnu/emacs/EmacsService.java
index d91d8f66009..14ff2cce98f 100644
--- a/java/org/gnu/emacs/EmacsService.java
+++ b/java/org/gnu/emacs/EmacsService.java
@@ -1537,15 +1537,13 @@ public final class EmacsService extends Service
      TRUNCATE and the document already exists, truncate its contents
      before returning.
 
-     On Android 9.0 and earlier, always open the document in
-     ``read-write'' mode; this instructs the document provider to
-     return a seekable file that is stored on disk and returns correct
-     file status.
+     If READ && WRITE, open the file under either the `rw' or `rwt'
+     access mode, which implies that the value must be a seekable
+     on-disk file.  If TRUNC && WRITE, also truncate the file after it
+     is opened.
 
-     Under newer versions of Android, open the document in a
-     non-writable mode if WRITE is false.  This is possible because
-     these versions allow Emacs to explicitly request a seekable
-     on-disk file.
+     If only READ or WRITE is set, value may be a non-seekable FIFO or
+     one end of a socket pair.
 
      Value is NULL upon failure or a parcel file descriptor upon
      success.  Call `ParcelFileDescriptor.close' on this file
@@ -1555,8 +1553,8 @@ public final class EmacsService extends Service
      UnsupportedOperationException may be thrown upon failure.  */
 
   public ParcelFileDescriptor
-  openDocument (String uri, String documentId, boolean write,
-               boolean truncate)
+  openDocument (String uri, String documentId,
+               boolean read, boolean write, boolean truncate)
   {
     /* Start the thread used to run SAF requests if it isn't already
        running.  */
@@ -1567,7 +1565,7 @@ public final class EmacsService extends Service
        storageThread.start ();
       }
 
-    return storageThread.openDocument (uri, documentId, write,
+    return storageThread.openDocument (uri, documentId, read, write,
                                       truncate);
   }
 
diff --git a/src/android.c b/src/android.c
index bd19107f53a..7f263bc83d1 100644
--- a/src/android.c
+++ b/src/android.c
@@ -1574,7 +1574,7 @@ android_init_emacs_service (void)
               "(Landroid/database/Cursor;)Lorg/gnu/emacs/"
               "EmacsDirectoryEntry;");
   FIND_METHOD (open_document, "openDocument",
-              "(Ljava/lang/String;Ljava/lang/String;ZZ)"
+              "(Ljava/lang/String;Ljava/lang/String;ZZZ)"
               "Landroid/os/ParcelFileDescriptor;");
   FIND_METHOD (create_document, "createDocument",
               "(Ljava/lang/String;Ljava/lang/String;"
diff --git a/src/androidvfs.c b/src/androidvfs.c
index 4234e337acb..0ee555c0ad4 100644
--- a/src/androidvfs.c
+++ b/src/androidvfs.c
@@ -5590,7 +5590,7 @@ android_saf_file_open (struct android_vnode *vnode, int 
flags,
   struct android_saf_file_vnode *vp;
   jobject uri, id, descriptor;
   jmethodID method;
-  jboolean trunc, write;
+  jboolean read, trunc, write;
   jint fd;
   struct android_parcel_fd *info;
   struct stat statb;
@@ -5601,6 +5601,15 @@ android_saf_file_open (struct android_vnode *vnode, int 
flags,
       return -1;
     }
 
+  /* O_APPEND isn't supported as a consequence of Android content
+     providers defaulting to truncating the file.  */
+
+  if (flags & O_APPEND)
+    {
+      errno = EOPNOTSUPP;
+      return -1;
+    }
+
   /* Build strings for both the URI and ID.  */
 
   vp = (struct android_saf_file_vnode *) vnode;
@@ -5611,18 +5620,43 @@ android_saf_file_open (struct android_vnode *vnode, int 
flags,
                                          vp->document_id);
   android_exception_check_1 (uri);
 
-  /* Open a parcel file descriptor according to flags.  */
+  /* Open a parcel file descriptor according to flags.  Documentation
+     for the SAF openDocument operation is scant and seldom helpful.
+     It's clear that their file access modes are inconsistently
+     implemented, and that at least:
+
+       r   = either an FIFO or a real file, without truncation.
+       w   = either an FIFO or a real file, with truncation.
+       wt  = either an FIFO or a real file, with truncation.
+       rw  = a real file, without truncation.
+       rwt = a real file, with truncation.
+
+     This diverges from the self-contradicting documentation, where
+     openDocument says nothing about truncation, and openFile, where
+     w can elect not to truncate.
+
+     Since Emacs is prepared to handle FIFOs within fileio.c, simply
+     use the straightforward relationships possible.  */
 
   method = service_class.open_document;
-  trunc  = (flags & O_TRUNC);
-  write  = (((flags & O_RDWR) == O_RDWR) || (flags & O_WRONLY));
+  read = trunc = write = false;
+
+  if ((flags & O_RDWR) == O_RDWR || (flags & O_WRONLY))
+    write = true;
+
+  if (flags & O_TRUNC)
+    trunc = true;
+
+  if ((flags & O_RDWR) == O_RDWR || !write)
+    read = true;
+
   inside_saf_critical_section = true;
   descriptor
     = (*android_java_env)->CallNonvirtualObjectMethod (android_java_env,
                                                       emacs_service,
                                                       service_class.class,
                                                       method, uri, id,
-                                                      write, trunc);
+                                                      read, write, trunc);
   inside_saf_critical_section = false;
 
   if (android_saf_exception_check (2, uri, id))
@@ -6448,6 +6482,8 @@ android_vfs_init (JNIEnv *env, jobject manager)
    vnodes may not be reentrant, but operating on them from within an
    async input handler will at worst cause an error to be returned.
 
+   The eight is that some vnode types do not support O_APPEND.
+
    And the final drawback is that directories cannot be directly
    opened.  Instead, `dirfd' must be called on a directory stream used
    by `openat'.



reply via email to

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