Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix setLastModified() exception on SAF #351

Merged
merged 2 commits into from
Jun 8, 2024

Conversation

lmagyar
Copy link
Contributor

@lmagyar lmagyar commented Jun 1, 2024

In theory it is not possible: DocumentsContract.Document.COLUMN_LAST_MODIFIED is read-only.

In reality it is possible: we can't write the SD card's files with the file API, but we can set the attributes with the file API (what we can't through SAF, "great" design).

The solution is a copy-paste from https://stackoverflow.com/questions/63495498/android-scoped-storage-getcontentresolver-update-column-last-modified/66681306#66681306

Note: I also removed the sshFile.setLastModified(new Date().getTime()); call in each SSH_FXP_WRITE

fixes #145

Tested on Android 9.0, Samsung A8

@@ -601,10 +601,6 @@ protected void process(Buffer buffer) throws IOException {
} else {
FileHandle fh = (FileHandle) p;
fh.write(data, offset);
SshFile sshFile = fh.getFile();

sshFile.setLastModified(new Date().getTime());
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it necessary to remove that?
When/where is setLastModified() invoked?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not necessary strictly, but slows down the copy, it calls this after each write block. Depending on the client (block size 4k-64k), 100 or 1000 times during each a file upload. :(

When invoked? In case of WinSCP:

  • If I turn off "preserve timestamp", WinSCP calls only open/write/close, and the OS sets the last modified time.
  • If I enable "preserve timestamp", it send a separate SSH_FXP_SETSTAT message, and that sets the timestamp.
  • Tested with SAF and POFS (plain old FS) and reading the ftpd logs.

@lmagyar
Copy link
Contributor Author

lmagyar commented Jun 2, 2024

FYI: And now I've tested it with even directories, this works even on them!

@wolpi wolpi added this to the 7.2 milestone Jun 8, 2024
@wolpi
Copy link
Owner

wolpi commented Jun 8, 2024

Ok, that sounds all good

@wolpi wolpi merged commit 7a78dd8 into wolpi:master Jun 8, 2024
1 check passed
@wolpi
Copy link
Owner

wolpi commented Jun 8, 2024

Many Thanks

@lmagyar lmagyar deleted the pr-fix-set-last-modified branch June 8, 2024 11:46
@catscarlet
Copy link

OMG.
6 years.

@lmagyar
Copy link
Contributor Author

lmagyar commented Jun 8, 2024

OMG. 6 years.

:) All credit goes to https://stackoverflow.com/users/15401262/usilo

@lmagyar
Copy link
Contributor Author

lmagyar commented Jun 10, 2024

One strange issue, seems to be an Android bug:

  • using FAT32 (32GB external SD card), with 2 second modification time resolution
  • setting a time to eg. 23.55 seconds with SETSTAT, SFTP protcoll will truncate it to integer seconds, ie. 23.00 seconds
  • reading back the modification timestamp with STAT gives 23.00 seconds, hmmm, strange, even when updating it through SAF and reading back from plain old FS, or vice-versa (OK, same file, but seems to be a low level Android cache issue)
  • nondeterministic way to emtpy some Android cache: restart pftpd, but sometimes it's not enough, we have to wait or completely restart the phone
  • reading back the modification timestamp with STAT gives 22.00 seconds, truncated to even integer (SAF and plain old FS also)

So it seems Android caches this mtime info, though the backing FAT32 FS stores only even-integer truncated values. When the cache is deleted and values are read from the real FS, timestamp magically changes...

This made me mad, I'm trying to create a bidirectional sync script, and even if I read back the "real" timestamp with STAT after SETSTAT, files started to change "randomly" during the night. They got 1 second older. Only the ones, that were odd-something seconds old on the previous day...

Android, what a mess...

Now I'm investigating where to put the workaround, in the ftpd server or in the sync script, I have to find a way to determine the filesystem's mtime resolution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Files modification time as create time, expect it as original modification time.
3 participants