1 // Copyright (c) 2012 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.
5 #include "chrome/browser/chromeos/drive/file_system/update_operation.h"
7 #include "base/platform_file.h"
8 #include "chrome/browser/chromeos/drive/drive.pb.h"
9 #include "chrome/browser/chromeos/drive/file_cache.h"
10 #include "chrome/browser/chromeos/drive/file_system/operation_observer.h"
11 #include "chrome/browser/chromeos/drive/file_system_util.h"
12 #include "chrome/browser/chromeos/drive/job_scheduler.h"
13 #include "chrome/browser/chromeos/drive/resource_entry_conversion.h"
14 #include "chrome/browser/chromeos/drive/resource_metadata.h"
15 #include "chrome/browser/drive/drive_api_util.h"
16 #include "content/public/browser/browser_thread.h"
18 using content::BrowserThread
;
21 namespace file_system
{
23 struct UpdateOperation::LocalState
{
24 LocalState() : content_is_same(false) {
29 base::FilePath drive_file_path
;
30 base::FilePath cache_file_path
;
36 // Gets locally stored information about the specified file.
37 FileError
GetFileLocalState(internal::ResourceMetadata
* metadata
,
38 internal::FileCache
* cache
,
39 UpdateOperation::ContentCheckMode check
,
40 UpdateOperation::LocalState
* local_state
) {
41 FileError error
= metadata
->GetResourceEntryById(local_state
->local_id
,
43 if (error
!= FILE_ERROR_OK
)
46 if (local_state
->entry
.file_info().is_directory())
47 return FILE_ERROR_NOT_A_FILE
;
49 local_state
->drive_file_path
= metadata
->GetFilePath(local_state
->local_id
);
50 if (local_state
->drive_file_path
.empty())
51 return FILE_ERROR_NOT_FOUND
;
53 error
= cache
->GetFile(local_state
->local_id
, &local_state
->cache_file_path
);
54 if (error
!= FILE_ERROR_OK
)
57 if (check
== UpdateOperation::RUN_CONTENT_CHECK
) {
58 const std::string
& md5
= util::GetMd5Digest(local_state
->cache_file_path
);
59 local_state
->content_is_same
=
60 (md5
== local_state
->entry
.file_specific_info().md5());
61 if (local_state
->content_is_same
)
62 cache
->ClearDirty(local_state
->local_id
, md5
);
64 local_state
->content_is_same
= false;
70 // Updates locally stored information about the specified file.
71 FileError
UpdateFileLocalState(
72 internal::ResourceMetadata
* metadata
,
73 internal::FileCache
* cache
,
74 const std::string
& local_id
,
75 scoped_ptr
<google_apis::ResourceEntry
> resource_entry
,
76 base::FilePath
* drive_file_path
) {
77 ResourceEntry existing_entry
;
78 FileError error
= metadata
->GetResourceEntryById(local_id
, &existing_entry
);
79 if (error
!= FILE_ERROR_OK
)
83 std::string parent_resource_id
;
84 if (!ConvertToResourceEntry(*resource_entry
, &entry
, &parent_resource_id
))
85 return FILE_ERROR_NOT_A_FILE
;
87 entry
.set_local_id(local_id
);
88 entry
.set_parent_local_id(existing_entry
.parent_local_id());
90 error
= metadata
->RefreshEntry(entry
);
91 if (error
!= FILE_ERROR_OK
)
94 *drive_file_path
= metadata
->GetFilePath(local_id
);
95 if (drive_file_path
->empty())
96 return FILE_ERROR_NOT_FOUND
;
98 // Do not clear the dirty bit if someone is writing to the file.
99 if (cache
->IsOpenedForWrite(local_id
))
100 return FILE_ERROR_OK
;
101 return cache
->ClearDirty(local_id
, entry
.file_specific_info().md5());
106 UpdateOperation::UpdateOperation(
107 base::SequencedTaskRunner
* blocking_task_runner
,
108 OperationObserver
* observer
,
109 JobScheduler
* scheduler
,
110 internal::ResourceMetadata
* metadata
,
111 internal::FileCache
* cache
)
112 : blocking_task_runner_(blocking_task_runner
),
114 scheduler_(scheduler
),
117 weak_ptr_factory_(this) {
118 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
121 UpdateOperation::~UpdateOperation() {
122 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
125 void UpdateOperation::UpdateFileByLocalId(
126 const std::string
& local_id
,
127 const ClientContext
& context
,
128 ContentCheckMode check
,
129 const FileOperationCallback
& callback
) {
130 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
131 DCHECK(!callback
.is_null());
133 LocalState
* local_state
= new LocalState
;
134 local_state
->local_id
= local_id
;
135 base::PostTaskAndReplyWithResult(
136 blocking_task_runner_
.get(),
138 base::Bind(&GetFileLocalState
,
143 base::Bind(&UpdateOperation::UpdateFileAfterGetLocalState
,
144 weak_ptr_factory_
.GetWeakPtr(),
147 base::Owned(local_state
)));
150 void UpdateOperation::UpdateFileAfterGetLocalState(
151 const ClientContext
& context
,
152 const FileOperationCallback
& callback
,
153 const LocalState
* local_state
,
155 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
156 DCHECK(!callback
.is_null());
158 if (error
!= FILE_ERROR_OK
|| local_state
->content_is_same
) {
163 scheduler_
->UploadExistingFile(
164 local_state
->entry
.resource_id(),
165 local_state
->drive_file_path
,
166 local_state
->cache_file_path
,
167 local_state
->entry
.file_specific_info().content_mime_type(),
170 base::Bind(&UpdateOperation::UpdateFileAfterUpload
,
171 weak_ptr_factory_
.GetWeakPtr(),
173 local_state
->local_id
));
176 void UpdateOperation::UpdateFileAfterUpload(
177 const FileOperationCallback
& callback
,
178 const std::string
& local_id
,
179 google_apis::GDataErrorCode error
,
180 scoped_ptr
<google_apis::ResourceEntry
> resource_entry
) {
181 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
182 DCHECK(!callback
.is_null());
184 FileError drive_error
= GDataToFileError(error
);
185 if (drive_error
!= FILE_ERROR_OK
) {
186 callback
.Run(drive_error
);
190 base::FilePath
* drive_file_path
= new base::FilePath
;
191 base::PostTaskAndReplyWithResult(
192 blocking_task_runner_
.get(),
194 base::Bind(&UpdateFileLocalState
,
198 base::Passed(&resource_entry
),
200 base::Bind(&UpdateOperation::UpdateFileAfterUpdateLocalState
,
201 weak_ptr_factory_
.GetWeakPtr(),
203 base::Owned(drive_file_path
)));
206 void UpdateOperation::UpdateFileAfterUpdateLocalState(
207 const FileOperationCallback
& callback
,
208 const base::FilePath
* drive_file_path
,
210 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
211 DCHECK(!callback
.is_null());
213 if (error
!= FILE_ERROR_OK
) {
217 observer_
->OnDirectoryChangedByOperation(drive_file_path
->DirName());
218 callback
.Run(FILE_ERROR_OK
);
221 } // namespace file_system