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"
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
{
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
);
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
) {
49 base::PostTaskAndReplyWithResult(
50 content::BrowserThread::GetBlockingPool(),
52 base::Bind(&ComputeSpaceNeedToBeFreedAfterGetMetadataOnBlockingPool
,
53 path
, file_info
.size
),
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(
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(
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
,
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
);
103 SnapshotManager::FileReferenceWithSizeInfo::FileReferenceWithSizeInfo(
104 scoped_refptr
<storage::ShareableFileReference
> ref
,
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
,
121 base::Bind(&FreeReferenceOnIOThread
, file_refs_
));
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());
134 if (!util::ConvertAbsoluteFilePathToFileSystemUrl(
135 profile_
, absolute_file_path
, kFileManagerAppId
, &url
)) {
136 callback
.Run(base::FilePath());
139 storage::FileSystemURL filesystem_url
= context
->CrackURL(url
);
141 ComputeSpaceNeedToBeFreed(profile_
, context
, filesystem_url
,
142 base::Bind(&SnapshotManager::CreateManagedSnapshotAfterSpaceComputed
,
143 weak_ptr_factory_
.GetWeakPtr(),
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());
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
,
172 base::Bind(&FreeReferenceOnIOThread
, to_free
));
176 // If we still could not achieve the space requirement, abort with failure.
177 if (needed_space
> 0) {
178 callback
.Run(base::FilePath());
182 // Start creating the snapshot.
183 content::BrowserThread::PostTask(
184 content::BrowserThread::IO
,
186 base::Bind(&CreateSnapshotFileOnIOThread
,
189 google_apis::CreateRelayCallback(
190 base::Bind(&SnapshotManager::OnCreateSnapshotFile
,
191 weak_ptr_factory_
.GetWeakPtr(),
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());
208 file_refs_
.push_back(FileReferenceWithSizeInfo(file_ref
, file_info
.size
));
209 callback
.Run(platform_path
);
212 } // namespace file_manager