West Wind Internet and Client Tools
wwSFTPClient, no preserve timestamp, SETSTAT unsupported
Gravatar is a globally recognized avatar based on your email address. wwSFTPClient, no preserve timestamp, SETSTAT unsupported
  Mike Helland
  All
  Aug 22, 2025 @ 06:52am

Hi, Rick!

I'm using wwSFTPClient to upload some files. It connects fine, and says it uploads, but the files are not there.

When I use WinSCP to copy files up, I get this:

I can change a setting in WinSCP to disable the "Preserve Timestamp"

And that works.

According to what I've read SSH.NET doesn't preserve timestamps... so maybe my issue is unrelated?

https://stackoverflow.com/questions/36638993/ssh-net-is-it-possible-to-upload-files-using-sftp-and-preserve-the-file-dates-f

I'm guessing it's something I need to send over oBridge to get to work. Any ideas?

Gravatar is a globally recognized avatar based on your email address. re: wwSFTPClient, no preserve timestamp, SETSTAT unsupported
  Rick Strahl
  Mike Helland
  Aug 22, 2025 @ 09:57am

Yeah - SFTP natively doesn't support file time forwarding because it's a streaming API, not a file based API like FPT/FTPS. So files are streamed to the server in chunks of bytes and so the file date information needs to be set explicitly.

It's straight forward in .NET code:

var fi = new FileInfo(localFilename);            
SftpClient.SetLastWriteTimeUtc(remoteFilename, fi.LastWriteTimeUtc);

In FoxPro that takes a bit more work:

ltTime = GetUtcTime(  FileTime(".\tests\sailbig.jpg") )  && wwUtils/wwapi
? ltTime
loFtp.oBridge.InvokeMethod(loFtp.oFtpClient.SftpClient,"SetLastWriteTimeUtc",lcUploadFile, ltTime)

The shitty part of this is getting the FoxPro UTC date...

I think I'll change the logic to automatically add the timestamp on uploads (and potentially on downloads too) since that makes a lot more sense than some default irrelevant date. People can override this if they need some other specific value.

According to your SO link that call may not always work though so I'm bracketing it and if the date setting fails it'll just use the old default whatever that may be (ie. server determined).

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: wwSFTPClient, no preserve timestamp, SETSTAT unsupported
  Mike Helland
  Rick Strahl
  Aug 22, 2025 @ 10:07am

SFTP natively doesn't support file time forwarding because it's a streaming API, not a file based API like FPT/FTPS. So files are streamed to the server in chunks of bytes and so the file date information needs to be set explicitly.

Which is totally fine with me, since the server doesn't support setting the date and time.

That suggests my issue isn't the same as WinSCP's.

Does SSH.NET do anything with permissions after the upload that you know of?

Gravatar is a globally recognized avatar based on your email address. re: wwSFTPClient, no preserve timestamp, SETSTAT unsupported
  Rick Strahl
  Mike Helland
  Aug 22, 2025 @ 10:19am

I've updated the DLLs. Give the new DLL a try it'll explicitly set the file dates for UploadFile() and DownloadFile() as part of the method calls (the xxxSimple() versions do not do this).

Yeah, permissions may affect this but the way this is set up now if the call fails the file is still up or downloaded without setting the date.

https://west-wind.com/files/WebConnectionExperimental.zip

Grab wwDotnetBridge.dll out of the zip file. It'll be v8.4.1.

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: wwSFTPClient, no preserve timestamp, SETSTAT unsupported
  Mike Helland
  Rick Strahl
  Aug 22, 2025 @ 11:05am

Using the new wwDotNetBridge.dll, I am able to upload to Rebex Tiny SFTP Server, as I was before.

I do get an error though:

ERROR: 1429 - OLE IDispatch exception code 0 from Anonymously Hosted DynamicMethods Assembly: Operator '==' cannot be applied to operands of type 'System.__ComObject' and 'System.DBNull'.. at 293 of WWSFTPCLIENT.CONNECT

That line of code is:

loSftp.FoxProwwFtpClientForProgress = THIS.oProgressEventObject

I'm setting oProgressEventObject before I call connect:

cd (pcDir)
do wwutils
DO wwSFtpClient && Load Library
loFtp  = CREATEOBJECT("wwsFtpClient")
loFtp.cLogFile = fullpath("ftp.log") && verbose log - leave empty
loFtp.lIgnoreCertificateErrors = .T.   && self-signed cert not installed
loFtp.cServer = lcServer
loFtp.nPort = lnPort
loFtp.cUsername = lcUsername
loFtp.cPassword = lcPassword
loFtp.oProgressEventObject = createobject("FtpClientProgressEvents")

if not loFtp.connect()
	writeLog("Could not connect to ftp server:")
	writeLog(transform(loFtp.cERRORMSG))
	return
endif

On the server that required I turn "Preserve File Dates" off to get a file uploaded, the logs say it was uploaded, but I don't see it there (same was happening with WinSCP before I disabled "Preserve Date").

What's the "&& verbose log - leave empty" about? Do I get more info if cLogFile = ""? Where does it go in that case?

Gravatar is a globally recognized avatar based on your email address. re: wwSFTPClient, no preserve timestamp, SETSTAT unsupported
  Rick Strahl
  Mike Helland
  Aug 22, 2025 @ 11:14am

ugh... thanks for catching that error.

Yeah there was another bug in the code that was causing problems if no progress object was provided so I added logic to automatically handle that and DbNull and ComObject proxies are both weird types - ended up failing when doing a comparsion.

Fixed with:

  public dynamic FoxProwwFtpClientForProgress
  {
      get => _foxProwwFtpClientForProgress;
      set 
      {
          // if (value == DBNull.Value)   // this doesn't work
          if (value is DBNull)
              value = null;

          _foxProwwFtpClientForProgress = value;
      }
  }
  private dynamic _foxProwwFtpClientForProgress;

I've updated the DLL.

I also added an explicit method for SetFileTime() to the wwSftpClient:

And updated the docs for UploadFile() and DownloadFile() to reflect that the time is now updated by default.

Update is v8.4.2. You'll need to update both the wwDotnetBridge.dll and wwDotnetBridge.prg to see the new SetFileTime() method.

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: wwSFTPClient, no preserve timestamp, SETSTAT unsupported
  Mike Helland
  Rick Strahl
  Aug 22, 2025 @ 11:17am

Cool, thanks, I'll give it a try.

Just so there's no miscommunication, I don't want to preserve the timestamp (the server doesn't allow changing it).

So even though that was WinSCP's problem, my problem might be unrelated.

Gravatar is a globally recognized avatar based on your email address. re: wwSFTPClient, no preserve timestamp, SETSTAT unsupported
  Rick Strahl
  Mike Helland
  Aug 22, 2025 @ 11:56am

If the server doesn't support it, then the upload should just work. The set of the file time in that scenario will then fail and be ignored.

My guess is that WinSCP attempts to set it and doesn't catch the exception and then fails.

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: wwSFTPClient, no preserve timestamp, SETSTAT unsupported
  Mike Helland
  Rick Strahl
  Aug 23, 2025 @ 08:37am

There was a 8.4.2 wwDotNetBridge.dll, but no wwDotNetBridge.prg.

No change using the wwDotNetBridge.dll and the wwSFTPClient.prg in the experimental.zip.

Gravatar is a globally recognized avatar based on your email address. re: wwSFTPClient, no preserve timestamp, SETSTAT unsupported
  Rick Strahl
  Mike Helland
  Aug 23, 2025 @ 08:42am

Sorry I meant wwSftpClient.prg - no changes in wwDotnetBridge.prg...

The log if specified is as detailed as it goes. It basically documents each step through the API (but not the internals of the API). However, if the API reports the upload worked and the files transferred then the server responded correctly and the file should be there. If it's not it might have to do with missing permissions to view the file or perhaps there's something running on the other end that moves the files once they come in.

+++ Rick ---

© 1996-2025