11e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko// Copyright 2015 The Chromium OS Authors. All rights reserved. 21e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko// Use of this source code is governed by a BSD-style license that can be 31e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko// found in the LICENSE file. 41e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko 59ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/streams/stream_utils.h> 61e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko 71e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko#include <limits> 81e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko 949fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko#include <base/bind.h> 109ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/message_loops/message_loop.h> 119ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/streams/stream_errors.h> 121e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko 139ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenkonamespace brillo { 141e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenkonamespace stream_utils { 151e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko 1649fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenkonamespace { 1749fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko 1849fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko// Status of asynchronous CopyData operation. 1949fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenkostruct CopyDataState { 209ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko brillo::StreamPtr in_stream; 219ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko brillo::StreamPtr out_stream; 2249fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko std::vector<uint8_t> buffer; 2349fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko uint64_t remaining_to_copy; 2449fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko uint64_t size_copied; 2549fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko CopyDataSuccessCallback success_callback; 2649fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko CopyDataErrorCallback error_callback; 2749fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko}; 2849fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko 2949fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko// Async CopyData I/O error callback. 3049fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenkovoid OnCopyDataError(const std::shared_ptr<CopyDataState>& state, 319ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko const brillo::Error* error) { 3249fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko state->error_callback.Run(std::move(state->in_stream), 3349fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko std::move(state->out_stream), error); 3449fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko} 3549fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko 3649fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko// Forward declaration. 3749fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenkovoid PerformRead(const std::shared_ptr<CopyDataState>& state); 3849fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko 3949fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko// Callback from read operation for CopyData. Writes the read data to the output 4049fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko// stream and invokes PerformRead when done to restart the copy cycle. 4149fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenkovoid PerformWrite(const std::shared_ptr<CopyDataState>& state, size_t size) { 4249fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko if (size == 0) { 4349fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko state->success_callback.Run(std::move(state->in_stream), 4449fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko std::move(state->out_stream), 4549fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko state->size_copied); 4649fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko return; 4749fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko } 4849fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko state->size_copied += size; 4949fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko CHECK_GE(state->remaining_to_copy, size); 5049fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko state->remaining_to_copy -= size; 5149fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko 529ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko brillo::ErrorPtr error; 5349fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko bool success = state->out_stream->WriteAllAsync( 5449fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko state->buffer.data(), size, base::Bind(&PerformRead, state), 5549fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko base::Bind(&OnCopyDataError, state), &error); 5649fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko 5749fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko if (!success) 5849fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko OnCopyDataError(state, error.get()); 5949fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko} 6049fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko 6149fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko// Performs the read part of asynchronous CopyData operation. Reads the data 6249fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko// from input stream and invokes PerformWrite when done to write the data to 6349fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko// the output stream. 6449fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenkovoid PerformRead(const std::shared_ptr<CopyDataState>& state) { 659ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko brillo::ErrorPtr error; 6649fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko const uint64_t buffer_size = state->buffer.size(); 6749fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko // |buffer_size| is guaranteed to fit in size_t, so |size_to_read| value will 6849fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko // also not overflow size_t, so the static_cast below is safe. 6949fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko size_t size_to_read = 7049fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko static_cast<size_t>(std::min(buffer_size, state->remaining_to_copy)); 7149fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko if (size_to_read == 0) 7249fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko return PerformWrite(state, 0); // Nothing more to read. Finish operation. 7349fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko bool success = state->in_stream->ReadAsync( 7449fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko state->buffer.data(), size_to_read, base::Bind(PerformWrite, state), 7549fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko base::Bind(OnCopyDataError, state), &error); 7649fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko 7749fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko if (!success) 7849fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko OnCopyDataError(state, error.get()); 7949fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko} 8049fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko 8149fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko} // anonymous namespace 8249fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko 831e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenkobool ErrorStreamClosed(const tracked_objects::Location& location, 841e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko ErrorPtr* error) { 851e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko Error::AddTo(error, 861e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko location, 871e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko errors::stream::kDomain, 881e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko errors::stream::kStreamClosed, 891e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko "Stream is closed"); 901e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko return false; 911e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko} 921e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko 931e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenkobool ErrorOperationNotSupported(const tracked_objects::Location& location, 941e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko ErrorPtr* error) { 951e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko Error::AddTo(error, 961e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko location, 971e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko errors::stream::kDomain, 981e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko errors::stream::kOperationNotSupported, 991e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko "Stream operation not supported"); 1001e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko return false; 1011e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko} 1021e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko 1031e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenkobool ErrorReadPastEndOfStream(const tracked_objects::Location& location, 1041e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko ErrorPtr* error) { 1051e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko Error::AddTo(error, 1061e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko location, 1071e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko errors::stream::kDomain, 1081e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko errors::stream::kPartialData, 1091e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko "Reading past the end of stream"); 1101e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko return false; 1111e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko} 1121e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko 1131b79239785bf964fd5f1a607a6ed9c9bbb57a4b1Alex Vakulenkobool ErrorOperationTimeout(const tracked_objects::Location& location, 1141b79239785bf964fd5f1a607a6ed9c9bbb57a4b1Alex Vakulenko ErrorPtr* error) { 1151b79239785bf964fd5f1a607a6ed9c9bbb57a4b1Alex Vakulenko Error::AddTo(error, 1161b79239785bf964fd5f1a607a6ed9c9bbb57a4b1Alex Vakulenko location, 1171b79239785bf964fd5f1a607a6ed9c9bbb57a4b1Alex Vakulenko errors::stream::kDomain, 1181b79239785bf964fd5f1a607a6ed9c9bbb57a4b1Alex Vakulenko errors::stream::kTimeout, 1191b79239785bf964fd5f1a607a6ed9c9bbb57a4b1Alex Vakulenko "Operation timed out"); 1201b79239785bf964fd5f1a607a6ed9c9bbb57a4b1Alex Vakulenko return false; 1211b79239785bf964fd5f1a607a6ed9c9bbb57a4b1Alex Vakulenko} 1221b79239785bf964fd5f1a607a6ed9c9bbb57a4b1Alex Vakulenko 1231e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenkobool CheckInt64Overflow(const tracked_objects::Location& location, 1241e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko uint64_t position, 1251e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko int64_t offset, 1261e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko ErrorPtr* error) { 1271e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko if (offset < 0) { 1281e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko // Subtracting the offset. Make sure we do not underflow. 1291e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko uint64_t unsigned_offset = static_cast<uint64_t>(-offset); 1301e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko if (position >= unsigned_offset) 1311e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko return true; 1321e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko } else { 1331e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko // Adding the offset. Make sure we do not overflow unsigned 64 bits first. 1341e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko if (position <= std::numeric_limits<uint64_t>::max() - offset) { 1351e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko // We definitely will not overflow the unsigned 64 bit integer. 1361e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko // Now check that we end up within the limits of signed 64 bit integer. 1371e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko uint64_t new_position = position + offset; 1381e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko uint64_t max = std::numeric_limits<int64_t>::max(); 1391e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko if (new_position <= max) 1401e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko return true; 1411e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko } 1421e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko } 1431e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko Error::AddTo(error, 1441e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko location, 1451e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko errors::stream::kDomain, 1461e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko errors::stream::kInvalidParameter, 1471e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko "The stream offset value is out of range"); 1481e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko return false; 1491e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko} 1501e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko 1511e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenkobool CalculateStreamPosition(const tracked_objects::Location& location, 1521e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko int64_t offset, 1531e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko Stream::Whence whence, 1541e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko uint64_t current_position, 1551e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko uint64_t stream_size, 1561e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko uint64_t* new_position, 1571e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko ErrorPtr* error) { 1581e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko uint64_t pos = 0; 1591e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko switch (whence) { 1601e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko case Stream::Whence::FROM_BEGIN: 1611e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko pos = 0; 1621e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko break; 1631e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko 1641e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko case Stream::Whence::FROM_CURRENT: 1651e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko pos = current_position; 1661e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko break; 1671e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko 1681e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko case Stream::Whence::FROM_END: 1691e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko pos = stream_size; 1701e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko break; 1711e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko 1721e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko default: 1731e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko Error::AddTo(error, 1741e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko location, 1751e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko errors::stream::kDomain, 1761e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko errors::stream::kInvalidParameter, 1771e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko "Invalid stream position whence"); 1781e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko return false; 1791e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko } 1801e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko 1811e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko if (!CheckInt64Overflow(location, pos, offset, error)) 1821e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko return false; 1831e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko 1841e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko *new_position = static_cast<uint64_t>(pos + offset); 1851e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko return true; 1861e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko} 1871e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko 18849fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenkovoid CopyData(StreamPtr in_stream, 18949fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko StreamPtr out_stream, 19049fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko const CopyDataSuccessCallback& success_callback, 19149fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko const CopyDataErrorCallback& error_callback) { 19249fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko CopyData(std::move(in_stream), std::move(out_stream), 19349fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko std::numeric_limits<uint64_t>::max(), 4096, success_callback, 19449fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko error_callback); 19549fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko} 19649fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko 19749fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenkovoid CopyData(StreamPtr in_stream, 19849fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko StreamPtr out_stream, 19949fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko uint64_t max_size_to_copy, 20049fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko size_t buffer_size, 20149fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko const CopyDataSuccessCallback& success_callback, 20249fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko const CopyDataErrorCallback& error_callback) { 20349fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko auto state = std::make_shared<CopyDataState>(); 20449fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko state->in_stream = std::move(in_stream); 20549fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko state->out_stream = std::move(out_stream); 20649fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko state->buffer.resize(buffer_size); 20749fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko state->remaining_to_copy = max_size_to_copy; 20849fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko state->size_copied = 0; 20949fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko state->success_callback = success_callback; 21049fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko state->error_callback = error_callback; 2119ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko brillo::MessageLoop::current()->PostTask(FROM_HERE, 21249fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko base::Bind(&PerformRead, state)); 21349fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko} 21449fb1ce7956110497bd7cad33b3a954faca4b77cAlex Vakulenko 2151e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko} // namespace stream_utils 2169ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko} // namespace brillo 217