1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/chromeos/file_system_provider/operations/read_file.h"
6
7#include <limits>
8#include <string>
9
10#include "base/debug/trace_event.h"
11#include "chrome/common/extensions/api/file_system_provider.h"
12#include "chrome/common/extensions/api/file_system_provider_internal.h"
13
14namespace chromeos {
15namespace file_system_provider {
16namespace operations {
17namespace {
18
19// Convert |value| into |output|. If parsing fails, then returns a negative
20// value. Otherwise returns number of bytes written to the buffer.
21int CopyRequestValueToBuffer(scoped_ptr<RequestValue> value,
22                             scoped_refptr<net::IOBuffer> buffer,
23                             int buffer_offset,
24                             int buffer_length) {
25  using extensions::api::file_system_provider_internal::
26      ReadFileRequestedSuccess::Params;
27
28  const Params* params = value->read_file_success_params();
29  if (!params)
30    return -1;
31
32  const size_t chunk_size = params->data.length();
33
34  // Check for overflows.
35  if (chunk_size > static_cast<size_t>(buffer_length) - buffer_offset)
36    return -1;
37
38  memcpy(buffer->data() + buffer_offset, params->data.c_str(), chunk_size);
39
40  return chunk_size;
41}
42
43}  // namespace
44
45ReadFile::ReadFile(
46    extensions::EventRouter* event_router,
47    const ProvidedFileSystemInfo& file_system_info,
48    int file_handle,
49    scoped_refptr<net::IOBuffer> buffer,
50    int64 offset,
51    int length,
52    const ProvidedFileSystemInterface::ReadChunkReceivedCallback& callback)
53    : Operation(event_router, file_system_info),
54      file_handle_(file_handle),
55      buffer_(buffer),
56      offset_(offset),
57      length_(length),
58      current_offset_(0),
59      callback_(callback) {
60}
61
62ReadFile::~ReadFile() {
63}
64
65bool ReadFile::Execute(int request_id) {
66  using extensions::api::file_system_provider::ReadFileRequestedOptions;
67  TRACE_EVENT0("file_system_provider", "ReadFile::Execute");
68
69  ReadFileRequestedOptions options;
70  options.file_system_id = file_system_info_.file_system_id();
71  options.request_id = request_id;
72  options.open_request_id = file_handle_;
73  options.offset = offset_;
74  options.length = length_;
75
76  return SendEvent(
77      request_id,
78      extensions::api::file_system_provider::OnReadFileRequested::kEventName,
79      extensions::api::file_system_provider::OnReadFileRequested::Create(
80          options));
81}
82
83void ReadFile::OnSuccess(int /* request_id */,
84                         scoped_ptr<RequestValue> result,
85                         bool has_more) {
86  TRACE_EVENT0("file_system_provider", "ReadFile::OnSuccess");
87  const int copy_result = CopyRequestValueToBuffer(
88      result.Pass(), buffer_, current_offset_, length_);
89
90  if (copy_result < 0) {
91    LOG(ERROR) << "Failed to parse a response for the read file operation.";
92    callback_.Run(
93        0 /* chunk_length */, false /* has_more */, base::File::FILE_ERROR_IO);
94    return;
95  }
96
97  if (copy_result > 0)
98    current_offset_ += copy_result;
99  callback_.Run(copy_result, has_more, base::File::FILE_OK);
100}
101
102void ReadFile::OnError(int /* request_id */,
103                       scoped_ptr<RequestValue> /* result */,
104                       base::File::Error error) {
105  TRACE_EVENT0("file_system_provider", "ReadFile::OnError");
106  callback_.Run(0 /* chunk_length */, false /* has_more */, error);
107}
108
109}  // namespace operations
110}  // namespace file_system_provider
111}  // namespace chromeos
112