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 }