190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// found in the LICENSE file. 490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/chromeos/drive/file_system/operation_test_base.h" 690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 77dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/prefs/testing_pref_service.h" 890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/threading/sequenced_worker_pool.h" 95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/chromeos/drive/change_list_loader.h" 1090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/chromeos/drive/fake_free_disk_space_getter.h" 1190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/chromeos/drive/file_cache.h" 12116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "chrome/browser/chromeos/drive/file_change.h" 135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/browser/chromeos/drive/file_system/operation_delegate.h" 1490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/chromeos/drive/job_scheduler.h" 1590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/chromeos/drive/resource_metadata.h" 165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/drive/event_logger.h" 177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "chrome/browser/drive/fake_drive_service.h" 185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "chrome/browser/drive/test_util.h" 197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "content/public/browser/browser_thread.h" 20116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "content/public/test/test_utils.h" 21a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "google_apis/drive/test_util.h" 2290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 2390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace drive { 2490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace file_system { 2590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)OperationTestBase::LoggingDelegate::LoggingDelegate() { 2790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 2890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)OperationTestBase::LoggingDelegate::~LoggingDelegate() { 3090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 3190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void OperationTestBase::LoggingDelegate::OnFileChangedByOperation( 33116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const FileChange& changed_files) { 34116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch changed_files_.Apply(changed_files); 3590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 3690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void OperationTestBase::LoggingDelegate::OnEntryUpdatedByOperation( 38f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const std::string& local_id) { 39a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) updated_local_ids_.insert(local_id); 40f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 41f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void OperationTestBase::LoggingDelegate::OnDriveSyncError( 435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DriveSyncErrorType type, const std::string& local_id) { 445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) drive_sync_errors_.push_back(type); 455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool OperationTestBase::LoggingDelegate::WaitForSyncComplete( 485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const std::string& local_id, 495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const FileOperationCallback& callback) { 505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return wait_for_sync_complete_handler_.is_null() ? 515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) false : wait_for_sync_complete_handler_.Run(local_id, callback); 525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)OperationTestBase::OperationTestBase() { 5590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 5690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 57ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben MurdochOperationTestBase::OperationTestBase(int test_thread_bundle_options) 58ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch : thread_bundle_(test_thread_bundle_options) { 59ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch} 60ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 6190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)OperationTestBase::~OperationTestBase() { 6290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 6390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 6490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void OperationTestBase::SetUp() { 6590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) scoped_refptr<base::SequencedWorkerPool> pool = 6690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) content::BrowserThread::GetBlockingPool(); 6790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) blocking_task_runner_ = 6890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) pool->GetSequencedTaskRunner(pool->GetSequenceToken()); 6990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch pref_service_.reset(new TestingPrefServiceSimple); 717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch test_util::RegisterDrivePrefs(pref_service_->registry()); 727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 7390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 7490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) logger_.reset(new EventLogger); 765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 77eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch fake_drive_service_.reset(new FakeDriveService); 785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu ASSERT_TRUE(test_util::SetUpTestEntries(fake_drive_service_.get())); 7990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch scheduler_.reset(new JobScheduler( 817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch pref_service_.get(), 825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) logger_.get(), 837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch fake_drive_service_.get(), 847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch blocking_task_runner_.get())); 8590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 86eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch metadata_storage_.reset(new internal::ResourceMetadataStorage( 877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch temp_dir_.path(), blocking_task_runner_.get())); 88eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool success = false; 89eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::PostTaskAndReplyWithResult( 907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch blocking_task_runner_.get(), 91eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch FROM_HERE, 92eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::Bind(&internal::ResourceMetadataStorage::Initialize, 93eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::Unretained(metadata_storage_.get())), 94eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch google_apis::test_util::CreateCopyResultCallback(&success)); 95116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch content::RunAllBlockingPoolTasksUntilIdle(); 96eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ASSERT_TRUE(success); 97eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 9890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) fake_free_disk_space_getter_.reset(new FakeFreeDiskSpaceGetter); 99eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch cache_.reset(new internal::FileCache(metadata_storage_.get(), 1007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) temp_dir_.path(), 1017d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) blocking_task_runner_.get(), 10290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) fake_free_disk_space_getter_.get())); 103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch success = false; 1047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) base::PostTaskAndReplyWithResult( 1057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch blocking_task_runner_.get(), 1067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) FROM_HERE, 1077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) base::Bind(&internal::FileCache::Initialize, 1087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) base::Unretained(cache_.get())), 109868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) google_apis::test_util::CreateCopyResultCallback(&success)); 110116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch content::RunAllBlockingPoolTasksUntilIdle(); 111868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ASSERT_TRUE(success); 11290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) metadata_.reset(new internal::ResourceMetadata(metadata_storage_.get(), 114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) cache_.get(), 115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) blocking_task_runner_)); 116cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 117cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) FileError error = FILE_ERROR_FAILED; 118cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::PostTaskAndReplyWithResult( 119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) blocking_task_runner_.get(), 120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) FROM_HERE, 121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::Bind(&internal::ResourceMetadata::Initialize, 122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::Unretained(metadata_.get())), 123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) google_apis::test_util::CreateCopyResultCallback(&error)); 124116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch content::RunAllBlockingPoolTasksUntilIdle(); 125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) ASSERT_EQ(FILE_ERROR_OK, error); 126cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 12790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Makes sure the FakeDriveService's content is loaded to the metadata_. 1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) about_resource_loader_.reset(new internal::AboutResourceLoader( 1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) scheduler_.get())); 1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) loader_controller_.reset(new internal::LoaderController); 131424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) change_list_loader_.reset(new internal::ChangeListLoader( 1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) logger_.get(), 13358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) blocking_task_runner_.get(), 13458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) metadata_.get(), 13558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) scheduler_.get(), 1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) about_resource_loader_.get(), 1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) loader_controller_.get())); 138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) change_list_loader_->LoadIfNeeded( 13990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) google_apis::test_util::CreateCopyResultCallback(&error)); 140116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch content::RunAllBlockingPoolTasksUntilIdle(); 14190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) ASSERT_EQ(FILE_ERROR_OK, error); 14290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 14390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 14490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)FileError OperationTestBase::GetLocalResourceEntry(const base::FilePath& path, 14590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) ResourceEntry* entry) { 14690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) FileError error = FILE_ERROR_FAILED; 14790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::PostTaskAndReplyWithResult( 14890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) blocking_task_runner(), 14990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) FROM_HERE, 15090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::Bind(&internal::ResourceMetadata::GetResourceEntryByPath, 15190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::Unretained(metadata()), path, entry), 15290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::Bind(google_apis::test_util::CreateCopyResultCallback(&error))); 153116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch content::RunAllBlockingPoolTasksUntilIdle(); 15490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return error; 15590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 15690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 157f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)FileError OperationTestBase::GetLocalResourceEntryById( 158f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const std::string& local_id, 159f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ResourceEntry* entry) { 160f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) FileError error = FILE_ERROR_FAILED; 161f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::PostTaskAndReplyWithResult( 162f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) blocking_task_runner(), 163f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) FROM_HERE, 164f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::Bind(&internal::ResourceMetadata::GetResourceEntryById, 165f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::Unretained(metadata()), local_id, entry), 166f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::Bind(google_apis::test_util::CreateCopyResultCallback(&error))); 167116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch content::RunAllBlockingPoolTasksUntilIdle(); 168f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return error; 169f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 170f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 171424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)std::string OperationTestBase::GetLocalId(const base::FilePath& path) { 172424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) std::string local_id; 173424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) FileError error = FILE_ERROR_FAILED; 174424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) base::PostTaskAndReplyWithResult( 175424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) blocking_task_runner(), 176424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) FROM_HERE, 177424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) base::Bind(&internal::ResourceMetadata::GetIdByPath, 178424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) base::Unretained(metadata()), path, &local_id), 179424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) base::Bind(google_apis::test_util::CreateCopyResultCallback(&error))); 180116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch content::RunAllBlockingPoolTasksUntilIdle(); 181424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) EXPECT_EQ(FILE_ERROR_OK, error) << path.value(); 182424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return local_id; 183424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)} 184424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 185424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)FileError OperationTestBase::CheckForUpdates() { 186424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) FileError error = FILE_ERROR_FAILED; 187424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) change_list_loader_->CheckForUpdates( 188424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) google_apis::test_util::CreateCopyResultCallback(&error)); 189116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch content::RunAllBlockingPoolTasksUntilIdle(); 190424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return error; 191424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)} 192424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 19390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} // namespace file_system 19490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} // namespace drive 195