smbprovider: Add ReadDirectory and GetMetadataEntry

Add ReadDirectory and GetMetadataEntry methods for SmbProviderClient.
This allows read-only navigation of the share, excluding reading files.

Bug:chromium:757625
CQ-DEPEND=CL:794892

Change-Id: I55d4baa6dec95392774cdea3c07c13989b31e782
Reviewed-on: https://chromium-review.googlesource.com/749897
Commit-Queue: Allen Vicencio <allenvic@chromium.org>
Reviewed-by: Zentaro Kavanagh <zentaro@chromium.org>
Reviewed-by: Dan Erat <derat@chromium.org>
Cr-Commit-Position: refs/heads/master@{#523259}
diff --git a/chrome/browser/chromeos/smb_client/smb_service.cc b/chrome/browser/chromeos/smb_client/smb_service.cc
index 4caa662b..b676e9a 100644
--- a/chrome/browser/chromeos/smb_client/smb_service.cc
+++ b/chrome/browser/chromeos/smb_client/smb_service.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/smb_client/smb_service.h"
 
+#include "base/files/file_path.h"
 #include "base/strings/string_number_conversions.h"
 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_info.h"
 #include "chrome/browser/chromeos/smb_client/smb_file_system.h"
@@ -35,7 +36,7 @@
 }
 
 void SmbService::Mount(const file_system_provider::MountOptions& options,
-                       const std::string& share_path,
+                       const base::FilePath& share_path,
                        MountResponse callback) {
   chromeos::DBusThreadManager::Get()->GetSmbProviderClient()->Mount(
       share_path, base::BindOnce(&SmbService::OnMountResponse,
diff --git a/chrome/browser/chromeos/smb_client/smb_service.h b/chrome/browser/chromeos/smb_client/smb_service.h
index ce685aa9..3404adb 100644
--- a/chrome/browser/chromeos/smb_client/smb_service.h
+++ b/chrome/browser/chromeos/smb_client/smb_service.h
@@ -18,6 +18,10 @@
 #include "chromeos/dbus/smb_provider_client.h"
 #include "components/keyed_service/core/keyed_service.h"
 
+namespace base {
+class FilePath;
+}  // namespace base
+
 namespace chromeos {
 namespace smb_client {
 
@@ -42,7 +46,7 @@
   // Starts the process of mounting an SMB file system.
   // Calls SmbProviderClient::Mount().
   void Mount(const file_system_provider::MountOptions& options,
-             const std::string& share_path,
+             const base::FilePath& share_path,
              MountResponse callback);
 
   // Completes the mounting of an SMB file system, passing |options| on to
diff --git a/chromeos/dbus/fake_smb_provider_client.cc b/chromeos/dbus/fake_smb_provider_client.cc
index 54eec61..45c135f 100644
--- a/chromeos/dbus/fake_smb_provider_client.cc
+++ b/chromeos/dbus/fake_smb_provider_client.cc
@@ -4,7 +4,6 @@
 
 #include "chromeos/dbus/fake_smb_provider_client.h"
 
-#include <string>
 #include <utility>
 
 #include "base/bind.h"
@@ -19,7 +18,7 @@
 
 void FakeSmbProviderClient::Init(dbus::Bus* bus) {}
 
-void FakeSmbProviderClient::Mount(const std::string& share_path,
+void FakeSmbProviderClient::Mount(const base::FilePath& share_path,
                                   MountCallback callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindOnce(std::move(callback), smbprovider::ERROR_OK, 1));
@@ -31,4 +30,22 @@
       FROM_HERE, base::BindOnce(std::move(callback), smbprovider::ERROR_OK));
 }
 
+void FakeSmbProviderClient::ReadDirectory(int32_t mount_id,
+                                          const base::FilePath& directory_path,
+                                          ReadDirectoryCallback callback) {
+  smbprovider::DirectoryEntryList entry_list;
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::BindOnce(std::move(callback), smbprovider::ERROR_OK, entry_list));
+}
+
+void FakeSmbProviderClient::GetMetadataEntry(int32_t mount_id,
+                                             const base::FilePath& entry_path,
+                                             GetMetdataEntryCallback callback) {
+  smbprovider::DirectoryEntry entry;
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::BindOnce(std::move(callback), smbprovider::ERROR_OK, entry));
+}
+
 }  // namespace chromeos
diff --git a/chromeos/dbus/fake_smb_provider_client.h b/chromeos/dbus/fake_smb_provider_client.h
index 3b46101..c794ae6 100644
--- a/chromeos/dbus/fake_smb_provider_client.h
+++ b/chromeos/dbus/fake_smb_provider_client.h
@@ -19,8 +19,14 @@
   void Init(dbus::Bus* bus) override;
 
   // SmbProviderClient override.
-  void Mount(const std::string& share_path, MountCallback callback) override;
+  void Mount(const base::FilePath& share_path, MountCallback callback) override;
   void Unmount(int32_t mount_id, UnmountCallback callback) override;
+  void ReadDirectory(int32_t mount_id,
+                     const base::FilePath& directory_path,
+                     ReadDirectoryCallback callback) override;
+  void GetMetadataEntry(int32_t mount_id,
+                        const base::FilePath& entry_path,
+                        GetMetdataEntryCallback callback) override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(FakeSmbProviderClient);
diff --git a/chromeos/dbus/smb_provider_client.cc b/chromeos/dbus/smb_provider_client.cc
index 1858238e..f0d0fea6 100644
--- a/chromeos/dbus/smb_provider_client.cc
+++ b/chromeos/dbus/smb_provider_client.cc
@@ -26,18 +26,38 @@
   return static_cast<smbprovider::ErrorType>(int_error);
 }
 
+smbprovider::ErrorType GetErrorAndProto(
+    dbus::Response* response,
+    google::protobuf::MessageLite* protobuf_out) {
+  if (!response) {
+    DLOG(ERROR) << "Failed to call smbprovider";
+    return smbprovider::ERROR_DBUS_PARSE_FAILED;
+  }
+  dbus::MessageReader reader(response);
+  smbprovider::ErrorType error(GetErrorFromReader(&reader));
+  if (error != smbprovider::ERROR_OK) {
+    return error;
+  }
+  if (!reader.PopArrayOfBytesAsProto(protobuf_out)) {
+    DLOG(ERROR) << "Failed to parse protobuf.";
+    return smbprovider::ERROR_DBUS_PARSE_FAILED;
+  }
+  return smbprovider::ERROR_OK;
+}
+
 class SmbProviderClientImpl : public SmbProviderClient {
  public:
   SmbProviderClientImpl() : weak_ptr_factory_(this) {}
 
   ~SmbProviderClientImpl() override {}
 
-  void Mount(const std::string& share_path, MountCallback callback) override {
+  void Mount(const base::FilePath& share_path,
+             MountCallback callback) override {
     dbus::MethodCall method_call(smbprovider::kSmbProviderInterface,
                                  smbprovider::kMountMethod);
     dbus::MessageWriter writer(&method_call);
     smbprovider::MountOptions mount_options;
-    mount_options.set_path(share_path);
+    mount_options.set_path(share_path.value());
     writer.AppendProtoAsArrayOfBytes(mount_options);
     proxy_->CallMethod(
         &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
@@ -58,6 +78,42 @@
                    weak_ptr_factory_.GetWeakPtr(), base::Passed(&callback)));
   }
 
+  void ReadDirectory(int32_t mount_id,
+                     const base::FilePath& directory_path,
+                     ReadDirectoryCallback callback) override {
+    dbus::MethodCall method_call(smbprovider::kSmbProviderInterface,
+                                 smbprovider::kReadDirectoryMethod);
+    dbus::MessageWriter writer(&method_call);
+    smbprovider::ReadDirectoryOptions read_directory_options;
+    read_directory_options.set_mount_id(mount_id);
+    read_directory_options.set_directory_path(directory_path.value());
+    writer.AppendProtoAsArrayOfBytes(read_directory_options);
+    proxy_->CallMethod(
+        &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+        base::BindOnce(&SmbProviderClientImpl::HandleProtoCallback<
+                           smbprovider::DirectoryEntryList>,
+                       weak_ptr_factory_.GetWeakPtr(),
+                       base::Passed(&callback)));
+  }
+
+  void GetMetadataEntry(int32_t mount_id,
+                        const base::FilePath& entry_path,
+                        GetMetdataEntryCallback callback) override {
+    dbus::MethodCall method_call(smbprovider::kSmbProviderInterface,
+                                 smbprovider::kGetMetadataEntryMethod);
+    dbus::MessageWriter writer(&method_call);
+    smbprovider::GetMetadataEntryOptions get_metadata_entry_options;
+    get_metadata_entry_options.set_mount_id(mount_id);
+    get_metadata_entry_options.set_entry_path(entry_path.value());
+    writer.AppendProtoAsArrayOfBytes(get_metadata_entry_options);
+    proxy_->CallMethod(
+        &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+        base::BindOnce(&SmbProviderClientImpl::HandleProtoCallback<
+                           smbprovider::DirectoryEntry>,
+                       weak_ptr_factory_.GetWeakPtr(),
+                       base::Passed(&callback)));
+  }
+
  protected:
   // DBusClient override.
   void Init(dbus::Bus* bus) override {
@@ -101,6 +157,17 @@
     std::move(callback).Run(GetErrorFromReader(&reader));
   }
 
+  // Handles D-Bus responses for methods that return an error and a protobuf
+  // object.
+  template <class T>
+  void HandleProtoCallback(base::OnceCallback<void(smbprovider::ErrorType error,
+                                                   const T& response)> callback,
+                           dbus::Response* response) {
+    T proto;
+    smbprovider::ErrorType error(GetErrorAndProto(response, &proto));
+    std::move(callback).Run(error, proto);
+  }
+
   dbus::ObjectProxy* proxy_ = nullptr;
 
   // Note: This should remain the last member so it'll be destroyed and
diff --git a/chromeos/dbus/smb_provider_client.h b/chromeos/dbus/smb_provider_client.h
index 776177f..94ba9cf6 100644
--- a/chromeos/dbus/smb_provider_client.h
+++ b/chromeos/dbus/smb_provider_client.h
@@ -5,10 +5,8 @@
 #ifndef CHROMEOS_DBUS_SMB_PROVIDER_CLIENT_H_
 #define CHROMEOS_DBUS_SMB_PROVIDER_CLIENT_H_
 
-#include <string>
-
-#include <base/callback.h>
-
+#include "base/callback.h"
+#include "base/files/file_path.h"
 #include "chromeos/chromeos_export.h"
 #include "chromeos/dbus/dbus_client.h"
 #include "chromeos/dbus/smbprovider/directory_entry.pb.h"
@@ -26,6 +24,12 @@
       base::OnceCallback<void(smbprovider::ErrorType error, int32_t mount_id)>;
   using UnmountCallback =
       base::OnceCallback<void(smbprovider::ErrorType error)>;
+  using ReadDirectoryCallback =
+      base::OnceCallback<void(smbprovider::ErrorType error,
+                              const smbprovider::DirectoryEntryList& entries)>;
+  using GetMetdataEntryCallback =
+      base::OnceCallback<void(smbprovider::ErrorType error,
+                              const smbprovider::DirectoryEntry& entry)>;
 
   ~SmbProviderClient() override;
 
@@ -36,12 +40,27 @@
   // Calls Mount. It runs OpenDirectory() on |share_path| to check that it is a
   // valid share. |callback| is called after getting (or failing to get) D-BUS
   // response.
-  virtual void Mount(const std::string& share_path, MountCallback callback) = 0;
+  virtual void Mount(const base::FilePath& share_path,
+                     MountCallback callback) = 0;
 
   // Calls Unmount. This removes the corresponding mount of |mount_id| from
   // the list of valid mounts. Subsequent operations on |mount_id| will fail.
   virtual void Unmount(int32_t mount_id, UnmountCallback callback) = 0;
 
+  // Calls ReadDirectory. Using the corresponding mount of |mount_id|, this
+  // reads the directory on a given |directory_path| and passes the
+  // DirectoryEntryList to the supplied ReadDirectoryCallback.
+  virtual void ReadDirectory(int32_t mount_id,
+                             const base::FilePath& directory_path,
+                             ReadDirectoryCallback callback) = 0;
+
+  // Calls GetMetadataEntry. Using the corresponding mount of |mount_id|, this
+  // reads an entry in a given |entry_path| and passes the DirectoryEntry to the
+  // supplied GetMetadataEntryCallback.
+  virtual void GetMetadataEntry(int32_t mount_id,
+                                const base::FilePath& entry_path,
+                                GetMetdataEntryCallback callback) = 0;
+
  protected:
   // Create() should be used instead.
   SmbProviderClient();