Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(38)

Side by Side Diff: chrome/browser/resources/file_manager/background/js/volume_manager.js

Issue 179553008: Simplify volume manager in Files app. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fixed unmounting. Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | chrome/browser/resources/file_manager/common/js/util.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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, // File system is not found.
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
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
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;
731 break; 695 break;
732 case util.VolumeType.REMOVABLE: 696 case util.VolumeType.REMOVABLE:
733 rootType = RootType.REMOVABLE; 697 rootType = RootType.REMOVABLE;
734 break; 698 break;
735 case util.VolumeType.ARCHIVE: 699 case util.VolumeType.ARCHIVE:
736 rootType = RootType.ARCHIVE; 700 rootType = RootType.ARCHIVE;
737 break; 701 break;
738 case util.VolumeType.CLOUD_DEVICE: 702 case util.VolumeType.CLOUD_DEVICE:
739 rootType = RootType.CLOUD_DEVICE; 703 rootType = RootType.CLOUD_DEVICE;
740 break; 704 break;
741 default: 705 default:
742 // Programming error, throw an exception. 706 // Programming error, throw an exception.
743 throw new Error('Invalid volume type: ' + volumeInfo.volumeType); 707 throw new Error('Invalid volume type: ' + volumeInfo.volumeType);
744 } 708 }
745 isReadOnly = volumeInfo.isReadOnly; 709 isReadOnly = volumeInfo.isReadOnly;
746 isRootEntry = util.isSameEntry(entry, volumeInfo.root); 710 isRootEntry = util.isSameEntry(entry, volumeInfo.fileSystem.root);
747 } 711 }
748 712
749 return new EntryLocation(volumeInfo, rootType, isRootEntry, isReadOnly); 713 return new EntryLocation(volumeInfo, rootType, isRootEntry, isReadOnly);
750 }; 714 };
751 715
752 /** 716 /**
753 * @param {string} key Key produced by |makeRequestKey_|. 717 * @param {string} key Key produced by |makeRequestKey_|.
754 * @param {function(VolumeInfo)} successCallback To be called when request 718 * @param {function(VolumeInfo)} successCallback To be called when request
755 * finishes successfully. 719 * finishes successfully.
756 * @param {function(util.VolumeError)} errorCallback To be called when 720 * @param {function(util.VolumeError)} errorCallback To be called when
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
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 }
OLDNEW
« no previous file with comments | « no previous file | chrome/browser/resources/file_manager/common/js/util.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698