FileSystemModel.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  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. * @constructor
  32. * @extends {WebInspector.Object}
  33. */
  34. WebInspector.FileSystemModel = function()
  35. {
  36. WebInspector.Object.call(this);
  37. this._fileSystemsForOrigin = {};
  38. WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.SecurityOriginAdded, this._securityOriginAdded, this);
  39. WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.SecurityOriginRemoved, this._securityOriginRemoved, this);
  40. FileSystemAgent.enable();
  41. this._reset();
  42. }
  43. WebInspector.FileSystemModel.prototype = {
  44. _reset: function()
  45. {
  46. for (var securityOrigin in this._fileSystemsForOrigin)
  47. this._removeOrigin(securityOrigin);
  48. var securityOrigins = WebInspector.resourceTreeModel.securityOrigins();
  49. for (var i = 0; i < securityOrigins.length; ++i)
  50. this._addOrigin(securityOrigins[i]);
  51. },
  52. /**
  53. * @param {WebInspector.Event} event
  54. */
  55. _securityOriginAdded: function(event)
  56. {
  57. var securityOrigin = /** @type {string} */ (event.data);
  58. this._addOrigin(securityOrigin);
  59. },
  60. /**
  61. * @param {WebInspector.Event} event
  62. */
  63. _securityOriginRemoved: function(event)
  64. {
  65. var securityOrigin = /** @type {string} */ (event.data);
  66. this._removeOrigin(securityOrigin);
  67. },
  68. /**
  69. * @param {string} securityOrigin
  70. */
  71. _addOrigin: function(securityOrigin)
  72. {
  73. this._fileSystemsForOrigin[securityOrigin] = {};
  74. var types = ["persistent", "temporary"];
  75. for (var i = 0; i < types.length; ++i)
  76. this._requestFileSystemRoot(securityOrigin, types[i], this._fileSystemRootReceived.bind(this, securityOrigin, types[i], this._fileSystemsForOrigin[securityOrigin]));
  77. },
  78. /**
  79. * @param {string} securityOrigin
  80. */
  81. _removeOrigin: function(securityOrigin)
  82. {
  83. for (var type in this._fileSystemsForOrigin[securityOrigin]) {
  84. var fileSystem = this._fileSystemsForOrigin[securityOrigin][type];
  85. delete this._fileSystemsForOrigin[securityOrigin][type];
  86. this._fileSystemRemoved(fileSystem);
  87. }
  88. delete this._fileSystemsForOrigin[securityOrigin];
  89. },
  90. /**
  91. * @param {string} origin
  92. * @param {string} type
  93. * @param {function(number, FileSystemAgent.Entry=)} callback
  94. */
  95. _requestFileSystemRoot: function(origin, type, callback)
  96. {
  97. /**
  98. * @param {?Protocol.Error} error
  99. * @param {number} errorCode
  100. * @param {FileSystemAgent.Entry=} backendRootEntry
  101. */
  102. function innerCallback(error, errorCode, backendRootEntry)
  103. {
  104. if (error) {
  105. callback(FileError.SECURITY_ERR);
  106. return;
  107. }
  108. callback(errorCode, backendRootEntry);
  109. }
  110. FileSystemAgent.requestFileSystemRoot(origin, type, innerCallback.bind(this));
  111. },
  112. /**
  113. * @param {WebInspector.FileSystemModel.FileSystem} fileSystem
  114. */
  115. _fileSystemAdded: function(fileSystem)
  116. {
  117. this.dispatchEventToListeners(WebInspector.FileSystemModel.EventTypes.FileSystemAdded, fileSystem);
  118. },
  119. /**
  120. * @param {WebInspector.FileSystemModel.FileSystem} fileSystem
  121. */
  122. _fileSystemRemoved: function(fileSystem)
  123. {
  124. this.dispatchEventToListeners(WebInspector.FileSystemModel.EventTypes.FileSystemRemoved, fileSystem);
  125. },
  126. refreshFileSystemList: function()
  127. {
  128. this._reset();
  129. },
  130. /**
  131. * @param {string} origin
  132. * @param {string} type
  133. * @param {Object.<WebInspector.FileSystemModel.FileSystem>} store
  134. * @param {number} errorCode
  135. * @param {FileSystemAgent.Entry=} backendRootEntry
  136. */
  137. _fileSystemRootReceived: function(origin, type, store, errorCode, backendRootEntry)
  138. {
  139. if (!errorCode && backendRootEntry && this._fileSystemsForOrigin[origin] === store) {
  140. var fileSystem = new WebInspector.FileSystemModel.FileSystem(this, origin, type, backendRootEntry);
  141. store[type] = fileSystem;
  142. this._fileSystemAdded(fileSystem);
  143. }
  144. },
  145. /**
  146. * @param {WebInspector.FileSystemModel.Directory} directory
  147. * @param {function(number, Array.<WebInspector.FileSystemModel.Entry>=)} callback
  148. */
  149. requestDirectoryContent: function(directory, callback)
  150. {
  151. this._requestDirectoryContent(directory.url, this._directoryContentReceived.bind(this, directory, callback));
  152. },
  153. /**
  154. * @param {string} url
  155. * @param {function(number, Array.<FileSystemAgent.Entry>=)} callback
  156. */
  157. _requestDirectoryContent: function(url, callback)
  158. {
  159. /**
  160. * @param {?Protocol.Error} error
  161. * @param {number} errorCode
  162. * @param {Array.<FileSystemAgent.Entry>=} backendEntries
  163. */
  164. function innerCallback(error, errorCode, backendEntries)
  165. {
  166. if (error) {
  167. callback(FileError.SECURITY_ERR);
  168. return;
  169. }
  170. if (errorCode !== 0) {
  171. callback(errorCode, null);
  172. return;
  173. }
  174. callback(errorCode, backendEntries);
  175. }
  176. FileSystemAgent.requestDirectoryContent(url, innerCallback.bind(this));
  177. },
  178. /**
  179. * @param {WebInspector.FileSystemModel.Directory} parentDirectory
  180. * @param {function(number, Array.<WebInspector.FileSystemModel.Entry>=)} callback
  181. * @param {number} errorCode
  182. * @param {Array.<FileSystemAgent.Entry>=} backendEntries
  183. */
  184. _directoryContentReceived: function(parentDirectory, callback, errorCode, backendEntries)
  185. {
  186. var entries = [];
  187. for (var i = 0; i < backendEntries.length; ++i) {
  188. if (backendEntries[i].isDirectory)
  189. entries.push(new WebInspector.FileSystemModel.Directory(this, parentDirectory.fileSystem, backendEntries[i]));
  190. else
  191. entries.push(new WebInspector.FileSystemModel.File(this, parentDirectory.fileSystem, backendEntries[i]));
  192. }
  193. callback(errorCode, entries);
  194. },
  195. /**
  196. * @param {WebInspector.FileSystemModel.Entry} entry
  197. * @param {function(number, FileSystemAgent.Metadata=)} callback
  198. */
  199. requestMetadata: function(entry, callback)
  200. {
  201. /**
  202. * @param {?Protocol.Error} error
  203. * @param {number} errorCode
  204. * @param {FileSystemAgent.Metadata=} metadata
  205. */
  206. function innerCallback(error, errorCode, metadata)
  207. {
  208. if (error) {
  209. callback(FileError.SECURITY_ERR);
  210. return;
  211. }
  212. callback(errorCode, metadata);
  213. }
  214. FileSystemAgent.requestMetadata(entry.url, innerCallback.bind(this));
  215. },
  216. /**
  217. * @param {WebInspector.FileSystemModel.File} file
  218. * @param {boolean} readAsText
  219. * @param {number=} start
  220. * @param {number=} end
  221. * @param {string=} charset
  222. * @param {function(number, string=, string=)=} callback
  223. */
  224. requestFileContent: function(file, readAsText, start, end, charset, callback)
  225. {
  226. this._requestFileContent(file.url, readAsText, start, end, charset, callback);
  227. },
  228. /**
  229. * @param {string} url
  230. * @param {boolean} readAsText
  231. * @param {number=} start
  232. * @param {number=} end
  233. * @param {string=} charset
  234. * @param {function(number, string=, string=)=} callback
  235. */
  236. _requestFileContent: function(url, readAsText, start, end, charset, callback)
  237. {
  238. /**
  239. * @param {?Protocol.Error} error
  240. * @param {number} errorCode
  241. * @param {string=} content
  242. * @param {string=} charset
  243. */
  244. function innerCallback(error, errorCode, content, charset)
  245. {
  246. if (error) {
  247. if (callback)
  248. callback(FileError.SECURITY_ERR);
  249. return;
  250. }
  251. if (callback)
  252. callback(errorCode, content, charset);
  253. }
  254. FileSystemAgent.requestFileContent(url, readAsText, start, end, charset, innerCallback.bind(this));
  255. },
  256. /**
  257. * @param {WebInspector.FileSystemModel.Entry} entry
  258. * @param {function(number)=} callback
  259. */
  260. deleteEntry: function(entry, callback)
  261. {
  262. var fileSystemModel = this;
  263. if (entry === entry.fileSystem.root)
  264. this._deleteEntry(entry.url, hookFileSystemDeletion);
  265. else
  266. this._deleteEntry(entry.url, callback);
  267. function hookFileSystemDeletion(errorCode)
  268. {
  269. callback(errorCode);
  270. if (!errorCode)
  271. fileSystemModel._removeFileSystem(entry.fileSystem);
  272. }
  273. },
  274. /**
  275. * @param {string} url
  276. * @param {function(number)=} callback
  277. */
  278. _deleteEntry: function(url, callback)
  279. {
  280. /**
  281. * @param {?Protocol.Error} error
  282. * @param {number} errorCode
  283. */
  284. function innerCallback(error, errorCode)
  285. {
  286. if (error) {
  287. if (callback)
  288. callback(FileError.SECURITY_ERR);
  289. return;
  290. }
  291. if (callback)
  292. callback(errorCode);
  293. }
  294. FileSystemAgent.deleteEntry(url, innerCallback.bind(this));
  295. },
  296. /**
  297. * @param {WebInspector.FileSystemModel.FileSystem} fileSystem
  298. */
  299. _removeFileSystem: function(fileSystem)
  300. {
  301. var origin = fileSystem.origin;
  302. var type = fileSystem.type;
  303. if (this._fileSystemsForOrigin[origin] && this._fileSystemsForOrigin[origin][type]) {
  304. delete this._fileSystemsForOrigin[origin][type];
  305. this._fileSystemRemoved(fileSystem);
  306. if (Object.isEmpty(this._fileSystemsForOrigin[origin]))
  307. delete this._fileSystemsForOrigin[origin];
  308. }
  309. },
  310. __proto__: WebInspector.Object.prototype
  311. }
  312. WebInspector.FileSystemModel.EventTypes = {
  313. FileSystemAdded: "FileSystemAdded",
  314. FileSystemRemoved: "FileSystemRemoved"
  315. }
  316. /**
  317. * @constructor
  318. * @param {WebInspector.FileSystemModel} fileSystemModel
  319. * @param {string} origin
  320. * @param {string} type
  321. * @param {FileSystemAgent.Entry} backendRootEntry
  322. */
  323. WebInspector.FileSystemModel.FileSystem = function(fileSystemModel, origin, type, backendRootEntry)
  324. {
  325. this.origin = origin;
  326. this.type = type;
  327. this.root = new WebInspector.FileSystemModel.Directory(fileSystemModel, this, backendRootEntry);
  328. }
  329. WebInspector.FileSystemModel.FileSystem.prototype = {
  330. /**
  331. * @type {string}
  332. */
  333. get name()
  334. {
  335. return "filesystem:" + this.origin + "/" + this.type;
  336. }
  337. }
  338. /**
  339. * @constructor
  340. * @param {WebInspector.FileSystemModel} fileSystemModel
  341. * @param {WebInspector.FileSystemModel.FileSystem} fileSystem
  342. * @param {FileSystemAgent.Entry} backendEntry
  343. */
  344. WebInspector.FileSystemModel.Entry = function(fileSystemModel, fileSystem, backendEntry)
  345. {
  346. this._fileSystemModel = fileSystemModel;
  347. this._fileSystem = fileSystem;
  348. this._url = backendEntry.url;
  349. this._name = backendEntry.name;
  350. this._isDirectory = backendEntry.isDirectory;
  351. }
  352. /**
  353. * @param {WebInspector.FileSystemModel.Entry} x
  354. * @param {WebInspector.FileSystemModel.Entry} y
  355. * @return {number}
  356. */
  357. WebInspector.FileSystemModel.Entry.compare = function(x, y)
  358. {
  359. if (x.isDirectory != y.isDirectory)
  360. return y.isDirectory ? 1 : -1;
  361. return x.name.compareTo(y.name);
  362. }
  363. WebInspector.FileSystemModel.Entry.prototype = {
  364. /**
  365. * @type {WebInspector.FileSystemModel}
  366. */
  367. get fileSystemModel()
  368. {
  369. return this._fileSystemModel;
  370. },
  371. /**
  372. * @type {WebInspector.FileSystemModel.FileSystem}
  373. */
  374. get fileSystem()
  375. {
  376. return this._fileSystem;
  377. },
  378. /**
  379. * @type {string}
  380. */
  381. get url()
  382. {
  383. return this._url;
  384. },
  385. /**
  386. * @type {string}
  387. */
  388. get name()
  389. {
  390. return this._name;
  391. },
  392. /**
  393. * @type {boolean}
  394. */
  395. get isDirectory()
  396. {
  397. return this._isDirectory;
  398. },
  399. /**
  400. * @param {function(number, FileSystemAgent.Metadata)} callback
  401. */
  402. requestMetadata: function(callback)
  403. {
  404. this.fileSystemModel.requestMetadata(this, callback);
  405. },
  406. /**
  407. * @param {function(number)} callback
  408. */
  409. deleteEntry: function(callback)
  410. {
  411. this.fileSystemModel.deleteEntry(this, callback);
  412. }
  413. }
  414. /**
  415. * @constructor
  416. * @extends {WebInspector.FileSystemModel.Entry}
  417. * @param {WebInspector.FileSystemModel} fileSystemModel
  418. * @param {WebInspector.FileSystemModel.FileSystem} fileSystem
  419. * @param {FileSystemAgent.Entry} backendEntry
  420. */
  421. WebInspector.FileSystemModel.Directory = function(fileSystemModel, fileSystem, backendEntry)
  422. {
  423. WebInspector.FileSystemModel.Entry.call(this, fileSystemModel, fileSystem, backendEntry);
  424. }
  425. WebInspector.FileSystemModel.Directory.prototype = {
  426. /**
  427. * @param {function(number, Array.<WebInspector.FileSystemModel.Directory>)} callback
  428. */
  429. requestDirectoryContent: function(callback)
  430. {
  431. this.fileSystemModel.requestDirectoryContent(this, callback);
  432. },
  433. __proto__: WebInspector.FileSystemModel.Entry.prototype
  434. }
  435. /**
  436. * @constructor
  437. * @extends {WebInspector.FileSystemModel.Entry}
  438. * @param {WebInspector.FileSystemModel} fileSystemModel
  439. * @param {WebInspector.FileSystemModel.FileSystem} fileSystem
  440. * @param {FileSystemAgent.Entry} backendEntry
  441. */
  442. WebInspector.FileSystemModel.File = function(fileSystemModel, fileSystem, backendEntry)
  443. {
  444. WebInspector.FileSystemModel.Entry.call(this, fileSystemModel, fileSystem, backendEntry);
  445. this._mimeType = backendEntry.mimeType;
  446. this._resourceType = WebInspector.resourceTypes[backendEntry.resourceType];
  447. this._isTextFile = backendEntry.isTextFile;
  448. }
  449. WebInspector.FileSystemModel.File.prototype = {
  450. /**
  451. * @type {string}
  452. */
  453. get mimeType()
  454. {
  455. return this._mimeType;
  456. },
  457. /**
  458. * @type {WebInspector.ResourceType}
  459. */
  460. get resourceType()
  461. {
  462. return this._resourceType;
  463. },
  464. /**
  465. * @type {boolean}
  466. */
  467. get isTextFile()
  468. {
  469. return this._isTextFile;
  470. },
  471. /**
  472. * @param {boolean} readAsText
  473. * @param {number=} start
  474. * @param {number=} end
  475. * @param {string=} charset
  476. * @param {function(number, string=)=} callback
  477. */
  478. requestFileContent: function(readAsText, start, end, charset, callback)
  479. {
  480. this.fileSystemModel.requestFileContent(this, readAsText, start, end, charset, callback);
  481. },
  482. __proto__: WebInspector.FileSystemModel.Entry.prototype
  483. }