Index: chrome/browser/chromeos/file_manager/snapshot_manager.cc |
diff --git a/chrome/browser/chromeos/file_manager/snapshot_manager.cc b/chrome/browser/chromeos/file_manager/snapshot_manager.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..452eaec1c82d12241cb674a7888bf4fbe350f11a |
--- /dev/null |
+++ b/chrome/browser/chromeos/file_manager/snapshot_manager.cc |
@@ -0,0 +1,155 @@ |
+// Copyright 2014 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 "chrome/browser/chromeos/file_manager/snapshot_manager.h" |
+ |
+#include "base/bind.h" |
+#include "base/file_util.h" |
+#include "base/files/file_path.h" |
+#include "base/sequenced_task_runner.h" |
+#include "base/sys_info.h" |
+#include "base/task_runner_util.h" |
+#include "chrome/browser/chromeos/file_manager/app_id.h" |
+#include "chrome/browser/chromeos/file_manager/fileapi_util.h" |
+#include "chrome/browser/profiles/profile.h" |
+#include "content/public/browser/browser_thread.h" |
+#include "google_apis/drive/task_util.h" |
+#include "third_party/cros_system_api/constants/cryptohome.h" |
+#include "webkit/common/blob/shareable_file_reference.h" |
+ |
+namespace file_manager { |
+namespace { |
+ |
+// Name of the directory for storing the snapshot files under the storage |
+// partition path. |
+const base::FilePath::CharType kFileManagerSnapshotDirectoryName[] = |
+ FILE_PATH_LITERAL("FileDialogSnapshot"); |
+ |
+// Cleans up the specified directory. |
+void DeleteDirectory(const base::FilePath& directory) { |
hashimoto
2014/06/19 02:26:01
nit: What is the point of having this function ins
kinaba
2014/06/19 04:41:56
Good catch. Removed.
(Actually I hadn't been able
|
+ base::DeleteFile(directory, true /* recursive */); |
+} |
+ |
+// Returns true if there is sufficient disk space in |directory| for file |
+// |size|. Besides, it heuristically cleans up old files under |directory|. |
+bool MakeSpaceIfNecessary(const base::FilePath& directory, int64 size) { |
+ int64 free_space = base::SysInfo::AmountOfFreeDiskSpace(directory); |
+ free_space -= cryptohome::kMinFreeSpaceInBytes; |
+ |
+ // TODO(kinaba): clean old snapshot files. |
+ return (size <= free_space); |
+} |
+ |
+// Part of CreateManagedSnapshot. Used for retaining |file_ref| until the |
+// blocking pool job finished. After returning from this function, |file_ref| is |
+// freed on the IO thread. |
+void CopyDone( |
+ const SnapshotManager::LocalPathCallback& callback, |
+ const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref, |
+ const base::FilePath& local_path) { |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
+ callback.Run(local_path); |
+} |
+ |
+// Part of CreateManagedSnapshot. |
+// Copy |path| into |directory| with space management. |
+base::FilePath CopyOnBlockingPool(const base::FilePath& directory, |
+ const base::FilePath& path) { |
+ base::File::Info info; |
+ base::FilePath copied; |
+ if (!base::GetFileInfo(path, &info) || |
+ !base::CreateDirectory(directory) || |
+ !MakeSpaceIfNecessary(directory, info.size) || |
+ !base::CreateTemporaryFileInDir(directory, &copied) || |
+ !base::CopyFile(path, copied)) { |
+ return base::FilePath(); |
+ } |
+ return copied; |
+} |
+ |
+// Part of CreateManagedSnapshot. Copies the created file to a temporary |
+// path. The snapshot file itself may be removed once |file_ref| is deleted. |
+void OnCreateSnapshotFile( |
+ scoped_refptr<base::SequencedTaskRunner> task_runner, |
+ const base::FilePath& base_path, |
+ const SnapshotManager::LocalPathCallback& callback, |
+ base::File::Error result, |
+ const base::File::Info& file_info, |
+ const base::FilePath& platform_path, |
+ const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) { |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
+ |
+ if (result != base::File::FILE_OK) { |
+ callback.Run(base::FilePath()); |
+ return; |
+ } |
+ |
+ base::PostTaskAndReplyWithResult( |
+ task_runner, |
+ FROM_HERE, |
+ base::Bind(&CopyOnBlockingPool, base_path, platform_path), |
+ base::Bind(&CopyDone, callback, file_ref)); |
+} |
+ |
+// Part of CreateManagedSnapshot. Runs CreateSnapshotFile method of fileapi. |
+void CreateSnapshotFileOnIOThread( |
+ scoped_refptr<fileapi::FileSystemContext> context, |
+ scoped_refptr<base::SequencedTaskRunner> task_runner, |
+ const base::FilePath& base_path, |
+ const fileapi::FileSystemURL& url, |
+ const SnapshotManager::LocalPathCallback& callback) { |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
+ |
+ context->operation_runner()->CreateSnapshotFile( |
+ url, base::Bind(&OnCreateSnapshotFile, task_runner, base_path, callback)); |
+} |
+ |
+} // namespace |
+ |
+SnapshotManager::SnapshotManager(Profile* profile) |
+ : profile_(profile) { |
+ base::SequencedWorkerPool* pool = |
+ content::BrowserThread::GetBlockingPool(); |
+ task_runner_ = pool->GetSequencedTaskRunner(pool->GetSequenceToken()); |
+} |
+ |
+SnapshotManager::~SnapshotManager() { |
+ if (task_runner_ && !base_path_.empty()) { |
hashimoto
2014/06/19 02:26:01
nit: In which case task_runner_ becomes NULL?
kinaba
2014/06/19 04:41:56
Never.
|
+ // Clean up all snapshots in the current run. |
+ task_runner_->PostTask( |
+ FROM_HERE, base::Bind(&DeleteDirectory, base_path_)); |
hashimoto
2014/06/19 02:26:01
I don't remember in which order objects are destru
kinaba
2014/06/19 04:41:56
It is still alive at this point (profile destructi
|
+ } |
+} |
+ |
+void SnapshotManager::CreateManagedSnapshot( |
+ const base::FilePath& absolute_file_path, |
+ const LocalPathCallback& callback) { |
+ fileapi::FileSystemContext* context = |
+ util::GetFileSystemContextForExtensionId(profile_, kFileManagerAppId); |
+ DCHECK(context); |
+ |
+ GURL url; |
+ if (!util::ConvertAbsoluteFilePathToFileSystemUrl( |
+ profile_, absolute_file_path, kFileManagerAppId, &url)) { |
+ callback.Run(base::FilePath()); |
+ return; |
+ } |
+ |
+ if (base_path_.empty()) { |
hashimoto
2014/06/19 02:26:01
nit: Why can't this be initialized in the ctor?
kinaba
2014/06/19 04:41:56
StorageParition/FileSystemContext related part is
|
+ base_path_ = context->partition_path().Append( |
+ kFileManagerSnapshotDirectoryName); |
+ } |
+ |
+ content::BrowserThread::PostTask( |
+ content::BrowserThread::IO, |
+ FROM_HERE, |
+ base::Bind(&CreateSnapshotFileOnIOThread, |
+ make_scoped_refptr(context), |
+ task_runner_, |
+ base_path_, |
+ context->CrackURL(url), |
+ google_apis::CreateRelayCallback(callback))); |
+} |
+ |
+} // namespace file_manager |