OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 'use strict'; | 5 'use strict'; |
6 | 6 |
7 /** | 7 /** |
8 * Represents each volume, such as "drive", "download directory", each "USB | 8 * Represents each volume, such as "drive", "download directory", each "USB |
9 * flush storage", or "mounted zip archive" etc. | 9 * flush storage", or "mounted zip archive" etc. |
10 * | 10 * |
11 * @param {util.VolumeType} volumeType The type of the volume. | 11 * @param {util.VolumeType} volumeType The type of the volume. |
12 * @param {string} volumeId ID of the volume. | 12 * @param {string} volumeId ID of the volume. |
13 * @param {DirectoryEntry} root The root directory entry of this volume. | 13 * @param {DOMFileSystem} fileSystem The file system object for this volume. |
14 * @param {string} error The error if an error is found. | 14 * @param {string} error The error if an error is found. |
15 * @param {string} deviceType The type of device ('usb'|'sd'|'optical'|'mobile' | 15 * @param {string} deviceType The type of device ('usb'|'sd'|'optical'|'mobile' |
16 * |'unknown') (as defined in chromeos/disks/disk_mount_manager.cc). | 16 * |'unknown') (as defined in chromeos/disks/disk_mount_manager.cc). |
17 * Can be null. | 17 * Can be null. |
18 * @param {boolean} isReadOnly True if the volume is read only. | 18 * @param {boolean} isReadOnly True if the volume is read only. |
19 * @param {!{displayName:string, isCurrentProfile:boolean}} profile Profile | 19 * @param {!{displayName:string, isCurrentProfile:boolean}} profile Profile |
20 * information. | 20 * information. |
21 * @param {string} label Label of the volume. | 21 * @param {string} label Label of the volume. |
22 * @constructor | 22 * @constructor |
23 */ | 23 */ |
24 function VolumeInfo( | 24 function VolumeInfo( |
25 volumeType, | 25 volumeType, |
26 volumeId, | 26 volumeId, |
27 root, | 27 fileSystem, |
28 error, | 28 error, |
29 deviceType, | 29 deviceType, |
30 isReadOnly, | 30 isReadOnly, |
31 profile, | 31 profile, |
32 label) { | 32 label) { |
33 this.volumeType_ = volumeType; | 33 this.volumeType_ = volumeType; |
34 // TODO(hidehiko): This should include FileSystem instance. | |
35 this.volumeId_ = volumeId; | 34 this.volumeId_ = volumeId; |
36 this.root_ = root; | 35 this.fileSystem_ = fileSystem; |
37 this.label_ = label; | 36 this.label_ = label; |
38 this.displayRoot_ = null; | 37 this.displayRoot_ = null; |
39 this.fakeEntries_ = {}; | 38 this.fakeEntries_ = {}; |
40 this.displayRoot_ = null; | 39 this.displayRoot_ = null; |
41 this.displayRootPromise_ = null; | 40 this.displayRootPromise_ = null; |
42 | 41 |
43 if (volumeType === util.VolumeType.DRIVE) { | 42 if (volumeType === util.VolumeType.DRIVE) { |
44 // TODO(mtomasz): Convert fake entries to DirectoryProvider. | 43 // TODO(mtomasz): Convert fake entries to DirectoryProvider. |
45 this.fakeEntries_[RootType.DRIVE_OFFLINE] = { | 44 this.fakeEntries_[RootType.DRIVE_OFFLINE] = { |
46 isDirectory: true, | 45 isDirectory: true, |
(...skipping 24 matching lines...) Expand all Loading... | |
71 } | 70 } |
72 | 71 |
73 VolumeInfo.prototype = { | 72 VolumeInfo.prototype = { |
74 /** | 73 /** |
75 * @return {util.VolumeType} Volume type. | 74 * @return {util.VolumeType} Volume type. |
76 */ | 75 */ |
77 get volumeType() { | 76 get volumeType() { |
78 return this.volumeType_; | 77 return this.volumeType_; |
79 }, | 78 }, |
80 /** | 79 /** |
81 * @return {string} Volume id. | 80 * @return {string} Volume ID. |
82 */ | 81 */ |
83 get volumeId() { | 82 get volumeId() { |
84 return this.volumeId_; | 83 return this.volumeId_; |
85 }, | 84 }, |
86 /** | 85 /** |
87 * @return {DirectoryEntry} Root path. | 86 * @return {DOMFileSystem} File system object. |
88 */ | 87 */ |
89 get root() { | 88 get fileSystem() { |
90 return this.root_; | 89 return this.fileSystem_; |
91 }, | 90 }, |
92 /** | 91 /** |
93 * @return {DirectoryEntry} Display root path. It is null before finishing to | 92 * @return {DirectoryEntry} Display root path. It is null before finishing to |
94 * resolve the entry. | 93 * resolve the entry. |
95 */ | 94 */ |
96 get displayRoot() { | 95 get displayRoot() { |
97 return this.displayRoot_; | 96 return this.displayRoot_; |
98 }, | 97 }, |
99 /** | 98 /** |
100 * @return {Object.<string, Object>} Fake entries. | 99 * @return {Object.<string, Object>} Fake entries. |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
140 * | 139 * |
141 * @param {function(DirectoryEntry)} onSuccess Success callback with the | 140 * @param {function(DirectoryEntry)} onSuccess Success callback with the |
142 * display root directory as an argument. | 141 * display root directory as an argument. |
143 * @param {function(FileError)} onFailure Failure callback. | 142 * @param {function(FileError)} onFailure Failure callback. |
144 */ | 143 */ |
145 VolumeInfo.prototype.resolveDisplayRoot = function(onSuccess, onFailure) { | 144 VolumeInfo.prototype.resolveDisplayRoot = function(onSuccess, onFailure) { |
146 if (!this.displayRootPromise_) { | 145 if (!this.displayRootPromise_) { |
147 // TODO(mtomasz): Do not add VolumeInfo which failed to resolve root, and | 146 // TODO(mtomasz): Do not add VolumeInfo which failed to resolve root, and |
148 // remove this if logic. Call onSuccess() always, instead. | 147 // remove this if logic. Call onSuccess() always, instead. |
149 if (this.volumeType !== util.VolumeType.DRIVE) { | 148 if (this.volumeType !== util.VolumeType.DRIVE) { |
150 if (this.root) | 149 if (this.fileSystem_) |
151 this.displayRootPromise_ = Promise.resolve(this.root); | 150 this.displayRootPromise_ = Promise.resolve(this.fileSystem_.root); |
152 else | 151 else |
153 this.displayRootPromise_ = Promise.reject(this.error); | 152 this.displayRootPromise_ = Promise.reject(this.error); |
154 } else { | 153 } else { |
155 // For Drive, we need to resolve. | 154 // For Drive, we need to resolve. |
156 var displayRootURL = this.root.toURL() + '/root'; | 155 var displayRootURL = this.fileSystem_.root.toURL() + '/root'; |
157 this.displayRootPromise_ = new Promise( | 156 this.displayRootPromise_ = new Promise( |
158 webkitResolveLocalFileSystemURL.bind(null, displayRootURL)); | 157 webkitResolveLocalFileSystemURL.bind(null, displayRootURL)); |
159 } | 158 } |
160 | 159 |
161 // Store the obtained displayRoot. | 160 // Store the obtained displayRoot. |
162 this.displayRootPromise_.then(function(displayRoot) { | 161 this.displayRootPromise_.then(function(displayRoot) { |
163 this.displayRoot_ = displayRoot; | 162 this.displayRoot_ = displayRoot; |
164 }.bind(this)); | 163 }.bind(this)); |
165 } | 164 } |
166 this.displayRootPromise_.then(onSuccess, onFailure); | 165 this.displayRootPromise_.then(onSuccess, onFailure); |
(...skipping 11 matching lines...) Expand all Loading... | |
178 volumeManagerUtil.validateError = function(error) { | 177 volumeManagerUtil.validateError = function(error) { |
179 for (var key in util.VolumeError) { | 178 for (var key in util.VolumeError) { |
180 if (error === util.VolumeError[key]) | 179 if (error === util.VolumeError[key]) |
181 return; | 180 return; |
182 } | 181 } |
183 | 182 |
184 throw new Error('Invalid mount error: ' + error); | 183 throw new Error('Invalid mount error: ' + error); |
185 }; | 184 }; |
186 | 185 |
187 /** | 186 /** |
188 * Returns the root entry of a volume mounted at mountPath. | |
189 * TODO(mtomasz): Remove this method. | |
190 * | |
191 * @param {string} volumeId ID of the volume to be mounted. | |
192 * @param {function(DirectoryEntry)} successCallback Called when the root entry | |
193 * is found. | |
194 * @param {function(FileError)} errorCallback Called when an error is found. | |
195 * @private | |
196 */ | |
197 volumeManagerUtil.getRootEntry_ = function( | |
198 volumeId, successCallback, errorCallback) { | |
199 // We always request FileSystem here, because requestFileSystem() grants | |
200 // permissions if necessary, especially for Drive File System at first mount | |
201 // time. | |
202 // Note that we actually need to request FileSystem after multi file system | |
203 // support, so this will be more natural code then. | |
204 chrome.fileBrowserPrivate.requestFileSystem( | |
205 volumeId, | |
206 function(fileSystem) { | |
207 // TODO(hidehiko): chrome.runtime.lastError should have error reason. | |
208 if (!fileSystem) { | |
209 errorCallback(util.createDOMError(util.FileError.NOT_FOUND_ERR)); | |
210 return; | |
211 } | |
212 | |
213 successCallback(fileSystem.root); | |
214 }); | |
215 }; | |
216 | |
217 /** | |
218 * Builds the VolumeInfo data from VolumeMetadata. | 187 * Builds the VolumeInfo data from VolumeMetadata. |
219 * @param {VolumeMetadata} volumeMetadata Metadata instance for the volume. | 188 * @param {VolumeMetadata} volumeMetadata Metadata instance for the volume. |
220 * @param {function(VolumeInfo)} callback Called on completion. | 189 * @param {function(VolumeInfo)} callback Called on completion. |
221 */ | 190 */ |
222 volumeManagerUtil.createVolumeInfo = function(volumeMetadata, callback) { | 191 volumeManagerUtil.createVolumeInfo = function(volumeMetadata, callback) { |
223 var localizedLabel; | 192 var localizedLabel; |
224 switch (volumeMetadata.volumeType) { | 193 switch (volumeMetadata.volumeType) { |
225 case util.VolumeType.DOWNLOADS: | 194 case util.VolumeType.DOWNLOADS: |
226 localizedLabel = str('DOWNLOADS_DIRECTORY_LABEL'); | 195 localizedLabel = str('DOWNLOADS_DIRECTORY_LABEL'); |
227 break; | 196 break; |
228 case util.VolumeType.DRIVE: | 197 case util.VolumeType.DRIVE: |
229 localizedLabel = str('DRIVE_DIRECTORY_LABEL'); | 198 localizedLabel = str('DRIVE_DIRECTORY_LABEL'); |
230 break; | 199 break; |
231 default: | 200 default: |
232 localizedLabel = volumeMetadata.volumeId.split(':', 2)[1]; | 201 localizedLabel = volumeMetadata.volumeId.split(':', 2)[1]; |
233 break; | 202 break; |
234 } | 203 } |
235 volumeManagerUtil.getRootEntry_( | 204 |
205 chrome.fileBrowserPrivate.requestFileSystem( | |
236 volumeMetadata.volumeId, | 206 volumeMetadata.volumeId, |
237 function(entry) { | 207 function(fileSystem) { |
208 // TODO(mtomasz): chrome.runtime.lastError should have error reason. | |
209 if (!fileSystem) { | |
210 console.error('File system not found: ' + volumeMetadata.volumeId); | |
211 callback(new VolumeInfo( | |
212 volumeMetadata.volumeType, | |
213 volumeMetadata.volumeId, | |
214 null, // Root entry is not found. | |
hirono
2014/02/26 06:33:02
nit: File system is not found.
mtomasz
2014/02/26 07:00:38
Done.
| |
215 volumeMetadata.mountCondition, | |
216 volumeMetadata.deviceType, | |
217 volumeMetadata.isReadOnly, | |
218 volumeMetadata.profile, | |
219 localizedLabel)); | |
220 return; | |
221 } | |
238 if (volumeMetadata.volumeType === util.VolumeType.DRIVE) { | 222 if (volumeMetadata.volumeType === util.VolumeType.DRIVE) { |
239 // After file system is mounted, we "read" drive grand root | 223 // After file system is mounted, we "read" drive grand root |
240 // entry at first. This triggers full feed fetch on background. | 224 // entry at first. This triggers full feed fetch on background. |
241 // Note: we don't need to handle errors here, because even if | 225 // Note: we don't need to handle errors here, because even if |
242 // it fails, accessing to some path later will just become | 226 // it fails, accessing to some path later will just become |
243 // a fast-fetch and it re-triggers full-feed fetch. | 227 // a fast-fetch and it re-triggers full-feed fetch. |
244 entry.createReader().readEntries( | 228 fileSystem.root.createReader().readEntries( |
245 function() { /* do nothing */ }, | 229 function() { /* do nothing */ }, |
246 function(error) { | 230 function(error) { |
247 console.error( | 231 console.error( |
248 'Triggering full feed fetch is failed: ' + error.name); | 232 'Triggering full feed fetch is failed: ' + error.name); |
249 }); | 233 }); |
250 } | 234 } |
251 callback(new VolumeInfo( | 235 callback(new VolumeInfo( |
252 volumeMetadata.volumeType, | 236 volumeMetadata.volumeType, |
253 volumeMetadata.volumeId, | 237 volumeMetadata.volumeId, |
254 entry, | 238 fileSystem, |
255 volumeMetadata.mountCondition, | 239 volumeMetadata.mountCondition, |
256 volumeMetadata.deviceType, | 240 volumeMetadata.deviceType, |
257 volumeMetadata.isReadOnly, | 241 volumeMetadata.isReadOnly, |
258 volumeMetadata.profile, | |
259 localizedLabel)); | |
260 }, | |
261 function(fileError) { | |
262 console.error('Root entry is not found: ' + | |
263 volumeMetadata.mountPath + ', ' + fileError.name); | |
264 callback(new VolumeInfo( | |
265 volumeMetadata.volumeType, | |
266 volumeMetadata.volumeId, | |
267 null, // Root entry is not found. | |
268 volumeMetadata.mountCondition, | |
269 volumeMetadata.deviceType, | |
270 volumeMetadata.isReadOnly, | |
271 volumeMetadata.profile, | 242 volumeMetadata.profile, |
272 localizedLabel)); | 243 localizedLabel)); |
273 }); | 244 }); |
274 }; | 245 }; |
275 | 246 |
276 /** | 247 /** |
277 * The order of the volume list based on root type. | 248 * The order of the volume list based on root type. |
278 * @type {Array.<util.VolumeType>} | 249 * @type {Array.<util.VolumeType>} |
279 * @const | 250 * @const |
280 * @private | 251 * @private |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
387 } | 358 } |
388 return -1; | 359 return -1; |
389 }; | 360 }; |
390 | 361 |
391 /** | 362 /** |
392 * Searches the information of the volume that contains the passed entry. | 363 * Searches the information of the volume that contains the passed entry. |
393 * @param {Entry|Object} entry Entry on the volume to be foudn. | 364 * @param {Entry|Object} entry Entry on the volume to be foudn. |
394 * @return {VolumeInfo} The volume's information, or null if not found. | 365 * @return {VolumeInfo} The volume's information, or null if not found. |
395 */ | 366 */ |
396 VolumeInfoList.prototype.findByEntry = function(entry) { | 367 VolumeInfoList.prototype.findByEntry = function(entry) { |
397 // TODO(mtomasz): Switch to comparing file systems once possible. | |
398 for (var i = 0; i < this.length; i++) { | 368 for (var i = 0; i < this.length; i++) { |
399 var volumeInfo = this.item(i); | 369 var volumeInfo = this.item(i); |
400 if (!volumeInfo.root) | 370 if (volumeInfo.fileSystem && |
401 continue; | 371 util.isSameFileSystem(volumeInfo.fileSystem, entry.filesystem)) { |
402 // URL of the root always contains the trailing slash. | |
403 if (util.isSameEntry(entry, volumeInfo.root) || | |
404 entry.toURL().indexOf(volumeInfo.root.toURL()) === 0) { | |
405 return volumeInfo; | 372 return volumeInfo; |
406 } | 373 } |
407 // Additionally, check fake entries. | 374 // Additionally, check fake entries. |
408 for (var key in volumeInfo.fakeEntries_) { | 375 for (var key in volumeInfo.fakeEntries_) { |
409 var fakeEntry = volumeInfo.fakeEntries_[key]; | 376 var fakeEntry = volumeInfo.fakeEntries_[key]; |
410 if (util.isSameEntry(fakeEntry, entry)) | 377 if (util.isSameEntry(fakeEntry, entry)) |
411 return volumeInfo; | 378 return volumeInfo; |
412 } | 379 } |
413 } | 380 } |
414 return null; | 381 return null; |
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
681 return null; | 648 return null; |
682 }; | 649 }; |
683 | 650 |
684 /** | 651 /** |
685 * Obtains location information from an entry. | 652 * Obtains location information from an entry. |
686 * | 653 * |
687 * @param {Entry|Object} entry File or directory entry. It can be a fake entry. | 654 * @param {Entry|Object} entry File or directory entry. It can be a fake entry. |
688 * @return {EntryLocation} Location information. | 655 * @return {EntryLocation} Location information. |
689 */ | 656 */ |
690 VolumeManager.prototype.getLocationInfo = function(entry) { | 657 VolumeManager.prototype.getLocationInfo = function(entry) { |
658 var volumeInfo = this.volumeInfoList.findByEntry(entry); | |
659 if (!volumeInfo) | |
660 return null; | |
661 | |
691 if (util.isFakeEntry(entry)) { | 662 if (util.isFakeEntry(entry)) { |
692 return new EntryLocation( | 663 return new EntryLocation( |
693 // TODO(hirono): Specify currect volume. | 664 volumeInfo, |
694 this.getCurrentProfileVolumeInfo(RootType.DRIVE), | |
695 entry.rootType, | 665 entry.rootType, |
696 true /* the entry points a root directory. */, | 666 true /* the entry points a root directory. */, |
697 true /* fake entries are read only. */); | 667 true /* fake entries are read only. */); |
698 } | 668 } |
699 | 669 |
700 var volumeInfo = this.volumeInfoList.findByEntry(entry); | |
701 if (!volumeInfo) | |
702 return null; | |
703 | |
704 var rootType; | 670 var rootType; |
705 var isReadOnly; | 671 var isReadOnly; |
706 var isRootEntry; | 672 var isRootEntry; |
707 if (volumeInfo.volumeType === util.VolumeType.DRIVE) { | 673 if (volumeInfo.volumeType === util.VolumeType.DRIVE) { |
708 // For Drive, the roots are /root and /other, instead of /. Root URLs | 674 // For Drive, the roots are /root and /other, instead of /. Root URLs |
709 // contain trailing slashes. | 675 // contain trailing slashes. |
710 // TODO(mtomasz): Simplify once switching to filesystem per volume. | 676 if (entry.fullPath == '/root' || entry.fullPath.indexOf('/root/') === 0) { |
711 if (entry.toURL() === volumeInfo.root.toURL() + 'root' || | |
712 entry.toURL().indexOf(volumeInfo.root.toURL() + 'root/') === 0) { | |
713 rootType = RootType.DRIVE; | 677 rootType = RootType.DRIVE; |
714 isReadOnly = volumeInfo.isReadOnly; | 678 isReadOnly = volumeInfo.isReadOnly; |
715 isRootEntry = entry.toURL() === volumeInfo.root.toURL() + 'root'; | 679 isRootEntry = entry.fullPath === '/root'; |
716 } else if (entry.toURL() === volumeInfo.root.toURL() + 'other' || | 680 } else if (entry.fullPath == '/other' || |
717 entry.toURL().indexOf(volumeInfo.root.toURL() + 'other/') === 0) { | 681 entry.fullPath.indexOf('/other/') === 0) { |
718 rootType = RootType.DRIVE_OTHER; | 682 rootType = RootType.DRIVE_OTHER; |
719 isReadOnly = true; | 683 isReadOnly = true; |
720 isRootEntry = entry.toURL() === volumeInfo.root.toURL() + 'other'; | 684 isRootEntry = entry.fullPath === '/other'; |
721 } else { | 685 } else { |
722 // Accessing Drive files outside of /drive/root and /drive/other is not | 686 // Accessing Drive files outside of /drive/root and /drive/other is not |
723 // allowed, but can happen. Therefore returning null. | 687 // allowed, but can happen. Therefore returning null. |
724 return null; | 688 return null; |
725 } | 689 } |
726 } else { | 690 } else { |
727 // Otherwise, root path is same with a mount path of the volume. | 691 // Otherwise, root path is same with a mount path of the volume. |
728 switch (volumeInfo.volumeType) { | 692 switch (volumeInfo.volumeType) { |
729 case util.VolumeType.DOWNLOADS: | 693 case util.VolumeType.DOWNLOADS: |
730 rootType = RootType.DOWNLOADS; | 694 rootType = RootType.DOWNLOADS; |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
884 this.isDriveBased; | 848 this.isDriveBased; |
885 | 849 |
886 /** | 850 /** |
887 * Whether the entry is read only or not. | 851 * Whether the entry is read only or not. |
888 * @type {boolean} | 852 * @type {boolean} |
889 */ | 853 */ |
890 this.isReadOnly = isReadOnly; | 854 this.isReadOnly = isReadOnly; |
891 | 855 |
892 Object.freeze(this); | 856 Object.freeze(this); |
893 } | 857 } |
OLD | NEW |