Skip to content

Commit

Permalink
fixed handling of relative paths when switching working dir for FTP, …
Browse files Browse the repository at this point in the history
…I see myself forced to implement handling for specific clients by introducing a flag to configure code to be run under test, see GH issue #293
  • Loading branch information
wolpi committed Dec 10, 2023
1 parent 983e65c commit 3fbe55a
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 49 deletions.
21 changes: 15 additions & 6 deletions primitiveFTPd/src/org/primftpd/filesystem/FsFtpFileSystemView.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,28 @@ public boolean changeWorkingDirectory(String dir) {
logger.trace("changeWorkingDirectory({})", dir);

File dirObj = new File(dir);
String currentAbsPath = workingDir.getAbsolutePath();
String path = dir;
String currentAbsPath = workingDir.getAbsolutePath();
if (!dirObj.isAbsolute()) {
// curl ignores current WD and tries to switch to WD from root dir by dir
File topLevelDir = new File("/" + dir);
if (topLevelDir.exists()) {
path = topLevelDir.getAbsolutePath();
if ("..".equals(path)) {
path = new File(currentAbsPath).getParent();
if (path == null) {
path = File.separator;
}
} else if (Utils.RUN_TESTS) {
// curl ignores current WD and tries to switch to WD from root dir by dir
File topLevelDir = new File(File.separator + dir);
if (topLevelDir.exists()) {
path = topLevelDir.getAbsolutePath();
} else {
path = currentAbsPath + File.separator + dir;
}
} else {
path = currentAbsPath + File.separator + dir;
}
}
logger.trace("using path for cwd operation: {}", path);
dirObj = new File(path);
logger.trace("using path for cwd operation: {}", path);

// check if new path is a dir
if (!dirObj.isDirectory()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,22 @@ public boolean changeWorkingDirectory(String dir) {
RootFtpFile newWorkingDir;
File fileObj = new File(dir);
if (!fileObj.isAbsolute()) {
// curl ignores current WD and tries to switch to WD from root dir by dir
File topLevelDir = new File("/" + dir);
if (topLevelDir.exists()) {
newPath = topLevelDir.getAbsolutePath();
if ("..".equals(dir)) {
newPath = new File(workingDir.getAbsolutePath()).getParent();
if (newPath == null) {
newPath = "/";
}
} else if (Utils.RUN_TESTS) {
// curl ignores current WD and tries to switch to WD from root dir by dir
File topLevelDir = new File("/" + dir);
if (topLevelDir.exists()) {
newPath = topLevelDir.getAbsolutePath();
} else {
newPath = workingDir.getAbsolutePath() + File.separator + dir;
logger.trace(" using path for cwd operation: {}", newPath);
}
} else {
newPath = workingDir.getAbsolutePath() + File.separator + dir;
logger.trace(" using path for cwd operation: {}", newPath);
}
} else {
newPath = dir;
Expand Down
4 changes: 3 additions & 1 deletion primitiveFTPd/src/org/primftpd/filesystem/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import java.util.List;
import java.util.SimpleTimeZone;

class Utils {
public class Utils {

static String absolute(String rel, String workingDir) {
if (rel.charAt(0) == '/') {
Expand Down Expand Up @@ -73,4 +73,6 @@ static String parent(String path) {
static String touchDate(long time) {
return TOUCH_DATE_FORMAT.format(time);
}

public static final boolean RUN_TESTS = false;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;

import org.primftpd.filesystem.Utils;
import org.primftpd.prefs.StorageType;
import org.primftpd.util.NotificationUtil;
import org.primftpd.util.ServicesStartStopUtil;
Expand Down Expand Up @@ -170,7 +171,11 @@ private synchronized void shellOpen() {
if (shell == null) {
logger.debug("opening root shell ({})", logName);
// TODO test .setShell()
shell = (new Shell.Builder()).useSU().open();
Shell.Builder builder = new Shell.Builder();
if (!Utils.RUN_TESTS) {
builder.useSU();
}
shell = builder.open();
} else {
logger.debug("root shell already open ({})", logName);
}
Expand Down
73 changes: 37 additions & 36 deletions tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ def checkEmpty(errors, text, msgPrefix):
if len(text) > 0:
errors.append(msgPrefix + " not empty")

def checkHomeListing(errors, text, msgPrefix, newDirPresent = False, dirRenamed = False):
def checkHomeListing(errors, text, msgPrefix, storageType, newDirPresent = False, dirRenamed = False):
log("checking home listing\n" + text)
msg = msgPrefix + " missing dir in home: "
msgPresent = msgPrefix + " present dir in home: "
Expand All @@ -169,7 +169,8 @@ def checkHomeListing(errors, text, msgPrefix, newDirPresent = False, dirRenamed
else:
checkNot(NEW_DIR, text, errors, msgPresent)
checkNot(NEW_DIR_RENAMED, text, errors, msgPresent)
checkNot(SUB_DIR, text, errors, msgPresent)
if not (storageType == STORAGE_TYPE_SAF or storageType == STORAGE_TYPE_SAFRO or storageType == STORAGE_TYPE_VIRTUAL):
checkNot(SUB_DIR, text, errors, msgPresent)

def checkListingLevel1(errors, text, msgPrefix, subDirPresent = True, subDirRenamed = False):
log("checking listing (level 1)\n" + text)
Expand Down Expand Up @@ -327,20 +328,20 @@ def downloadScp(remotePath, tmpPath):
return runCommand(cmd)


def testCycle(baseUrl, remoteBasePath, errorTag, errors, protocol):
def testCycle(baseUrl, remoteBasePath, errorTag, errors, protocol, storageType):
setupTmpDir()

# check listing of home dir
output = downloadListing(baseUrl + remoteBasePath, protocol)
checkHomeListing(errors, output, errorTag)
checkHomeListing(errors, output, errorTag, storageType)
# if we have errors that early it is not worth continuing
if len(errors) > 0:
print("abort due to errors\n")
return

# create dir
output = createDir(baseUrl, remoteBasePath, NEW_DIR, protocol)
checkHomeListing(errors, output, errorTag, newDirPresent = True)
checkHomeListing(errors, output, errorTag, storageType, newDirPresent = True)

# create sub-dir
createSubDir(baseUrl, remoteBasePath, [NEW_DIR, SUB_DIR], protocol)
Expand Down Expand Up @@ -374,7 +375,7 @@ def testCycle(baseUrl, remoteBasePath, errorTag, errors, protocol):
# rename dir
rename(baseUrl, remoteBasePath, [], NEW_DIR, NEW_DIR_RENAMED, protocol)
output = downloadListing(baseUrl + remoteBasePath, protocol)
checkHomeListing(errors, output, errorTag, newDirPresent = True, dirRenamed = True)
checkHomeListing(errors, output, errorTag, storageType, newDirPresent = True, dirRenamed = True)
url = baseUrl + remoteBasePath + NEW_DIR_RENAMED + "/" + SUB_DIR_RENAMED + "/"

# delete file
Expand All @@ -389,15 +390,15 @@ def testCycle(baseUrl, remoteBasePath, errorTag, errors, protocol):

# delete dir
output = removeDir(baseUrl, remoteBasePath, NEW_DIR_RENAMED, protocol)
checkHomeListing(errors, output, errorTag)
checkHomeListing(errors, output, errorTag, storageType)


def testCycleReadOnly(baseUrl, remoteBasePath, errorTag, errors, protocol):
def testCycleReadOnly(baseUrl, remoteBasePath, errorTag, errors, protocol, storageType):
setupTmpDir()

# check listing of home dir
output = downloadListing(baseUrl + remoteBasePath, protocol)
checkHomeListing(errors, output, errorTag)
checkHomeListing(errors, output, errorTag, storageType)
# if we have errors that early it is not worth continuing
if len(errors) > 0:
return
Expand Down Expand Up @@ -443,21 +444,21 @@ def scpDownload(remoteBasePath, errorTag, errors):
def testKeys(baseUrl, errors):
protocol = Protocol.SFTP
output = downloadListing(baseUrl, protocol, key = KEY_PATH_DSA)
checkHomeListing(errors, output, "[key dsa]")
checkHomeListing(errors, output, "[key dsa]", storageType)
output = downloadListing(baseUrl, protocol, key = KEY_PATH_RSA)
checkHomeListing(errors, output, "[key rsa]")
checkHomeListing(errors, output, "[key rsa]", storageType)
output = downloadListing(baseUrl, protocol, key = KEY_PATH_ECDSA)
checkHomeListing(errors, output, "[key ecdsa]")
checkHomeListing(errors, output, "[key ecdsa]", storageType)
output = downloadListing(baseUrl, protocol, key = KEY_PATH_ECDSA_384)
checkHomeListing(errors, output, "[key ecdsa 384]")
checkHomeListing(errors, output, "[key ecdsa 384]", storageType)
# check bad keys
output = downloadListing(baseUrl, protocol, key = KEY_PATH_RSA_BAD, check = False)
checkEmpty(errors, output, "[key bad rsa]")
output = downloadListing(baseUrl, protocol, key = KEY_PATH_ED25519_BAD, check = False)
checkEmpty(errors, output, "[key bad ed25519]")
# check username & password for sftp
output = downloadListingSftpPassword(baseUrl)
checkHomeListing(errors, output, "[sftp password]")
checkHomeListing(errors, output, "[sftp password]", storageType)


############################################################################
Expand Down Expand Up @@ -485,22 +486,22 @@ def testKeys(baseUrl, errors):
errors = []
if storageType == STORAGE_TYPE_FS:
if readOnly:
testCycleReadOnly(BASE_URL_SFTP, DEFAULT_PATH_FS, "[fs sftp]", errors, Protocol.SFTP)
testCycleReadOnly(BASE_URL_FTP, DEFAULT_PATH_FS, "[fs ftp]", errors, Protocol.FTP)
testCycleReadOnly(BASE_URL_SFTP, DEFAULT_PATH_FS, "[fs sftp]", errors, Protocol.SFTP, storageType)
testCycleReadOnly(BASE_URL_FTP, DEFAULT_PATH_FS, "[fs ftp]", errors, Protocol.FTP, storageType)
else:
testCycle(BASE_URL_SFTP, DEFAULT_PATH_FS, "[fs sftp]", errors, Protocol.SFTP)
testCycle(BASE_URL_FTP, DEFAULT_PATH_FS, "[fs ftp]", errors, Protocol.FTP)
testCycle(BASE_URL_SFTP, DEFAULT_PATH_FS, "[fs sftp]", errors, Protocol.SFTP, storageType)
testCycle(BASE_URL_FTP, DEFAULT_PATH_FS, "[fs ftp]", errors, Protocol.FTP, storageType)
scpUpload(BASE_URL_SFTP, DEFAULT_PATH_FS, "[fs scp]", errors)
scpDownload(DEFAULT_PATH_FS, "[fs scp]", errors)
testKeys(BASE_URL_SFTP + DEFAULT_PATH_FS, errors)

if storageType == STORAGE_TYPE_ROOT:
if readOnly:
testCycleReadOnly(BASE_URL_SFTP, DEFAULT_PATH_ROOT, "[root sftp]", errors, Protocol.SFTP)
testCycleReadOnly(BASE_URL_FTP, DEFAULT_PATH_ROOT, "[root ftp]", errors, Protocol.FTP)
testCycleReadOnly(BASE_URL_SFTP, DEFAULT_PATH_ROOT, "[root sftp]", errors, Protocol.SFTP, storageType)
testCycleReadOnly(BASE_URL_FTP, DEFAULT_PATH_ROOT, "[root ftp]", errors, Protocol.FTP, storageType)
else:
testCycle(BASE_URL_SFTP, DEFAULT_PATH_ROOT, "[root sftp]", errors, Protocol.SFTP)
testCycle(BASE_URL_FTP, DEFAULT_PATH_ROOT, "[root ftp]", errors, Protocol.FTP)
testCycle(BASE_URL_SFTP, DEFAULT_PATH_ROOT, "[root sftp]", errors, Protocol.SFTP, storageType)
testCycle(BASE_URL_FTP, DEFAULT_PATH_ROOT, "[root ftp]", errors, Protocol.FTP, storageType)
# note: scp upload with root causes known error: filesize is 0
scpUpload(BASE_URL_SFTP, DEFAULT_PATH_ROOT, "[root scp]", errors)
# scp download with root causes EOFException in ScpHelper.readAck, even with copy-to-tmp
Expand All @@ -509,28 +510,28 @@ def testKeys(baseUrl, errors):

if storageType == STORAGE_TYPE_SAF:
if readOnly:
testCycleReadOnly(BASE_URL_SFTP, DEFAULT_PATH_SAF, "[SAF sftp]", errors, Protocol.SFTP)
testCycleReadOnly(BASE_URL_FTP, DEFAULT_PATH_SAF, "[SAF ftp]", errors, Protocol.FTP)
testCycleReadOnly(BASE_URL_SFTP, DEFAULT_PATH_SAF, "[SAF sftp]", errors, Protocol.SFTP, storageType)
testCycleReadOnly(BASE_URL_FTP, DEFAULT_PATH_SAF, "[SAF ftp]", errors, Protocol.FTP, storageType)
else:
testCycle(BASE_URL_SFTP, DEFAULT_PATH_SAF, "[SAF sftp]", errors, Protocol.SFTP)
testCycle(BASE_URL_FTP, DEFAULT_PATH_SAF, "[SAF ftp]", errors, Protocol.FTP)
testCycle(BASE_URL_SFTP, DEFAULT_PATH_SAF, "[SAF sftp]", errors, Protocol.SFTP, storageType)
testCycle(BASE_URL_FTP, DEFAULT_PATH_SAF, "[SAF ftp]", errors, Protocol.FTP, storageType)
scpUpload(BASE_URL_SFTP, DEFAULT_PATH_SAF, "[SAF scp]", errors)
scpDownload(DEFAULT_PATH_SAF, "[SAF scp]", errors)
testKeys(BASE_URL_SFTP + DEFAULT_PATH_SAF, errors)

if storageType == STORAGE_TYPE_SAFRO:
testCycleReadOnly(BASE_URL_SFTP, DEFAULT_PATH_ROSAF, "[SAFRO sftp]", errors, Protocol.SFTP)
testCycleReadOnly(BASE_URL_FTP, DEFAULT_PATH_ROSAF, "[SAFRO ftp]", errors, Protocol.FTP)
testCycleReadOnly(BASE_URL_SFTP, DEFAULT_PATH_ROSAF, "[SAFRO sftp]", errors, Protocol.SFTP, storageType)
testCycleReadOnly(BASE_URL_FTP, DEFAULT_PATH_ROSAF, "[SAFRO ftp]", errors, Protocol.FTP, storageType)
scpDownload(DEFAULT_PATH_ROSAF, "[SAFRO scp]", errors)
testKeys(BASE_URL_SFTP + DEFAULT_PATH_ROSAF, errors)

if storageType == STORAGE_TYPE_VIRTUAL:
try:
testCycleReadOnly(BASE_URL_SFTP, DEFAULT_PATH_VIRTUAL_FS, "[virtual fs sftp]", errors, Protocol.SFTP)
testCycleReadOnly(BASE_URL_SFTP, DEFAULT_PATH_VIRTUAL_FS, "[virtual fs sftp]", errors, Protocol.SFTP, storageType)
except:
errors.append("error in fs sftp")
# no tests vor virtual FS with FTP because of issues with change-dir with curl
#testCycleReadOnly(BASE_URL_FTP, DEFAULT_PATH_VIRTUAL_FS, "[virtual fs ftp]", errors, Protocol.FTP)
#testCycleReadOnly(BASE_URL_FTP, DEFAULT_PATH_VIRTUAL_FS, "[virtual fs ftp]", errors, Protocol.FTP, storageType)
# same curl issue prevents creation of dirs -> read only tests, no scp upload
#scpUpload(BASE_URL_SFTP, DEFAULT_PATH_VIRTUAL_FS, "[virtual fs scp]", errors)
try:
Expand All @@ -539,26 +540,26 @@ def testKeys(baseUrl, errors):
errors.append("error in fs scp")

try:
testCycleReadOnly(BASE_URL_SFTP, DEFAULT_PATH_VIRTUAL_ROOT, "[virtual root sftp]", errors, Protocol.SFTP)
testCycleReadOnly(BASE_URL_SFTP, DEFAULT_PATH_VIRTUAL_ROOT, "[virtual root sftp]", errors, Protocol.SFTP, storageType)
except:
errors.append("error in root sftp")
try:
testCycleReadOnly(BASE_URL_FTP, DEFAULT_PATH_VIRTUAL_ROOT, "[virtual root ftp]", errors, Protocol.FTP)
testCycleReadOnly(BASE_URL_FTP, DEFAULT_PATH_VIRTUAL_ROOT, "[virtual root ftp]", errors, Protocol.FTP, storageType)
except:
errors.append("error in root ftp")
# no scp for root, see above
#scpUpload(BASE_URL_SFTP, DEFAULT_PATH_VIRTUAL_ROOT, "[virtual root scp]", errors)
#scpDownload(DEFAULT_PATH_VIRTUAL_ROOT, "[virtual root scp]", errors)

testCycleReadOnly(BASE_URL_SFTP, DEFAULT_PATH_VIRTUAL_SAF, "[virtual saf sftp]", errors, Protocol.SFTP)
testCycleReadOnly(BASE_URL_FTP, DEFAULT_PATH_VIRTUAL_SAF, "[virtual saf ftp]", errors, Protocol.FTP)
testCycleReadOnly(BASE_URL_SFTP, DEFAULT_PATH_VIRTUAL_SAF, "[virtual saf sftp]", errors, Protocol.SFTP, storageType)
testCycleReadOnly(BASE_URL_FTP, DEFAULT_PATH_VIRTUAL_SAF, "[virtual saf ftp]", errors, Protocol.FTP, storageType)
# no scp upload for virtual with curl, see above
#scpUpload(BASE_URL_SFTP, DEFAULT_PATH_VIRTUAL_SAF, "[virtual saf scp]", errors)
scpDownload(DEFAULT_PATH_VIRTUAL_SAF, "[virtual saf scp]", errors)

# no RoSAF due to issues with SAF-API
#testCycleReadOnly(BASE_URL_SFTP, DEFAULT_PATH_VIRTUAL_ROSAF, "[virtual SAFRO sftp]", errors, Protocol.SFTP)
#testCycleReadOnly(BASE_URL__FTP, DEFAULT_PATH_VIRTUAL_ROSAF, "[virtual SAFRO ftp]", errors, Protocol.FTP)
#testCycleReadOnly(BASE_URL_SFTP, DEFAULT_PATH_VIRTUAL_ROSAF, "[virtual SAFRO sftp]", errors, Protocol.SFTP, storageType)
#testCycleReadOnly(BASE_URL__FTP, DEFAULT_PATH_VIRTUAL_ROSAF, "[virtual SAFRO ftp]", errors, Protocol.FTP, storageType)
#scpDownload(DEFAULT_PATH_VIRTUAL_ROSAF, "[virtual SAFRO scp]", errors)

testKeys(BASE_URL_SFTP + DEFAULT_PATH_VIRTUAL_FS, errors)
Expand Down

0 comments on commit 3fbe55a

Please sign in to comment.