diff options
author | kinaba@chromium.org <kinaba@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-16 05:06:11 +0000 |
---|---|---|
committer | kinaba@chromium.org <kinaba@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-16 05:06:11 +0000 |
commit | b1abc6a57f507c372e3f9b1dd17354a4cb2ecf05 (patch) | |
tree | 733cc3689ffad73fafe94f55f8e847cd2d3714a8 | |
parent | 127f18ec329490d72c21ffaac2af086534f95412 (diff) | |
download | chromium_src-b1abc6a57f507c372e3f9b1dd17354a4cb2ecf05.zip chromium_src-b1abc6a57f507c372e3f9b1dd17354a4cb2ecf05.tar.gz chromium_src-b1abc6a57f507c372e3f9b1dd17354a4cb2ecf05.tar.bz2 |
Truncate() operation for GData file system.
BUG=127097
TEST=browser_test --gest_filter='*RemoteFileSystem*'
TEST=unit_tests --gtest_filter='*GData*'
Review URL: https://chromiumcodereview.appspot.com/10441015
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@142579 0039d316-1c4b-4281-b951-d872f2087c98
5 files changed, 165 insertions, 1 deletions
diff --git a/chrome/browser/chromeos/gdata/gdata_file_system_proxy.cc b/chrome/browser/chromeos/gdata/gdata_file_system_proxy.cc index e739abe..ed07c3a 100644 --- a/chrome/browser/chromeos/gdata/gdata_file_system_proxy.cc +++ b/chrome/browser/chromeos/gdata/gdata_file_system_proxy.cc @@ -123,6 +123,34 @@ void OnClose(const FilePath& local_path, base::PlatformFileError error_code) { DVLOG(1) << "Closed: " << local_path.AsUTF8Unsafe() << ": " << error_code; } +void DoTruncateOnFileThread( + const FilePath& local_cache_path, + int64 length, + base::PlatformFileError* result) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + + base::PlatformFile file = base::CreatePlatformFile( + local_cache_path, + base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE, + NULL, + result); + if (*result == base::PLATFORM_FILE_OK) { + DCHECK_NE(base::kInvalidPlatformFileValue, file); + if (!base::TruncatePlatformFile(file, length)) + *result = base::PLATFORM_FILE_ERROR_FAILED; + base::ClosePlatformFile(file); + } +} + +void DidCloseFileForTruncate( + const fileapi::FileSystemOperationInterface::StatusCallback& callback, + base::PlatformFileError truncate_result, + base::PlatformFileError close_result) { + // Reports the first error. + callback.Run(truncate_result == base::PLATFORM_FILE_OK ? close_result + : truncate_result); +} + } // namespace namespace gdata { @@ -265,6 +293,74 @@ void GDataFileSystemProxy::CreateDirectory( file_system_->CreateDirectory(file_path, exclusive, recursive, callback); } +void GDataFileSystemProxy::Truncate(const GURL& file_url, int64 length, + const fileapi::FileSystemOperationInterface::StatusCallback& callback) { + if (length < 0) { + MessageLoopProxy::current()->PostTask(FROM_HERE, + base::Bind(callback, base::PLATFORM_FILE_ERROR_INVALID_OPERATION)); + return; + } + + FilePath file_path; + if (!ValidateUrl(file_url, &file_path)) { + MessageLoopProxy::current()->PostTask(FROM_HERE, + base::Bind(callback, base::PLATFORM_FILE_ERROR_NOT_FOUND)); + return; + } + + // TODO(kinaba): http://crbug.com/132780. + // Optimize the cases for small |length|, at least for |length| == 0. + // CreateWritableSnapshotFile downloads the whole content unnecessarily. + file_system_->OpenFile( + file_path, + base::Bind(&GDataFileSystemProxy::OnFileOpenedForTruncate, + this, + file_path, + length, + callback)); +} + +void GDataFileSystemProxy::OnFileOpenedForTruncate( + const FilePath& virtual_path, + int64 length, + const fileapi::FileSystemOperationInterface::StatusCallback& callback, + base::PlatformFileError open_result, + const FilePath& local_cache_path) { + if (open_result != base::PLATFORM_FILE_OK) { + callback.Run(open_result); + return; + } + + // Cache file prepared for modification is available. Truncate it. + // File operation must be done on FILE thread, so relay the operation. + base::PlatformFileError* result = + new base::PlatformFileError(base::PLATFORM_FILE_ERROR_FAILED); + bool posted = BrowserThread::GetMessageLoopProxyForThread( + BrowserThread::FILE)->PostTaskAndReply( + FROM_HERE, + base::Bind(&DoTruncateOnFileThread, + local_cache_path, + length, + result), + base::Bind(&GDataFileSystemProxy::DidTruncate, + this, + virtual_path, + callback, + base::Owned(result))); + DCHECK(posted); +} + +void GDataFileSystemProxy::DidTruncate( + const FilePath& virtual_path, + const fileapi::FileSystemOperationInterface::StatusCallback& callback, + base::PlatformFileError* truncate_result) { + // Truncation finished. We must close the file no matter |truncate_result| + // indicates an error or not. + file_system_->CloseFile(virtual_path, base::Bind(&DidCloseFileForTruncate, + callback, + *truncate_result)); +} + void GDataFileSystemProxy::OpenFile( const GURL& file_url, int file_flags, diff --git a/chrome/browser/chromeos/gdata/gdata_file_system_proxy.h b/chrome/browser/chromeos/gdata/gdata_file_system_proxy.h index d587463..39b1008 100644 --- a/chrome/browser/chromeos/gdata/gdata_file_system_proxy.h +++ b/chrome/browser/chromeos/gdata/gdata_file_system_proxy.h @@ -47,6 +47,9 @@ class GDataFileSystemProxy : public fileapi::RemoteFileSystemProxyInterface { bool recursive, const fileapi::FileSystemOperationInterface::StatusCallback& callback) OVERRIDE; + virtual void Truncate(const GURL& file_url, int64 length, + const fileapi::FileSystemOperationInterface::StatusCallback& callback) + OVERRIDE; virtual void CreateSnapshotFile( const GURL& path, const fileapi::FileSystemOperationInterface::SnapshotFileCallback& @@ -111,6 +114,22 @@ class GDataFileSystemProxy : public fileapi::RemoteFileSystemProxyInterface { const FilePath& virtual_path, const FilePath& local_path); + // Invoked during Truncate() operation. This is called when a local modifiable + // cache is ready for truncation. + void OnFileOpenedForTruncate( + const FilePath& virtual_path, + int64 length, + const fileapi::FileSystemOperationInterface::StatusCallback& callback, + base::PlatformFileError open_result, + const FilePath& local_cache_path); + + // Invoked during Truncate() operation. This is called when the truncation of + // a local cache file is finished on FILE thread. + void DidTruncate( + const FilePath& virtual_path, + const fileapi::FileSystemOperationInterface::StatusCallback& callback, + base::PlatformFileError* truncate_result); + // GDataFileSystemProxy is owned by Profile, which outlives // GDataFileSystemProxy, which is owned by CrosMountPointProvider (i.e. by // the time Profile is removed, the file manager is already gone). Hence diff --git a/chrome/test/data/extensions/api_test/filebrowser_component/remote.js b/chrome/test/data/extensions/api_test/filebrowser_component/remote.js index 2748a59..61ce941 100644 --- a/chrome/test/data/extensions/api_test/filebrowser_component/remote.js +++ b/chrome/test/data/extensions/api_test/filebrowser_component/remote.js @@ -18,6 +18,10 @@ var kExpectedContents = 'hello, world\0'; var kWriteOffset = 12; var kWriteData = '!!!'; var kExpectedAfterWrite = 'hello, world!!!'; +var kTruncateShortLength = 5; +var kExpectedAfterTruncateShort = 'hello'; +var kTruncateLongLength = 7; +var kExpectedAfterTruncateLong = 'hello\0\0'; var kNewDirectoryPath = 'drive/FolderNew'; // Gets local filesystem used in tests. @@ -86,6 +90,25 @@ TestRunner.prototype.runWriteFileTest = function(fileName) { self.errorCallback_.bind(self, 'Error opening file: ')); }; +TestRunner.prototype.runTruncateFileTest = function(fileName, length) { + var self = this; + chrome.test.assertTrue(!!this.directoryEntry_); + this.directoryEntry_.getFile(fileName, {}, + function(entry) { + entry.createWriter( + function(writer) { + writer.onerror = self.errorCallback_.bind(self, + 'Error writing file: '); + writer.onwriteend = function(e) { + chrome.test.succeed(); + }; + writer.truncate(length); + }, + self.errorCallback_.bind(self, 'Error creating writer: ')); + }, + self.errorCallback_.bind(self, 'Error opening file: ')); +}; + TestRunner.prototype.runExecuteReadTask = function() { chrome.test.assertTrue(!!this.fileEntry_); @@ -211,6 +234,20 @@ chrome.test.runTests([function initTests() { function readFileAfterWrite() { testRunner.runReadFileTest(kFileName, kExpectedAfterWrite); }, + function truncateFileShort() { + // Opens a file in the directory and make it shorter. + testRunner.runTruncateFileTest(kFileName, kTruncateShortLength); + }, + function readFileAfterTruncateShort() { + testRunner.runReadFileTest(kFileName, kExpectedAfterTruncateShort); + }, + function truncateFileLong() { + // Opens a file in the directory and make it longer. + testRunner.runTruncateFileTest(kFileName, kTruncateLongLength); + }, + function readFileAfterTruncateLong() { + testRunner.runReadFileTest(kFileName, kExpectedAfterTruncateLong); + }, function createDir() { // Creates new directory. testRunner.runGetDirTest(kNewDirectoryPath, true); diff --git a/webkit/chromeos/fileapi/remote_file_system_operation.cc b/webkit/chromeos/fileapi/remote_file_system_operation.cc index 3404f37..e3a551b 100644 --- a/webkit/chromeos/fileapi/remote_file_system_operation.cc +++ b/webkit/chromeos/fileapi/remote_file_system_operation.cc @@ -129,7 +129,11 @@ void RemoteFileSystemOperation::Write( void RemoteFileSystemOperation::Truncate(const GURL& path, int64 length, const StatusCallback& callback) { - NOTIMPLEMENTED(); + DCHECK(SetPendingOperationType(kOperationTruncate)); + + remote_proxy_->Truncate(path, length, + base::Bind(&RemoteFileSystemOperation::DidFinishFileOperation, + base::Owned(this), callback)); } void RemoteFileSystemOperation::Cancel(const StatusCallback& cancel_callback) { diff --git a/webkit/chromeos/fileapi/remote_file_system_proxy.h b/webkit/chromeos/fileapi/remote_file_system_proxy.h index 214b624..77e4a04 100644 --- a/webkit/chromeos/fileapi/remote_file_system_proxy.h +++ b/webkit/chromeos/fileapi/remote_file_system_proxy.h @@ -64,6 +64,14 @@ class RemoteFileSystemProxyInterface : bool recursive, const FileSystemOperationInterface::StatusCallback& callback) = 0; + // Changes the length of an existing file at |path| to |length|. If |length| + // is negative, an error is raised. If |length| is more than the current size + // of the file, zero is padded for the extended part. + virtual void Truncate( + const GURL& path, + int64 length, + const FileSystemOperationInterface::StatusCallback& callback) = 0; + // Creates a local snapshot file for a given |path| and returns the // metadata and platform path of the snapshot file via |callback|. // See also FileSystemOperationInterface::CreateSnapshotFile(). |