1/* 2 * Copyright (C) 2013 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 * @param {WebInspector.IsolatedFileSystemManager} manager 34 * @param {string} path 35 */ 36WebInspector.IsolatedFileSystem = function(manager, path, name, rootURL) 37{ 38 this._manager = manager; 39 this._path = path; 40 this._name = name; 41 this._rootURL = rootURL; 42} 43 44WebInspector.IsolatedFileSystem.errorMessage = function(error) 45{ 46 var msg; 47 switch (error.code) { 48 case FileError.QUOTA_EXCEEDED_ERR: 49 msg = "QUOTA_EXCEEDED_ERR"; 50 break; 51 case FileError.NOT_FOUND_ERR: 52 msg = "NOT_FOUND_ERR"; 53 break; 54 case FileError.SECURITY_ERR: 55 msg = "SECURITY_ERR"; 56 break; 57 case FileError.INVALID_MODIFICATION_ERR: 58 msg = "INVALID_MODIFICATION_ERR"; 59 break; 60 case FileError.INVALID_STATE_ERR: 61 msg = "INVALID_STATE_ERR"; 62 break; 63 default: 64 msg = "Unknown Error"; 65 break; 66 }; 67 68 return "File system error: " + msg; 69} 70 71WebInspector.IsolatedFileSystem.prototype = { 72 /** 73 * @return {string} 74 */ 75 path: function() 76 { 77 return this._path; 78 }, 79 80 /** 81 * @return {string} 82 */ 83 name: function() 84 { 85 return this._name; 86 }, 87 88 /** 89 * @return {string} 90 */ 91 rootURL: function() 92 { 93 return this._rootURL; 94 }, 95 96 /** 97 * @param {function(DOMFileSystem)} callback 98 */ 99 _requestFileSystem: function(callback) 100 { 101 this._manager.requestDOMFileSystem(this._path, callback); 102 }, 103 104 /** 105 * @param {string} path 106 * @param {function(string)} callback 107 */ 108 requestFilesRecursive: function(path, callback) 109 { 110 this._requestFileSystem(fileSystemLoaded.bind(this)); 111 112 var domFileSystem; 113 /** 114 * @param {DOMFileSystem} fs 115 */ 116 function fileSystemLoaded(fs) 117 { 118 domFileSystem = fs; 119 this._requestEntries(domFileSystem, path, innerCallback.bind(this)); 120 } 121 122 /** 123 * @param {Array.<FileEntry>} entries 124 */ 125 function innerCallback(entries) 126 { 127 for (var i = 0; i < entries.length; ++i) { 128 var entry = entries[i]; 129 if (!entry.isDirectory) 130 callback(entry.fullPath); 131 else 132 this._requestEntries(domFileSystem, entry.fullPath, innerCallback.bind(this)); 133 } 134 } 135 }, 136 137 /** 138 * @param {string} path 139 * @param {function(?string)} callback 140 */ 141 requestFileContent: function(path, callback) 142 { 143 this._requestFileSystem(fileSystemLoaded.bind(this)); 144 145 /** 146 * @param {DOMFileSystem} domFileSystem 147 */ 148 function fileSystemLoaded(domFileSystem) 149 { 150 domFileSystem.root.getFile(path, null, fileEntryLoaded, errorHandler); 151 } 152 153 /** 154 * @param {FileEntry} entry 155 */ 156 function fileEntryLoaded(entry) 157 { 158 entry.file(fileLoaded, errorHandler); 159 } 160 161 /** 162 * @param {!Blob} file 163 */ 164 function fileLoaded(file) 165 { 166 var reader = new FileReader(); 167 reader.onloadend = readerLoadEnd; 168 reader.readAsText(file); 169 } 170 171 /** 172 * @this {FileReader} 173 */ 174 function readerLoadEnd() 175 { 176 callback(/** @type {string} */ (this.result)); 177 } 178 179 function errorHandler(error) 180 { 181 if (error.code === FileError.NOT_FOUND_ERR) { 182 callback(null); 183 return; 184 } 185 186 var errorMessage = WebInspector.IsolatedFileSystem.errorMessage(error); 187 console.error(errorMessage + " when getting content for file '" + (this._path + "/" + path) + "'"); 188 callback(null); 189 } 190 }, 191 192 /** 193 * @param {string} path 194 * @param {string} content 195 * @param {function()} callback 196 */ 197 setFileContent: function(path, content, callback) 198 { 199 this._requestFileSystem(fileSystemLoaded); 200 201 /** 202 * @param {DOMFileSystem} domFileSystem 203 */ 204 function fileSystemLoaded(domFileSystem) 205 { 206 domFileSystem.root.getFile(path, { create: true }, fileEntryLoaded, errorHandler); 207 } 208 209 /** 210 * @param {FileEntry} entry 211 */ 212 function fileEntryLoaded(entry) 213 { 214 entry.createWriter(fileWriterCreated, errorHandler); 215 } 216 217 /** 218 * @param {FileWriter} fileWriter 219 */ 220 function fileWriterCreated(fileWriter) 221 { 222 fileWriter.onerror = errorHandler; 223 fileWriter.onwriteend = fileTruncated; 224 fileWriter.truncate(0); 225 226 function fileTruncated() 227 { 228 fileWriter.onwriteend = writerEnd; 229 var blob = new Blob([content], { type: "text/plain" }); 230 fileWriter.write(blob); 231 } 232 } 233 234 function writerEnd() 235 { 236 callback(); 237 } 238 239 function errorHandler(error) 240 { 241 var errorMessage = WebInspector.IsolatedFileSystem.errorMessage(error); 242 console.error(errorMessage + " when setting content for file '" + (this._path + "/" + path) + "'"); 243 callback(); 244 } 245 }, 246 247 /** 248 * @param {DirectoryEntry} dirEntry 249 * @param {function(Array.<FileEntry>)} callback 250 */ 251 _readDirectory: function(dirEntry, callback) 252 { 253 var dirReader = dirEntry.createReader(); 254 var entries = []; 255 256 function innerCallback(results) 257 { 258 if (!results.length) 259 callback(entries.sort()); 260 else { 261 entries = entries.concat(toArray(results)); 262 dirReader.readEntries(innerCallback, errorHandler); 263 } 264 } 265 266 function toArray(list) 267 { 268 return Array.prototype.slice.call(list || [], 0); 269 } 270 271 dirReader.readEntries(innerCallback, errorHandler); 272 273 function errorHandler(error) 274 { 275 var errorMessage = WebInspector.IsolatedFileSystem.errorMessage(error); 276 console.error(errorMessage + " when reading directory '" + dirEntry.fullPath + "'"); 277 callback([]); 278 } 279 }, 280 281 /** 282 * @param {DOMFileSystem} domFileSystem 283 * @param {string} path 284 * @param {function(Array.<FileEntry>)} callback 285 */ 286 _requestEntries: function(domFileSystem, path, callback) 287 { 288 domFileSystem.root.getDirectory(path, null, innerCallback.bind(this), errorHandler); 289 290 function innerCallback(dirEntry) 291 { 292 this._readDirectory(dirEntry, callback) 293 } 294 295 function errorHandler(error) 296 { 297 var errorMessage = WebInspector.IsolatedFileSystem.errorMessage(error); 298 console.error(errorMessage + " when requesting entry '" + path + "'"); 299 callback([]); 300 } 301 } 302} 303