diff --git a/java/org/gnu/emacs/EmacsSafThread.java b/java/org/gnu/emacs/EmacsSafThread.java index 421e82c5759..1b62662b4fc 100644 --- a/java/org/gnu/emacs/EmacsSafThread.java +++ b/java/org/gnu/emacs/EmacsSafThread.java @@ -437,11 +437,14 @@ private static final class CacheEntry /* Cache file status for DOCUMENTID within TOPLEVEL. Value is the new cache entry. CURSOR is the cursor from where to retrieve the file status, in the form of the columns COLUMN_FLAGS, - COLUMN_SIZE, COLUMN_MIME_TYPE and COLUMN_LAST_MODIFIED. */ + COLUMN_SIZE, COLUMN_MIME_TYPE and COLUMN_LAST_MODIFIED. + + If NO_CACHE, don't cache the file status; just return the + entry. */ private StatCacheEntry cacheFileStatus (String documentId, CacheToplevel toplevel, - Cursor cursor) + Cursor cursor, boolean no_cache) { StatCacheEntry entry; int flagsIndex, columnIndex, typeIndex; @@ -482,7 +485,8 @@ private static final class CacheEntry entry.mtime = cursor.getLong (mtimeIndex); /* Finally, add this entry to the cache and return. */ - toplevel.statCache.put (documentId, entry); + if (!no_cache) + toplevel.statCache.put (documentId, entry); return entry; } @@ -546,7 +550,7 @@ private static final class CacheEntry directory listing is being requested, it's very likely that a series of calls for file status will follow. */ - cacheFileStatus (id, toplevel, cursor); + cacheFileStatus (id, toplevel, cursor, false); /* If this constituent is a directory, don't cache any information about it. It cannot be cached without @@ -1217,7 +1221,7 @@ type is either NULL (in which case id should also be NULL) or private long[] statDocument1 (String uri, String documentId, - CancellationSignal signal) + CancellationSignal signal, boolean noCache) { Uri uriObject, tree; String[] projection; @@ -1266,7 +1270,8 @@ type is either NULL (in which case id should also be NULL) or if (!cursor.moveToFirst ()) return null; - cache = cacheFileStatus (documentId, toplevel, cursor); + cache = cacheFileStatus (documentId, toplevel, cursor, + noCache); } finally { @@ -1332,18 +1337,22 @@ type is either NULL (in which case id should also be NULL) or last modification to this file in milliseconds since 00:00, January 1st, 1970. + If NOCACHE, refrain from placing the file status within the + status cache. + OperationCanceledException and other typical exceptions may be signaled upon receiving async input or other errors. */ public long[] - statDocument (final String uri, final String documentId) + statDocument (final String uri, final String documentId, + final boolean noCache) { return (long[]) runObjectFunction (new SafObjectFunction () { @Override public Object runObject (CancellationSignal signal) { - return statDocument1 (uri, documentId, signal); + return statDocument1 (uri, documentId, signal, noCache); } }); } diff --git a/java/org/gnu/emacs/EmacsService.java b/java/org/gnu/emacs/EmacsService.java index 14ff2cce98f..379b1d30eda 100644 --- a/java/org/gnu/emacs/EmacsService.java +++ b/java/org/gnu/emacs/EmacsService.java @@ -1389,11 +1389,14 @@ else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) last modification to this file in milliseconds since 00:00, January 1st, 1970. + If NOCACHE, refrain from placing the file status within the + status cache. + OperationCanceledException and other typical exceptions may be signaled upon receiving async input or other errors. */ public long[] - statDocument (String uri, String documentId) + statDocument (String uri, String documentId, boolean noCache) { /* Start the thread used to run SAF requests if it isn't already running. */ @@ -1404,7 +1407,7 @@ else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) storageThread.start (); } - return storageThread.statDocument (uri, documentId); + return storageThread.statDocument (uri, documentId, noCache); } /* Find out whether Emacs has access to the document designated by diff --git a/src/android.c b/src/android.c index 7f263bc83d1..705ef227df3 100644 --- a/src/android.c +++ b/src/android.c @@ -1564,7 +1564,7 @@ android_init_emacs_service (void) "(Ljava/lang/String;Ljava/lang/String;)" "Ljava/lang/String;"); FIND_METHOD (stat_document, "statDocument", - "(Ljava/lang/String;Ljava/lang/String;)[J"); + "(Ljava/lang/String;Ljava/lang/String;Z)[J"); FIND_METHOD (access_document, "accessDocument", "(Ljava/lang/String;Ljava/lang/String;Z)I"); FIND_METHOD (open_document_directory, "openDocumentDirectory", diff --git a/src/androidvfs.c b/src/androidvfs.c index 8e742f8b26f..0385e7348c6 100644 --- a/src/androidvfs.c +++ b/src/androidvfs.c @@ -3932,12 +3932,15 @@ android_saf_exception_check (int n, ...) /* Return file status for the document designated by ID_NAME within the document tree identified by URI_NAME. + If NO_CACHE, don't cache the resulting file status. Enable this + option if the file status is subject to imminent change. + If the file status is available, place it within *STATB and return 0. If not, return -1 and set errno to EPERM. */ static int android_saf_stat (const char *uri_name, const char *id_name, - struct stat *statb) + struct stat *statb, bool no_cache) { jmethodID method; jstring uri, id; @@ -3969,10 +3972,12 @@ android_saf_stat (const char *uri_name, const char *id_name, /* Try to retrieve the file status. */ method = service_class.stat_document; inside_saf_critical_section = true; - status = (*android_java_env)->CallNonvirtualObjectMethod (android_java_env, - emacs_service, - service_class.class, - method, uri, id); + status + = (*android_java_env)->CallNonvirtualObjectMethod (android_java_env, + emacs_service, + service_class.class, + method, uri, id, + (jboolean) no_cache); inside_saf_critical_section = false; /* Check for exceptions and release unneeded local references. */ @@ -5076,7 +5081,7 @@ android_saf_tree_stat (struct android_vnode *vnode, vp = (struct android_saf_tree_vnode *) vnode; return android_saf_stat (vp->tree_uri, vp->document_id, - statb); + statb, false); } static int @@ -5716,10 +5721,15 @@ android_saf_file_open (struct android_vnode *vnode, int flags, ANDROID_DELETE_LOCAL_REF (descriptor); /* Try to retrieve the modification time of this file from the - content provider. */ + content provider. + + Refrain from introducing the file status into the file status + cache if FLAGS & O_RDWR or FLAGS & O_WRONLY: the cached file + status will contain a size and modification time inconsistent + with the result of any modifications that later transpire. */ if (!android_saf_stat (vp->tree_uri, vp->document_id, - &statb)) + &statb, write)) info->mtime = get_stat_mtime (&statb); else info->mtime = invalid_timespec ();