Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2088)

Unified Diff: chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.cc

Issue 982283002: Implement DeleteFile and DeleteDirectory. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add DCHECK. Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.cc
diff --git a/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.cc b/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.cc
index b742eea8cf08c89944a53ca2662d18aafde5fba8..006f6398ea6de1e75f2a58da15314b373cf415fd 100644
--- a/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.cc
+++ b/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.cc
@@ -113,6 +113,33 @@ void ReadDirectoryOnUIThread(
task_helper->ReadDirectory(dir_id, success_callback, error_callback);
}
+// Gets entry ids on |directory_id|.
+//
+// Called on the UI thread to dispatch the request to the
+// MediaTransferProtocolManager.
+//
+// |storage_name| specifies the name of the storage device.
+// |read_only| specifies the mode of the storage device.
+// |directory_id| is the directory to be read.
+// |success_callback| is called when the ReadDirectoryEntryIds request succeeds.
+// |error_callback| is called when the ReadDirectoryEntryIds request fails.
+// |success_callback| and |error_callback| runs on the IO thread.
+void ReadDirectoryEntryIdsOnUIThread(
+ const std::string& storage_name,
+ const bool read_only,
+ const uint32 directory_id,
+ const MTPDeviceTaskHelper::ReadDirectoryEntryIdsSuccessCallback&
+ success_callback,
+ const MTPDeviceTaskHelper::ErrorCallback& error_callback) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ MTPDeviceTaskHelper* task_helper =
+ GetDeviceTaskHelperForStorage(storage_name, read_only);
+ if (!task_helper)
+ return;
+ task_helper->ReadDirectoryEntryIds(directory_id, success_callback,
+ error_callback);
+}
+
// Gets the |file_path| details.
//
// Called on the UI thread to dispatch the request to the
@@ -214,6 +241,31 @@ void CopyFileFromLocalOnUIThread(
error_callback);
}
+// Deletes |object_id|.
+//
+// Called on the UI thread to dispatch the request to the
+// MediaTransferProtocolManager.
+//
+// |storage_name| specifies the name of the storage device.
+// |read_only| specifies the mode of the storage device.
+// |object_id| is the object to be deleted.
+// |success_callback| is called when the object is deleted successfully.
+// |error_callback| is called when it fails to delete the object.
+// |success_callback| and |error_callback| runs on the IO thread.
+void DeleteObjectOnUIThread(
+ const std::string storage_name,
+ const bool read_only,
+ const uint32 object_id,
+ const MTPDeviceTaskHelper::DeleteObjectSuccessCallback success_callback,
+ const MTPDeviceTaskHelper::ErrorCallback error_callback) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ MTPDeviceTaskHelper* task_helper =
+ GetDeviceTaskHelperForStorage(storage_name, read_only);
+ if (!task_helper)
+ return;
+ task_helper->DeleteObject(object_id, success_callback, error_callback);
+}
+
// Closes the device storage specified by the |storage_name| and destroys the
// MTPDeviceTaskHelper object associated with the device storage.
//
@@ -282,6 +334,8 @@ class MTPDeviceDelegateImplLinux::MTPFileNode {
bool DeleteChild(uint32 file_id);
+ bool HasChildren() const;
+
uint32 file_id() const { return file_id_; }
const std::string& file_name() const { return file_name_; }
MTPFileNode* parent() { return parent_; }
@@ -362,6 +416,7 @@ bool MTPDeviceDelegateImplLinux::MTPFileNode::DeleteChild(uint32 file_id) {
for (ChildNodes::iterator it = children_.begin();
it != children_.end(); ++it) {
if (it->second->file_id() == file_id) {
+ DCHECK(!it->second->HasChildren());
children_.erase(it);
return true;
}
@@ -369,6 +424,11 @@ bool MTPDeviceDelegateImplLinux::MTPFileNode::DeleteChild(uint32 file_id) {
return false;
}
+bool MTPDeviceDelegateImplLinux::MTPFileNode::HasChildren() const {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ return children_.size() > 0;
+}
+
MTPDeviceDelegateImplLinux::MTPDeviceDelegateImplLinux(
const std::string& device_location,
const bool read_only)
@@ -494,7 +554,7 @@ void MTPDeviceDelegateImplLinux::ReadBytes(
closure));
}
-bool MTPDeviceDelegateImplLinux::IsReadOnly() {
+bool MTPDeviceDelegateImplLinux::IsReadOnly() const {
return read_only_;
}
@@ -520,6 +580,46 @@ void MTPDeviceDelegateImplLinux::CopyFileFromLocal(
error_callback));
}
+void MTPDeviceDelegateImplLinux::DeleteFile(
+ const base::FilePath& file_path,
+ const DeleteFileSuccessCallback& success_callback,
+ const ErrorCallback& error_callback) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ DCHECK(!file_path.empty());
+
+ const GetFileInfoSuccessCallback& success_callback_wrapper =
+ base::Bind(&MTPDeviceDelegateImplLinux::DeleteFileInternal,
+ weak_ptr_factory_.GetWeakPtr(), file_path, success_callback,
+ error_callback);
+
+ const base::Closure closure =
+ base::Bind(&MTPDeviceDelegateImplLinux::GetFileInfoInternal,
+ weak_ptr_factory_.GetWeakPtr(), file_path,
+ success_callback_wrapper, error_callback);
+ EnsureInitAndRunTask(PendingTaskInfo(file_path, content::BrowserThread::IO,
+ FROM_HERE, closure));
+}
+
+void MTPDeviceDelegateImplLinux::DeleteDirectory(
+ const base::FilePath& file_path,
+ const DeleteDirectorySuccessCallback& success_callback,
+ const ErrorCallback& error_callback) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ DCHECK(!file_path.empty());
+
+ const GetFileInfoSuccessCallback& success_callback_wrapper =
+ base::Bind(&MTPDeviceDelegateImplLinux::DeleteDirectoryInternal,
+ weak_ptr_factory_.GetWeakPtr(), file_path, success_callback,
+ error_callback);
+
+ const base::Closure closure =
+ base::Bind(&MTPDeviceDelegateImplLinux::GetFileInfoInternal,
+ weak_ptr_factory_.GetWeakPtr(), file_path,
+ success_callback_wrapper, error_callback);
+ EnsureInitAndRunTask(PendingTaskInfo(file_path, content::BrowserThread::IO,
+ FROM_HERE, closure));
+}
+
void MTPDeviceDelegateImplLinux::CancelPendingTasksAndDeleteDelegate() {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
// To cancel all the pending tasks, destroy the MTPDeviceTaskHelper object.
@@ -716,6 +816,111 @@ void MTPDeviceDelegateImplLinux::CopyFileFromLocalInternal(
PendingRequestDone();
}
+void MTPDeviceDelegateImplLinux::DeleteFileInternal(
+ const base::FilePath& file_path,
+ const DeleteFileSuccessCallback& success_callback,
+ const ErrorCallback& error_callback,
+ const base::File::Info& file_info) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+ if (file_info.is_directory) {
+ error_callback.Run(base::File::FILE_ERROR_NOT_A_FILE);
+ } else {
+ uint32 file_id;
+ if (CachedPathToId(file_path, &file_id))
+ RunDeleteObjectOnUIThread(file_id, success_callback, error_callback);
+ else
+ error_callback.Run(base::File::FILE_ERROR_NOT_FOUND);
+ }
+
+ PendingRequestDone();
+}
+
+void MTPDeviceDelegateImplLinux::DeleteDirectoryInternal(
+ const base::FilePath& file_path,
+ const DeleteDirectorySuccessCallback& success_callback,
+ const ErrorCallback& error_callback,
+ const base::File::Info& file_info) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+ if (!file_info.is_directory) {
+ error_callback.Run(base::File::FILE_ERROR_NOT_A_DIRECTORY);
+ PendingRequestDone();
+ return;
+ }
+
+ uint32 directory_id;
+ if (!CachedPathToId(file_path, &directory_id)) {
+ error_callback.Run(base::File::FILE_ERROR_NOT_FOUND);
+ PendingRequestDone();
+ return;
+ }
+
+ // Checks the cache first. If it has children in cache, the directory cannot
+ // be empty.
+ FileIdToMTPFileNodeMap::const_iterator it =
+ file_id_to_node_map_.find(directory_id);
+ if (it != file_id_to_node_map_.end() && it->second->HasChildren()) {
+ error_callback.Run(base::File::FILE_ERROR_NOT_EMPTY);
+ PendingRequestDone();
+ return;
+ }
+
+ // Since the directory can contain a file even if the cache returns it as
+ // empty, read the directory and confirm the directory is actually empty.
+ const MTPDeviceTaskHelper::ReadDirectoryEntryIdsSuccessCallback
+ success_callback_wrapper =
+ base::Bind(&MTPDeviceDelegateImplLinux::
+ OnDidReadDirectoryEntryIdsToDeleteDirectory,
+ weak_ptr_factory_.GetWeakPtr(), directory_id,
+ success_callback, error_callback);
+ const MTPDeviceTaskHelper::ErrorCallback error_callback_wrapper =
+ base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError,
+ weak_ptr_factory_.GetWeakPtr(), error_callback, directory_id);
+ const base::Closure closure = base::Bind(
+ &ReadDirectoryEntryIdsOnUIThread, storage_name_, read_only_, directory_id,
+ success_callback_wrapper, error_callback_wrapper);
+ EnsureInitAndRunTask(PendingTaskInfo(
Lei Zhang 2015/03/10 00:48:06 This can also just be PostTask().
yawano 2015/03/10 05:01:28 If we use PostTask instead of PendingTaskInfo with
Lei Zhang 2015/03/10 08:12:04 If you were to use PostTask(), then you would not
yawano 2015/03/10 08:20:36 Acknowledged.
+ base::FilePath(), content::BrowserThread::UI, FROM_HERE, closure));
+ PendingRequestDone();
+}
+
+void MTPDeviceDelegateImplLinux::OnDidReadDirectoryEntryIdsToDeleteDirectory(
+ const uint32 directory_id,
+ const DeleteDirectorySuccessCallback& success_callback,
+ const ErrorCallback& error_callback,
+ const std::vector<uint32>& file_ids) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+ if (file_ids.size() > 0)
+ error_callback.Run(base::File::FILE_ERROR_NOT_EMPTY);
+ else
+ RunDeleteObjectOnUIThread(directory_id, success_callback, error_callback);
+
+ PendingRequestDone();
+}
+
+void MTPDeviceDelegateImplLinux::RunDeleteObjectOnUIThread(
+ const uint32 object_id,
+ const DeleteObjectSuccessCallback& success_callback,
+ const ErrorCallback& error_callback) {
+ const MTPDeviceTaskHelper::DeleteObjectSuccessCallback
+ success_callback_wrapper = base::Bind(
+ &MTPDeviceDelegateImplLinux::OnDidDeleteObject,
+ weak_ptr_factory_.GetWeakPtr(), object_id, success_callback);
+
+ const MTPDeviceTaskHelper::ErrorCallback error_callback_wrapper =
+ base::Bind(&MTPDeviceDelegateImplLinux::HandleDeleteFileOrDirectoryError,
+ weak_ptr_factory_.GetWeakPtr(), error_callback);
+
+ const base::Closure closure =
+ base::Bind(&DeleteObjectOnUIThread, storage_name_, read_only_, object_id,
+ success_callback_wrapper, error_callback_wrapper);
+
+ content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
+ closure);
+}
+
void MTPDeviceDelegateImplLinux::EnsureInitAndRunTask(
const PendingTaskInfo& task_info) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
@@ -1022,20 +1227,32 @@ void MTPDeviceDelegateImplLinux::HandleCopyFileFromLocalError(
PendingRequestDone();
}
+void MTPDeviceDelegateImplLinux::OnDidDeleteObject(
+ const uint32 object_id,
+ const DeleteObjectSuccessCallback success_callback) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+ EvictCachedPathToId(object_id);
+ success_callback.Run();
+ PendingRequestDone();
+}
+
+void MTPDeviceDelegateImplLinux::HandleDeleteFileOrDirectoryError(
+ const ErrorCallback& error_callback,
+ base::File::Error error) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+ error_callback.Run(error);
+ PendingRequestDone();
+}
+
void MTPDeviceDelegateImplLinux::HandleDeviceFileError(
const ErrorCallback& error_callback,
uint32 file_id,
base::File::Error error) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- FileIdToMTPFileNodeMap::iterator it = file_id_to_node_map_.find(file_id);
- if (it != file_id_to_node_map_.end()) {
- MTPFileNode* parent = it->second->parent();
- if (parent) {
- bool ret = parent->DeleteChild(file_id);
- DCHECK(ret);
- }
- }
+ EvictCachedPathToId(file_id);
error_callback.Run(error);
PendingRequestDone();
}
@@ -1109,6 +1326,18 @@ bool MTPDeviceDelegateImplLinux::CachedPathToId(const base::FilePath& path,
return true;
}
+void MTPDeviceDelegateImplLinux::EvictCachedPathToId(const uint32 id) {
+ FileIdToMTPFileNodeMap::iterator it = file_id_to_node_map_.find(id);
+ if (it != file_id_to_node_map_.end()) {
+ DCHECK(!it->second->HasChildren());
+ MTPFileNode* parent = it->second->parent();
+ if (parent) {
+ const bool ret = parent->DeleteChild(id);
+ DCHECK(ret);
+ }
+ }
+}
+
void CreateMTPDeviceAsyncDelegate(
const std::string& device_location,
const bool read_only,

Powered by Google App Engine
This is Rietveld 408576698