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 WEBKIT_BROWSER_FILEAPI_ISOLATED_CONTEXT_H_
6#define WEBKIT_BROWSER_FILEAPI_ISOLATED_CONTEXT_H_
7
8#include <map>
9#include <set>
10#include <string>
11#include <vector>
12
13#include "base/basictypes.h"
14#include "base/files/file_path.h"
15#include "base/lazy_instance.h"
16#include "base/memory/singleton.h"
17#include "base/synchronization/lock.h"
18#include "webkit/browser/fileapi/mount_points.h"
19#include "webkit/browser/webkit_storage_browser_export.h"
20#include "webkit/common/fileapi/file_system_types.h"
21
22namespace fileapi {
23class FileSystemURL;
24}
25
26namespace fileapi {
27
28// Manages isolated filesystem mount points which have no well-known names
29// and are identified by a string 'filesystem ID', which usually just looks
30// like random value.
31// This type of filesystem can be created on the fly and may go away when it has
32// no references from renderers.
33// Files in an isolated filesystem are registered with corresponding names and
34// identified by a filesystem URL like:
35//
36//   filesystem:<origin>/isolated/<filesystem_id>/<name>/relative/path
37//
38// Some methods of this class are virtual just for mocking.
39//
40class WEBKIT_STORAGE_BROWSER_EXPORT IsolatedContext : public MountPoints {
41 public:
42  class WEBKIT_STORAGE_BROWSER_EXPORT FileInfoSet {
43   public:
44    FileInfoSet();
45    ~FileInfoSet();
46
47    // Add the given |path| to the set and populates |registered_name| with
48    // the registered name assigned for the path. |path| needs to be
49    // absolute and should not contain parent references.
50    // Return false if the |path| is not valid and could not be added.
51    bool AddPath(const base::FilePath& path, std::string* registered_name);
52
53    // Add the given |path| with the |name|.
54    // Return false if the |name| is already registered in the set or
55    // is not valid and could not be added.
56    bool AddPathWithName(const base::FilePath& path, const std::string& name);
57
58    const std::set<MountPointInfo>& fileset() const { return fileset_; }
59
60   private:
61    std::set<MountPointInfo> fileset_;
62  };
63
64  // The instance is lazily created per browser process.
65  static IsolatedContext* GetInstance();
66
67  // Returns true if the given filesystem type is managed by IsolatedContext
68  // (i.e. if the given |type| is Isolated or External).
69  // TODO(kinuko): needs a better function name.
70  static bool IsIsolatedType(FileSystemType type);
71
72  // Registers a new isolated filesystem with the given FileInfoSet |files|
73  // and returns the new filesystem_id.  The files are registered with their
74  // register_name as their keys so that later we can resolve the full paths
75  // for the given name.  We only expose the name and the ID for the
76  // newly created filesystem to the renderer for the sake of security.
77  //
78  // The renderer will be sending filesystem requests with a virtual path like
79  // '/<filesystem_id>/<registered_name>/<relative_path_from_the_dropped_path>'
80  // for which we could crack in the browser process by calling
81  // CrackIsolatedPath to get the full path.
82  //
83  // For example: if a dropped file has a path like '/a/b/foo' and we register
84  // the path with the name 'foo' in the newly created filesystem.
85  // Later if the context is asked to crack a virtual path like '/<fsid>/foo'
86  // it can properly return the original path '/a/b/foo' by looking up the
87  // internal mapping.  Similarly if a dropped entry is a directory and its
88  // path is like '/a/b/dir' a virtual path like '/<fsid>/dir/foo' can be
89  // cracked into '/a/b/dir/foo'.
90  //
91  // Note that the path in |fileset| that contains '..' or is not an
92  // absolute path is skipped and is not registered.
93  std::string RegisterDraggedFileSystem(const FileInfoSet& files);
94
95  // Registers a new isolated filesystem for a given |path| of filesystem
96  // |type| filesystem with |filesystem_id| and returns a new filesystem ID.
97  // |path| must be an absolute path which has no parent references ('..').
98  // If |register_name| is non-null and has non-empty string the path is
99  // registered as the given |register_name|, otherwise it is populated
100  // with the name internally assigned to the path.
101  std::string RegisterFileSystemForPath(FileSystemType type,
102                                        const std::string& filesystem_id,
103                                        const base::FilePath& path,
104                                        std::string* register_name);
105
106  // Registers a virtual filesystem. This is different from
107  // RegisterFileSystemForPath because register_name is required, and
108  // cracked_path_prefix is allowed to be non-absolute.
109  // |register_name| is required, since we cannot infer one from the path.
110  // |cracked_path_prefix| has no parent references, but can be relative.
111  std::string RegisterFileSystemForVirtualPath(
112      FileSystemType type,
113      const std::string& register_name,
114      const base::FilePath& cracked_path_prefix);
115
116  // Revokes all filesystem(s) registered for the given path.
117  // This is assumed to be called when the registered path becomes
118  // globally invalid, e.g. when a device for the path is detached.
119  //
120  // Note that this revokes the filesystem no matter how many references it has.
121  // It is ok to call this for the path that has no associated filesystems.
122  // Note that this only works for the filesystems registered by
123  // |RegisterFileSystemForPath|.
124  void RevokeFileSystemByPath(const base::FilePath& path);
125
126  // Adds a reference to a filesystem specified by the given filesystem_id.
127  void AddReference(const std::string& filesystem_id);
128
129  // Removes a reference to a filesystem specified by the given filesystem_id.
130  // If the reference count reaches 0 the isolated context gets destroyed.
131  // It is OK to call this on the filesystem that has been already deleted
132  // (e.g. by RevokeFileSystemByPath).
133  void RemoveReference(const std::string& filesystem_id);
134
135  // Returns a set of dragged MountPointInfos registered for the
136  // |filesystem_id|.
137  // The filesystem_id must be pointing to a dragged file system
138  // (i.e. must be the one registered by RegisterDraggedFileSystem).
139  // Returns false if the |filesystem_id| is not valid.
140  bool GetDraggedFileInfo(const std::string& filesystem_id,
141                          std::vector<MountPointInfo>* files) const;
142
143  // MountPoints overrides.
144  virtual bool HandlesFileSystemMountType(FileSystemType type) const OVERRIDE;
145  virtual bool RevokeFileSystem(const std::string& filesystem_id) OVERRIDE;
146  virtual bool GetRegisteredPath(const std::string& filesystem_id,
147                                 base::FilePath* path) const OVERRIDE;
148  virtual bool CrackVirtualPath(
149      const base::FilePath& virtual_path,
150      std::string* filesystem_id,
151      FileSystemType* type,
152      std::string* cracked_id,
153      base::FilePath* path,
154      FileSystemMountOption* mount_option) const OVERRIDE;
155  virtual FileSystemURL CrackURL(const GURL& url) const OVERRIDE;
156  virtual FileSystemURL CreateCrackedFileSystemURL(
157      const GURL& origin,
158      FileSystemType type,
159      const base::FilePath& path) const OVERRIDE;
160
161  // Returns the virtual root path that looks like /<filesystem_id>.
162  base::FilePath CreateVirtualRootPath(const std::string& filesystem_id) const;
163
164 private:
165  friend struct base::DefaultLazyInstanceTraits<IsolatedContext>;
166
167  // Represents each file system instance (defined in the .cc).
168  class Instance;
169
170  typedef std::map<std::string, Instance*> IDToInstance;
171
172  // Reverse map from registered path to IDs.
173  typedef std::map<base::FilePath, std::set<std::string> > PathToID;
174
175  // Obtain an instance of this class via GetInstance().
176  IsolatedContext();
177  virtual ~IsolatedContext();
178
179  // MountPoints overrides.
180  virtual FileSystemURL CrackFileSystemURL(
181      const FileSystemURL& url) const OVERRIDE;
182
183  // Unregisters a file system of given |filesystem_id|. Must be called with
184  // lock_ held.  Returns true if the file system is unregistered.
185  bool UnregisterFileSystem(const std::string& filesystem_id);
186
187  // Returns a new filesystem_id.  Called with lock.
188  std::string GetNewFileSystemId() const;
189
190  // This lock needs to be obtained when accessing the instance_map_.
191  mutable base::Lock lock_;
192
193  IDToInstance instance_map_;
194  PathToID path_to_id_map_;
195
196  DISALLOW_COPY_AND_ASSIGN(IsolatedContext);
197};
198
199}  // namespace fileapi
200
201#endif  // WEBKIT_BROWSER_FILEAPI_ISOLATED_CONTEXT_H_
202