emacs-diffs
[Top][All Lists]
Advanced

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

feature/android 03cf3bbb5c3: Update Android port


From: Po Lu
Subject: feature/android 03cf3bbb5c3: Update Android port
Date: Fri, 28 Jul 2023 00:22:22 -0400 (EDT)

branch: feature/android
commit 03cf3bbb5c38aa55abd6f7d4860025f7482fcfc3
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Update Android port
    
    * java/org/gnu/emacs/EmacsDirectoryEntry.java
    (EmacsDirectoryEntry): Make class final.
    * java/org/gnu/emacs/EmacsService.java (accessDocument)
    (openDocumentDirectory, openDocument, createDocument): Throw
    access and IO error exceptions instead of catching them.
    (createDirectory, deleteDocument): New functions.
    * src/android.c (android_init_emacs_service): Add new functions.
    * src/android.h (struct android_emacs_service): Likewise.
    * src/androidvfs.c (android_saf_exception_check): New function.
    Translate between Java exceptions and errno values.
    (android_saf_stat, android_saf_access, android_saf_delete_document)
    (struct android_saf_tree_vnode, android_document_id_from_name)
    (android_saf_tree_name, android_saf_tree_rmdir)
    (android_saf_tree_opendir_1, android_saf_tree_opendir)
    (android_saf_file_open, android_saf_file_unlink)
    (android_saf_new_open, android_saf_new_mkdir): Implement missing
    VFS operations and derive errno values from the type of any
    exceptions thrown.
    (android_vfs_init): Initialize exception classes.
    (android_mkdir, android_fstat): Remove trailing whitespace.
---
 java/org/gnu/emacs/EmacsDirectoryEntry.java |   2 +-
 java/org/gnu/emacs/EmacsService.java        | 210 ++++++++++--------
 src/android.c                               |   5 +
 src/android.h                               |   2 +
 src/androidvfs.c                            | 316 +++++++++++++++++++++++++---
 5 files changed, 410 insertions(+), 125 deletions(-)

diff --git a/java/org/gnu/emacs/EmacsDirectoryEntry.java 
b/java/org/gnu/emacs/EmacsDirectoryEntry.java
index 9c10f2e8771..75c52e48002 100644
--- a/java/org/gnu/emacs/EmacsDirectoryEntry.java
+++ b/java/org/gnu/emacs/EmacsDirectoryEntry.java
@@ -22,7 +22,7 @@ package org.gnu.emacs;
 /* Structure holding a single ``directory entry'' from a document
    provider.  */
 
-public class EmacsDirectoryEntry
+public final class EmacsDirectoryEntry
 {
   /* The type of this directory entry.  0 means a regular file and 1
      means a directory.  */
diff --git a/java/org/gnu/emacs/EmacsService.java 
b/java/org/gnu/emacs/EmacsService.java
index bc62e050345..aa672994f12 100644
--- a/java/org/gnu/emacs/EmacsService.java
+++ b/java/org/gnu/emacs/EmacsService.java
@@ -1723,9 +1723,12 @@ public final class EmacsService extends Service
      not:
 
        -1, if the file does not exist.
-       -2, upon a security exception or if WRITABLE the file
-           is not writable.
-       -3, upon any other error.  */
+       -2, if WRITABLE and the file is not writable.
+       -3, upon any other error.
+
+     In addition, arbitrary runtime exceptions (such as
+     SecurityException or UnsupportedOperationException) may be
+     thrown.  */
 
   public int
   accessDocument (String uri, String documentId, boolean writable)
@@ -1754,24 +1757,8 @@ public final class EmacsService extends Service
       Document.COLUMN_MIME_TYPE,
     };
 
-    try
-      {
-       cursor = resolver.query (uriObject, projection, null,
-                                null, null);
-      }
-    catch (SecurityException exception)
-      {
-       /* A SecurityException can be thrown if Emacs doesn't have
-          access to uriObject.  */
-       return -2;
-      }
-    catch (UnsupportedOperationException exception)
-      {
-       exception.printStackTrace ();
-
-       /* Why is this? */
-       return -3;
-      }
+    cursor = resolver.query (uriObject, projection, null,
+                            null, null);
 
     if (cursor == null || !cursor.moveToFirst ())
       return -1;
@@ -1816,13 +1803,10 @@ public final class EmacsService extends Service
        if (writable && (tem & Document.FLAG_SUPPORTS_WRITE) == 0)
          return -3;
       }
-    catch (Exception exception)
+    finally
       {
-       /* Whether or not type errors cause exceptions to be signaled
-          is defined ``by the implementation of Cursor'', whatever
-          that means.  */
-       exception.printStackTrace ();
-       return -3;
+       /* Close the cursor if an exception occurs.  */
+       cursor.close ();
       }
 
     return 0;
@@ -1832,7 +1816,11 @@ public final class EmacsService extends Service
      designated by the specified DOCUMENTID within the tree URI.
 
      If DOCUMENTID is NULL, use the document ID within URI itself.
-     Value is NULL upon failure.  */
+     Value is NULL upon failure.
+
+     In addition, arbitrary runtime exceptions (such as
+     SecurityException or UnsupportedOperationException) may be
+     thrown.  */
 
   public Cursor
   openDocumentDirectory (String uri, String documentId)
@@ -1861,25 +1849,8 @@ public final class EmacsService extends Service
       Document.COLUMN_MIME_TYPE,
     };
 
-    try
-      {
-       cursor = resolver.query (uriObject, projection, null, null,
-                                null);
-      }
-    catch (SecurityException exception)
-      {
-       /* A SecurityException can be thrown if Emacs doesn't have
-          access to uriObject.  */
-       return null;
-      }
-    catch (UnsupportedOperationException exception)
-      {
-       exception.printStackTrace ();
-
-       /* Why is this? */
-       return null;
-      }
-
+    cursor = resolver.query (uriObject, projection, null, null,
+                            null);
     /* Return the cursor.  */
     return cursor;
   }
@@ -1966,11 +1937,15 @@ public final class EmacsService extends Service
 
      Value is NULL upon failure or a parcel file descriptor upon
      success.  Call `ParcelFileDescriptor.close' on this file
-     descriptor instead of using the `close' system call.  */
+     descriptor instead of using the `close' system call.
+
+     FileNotFoundException and/or SecurityException and
+     UnsupportedOperationException may be thrown upon failure.  */
 
   public ParcelFileDescriptor
   openDocument (String uri, String documentId, boolean write,
                boolean truncate)
+    throws FileNotFoundException
   {
     Uri treeUri, documentUri;
     String mode;
@@ -1984,40 +1959,33 @@ public final class EmacsService extends Service
     documentUri
       = DocumentsContract.buildDocumentUriUsingTree (treeUri, documentId);
 
-    try
+    if (write || Build.VERSION.SDK_INT < Build.VERSION_CODES.Q)
       {
-       if (write || Build.VERSION.SDK_INT < Build.VERSION_CODES.Q)
-         {
-           /* Select the mode used to open the file.  `rw' means open
-              a stat-able file, while `rwt' means that and to
-              truncate the file as well.  */
-
-           if (truncate)
-             mode = "rwt";
-           else
-             mode = "rw";
-
-           fileDescriptor
-             = resolver.openFileDescriptor (documentUri, mode,
-                                            null);
-         }
-       else
-         {
-           /* Select the mode used to open the file.  `openFile'
-              below means always open a stat-able file.  */
+       /* Select the mode used to open the file.  `rw' means open
+          a stat-able file, while `rwt' means that and to
+          truncate the file as well.  */
 
-           if (truncate)
-             /* Invalid mode! */
-             return null;
-           else
-             mode = "r";
+       if (truncate)
+         mode = "rwt";
+       else
+         mode = "rw";
 
-           fileDescriptor = resolver.openFile (documentUri, mode, null);
-         }
+       fileDescriptor
+         = resolver.openFileDescriptor (documentUri, mode,
+                                        null);
       }
-    catch (Exception exception)
+    else
       {
-       return null;
+       /* Select the mode used to open the file.  `openFile'
+          below means always open a stat-able file.  */
+
+       if (truncate)
+         /* Invalid mode! */
+         return null;
+       else
+         mode = "r";
+
+       fileDescriptor = resolver.openFile (documentUri, mode, null);
       }
 
     return fileDescriptor;
@@ -2030,11 +1998,15 @@ public final class EmacsService extends Service
      If DOCUMENTID is NULL, create the document inside the root of
      that tree.
 
+     Either FileNotFoundException, SecurityException or
+     UnsupportedOperationException may be thrown upon failure.
+
      Return the document ID of the new file upon success, NULL
      otherwise.  */
 
   public String
   createDocument (String uri, String documentId, String name)
+    throws FileNotFoundException
   {
     String mimeType, separator, mime, extension;
     int index;
@@ -2072,23 +2044,77 @@ public final class EmacsService extends Service
       = DocumentsContract.buildChildDocumentsUriUsingTree (directoryUri,
                                                           documentId);
 
-    try
-      {
-       docUri = DocumentsContract.createDocument (resolver,
-                                                  directoryUri,
-                                                  mimeType, name);
+    docUri = DocumentsContract.createDocument (resolver,
+                                              directoryUri,
+                                              mimeType, name);
 
-       if (docUri == null)
-         return null;
+    if (docUri == null)
+      return null;
 
-       /* Return the ID of the new document.  */
-       return DocumentsContract.getDocumentId (docUri);
-      }
-    catch (Exception exception)
-      {
-       exception.printStackTrace ();
-      }
+    /* Return the ID of the new document.  */
+    return DocumentsContract.getDocumentId (docUri);
+  }
 
-    return null;
+  /* Like `createDocument', but create a directory instead of an
+     ordinary document.  */
+
+  public String
+  createDirectory (String uri, String documentId, String name)
+    throws FileNotFoundException
+  {
+    int index;
+    Uri directoryUri, docUri;
+
+    /* Now parse URI.  */
+    directoryUri = Uri.parse (uri);
+
+    if (documentId == null)
+      documentId = DocumentsContract.getTreeDocumentId (directoryUri);
+
+    /* And build a file URI referring to the directory.  */
+
+    directoryUri
+      = DocumentsContract.buildChildDocumentsUriUsingTree (directoryUri,
+                                                          documentId);
+
+    /* If name ends with a directory separator character, delete
+       it.  */
+
+    if (name.endsWith ("/"))
+      name = name.substring (0, name.length () - 1);
+
+    /* From Android's perspective, directories are just ordinary
+       documents with the `MIME_TYPE_DIR' type.  */
+
+    docUri = DocumentsContract.createDocument (resolver,
+                                              directoryUri,
+                                              Document.MIME_TYPE_DIR,
+                                              name);
+
+    if (docUri == null)
+      return null;
+
+    /* Return the ID of the new document.  */
+    return DocumentsContract.getDocumentId (docUri);
+  }
+
+  /* Delete the document identified by ID from the document tree
+     identified by URI.  Return 0 upon success and -1 upon
+     failure.  */
+
+  public int
+  deleteDocument (String uri, String id)
+    throws FileNotFoundException
+  {
+    Uri uriObject;
+
+    uriObject = Uri.parse (uri);
+    uriObject = DocumentsContract.buildDocumentUriUsingTree (uriObject,
+                                                            id);
+
+    if (DocumentsContract.deleteDocument (resolver, uriObject))
+      return 0;
+
+    return -1;
   }
 };
diff --git a/src/android.c b/src/android.c
index 098fa6c383d..687c0b48a2a 100644
--- a/src/android.c
+++ b/src/android.c
@@ -1577,6 +1577,11 @@ android_init_emacs_service (void)
   FIND_METHOD (create_document, "createDocument",
               "(Ljava/lang/String;Ljava/lang/String;"
               "Ljava/lang/String;)Ljava/lang/String;");
+  FIND_METHOD (create_directory, "createDirectory",
+              "(Ljava/lang/String;Ljava/lang/String;"
+              "Ljava/lang/String;)Ljava/lang/String;");
+  FIND_METHOD (delete_document, "deleteDocument",
+              "(Ljava/lang/String;Ljava/lang/String;)I");
 #undef FIND_METHOD
 }
 
diff --git a/src/android.h b/src/android.h
index 94a3ad46e74..fd391fa6435 100644
--- a/src/android.h
+++ b/src/android.h
@@ -279,6 +279,8 @@ struct android_emacs_service
   jmethodID read_directory_entry;
   jmethodID open_document;
   jmethodID create_document;
+  jmethodID create_directory;
+  jmethodID delete_document;
 };
 
 extern JNIEnv *android_java_env;
diff --git a/src/androidvfs.c b/src/androidvfs.c
index c174c35f02b..2cd50963e97 100644
--- a/src/androidvfs.c
+++ b/src/androidvfs.c
@@ -276,6 +276,10 @@ static struct emacs_directory_entry_class entry_class;
    class.  */
 static struct android_parcel_file_descriptor_class fd_class;
 
+/* Global references to several exception classes.  */
+static jclass file_not_found_exception, security_exception;
+static jclass unsupported_operation_exception, out_of_memory_error;
+
 /* Initialize `cursor_class' using the given JNI environment ENV.
    Calling this function is not necessary on Android 4.4 and
    earlier.  */
@@ -3688,6 +3692,85 @@ android_saf_root_get_directory (int dirfd)
 
 /* Functions common to both SAF directory and file nodes.  */
 
+/* Check for JNI exceptions, clear them, and set errno accordingly.
+   Also, free each of the N local references given as arguments if an
+   exception takes place.
+
+   Value is 1 if an exception has taken place, 0 otherwise.
+
+   If the exception thrown derives from FileNotFoundException, set
+   errno to ENOENT.
+
+   If the exception thrown derives from SecurityException, set errno
+   to EACCES.
+
+   If the exception thrown derives from UnsupportedOperationException,
+   set errno to ENOSYS.
+
+   If the exception thrown derives from OutOfMemoryException, call
+   `memory_full'.
+
+   If the exception thrown is anything else, set errno to EIO.  */
+
+static int
+android_saf_exception_check (int n, ...)
+{
+  jthrowable exception;
+  JNIEnv *env;
+  va_list ap;
+
+  env = android_java_env;
+  va_start (ap, n);
+
+  /* First, check for an exception.  */
+
+  if (!(*env)->ExceptionCheck (env))
+    /* No exception has taken place.  Return 0.  */
+    return 0;
+
+  exception = (*env)->ExceptionOccurred (env);
+
+  if (!exception)
+    /* JNI couldn't return a local reference to the exception.  */
+    memory_full (0);
+
+  /* Clear the exception, making it safe to subsequently call other
+     JNI functions.  */
+  (*env)->ExceptionClear (env);
+
+  /* Delete each of the N arguments.  */
+
+  while (n > 0)
+    {
+      ANDROID_DELETE_LOCAL_REF (va_arg (ap, jobject));
+      n--;
+    }
+
+  /* Now set errno or signal memory_full as required.  */
+
+  if ((*env)->IsInstanceOf (env, (jobject) exception,
+                           file_not_found_exception))
+    errno = ENOENT;
+  else if ((*env)->IsInstanceOf (env, (jobject) exception,
+                                security_exception))
+    errno = EACCES;
+  else if ((*env)->IsInstanceOf (env, (jobject) exception,
+                                unsupported_operation_exception))
+    errno = ENOSYS;
+  else if ((*env)->IsInstanceOf (env, (jobject) exception,
+                                out_of_memory_error))
+    {
+      ANDROID_DELETE_LOCAL_REF ((jobject) exception);
+      memory_full (0);
+    }
+  else
+    errno = EIO;
+
+  /* expression is still a local reference! */
+  ANDROID_DELETE_LOCAL_REF ((jobject) exception);
+  return 1;
+}
+
 /* Return file status for the document designated by ID_NAME within
    the document tree identified by URI_NAME.
 
@@ -3727,11 +3810,13 @@ android_saf_stat (const char *uri_name, const char 
*id_name,
 
   if (id)
     {
-      android_exception_check_2 (uri, id);
+      if (android_saf_exception_check (2, uri, id))
+       return -1;
+
       ANDROID_DELETE_LOCAL_REF (id);
     }
-  else
-    android_exception_check_1 (uri);
+  else if (android_saf_exception_check (1, uri))
+    return -1;
 
   ANDROID_DELETE_LOCAL_REF (uri);
 
@@ -3810,11 +3895,13 @@ android_saf_access (const char *uri_name, const char 
*id_name,
 
   if (id)
     {
-      android_exception_check_2 (uri, id);
+      if (android_saf_exception_check (2, uri, id))
+       return -1;
+
       ANDROID_DELETE_LOCAL_REF (id);
     }
-  else
-    android_exception_check_1 (uri);
+  else if (android_saf_exception_check (1, uri))
+    return -1;
 
   ANDROID_DELETE_LOCAL_REF (uri);
 
@@ -3840,6 +3927,46 @@ android_saf_access (const char *uri_name, const char 
*id_name,
   return 0;
 }
 
+/* Delete the document designated by DOC_ID within the tree identified
+   through the URI TREE.  Return 0 if the document has been deleted,
+   set errno and return -1 upon failure.  */
+
+static int
+android_saf_delete_document (const char *tree, const char *doc_id)
+{
+  jobject id, uri;
+  jmethodID method;
+  jint rc;
+
+  /* Build the strings holding the ID and URI.  */
+  id = (*android_java_env)->NewStringUTF (android_java_env,
+                                         doc_id);
+  android_exception_check ();
+  uri = (*android_java_env)->NewStringUTF (android_java_env,
+                                          tree);
+  android_exception_check_1 (id);
+
+  /* Now, try to delete the document.  */
+  method = service_class.delete_document;
+  rc = (*android_java_env)->CallIntMethod (android_java_env,
+                                          emacs_service,
+                                          method, uri, id);
+
+  if (android_saf_exception_check (2, id, uri))
+    return -1;
+
+  ANDROID_DELETE_LOCAL_REF (id);
+  ANDROID_DELETE_LOCAL_REF (uri);
+
+  if (rc)
+    {
+      errno = EACCES;
+      return -1;
+    }
+
+  return 0;
+}
+
 
 
 /* SAF directory vnode.  A file within a SAF directory tree is
@@ -3863,7 +3990,9 @@ struct android_saf_tree_vnode
   char *tree_id;
 
   /* The document ID of the directory represented, or NULL if this is
-     the root directory of the tree.  */
+     the root directory of the tree.  Since file and new vnodes don't
+     represent the root directory, this field is always set in
+     them.  */
   char *document_id;
 
   /* The file name of this tree vnode.  This is a ``path'' to the
@@ -4004,7 +4133,7 @@ android_verify_jni_string (const char *name)
    must name a directory file within TREE_URI.
 
    If NAME is not correct for the Java ``modified UTF-8'' coding
-   system, return -1.
+   system, return -1 and set errno to ENOENT.
 
    Upon success, return 0 or 1 (contingent upon whether or not the
    last component within NAME is a directory) and place the document
@@ -4014,7 +4143,8 @@ android_verify_jni_string (const char *name)
    within NAME does and is also a directory, return -2 and place the
    document ID of that directory within *ID.
 
-   If the designated file can't be located, return -1.  */
+   If the designated file can't be located, return -1 and set errno
+   accordingly.  */
 
 static int
 android_document_id_from_name (const char *tree_uri, char *name,
@@ -4023,7 +4153,6 @@ android_document_id_from_name (const char *tree_uri, char 
*name,
   jobjectArray result;
   jstring uri;
   jbyteArray java_name;
-  size_t length;
   jint rc;
   jmethodID method;
   const char *doc_id;
@@ -4055,7 +4184,10 @@ android_document_id_from_name (const char *tree_uri, 
char *name,
                                                     method,
                                                     uri, java_name,
                                                     result);
-  android_exception_check_3 (result, uri, java_name);
+
+  if (android_saf_exception_check (3, result, uri, java_name))
+    goto finish;
+
   ANDROID_DELETE_LOCAL_REF (uri);
   ANDROID_DELETE_LOCAL_REF (java_name);
 
@@ -4178,7 +4310,6 @@ android_saf_tree_name (struct android_vnode *vnode, char 
*name,
 
       /* The document ID can't be found.  */
       xfree (filename);
-      errno = ENOENT;
       return NULL;
     }
 
@@ -4354,9 +4485,19 @@ android_saf_tree_symlink (const char *target, struct 
android_vnode *vnode)
 static int
 android_saf_tree_rmdir (struct android_vnode *vnode)
 {
-  /* TODO */
-  errno = ENOSYS;
-  return -1;
+  struct android_saf_tree_vnode *vp;
+
+  vp = (struct android_saf_tree_vnode *) vnode;
+
+  /* Don't allow deleting the root directory.  */
+
+  if (!vp->document_id)
+    {
+      errno = EROFS;
+      return -1;
+    }
+
+  return android_saf_delete_document (vp->tree_uri, vp->document_id);
 }
 
 static int
@@ -4412,8 +4553,8 @@ android_saf_tree_mkdir (struct android_vnode *vnode, 
mode_t mode)
 /* Open a database Cursor containing each directory entry within the
    supplied SAF tree vnode VP.
 
-   Value is NULL upon failure, a local reference to the Cursor object
-   otherwise.  */
+   Value is NULL upon failure with errno set to a suitable value, a
+   local reference to the Cursor object otherwise.  */
 
 static jobject
 android_saf_tree_opendir_1 (struct android_saf_tree_vnode *vp)
@@ -4445,11 +4586,13 @@ android_saf_tree_opendir_1 (struct 
android_saf_tree_vnode *vp)
 
   if (id)
     {
-      android_exception_check_2 (id, uri);
+      if (android_saf_exception_check (2, id, uri))
+       return NULL;
+
       ANDROID_DELETE_LOCAL_REF (id);
     }
-  else
-    android_exception_check_1 (uri);
+  else if (android_saf_exception_check (1, uri))
+    return NULL;
 
   ANDROID_DELETE_LOCAL_REF (uri);
 
@@ -4657,7 +4800,6 @@ android_saf_tree_opendir (struct android_vnode *vnode)
     {
       xfree (dir);
       xfree (dir->name);
-      errno = ENOENT;
       return NULL;
     }
 
@@ -4880,7 +5022,10 @@ android_saf_file_open (struct android_vnode *vnode, int 
flags,
                                                       service_class.class,
                                                       method, uri, id,
                                                       write, trunc);
-  android_exception_check_2 (uri, id);
+
+  if (android_saf_exception_check (2, uri, id))
+    return -1;
+
   ANDROID_DELETE_LOCAL_REF (uri);
   ANDROID_DELETE_LOCAL_REF (id);
 
@@ -4953,9 +5098,10 @@ android_saf_file_open (struct android_vnode *vnode, int 
flags,
 static int
 android_saf_file_unlink (struct android_vnode *vnode)
 {
-  /* TODO */
-  errno = ENOSYS;
-  return -1;
+  struct android_saf_file_vnode *vp;
+
+  vp = (struct android_saf_file_vnode *) vnode;
+  return android_saf_delete_document (vp->tree_uri, vp->document_id);
 }
 
 static int
@@ -5114,7 +5260,7 @@ android_saf_new_open (struct android_vnode *vnode, int 
flags,
     {
       errno = ENOENT;
       return -1;
-    }  
+    }
 
   /* Otherwise, try to create a new document.  First, build strings
      for the name, ID and document URI.  */
@@ -5137,7 +5283,9 @@ android_saf_new_open (struct android_vnode *vnode, int 
flags,
                                                            service_class.class,
                                                            method, uri, id,
                                                            name);
-  android_exception_check_3 (name, id, uri);
+
+  if (android_saf_exception_check (3, name, id, uri))
+    return -1;
 
   /* Delete unused local references.  */
   ANDROID_DELETE_LOCAL_REF (name);
@@ -5225,9 +5373,90 @@ android_saf_new_access (struct android_vnode *vnode, int 
mode)
 static int
 android_saf_new_mkdir (struct android_vnode *vnode, mode_t mode)
 {
-  /* TODO */
-  errno = ENOSYS;
-  return -1;
+  struct android_saf_new_vnode *vp;
+  jstring name, id, uri, new_id;
+  jmethodID method;
+  const char *new_doc_id;
+  char *end;
+
+  vp = (struct android_saf_tree_vnode *) vnode;
+
+  /* Find the last component of vp->name.  */
+  end = strrchr (vp->name, '/');
+
+  /* VP->name must contain at least one directory separator.  */
+  eassert (end);
+
+  if (end[1] == '\0')
+    {
+      /* There's a trailing directory separator.  Search
+        backwards.  */
+
+      end--;
+      while (end != vp->name && *end != '/')
+       end--;
+
+      /* vp->name[0] is always a directory separator.  */
+      eassert (*end == '/');
+    }
+
+  /* Otherwise, try to create a new document.  First, build strings
+     for the name, ID and document URI.  */
+
+  name = (*android_java_env)->NewStringUTF (android_java_env,
+                                           end + 1);
+  android_exception_check ();
+  id = (*android_java_env)->NewStringUTF (android_java_env,
+                                         vp->document_id);
+  android_exception_check_1 (name);
+  uri = (*android_java_env)->NewStringUTF (android_java_env,
+                                          vp->tree_uri);
+  android_exception_check_2 (name, id);
+
+  /* Next, try to create a new document and retrieve its ID.  */
+
+  method = service_class.create_directory;
+  new_id = (*android_java_env)->CallNonvirtualObjectMethod (android_java_env,
+                                                           emacs_service,
+                                                           service_class.class,
+                                                           method, uri, id,
+                                                           name);
+
+  if (android_saf_exception_check (3, name, id, uri))
+    return -1;
+
+  /* Delete unused local references.  */
+  ANDROID_DELETE_LOCAL_REF (name);
+  ANDROID_DELETE_LOCAL_REF (id);
+  ANDROID_DELETE_LOCAL_REF (uri);
+
+  if (!new_id)
+    {
+      /* The file couldn't be created for some reason.  */
+      errno = EIO;
+      return -1;
+    }
+
+  /* Now, free VP->document_id and replace it with the service
+     document ID.  */
+
+  new_doc_id = (*android_java_env)->GetStringUTFChars (android_java_env,
+                                                      new_id, NULL);
+
+  if (android_saf_exception_check (3, name, id, uri))
+    return -1;
+
+  xfree (vp->document_id);
+  vp->document_id = xstrdup (new_doc_id);
+
+  (*android_java_env)->ReleaseStringUTFChars (android_java_env,
+                                             new_id, new_doc_id);
+  ANDROID_DELETE_LOCAL_REF (new_id);
+
+  /* Finally, transform this vnode into a directory vnode.  */
+  vp->vnode.type = ANDROID_VNODE_SAF_TREE;
+  vp->vnode.ops = &saf_tree_vfs_ops;
+  return 0;
 }
 
 static struct android_vdir *
@@ -5449,6 +5678,29 @@ android_vfs_init (JNIEnv *env, jobject manager)
   android_init_cursor_class (env);
   android_init_entry_class (env);
   android_init_fd_class (env);
+
+  /* Initialize each of the exception classes used by
+     `android_saf_exception_check'.  */
+
+  old = (*env)->FindClass (env, "java/io/FileNotFoundException");
+  file_not_found_exception = (*env)->NewGlobalRef (env, old);
+  (*env)->DeleteLocalRef (env, old);
+  eassert (file_not_found_exception);
+
+  old = (*env)->FindClass (env, "java/lang/SecurityException");
+  security_exception = (*env)->NewGlobalRef (env, old);
+  (*env)->DeleteLocalRef (env, old);
+  eassert (security_exception);
+
+  old = (*env)->FindClass (env, "java/lang/UnsupportedOperationException");
+  unsupported_operation_exception = (*env)->NewGlobalRef (env, old);
+  (*env)->DeleteLocalRef (env, old);
+  eassert (unsupported_operation_exception);
+
+  old = (*env)->FindClass (env, "java/lang/OutOfMemoryError");
+  out_of_memory_error = (*env)->NewGlobalRef (env, old);
+  (*env)->DeleteLocalRef (env, old);
+  eassert (out_of_memory_error);
 }
 
 /* The replacement functions that follow have several major
@@ -5606,7 +5858,7 @@ android_mkdir (const char *name, mode_t mode)
 
   rc = (*vp->ops->mkdir) (vp, mode);
   (*vp->ops->close) (vp);
-  return rc; 
+  return rc;
 }
 
 /* Rename the vnode designated by SRC to the vnode designated by DST.
@@ -5724,7 +5976,7 @@ android_fstat (int fd, struct stat *statb)
   for (tem = afs_file_descriptors; tem; tem = tem->next)
     {
       if (tem->fd == fd)
-       {         
+       {
          memcpy (statb, &tem->statb, sizeof *statb);
          return 0;
        }



reply via email to

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