This source file includes following definitions.
- GeneratesUniquePathWithExtension
- PrepareForDownloadFile
- CheckPreConditionForEnsureFileDownloaded
- CheckPreConditionForEnsureFileDownloadedByLocalId
- CheckPreConditionForEnsureFileDownloadedByPath
- UpdateLocalStateForDownloadFile
- weak_ptr_factory_
- GetCancelClosure
- OnCacheFileFound
- OnStartDownloading
- OnError
- OnComplete
- get_content_callback
- entry
- was_cancelled
- Cancel
- weak_ptr_factory_
- EnsureFileDownloadedByLocalId
- EnsureFileDownloadedByPath
- EnsureFileDownloadedAfterCheckPreCondition
- EnsureFileDownloadedAfterDownloadFile
- EnsureFileDownloadedAfterUpdateLocalState
- CancelJob
#include "chrome/browser/chromeos/drive/file_system/download_operation.h"
#include "base/callback_helpers.h"
#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "base/task_runner_util.h"
#include "chrome/browser/chromeos/drive/drive.pb.h"
#include "chrome/browser/chromeos/drive/file_cache.h"
#include "chrome/browser/chromeos/drive/file_errors.h"
#include "chrome/browser/chromeos/drive/file_system/operation_observer.h"
#include "chrome/browser/chromeos/drive/file_system_util.h"
#include "chrome/browser/chromeos/drive/job_scheduler.h"
#include "chrome/browser/chromeos/drive/resource_entry_conversion.h"
#include "chrome/browser/chromeos/drive/resource_metadata.h"
#include "content/public/browser/browser_thread.h"
#include "google_apis/drive/gdata_errorcode.h"
using content::BrowserThread;
namespace drive {
namespace file_system {
namespace {
bool GeneratesUniquePathWithExtension(
const base::FilePath& dir,
const base::FilePath::StringType& extension,
base::FilePath* out_path) {
base::FilePath subdir;
if (!base::CreateTemporaryDirInDir(dir, base::FilePath::StringType(),
&subdir)) {
return false;
}
*out_path = subdir.Append(FILE_PATH_LITERAL("tmp") + extension);
return true;
}
FileError PrepareForDownloadFile(internal::FileCache* cache,
int64 expected_file_size,
const base::FilePath& temporary_file_directory,
base::FilePath* temp_download_file) {
DCHECK(cache);
DCHECK(temp_download_file);
if (!cache->FreeDiskSpaceIfNeededFor(expected_file_size))
return FILE_ERROR_NO_LOCAL_SPACE;
return base::CreateTemporaryFileInDir(
temporary_file_directory,
temp_download_file) ? FILE_ERROR_OK : FILE_ERROR_FAILED;
}
FileError CheckPreConditionForEnsureFileDownloaded(
internal::ResourceMetadata* metadata,
internal::FileCache* cache,
const base::FilePath& temporary_file_directory,
const std::string& local_id,
ResourceEntry* entry,
base::FilePath* cache_file_path,
base::FilePath* temp_download_file_path) {
DCHECK(metadata);
DCHECK(cache);
DCHECK(cache_file_path);
FileError error = metadata->GetResourceEntryById(local_id, entry);
if (error != FILE_ERROR_OK)
return error;
if (entry->file_info().is_directory())
return FILE_ERROR_NOT_A_FILE;
if (entry->file_specific_info().is_hosted_document()) {
base::FilePath::StringType extension = base::FilePath::FromUTF8Unsafe(
entry->file_specific_info().document_extension()).value();
base::FilePath gdoc_file_path;
base::File::Info file_info;
if (!GeneratesUniquePathWithExtension(temporary_file_directory,
extension,
&gdoc_file_path) ||
!util::CreateGDocFile(gdoc_file_path,
GURL(entry->file_specific_info().alternate_url()),
entry->resource_id()) ||
!base::GetFileInfo(gdoc_file_path,
reinterpret_cast<base::File::Info*>(&file_info)))
return FILE_ERROR_FAILED;
*cache_file_path = gdoc_file_path;
SetPlatformFileInfoToResourceEntry(file_info, entry);
return FILE_ERROR_OK;
}
FileCacheEntry cache_entry;
if (!cache->GetCacheEntry(local_id, &cache_entry) ||
!cache_entry.is_present()) {
if (!entry->resource_id().empty()) {
return PrepareForDownloadFile(cache, entry->file_info().size(),
temporary_file_directory,
temp_download_file_path);
}
base::FilePath empty_file;
if (!base::CreateTemporaryFileInDir(temporary_file_directory, &empty_file))
return FILE_ERROR_FAILED;
error = cache->Store(local_id, std::string(), empty_file,
internal::FileCache::FILE_OPERATION_MOVE);
if (error != FILE_ERROR_OK)
return error;
if (!cache->GetCacheEntry(local_id, &cache_entry))
return FILE_ERROR_NOT_FOUND;
}
if (!cache_entry.is_dirty() &&
entry->file_specific_info().md5() != cache_entry.md5()) {
return PrepareForDownloadFile(cache, entry->file_info().size(),
temporary_file_directory,
temp_download_file_path);
}
error = cache->GetFile(local_id, cache_file_path);
if (error != FILE_ERROR_OK)
return error;
base::File::Info file_info;
if (base::GetFileInfo(*cache_file_path, &file_info))
SetPlatformFileInfoToResourceEntry(file_info, entry);
return FILE_ERROR_OK;
}
struct CheckPreconditionForEnsureFileDownloadedParams {
internal::ResourceMetadata* metadata;
internal::FileCache* cache;
base::FilePath temporary_file_directory;
};
FileError CheckPreConditionForEnsureFileDownloadedByLocalId(
const CheckPreconditionForEnsureFileDownloadedParams& params,
const std::string& local_id,
base::FilePath* drive_file_path,
base::FilePath* cache_file_path,
base::FilePath* temp_download_file_path,
ResourceEntry* entry) {
*drive_file_path = params.metadata->GetFilePath(local_id);
return CheckPreConditionForEnsureFileDownloaded(
params.metadata, params.cache, params.temporary_file_directory, local_id,
entry, cache_file_path, temp_download_file_path);
}
FileError CheckPreConditionForEnsureFileDownloadedByPath(
const CheckPreconditionForEnsureFileDownloadedParams& params,
const base::FilePath& file_path,
base::FilePath* cache_file_path,
base::FilePath* temp_download_file_path,
ResourceEntry* entry) {
std::string local_id;
FileError error = params.metadata->GetIdByPath(file_path, &local_id);
if (error != FILE_ERROR_OK)
return error;
return CheckPreConditionForEnsureFileDownloaded(
params.metadata, params.cache, params.temporary_file_directory, local_id,
entry, cache_file_path, temp_download_file_path);
}
FileError UpdateLocalStateForDownloadFile(
internal::FileCache* cache,
const std::string& local_id,
const std::string& md5,
google_apis::GDataErrorCode gdata_error,
const base::FilePath& downloaded_file_path,
base::FilePath* cache_file_path) {
DCHECK(cache);
base::ScopedClosureRunner file_deleter(base::Bind(
base::IgnoreResult(&base::DeleteFile),
downloaded_file_path, false ));
FileError error = GDataToFileError(gdata_error);
if (error != FILE_ERROR_OK)
return error;
FileCacheEntry cache_entry;
if (cache->GetCacheEntry(local_id, &cache_entry) && cache_entry.is_dirty())
return FILE_ERROR_IN_USE;
error = cache->Store(local_id, md5, downloaded_file_path,
internal::FileCache::FILE_OPERATION_MOVE);
if (error != FILE_ERROR_OK)
return error;
base::Closure unused_file_deleter_closure = file_deleter.Release();
return cache->GetFile(local_id, cache_file_path);
}
}
class DownloadOperation::DownloadParams {
public:
DownloadParams(
const GetFileContentInitializedCallback initialized_callback,
const google_apis::GetContentCallback get_content_callback,
const GetFileCallback completion_callback,
scoped_ptr<ResourceEntry> entry)
: initialized_callback_(initialized_callback),
get_content_callback_(get_content_callback),
completion_callback_(completion_callback),
entry_(entry.Pass()),
was_cancelled_(false),
weak_ptr_factory_(this) {
DCHECK(!completion_callback_.is_null());
DCHECK(entry_);
}
base::Closure GetCancelClosure() {
return base::Bind(&DownloadParams::Cancel, weak_ptr_factory_.GetWeakPtr());
}
void OnCacheFileFound(const base::FilePath& cache_file_path) const {
if (initialized_callback_.is_null())
return;
DCHECK(entry_);
initialized_callback_.Run(FILE_ERROR_OK, cache_file_path,
make_scoped_ptr(new ResourceEntry(*entry_)));
}
void OnStartDownloading(const base::Closure& cancel_download_closure) {
cancel_download_closure_ = cancel_download_closure;
if (initialized_callback_.is_null()) {
return;
}
DCHECK(entry_);
initialized_callback_.Run(FILE_ERROR_OK, base::FilePath(),
make_scoped_ptr(new ResourceEntry(*entry_)));
}
void OnError(FileError error) const {
completion_callback_.Run(
error, base::FilePath(), scoped_ptr<ResourceEntry>());
}
void OnComplete(const base::FilePath& cache_file_path) {
completion_callback_.Run(FILE_ERROR_OK, cache_file_path, entry_.Pass());
}
const google_apis::GetContentCallback& get_content_callback() const {
return get_content_callback_;
}
const ResourceEntry& entry() const { return *entry_; }
bool was_cancelled() const { return was_cancelled_; }
private:
void Cancel() {
was_cancelled_ = true;
if (!cancel_download_closure_.is_null())
cancel_download_closure_.Run();
}
const GetFileContentInitializedCallback initialized_callback_;
const google_apis::GetContentCallback get_content_callback_;
const GetFileCallback completion_callback_;
scoped_ptr<ResourceEntry> entry_;
base::Closure cancel_download_closure_;
bool was_cancelled_;
base::WeakPtrFactory<DownloadParams> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(DownloadParams);
};
DownloadOperation::DownloadOperation(
base::SequencedTaskRunner* blocking_task_runner,
OperationObserver* observer,
JobScheduler* scheduler,
internal::ResourceMetadata* metadata,
internal::FileCache* cache,
const base::FilePath& temporary_file_directory)
: blocking_task_runner_(blocking_task_runner),
observer_(observer),
scheduler_(scheduler),
metadata_(metadata),
cache_(cache),
temporary_file_directory_(temporary_file_directory),
weak_ptr_factory_(this) {
}
DownloadOperation::~DownloadOperation() {
}
base::Closure DownloadOperation::EnsureFileDownloadedByLocalId(
const std::string& local_id,
const ClientContext& context,
const GetFileContentInitializedCallback& initialized_callback,
const google_apis::GetContentCallback& get_content_callback,
const GetFileCallback& completion_callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(!completion_callback.is_null());
CheckPreconditionForEnsureFileDownloadedParams params;
params.metadata = metadata_;
params.cache = cache_;
params.temporary_file_directory = temporary_file_directory_;
base::FilePath* drive_file_path = new base::FilePath;
base::FilePath* cache_file_path = new base::FilePath;
base::FilePath* temp_download_file_path = new base::FilePath;
ResourceEntry* entry = new ResourceEntry;
scoped_ptr<DownloadParams> download_params(new DownloadParams(
initialized_callback, get_content_callback, completion_callback,
make_scoped_ptr(entry)));
base::Closure cancel_closure = download_params->GetCancelClosure();
base::PostTaskAndReplyWithResult(
blocking_task_runner_.get(),
FROM_HERE,
base::Bind(&CheckPreConditionForEnsureFileDownloadedByLocalId,
params,
local_id,
drive_file_path,
cache_file_path,
temp_download_file_path,
entry),
base::Bind(&DownloadOperation::EnsureFileDownloadedAfterCheckPreCondition,
weak_ptr_factory_.GetWeakPtr(),
base::Passed(&download_params),
context,
base::Owned(drive_file_path),
base::Owned(cache_file_path),
base::Owned(temp_download_file_path)));
return cancel_closure;
}
base::Closure DownloadOperation::EnsureFileDownloadedByPath(
const base::FilePath& file_path,
const ClientContext& context,
const GetFileContentInitializedCallback& initialized_callback,
const google_apis::GetContentCallback& get_content_callback,
const GetFileCallback& completion_callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(!completion_callback.is_null());
CheckPreconditionForEnsureFileDownloadedParams params;
params.metadata = metadata_;
params.cache = cache_;
params.temporary_file_directory = temporary_file_directory_;
base::FilePath* drive_file_path = new base::FilePath(file_path);
base::FilePath* cache_file_path = new base::FilePath;
base::FilePath* temp_download_file_path = new base::FilePath;
ResourceEntry* entry = new ResourceEntry;
scoped_ptr<DownloadParams> download_params(new DownloadParams(
initialized_callback, get_content_callback, completion_callback,
make_scoped_ptr(entry)));
base::Closure cancel_closure = download_params->GetCancelClosure();
base::PostTaskAndReplyWithResult(
blocking_task_runner_.get(),
FROM_HERE,
base::Bind(&CheckPreConditionForEnsureFileDownloadedByPath,
params,
file_path,
cache_file_path,
temp_download_file_path,
entry),
base::Bind(&DownloadOperation::EnsureFileDownloadedAfterCheckPreCondition,
weak_ptr_factory_.GetWeakPtr(),
base::Passed(&download_params),
context,
base::Owned(drive_file_path),
base::Owned(cache_file_path),
base::Owned(temp_download_file_path)));
return cancel_closure;
}
void DownloadOperation::EnsureFileDownloadedAfterCheckPreCondition(
scoped_ptr<DownloadParams> params,
const ClientContext& context,
base::FilePath* drive_file_path,
base::FilePath* cache_file_path,
base::FilePath* temp_download_file_path,
FileError error) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(params);
DCHECK(drive_file_path);
DCHECK(cache_file_path);
if (error != FILE_ERROR_OK) {
params->OnError(error);
return;
}
if (!cache_file_path->empty()) {
params->OnCacheFileFound(*cache_file_path);
params->OnComplete(*cache_file_path);
return;
}
if (params->was_cancelled()) {
params->OnError(FILE_ERROR_ABORT);
return;
}
DCHECK(!params->entry().resource_id().empty());
DownloadParams* params_ptr = params.get();
JobID id = scheduler_->DownloadFile(
*drive_file_path,
params_ptr->entry().file_info().size(),
*temp_download_file_path,
params_ptr->entry().resource_id(),
context,
base::Bind(&DownloadOperation::EnsureFileDownloadedAfterDownloadFile,
weak_ptr_factory_.GetWeakPtr(),
*drive_file_path,
base::Passed(¶ms)),
params_ptr->get_content_callback());
params_ptr->OnStartDownloading(
base::Bind(&DownloadOperation::CancelJob,
weak_ptr_factory_.GetWeakPtr(), id));
}
void DownloadOperation::EnsureFileDownloadedAfterDownloadFile(
const base::FilePath& drive_file_path,
scoped_ptr<DownloadParams> params,
google_apis::GDataErrorCode gdata_error,
const base::FilePath& downloaded_file_path) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
const std::string& local_id = params->entry().local_id();
const std::string& md5 = params->entry().file_specific_info().md5();
base::FilePath* cache_file_path = new base::FilePath;
base::PostTaskAndReplyWithResult(
blocking_task_runner_.get(),
FROM_HERE,
base::Bind(&UpdateLocalStateForDownloadFile,
base::Unretained(cache_),
local_id,
md5,
gdata_error,
downloaded_file_path,
cache_file_path),
base::Bind(&DownloadOperation::EnsureFileDownloadedAfterUpdateLocalState,
weak_ptr_factory_.GetWeakPtr(),
drive_file_path,
base::Passed(¶ms),
base::Owned(cache_file_path)));
}
void DownloadOperation::EnsureFileDownloadedAfterUpdateLocalState(
const base::FilePath& file_path,
scoped_ptr<DownloadParams> params,
base::FilePath* cache_file_path,
FileError error) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (error != FILE_ERROR_OK) {
params->OnError(error);
return;
}
observer_->OnDirectoryChangedByOperation(file_path.DirName());
params->OnComplete(*cache_file_path);
}
void DownloadOperation::CancelJob(JobID job_id) {
scheduler_->CancelJob(job_id);
}
}
}