Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / chromeos / file_manager / snapshot_manager.cc
blob5ebb08a98be0ed876da464b753e354743599a5fb
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.
5 #include "chrome/browser/chromeos/file_manager/snapshot_manager.h"
7 #include "base/bind.h"
8 #include "base/sys_info.h"
9 #include "chrome/browser/chromeos/file_manager/app_id.h"
10 #include "chrome/browser/chromeos/file_manager/fileapi_util.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "google_apis/drive/task_util.h"
14 #include "storage/browser/blob/shareable_file_reference.h"
15 #include "storage/browser/fileapi/file_system_context.h"
16 #include "third_party/cros_system_api/constants/cryptohome.h"
18 namespace file_manager {
19 namespace {
21 typedef base::Callback<void(int64)> GetNecessaryFreeSpaceCallback;
23 // Part of ComputeSpaceNeedToBeFreed.
24 int64 ComputeSpaceNeedToBeFreedAfterGetMetadataOnBlockingPool(
25 const base::FilePath& path,
26 int64 snapshot_size) {
27 int64 free_size = base::SysInfo::AmountOfFreeDiskSpace(path);
28 if (free_size < 0)
29 return -1;
31 // We need to keep cryptohome::kMinFreeSpaceInBytes free space even after
32 // |snapshot_size| is occupied.
33 free_size -= snapshot_size + cryptohome::kMinFreeSpaceInBytes;
34 return (free_size < 0 ? -free_size : 0);
37 // Part of ComputeSpaceNeedToBeFreed.
38 void ComputeSpaceNeedToBeFreedAfterGetMetadata(
39 const base::FilePath& path,
40 const GetNecessaryFreeSpaceCallback& callback,
41 base::File::Error result,
42 const base::File::Info& file_info) {
43 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
44 if (result != base::File::FILE_OK) {
45 callback.Run(-1);
46 return;
49 base::PostTaskAndReplyWithResult(
50 content::BrowserThread::GetBlockingPool(),
51 FROM_HERE,
52 base::Bind(&ComputeSpaceNeedToBeFreedAfterGetMetadataOnBlockingPool,
53 path, file_info.size),
54 callback);
57 // Part of ComputeSpaceNeedToBeFreed.
58 void GetMetadataOnIOThread(const base::FilePath& path,
59 scoped_refptr<storage::FileSystemContext> context,
60 const storage::FileSystemURL& url,
61 const GetNecessaryFreeSpaceCallback& callback) {
62 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
63 context->operation_runner()->GetMetadata(
64 url,
65 base::Bind(&ComputeSpaceNeedToBeFreedAfterGetMetadata, path, callback));
68 // Computes the size of space that need to be __additionally__ made available
69 // in the |profile|'s data directory for taking the snapshot of |url|.
70 // Returns 0 if no additional space is required, or -1 in the case of an error.
71 void ComputeSpaceNeedToBeFreed(
72 Profile* profile,
73 scoped_refptr<storage::FileSystemContext> context,
74 const storage::FileSystemURL& url,
75 const GetNecessaryFreeSpaceCallback& callback) {
76 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
77 content::BrowserThread::PostTask(
78 content::BrowserThread::IO,
79 FROM_HERE,
80 base::Bind(&GetMetadataOnIOThread, profile->GetPath(), context, url,
81 google_apis::CreateRelayCallback(callback)));
84 // Part of CreateManagedSnapshot. Runs CreateSnapshotFile method of fileapi.
85 void CreateSnapshotFileOnIOThread(
86 scoped_refptr<storage::FileSystemContext> context,
87 const storage::FileSystemURL& url,
88 const storage::FileSystemOperation::SnapshotFileCallback& callback) {
89 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
90 context->operation_runner()->CreateSnapshotFile(url, callback);
93 // Utility for destructing the bound |file_refs| on IO thread. This is meant
94 // to be used together with base::Bind. After this function finishes, the
95 // Bind callback should destruct the bound argument.
96 void FreeReferenceOnIOThread(
97 const std::deque<SnapshotManager::FileReferenceWithSizeInfo>& file_refs) {
98 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
101 } // namespace
103 SnapshotManager::FileReferenceWithSizeInfo::FileReferenceWithSizeInfo(
104 scoped_refptr<storage::ShareableFileReference> ref,
105 int64 size)
106 : file_ref(ref), file_size(size) {
109 SnapshotManager::FileReferenceWithSizeInfo::~FileReferenceWithSizeInfo() {
112 SnapshotManager::SnapshotManager(Profile* profile)
113 : profile_(profile), weak_ptr_factory_(this) {
116 SnapshotManager::~SnapshotManager() {
117 if (!file_refs_.empty()) {
118 bool posted = content::BrowserThread::PostTask(
119 content::BrowserThread::IO,
120 FROM_HERE,
121 base::Bind(&FreeReferenceOnIOThread, file_refs_));
122 DCHECK(posted);
126 void SnapshotManager::CreateManagedSnapshot(
127 const base::FilePath& absolute_file_path,
128 const LocalPathCallback& callback) {
129 scoped_refptr<storage::FileSystemContext> context(
130 util::GetFileSystemContextForExtensionId(profile_, kFileManagerAppId));
131 DCHECK(context.get());
133 GURL url;
134 if (!util::ConvertAbsoluteFilePathToFileSystemUrl(
135 profile_, absolute_file_path, kFileManagerAppId, &url)) {
136 callback.Run(base::FilePath());
137 return;
139 storage::FileSystemURL filesystem_url = context->CrackURL(url);
141 ComputeSpaceNeedToBeFreed(profile_, context, filesystem_url,
142 base::Bind(&SnapshotManager::CreateManagedSnapshotAfterSpaceComputed,
143 weak_ptr_factory_.GetWeakPtr(),
144 filesystem_url,
145 callback));
148 void SnapshotManager::CreateManagedSnapshotAfterSpaceComputed(
149 const storage::FileSystemURL& filesystem_url,
150 const LocalPathCallback& callback,
151 int64 needed_space) {
152 scoped_refptr<storage::FileSystemContext> context(
153 util::GetFileSystemContextForExtensionId(profile_, kFileManagerAppId));
154 DCHECK(context.get());
156 if (needed_space < 0) {
157 callback.Run(base::FilePath());
158 return;
161 // Free up to the required size.
162 std::deque<FileReferenceWithSizeInfo> to_free;
163 while (needed_space > 0 && !file_refs_.empty()) {
164 needed_space -= file_refs_.front().file_size;
165 to_free.push_back(file_refs_.front());
166 file_refs_.pop_front();
168 if (!to_free.empty()) {
169 bool posted = content::BrowserThread::PostTask(
170 content::BrowserThread::IO,
171 FROM_HERE,
172 base::Bind(&FreeReferenceOnIOThread, to_free));
173 DCHECK(posted);
176 // If we still could not achieve the space requirement, abort with failure.
177 if (needed_space > 0) {
178 callback.Run(base::FilePath());
179 return;
182 // Start creating the snapshot.
183 content::BrowserThread::PostTask(
184 content::BrowserThread::IO,
185 FROM_HERE,
186 base::Bind(&CreateSnapshotFileOnIOThread,
187 context,
188 filesystem_url,
189 google_apis::CreateRelayCallback(
190 base::Bind(&SnapshotManager::OnCreateSnapshotFile,
191 weak_ptr_factory_.GetWeakPtr(),
192 callback))));
195 void SnapshotManager::OnCreateSnapshotFile(
196 const LocalPathCallback& callback,
197 base::File::Error result,
198 const base::File::Info& file_info,
199 const base::FilePath& platform_path,
200 const scoped_refptr<storage::ShareableFileReference>& file_ref) {
201 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
203 if (result != base::File::FILE_OK) {
204 callback.Run(base::FilePath());
205 return;
208 file_refs_.push_back(FileReferenceWithSizeInfo(file_ref, file_info.size));
209 callback.Run(platform_path);
212 } // namespace file_manager