Android Question FTPServer example not working with DirInternal

thoward

Member
Licensed User
Longtime User
I downloaded the B4A FTP Server library and example from here: https://www.b4x.com/android/forum/t...mplemented-with-socket-and-asyncstreams.74320
When I ran it as-is, it worked exactly as expected. I can use WinSCP or Windows explorer on my PC to transfer files to/from my phone.

However, when I change the BaseDir to File.DirInternal, I cannot even connect with an FTP client anymore. I've gone back and forth several times to make sure I'm not imagining things.

Is there something I'm missing? You can use DirInternal for the FTP server, can't you?

Thanks in advance for any help!

Tim
 

JohnC

Expert
Licensed User
Longtime User
Are there any errors listed in the right-hand log list of the IDE?
 
Upvote 0

edgar_ortiz

Active Member
Licensed User
Longtime User
Use File.DirDefaultExternal

You can check:
 
Upvote 0

thoward

Member
Licensed User
Longtime User
Use File.DirDefaultExternal

You can check:
Nope. My app's files are in DirInternal. That's where I need them to be. I also need the FTP Server to use DirInternal, so I can transfer the files to a PC.
 
Upvote 0

JohnC

Expert
Licensed User
Longtime User
If for some reason FTP is not compatible with DirInternal, couldn't you use rp.GetSafeDirDefaultExternal("") and just manage your files in that directory (and copy them from DirInternal) as a worse case scenario?
 
Upvote 0

thoward

Member
Licensed User
Longtime User
If for some reason FTP is not compatible with DirInternal, couldn't you use rp.GetSafeDirDefaultExternal("") and just manage your files in that directory (and copy them from DirInternal) as a worse case scenario?
For security reasons, I have to avoid placing the files into any folder that is accessible by another app. Would GetSafeDirDefaultExternal provide that?
 
Upvote 0

thoward

Member
Licensed User
Longtime User
After rebooting both my phone and the PC, I can connect to the FTPServer example using DirInternal. However, I am unable to change directories or transfer files either direction from DirInternal.

Here is the log from connecting and changing directories using DirRootExternal, which is what is included in the sample. I was also able to transfer files just fine.

--------- beginning of main
Copying updated assets files (1)
*** Service (starter) Create ***
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
** Activity (main) Pause, UserClosed = false **
sending message to waiting queue (activity_permissionresult)
running waiting messages (1)
** Activity (main) Resume **
client: USER Test
client: PASS test
User logged in: Test
client: SYST
client: FEAT
client: OPTS UTF8 ON
client: PWD
client: CWD /DCIM/Camera
CurrentPath: /DCIM/Camera
client: PWD
client: TYPE A
client: PASV
client: LIST -a
Data connection terminated: /DCIM/Camera
DataConnection_Close
client: CWD /DCIM
CurrentPath: /DCIM
client: PWD
client: TYPE A
client: PASV
DataConnection_Close
client: LIST -a
Data connection terminated: /DCIM
DataConnection_Close
client: CWD /
CurrentPath: /
client: PWD
client: TYPE A
client: PASV
DataConnection_Close
client: LIST -a
Data connection terminated: /
DataConnection_Close
client: PWD
client: PWD
client: TYPE A
terminated
DataConnection_Close

After changing to DirInternal, I get this:

*** Service (starter) Create ***
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
client: USER Test
client: PASS test
User logged in: Test
client: SYST
client: FEAT
client: OPTS UTF8 ON
client: PWD
client: CWD /
Data connection terminated: /
DataConnection_Close
Data connection terminated: /
DataConnection_Close
client: TYPE I
client: PASV
DataConnection_Close
client: RETR app_allow_list.txt
Data connection terminated: null
DataConnection_Close
client: CWD virtual_assets
terminated
DataConnection_Close

On the FTP client side (WinSCP), I get this error:
Copying files from remote side failed.
Invalid path: app_allow_list.txt

Or transferring from the PC to the phone, I get this:
Copying files to remote side failed.
Invalid path: image1.jpg
 
Upvote 0

thoward

Member
Licensed User
Longtime User
I have unpacked the FTPServer.b4xlib file and changed the example project to use the .bas files instead of the library. Now I'm trying to troubleshoot and see where it's going off the rails.
 
Upvote 0

JohnC

Expert
Licensed User
Longtime User
In the top set of events you posted (where you are not using DirInternal), it seems like you are just navigating to directories and doing a list command.

But, then in the later events (when you are having problems) it seems that you are trying to work with files and not directories, so maybe the cause of your problem is a syntax issue of not having the path and/or filename specified correctly.
 
Last edited:
Upvote 0

thoward

Member
Licensed User
Longtime User
Okay, I think I may have something. In FTPClient.NormalizePath, it assumes that the results of the Java method "getCanonicalPath" are going to be the same as BaseDir, which is what we set to DirInternal. This is a correct assumption for DirRootExternal, but (at least on my phone) appears to be incorrect for DirInternal. Take a look at the code:

FTPClient.NormalizePath:
Private Sub NormalizePath(p As String) As String
    If p.StartsWith("/") Or p.StartsWith("\") Then p = p.SubString(1)
    
    '#if B4A Or B4J
    Dim jo As JavaObject
    jo.InitializeNewInstance("java.io.File", Array(File.Combine(mServer.BaseDir, p)))
    Dim CanonicalPath As String = jo.RunMethod("getCanonicalPath", Null)
    If CanonicalPath.ToLowerCase.StartsWith(mServer.BaseDir.ToLowerCase) Then
        Dim r As String = CanonicalPath.SubString(mServer.BaseDir.Length).Replace("\", "/")
        If r.Length = 0 Then Return "/" Else Return r
    Else
        SendResponse(450, "Invalid path: " & p)
        Return ""
    End If
    '...
End Sub

When I set BaseDir to DirRootExternal -
BaseDir: /storage/emulated/0
CanonicalPath: /storage/emulated/0

When I set BaseDir to DirInternal -
BaseDir is /data/user/0/b4a.example/files
CanonicalPath is /data/data/b4a.example/files

I believe this is why DirInternal is not working for me.
 
Upvote 0

thoward

Member
Licensed User
Longtime User
As a test, I changed line 7 above to this
B4X:
Dim CanonicalPath As String = File.Combine(mServer.BaseDir, p)
Now, everything works for both DirInternal and DirRootExternal, as far as I can tell.

I'm not sure why getCanonicalPath was used to begin with, but I'm sure @Erel had a good reason for it.
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
I'm not sure why getCanonicalPath was used to begin with, but I'm sure @Erel had a good reason for it.
It is a safety procedure to prevent the client from trying to access folders outside of the base folder.
It is less relevant if the base folder is the internal folder, assuming that you are fine with the customer accessing all of the files there.
 
Upvote 0
Top