Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(87)

Unified Diff: chrome/browser/chromeos/arc/fileapi/arc_content_file_system_file_stream_reader.cc

Issue 2551913004: arc: Implement ArcContentFileSystemFileStreamReader offset handling (Closed)
Patch Set: constexpr Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/chromeos/arc/fileapi/arc_content_file_system_file_stream_reader.cc
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_file_stream_reader.cc b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_file_stream_reader.cc
index a43f395285495488e4e70d6437de1002574715bf..a1302df9667a533f420f2e0ab9d20ebd5a7c4597 100644
--- a/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_file_stream_reader.cc
+++ b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_file_stream_reader.cc
@@ -4,10 +4,14 @@
#include "chrome/browser/chromeos/arc/fileapi/arc_content_file_system_file_stream_reader.h"
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/files/file.h"
+#include "base/threading/thread_restrictions.h"
#include "chrome/browser/chromeos/arc/fileapi/arc_file_system_instance_util.h"
#include "content/public/browser/browser_thread.h"
#include "mojo/edk/embedder/embedder.h"
-#include "net/base/file_stream.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
@@ -15,9 +19,19 @@ namespace arc {
namespace {
-void OnGetFileSize(const net::Int64CompletionCallback& callback, int64_t size) {
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- callback.Run(size < 0 ? net::ERR_FAILED : size);
+// Calls base::File::ReadAtCurrentPosNoBestEffort with the given buffer.
+int ReadFile(base::File* file,
+ scoped_refptr<net::IOBuffer> buffer,
+ int buffer_length) {
+ return file->ReadAtCurrentPosNoBestEffort(buffer->data(), buffer_length);
+}
+
+// Seeks the file, returns 0 on success, or errno on an error.
+int SeekFile(base::File* file, size_t offset) {
+ base::ThreadRestrictions::AssertIOAllowed();
+ // lseek() instead of |file|'s method for errno.
+ off_t result = lseek(file->GetPlatformFile(), offset, SEEK_SET);
+ return result < 0 ? errno : 0;
}
} // namespace
@@ -25,24 +39,28 @@ void OnGetFileSize(const net::Int64CompletionCallback& callback, int64_t size) {
ArcContentFileSystemFileStreamReader::ArcContentFileSystemFileStreamReader(
const GURL& arc_url,
int64_t offset)
- : arc_url_(arc_url), offset_(offset), weak_ptr_factory_(this) {}
+ : arc_url_(arc_url), offset_(offset), weak_ptr_factory_(this) {
+ auto* blocking_pool = content::BrowserThread::GetBlockingPool();
+ task_runner_ = blocking_pool->GetSequencedTaskRunnerWithShutdownBehavior(
+ blocking_pool->GetSequenceToken(),
+ base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+}
-ArcContentFileSystemFileStreamReader::~ArcContentFileSystemFileStreamReader() =
- default;
+ArcContentFileSystemFileStreamReader::~ArcContentFileSystemFileStreamReader() {
+ // Use the task runner to destruct |file_| after the completion of all
+ // in-flight operations.
+ task_runner_->PostTask(
+ FROM_HERE, base::Bind(&base::DeletePointer<base::File>, file_.release()));
+}
int ArcContentFileSystemFileStreamReader::Read(
net::IOBuffer* buffer,
int buffer_length,
const net::CompletionCallback& callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- if (file_stream_)
- return file_stream_->Read(buffer, buffer_length, callback);
-
- if (offset_ != 0) {
- // TODO(hashimoto): Handle offset_ != 0 cases.
- NOTIMPLEMENTED() << "Non-zero offset is not supported yet: offset_ = "
- << offset_;
- return net::ERR_FAILED;
+ if (file_) {
+ ReadInternal(buffer, buffer_length, callback);
+ return net::ERR_IO_PENDING;
}
file_system_instance_util::OpenFileToReadOnIOThread(
arc_url_,
@@ -56,16 +74,47 @@ int64_t ArcContentFileSystemFileStreamReader::GetLength(
const net::Int64CompletionCallback& callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
file_system_instance_util::GetFileSizeOnIOThread(
- arc_url_, base::Bind(&OnGetFileSize, callback));
+ arc_url_, base::Bind(&ArcContentFileSystemFileStreamReader::OnGetFileSize,
+ weak_ptr_factory_.GetWeakPtr(), callback));
return net::ERR_IO_PENDING;
}
+void ArcContentFileSystemFileStreamReader::ReadInternal(
+ net::IOBuffer* buffer,
+ int buffer_length,
+ const net::CompletionCallback& callback) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ DCHECK(file_);
+ DCHECK(file_->IsValid());
+ base::PostTaskAndReplyWithResult(
+ task_runner_.get(), FROM_HERE,
+ base::Bind(&ReadFile, file_.get(), make_scoped_refptr(buffer),
+ buffer_length),
+ base::Bind(&ArcContentFileSystemFileStreamReader::OnRead,
+ weak_ptr_factory_.GetWeakPtr(), callback));
+}
+
+void ArcContentFileSystemFileStreamReader::OnRead(
+ const net::CompletionCallback& callback,
+ int result) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ callback.Run(result < 0 ? net::ERR_FAILED : result);
+}
+
+void ArcContentFileSystemFileStreamReader::OnGetFileSize(
+ const net::Int64CompletionCallback& callback,
+ int64_t size) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ callback.Run(size < 0 ? net::ERR_FAILED : size);
+}
+
void ArcContentFileSystemFileStreamReader::OnOpenFile(
scoped_refptr<net::IOBuffer> buf,
int buffer_length,
const net::CompletionCallback& callback,
mojo::ScopedHandle handle) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ DCHECK(!file_);
mojo::edk::ScopedPlatformHandle platform_handle;
if (mojo::edk::PassWrappedPlatformHandle(
@@ -74,18 +123,90 @@ void ArcContentFileSystemFileStreamReader::OnOpenFile(
callback.Run(net::ERR_FAILED);
return;
}
- base::File file(platform_handle.release().handle);
- if (!file.IsValid()) {
+ file_.reset(new base::File(platform_handle.release().handle));
+ if (!file_->IsValid()) {
LOG(ERROR) << "Invalid file.";
callback.Run(net::ERR_FAILED);
return;
}
- file_stream_.reset(new net::FileStream(
- std::move(file), content::BrowserThread::GetBlockingPool()));
- // Resume Read().
- int result = Read(buf.get(), buffer_length, callback);
- if (result != net::ERR_IO_PENDING)
- callback.Run(result);
+ base::PostTaskAndReplyWithResult(
+ task_runner_.get(), FROM_HERE,
+ base::Bind(&SeekFile, file_.get(), offset_),
+ base::Bind(&ArcContentFileSystemFileStreamReader::OnSeekFile,
+ weak_ptr_factory_.GetWeakPtr(), buf, buffer_length, callback));
+}
+
+void ArcContentFileSystemFileStreamReader::OnSeekFile(
+ scoped_refptr<net::IOBuffer> buf,
+ int buffer_length,
+ const net::CompletionCallback& callback,
+ int seek_result) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ DCHECK(file_);
+ DCHECK(file_->IsValid());
+ switch (seek_result) {
+ case 0:
+ // File stream is ready. Resume Read().
+ ReadInternal(buf.get(), buffer_length, callback);
+ break;
+ case ESPIPE: {
+ // Pipe is not seekable. Just consume the contents.
+ const size_t kTemporaryBufferSize = 1024 * 1024;
+ auto temporary_buffer =
+ make_scoped_refptr(new net::IOBufferWithSize(kTemporaryBufferSize));
+ ConsumeFileContents(buf, buffer_length, callback, temporary_buffer,
+ offset_);
+ break;
+ }
+ default:
+ LOG(ERROR) << "Failed to seek: " << seek_result;
+ callback.Run(net::FileErrorToNetError(
+ base::File::OSErrorToFileError(seek_result)));
+ }
+}
+
+void ArcContentFileSystemFileStreamReader::ConsumeFileContents(
+ scoped_refptr<net::IOBuffer> buf,
+ int buffer_length,
+ const net::CompletionCallback& callback,
+ scoped_refptr<net::IOBufferWithSize> temporary_buffer,
+ int64_t num_bytes_to_consume) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ DCHECK(file_);
+ DCHECK(file_->IsValid());
+ if (num_bytes_to_consume == 0) {
+ // File stream is ready. Resume Read().
+ ReadInternal(buf.get(), buffer_length, callback);
+ return;
+ }
+ auto num_bytes_to_read = std::min(
+ static_cast<int64_t>(temporary_buffer->size()), num_bytes_to_consume);
+ // TODO(hashimoto): This may block the worker thread forever. crbug.com/673222
+ base::PostTaskAndReplyWithResult(
+ task_runner_.get(), FROM_HERE,
+ base::Bind(&ReadFile, file_.get(), temporary_buffer, num_bytes_to_read),
+ base::Bind(&ArcContentFileSystemFileStreamReader::OnConsumeFileContents,
+ weak_ptr_factory_.GetWeakPtr(), buf, buffer_length, callback,
+ temporary_buffer, num_bytes_to_consume));
+}
+
+void ArcContentFileSystemFileStreamReader::OnConsumeFileContents(
+ scoped_refptr<net::IOBuffer> buf,
+ int buffer_length,
+ const net::CompletionCallback& callback,
+ scoped_refptr<net::IOBufferWithSize> temporary_buffer,
+ int64_t num_bytes_to_consume,
+ int read_result) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ if (read_result < 0) {
+ LOG(ERROR) << "Failed to consume the file stream.";
+ callback.Run(net::ERR_FAILED);
+ return;
+ }
+ DCHECK_GE(num_bytes_to_consume, read_result);
+ num_bytes_to_consume -= read_result;
+ ConsumeFileContents(buf, buffer_length, callback, temporary_buffer,
+ num_bytes_to_consume);
}
} // namespace arc

Powered by Google App Engine
This is Rietveld 408576698