Skip to content

Commit

Permalink
Merge pull request #351 from lmagyar/pr-fix-set-last-modified
Browse files Browse the repository at this point in the history
Fix setLastModified() exception on SAF
  • Loading branch information
wolpi authored Jun 8, 2024
2 parents a0351b5 + 286abd8 commit 7a78dd8
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 9 deletions.
13 changes: 8 additions & 5 deletions primitiveFTPd/src/org/primftpd/filesystem/SafFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,17 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributeView;
import java.nio.file.attribute.FileTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

public abstract class SafFile<T> extends AbstractFile {

Expand Down Expand Up @@ -124,12 +130,9 @@ public boolean setLastModified(long time) {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
try {
ContentValues updateValues = new ContentValues();
//time = Utils.sshTimeToFileTime(time);
updateValues.put(DocumentsContract.Document.COLUMN_LAST_MODIFIED, time);
Uri docUri = documentFile.getUri();
int updated = contentResolver.update(docUri, updateValues, "name="+name, null);
return updated == 1;
Path filePath = Paths.get(StorageManagerUtil.getFullDocIdPathFromTreeUri(docUri, pftpdService.getContext()));
Files.getFileAttributeView(filePath, BasicFileAttributeView.class).setTimes(FileTime.fromMillis(time), null, null);
} catch (Exception e) {
String baseMsg = "could not set last modified time";
logger.error(baseMsg, e);
Expand Down
108 changes: 108 additions & 0 deletions primitiveFTPd/src/org/primftpd/filesystem/StorageManagerUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package org.primftpd.filesystem;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.net.Uri;
import android.os.Build;
import android.os.storage.StorageManager;
import android.provider.DocumentsContract;

import androidx.annotation.Nullable;
import androidx.documentfile.provider.DocumentFile;

import java.io.File;
import java.io.FileNotFoundException;
import java.lang.reflect.Array;
import java.lang.reflect.Method;

public final class StorageManagerUtil {
private static final String PRIMARY_VOLUME_NAME = "primary";

public static String getFullDocIdPathFromTreeUri(@Nullable final Uri treeUri, Context context) {
if (treeUri == null) {
return null;
}
String volumePath = getVolumePath(getVolumeIdFromTreeUri(treeUri), context);
if (volumePath == null) {
return File.separator;
}
if (volumePath.endsWith(File.separator)) {
volumePath = volumePath.substring(0, volumePath.length() - 1);
}

String documentPath = getDocumentPathFromTreeUri(treeUri);
if (documentPath.endsWith(File.separator)) {
documentPath = documentPath.substring(0, documentPath.length() - 1);
}

if (documentPath.length() > 0) {
if (documentPath.startsWith(File.separator)) {
return volumePath + documentPath;
} else {
return volumePath + File.separator + documentPath;
}
} else {
return volumePath;
}
}

@SuppressLint("ObsoleteSdkInt")
private static String getVolumePath(final String volumeId, Context context) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
return null;
}
try {
StorageManager mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
Class<?> storageVolumeClass = Class.forName("android.os.storage.StorageVolume");
Method getVolumeList = mStorageManager.getClass().getMethod("getVolumeList");
Method getUuid = storageVolumeClass.getMethod("getUuid");
Method getPath = storageVolumeClass.getMethod("getPath");
Method isPrimary = storageVolumeClass.getMethod("isPrimary");
Object result = getVolumeList.invoke(mStorageManager);

final int length = Array.getLength(result);
for (int i = 0; i < length; i++) {
Object storageVolumeElement = Array.get(result, i);
String uuid = (String) getUuid.invoke(storageVolumeElement);
Boolean primary = (Boolean) isPrimary.invoke(storageVolumeElement);

// primary volume?
if (primary && PRIMARY_VOLUME_NAME.equals(volumeId)) {
return (String) getPath.invoke(storageVolumeElement);
}

// other volumes?
if (uuid != null && uuid.equals(volumeId)) {
return (String) getPath.invoke(storageVolumeElement);
}
}
// not found.
return null;
} catch (Exception ex) {
return null;
}
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public static String getVolumeIdFromTreeUri(final Uri treeUri) {
final String docId = DocumentsContract.getTreeDocumentId(treeUri);
final String[] split = docId.split(":");
if (split.length > 0) {
return split[0];
} else {
return null;
}
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private static String getDocumentPathFromTreeUri(final Uri treeUri) {
final String docId = DocumentsContract.getDocumentId(treeUri);
final String[] split = docId.split(":");
if ((split.length >= 2) && (split[1] != null)) {
return split[1];
} else {
return File.separator;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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());

sendStatus(id, SSH_FX_OK, "");
}
} catch (IOException e) {
Expand Down

0 comments on commit 7a78dd8

Please sign in to comment.