blob: 3e1bedce49ea8d48b0c3bdfdda98cda6cf76f971 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.mtp;
import android.content.Context;
import android.mtp.MtpObjectInfo;
import android.os.ParcelFileDescriptor;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
import com.android.internal.util.Preconditions;
import java.io.File;
import java.io.IOException;
class MtpFileWriter implements AutoCloseable {
final ParcelFileDescriptor mCacheFd;
final String mDocumentId;
boolean mDirty;
MtpFileWriter(Context context, String documentId) throws IOException {
mDocumentId = documentId;
mDirty = false;
final File tempFile = File.createTempFile("mtp", "tmp", context.getCacheDir());
mCacheFd = ParcelFileDescriptor.open(
tempFile,
ParcelFileDescriptor.MODE_READ_WRITE |
ParcelFileDescriptor.MODE_TRUNCATE |
ParcelFileDescriptor.MODE_CREATE);
tempFile.delete();
}
String getDocumentId() {
return mDocumentId;
}
int write(long offset, int size, byte[] bytes) throws IOException, ErrnoException {
Preconditions.checkArgumentNonnegative(offset, "offset");
Preconditions.checkArgumentNonnegative(size, "size");
Preconditions.checkArgument(size <= bytes.length);
if (size == 0) {
return 0;
}
mDirty = true;
Os.lseek(mCacheFd.getFileDescriptor(), offset, OsConstants.SEEK_SET);
return Os.write(mCacheFd.getFileDescriptor(), bytes, 0, size);
}
void flush(MtpManager manager, MtpDatabase database, int[] operationsSupported)
throws IOException, ErrnoException {
// Skip unnecessary flush.
if (!mDirty) {
return;
}
// Get the placeholder object info.
final Identifier identifier = database.createIdentifier(mDocumentId);
final MtpObjectInfo placeholderObjectInfo =
manager.getObjectInfo(identifier.mDeviceId, identifier.mObjectHandle);
// Delete the target object info if it already exists (as a placeholder).
manager.deleteDocument(identifier.mDeviceId, identifier.mObjectHandle);
// Create the target object info with a correct file size and upload the file.
final long size = Os.lseek(mCacheFd.getFileDescriptor(), 0, OsConstants.SEEK_END);
final MtpObjectInfo targetObjectInfo = new MtpObjectInfo.Builder(placeholderObjectInfo)
.setCompressedSize(size)
.build();
Os.lseek(mCacheFd.getFileDescriptor(), 0, OsConstants.SEEK_SET);
final int newObjectHandle = manager.createDocument(
identifier.mDeviceId, targetObjectInfo, mCacheFd);
final MtpObjectInfo newObjectInfo = manager.getObjectInfo(
identifier.mDeviceId, newObjectHandle);
final Identifier parentIdentifier =
database.getParentIdentifier(identifier.mDocumentId);
database.updateObject(
identifier.mDocumentId,
identifier.mDeviceId,
parentIdentifier.mDocumentId,
operationsSupported,
newObjectInfo,
size);
mDirty = false;
}
@Override
public void close() throws IOException {
mCacheFd.close();
}
}