Chromium Code Reviews| 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 |