~xdavidwu/saf-sftp

63558d4b90ee4d1731cdf5cd00900c7ce0715b04 — xdavidwu 1 year, 10 months ago a3b738d
seekable reader, bump min sdk level to 26
4 files changed, 66 insertions(+), 63 deletions(-)

M build.gradle
D src/main/java/org/safsftp/ReadTask.java
M src/main/java/org/safsftp/SFTPDocumentsProvider.java
A src/main/java/org/safsftp/SFTPProxyFileDescriptorCallback.java
M build.gradle => build.gradle +1 -1
@@ 14,7 14,7 @@ android {
	buildToolsVersion '31'

	defaultConfig {
		minSdkVersion 19
		minSdkVersion 26
		targetSdkVersion 28
	}


D src/main/java/org/safsftp/ReadTask.java => src/main/java/org/safsftp/ReadTask.java +0 -50
@@ 1,50 0,0 @@
package org.safsftp;

import android.os.AsyncTask;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.ParcelFileDescriptor.AutoCloseOutputStream;
import android.util.Log;

import com.trilead.ssh2.Connection;
import com.trilead.ssh2.SFTPv3Client;
import com.trilead.ssh2.SFTPv3FileHandle;

import org.safsftp.ToastThread;

public class ReadTask extends AsyncTask<Void,Void,Void> {
	private SFTPv3Client sftp;
	private SFTPv3FileHandle file;
	private ParcelFileDescriptor fd;

	public ReadTask(SFTPv3Client sftp,SFTPv3FileHandle file,ParcelFileDescriptor fd) {
		this.fd=fd;
		this.sftp=sftp;
		this.file=file;
	}

	@Override
	public Void doInBackground(Void... args) {
		AutoCloseOutputStream acos=new AutoCloseOutputStream(fd);
		int size,offset=0;
		byte[] buf=new byte[32768];
		try{
			while((size=sftp.read(file,offset,buf,0,32768))>0) {
				acos.write(buf,0,size);
				offset+=size;
			}
			acos.close();
		}
		catch(Exception e){
			Log.e("SFTP","read file "+e.toString());
		}
		try{
			sftp.closeFile(file);
		}
		catch(Exception e){
			Log.e("SFTP","close file "+e.toString());
		}
		sftp.close();
		return null;
	}
}

M src/main/java/org/safsftp/SFTPDocumentsProvider.java => src/main/java/org/safsftp/SFTPDocumentsProvider.java +17 -12
@@ 1,13 1,16 @@
package org.safsftp;

import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.storage.StorageManager;
import android.os.StrictMode;
import android.preference.PreferenceManager;
import android.provider.DocumentsContract.Document;


@@ 26,12 29,11 @@ import com.trilead.ssh2.SFTPv3FileHandle;
import java.io.IOException;
import java.util.Vector;

import org.safsftp.ToastThread;
import org.safsftp.ReadTask;

public class SFTPDocumentsProvider extends DocumentsProvider {
	private Connection connection;
	private String host=null,port=null; //TODO: multiple server support
	private StorageManager sm;
	private Handler ioHandler;
	private ToastThread lthread;
	
	private static final String[] DEFAULT_ROOT_PROJECTION=new String[]{


@@ 106,8 108,13 @@ public class SFTPDocumentsProvider extends DocumentsProvider {

	@Override
	public boolean onCreate() {
		lthread=new ToastThread(getContext());
		sm = (StorageManager) getContext()
			.getSystemService(Context.STORAGE_SERVICE);
		lthread = new ToastThread(getContext());
		lthread.start();
		HandlerThread ioThread = new HandlerThread("IO thread");
		ioThread.start();
		ioHandler = new Handler(ioThread.getLooper());
		return true;
	}



@@ 124,20 131,18 @@ public class SFTPDocumentsProvider extends DocumentsProvider {
		}
		String filename=documentId.substring(documentId.indexOf("/")+1);
		Log.v("SFTP","od "+documentId+" on "+host+":"+port);
		ParcelFileDescriptor[] fd;
		SFTPv3FileHandle file;
		try {
			fd=ParcelFileDescriptor.createReliablePipe();
			file=sftp.openFileRO(filename);
		}
		catch(IOException e) {
			file = sftp.openFileRO(filename);
			return sm.openProxyFileDescriptor(
				ParcelFileDescriptor.MODE_READ_ONLY,
				new SFTPProxyFileDescriptorCallback(sftp, file),
				ioHandler);
		} catch (IOException e) {
			//TODO notify error
			Log.e("SFTP","read file "+filename+" init "+e.toString());
			return null;
		}
		new ReadTask(sftp,file,fd[1]).execute();
		Log.v("SFTP","od "+documentId+" on "+host+":"+port+" return");
		return fd[0];
	}

	public Cursor queryChildDocuments(String parentDocumentId,

A src/main/java/org/safsftp/SFTPProxyFileDescriptorCallback.java => src/main/java/org/safsftp/SFTPProxyFileDescriptorCallback.java +48 -0
@@ 0,0 1,48 @@
package org.safsftp;

import android.os.ProxyFileDescriptorCallback;
import android.system.ErrnoException;
import android.system.OsConstants;

import java.io.IOException;

import com.trilead.ssh2.Connection;
import com.trilead.ssh2.SFTPv3Client;
import com.trilead.ssh2.SFTPv3FileHandle;

public class SFTPProxyFileDescriptorCallback extends ProxyFileDescriptorCallback {
	private SFTPv3Client sftp;
	private SFTPv3FileHandle file;


	public SFTPProxyFileDescriptorCallback(SFTPv3Client sftp, SFTPv3FileHandle file) {
		this.sftp = sftp;
		this.file = file;
	}

	@Override
	public long onGetSize() throws ErrnoException {
		try {
			return sftp.fstat(file).size;
		} catch (IOException e) {
			throw new ErrnoException("fstat", OsConstants.EIO);
		}
	}

	@Override
	public int onRead(long offset, int size, byte[] data)
		throws ErrnoException {
		try {
			return sftp.read(file, offset, data, 0, size);
		} catch (IOException e) {
			throw new ErrnoException("read", OsConstants.EIO);
		}
	}

	@Override
	public void onRelease() {
		try {
			sftp.closeFile(file);
		} catch (IOException e) {} //TODO
	}
}