Skip to content

Commit

Permalink
Add handling of plus sign (+) in path name
Browse files Browse the repository at this point in the history
With test cases, with test cases to prove TeamAmaze#2964 will work.

Fixes TeamAmaze#3560, fixes TeamAmaze#3636, fixes TeamAmaze#2964
  • Loading branch information
TranceLove committed Jan 22, 2023
1 parent 54024a3 commit f99a1ae
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 34 deletions.
22 changes: 11 additions & 11 deletions app/src/main/java/com/amaze/filemanager/filesystem/HybridFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@ public Long execute(@NonNull SFTPClient client) throws IOException {
*/
public String getPath() {
try {
return URLDecoder.decode(path, "UTF-8");
return URLDecoder.decode(path.replace("+", "%2b"), "UTF-8");
} catch (UnsupportedEncodingException | IllegalArgumentException e) {
LOG.warn("failed to decode path {}", path, e);
return path;
Expand Down Expand Up @@ -549,7 +549,7 @@ public String getParent(Context context) {
String thisPath = path;
if (thisPath.contains("%")) {
try {
thisPath = URLDecoder.decode(path, Charsets.UTF_8.name());
thisPath = URLDecoder.decode(getPath(), Charsets.UTF_8.name());
} catch (UnsupportedEncodingException ignored) {
}
}
Expand Down Expand Up @@ -936,20 +936,20 @@ public void forEachChildrenFile(Context context, boolean isRoot, OnFileFound onF
switch (mode) {
case SFTP:
NetCopyClientUtils.INSTANCE.<SSHClient, Boolean>execute(
new SFtpClientTemplate<Boolean>(path, false) {
new SFtpClientTemplate<Boolean>(getPath(), false) {
@Override
public Boolean execute(@NonNull SFTPClient client) {
try {
for (RemoteResourceInfo info :
client.ls(NetCopyClientUtils.INSTANCE.extractRemotePathFrom(path))) {
client.ls(NetCopyClientUtils.INSTANCE.extractRemotePathFrom(getPath()))) {
boolean isDirectory = false;
try {
isDirectory = SshClientUtils.isDirectory(client, info);
} catch (IOException ifBrokenSymlink) {
LOG.warn("IOException checking isDirectory(): " + info.getPath());
continue;
}
HybridFileParcelable f = new HybridFileParcelable(path, isDirectory, info);
HybridFileParcelable f = new HybridFileParcelable(getPath(), isDirectory, info);
onFileFound.onFileFound(f);
}
} catch (IOException e) {
Expand Down Expand Up @@ -986,18 +986,18 @@ public Boolean execute(@NonNull SFTPClient client) {
}
break;
case FTP:
String thisPath = NetCopyClientUtils.INSTANCE.extractRemotePathFrom(path);
String thisPath = NetCopyClientUtils.INSTANCE.extractRemotePathFrom(getPath());
FTPFile[] ftpFiles =
NetCopyClientUtils.INSTANCE.execute(
new FtpClientTemplate<FTPFile[]>(path, false) {
new FtpClientTemplate<FTPFile[]>(getPath(), false) {
public FTPFile[] executeWithFtpClient(@NonNull FTPClient ftpClient)
throws IOException {
ftpClient.changeWorkingDirectory(thisPath);
return ftpClient.listFiles();
}
});
for (FTPFile ftpFile : ftpFiles) {
onFileFound.onFileFound(new HybridFileParcelable(path, ftpFile));
onFileFound.onFileFound(new HybridFileParcelable(getPath(), ftpFile));
}
break;
case OTG:
Expand Down Expand Up @@ -1085,11 +1085,11 @@ public InputStream getInputStream(Context context) {
case SFTP:
inputStream =
SshClientUtils.execute(
new SFtpClientTemplate<InputStream>(path, false) {
new SFtpClientTemplate<InputStream>(getPath(), false) {
@Override
public InputStream execute(@NonNull final SFTPClient client) throws IOException {
final RemoteFile rf =
client.open(NetCopyClientUtils.INSTANCE.extractRemotePathFrom(path));
client.open(NetCopyClientUtils.INSTANCE.extractRemotePathFrom(getPath()));
return rf.new RemoteFileInputStream() {
@Override
public void close() throws IOException {
Expand All @@ -1115,7 +1115,7 @@ public void close() throws IOException {
case FTP:
inputStream =
NetCopyClientUtils.INSTANCE.execute(
new FtpClientTemplate<InputStream>(path, false) {
new FtpClientTemplate<InputStream>(getPath(), false) {
public InputStream executeWithFtpClient(@NonNull FTPClient ftpClient)
throws IOException {
String parent = getParent(AppConfig.getInstance());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ class FtpServiceAndroidFileSystemIntegrationTest {
Environment.DIRECTORY_DOWNLOADS,
Environment.DIRECTORY_DCIM,
Environment.DIRECTORY_DOCUMENTS,
"1/2/3/4/5/6/7"
"1/2/3/4/5/6/7",
"lost+found"
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,31 +25,32 @@ import androidx.test.core.app.ApplicationProvider
import com.amaze.filemanager.fileoperations.filesystem.OpenMode
import com.amaze.filemanager.filesystem.HybridFile
import com.amaze.filemanager.filesystem.HybridFileParcelable
import com.amaze.filemanager.test.randomBytes
import com.amaze.filemanager.utils.OnFileFound
import org.awaitility.Awaitility.await
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
import java.io.ByteArrayInputStream
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.nio.file.Files
import java.nio.file.Paths

/**
* Test listing files on SSH server.
*/
@Suppress("StringLiteralDuplication")
class ListFilesOnSshdTest : AbstractSftpServerTest() {
class FilesOnSshdTest : AbstractSftpServerTest() {

/**
* Test list directories normally
*/
@Test
fun testNormalListDirs() {
for (s in arrayOf("sysroot", "srv", "var", "tmp", "bin", "lib", "usr")) {
for (s in arrayOf("sysroot", "srv", "var", "tmp", "bin", "lib", "usr", "sysroot+v2")) {
File(Environment.getExternalStorageDirectory(), s).mkdir()
}
assertTrue(performVerify())
Expand All @@ -59,26 +60,48 @@ class ListFilesOnSshdTest : AbstractSftpServerTest() {
* Test list directories and symbolic links
*/
@Test
@Throws(Exception::class)
fun testListDirsAndSymlinks() {
createNecessaryDirsForSymlinkRelatedTests()
assertTrue(performVerify())
}

@Throws(IOException::class)
/**
* Test listing directories and files with special characters. This includes colon signs, which
* is possible - even on Windows. See #2964
*/
@Test
fun testListFilesWithSpecialChars() {
createFilesAndDirectoriesWithSpecialChars()
performVerify2()
}

private fun createNecessaryDirsForSymlinkRelatedTests() {
val sysroot = File(Environment.getExternalStorageDirectory(), "sysroot")
sysroot.mkdir()
for (s in arrayOf("srv", "var", "tmp")) {
val subdir = File(sysroot, s)
subdir.mkdir()
Files.createSymbolicLink(
Paths.get(File(Environment.getExternalStorageDirectory(), s).absolutePath),
Paths.get(subdir.absolutePath)
)
Environment.getExternalStorageDirectory().let { root ->
val sysroot = File(root, "sysroot")
sysroot.mkdir()
for (s in arrayOf("srv", "var", "tmp")) {
val subdir = File(sysroot, s)
subdir.mkdir()
Files.createSymbolicLink(
Paths.get(File(root, s).absolutePath),
Paths.get(subdir.absolutePath)
)
}
for (s in arrayOf("bin", "lib", "usr")) {
File(root, s).mkdir()
}
File(root, "sysroot+v2").mkdirs()
}
for (s in arrayOf("bin", "lib", "usr")) {
File(Environment.getExternalStorageDirectory(), s).mkdir()
}

private fun createFilesAndDirectoriesWithSpecialChars() {
File(Environment.getExternalStorageDirectory(), "sysroot+v2").let {
it.mkdirs()
File(it, "D:").run {
mkdirs()
File(this, "Users").mkdirs()
}
ByteArrayInputStream(randomBytes()).copyTo(FileOutputStream(File(it, "test+file.bin")))
}
}

Expand All @@ -98,10 +121,71 @@ class ListFilesOnSshdTest : AbstractSftpServerTest() {
}
}
)
await().until { result.size == 7 }
await().until { result.size == 8 }
assertThat<List<String>>(
result,
Matchers.hasItems("sysroot", "srv", "var", "tmp", "bin", "lib", "usr", "sysroot+v2")
)
return true
}

private fun performVerify2(): Boolean {
val result: MutableList<String> = ArrayList()
var file = HybridFile(
OpenMode.SFTP,
"ssh://$USERNAME:$encryptedPassword@$HOST:$serverPort/sysroot%2Bv2"
)
file.forEachChildrenFile(
ApplicationProvider.getApplicationContext(),
false,
object : OnFileFound {
override fun onFileFound(fileFound: HybridFileParcelable) {
result.add(fileFound.name)
}
}
)
await().until { result.size == 2 }
assertThat<List<String>>(
result,
Matchers.hasItems("test+file.bin", "D:")
)
result.clear()
file = HybridFile(
OpenMode.SFTP,
"ssh://$USERNAME:$encryptedPassword@$HOST:$serverPort/sysroot%2Bv2/D:"
)
file.forEachChildrenFile(
ApplicationProvider.getApplicationContext(),
false,
object : OnFileFound {
override fun onFileFound(fileFound: HybridFileParcelable) {
result.add(fileFound.name)
}
}
)
await().until { result.size == 1 }
assertThat<List<String>>(
result,
Matchers.hasItems("Users")
)
result.clear()
file = HybridFile(
OpenMode.SFTP,
"ssh://$USERNAME:$encryptedPassword@$HOST:$serverPort/sysroot%2Bv2/D%3A"
)
file.forEachChildrenFile(
ApplicationProvider.getApplicationContext(),
false,
object : OnFileFound {
override fun onFileFound(fileFound: HybridFileParcelable) {
result.add(fileFound.name)
}
}
)
await().until { result.size == 1 }
assertThat<List<String>>(
result,
Matchers.hasItems("sysroot", "srv", "var", "tmp", "bin", "lib", "usr")
Matchers.hasItems("Users")
)
return true
}
Expand Down Expand Up @@ -153,10 +237,10 @@ class ListFilesOnSshdTest : AbstractSftpServerTest() {
}
}
)
await().until { dirs.size == 7 }
await().until { dirs.size == 8 }
assertThat<List<String>>(
dirs,
Matchers.hasItems("sysroot", "srv", "var", "tmp", "bin", "lib", "usr")
Matchers.hasItems("sysroot", "srv", "var", "tmp", "bin", "lib", "usr", "sysroot+v2")
)
assertThat<List<String>>(
files,
Expand Down Expand Up @@ -236,10 +320,10 @@ class ListFilesOnSshdTest : AbstractSftpServerTest() {
}
}
)
await().until { result2.size == 7 }
await().until { result2.size == 8 }
assertThat<List<String>>(
result2,
Matchers.hasItems("sysroot", "srv", "var", "tmp", "bin", "lib", "usr")
Matchers.hasItems("sysroot", "srv", "var", "tmp", "bin", "lib", "usr", "sysroot+v2")
)
}
}

0 comments on commit f99a1ae

Please sign in to comment.