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.
This commit is contained in:
parent
3fb2c174d3
commit
d35ead5bd8
4 changed files with 85 additions and 41 deletions
|
@ -1565,8 +1565,9 @@ In addition, arbitrary runtime exceptions (such as
|
|||
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 @@ In addition, arbitrary runtime exceptions (such as
|
|||
|
||||
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 @@ In addition, arbitrary runtime exceptions (such as
|
|||
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 @@ In addition, arbitrary runtime exceptions (such as
|
|||
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 @@ In addition, arbitrary runtime exceptions (such as
|
|||
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 @@ In addition, arbitrary runtime exceptions (such as
|
|||
|
||||
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 @@ In addition, arbitrary runtime exceptions (such as
|
|||
runObject (CancellationSignal signal)
|
||||
throws Throwable
|
||||
{
|
||||
return openDocument1 (uri, documentId, write, truncate,
|
||||
signal);
|
||||
return openDocument1 (uri, documentId, read,
|
||||
write, truncate, signal);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -1537,15 +1537,13 @@ In addition, arbitrary runtime exceptions (such as
|
|||
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 @@ In addition, arbitrary runtime exceptions (such as
|
|||
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 @@ In addition, arbitrary runtime exceptions (such as
|
|||
storageThread.start ();
|
||||
}
|
||||
|
||||
return storageThread.openDocument (uri, documentId, write,
|
||||
return storageThread.openDocument (uri, documentId, read, write,
|
||||
truncate);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;"
|
||||
|
|
|
@ -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'.
|
||||
|
|
Loading…
Add table
Reference in a new issue