1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef CHROMEOS_DBUS_CROS_DISKS_CLIENT_H_
6 #define CHROMEOS_DBUS_CROS_DISKS_CLIENT_H_
7 
8 #include <stdint.h>
9 
10 #include <memory>
11 #include <string>
12 #include <vector>
13 
14 #include "base/callback_forward.h"
15 #include "base/component_export.h"
16 #include "base/macros.h"
17 #include "base/observer_list_types.h"
18 #include "chromeos/dbus/dbus_client.h"
19 #include "chromeos/dbus/dbus_method_call_status.h"
20 
21 namespace base {
22 class FilePath;
23 }
24 
25 namespace dbus {
26 class Response;
27 }
28 
29 // TODO(tbarzic): We should move these enums inside CrosDisksClient,
30 // to be clearer where they come from. Also, most of these are partially or
31 // completely duplicated in third_party/dbus/service_constants.h. We should
32 // probably use enums from service_contstants directly.
33 namespace chromeos {
34 
35 // Enum describing types of mount used by cros-disks.
36 enum MountType {
37   MOUNT_TYPE_INVALID,
38   MOUNT_TYPE_DEVICE,
39   MOUNT_TYPE_ARCHIVE,
40   MOUNT_TYPE_NETWORK_STORAGE,
41 };
42 
43 // Type of device.
44 enum DeviceType {
45   DEVICE_TYPE_UNKNOWN,
46   DEVICE_TYPE_USB,  // USB stick.
47   DEVICE_TYPE_SD,  // SD card.
48   DEVICE_TYPE_OPTICAL_DISC,  // e.g. Optical disc excluding DVD.
49   DEVICE_TYPE_MOBILE,  // Storage on a mobile device (e.g. Android).
50   DEVICE_TYPE_DVD,  // DVD.
51 };
52 
53 // Mount error code used by cros-disks.
54 // These values are not the same as cros_disks::MountErrorType.
55 // These values are persisted to logs. Entries should not be renumbered and
56 // numeric values should never be reused.
57 enum MountError {
58   MOUNT_ERROR_NONE,
59   MOUNT_ERROR_UNKNOWN,
60   MOUNT_ERROR_INTERNAL,
61   MOUNT_ERROR_INVALID_ARGUMENT,
62   MOUNT_ERROR_INVALID_PATH,
63   MOUNT_ERROR_PATH_ALREADY_MOUNTED,
64   MOUNT_ERROR_PATH_NOT_MOUNTED,
65   MOUNT_ERROR_DIRECTORY_CREATION_FAILED,
66   MOUNT_ERROR_INVALID_MOUNT_OPTIONS,
67   MOUNT_ERROR_INVALID_UNMOUNT_OPTIONS,
68   MOUNT_ERROR_INSUFFICIENT_PERMISSIONS,
69   MOUNT_ERROR_MOUNT_PROGRAM_NOT_FOUND,
70   MOUNT_ERROR_MOUNT_PROGRAM_FAILED,
71   MOUNT_ERROR_INVALID_DEVICE_PATH,
72   MOUNT_ERROR_UNKNOWN_FILESYSTEM,
73   MOUNT_ERROR_UNSUPPORTED_FILESYSTEM,
74   MOUNT_ERROR_INVALID_ARCHIVE,
75   MOUNT_ERROR_NEED_PASSWORD,
76   MOUNT_ERROR_COUNT,
77 };
78 
79 // Rename error reported by cros-disks.
80 enum RenameError {
81   RENAME_ERROR_NONE,
82   RENAME_ERROR_UNKNOWN,
83   RENAME_ERROR_INTERNAL,
84   RENAME_ERROR_INVALID_DEVICE_PATH,
85   RENAME_ERROR_DEVICE_BEING_RENAMED,
86   RENAME_ERROR_UNSUPPORTED_FILESYSTEM,
87   RENAME_ERROR_RENAME_PROGRAM_NOT_FOUND,
88   RENAME_ERROR_RENAME_PROGRAM_FAILED,
89   RENAME_ERROR_DEVICE_NOT_ALLOWED,
90   RENAME_ERROR_LONG_NAME,
91   RENAME_ERROR_INVALID_CHARACTER,
92 };
93 
94 // Format error reported by cros-disks.
95 // These values are persisted to logs. Entries should not be renumbered and
96 // numeric values should never be reused.
97 enum FormatError {
98   FORMAT_ERROR_NONE,
99   FORMAT_ERROR_UNKNOWN,
100   FORMAT_ERROR_INTERNAL,
101   FORMAT_ERROR_INVALID_DEVICE_PATH,
102   FORMAT_ERROR_DEVICE_BEING_FORMATTED,
103   FORMAT_ERROR_UNSUPPORTED_FILESYSTEM,
104   FORMAT_ERROR_FORMAT_PROGRAM_NOT_FOUND,
105   FORMAT_ERROR_FORMAT_PROGRAM_FAILED,
106   FORMAT_ERROR_DEVICE_NOT_ALLOWED,
107   FORMAT_ERROR_INVALID_OPTIONS,
108   FORMAT_ERROR_LONG_NAME,
109   FORMAT_ERROR_INVALID_CHARACTER,
110   FORMAT_ERROR_COUNT,
111 };
112 
113 // Partition error reported by cros-disks.
114 enum PartitionError {
115   PARTITION_ERROR_NONE = 0,
116   PARTITION_ERROR_UNKNOWN = 1,
117   PARTITION_ERROR_INTERNAL = 2,
118   PARTITION_ERROR_INVALID_DEVICE_PATH = 3,
119   PARTITION_ERROR_DEVICE_BEING_PARTITIONED = 4,
120   PARTITION_ERROR_PROGRAM_NOT_FOUND = 5,
121   PARTITION_ERROR_PROGRAM_FAILED = 6,
122   PARTITION_ERROR_DEVICE_NOT_ALLOWED = 7,
123 };
124 
125 // Event type each corresponding to a signal sent from cros-disks.
126 enum MountEventType {
127   CROS_DISKS_DISK_ADDED,
128   CROS_DISKS_DISK_REMOVED,
129   CROS_DISKS_DISK_CHANGED,
130   CROS_DISKS_DEVICE_ADDED,
131   CROS_DISKS_DEVICE_REMOVED,
132   CROS_DISKS_DEVICE_SCANNED,
133 };
134 
135 // Mount option to control write permission to a device.
136 enum MountAccessMode {
137   MOUNT_ACCESS_MODE_READ_WRITE,
138   MOUNT_ACCESS_MODE_READ_ONLY,
139 };
140 
141 // Whether to mount to a new path or remount a device already mounted.
142 enum RemountOption {
143   // Mount a new device. If the device is already mounted, the mount status is
144   // unchanged and the callback for MountCompleted will receive
145   // MOUNT_ERROR_PATH_ALREADY_MOUNTED error code.
146   REMOUNT_OPTION_MOUNT_NEW_DEVICE,
147   // Remount a device that is already mounted. If the device is not mounted
148   // yet, it will do nothing and the callback for MountCompleted will receive
149   // MOUNT_ERROR_PATH_NOT_MOUNTED error code.
150   REMOUNT_OPTION_REMOUNT_EXISTING_DEVICE,
151 };
152 
153 // A class to represent information about a disk sent from cros-disks.
COMPONENT_EXPORT(CHROMEOS_DBUS)154 class COMPONENT_EXPORT(CHROMEOS_DBUS) DiskInfo {
155  public:
156   DiskInfo(const std::string& device_path, dbus::Response* response);
157   ~DiskInfo();
158 
159   // Device path. (e.g. /sys/devices/pci0000:00/.../8:0:0:0/block/sdb/sdb1)
160   const std::string& device_path() const { return device_path_; }
161 
162   // Disk mount path. (e.g. /media/removable/VOLUME)
163   const std::string& mount_path() const { return mount_path_; }
164 
165   // Path of the scsi/mmc/nvme storage device that this disk is a part of.
166   // (e.g. /sys/devices/pci0000:00/.../mmc_host/mmc0/mmc0:0002)
167   const std::string& storage_device_path() const {
168     return storage_device_path_;
169   }
170 
171   // Is a drive or not. (i.e. true with /dev/sdb, false with /dev/sdb1)
172   bool is_drive() const { return is_drive_; }
173 
174   // Does the disk have media content.
175   bool has_media() const { return has_media_; }
176 
177   // Is the disk on device we booted the machine from.
178   bool on_boot_device() const { return on_boot_device_; }
179 
180   // Is the disk on a removable device.
181   bool on_removable_device() const { return on_removable_device_; }
182 
183   // Is the device read-only.
184   bool is_read_only() const { return is_read_only_; }
185 
186   // Returns true if the device should be hidden from the file browser.
187   bool is_hidden() const { return is_hidden_; }
188 
189   // Is the disk virtual.
190   bool is_virtual() const { return is_virtual_; }
191 
192   // Is the disk auto-mountable.
193   bool is_auto_mountable() const { return is_auto_mountable_; }
194 
195   // Disk file path (e.g. /dev/sdb).
196   const std::string& file_path() const { return file_path_; }
197 
198   // Disk label.
199   const std::string& label() const { return label_; }
200 
201   // Vendor ID of the device (e.g. "18d1").
202   const std::string& vendor_id() const { return vendor_id_; }
203 
204   // Vendor name of the device (e.g. "Google Inc.").
205   const std::string& vendor_name() const { return vendor_name_; }
206 
207   // Product ID of the device (e.g. "4e11").
208   const std::string& product_id() const { return product_id_; }
209 
210   // Product name of the device (e.g. "Nexus One").
211   const std::string& product_name() const { return product_name_; }
212 
213   // Disk model. (e.g. "TransMemory")
214   const std::string& drive_label() const { return drive_model_; }
215 
216   // Device type. Not working well, yet.
217   DeviceType device_type() const { return device_type_; }
218 
219   // Total size of the disk in bytes.
220   uint64_t total_size_in_bytes() const { return total_size_in_bytes_; }
221 
222   // Returns file system uuid.
223   const std::string& uuid() const { return uuid_; }
224 
225   // Returns file system type identifier.
226   const std::string& file_system_type() const { return file_system_type_; }
227 
228  private:
229   void InitializeFromResponse(dbus::Response* response);
230 
231   std::string device_path_;
232   std::string mount_path_;
233   std::string storage_device_path_;
234   bool is_drive_;
235   bool has_media_;
236   bool on_boot_device_;
237   bool on_removable_device_;
238   bool is_read_only_;
239   bool is_hidden_;
240   bool is_virtual_;
241   bool is_auto_mountable_;
242 
243   std::string file_path_;
244   std::string label_;
245   std::string vendor_id_;
246   std::string vendor_name_;
247   std::string product_id_;
248   std::string product_name_;
249   std::string drive_model_;
250   DeviceType device_type_;
251   uint64_t total_size_in_bytes_;
252   std::string uuid_;
253   std::string file_system_type_;
254 };
255 
256 // A struct to represent information about a mount point sent from cros-disks.
COMPONENT_EXPORT(CHROMEOS_DBUS)257 struct COMPONENT_EXPORT(CHROMEOS_DBUS) MountEntry {
258  public:
259   MountEntry()
260       : error_code_(MOUNT_ERROR_UNKNOWN), mount_type_(MOUNT_TYPE_INVALID) {
261   }
262 
263   MountEntry(MountError error_code,
264              const std::string& source_path,
265              MountType mount_type,
266              const std::string& mount_path)
267       : error_code_(error_code),
268         source_path_(source_path),
269         mount_type_(mount_type),
270         mount_path_(mount_path) {
271   }
272 
273   MountError error_code() const { return error_code_; }
274   const std::string& source_path() const { return source_path_; }
275   MountType mount_type() const { return mount_type_; }
276   const std::string& mount_path() const { return mount_path_; }
277 
278  private:
279   MountError error_code_;
280   std::string source_path_;
281   MountType mount_type_;
282   std::string mount_path_;
283 };
284 
285 // A class to make the actual DBus calls for cros-disks service.
286 // This class only makes calls, result/error handling should be done
287 // by callbacks.
COMPONENT_EXPORT(CHROMEOS_DBUS)288 class COMPONENT_EXPORT(CHROMEOS_DBUS) CrosDisksClient : public DBusClient {
289  public:
290   // A callback to handle the result of EnumerateDevices.
291   // The argument is the enumerated device paths.
292   typedef base::OnceCallback<void(const std::vector<std::string>& device_paths)>
293       EnumerateDevicesCallback;
294 
295   // A callback to handle the result of EnumerateMountEntries.
296   // The argument is the enumerated mount entries.
297   typedef base::OnceCallback<void(const std::vector<MountEntry>& entries)>
298       EnumerateMountEntriesCallback;
299 
300   // A callback to handle the result of GetDeviceProperties.
301   // The argument is the information about the specified device.
302   typedef base::OnceCallback<void(const DiskInfo& disk_info)>
303       GetDevicePropertiesCallback;
304 
305   // A callback to handle the result of Unmount.
306   // The argument is the unmount error code.
307   typedef base::OnceCallback<void(MountError error_code)> UnmountCallback;
308 
309   // A callback to handle the result of SinglePartitionFormat.
310   // The argument is the partition error code.
311   using PartitionCallback = base::OnceCallback<void(PartitionError error_code)>;
312 
313   class Observer : public base::CheckedObserver {
314    public:
315     // Called when a mount event signal is received.
316     virtual void OnMountEvent(MountEventType event_type,
317                               const std::string& device_path) = 0;
318 
319     // Called when a MountCompleted signal is received.
320     virtual void OnMountCompleted(const MountEntry& entry) = 0;
321 
322     // Called when a FormatCompleted signal is received.
323     virtual void OnFormatCompleted(FormatError error_code,
324                                    const std::string& device_path) = 0;
325 
326     // Called when a RenameCompleted signal is received.
327     virtual void OnRenameCompleted(RenameError error_code,
328                                    const std::string& device_path) = 0;
329   };
330 
331   ~CrosDisksClient() override;
332 
333   // Registers the given |observer| to listen D-Bus signals.
334   virtual void AddObserver(Observer* observer) = 0;
335 
336   // Unregisters the |observer| from this instance.
337   virtual void RemoveObserver(Observer* observer) = 0;
338 
339   // Calls Mount method.  On method call completion, |callback| is called with
340   // |true| on success, or with |false| otherwise.
341   // When mounting an archive, caller may set two optional arguments:
342   // - The |source_format| argument passes the file extension (with the leading
343   //   dot, for example ".zip"). If |source_format| is empty then the source
344   //   format is auto-detected.
345   // - The |mount_label| argument passes an optional mount label to be used as
346   //   the directory name of the mount point. If |mount_label| is empty, the
347   //   mount label will be based on the |source_path|.
348   virtual void Mount(const std::string& source_path,
349                      const std::string& source_format,
350                      const std::string& mount_label,
351                      const std::vector<std::string>& mount_options,
352                      MountAccessMode access_mode,
353                      RemountOption remount,
354                      VoidDBusMethodCallback callback) = 0;
355 
356   // Calls Unmount method.  On method call completion, |callback| is called
357   // with the error code.
358   virtual void Unmount(const std::string& device_path,
359                        UnmountCallback callback) = 0;
360 
361   // Calls EnumerateDevices method.  |callback| is called after the
362   // method call succeeds, otherwise, |error_callback| is called.
363   virtual void EnumerateDevices(EnumerateDevicesCallback callback,
364                                 base::OnceClosure error_callback) = 0;
365 
366   // Calls EnumerateMountEntries.  |callback| is called after the
367   // method call succeeds, otherwise, |error_callback| is called.
368   virtual void EnumerateMountEntries(EnumerateMountEntriesCallback callback,
369                                      base::OnceClosure error_callback) = 0;
370 
371   // Calls Format method. On completion, |callback| is called, with |true| on
372   // success, or with |false| otherwise.
373   virtual void Format(const std::string& device_path,
374                       const std::string& filesystem,
375                       const std::string& label,
376                       VoidDBusMethodCallback callback) = 0;
377 
378   // Calls SinglePartitionFormat async method. |callback| is called when
379   // response received.
380   virtual void SinglePartitionFormat(const std::string& device_path,
381                                      PartitionCallback callback) = 0;
382 
383   // Calls Rename method. On completion, |callback| is called, with |true| on
384   // success, or with |false| otherwise.
385   virtual void Rename(const std::string& device_path,
386                       const std::string& volume_name,
387                       VoidDBusMethodCallback callback) = 0;
388 
389   // Calls GetDeviceProperties method.  |callback| is called after the method
390   // call succeeds, otherwise, |error_callback| is called.
391   virtual void GetDeviceProperties(const std::string& device_path,
392                                    GetDevicePropertiesCallback callback,
393                                    base::OnceClosure error_callback) = 0;
394 
395   // Factory function, creates a new instance and returns ownership.
396   // For normal usage, access the singleton via DBusThreadManager::Get().
397   static std::unique_ptr<CrosDisksClient> Create();
398 
399   // Returns the path of the mount point for archive files.
400   static base::FilePath GetArchiveMountPoint();
401 
402   // Returns the path of the mount point for removable disks.
403   static base::FilePath GetRemovableDiskMountPoint();
404 
405   // Composes a list of mount options.
406   static std::vector<std::string> ComposeMountOptions(
407       const std::vector<std::string>& options,
408       const std::string& mount_label,
409       MountAccessMode access_mode,
410       RemountOption remount);
411 
412  protected:
413   // Create() should be used instead.
414   CrosDisksClient();
415 
416  private:
417   DISALLOW_COPY_AND_ASSIGN(CrosDisksClient);
418 };
419 
420 }  // namespace chromeos
421 
422 #endif  // CHROMEOS_DBUS_CROS_DISKS_CLIENT_H_
423