• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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 #include "chrome/browser/chromeos/cros/mount_library.h"
6 
7 #include <set>
8 
9 #include "base/message_loop.h"
10 #include "base/string_util.h"
11 #include "chrome/browser/chromeos/cros/cros_library.h"
12 #include "content/browser/browser_thread.h"
13 
14 const char* kLibraryNotLoaded = "Cros Library not loaded";
15 
16 namespace chromeos {
17 
Disk(const std::string & device_path,const std::string & mount_path,const std::string & system_path,const std::string & file_path,const std::string & device_label,const std::string & drive_label,const std::string & parent_path,DeviceType device_type,uint64 total_size,bool is_parent,bool is_read_only,bool has_media,bool on_boot_device)18 MountLibrary::Disk::Disk(const std::string& device_path,
19      const std::string& mount_path,
20      const std::string& system_path,
21      const std::string& file_path,
22      const std::string& device_label,
23      const std::string& drive_label,
24      const std::string& parent_path,
25      DeviceType device_type,
26      uint64 total_size,
27      bool is_parent,
28      bool is_read_only,
29      bool has_media,
30      bool on_boot_device)
31     : device_path_(device_path),
32       mount_path_(mount_path),
33       system_path_(system_path),
34       file_path_(file_path),
35       device_label_(device_label),
36       drive_label_(drive_label),
37       parent_path_(parent_path),
38       device_type_(device_type),
39       total_size_(total_size),
40       is_parent_(is_parent),
41       is_read_only_(is_read_only),
42       has_media_(has_media),
43       on_boot_device_(on_boot_device) {
44   // Add trailing slash to mount path.
45   if (mount_path_.length() && mount_path_.at(mount_path_.length() -1) != '/')
46     mount_path_ = mount_path_.append("/");
47 }
48 
49 class MountLibraryImpl : public MountLibrary {
50  public:
MountLibraryImpl()51   MountLibraryImpl() : mount_status_connection_(NULL) {
52     if (CrosLibrary::Get()->EnsureLoaded())
53       Init();
54     else
55       LOG(ERROR) << kLibraryNotLoaded;
56   }
57 
~MountLibraryImpl()58   virtual ~MountLibraryImpl() {
59     if (mount_status_connection_)
60       DisconnectMountEventMonitor(mount_status_connection_);
61   }
62 
63   // MountLibrary overrides.
AddObserver(Observer * observer)64   virtual void AddObserver(Observer* observer) OVERRIDE {
65     observers_.AddObserver(observer);
66   }
67 
RemoveObserver(Observer * observer)68   virtual void RemoveObserver(Observer* observer) OVERRIDE {
69     observers_.RemoveObserver(observer);
70   }
71 
MountPath(const char * device_path)72   virtual void MountPath(const char* device_path) OVERRIDE {
73     CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
74     if (!CrosLibrary::Get()->EnsureLoaded()) {
75       OnMountRemovableDevice(device_path,
76                              NULL,
77                              MOUNT_METHOD_ERROR_LOCAL,
78                              kLibraryNotLoaded);
79       return;
80     }
81     MountRemovableDevice(device_path,
82                          &MountLibraryImpl::MountRemovableDeviceCallback,
83                          this);
84   }
85 
UnmountPath(const char * device_path)86   virtual void UnmountPath(const char* device_path) OVERRIDE {
87     CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
88     if (!CrosLibrary::Get()->EnsureLoaded()) {
89       OnUnmountRemovableDevice(device_path,
90                                MOUNT_METHOD_ERROR_LOCAL,
91                                kLibraryNotLoaded);
92       return;
93     }
94     UnmountRemovableDevice(device_path,
95                            &MountLibraryImpl::UnmountRemovableDeviceCallback,
96                            this);
97   }
98 
RequestMountInfoRefresh()99   virtual void RequestMountInfoRefresh() OVERRIDE {
100     CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
101     if (!CrosLibrary::Get()->EnsureLoaded()) {
102       OnRequestMountInfo(NULL,
103                          0,
104                          MOUNT_METHOD_ERROR_LOCAL,
105                          kLibraryNotLoaded);
106       return;
107     }
108     RequestMountInfo(&MountLibraryImpl::RequestMountInfoCallback,
109                      this);
110   }
111 
RefreshDiskProperties(const Disk * disk)112   virtual void RefreshDiskProperties(const Disk* disk) OVERRIDE {
113     CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
114     DCHECK(disk);
115     if (!CrosLibrary::Get()->EnsureLoaded()) {
116       OnGetDiskProperties(disk->device_path().c_str(),
117                           NULL,
118                           MOUNT_METHOD_ERROR_LOCAL,
119                           kLibraryNotLoaded);
120       return;
121     }
122     GetDiskProperties(disk->device_path().c_str(),
123                       &MountLibraryImpl::GetDiskPropertiesCallback,
124                       this);
125   }
126 
disks() const127   const DiskMap& disks() const OVERRIDE { return disks_; }
128 
129  private:
130 
131   // Callback for MountRemovableDevice method.
MountRemovableDeviceCallback(void * object,const char * device_path,const char * mount_path,MountMethodErrorType error,const char * error_message)132   static void MountRemovableDeviceCallback(void* object,
133                                            const char* device_path,
134                                            const char* mount_path,
135                                            MountMethodErrorType error,
136                                            const char* error_message) {
137     DCHECK(object);
138     MountLibraryImpl* self = static_cast<MountLibraryImpl*>(object);
139     self->OnMountRemovableDevice(device_path,
140                                  mount_path,
141                                  error,
142                                  error_message);
143   }
144 
145   // Callback for UnmountRemovableDevice method.
UnmountRemovableDeviceCallback(void * object,const char * device_path,const char * mount_path,MountMethodErrorType error,const char * error_message)146   static void UnmountRemovableDeviceCallback(void* object,
147                                              const char* device_path,
148                                              const char* mount_path,
149                                              MountMethodErrorType error,
150                                              const char* error_message) {
151     DCHECK(object);
152     MountLibraryImpl* self = static_cast<MountLibraryImpl*>(object);
153     self->OnUnmountRemovableDevice(device_path,
154                                    error,
155                                    error_message);
156   }
157 
158   // Callback for disk information retrieval calls.
GetDiskPropertiesCallback(void * object,const char * device_path,const DiskInfo * disk,MountMethodErrorType error,const char * error_message)159   static void GetDiskPropertiesCallback(void* object,
160                                         const char* device_path,
161                                         const DiskInfo* disk,
162                                         MountMethodErrorType error,
163                                         const char* error_message) {
164     DCHECK(object);
165     MountLibraryImpl* self = static_cast<MountLibraryImpl*>(object);
166     self->OnGetDiskProperties(device_path,
167                               disk,
168                               error,
169                               error_message);
170   }
171 
172   // Callback for RequestMountInfo call.
RequestMountInfoCallback(void * object,const char ** devices,size_t device_len,MountMethodErrorType error,const char * error_message)173   static void RequestMountInfoCallback(void* object,
174                                        const char** devices,
175                                        size_t device_len,
176                                        MountMethodErrorType error,
177                                        const char* error_message) {
178     DCHECK(object);
179     MountLibraryImpl* self = static_cast<MountLibraryImpl*>(object);
180     self->OnRequestMountInfo(devices,
181                              device_len,
182                              error,
183                              error_message);
184   }
185 
186   // This method will receive events that are caused by drive status changes.
MonitorMountEventsHandler(void * object,MountEventType evt,const char * device_path)187   static void MonitorMountEventsHandler(void* object,
188                                         MountEventType evt,
189                                         const char* device_path) {
190     DCHECK(object);
191     MountLibraryImpl* self = static_cast<MountLibraryImpl*>(object);
192     self->OnMountEvent(evt, device_path);
193   }
194 
195 
OnMountRemovableDevice(const char * device_path,const char * mount_path,MountMethodErrorType error,const char * error_message)196   void OnMountRemovableDevice(const char* device_path,
197                               const char* mount_path,
198                               MountMethodErrorType error,
199                               const char* error_message) {
200     DCHECK(device_path);
201 
202     if (error == MOUNT_METHOD_ERROR_NONE && device_path && mount_path) {
203       std::string path(device_path);
204       DiskMap::iterator iter = disks_.find(path);
205       if (iter == disks_.end()) {
206         // disk might have been removed by now?
207         return;
208       }
209       Disk* disk = iter->second;
210       DCHECK(disk);
211       disk->set_mount_path(mount_path);
212       FireDiskStatusUpdate(MOUNT_DISK_MOUNTED, disk);
213     } else {
214       LOG(WARNING) << "Mount request failed for device "
215                    << device_path << ", with error: "
216                    << (error_message ? error_message : "Unknown");
217     }
218   }
219 
OnUnmountRemovableDevice(const char * device_path,MountMethodErrorType error,const char * error_message)220   void OnUnmountRemovableDevice(const char* device_path,
221                                 MountMethodErrorType error,
222                                 const char* error_message) {
223     DCHECK(device_path);
224     if (error == MOUNT_METHOD_ERROR_NONE && device_path) {
225       std::string path(device_path);
226       DiskMap::iterator iter = disks_.find(path);
227       if (iter == disks_.end()) {
228         // disk might have been removed by now?
229         return;
230       }
231       Disk* disk = iter->second;
232       DCHECK(disk);
233       disk->clear_mount_path();
234       FireDiskStatusUpdate(MOUNT_DISK_UNMOUNTED, disk);
235     } else {
236       LOG(WARNING) << "Unmount request failed for device "
237                    << device_path << ", with error: "
238                    << (error_message ? error_message : "Unknown");
239     }
240   }
241 
OnGetDiskProperties(const char * device_path,const DiskInfo * disk1,MountMethodErrorType error,const char * error_message)242   void OnGetDiskProperties(const char* device_path,
243                            const DiskInfo* disk1,
244                            MountMethodErrorType error,
245                            const char* error_message) {
246     DCHECK(device_path);
247     if (error == MOUNT_METHOD_ERROR_NONE && device_path) {
248       // TODO(zelidrag): Find a better way to filter these out before we
249       // fetch the properties:
250       // Ignore disks coming from the device we booted the system from.
251 
252       // This cast is temporal solution, until we merge DiskInfo and
253       // DiskInfoAdvanced into single interface.
254       const DiskInfoAdvanced* disk =
255           reinterpret_cast<const DiskInfoAdvanced*>(disk1);
256       if (disk->on_boot_device())
257         return;
258 
259       LOG(WARNING) << "Found disk " << device_path;
260       // Delete previous disk info for this path:
261       bool is_new = true;
262       std::string device_path_string(device_path);
263       DiskMap::iterator iter = disks_.find(device_path_string);
264       if (iter != disks_.end()) {
265         delete iter->second;
266         disks_.erase(iter);
267         is_new = false;
268       }
269       std::string path;
270       std::string mountpath;
271       std::string systempath;
272       std::string filepath;
273       std::string devicelabel;
274       std::string drivelabel;
275       std::string parentpath;
276 
277       if (disk->path() != NULL)
278         path = disk->path();
279 
280       if (disk->mount_path() != NULL)
281         mountpath = disk->mount_path();
282 
283       if (disk->system_path() != NULL)
284         systempath = disk->system_path();
285 
286       if (disk->file_path() != NULL)
287         filepath = disk->file_path();
288 
289       if (disk->label() != NULL)
290         devicelabel = disk->label();
291 
292       if (disk->drive_label() != NULL)
293         drivelabel = disk->drive_label();
294 
295       if (disk->partition_slave() != NULL)
296         parentpath = disk->partition_slave();
297 
298       Disk* new_disk = new Disk(path,
299                                 mountpath,
300                                 systempath,
301                                 filepath,
302                                 devicelabel,
303                                 drivelabel,
304                                 parentpath,
305                                 disk->device_type(),
306                                 disk->size(),
307                                 disk->is_drive(),
308                                 disk->is_read_only(),
309                                 disk->has_media(),
310                                 disk->on_boot_device());
311       disks_.insert(
312           std::pair<std::string, Disk*>(device_path_string, new_disk));
313       FireDiskStatusUpdate(is_new ? MOUNT_DISK_ADDED : MOUNT_DISK_CHANGED,
314                            new_disk);
315     } else {
316       LOG(WARNING) << "Property retrieval request failed for device "
317                    << device_path << ", with error: "
318                    << (error_message ? error_message : "Unknown");
319     }
320   }
321 
OnRequestMountInfo(const char ** devices,size_t devices_len,MountMethodErrorType error,const char * error_message)322   void OnRequestMountInfo(const char** devices,
323                           size_t devices_len,
324                           MountMethodErrorType error,
325                           const char* error_message) {
326     std::set<std::string> current_device_set;
327     if (error == MOUNT_METHOD_ERROR_NONE && devices && devices_len) {
328       // Initiate properties fetch for all removable disks,
329       bool found_disk = false;
330       for (size_t i = 0; i < devices_len; i++) {
331         if (!devices[i]) {
332           NOTREACHED();
333           continue;
334         }
335         current_device_set.insert(std::string(devices[i]));
336         found_disk = true;
337         // Initiate disk property retrieval for each relevant device path.
338         GetDiskProperties(devices[i],
339                           &MountLibraryImpl::GetDiskPropertiesCallback,
340                           this);
341       }
342     } else if (error != MOUNT_METHOD_ERROR_NONE) {
343       LOG(WARNING) << "Request mount info retrieval request failed with error: "
344                    << (error_message ? error_message : "Unknown");
345     }
346     // Search and remove disks that are no longer present.
347     for (MountLibrary::DiskMap::iterator iter = disks_.begin();
348          iter != disks_.end(); ) {
349       if (current_device_set.find(iter->first) == current_device_set.end()) {
350         Disk* disk = iter->second;
351         FireDiskStatusUpdate(MOUNT_DISK_REMOVED, disk);
352         delete iter->second;
353         disks_.erase(iter++);
354       } else {
355         ++iter;
356       }
357     }
358   }
359 
OnMountEvent(MountEventType evt,const char * device_path)360   void OnMountEvent(MountEventType evt,
361                     const char* device_path) {
362     if (!device_path)
363       return;
364     MountLibraryEventType type = MOUNT_DEVICE_ADDED;
365     switch (evt) {
366       case DISK_ADDED:
367       case DISK_CHANGED: {
368         GetDiskProperties(device_path,
369                           &MountLibraryImpl::GetDiskPropertiesCallback,
370                           this);
371         return;
372       }
373       case DISK_REMOVED: {
374         // Search and remove disks that are no longer present.
375         MountLibrary::DiskMap::iterator iter =
376             disks_.find(std::string(device_path));
377         if (iter != disks_.end()) {
378             Disk* disk = iter->second;
379             FireDiskStatusUpdate(MOUNT_DISK_REMOVED, disk);
380             delete iter->second;
381             disks_.erase(iter);
382         }
383         return;
384       }
385       case DEVICE_ADDED: {
386         type = MOUNT_DEVICE_ADDED;
387         break;
388       }
389       case DEVICE_REMOVED: {
390         type = MOUNT_DEVICE_REMOVED;
391         break;
392       }
393       case DEVICE_SCANNED: {
394         type = MOUNT_DEVICE_SCANNED;
395         break;
396       }
397     }
398     FireDeviceStatusUpdate(type, std::string(device_path));
399   }
400 
Init()401   void Init() {
402     // Getting the monitor status so that the daemon starts up.
403     mount_status_connection_ = MonitorMountEvents(
404         &MonitorMountEventsHandler, this);
405   }
406 
FireDiskStatusUpdate(MountLibraryEventType evt,const Disk * disk)407   void FireDiskStatusUpdate(MountLibraryEventType evt,
408                             const Disk* disk) {
409     // Make sure we run on UI thread.
410     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
411     FOR_EACH_OBSERVER(
412         Observer, observers_, DiskChanged(evt, disk));
413   }
414 
FireDeviceStatusUpdate(MountLibraryEventType evt,const std::string & device_path)415   void FireDeviceStatusUpdate(MountLibraryEventType evt,
416                               const std::string& device_path) {
417     // Make sure we run on UI thread.
418     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
419     FOR_EACH_OBSERVER(
420         Observer, observers_, DeviceChanged(evt, device_path));
421   }
422 
423   // Mount event change observers.
424   ObserverList<Observer> observers_;
425 
426   // A reference to the  mount api, to allow callbacks when the mount
427   // status changes.
428   MountEventConnection mount_status_connection_;
429 
430   // The list of disks found.
431   MountLibrary::DiskMap disks_;
432 
433   DISALLOW_COPY_AND_ASSIGN(MountLibraryImpl);
434 };
435 
436 class MountLibraryStubImpl : public MountLibrary {
437  public:
MountLibraryStubImpl()438   MountLibraryStubImpl() {}
~MountLibraryStubImpl()439   virtual ~MountLibraryStubImpl() {}
440 
441   // MountLibrary overrides.
AddObserver(Observer * observer)442   virtual void AddObserver(Observer* observer) OVERRIDE {}
RemoveObserver(Observer * observer)443   virtual void RemoveObserver(Observer* observer) OVERRIDE {}
disks() const444   virtual const DiskMap& disks() const OVERRIDE { return disks_; }
RequestMountInfoRefresh()445   virtual void RequestMountInfoRefresh() OVERRIDE {}
MountPath(const char * device_path)446   virtual void MountPath(const char* device_path) OVERRIDE {}
UnmountPath(const char * device_path)447   virtual void UnmountPath(const char* device_path) OVERRIDE {}
IsBootPath(const char * device_path)448   virtual bool IsBootPath(const char* device_path) OVERRIDE { return true; }
449 
450  private:
451   // The list of disks found.
452   DiskMap disks_;
453 
454   DISALLOW_COPY_AND_ASSIGN(MountLibraryStubImpl);
455 };
456 
457 // static
GetImpl(bool stub)458 MountLibrary* MountLibrary::GetImpl(bool stub) {
459   if (stub)
460     return new MountLibraryStubImpl();
461   else
462     return new MountLibraryImpl();
463 }
464 
465 }  // namespace chromeos
466 
467 // Allows InvokeLater without adding refcounting. This class is a Singleton and
468 // won't be deleted until it's last InvokeLater is run.
469 DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::MountLibraryImpl);
470 
471