File indexing completed on 2024-12-22 04:41:40
0001 /* 0002 * SPDX-FileCopyrightText: 2018 Erik Duisters <e.duisters1@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 0007 package org.kde.kdeconnect.Plugins.SftpPlugin; 0008 0009 import android.content.Context; 0010 import android.net.Uri; 0011 import android.provider.DocumentsContract; 0012 0013 import org.apache.sshd.common.file.FileSystemView; 0014 import org.apache.sshd.common.file.SshFile; 0015 import org.apache.sshd.common.file.nativefs.NativeSshFile; 0016 0017 import java.io.File; 0018 import java.util.ArrayList; 0019 import java.util.List; 0020 import java.util.Map; 0021 0022 public class AndroidSafFileSystemView implements FileSystemView { 0023 final String userName; 0024 final Context context; 0025 private final Map<String, String> roots; 0026 private final RootFile rootFile; 0027 0028 AndroidSafFileSystemView(Map<String, String> roots, String userName, Context context) { 0029 this.roots = roots; 0030 this.userName = userName; 0031 this.context = context; 0032 this.rootFile = new RootFile( createFileList(), userName, true); 0033 } 0034 0035 private List<SshFile> createFileList() { 0036 List<SshFile> list = new ArrayList<>(); 0037 for (Map.Entry<String, String> entry : roots.entrySet()) { 0038 String displayName = entry.getKey(); 0039 String uri = entry.getValue(); 0040 0041 Uri treeUri = Uri.parse(uri); 0042 Uri documentUri = DocumentsContract.buildDocumentUriUsingTree(treeUri, DocumentsContract.getTreeDocumentId(treeUri)); 0043 list.add(createAndroidSafSshFile(null, documentUri, File.separatorChar + displayName)); 0044 } 0045 0046 return list; 0047 } 0048 0049 @Override 0050 public SshFile getFile(String file) { 0051 return getFile("/", file); 0052 } 0053 0054 @Override 0055 public SshFile getFile(SshFile baseDir, String file) { 0056 return getFile(baseDir.getAbsolutePath(), file); 0057 } 0058 0059 protected SshFile getFile(String dir, String file) { 0060 if (!dir.endsWith("/")) { 0061 dir = dir + "/"; 0062 } 0063 0064 if (!file.startsWith("/")) { 0065 file = dir + file; 0066 } 0067 0068 String filename = NativeSshFile.getPhysicalName("/", "/", file, false); 0069 0070 if (filename.equals("/")) { 0071 return rootFile; 0072 } 0073 0074 for (String root : roots.keySet()) { 0075 if (filename.indexOf(root) == 1) { 0076 String nameWithoutRoot = filename.substring(root.length() + 1); 0077 String pathOrUri = roots.get(root); 0078 0079 Uri treeUri = Uri.parse(pathOrUri); 0080 if (nameWithoutRoot.isEmpty()) { 0081 //TreeDocument 0082 Uri documentUri = DocumentsContract.buildDocumentUriUsingTree(treeUri, DocumentsContract.getTreeDocumentId(treeUri)); 0083 0084 return createAndroidSafSshFile(documentUri, documentUri, filename); 0085 } else { 0086 /* 0087 When sharing a root document tree like "Internal Storage" documentUri looks like: 0088 content://com.android.externalstorage.documents/tree/primary:/document/primary: 0089 For a file or folder beneath that the uri looks like: 0090 content://com.android.externalstorage.documents/tree/primary:/document/primary:Folder/file.txt 0091 0092 Sharing a non root document tree the documentUri looks like: 0093 content://com.android.externalstorage.documents/tree/primary:Download/document/primary:Download 0094 For a file or folder beneath that the uri looks like: 0095 content://com.android.externalstorage.documents/tree/primary:Download/document/primary:Download/Folder/file.txt 0096 */ 0097 String treeDocumentId = DocumentsContract.getTreeDocumentId(treeUri); 0098 File nameWithoutRootFile = new File(nameWithoutRoot); 0099 String parentSuffix = nameWithoutRootFile.getParent(); 0100 String parentDocumentId = treeDocumentId + ("/".equals(parentSuffix) ? "" : parentSuffix); 0101 0102 Uri parentUri = DocumentsContract.buildDocumentUriUsingTree(treeUri, parentDocumentId); 0103 0104 String documentId = treeDocumentId + (treeDocumentId.endsWith(":") ? nameWithoutRoot.substring(1) : nameWithoutRoot); 0105 Uri documentUri = DocumentsContract.buildDocumentUriUsingTree(treeUri, documentId); 0106 0107 return createAndroidSafSshFile(parentUri, documentUri, filename); 0108 } 0109 } 0110 } 0111 0112 //It's a file under / but not one covered by any Tree 0113 return new RootFile(new ArrayList<>(0), userName, false); 0114 } 0115 0116 public AndroidSafSshFile createAndroidSafSshFile(Uri parentUri, Uri documentUri, String virtualFilename) { 0117 return new AndroidSafSshFile(this, parentUri, documentUri, virtualFilename); 0118 } 0119 0120 @Override 0121 public FileSystemView getNormalizedView() { 0122 return this; 0123 } 0124 }