mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-11-24 14:26:09 +03:00
248 lines
7.6 KiB
C++
248 lines
7.6 KiB
C++
|
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style license that can be
|
||
|
// found in the LICENSE file.
|
||
|
|
||
|
#include "net/base/file_stream_context.h"
|
||
|
|
||
|
#include <utility>
|
||
|
|
||
|
#include "base/files/file_path.h"
|
||
|
#include "base/location.h"
|
||
|
#include "base/task_runner.h"
|
||
|
#include "base/task_runner_util.h"
|
||
|
#include "base/threading/thread_restrictions.h"
|
||
|
#include "base/values.h"
|
||
|
#include "net/base/net_errors.h"
|
||
|
|
||
|
#if defined(OS_ANDROID)
|
||
|
#include "base/android/content_uri_utils.h"
|
||
|
#endif
|
||
|
|
||
|
namespace net {
|
||
|
|
||
|
namespace {
|
||
|
|
||
|
void CallInt64ToInt(CompletionOnceCallback callback, int64_t result) {
|
||
|
std::move(callback).Run(static_cast<int>(result));
|
||
|
}
|
||
|
|
||
|
} // namespace
|
||
|
|
||
|
FileStream::Context::IOResult::IOResult()
|
||
|
: result(OK),
|
||
|
os_error(0) {
|
||
|
}
|
||
|
|
||
|
FileStream::Context::IOResult::IOResult(int64_t result,
|
||
|
logging::SystemErrorCode os_error)
|
||
|
: result(result), os_error(os_error) {
|
||
|
}
|
||
|
|
||
|
// static
|
||
|
FileStream::Context::IOResult FileStream::Context::IOResult::FromOSError(
|
||
|
logging::SystemErrorCode os_error) {
|
||
|
return IOResult(MapSystemError(os_error), os_error);
|
||
|
}
|
||
|
|
||
|
// ---------------------------------------------------------------------
|
||
|
|
||
|
FileStream::Context::OpenResult::OpenResult() = default;
|
||
|
|
||
|
FileStream::Context::OpenResult::OpenResult(base::File file,
|
||
|
IOResult error_code)
|
||
|
: file(std::move(file)), error_code(error_code) {}
|
||
|
|
||
|
FileStream::Context::OpenResult::OpenResult(OpenResult&& other)
|
||
|
: file(std::move(other.file)), error_code(other.error_code) {}
|
||
|
|
||
|
FileStream::Context::OpenResult& FileStream::Context::OpenResult::operator=(
|
||
|
OpenResult&& other) {
|
||
|
file = std::move(other.file);
|
||
|
error_code = other.error_code;
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
// ---------------------------------------------------------------------
|
||
|
|
||
|
void FileStream::Context::Orphan() {
|
||
|
DCHECK(!orphaned_);
|
||
|
|
||
|
orphaned_ = true;
|
||
|
|
||
|
if (!async_in_progress_) {
|
||
|
CloseAndDelete();
|
||
|
} else if (file_.IsValid()) {
|
||
|
#if defined(OS_WIN)
|
||
|
CancelIo(file_.GetPlatformFile());
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void FileStream::Context::Open(const base::FilePath& path,
|
||
|
int open_flags,
|
||
|
CompletionOnceCallback callback) {
|
||
|
DCHECK(!async_in_progress_);
|
||
|
|
||
|
bool posted = base::PostTaskAndReplyWithResult(
|
||
|
task_runner_.get(), FROM_HERE,
|
||
|
base::BindOnce(&Context::OpenFileImpl, base::Unretained(this), path,
|
||
|
open_flags),
|
||
|
base::BindOnce(&Context::OnOpenCompleted, base::Unretained(this),
|
||
|
std::move(callback)));
|
||
|
DCHECK(posted);
|
||
|
|
||
|
async_in_progress_ = true;
|
||
|
}
|
||
|
|
||
|
void FileStream::Context::Close(CompletionOnceCallback callback) {
|
||
|
DCHECK(!async_in_progress_);
|
||
|
|
||
|
bool posted = base::PostTaskAndReplyWithResult(
|
||
|
task_runner_.get(), FROM_HERE,
|
||
|
base::BindOnce(&Context::CloseFileImpl, base::Unretained(this)),
|
||
|
base::BindOnce(&Context::OnAsyncCompleted, base::Unretained(this),
|
||
|
IntToInt64(std::move(callback))));
|
||
|
DCHECK(posted);
|
||
|
|
||
|
async_in_progress_ = true;
|
||
|
}
|
||
|
|
||
|
void FileStream::Context::Seek(int64_t offset,
|
||
|
Int64CompletionOnceCallback callback) {
|
||
|
DCHECK(!async_in_progress_);
|
||
|
|
||
|
bool posted = base::PostTaskAndReplyWithResult(
|
||
|
task_runner_.get(), FROM_HERE,
|
||
|
base::BindOnce(&Context::SeekFileImpl, base::Unretained(this), offset),
|
||
|
base::BindOnce(&Context::OnAsyncCompleted, base::Unretained(this),
|
||
|
std::move(callback)));
|
||
|
DCHECK(posted);
|
||
|
|
||
|
async_in_progress_ = true;
|
||
|
}
|
||
|
|
||
|
void FileStream::Context::GetFileInfo(base::File::Info* file_info,
|
||
|
CompletionOnceCallback callback) {
|
||
|
base::PostTaskAndReplyWithResult(
|
||
|
task_runner_.get(), FROM_HERE,
|
||
|
base::BindOnce(&Context::GetFileInfoImpl, base::Unretained(this),
|
||
|
base::Unretained(file_info)),
|
||
|
base::BindOnce(&Context::OnAsyncCompleted, base::Unretained(this),
|
||
|
IntToInt64(std::move(callback))));
|
||
|
|
||
|
async_in_progress_ = true;
|
||
|
}
|
||
|
|
||
|
void FileStream::Context::Flush(CompletionOnceCallback callback) {
|
||
|
DCHECK(!async_in_progress_);
|
||
|
|
||
|
bool posted = base::PostTaskAndReplyWithResult(
|
||
|
task_runner_.get(), FROM_HERE,
|
||
|
base::BindOnce(&Context::FlushFileImpl, base::Unretained(this)),
|
||
|
base::BindOnce(&Context::OnAsyncCompleted, base::Unretained(this),
|
||
|
IntToInt64(std::move(callback))));
|
||
|
DCHECK(posted);
|
||
|
|
||
|
async_in_progress_ = true;
|
||
|
}
|
||
|
|
||
|
bool FileStream::Context::IsOpen() const {
|
||
|
return file_.IsValid();
|
||
|
}
|
||
|
|
||
|
FileStream::Context::OpenResult FileStream::Context::OpenFileImpl(
|
||
|
const base::FilePath& path, int open_flags) {
|
||
|
#if defined(OS_POSIX)
|
||
|
// Always use blocking IO.
|
||
|
open_flags &= ~base::File::FLAG_ASYNC;
|
||
|
#endif
|
||
|
base::File file;
|
||
|
#if defined(OS_ANDROID)
|
||
|
if (path.IsContentUri()) {
|
||
|
// Check that only Read flags are set.
|
||
|
DCHECK_EQ(open_flags & ~base::File::FLAG_ASYNC,
|
||
|
base::File::FLAG_OPEN | base::File::FLAG_READ);
|
||
|
file = base::OpenContentUriForRead(path);
|
||
|
} else {
|
||
|
#endif // defined(OS_ANDROID)
|
||
|
// FileStream::Context actually closes the file asynchronously,
|
||
|
// independently from FileStream's destructor. It can cause problems for
|
||
|
// users wanting to delete the file right after FileStream deletion. Thus
|
||
|
// we are always adding SHARE_DELETE flag to accommodate such use case.
|
||
|
// TODO(rvargas): This sounds like a bug, as deleting the file would
|
||
|
// presumably happen on the wrong thread. There should be an async delete.
|
||
|
open_flags |= base::File::FLAG_SHARE_DELETE;
|
||
|
file.Initialize(path, open_flags);
|
||
|
#if defined(OS_ANDROID)
|
||
|
}
|
||
|
#endif // defined(OS_ANDROID)
|
||
|
if (!file.IsValid()) {
|
||
|
return OpenResult(base::File(),
|
||
|
IOResult::FromOSError(logging::GetLastSystemErrorCode()));
|
||
|
}
|
||
|
|
||
|
return OpenResult(std::move(file), IOResult(OK, 0));
|
||
|
}
|
||
|
|
||
|
FileStream::Context::IOResult FileStream::Context::GetFileInfoImpl(
|
||
|
base::File::Info* file_info) {
|
||
|
bool result = file_.GetInfo(file_info);
|
||
|
if (!result)
|
||
|
return IOResult::FromOSError(logging::GetLastSystemErrorCode());
|
||
|
return IOResult(OK, 0);
|
||
|
}
|
||
|
|
||
|
FileStream::Context::IOResult FileStream::Context::CloseFileImpl() {
|
||
|
file_.Close();
|
||
|
return IOResult(OK, 0);
|
||
|
}
|
||
|
|
||
|
FileStream::Context::IOResult FileStream::Context::FlushFileImpl() {
|
||
|
if (file_.Flush())
|
||
|
return IOResult(OK, 0);
|
||
|
|
||
|
return IOResult::FromOSError(logging::GetLastSystemErrorCode());
|
||
|
}
|
||
|
|
||
|
void FileStream::Context::OnOpenCompleted(CompletionOnceCallback callback,
|
||
|
OpenResult open_result) {
|
||
|
file_ = std::move(open_result.file);
|
||
|
if (file_.IsValid() && !orphaned_)
|
||
|
OnFileOpened();
|
||
|
|
||
|
OnAsyncCompleted(IntToInt64(std::move(callback)), open_result.error_code);
|
||
|
}
|
||
|
|
||
|
void FileStream::Context::CloseAndDelete() {
|
||
|
DCHECK(!async_in_progress_);
|
||
|
|
||
|
if (file_.IsValid()) {
|
||
|
bool posted = task_runner_.get()->PostTask(
|
||
|
FROM_HERE, base::BindOnce(base::IgnoreResult(&Context::CloseFileImpl),
|
||
|
base::Owned(this)));
|
||
|
DCHECK(posted);
|
||
|
} else {
|
||
|
delete this;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Int64CompletionOnceCallback FileStream::Context::IntToInt64(
|
||
|
CompletionOnceCallback callback) {
|
||
|
return base::BindOnce(&CallInt64ToInt, std::move(callback));
|
||
|
}
|
||
|
|
||
|
void FileStream::Context::OnAsyncCompleted(Int64CompletionOnceCallback callback,
|
||
|
const IOResult& result) {
|
||
|
// Reset this before Run() as Run() may issue a new async operation. Also it
|
||
|
// should be reset before Close() because it shouldn't run if any async
|
||
|
// operation is in progress.
|
||
|
async_in_progress_ = false;
|
||
|
if (orphaned_) {
|
||
|
CloseAndDelete();
|
||
|
} else {
|
||
|
std::move(callback).Run(result.result);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} // namespace net
|