• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2012 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 *     * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *     * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 *     * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/**
32 * @constructor
33 * @extends {WebInspector.Object}
34 */
35WebInspector.FileSystemModel = function()
36{
37    WebInspector.Object.call(this);
38
39    this._fileSystemsForOrigin = {};
40
41    WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.SecurityOriginAdded, this._securityOriginAdded, this);
42    WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.SecurityOriginRemoved, this._securityOriginRemoved, this);
43
44    FileSystemAgent.enable();
45
46    this._reset();
47}
48
49WebInspector.FileSystemModel.prototype = {
50    _reset: function()
51    {
52        for (var securityOrigin in this._fileSystemsForOrigin)
53            this._removeOrigin(securityOrigin);
54        var securityOrigins = WebInspector.resourceTreeModel.securityOrigins();
55        for (var i = 0; i < securityOrigins.length; ++i)
56            this._addOrigin(securityOrigins[i]);
57    },
58
59    /**
60     * @param {!WebInspector.Event} event
61     */
62    _securityOriginAdded: function(event)
63    {
64        var securityOrigin = /** @type {string} */ (event.data);
65        this._addOrigin(securityOrigin);
66    },
67
68    /**
69     * @param {!WebInspector.Event} event
70     */
71    _securityOriginRemoved: function(event)
72    {
73        var securityOrigin = /** @type {string} */ (event.data);
74        this._removeOrigin(securityOrigin);
75    },
76
77    /**
78     * @param {string} securityOrigin
79     */
80    _addOrigin: function(securityOrigin)
81    {
82        this._fileSystemsForOrigin[securityOrigin] = {};
83
84        var types = ["persistent", "temporary"];
85        for (var i = 0; i < types.length; ++i)
86            this._requestFileSystemRoot(securityOrigin, types[i], this._fileSystemRootReceived.bind(this, securityOrigin, types[i], this._fileSystemsForOrigin[securityOrigin]));
87    },
88
89    /**
90     * @param {string} securityOrigin
91     */
92    _removeOrigin: function(securityOrigin)
93    {
94        for (var type in this._fileSystemsForOrigin[securityOrigin]) {
95            var fileSystem = this._fileSystemsForOrigin[securityOrigin][type];
96            delete this._fileSystemsForOrigin[securityOrigin][type];
97            this._fileSystemRemoved(fileSystem);
98        }
99        delete this._fileSystemsForOrigin[securityOrigin];
100    },
101
102    /**
103     * @param {string} origin
104     * @param {string} type
105     * @param {function(number, !FileSystemAgent.Entry=)} callback
106     */
107    _requestFileSystemRoot: function(origin, type, callback)
108    {
109        /**
110         * @param {?Protocol.Error} error
111         * @param {number} errorCode
112         * @param {!FileSystemAgent.Entry=} backendRootEntry
113         */
114        function innerCallback(error, errorCode, backendRootEntry)
115        {
116            if (error) {
117                callback(FileError.SECURITY_ERR);
118                return;
119            }
120
121            callback(errorCode, backendRootEntry);
122        }
123
124        FileSystemAgent.requestFileSystemRoot(origin, type, innerCallback.bind(this));
125    },
126
127    /**
128     * @param {!WebInspector.FileSystemModel.FileSystem} fileSystem
129     */
130    _fileSystemAdded: function(fileSystem)
131    {
132        this.dispatchEventToListeners(WebInspector.FileSystemModel.EventTypes.FileSystemAdded, fileSystem);
133    },
134
135    /**
136     * @param {!WebInspector.FileSystemModel.FileSystem} fileSystem
137     */
138    _fileSystemRemoved: function(fileSystem)
139    {
140        this.dispatchEventToListeners(WebInspector.FileSystemModel.EventTypes.FileSystemRemoved, fileSystem);
141    },
142
143    refreshFileSystemList: function()
144    {
145        this._reset();
146    },
147
148    /**
149     * @param {string} origin
150     * @param {string} type
151     * @param {!Object.<string, !WebInspector.FileSystemModel.FileSystem>} store
152     * @param {number} errorCode
153     * @param {!FileSystemAgent.Entry=} backendRootEntry
154     */
155    _fileSystemRootReceived: function(origin, type, store, errorCode, backendRootEntry)
156    {
157        if (!errorCode && backendRootEntry && this._fileSystemsForOrigin[origin] === store) {
158            var fileSystem = new WebInspector.FileSystemModel.FileSystem(this, origin, type, backendRootEntry);
159            store[type] = fileSystem;
160            this._fileSystemAdded(fileSystem);
161        }
162    },
163
164    /**
165     * @param {!WebInspector.FileSystemModel.Directory} directory
166     * @param {function(number, !Array.<!WebInspector.FileSystemModel.Entry>=)} callback
167     */
168    requestDirectoryContent: function(directory, callback)
169    {
170        this._requestDirectoryContent(directory.url, this._directoryContentReceived.bind(this, directory, callback));
171    },
172
173    /**
174     * @param {string} url
175     * @param {function(number, !Array.<!FileSystemAgent.Entry>=)} callback
176     */
177    _requestDirectoryContent: function(url, callback)
178    {
179        /**
180         * @param {?Protocol.Error} error
181         * @param {number} errorCode
182         * @param {!Array.<!FileSystemAgent.Entry>=} backendEntries
183         */
184        function innerCallback(error, errorCode, backendEntries)
185        {
186            if (error) {
187                callback(FileError.SECURITY_ERR);
188                return;
189            }
190
191            if (errorCode !== 0) {
192                callback(errorCode);
193                return;
194            }
195
196            callback(errorCode, backendEntries);
197        }
198
199        FileSystemAgent.requestDirectoryContent(url, innerCallback.bind(this));
200    },
201
202    /**
203     * @param {!WebInspector.FileSystemModel.Directory} parentDirectory
204     * @param {function(number, !Array.<!WebInspector.FileSystemModel.Entry>=)} callback
205     * @param {number} errorCode
206     * @param {!Array.<!FileSystemAgent.Entry>=} backendEntries
207     */
208    _directoryContentReceived: function(parentDirectory, callback, errorCode, backendEntries)
209    {
210        if (!backendEntries) {
211            callback(errorCode);
212            return;
213        }
214
215        var entries = [];
216        for (var i = 0; i < backendEntries.length; ++i) {
217            if (backendEntries[i].isDirectory)
218                entries.push(new WebInspector.FileSystemModel.Directory(this, parentDirectory.fileSystem, backendEntries[i]));
219            else
220                entries.push(new WebInspector.FileSystemModel.File(this, parentDirectory.fileSystem, backendEntries[i]));
221        }
222
223        callback(errorCode, entries);
224    },
225
226    /**
227     * @param {!WebInspector.FileSystemModel.Entry} entry
228     * @param {function(number, !FileSystemAgent.Metadata=)} callback
229     */
230    requestMetadata: function(entry, callback)
231    {
232        /**
233         * @param {?Protocol.Error} error
234         * @param {number} errorCode
235         * @param {!FileSystemAgent.Metadata=} metadata
236         */
237        function innerCallback(error, errorCode, metadata)
238        {
239            if (error) {
240                callback(FileError.SECURITY_ERR);
241                return;
242            }
243
244            callback(errorCode, metadata);
245        }
246
247        FileSystemAgent.requestMetadata(entry.url, innerCallback.bind(this));
248    },
249
250    /**
251     * @param {!WebInspector.FileSystemModel.File} file
252     * @param {boolean} readAsText
253     * @param {number=} start
254     * @param {number=} end
255     * @param {string=} charset
256     * @param {function(number, string=, string=)=} callback
257     */
258    requestFileContent: function(file, readAsText, start, end, charset, callback)
259    {
260        this._requestFileContent(file.url, readAsText, start, end, charset, callback);
261    },
262
263    /**
264     * @param {string} url
265     * @param {boolean} readAsText
266     * @param {number=} start
267     * @param {number=} end
268     * @param {string=} charset
269     * @param {function(number, string=, string=)=} callback
270     */
271    _requestFileContent: function(url, readAsText, start, end, charset, callback)
272    {
273        /**
274         * @param {?Protocol.Error} error
275         * @param {number} errorCode
276         * @param {string=} content
277         * @param {string=} charset
278         */
279        function innerCallback(error, errorCode, content, charset)
280        {
281            if (error) {
282                if (callback)
283                    callback(FileError.SECURITY_ERR);
284                return;
285            }
286
287            if (callback)
288                callback(errorCode, content, charset);
289        }
290
291        FileSystemAgent.requestFileContent(url, readAsText, start, end, charset, innerCallback.bind(this));
292    },
293    /**
294     * @param {!WebInspector.FileSystemModel.Entry} entry
295     * @param {function(number)=} callback
296     */
297    deleteEntry: function(entry, callback)
298    {
299        var fileSystemModel = this;
300        if (entry === entry.fileSystem.root)
301            this._deleteEntry(entry.url, hookFileSystemDeletion);
302        else
303            this._deleteEntry(entry.url, callback);
304
305        function hookFileSystemDeletion(errorCode)
306        {
307            callback(errorCode);
308            if (!errorCode)
309                fileSystemModel._removeFileSystem(entry.fileSystem);
310        }
311    },
312
313    /**
314     * @param {string} url
315     * @param {function(number)=} callback
316     */
317    _deleteEntry: function(url, callback)
318    {
319        /**
320         * @param {?Protocol.Error} error
321         * @param {number} errorCode
322         */
323        function innerCallback(error, errorCode)
324        {
325            if (error) {
326                if (callback)
327                    callback(FileError.SECURITY_ERR);
328                return;
329            }
330
331            if (callback)
332                callback(errorCode);
333        }
334
335        FileSystemAgent.deleteEntry(url, innerCallback.bind(this));
336    },
337
338    /**
339     * @param {!WebInspector.FileSystemModel.FileSystem} fileSystem
340     */
341    _removeFileSystem: function(fileSystem)
342    {
343        var origin = fileSystem.origin;
344        var type = fileSystem.type;
345        if (this._fileSystemsForOrigin[origin] && this._fileSystemsForOrigin[origin][type]) {
346            delete this._fileSystemsForOrigin[origin][type];
347            this._fileSystemRemoved(fileSystem);
348
349            if (Object.isEmpty(this._fileSystemsForOrigin[origin]))
350                delete this._fileSystemsForOrigin[origin];
351        }
352    },
353
354    __proto__: WebInspector.Object.prototype
355}
356
357
358WebInspector.FileSystemModel.EventTypes = {
359    FileSystemAdded: "FileSystemAdded",
360    FileSystemRemoved: "FileSystemRemoved"
361}
362
363/**
364 * @constructor
365 * @param {!WebInspector.FileSystemModel} fileSystemModel
366 * @param {string} origin
367 * @param {string} type
368 * @param {!FileSystemAgent.Entry} backendRootEntry
369 */
370WebInspector.FileSystemModel.FileSystem = function(fileSystemModel, origin, type, backendRootEntry)
371{
372    this.origin = origin;
373    this.type = type;
374
375    this.root = new WebInspector.FileSystemModel.Directory(fileSystemModel, this, backendRootEntry);
376}
377
378WebInspector.FileSystemModel.FileSystem.prototype = {
379    /**
380     * @type {string}
381     */
382    get name()
383    {
384        return "filesystem:" + this.origin + "/" + this.type;
385    }
386}
387
388/**
389 * @constructor
390 * @param {!WebInspector.FileSystemModel} fileSystemModel
391 * @param {!WebInspector.FileSystemModel.FileSystem} fileSystem
392 * @param {!FileSystemAgent.Entry} backendEntry
393 */
394WebInspector.FileSystemModel.Entry = function(fileSystemModel, fileSystem, backendEntry)
395{
396    this._fileSystemModel = fileSystemModel;
397    this._fileSystem = fileSystem;
398
399    this._url = backendEntry.url;
400    this._name = backendEntry.name;
401    this._isDirectory = backendEntry.isDirectory;
402}
403
404/**
405 * @param {!WebInspector.FileSystemModel.Entry} x
406 * @param {!WebInspector.FileSystemModel.Entry} y
407 * @return {number}
408 */
409WebInspector.FileSystemModel.Entry.compare = function(x, y)
410{
411    if (x.isDirectory != y.isDirectory)
412        return y.isDirectory ? 1 : -1;
413    return x.name.compareTo(y.name);
414}
415
416WebInspector.FileSystemModel.Entry.prototype = {
417    /**
418     * @type {!WebInspector.FileSystemModel}
419     */
420    get fileSystemModel()
421    {
422        return this._fileSystemModel;
423    },
424
425    /**
426     * @type {!WebInspector.FileSystemModel.FileSystem}
427     */
428    get fileSystem()
429    {
430        return this._fileSystem;
431    },
432
433    /**
434     * @type {string}
435     */
436    get url()
437    {
438        return this._url;
439    },
440
441    /**
442     * @type {string}
443     */
444    get name()
445    {
446        return this._name;
447    },
448
449    /**
450     * @type {boolean}
451     */
452    get isDirectory()
453    {
454        return this._isDirectory;
455    },
456
457    /**
458     * @param {function(number, !FileSystemAgent.Metadata)} callback
459     */
460    requestMetadata: function(callback)
461    {
462        this.fileSystemModel.requestMetadata(this, callback);
463    },
464
465    /**
466     * @param {function(number)} callback
467     */
468    deleteEntry: function(callback)
469    {
470        this.fileSystemModel.deleteEntry(this, callback);
471    }
472}
473
474/**
475 * @constructor
476 * @extends {WebInspector.FileSystemModel.Entry}
477 * @param {!WebInspector.FileSystemModel} fileSystemModel
478 * @param {!WebInspector.FileSystemModel.FileSystem} fileSystem
479 * @param {!FileSystemAgent.Entry} backendEntry
480 */
481WebInspector.FileSystemModel.Directory = function(fileSystemModel, fileSystem, backendEntry)
482{
483    WebInspector.FileSystemModel.Entry.call(this, fileSystemModel, fileSystem, backendEntry);
484}
485
486WebInspector.FileSystemModel.Directory.prototype = {
487    /**
488     * @param {function(number, !Array.<!WebInspector.FileSystemModel.Directory>)} callback
489     */
490    requestDirectoryContent: function(callback)
491    {
492        this.fileSystemModel.requestDirectoryContent(this, callback);
493    },
494
495    __proto__: WebInspector.FileSystemModel.Entry.prototype
496}
497
498/**
499 * @constructor
500 * @extends {WebInspector.FileSystemModel.Entry}
501 * @param {!WebInspector.FileSystemModel} fileSystemModel
502 * @param {!WebInspector.FileSystemModel.FileSystem} fileSystem
503 * @param {!FileSystemAgent.Entry} backendEntry
504 */
505WebInspector.FileSystemModel.File = function(fileSystemModel, fileSystem, backendEntry)
506{
507    WebInspector.FileSystemModel.Entry.call(this, fileSystemModel, fileSystem, backendEntry);
508
509    this._mimeType = backendEntry.mimeType;
510    this._resourceType = WebInspector.resourceTypes[backendEntry.resourceType];
511    this._isTextFile = backendEntry.isTextFile;
512}
513
514WebInspector.FileSystemModel.File.prototype = {
515    /**
516     * @type {string}
517     */
518    get mimeType()
519    {
520        return this._mimeType;
521    },
522
523    /**
524     * @type {!WebInspector.ResourceType}
525     */
526    get resourceType()
527    {
528        return this._resourceType;
529    },
530
531    /**
532     * @type {boolean}
533     */
534    get isTextFile()
535    {
536        return this._isTextFile;
537    },
538
539    /**
540     * @param {boolean} readAsText
541     * @param {number=} start
542     * @param {number=} end
543     * @param {string=} charset
544     * @param {function(number, string=)=} callback
545     */
546    requestFileContent: function(readAsText, start, end, charset, callback)
547    {
548        this.fileSystemModel.requestFileContent(this, readAsText, start, end, charset, callback);
549    },
550
551    __proto__: WebInspector.FileSystemModel.Entry.prototype
552}
553