Some bug fixes and tiny improvements upon seekable files.

This commit is contained in:
Garfield Tan 2017-07-06 16:20:00 -07:00
parent 0c5030a704
commit 061d34895d
5 changed files with 107 additions and 91 deletions

View file

@ -19,7 +19,6 @@ package com.google.android.sambadocumentsprovider.nativefacade;
import android.system.ErrnoException;
import android.system.StructStat;
import android.util.Log;
import java.io.IOException;
import java.nio.ByteBuffer;
@ -27,15 +26,21 @@ import java.nio.ByteBuffer;
class SambaFile implements SmbFile {
private final long mNativeHandler;
private int mNativeFd;
private long mOffset;
SambaFile(long nativeHandler, int nativeFd) {
mNativeHandler = nativeHandler;
mNativeFd = nativeFd;
}
public int read(ByteBuffer buffer) throws IOException {
public int read(ByteBuffer buffer, int maxLen) throws IOException {
try {
return read(mNativeHandler, mNativeFd, buffer, buffer.capacity());
final int bytesRead =
read(mNativeHandler, mNativeFd, buffer, Math.min(maxLen, buffer.capacity()));
mOffset += bytesRead;
return bytesRead;
} catch(ErrnoException e) {
throw new IOException("Failed to read file. Fd: " + mNativeFd, e);
}
@ -43,15 +48,22 @@ class SambaFile implements SmbFile {
public int write(ByteBuffer buffer, int length) throws IOException {
try {
return write(mNativeHandler, mNativeFd, buffer, length);
final int bytesWritten = write(mNativeHandler, mNativeFd, buffer, length);
mOffset += bytesWritten;
return bytesWritten;
} catch(ErrnoException e) {
throw new IOException("Failed to write file. Fd: " + mNativeFd, e);
}
}
public long seek(long offset) throws IOException {
if (mOffset == offset) {
return mOffset;
}
try {
return seek(mNativeHandler, mNativeFd, offset, 0);
mOffset = seek(mNativeHandler, mNativeFd, offset, 0);
return mOffset;
} catch (ErrnoException e) {
throw new IOException("Failed to move to offset in file. Fd: " + mNativeFd, e);
}

View file

@ -39,14 +39,12 @@ class SambaFileClient extends BaseClient implements SmbFile {
private static final int SEEK = 4;
private static final int FSTAT = 5;
private static final String OFFSET = "offset";
SambaFileClient(Looper looper, SmbFile smbFileImpl) {
mHandler = new SambaFileHandler(looper, smbFileImpl);
}
@Override
public int read(ByteBuffer buffer) throws IOException {
public int read(ByteBuffer buffer, int maxLen) throws IOException {
try(final MessageValues<ByteBuffer> messageValues = MessageValues.obtain()) {
messageValues.setObj(buffer);
final Message msg = mHandler.obtainMessage(READ, messageValues);
@ -68,16 +66,12 @@ class SambaFileClient extends BaseClient implements SmbFile {
@Override
public long seek(long offset) throws IOException {
try (final MessageValues messageValues = MessageValues.obtain()) {
try (final MessageValues<?> messageValues = MessageValues.obtain()) {
final Message msg = mHandler.obtainMessage(SEEK, messageValues);
Bundle data = new Bundle();
data.putLong(OFFSET, offset);
msg.setData(data);
messageValues.setLong(offset);
enqueue(msg);
return msg.peekData().getLong(OFFSET);
return messageValues.getLong();
}
}
@ -92,7 +86,7 @@ class SambaFileClient extends BaseClient implements SmbFile {
@Override
public void close() throws IOException {
try (final MessageValues messageValues = MessageValues.obtain()) {
try (final MessageValues<?> messageValues = MessageValues.obtain()) {
final Message msg = mHandler.obtainMessage(CLOSE, messageValues);
enqueue(msg);
messageValues.checkException();
@ -115,10 +109,12 @@ class SambaFileClient extends BaseClient implements SmbFile {
final MessageValues messageValues = (MessageValues) msg.obj;
try {
switch (msg.what) {
case READ:
case READ: {
final int maxLen = messageValues.getInt();
final ByteBuffer readBuffer = (ByteBuffer) messageValues.getObj();
messageValues.setInt(mSmbFileImpl.read(readBuffer));
messageValues.setInt(mSmbFileImpl.read(readBuffer, maxLen));
break;
}
case WRITE: {
final ByteBuffer writeBuffer = (ByteBuffer) messageValues.getObj();
final int length = msg.arg1;
@ -129,8 +125,9 @@ class SambaFileClient extends BaseClient implements SmbFile {
mSmbFileImpl.close();
break;
case SEEK:
long offset = mSmbFileImpl.seek(msg.peekData().getLong(OFFSET));
msg.peekData().putLong(OFFSET, offset);
long offset = mSmbFileImpl.seek(messageValues.getLong());
messageValues.setLong(offset);
break;
case FSTAT:
messageValues.setObj(mSmbFileImpl.fstat());
break;

View file

@ -25,7 +25,7 @@ import java.nio.ByteBuffer;
public interface SmbFile extends Closeable {
int read(ByteBuffer buffer) throws IOException;
int read(ByteBuffer buffer, int maxLen) throws IOException;
int write(ByteBuffer buffer, int length) throws IOException;
long seek(long offset) throws IOException;
StructStat fstat() throws IOException;

View file

@ -61,7 +61,7 @@ public class ReadFileTask extends AsyncTask<Void, Void, Void> {
int size;
byte[] buf = new byte[mBuffer.capacity()];
while ((mSignal == null || !mSignal.isCanceled())
&& (size = file.read(mBuffer)) > 0) {
&& (size = file.read(mBuffer, Integer.MAX_VALUE)) > 0) {
mBuffer.get(buf, 0, size);
os.write(buf, 0, size);
mBuffer.clear();

View file

@ -17,6 +17,7 @@
package com.google.android.sambadocumentsprovider.provider;
import android.annotation.TargetApi;
import android.os.CancellationSignal;
import android.os.ProxyFileDescriptorCallback;
import android.system.ErrnoException;
@ -29,89 +30,95 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
@TargetApi(26)
public class SambaProxyFileCallback extends ProxyFileDescriptorCallback {
private static final String TAG = "SambaProxyFileCallback";
private static final String TAG = "SambaProxyFileCallback";
private final SmbFile mFile;
private final ByteBufferPool mBufferPool;
private final ByteBuffer mBuffer;
private final CancellationSignal mSignal;
private final SmbFile mFile;
private final ByteBufferPool mBufferPool;
private final CancellationSignal mSignal;
public SambaProxyFileCallback(SmbFile file, ByteBufferPool bufferPool, CancellationSignal signal) {
mFile = file;
mBufferPool = bufferPool;
mBuffer = mBufferPool.obtainBuffer();
mSignal = signal;
public SambaProxyFileCallback(
SmbFile file, ByteBufferPool bufferPool, CancellationSignal signal) {
mFile = file;
mBufferPool = bufferPool;
mSignal = signal;
}
@Override
public long onGetSize() throws ErrnoException {
StructStat stat;
try {
stat = mFile.fstat();
return stat.st_size;
} catch (IOException e) {
Log.e(TAG, "Failed to get size for file", e);
}
@Override
public long onGetSize() throws ErrnoException {
StructStat stat = null;
try {
stat = mFile.fstat();
return stat.st_size;
} catch (IOException e) {
Log.e(TAG, "Failed to get size for file");
return 0;
}
@Override
public int onRead(long offset, int size, byte[] data) throws ErrnoException {
final ByteBuffer buffer = mBufferPool.obtainBuffer();
try {
mFile.seek(offset);
int readSize;
int total = 0;
while ((mSignal == null || !mSignal.isCanceled())
&& (readSize = mFile.read(buffer, size - total)) > 0) {
final int len = Math.min(size - total, readSize);
buffer.get(data, total, len);
buffer.clear();
total += len;
if (total >= size) {
break;
}
}
return 0;
return Math.min(size, total);
} catch (IOException e) {
e.printStackTrace();
} finally {
mBufferPool.recycleBuffer(buffer);
}
@Override
public int onRead(long offset, int size, byte[] data) throws ErrnoException {
try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
mFile.seek(offset);
return 0;
}
int readSize;
int total = 0;
while ((mSignal == null || !mSignal.isCanceled())
&& (readSize = mFile.read(mBuffer)) > 0) {
mBuffer.get(data, total, Math.min(size - total, readSize));
mBuffer.clear();
total += Math.min(size - total, readSize);
if (total >= size) {
break;
}
}
@Override
public int onWrite(long offset, int size, byte[] data) throws ErrnoException {
int written = 0;
return Math.min(size, total);
} catch (IOException e) {
e.printStackTrace();
}
final ByteBuffer buffer = mBufferPool.obtainBuffer();
try {
mFile.seek(offset);
return 0;
while ((mSignal == null || !mSignal.isCanceled())
&& written < size) {
int willWrite = Math.min(size - written, buffer.capacity());
buffer.put(data, written, willWrite);
int res = mFile.write(buffer, willWrite);
written += res;
buffer.clear();
}
} catch (IOException e) {
Log.e(TAG, "Failed to write file.", e);
} finally {
mBufferPool.recycleBuffer(buffer);
}
@Override
public int onWrite(long offset, int size, byte[] data) throws ErrnoException {
int written = 0;
return written;
}
try {
mFile.seek(offset);
while ((mSignal == null || !mSignal.isCanceled())
&& written < size) {
int willWrite = Math.min(size - written, mBuffer.capacity());
mBuffer.put(data, written, willWrite);
int res = mFile.write(mBuffer, willWrite);
written += res;
mBuffer.clear();
}
} catch (IOException e) {
Log.e(TAG, "Failed to write file.", e);
}
return written;
}
@Override
public void onRelease() {
mBufferPool.recycleBuffer(mBuffer);
try {
mFile.close();
} catch (IOException e) {
Log.e(TAG, "Failed to close file");
}
@Override
public void onRelease() {
try {
mFile.close();
} catch (IOException e) {
Log.e(TAG, "Failed to close file", e);
}
}
}