1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
|
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef WEBKIT_FILEAPI_ISOLATED_CONTEXT_H_
#define WEBKIT_FILEAPI_ISOLATED_CONTEXT_H_
#include <map>
#include <set>
#include <string>
#include <vector>
#include "base/basictypes.h"
#include "base/file_path.h"
#include "base/memory/singleton.h"
#include "base/synchronization/lock.h"
#include "base/lazy_instance.h"
#include "webkit/fileapi/file_system_types.h"
#include "webkit/fileapi/fileapi_export.h"
namespace fileapi {
// Manages isolated filename namespaces. A namespace is simply defined as a
// set of file paths and corresponding filesystem ID. This context class is
// a singleton and access to the context is thread-safe (protected with a
// lock).
// Some methods of this class are virtual just for mocking.
class FILEAPI_EXPORT IsolatedContext {
public:
struct FILEAPI_EXPORT FileInfo {
FileInfo();
FileInfo(const std::string& name, const FilePath& path);
// The name to be used to register the file. The registered file can
// be referred by a virtual path /<filesystem_id>/<name>.
// The name should NOT contain a path separator '/'.
std::string name;
// The path of the file.
FilePath path;
// For STL operation.
bool operator<(const FileInfo& that) const { return name < that.name; }
};
class FILEAPI_EXPORT FileInfoSet {
public:
FileInfoSet();
~FileInfoSet();
// Add the given |path| to the set and populates |registered_name| with
// the registered name assigned for the path. |path| needs to be
// absolute and should not contain parent references.
// Return false if the |path| is not valid and could not be added.
bool AddPath(const FilePath& path, std::string* registered_name);
// Add the given |path| with the |name|.
// Return false if the |name| is already registered in the set or
// is not valid and could not be added.
bool AddPathWithName(const FilePath& path, const std::string& name);
const std::set<FileInfo>& fileset() const { return fileset_; }
private:
std::set<FileInfo> fileset_;
};
// The instance is lazily created per browser process.
static IsolatedContext* GetInstance();
// Registers a new isolated filesystem with the given FileInfoSet |files|
// and returns the new filesystem_id. The files are registered with their
// register_name as their keys so that later we can resolve the full paths
// for the given name. We only expose the name and the ID for the
// newly created filesystem to the renderer for the sake of security.
//
// The renderer will be sending filesystem requests with a virtual path like
// '/<filesystem_id>/<registered_name>/<relative_path_from_the_dropped_path>'
// for which we could crack in the browser process by calling
// CrackIsolatedPath to get the full path.
//
// For example: if a dropped file has a path like '/a/b/foo' and we register
// the path with the name 'foo' in the newly created filesystem.
// Later if the context is asked to crack a virtual path like '/<fsid>/foo'
// it can properly return the original path '/a/b/foo' by looking up the
// internal mapping. Similarly if a dropped entry is a directory and its
// path is like '/a/b/dir' a virtual path like '/<fsid>/dir/foo' can be
// cracked into '/a/b/dir/foo'.
//
// Note that the path in |fileset| that contains '..' or is not an
// absolute path is skipped and is not registerred.
std::string RegisterDraggedFileSystem(const FileInfoSet& files);
// Registers a new isolated filesystem for a given |path| of filesystem
// |type| filesystem and returns a new filesystem ID.
// |path| must be an absolute path which has no parent references ('..').
// If |register_name| is non-null and has non-empty string the path is
// registered as the given |register_name|, otherwise it is populated
// with the name internally assigned to the path.
std::string RegisterFileSystemForPath(FileSystemType type,
const FilePath& path,
std::string* register_name);
// Revokes filesystem specified by the given filesystem_id.
// Note that this revokes the filesystem no matter how many references it has.
// It is ok to call this on the filesystem that has been already deleted
// (if its reference count had reached 0).
void RevokeFileSystem(const std::string& filesystem_id);
// Adds a reference to a filesystem specified by the given filesystem_id.
void AddReference(const std::string& filesystem_id);
// Removes a reference to a filesystem specified by the given filesystem_id.
// If the reference count reaches 0 the isolated context gets destroyed.
// It is ok to call this on the filesystem that has been already deleted
// (e.g. by RevokeFileSystem).
void RemoveReference(const std::string& filesystem_id);
// Cracks the given |virtual_path| (which should look like
// "/<filesystem_id>/<registered_name>/<relative_path>") and populates
// the |filesystem_id| and |path| if the embedded <filesystem_id>
// is registerred to this context. |root_path| is also populated to have
// the registered root (toplevel) file info for the |virtual_path|.
//
// Returns false if the given virtual_path or the cracked filesystem_id
// is not valid.
//
// Note that |root_info| and |path| are set to empty paths if
// |virtual_path| has no <relative_path> part (i.e. pointing to
// the virtual root).
//
// TODO(kinuko): Return filesystem type as well.
bool CrackIsolatedPath(const FilePath& virtual_path,
std::string* filesystem_id,
FileInfo* root_info,
FilePath* path) const;
// Returns a set of dragged FileInfo's registered for the |filesystem_id|.
// The filesystem_id must be pointing to a dragged file system
// (i.e. must be the one registered by RegisterDraggedFileSystem).
// Returns false if the |filesystem_id| is not valid.
bool GetDraggedFileInfo(const std::string& filesystem_id,
std::vector<FileInfo>* files) const;
// Returns the file path registered for the |filesystem_id|.
// The filesystem_id must NOT be pointing to a dragged file system
// (i.e. must be the one registered by RegisterFileSystemForPath).
// Returns false if the |filesystem_id| is not valid.
bool GetRegisteredPath(const std::string& filesystem_id,
FilePath* path) const;
// Returns the virtual root path that looks like /<filesystem_id>.
FilePath CreateVirtualRootPath(const std::string& filesystem_id) const;
private:
friend struct base::DefaultLazyInstanceTraits<IsolatedContext>;
// Represents each isolated file system instance.
class Instance {
public:
Instance(FileSystemType type, const FileInfo& file_info);
explicit Instance(const std::set<FileInfo>& dragged_files);
~Instance();
FileSystemType type() const { return type_; }
const FileInfo& file_info() const { return file_info_; }
const std::set<FileInfo>& dragged_files() const { return dragged_files_; }
int ref_counts() const { return ref_counts_; }
void AddRef() { ++ref_counts_; }
void RemoveRef() { --ref_counts_; }
bool ResolvePathForName(const std::string& name, FilePath* path);
private:
const FileSystemType type_;
const FileInfo file_info_;
// For dragged file system.
const std::set<FileInfo> dragged_files_;
// Reference counts. Note that an isolated filesystem is created with ref==0
// and will get deleted when the ref count reaches <=0.
int ref_counts_;
DISALLOW_COPY_AND_ASSIGN(Instance);
};
typedef std::map<std::string, Instance*> IDToInstance;
// Obtain an instance of this class via GetInstance().
IsolatedContext();
~IsolatedContext();
// Returns a new filesystem_id. Called with lock.
std::string GetNewFileSystemId() const;
// This lock needs to be obtained when accessing the instance_map_.
mutable base::Lock lock_;
IDToInstance instance_map_;
DISALLOW_COPY_AND_ASSIGN(IsolatedContext);
};
} // namespace fileapi
#endif // WEBKIT_FILEAPI_ISOLATED_CONTEXT_H_
|