Correct module remote file implementation
This commit is contained in:
parent
5e3d4d6559
commit
4c3f8d95db
|
|
@ -299,12 +299,22 @@ public class LSPosedContext extends XposedContext {
|
|||
|
||||
@Override
|
||||
public boolean moveSharedPreferencesFrom(Context sourceContext, String name) {
|
||||
throw new AbstractMethodError();
|
||||
if (name == null) throw new IllegalArgumentException("name must not be null");
|
||||
if (name.startsWith("remote://")) {
|
||||
throw new IllegalArgumentException("Moving remote preferences is not supported");
|
||||
} else {
|
||||
return mBase.moveSharedPreferencesFrom(sourceContext, name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteSharedPreferences(String name) {
|
||||
throw new AbstractMethodError();
|
||||
if (name == null) throw new IllegalArgumentException("name must not be null");
|
||||
if (name.startsWith("remote://")) {
|
||||
throw new IllegalArgumentException("Read only implementation");
|
||||
} else {
|
||||
return mBase.deleteSharedPreferences(name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -325,7 +335,7 @@ public class LSPosedContext extends XposedContext {
|
|||
public FileOutputStream openFileOutput(String name, int mode) throws FileNotFoundException {
|
||||
if (name == null) throw new IllegalArgumentException("name must not be null");
|
||||
if (name.startsWith("remote://")) {
|
||||
throw new FileNotFoundException("Read only implementation");
|
||||
throw new IllegalArgumentException("Read only implementation");
|
||||
} else {
|
||||
return mBase.openFileOutput(name, mode);
|
||||
}
|
||||
|
|
@ -333,12 +343,22 @@ public class LSPosedContext extends XposedContext {
|
|||
|
||||
@Override
|
||||
public boolean deleteFile(String name) {
|
||||
throw new AbstractMethodError();
|
||||
if (name == null) throw new IllegalArgumentException("name must not be null");
|
||||
if (name.startsWith("remote://")) {
|
||||
throw new IllegalArgumentException("Read only implementation");
|
||||
} else {
|
||||
return mBase.deleteFile(name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getFileStreamPath(String name) {
|
||||
return mBase.getFileStreamPath(name);
|
||||
if (name == null) throw new IllegalArgumentException("name must not be null");
|
||||
if (name.startsWith("remote://")) {
|
||||
throw new IllegalArgumentException("Getting remote file path is not supported");
|
||||
} else {
|
||||
return mBase.getFileStreamPath(name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -427,32 +447,64 @@ public class LSPosedContext extends XposedContext {
|
|||
|
||||
@Override
|
||||
public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory) {
|
||||
throw new AbstractMethodError();
|
||||
if (name == null) throw new IllegalArgumentException("name must not be null");
|
||||
if (name.startsWith("remote://")) {
|
||||
return openOrCreateDatabase(name, mode, factory, null);
|
||||
} else {
|
||||
return mBase.openOrCreateDatabase(name, mode, factory);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory, @Nullable DatabaseErrorHandler errorHandler) {
|
||||
throw new AbstractMethodError();
|
||||
if (name == null) throw new IllegalArgumentException("name must not be null");
|
||||
if (name.startsWith("remote://")) {
|
||||
throw new IllegalArgumentException("Opening remote database is not supported");
|
||||
} else {
|
||||
return mBase.openOrCreateDatabase(name, mode, factory, errorHandler);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean moveDatabaseFrom(Context sourceContext, String name) {
|
||||
throw new AbstractMethodError();
|
||||
if (name == null) throw new IllegalArgumentException("name must not be null");
|
||||
if (name.startsWith("remote://")) {
|
||||
throw new IllegalArgumentException("Moving remote database is not supported");
|
||||
} else {
|
||||
return mBase.moveDatabaseFrom(sourceContext, name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteDatabase(String name) {
|
||||
throw new AbstractMethodError();
|
||||
if (name == null) throw new IllegalArgumentException("name must not be null");
|
||||
if (name.startsWith("remote://")) {
|
||||
throw new IllegalArgumentException("Read only implementation");
|
||||
} else {
|
||||
return mBase.deleteDatabase(name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getDatabasePath(String name) {
|
||||
throw new AbstractMethodError();
|
||||
if (name == null) throw new IllegalArgumentException("name must not be null");
|
||||
if (name.startsWith("remote://")) {
|
||||
throw new IllegalArgumentException("Getting remote database path is not supported");
|
||||
} else {
|
||||
return mBase.getDatabasePath(name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] databaseList() {
|
||||
throw new AbstractMethodError();
|
||||
var remoteFiles = new String[0]; // TODO
|
||||
var localFiles = mBase.databaseList();
|
||||
var files = new String[remoteFiles.length + localFiles.length];
|
||||
for (int i = 0; i < remoteFiles.length; i++) {
|
||||
files[i] = "remote://" + remoteFiles[i];
|
||||
}
|
||||
System.arraycopy(localFiles, 0, files, remoteFiles.length, localFiles.length);
|
||||
return files;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import android.content.res.AssetManager;
|
|||
import android.content.res.Resources;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SELinux;
|
||||
import android.os.SharedMemory;
|
||||
import android.system.ErrnoException;
|
||||
|
|
@ -428,17 +429,27 @@ public class ConfigFileManager {
|
|||
return preloadDex;
|
||||
}
|
||||
|
||||
static Path resolveModulePath(String packageName, String path) throws IOException {
|
||||
var requestPath = Paths.get(path);
|
||||
if (requestPath.isAbsolute()) {
|
||||
throw new IOException("path must be relative");
|
||||
static void ensureValidPath(String path) throws RemoteException {
|
||||
if (path == null || path.indexOf(File.separatorChar) >= 0 || ".".equals(path) || "..".equals(path)) {
|
||||
throw new RemoteException("Invalid path: " + path);
|
||||
}
|
||||
var moduleDir = modulePath.resolve(packageName).normalize();
|
||||
var absolutePath = moduleDir.resolve(requestPath).normalize();
|
||||
if (!absolutePath.startsWith(moduleDir)) {
|
||||
throw new IOException("path must be in module dir");
|
||||
}
|
||||
|
||||
static Path resolveModuleDir(String packageName, String dir, int userId, int uid) throws IOException {
|
||||
var path = modulePath.resolve(String.valueOf(userId)).resolve(packageName).resolve(dir).normalize();
|
||||
if (uid != -1) {
|
||||
if (!path.toFile().mkdirs()) {
|
||||
throw new IOException("Can not create " + dir + " for " + packageName);
|
||||
}
|
||||
SELinux.setFileContext(path.toString(), "u:object_r::s0");
|
||||
try {
|
||||
Os.chown(path.toString(), uid, uid);
|
||||
Os.chmod(path.toString(), 0755);
|
||||
} catch (ErrnoException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
return absolutePath;
|
||||
return path;
|
||||
}
|
||||
|
||||
private static class FileLocker {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import android.os.RemoteException;
|
|||
|
||||
import org.lsposed.lspd.models.Module;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
|
@ -44,9 +45,11 @@ public class LSPInjectedModuleService extends ILSPInjectedModuleService.Stub {
|
|||
|
||||
@Override
|
||||
public ParcelFileDescriptor openRemoteFile(String path) throws RemoteException {
|
||||
ConfigFileManager.ensureValidPath(path);
|
||||
var userId = Binder.getCallingUid() / PER_USER_RANGE;
|
||||
try {
|
||||
var absolutePath = ConfigFileManager.resolveModulePath(loadedModule.packageName, path);
|
||||
return ParcelFileDescriptor.open(absolutePath.toFile(), ParcelFileDescriptor.MODE_READ_ONLY);
|
||||
var dirPath = ConfigFileManager.resolveModuleDir(loadedModule.packageName, "files", userId, -1);
|
||||
return ParcelFileDescriptor.open(dirPath.resolve(path).toFile(), ParcelFileDescriptor.MODE_READ_ONLY);
|
||||
} catch (Throwable e) {
|
||||
throw new RemoteException(e.getMessage());
|
||||
}
|
||||
|
|
@ -55,8 +58,11 @@ public class LSPInjectedModuleService extends ILSPInjectedModuleService.Stub {
|
|||
@Override
|
||||
public String[] getRemoteFileList() throws RemoteException {
|
||||
try {
|
||||
var absolutePath = ConfigFileManager.resolveModulePath(loadedModule.packageName, ".");
|
||||
return absolutePath.toFile().list();
|
||||
var userId = Binder.getCallingUid() / PER_USER_RANGE;
|
||||
var dir = ConfigFileManager.resolveModuleDir(loadedModule.packageName, "files", userId, -1);
|
||||
var files = dir.toFile().list();
|
||||
return files == null ? new String[0] : files;
|
||||
|
||||
} catch (Throwable e) {
|
||||
throw new RemoteException(e.getMessage());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import androidx.annotation.NonNull;
|
|||
import org.lsposed.daemon.BuildConfig;
|
||||
import org.lsposed.lspd.models.Module;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
|
@ -224,12 +225,11 @@ public class LSPModuleService extends IXposedService.Stub {
|
|||
|
||||
@Override
|
||||
public ParcelFileDescriptor openRemoteFile(String path, int mode) throws RemoteException {
|
||||
var userId = ensureModule();
|
||||
ConfigFileManager.ensureValidPath(path);
|
||||
try {
|
||||
var absolutePath = ConfigFileManager.resolveModulePath(loadedModule.packageName, path);
|
||||
if (!absolutePath.getParent().toFile().mkdirs()) {
|
||||
throw new IOException("failed to create parent dir");
|
||||
}
|
||||
return ParcelFileDescriptor.open(absolutePath.toFile(), mode);
|
||||
var dir = ConfigFileManager.resolveModuleDir(loadedModule.packageName, "files", userId, Binder.getCallingUid());
|
||||
return ParcelFileDescriptor.open(dir.resolve(path).toFile(), mode);
|
||||
} catch (Throwable e) {
|
||||
throw new RemoteException(e.getMessage());
|
||||
}
|
||||
|
|
@ -237,9 +237,23 @@ public class LSPModuleService extends IXposedService.Stub {
|
|||
|
||||
@Override
|
||||
public boolean deleteRemoteFile(String path) throws RemoteException {
|
||||
var userId = ensureModule();
|
||||
ConfigFileManager.ensureValidPath(path);
|
||||
try {
|
||||
var absolutePath = ConfigFileManager.resolveModulePath(loadedModule.packageName, path);
|
||||
return absolutePath.toFile().delete();
|
||||
var dir = ConfigFileManager.resolveModuleDir(loadedModule.packageName, "files", userId, Binder.getCallingUid());
|
||||
return dir.resolve(path).toFile().delete();
|
||||
} catch (Throwable e) {
|
||||
throw new RemoteException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] listRemoteFiles() throws RemoteException {
|
||||
var userId = ensureModule();
|
||||
try {
|
||||
var dir = ConfigFileManager.resolveModuleDir(loadedModule.packageName, "files", userId, Binder.getCallingUid());
|
||||
var files = dir.toFile().list();
|
||||
return files == null ? new String[0] : files;
|
||||
} catch (Throwable e) {
|
||||
throw new RemoteException(e.getMessage());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,4 +33,5 @@ interface IXposedService {
|
|||
// remote file utilities
|
||||
ParcelFileDescriptor openRemoteFile(String path, int mode) = 30;
|
||||
boolean deleteRemoteFile(String path) = 31;
|
||||
String[] listRemoteFiles() = 32;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue