1 // Copyright 2018 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 CHROME_BROWSER_CHROMEOS_GUEST_OS_GUEST_OS_SHARE_PATH_H_
6 #define CHROME_BROWSER_CHROMEOS_GUEST_OS_GUEST_OS_SHARE_PATH_H_
7 
8 #include <map>
9 #include <memory>
10 #include <set>
11 #include <vector>
12 
13 #include "base/callback.h"
14 #include "base/files/file_path.h"
15 #include "base/files/file_path_watcher.h"
16 #include "base/memory/weak_ptr.h"
17 #include "base/observer_list.h"
18 #include "base/sequenced_task_runner.h"
19 #include "chrome/browser/chromeos/crostini/crostini_manager.h"
20 #include "chrome/browser/chromeos/file_manager/volume_manager_observer.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chromeos/components/drivefs/drivefs_host_observer.h"
23 #include "chromeos/dbus/seneschal/seneschal_service.pb.h"
24 #include "components/keyed_service/core/keyed_service.h"
25 
26 namespace guest_os {
27 
28 using SuccessCallback =
29     base::OnceCallback<void(bool success, const std::string& failure_reason)>;
30 
31 struct SharedPathInfo {
32   explicit SharedPathInfo(std::unique_ptr<base::FilePathWatcher> watcher,
33                           const std::string& vm_name);
34   SharedPathInfo(SharedPathInfo&&);
35   ~SharedPathInfo();
36 
37   std::unique_ptr<base::FilePathWatcher> watcher;
38   std::set<std::string> vm_names;
39 };
40 
41 // Handles sharing and unsharing paths from the Chrome OS host to guest VMs via
42 // seneschal.
43 class GuestOsSharePath : public KeyedService,
44                          public file_manager::VolumeManagerObserver,
45                          public drivefs::DriveFsHostObserver {
46  public:
47   using SharePathCallback =
48       base::OnceCallback<void(const base::FilePath&, bool, const std::string&)>;
49   using SeneschalCallback =
50       base::RepeatingCallback<void(const std::string& operation,
51                                    const base::FilePath& cros_path,
52                                    const base::FilePath& container_path,
53                                    bool result,
54                                    const std::string& failure_reason)>;
55   class Observer {
56    public:
57     virtual void OnUnshare(const std::string& vm_name,
58                            const base::FilePath& path) = 0;
59   };
60 
61   static GuestOsSharePath* GetForProfile(Profile* profile);
62   explicit GuestOsSharePath(Profile* profile);
63   ~GuestOsSharePath() override;
64 
65   // KeyedService:
66   // FilePathWatchers are removed in Shutdown to ensure they are all destroyed
67   // before the service.
68   void Shutdown() override;
69 
70   // Observer receives unshare events.
71   void AddObserver(Observer* obs);
72 
73   // Share specified absolute |path| with vm. If |persist| is set, the path will
74   // be automatically shared at container startup. Callback receives path mapped
75   // in container, success bool and failure reason string.
76   void SharePath(const std::string& vm_name,
77                  const base::FilePath& path,
78                  bool persist,
79                  SharePathCallback callback);
80 
81   // Share specified absolute |paths| with vm. If |persist| is set, the paths
82   // will be automatically shared at container startup. Callback receives
83   // success bool and failure reason string of the first error.
84   void SharePaths(const std::string& vm_name,
85                   std::vector<base::FilePath> paths,
86                   bool persist,
87                   SuccessCallback callback);
88 
89   // Unshare specified |path| with |vm_name|.  If |unpersist| is set, the path
90   // is removed from prefs, and will not be shared at container startup.
91   // Callback receives success bool and failure reason string.
92   void UnsharePath(const std::string& vm_name,
93                    const base::FilePath& path,
94                    bool unpersist,
95                    SuccessCallback callback);
96 
97   // Returns true the first time it is called on this service.
98   bool GetAndSetFirstForSession();
99 
100   // Get list of all shared paths for the specified VM.
101   std::vector<base::FilePath> GetPersistedSharedPaths(
102       const std::string& vm_name);
103 
104   // Share all paths configured in prefs for the specified VM.
105   // Called at container startup.  Callback is invoked once complete.
106   void SharePersistedPaths(const std::string& vm_name,
107                            SuccessCallback callback);
108 
109   // Save |path| into prefs for |vm_name|.
110   void RegisterPersistedPath(const std::string& vm_name,
111                              const base::FilePath& path);
112 
113   // Returns true if |path| or a parent is shared with |vm_name|.
114   bool IsPathShared(const std::string& vm_name, base::FilePath path) const;
115 
116   // file_manager::VolumeManagerObserver
117   void OnVolumeMounted(chromeos::MountError error_code,
118                        const file_manager::Volume& volume) override;
119   void OnVolumeUnmounted(chromeos::MountError error_code,
120                          const file_manager::Volume& volume) override;
121 
122   // drivefs::DriveFsHostObserver
123   void OnFilesChanged(
124       const std::vector<drivefs::mojom::FileChange>& changes) override;
125 
126   // Registers |path| as shared with |vm_name|.  Adds a FilePathWatcher to
127   // detect when the path has been deleted.  If the path is deleted, we unshare
128   // the path, and remove it from prefs if it was persisted.
129   // Visible for testing.
130   void RegisterSharedPath(const std::string& vm_name,
131                           const base::FilePath& path);
132 
133   // Runs on UI Thread to handle when a path is deleted.
134   // Visible for testing.
135   void PathDeleted(const base::FilePath& path);
136 
137   // Allow seneschal callback to be overridden for testing.
set_seneschal_callback_for_testing(SeneschalCallback callback)138   void set_seneschal_callback_for_testing(SeneschalCallback callback) {
139     seneschal_callback_ = std::move(callback);
140   }
141 
142  private:
143   void CallSeneschalSharePath(const std::string& vm_name,
144                               const base::FilePath& path,
145                               bool persist,
146                               SharePathCallback callback);
147 
148   void CallSeneschalUnsharePath(const std::string& vm_name,
149                                 const base::FilePath& path,
150                                 SuccessCallback callback);
151 
152   void OnFileWatcherDeleted(const base::FilePath& path);
153 
154   void OnVolumeMountCheck(const base::FilePath& path, bool mount_exists);
155 
156   // Returns info for specified path or nullptr if not found.
157   SharedPathInfo* FindSharedPathInfo(const base::FilePath& path);
158 
159   Profile* profile_;
160   // Task runner for FilePathWatchers to be created, run, and be destroyed on.
161   scoped_refptr<base::SequencedTaskRunner> file_watcher_task_runner_;
162   bool first_for_session_ = true;
163 
164   // Allow seneschal callback to be overridden for testing.
165   SeneschalCallback seneschal_callback_;
166   base::ObserverList<Observer>::Unchecked observers_;
167   std::map<base::FilePath, SharedPathInfo> shared_paths_;
168 
169   base::WeakPtrFactory<GuestOsSharePath> weak_ptr_factory_{this};
170 
171   DISALLOW_COPY_AND_ASSIGN(GuestOsSharePath);
172 };  // class
173 
174 }  // namespace guest_os
175 
176 #endif  // CHROME_BROWSER_CHROMEOS_GUEST_OS_GUEST_OS_SHARE_PATH_H_
177