FluentFTP: UploadDirectory with FtpNavigate.Conditional causing path issue and not uploading files

FTP Server OS: Windows

FTP Server Type: WSFTP Server

Client Computer OS: Windows /Linux

FluentFTP Version: 48.0.0

Framework: .NET 6

Logs :

Upload directory is not working as expected. Creating directories working fine but uploading files are failed. After seeing logs came to know virtual path names getting occured twice. PFA. VirtualPath : “\virtual-path-name” or “\virtual-path-name” tried both ways but didn’t work for upload files. my remote path contains spaces with virtual path i.e \virtualpathname\stagingfolder.…

 using IAsyncFtpClient asyncFtpClient = new AsyncFtpClient(ftpServer, username, password);
 await asyncFtpClient.Connect();
 await asyncFtpClient.SetWorkingDirectory(remotePath);
 asyncFtpClient.Config.LogToConsole = true;
 asyncFtpClient.Config.Navigate = FtpNavigate.Conditional;
 var result = await asyncFtpClient.UploadDirectory(resourcesDirFullPath, remoteFullPath, mode: FtpFolderSyncMode.Update, existsMode: FtpRemoteExists.Overwrite, verifyOptions: FtpVerify.Retry, token: CancellationToken.None).ConfigureAwait(false);

uploaddirlogs.txt

About this issue

  • Original URL
  • State: closed
  • Created 9 months ago
  • Comments: 35 (2 by maintainers)

Commits related to this issue

Most upvoted comments

48.0.1 as bugfix. I would not mind. I don’t know if there won’t be more coming though, Venkata is quite prolific in testing this feature but prefers nugets to test with.

@FanDjango , Please notify me once the fixed version is available with the latest master.

I am using WSFTP Server on windows OS but app runs on Linux\windows OS

Oh, I am so sorry - I forgot that, you posted it up at the top.

I think then, that WSFTP server is perhaps actually allowing the "" and interpreting it as a directory separator. My bad. But - if FluentFTP “recognizes” it to be a Unix type server, things will not go right.

I think some of the path / filename logic needs to be fixed up a little bit sometime.

I will look at the SIZE logs…

I should add:

GetFtpPath(..), which will translate backslashes to forward slashes, is needed internally wherever .NET path extensions, such as GetDirectory or Combine will return unwanted backslashes.

It is not meant to convert a users possibly perfectly valid backslashes (part of a filename) to forward slashes, which would causes errors.

And now comes a problem: In FluentFTP, currently, I think that you actually cannot safely use backward slashes on purpose (as filename chararcters), because we will lose them in many API functions. Needs to be fixed someday.

But the solution can’t be to forcefully move towards permanently recognizing a backslash as a path separator (because unless you write a custom server handler) a Unix server type should not recognize that.

You could write a custom handler for WSFTPd, if you want. You have never shown the Connect/FEAT etc. sequence in your logs. As what is the server recognized?As a Unix server? If so, you need to adhere to that systems path and filename semantics.

Yes, I know. And it can be reproduced. I get the same (incorrect) behaviour.

If I replace backward with forward slashes . it will work for me .

Right. So for deity’s sake, correct your filename strings.


If you prefer to hard-code the directory separator character, you should use the forward slash ( / ) character. It is the only recognized directory separator character on Unix systems. By the way, it is the AltDirectorySeparatorChar on Windows.

The backslash is a valid character for a Unix filename, and it is not a path separator.

Example: /home/venkata/test/my\strange\file.text

The path is /home/venkata/test. The filename is my\strange\file.text.

I will not make such a code change. Code the path correctly. You need to make the transition between Windows and Unix filepaths watertight on your side.

Upload directory is working fine because remotePath.GetFtpPath() is called before calling upload file.

Yes. It is part of the needed logic in UploadDirectory. This is not needed in UploadFile. So it is just a coincidence.

You should use

var remoteFilePath = Path.Combine(stagingPath, @"bvk test city", "1kbtestfile.txt").Replace("\\","/");

I will fix that right away…

@FanDjango , Also in upload file there is another issue while create directory before calling settingworking directory . In line no 47 : it should be remoteDir but not remotePath as shown in screenshot. image

@FanDjango , Upload file failed. Hoping below code, logs, screenshots, solutions might be helpful.

Logs:

uploadfile_failed_logs.txt

Code:

    public async Task UploadFile()
    {
         remotePath = @"\NonProdVirtualPath";
         stagingPath = @"\NonProdVirtualPath\Staging\dev\invoices";
        var remoteFilePath = Path.Combine(stagingPath, @"bvk test city", "1kbtestfile.txt");

        using IAsyncFtpClient asyncFtpClient = new AsyncFtpClient(ftpServer, username, password);
        await asyncFtpClient.Connect();
        await asyncFtpClient.SetWorkingDirectory(remotePath);//
        asyncFtpClient.Config.LogToConsole = true;
        asyncFtpClient.Config.Navigate = FtpNavigate.Conditional;
        string localpath = @"D:\BackUp\FTP_Demo\FTP_Demo\Resources\20230815_101_City and bvkdownload1\1KB.txt";

        try
        {
            var ftpStatus = await asyncFtpClient.UploadFile(localpath, remoteFilePath, existsMode: FtpRemoteExists.Overwrite, createRemoteDir: true).ConfigureAwait(false);
            if (ftpStatus == FtpStatus.Success)
                await Console.Out.WriteLineAsync("upload success.");
        }
        catch (Exception ex)
        {
            Console.WriteLine($" \n \n File {remoteFilePath} uploaded falied. {ex?.ToString()}");
        }

    }

Issue occurring at GetAbsolutePathAsync method: Call before GetAbsolutePathAsync method , See remote path value

image

Inside GetAbsolutePathsAsync method image

image

image

Solution: two ways can be solved

  1. One way : calling remotepath = remotepath.GetFtpPath before GetAbsolutePath method. this is just bypassing GetAbsolutePath method else if condition.
  2. Second way :

image

Gimme some time to consolidate and check status - we have a slight overlap on progress here now.

@Venkatakrishna-bvk I see the problem. Working on it…

@FanDjango , The code mentioned above is working fine for me.

@Venkatakrishna-bvk

Please open a new issue for this “separate issue not related to it”, call it “Autonavigate feature should also work for GetCheckSum” and include the log file there.

Meanwhile I will investigate this.

Ok, I have identified the problem. Now proceeding with fixing it…

@Venkatakrishna-bvk …studying log file