| // Copyright 2013 The Chromium Authors | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "base/android/content_uri_utils.h" | 
 |  | 
 | #include <sys/stat.h> | 
 |  | 
 | #include "base/android/jni_android.h" | 
 | #include "base/android/jni_array.h" | 
 | #include "base/android/jni_string.h" | 
 | #include "base/files/file.h" | 
 | #include "base/logging.h" | 
 | #include "base/time/time.h" | 
 |  | 
 | // Must come after all headers that specialize FromJniType() / ToJniType(). | 
 | #include "base/content_uri_utils_jni/ContentUriUtils_jni.h" | 
 |  | 
 | using base::android::ConvertUTF8ToJavaString; | 
 | using base::android::JavaParamRef; | 
 | using base::android::JavaRef; | 
 | using base::android::ScopedJavaLocalRef; | 
 |  | 
 | namespace base { | 
 |  | 
 | namespace internal { | 
 |  | 
 | bool ContentUriExists(const FilePath& content_uri) { | 
 |   JNIEnv* env = android::AttachCurrentThread(); | 
 |   return Java_ContentUriUtils_contentUriExists(env, content_uri.value()); | 
 | } | 
 |  | 
 | std::optional<std::string> TranslateOpenFlagsToJavaMode(uint32_t open_flags) { | 
 |   // The allowable modes from ParcelFileDescriptor#parseMode() are | 
 |   // ("r", "w", "wt", "wa", "rw", "rwt"), we disallow "w" which has been the | 
 |   // source of android security issues. | 
 |  | 
 |   // Ignore async. | 
 |   open_flags &= ~File::FLAG_ASYNC; | 
 |  | 
 |   switch (open_flags) { | 
 |     case File::FLAG_OPEN | File::FLAG_READ: | 
 |     case File::FLAG_OPEN_ALWAYS | File::FLAG_READ: | 
 |     case File::FLAG_CREATE | File::FLAG_READ: | 
 |       return "r"; | 
 |     case File::FLAG_OPEN_ALWAYS | File::FLAG_READ | File::FLAG_WRITE: | 
 |       return "rw"; | 
 |     case File::FLAG_OPEN_ALWAYS | File::FLAG_APPEND: | 
 |       return "wa"; | 
 |     case File::FLAG_CREATE_ALWAYS | File::FLAG_READ | File::FLAG_WRITE: | 
 |       return "rwt"; | 
 |     case File::FLAG_CREATE_ALWAYS | File::FLAG_WRITE: | 
 |       return "wt"; | 
 |     default: | 
 |       return std::nullopt; | 
 |   } | 
 | } | 
 |  | 
 | ScopedJavaLocalRef<jobject> OpenContentUri(const FilePath& content_uri, | 
 |                                            uint32_t open_flags) { | 
 |   JNIEnv* env = android::AttachCurrentThread(); | 
 |   auto mode = TranslateOpenFlagsToJavaMode(open_flags); | 
 |   CHECK(mode.has_value()) << "Unsupported flags=0x" << std::hex << open_flags; | 
 |   return Java_ContentUriUtils_openContentUri(env, content_uri.value(), *mode); | 
 | } | 
 |  | 
 | int ContentUriGetFd(const JavaRef<jobject>& java_parcel_file_descriptor) { | 
 |   if (!java_parcel_file_descriptor) { | 
 |     return -1; | 
 |   } | 
 |   JNIEnv* env = android::AttachCurrentThread(); | 
 |   int fd = Java_ContentUriUtils_getFd(env, java_parcel_file_descriptor); | 
 |   return dup(fd); | 
 | } | 
 |  | 
 | void ContentUriClose(const JavaRef<jobject>& java_parcel_file_descriptor) { | 
 |   JNIEnv* env = android::AttachCurrentThread(); | 
 |   Java_ContentUriUtils_close(env, java_parcel_file_descriptor); | 
 | } | 
 |  | 
 | bool ContentUriGetFileInfo(const FilePath& content_uri, | 
 |                            FileEnumerator::FileInfo* info) { | 
 |   JNIEnv* env = android::AttachCurrentThread(); | 
 |   std::vector<FileEnumerator::FileInfo> list; | 
 |   Java_ContentUriUtils_getFileInfo(env, content_uri.value(), | 
 |                                    reinterpret_cast<jlong>(&list)); | 
 |   // Java will call back sync to AddFileInfoToVector(&list). | 
 |   if (list.empty()) { | 
 |     return false; | 
 |   } | 
 |   // Android can return -1 for unknown size, which | 
 |   // we can't deal with, so we will consider that the file wasn't found. | 
 |   if (list[0].GetSize() < 0) { | 
 |     LOG(ERROR) << "Unknown file length for " << content_uri; | 
 |     return false; | 
 |   } | 
 |   *info = std::move(list[0]); | 
 |   return true; | 
 | } | 
 |  | 
 | std::vector<FileEnumerator::FileInfo> ListContentUriDirectory( | 
 |     const FilePath& content_uri, | 
 |     int file_type) { | 
 |   JNIEnv* env = android::AttachCurrentThread(); | 
 |   std::vector<FileEnumerator::FileInfo> result; | 
 |   Java_ContentUriUtils_listDirectory(env, content_uri.value(), file_type, | 
 |                                      reinterpret_cast<jlong>(&result)); | 
 |   // Java will call back sync to AddFileInfoToVector(&result). | 
 |   return result; | 
 | } | 
 |  | 
 | bool DeleteContentUri(const FilePath& content_uri) { | 
 |   DCHECK(content_uri.IsContentUri()); | 
 |   JNIEnv* env = android::AttachCurrentThread(); | 
 |   return Java_ContentUriUtils_delete(env, content_uri.value()); | 
 | } | 
 |  | 
 | bool IsDocumentUri(const FilePath& content_uri) { | 
 |   DCHECK(content_uri.IsContentUri()); | 
 |   JNIEnv* env = android::AttachCurrentThread(); | 
 |   return Java_ContentUriUtils_isDocumentUri(env, content_uri.value()); | 
 | } | 
 |  | 
 | }  // namespace internal | 
 |  | 
 | void JNI_ContentUriUtils_AddFileInfoToVector(JNIEnv* env, | 
 |                                              jlong vector_pointer, | 
 |                                              std::string& uri, | 
 |                                              std::string& display_name, | 
 |                                              jboolean is_directory, | 
 |                                              jlong size, | 
 |                                              jlong last_modified) { | 
 |   auto* result = | 
 |       reinterpret_cast<std::vector<FileEnumerator::FileInfo>*>(vector_pointer); | 
 |   result->emplace_back(FilePath(uri), FilePath(display_name), is_directory, | 
 |                        size, | 
 |                        Time::FromMillisecondsSinceUnixEpoch(last_modified)); | 
 | } | 
 |  | 
 | std::string GetContentUriMimeType(const FilePath& content_uri) { | 
 |   JNIEnv* env = android::AttachCurrentThread(); | 
 |   return Java_ContentUriUtils_getMimeType(env, content_uri.value()); | 
 | } | 
 |  | 
 | bool MaybeGetFileDisplayName(const FilePath& content_uri, | 
 |                              std::u16string* file_display_name) { | 
 |   if (!content_uri.IsContentUri()) { | 
 |     return false; | 
 |   } | 
 |  | 
 |   DCHECK(file_display_name); | 
 |  | 
 |   JNIEnv* env = android::AttachCurrentThread(); | 
 |   ScopedJavaLocalRef<jstring> j_display_name = | 
 |       Java_ContentUriUtils_maybeGetDisplayName(env, content_uri.value()); | 
 |  | 
 |   if (j_display_name.is_null()) { | 
 |     return false; | 
 |   } | 
 |  | 
 |   *file_display_name = android::ConvertJavaStringToUTF16(j_display_name); | 
 |   return true; | 
 | } | 
 |  | 
 | FilePath ContentUriBuildDocumentUriUsingTree( | 
 |     const FilePath& tree_uri, | 
 |     const std::string& encoded_document_id) { | 
 |   JNIEnv* env = android::AttachCurrentThread(); | 
 |   std::string j_uri = Java_ContentUriUtils_buildDocumentUriUsingTree( | 
 |       env, tree_uri.value(), encoded_document_id); | 
 |   return FilePath(j_uri); | 
 | } | 
 |  | 
 | FilePath ContentUriGetChildDocumentOrQuery(const FilePath& parent, | 
 |                                            const std::string& display_name, | 
 |                                            const std::string& mime_type, | 
 |                                            bool is_directory, | 
 |                                            bool create) { | 
 |   JNIEnv* env = android::AttachCurrentThread(); | 
 |   std::string j_uri = Java_ContentUriUtils_getChildDocumentOrQuery( | 
 |       env, parent.value(), display_name, mime_type, is_directory, create); | 
 |   return FilePath(j_uri); | 
 | } | 
 |  | 
 | bool ContentUriIsCreateChildDocumentQuery(const FilePath& content_uri) { | 
 |   JNIEnv* env = android::AttachCurrentThread(); | 
 |   return Java_ContentUriUtils_isCreateChildDocumentQuery(env, | 
 |                                                          content_uri.value()); | 
 | } | 
 |  | 
 | FilePath ContentUriGetDocumentFromQuery(const FilePath& content_uri, | 
 |                                         bool create) { | 
 |   JNIEnv* env = android::AttachCurrentThread(); | 
 |   std::string j_uri = Java_ContentUriUtils_getDocumentFromQuery( | 
 |       env, content_uri.value(), create); | 
 |   return FilePath(j_uri); | 
 | } | 
 |  | 
 | }  // namespace base |