Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / resources / file_manager / background / js / volume_manager.js
index e55c9e7..67eaffe 100644 (file)
@@ -9,7 +9,6 @@
  * flush storage", or "mounted zip archive" etc.
  *
  * @param {util.VolumeType} volumeType The type of the volume.
- * @param {string} mountPath Where the volume is mounted.
  * @param {string} volumeId ID of the volume.
  * @param {DirectoryEntry} root The root directory entry of this volume.
  * @param {string} error The error if an error is found.
@@ -23,7 +22,6 @@
  */
 function VolumeInfo(
     volumeType,
-    mountPath,
     volumeId,
     root,
     error,
@@ -32,7 +30,6 @@ function VolumeInfo(
     profile) {
   this.volumeType_ = volumeType;
   // TODO(hidehiko): This should include FileSystem instance.
-  this.mountPath_ = mountPath;
   this.volumeId_ = volumeId;
   this.root_ = root;
   this.displayRoot_ = null;
@@ -41,23 +38,21 @@ function VolumeInfo(
   this.displayRootPromise_ = null;
 
   if (volumeType === util.VolumeType.DRIVE) {
-    this.fakeEntries[RootType.DRIVE_OFFLINE] = {
-      fullPath: RootDirectory.DRIVE_OFFLINE,
+    // TODO(mtomasz): Convert fake entries to DirectoryProvider.
+    this.fakeEntries_[RootType.DRIVE_OFFLINE] = {
       isDirectory: true,
       rootType: RootType.DRIVE_OFFLINE,
-      toURL: function() { return 'fake-entry://' + this.fullPath; }
+      toURL: function() { return 'fake-entry://drive_offline' }
     };
-    this.fakeEntries[RootType.DRIVE_SHARED_WITH_ME] = {
-      fullPath: RootDirectory.DRIVE_SHARED_WITH_ME,
+    this.fakeEntries_[RootType.DRIVE_SHARED_WITH_ME] = {
       isDirectory: true,
       rootType: RootType.DRIVE_SHARED_WITH_ME,
-      toURL: function() { return 'fake-entry://' + this.fullPath; }
+      toURL: function() { return 'fake-entry://drive_shared_with_me'; }
     };
-    this.fakeEntries[RootType.DRIVE_RECENT] = {
-      fullPath: RootDirectory.DRIVE_RECENT,
+    this.fakeEntries_[RootType.DRIVE_RECENT] = {
       isDirectory: true,
       rootType: RootType.DRIVE_RECENT,
-      toURL: function() { return 'fake-entry://' + this.fullPath; }
+      toURL: function() { return 'fake-entry://drive_recent'; }
     };
   }
 
@@ -80,12 +75,6 @@ VolumeInfo.prototype = {
     return this.volumeType_;
   },
   /**
-   * @return {string} Mount path.
-   */
-  get mountPath() {
-    return this.mountPath_;
-  },
-  /**
    * @return {string} Volume id.
    */
   get volumeId() {
@@ -179,6 +168,7 @@ volumeManagerUtil.validateError = function(error) {
 
 /**
  * Returns the root entry of a volume mounted at mountPath.
+ * TODO(mtomasz): Migrate to volumeId, once requestFileSystem can handle it.
  *
  * @param {string} mountPath The mounted path of the volume.
  * @param {function(DirectoryEntry)} successCallback Called when the root entry
@@ -232,7 +222,6 @@ volumeManagerUtil.createVolumeInfo = function(volumeMetadata, callback) {
         }
         callback(new VolumeInfo(
             volumeMetadata.volumeType,
-            volumeMetadata.mountPath,
             volumeMetadata.volumeId,
             entry,
             volumeMetadata.mountCondition,
@@ -245,7 +234,6 @@ volumeManagerUtil.createVolumeInfo = function(volumeMetadata, callback) {
             volumeMetadata.mountPath + ', ' + fileError.name);
         callback(new VolumeInfo(
             volumeMetadata.volumeType,
-            volumeMetadata.mountPath,
             volumeMetadata.volumeId,
             null,  // Root entry is not found.
             volumeMetadata.mountCondition,
@@ -270,7 +258,7 @@ volumeManagerUtil.volumeListOrder_ = [
 ];
 
 /**
- * Orders two volumes by volumeType and mountPath.
+ * Orders two volumes by volumeType and volumeId.
  *
  * The volumes at first are compared by volume type in the order of
  * volumeListOrder_.  Then they are compared by volume ID.
@@ -371,16 +359,26 @@ VolumeInfoList.prototype.findIndex = function(volumeId) {
 };
 
 /**
- * Searches the information of the volume that contains an item pointed by the
- * path.
- * @param {string} path Path pointing an entry on a volume.
+ * Searches the information of the volume that contains the passed entry.
+ * @param {Entry|Object} entry Entry on the volume to be foudn.
  * @return {VolumeInfo} The volume's information, or null if not found.
  */
-VolumeInfoList.prototype.findByPath = function(path) {
+VolumeInfoList.prototype.findByEntry = function(entry) {
+  // TODO(mtomasz): Switch to comparing file systems once possible.
   for (var i = 0; i < this.length; i++) {
-    var mountPath = this.item(i).mountPath;
-    if (path === mountPath || path.indexOf(mountPath + '/') === 0)
-      return this.item(i);
+    var volumeInfo = this.item(i);
+    if (!volumeInfo.root)
+      continue;
+    if (util.isSameEntry(entry, volumeInfo.root) ||
+        entry.toURL().indexOf(volumeInfo.root.toURL() + '/') === 0) {
+      return volumeInfo;
+    }
+    // Additionally, check fake entries.
+    for (var key in volumeInfo.fakeEntries_) {
+      var fakeEntry = volumeInfo.fakeEntries_[key];
+      if (util.isSameEntry(fakeEntry, entry))
+        return volumeInfo;
+    }
   }
   return null;
 };
@@ -533,6 +531,7 @@ VolumeManager.prototype.initialize_ = function(callback) {
  */
 VolumeManager.prototype.onMountCompleted_ = function(event) {
   if (event.eventType === 'mount') {
+    // TODO(mtomasz): Migrate to volumeId once possible.
     if (event.volumeMetadata.mountPath) {
       var requestKey = this.makeRequestKey_(
           'mount',
@@ -544,7 +543,7 @@ VolumeManager.prototype.onMountCompleted_ = function(event) {
           event.volumeMetadata,
           function(volumeInfo) {
             this.volumeInfoList.add(volumeInfo);
-            this.finishRequest_(requestKey, event.status, volumeInfo.mountPath);
+            this.finishRequest_(requestKey, event.status, volumeInfo);
 
             if (volumeInfo.volumeType === util.VolumeType.DRIVE) {
               // Update the network connection status, because until the
@@ -559,23 +558,21 @@ VolumeManager.prototype.onMountCompleted_ = function(event) {
       this.finishRequest_(requestKey, event.status);
     }
   } else if (event.eventType === 'unmount') {
-    var mountPath = event.volumeMetadata.mountPath;
+    var volumeId = event.volumeMetadata.volumeId;
     var status = event.status;
     if (status === util.VolumeError.PATH_UNMOUNTED) {
-      console.warn('Volume already unmounted: ', mountPath);
+      console.warn('Volume already unmounted: ', volumeId);
       status = 'success';
     }
-    var requestKey = this.makeRequestKey_('unmount', mountPath);
+    var requestKey = this.makeRequestKey_('unmount', volumeId);
     var requested = requestKey in this.requests_;
     var volumeInfoIndex =
-        this.volumeInfoList.findIndex(event.volumeMetadata.volumeId);
-    var volumeInfo = volumeInfoIndex != -1 ?
+        this.volumeInfoList.findIndex(volumeId);
+    var volumeInfo = volumeInfoIndex !== -1 ?
         this.volumeInfoList.item(volumeInfoIndex) : null;
     if (event.status === 'success' && !requested && volumeInfo) {
-      console.warn('Mounted volume without a request: ', mountPath);
+      console.warn('Mounted volume without a request: ', volumeId);
       var e = new Event('externally-unmounted');
-      // TODO(mtomasz): The mountPath field is deprecated. Remove it.
-      e.mountPath = mountPath;
       e.volumeInfo = volumeInfo;
       this.dispatchEvent(e);
     }
@@ -590,25 +587,25 @@ VolumeManager.prototype.onMountCompleted_ = function(event) {
  * Creates string to match mount events with requests.
  * @param {string} requestType 'mount' | 'unmount'. TODO(hidehiko): Replace by
  *     enum.
- * @param {string} path Source path provided by API for mount request, or
- *     mount path for unmount request.
+ * @param {string} argument Argument describing the request, eg. source file
+ *     path of the archive to be mounted, or a volumeId for unmounting.
  * @return {string} Key for |this.requests_|.
  * @private
  */
-VolumeManager.prototype.makeRequestKey_ = function(requestType, path) {
-  return requestType + ':' + path;
+VolumeManager.prototype.makeRequestKey_ = function(requestType, argument) {
+  return requestType + ':' + argument;
 };
 
 /**
  * @param {string} fileUrl File url to the archive file.
- * @param {function(string)} successCallback Success callback.
+ * @param {function(VolumeInfo)} successCallback Success callback.
  * @param {function(util.VolumeError)} errorCallback Error callback.
  */
 VolumeManager.prototype.mountArchive = function(
     fileUrl, successCallback, errorCallback) {
   chrome.fileBrowserPrivate.addMount(fileUrl, function(sourcePath) {
     console.info(
-        'Mount request: url=' + fileUrl + '; sourceUrl=' + sourcePath);
+        'Mount request: url=' + fileUrl + '; sourcePath=' + sourcePath);
     var requestKey = this.makeRequestKey_('mount', sourcePath);
     this.startRequest_(requestKey, successCallback, errorCallback);
   }.bind(this));
@@ -617,54 +614,24 @@ VolumeManager.prototype.mountArchive = function(
 /**
  * Unmounts volume.
  * @param {!VolumeInfo} volumeInfo Volume to be unmounted.
- * @param {function(string)} successCallback Success callback.
+ * @param {function()} successCallback Success callback.
  * @param {function(util.VolumeError)} errorCallback Error callback.
  */
 VolumeManager.prototype.unmount = function(volumeInfo,
                                            successCallback,
                                            errorCallback) {
-  chrome.fileBrowserPrivate.removeMount(
-      util.makeFilesystemUrl(volumeInfo.mountPath));
-  var requestKey = this.makeRequestKey_('unmount', volumeInfo.mountPath);
+  chrome.fileBrowserPrivate.removeMount(volumeInfo.volumeId);
+  var requestKey = this.makeRequestKey_('unmount', volumeInfo.volumeId);
   this.startRequest_(requestKey, successCallback, errorCallback);
 };
 
 /**
- * Resolves the absolute path to its entry. Shouldn't be used outside of the
- * Files app's initialization.
- * @param {string} path The path to be resolved.
- * @param {function(Entry)} successCallback Called with the resolved entry on
- *     success.
- * @param {function(FileError)} errorCallback Called on error.
+ * Obtains a volume info containing the passed entry.
+ * @param {Entry|Object} entry Entry on the volume to be returned. Can be fake.
+ * @return {VolumeInfo} The VolumeInfo instance or null if not found.
  */
-VolumeManager.prototype.resolveAbsolutePath = function(
-    path, successCallback, errorCallback) {
-  // Make sure the path is in the mounted volume.
-  var volumeInfo = this.getVolumeInfo(path);
-  if (!volumeInfo || !volumeInfo.root) {
-    errorCallback(util.createDOMError(util.FileError.NOT_FOUND_ERR));
-    return;
-  }
-
-  webkitResolveLocalFileSystemURL(
-      util.makeFilesystemUrl(path), successCallback, errorCallback);
-};
-
-/**
- * Obtains the information of the volume that containing an entry pointed by the
- * specified path.
- * TODO(hirono): Stop to use path to get a volume info.
- *
- * @param {string|Entry} target Path or Entry pointing anywhere on a volume.
- * @return {VolumeInfo} The data about the volume.
- */
-VolumeManager.prototype.getVolumeInfo = function(target) {
-  if (typeof target === 'string')
-    return this.volumeInfoList.findByPath(target);
-  else if (util.isFakeEntry(target))
-    return this.getCurrentProfileVolumeInfo(util.VolumeType.DRIVE);
-  else
-    return this.volumeInfoList.findByPath(target.fullPath);
+VolumeManager.prototype.getVolumeInfo = function(entry) {
+  return this.volumeInfoList.findByEntry(entry);
 };
 
 /**
@@ -699,34 +666,33 @@ VolumeManager.prototype.getLocationInfo = function(entry) {
         true /* fake entries are read only. */);
   }
 
-  // TODO(mtomasz): Find by Entry instead.
-  var volumeInfo = this.volumeInfoList.findByPath(entry.fullPath);
+  var volumeInfo = this.volumeInfoList.findByEntry(entry);
   if (!volumeInfo)
     return null;
 
-  var rootPath;
   var rootType;
   var isReadOnly;
+  var isRootEntry;
   if (volumeInfo.volumeType === util.VolumeType.DRIVE) {
-    // If the volume is drive, root path can be either mountPath + '/root' or
-    // mountPath + '/other'.
-    if ((entry.fullPath + '/').indexOf(volumeInfo.mountPath + '/root/') === 0) {
-      rootPath = volumeInfo.mountPath + '/root';
+    // For Drive, the roots are /root and /other, instead of /.
+    // TODO(mtomasz): Simplify once switching to filesystem per volume.
+    if (entry.toURL() === volumeInfo.root.toURL() + '/root' ||
+        entry.toURL().indexOf(volumeInfo.root.toURL() + '/root/') === 0) {
       rootType = RootType.DRIVE;
-      isReadOnly = volumeInfo.isReadOnly ||
-          this.getDriveConnectionState().type ===
-              util.DriveConnectionType.OFFLINE;
-    } else if ((entry.fullPath + '/').indexOf(
-                   volumeInfo.mountPath + '/other/') === 0) {
-      rootPath = volumeInfo.mountPath + '/other';
+      isReadOnly = volumeInfo.isReadOnly;
+      isRootEntry = entry.toURL() === volumeInfo.root.toURL() + '/root';
+    } else if (entry.toURL() === volumeInfo.root.toURL() + '/other' ||
+        entry.toURL().indexOf(volumeInfo.root.toURL() + '/other/') === 0) {
       rootType = RootType.DRIVE_OTHER;
       isReadOnly = true;
+      isRootEntry = entry.toURL() === volumeInfo.root.toURL() + '/other';
     } else {
-      throw new Error(entry.fullPath + ' is an invalid drive path.');
+      // Accessing Drive files outside of /drive/root and /drive/other is not
+      // allowed, but can happen. Therefore returning null.
+      return null;
     }
   } else {
     // Otherwise, root path is same with a mount path of the volume.
-    rootPath = volumeInfo.mountPath;
     switch (volumeInfo.volumeType) {
       case util.VolumeType.DOWNLOADS:
         rootType = RootType.DOWNLOADS;
@@ -741,20 +707,20 @@ VolumeManager.prototype.getLocationInfo = function(entry) {
         rootType = RootType.CLOUD_DEVICE;
         break;
       default:
+        // Programming error, throw an exception.
         throw new Error('Invalid volume type: ' + volumeInfo.volumeType);
     }
     isReadOnly = volumeInfo.isReadOnly;
+    isRootEntry = util.isSameEntry(entry, volumeInfo.root);
   }
-  var isRootEntry = (entry.fullPath.substr(0, rootPath.length) || '/') ===
-      entry.fullPath;
 
   return new EntryLocation(volumeInfo, rootType, isRootEntry, isReadOnly);
 };
 
 /**
  * @param {string} key Key produced by |makeRequestKey_|.
- * @param {function(string)} successCallback To be called when request finishes
- *     successfully.
+ * @param {function(VolumeInfo)} successCallback To be called when request
+ *     finishes successfully.
  * @param {function(util.VolumeError)} errorCallback To be called when
  *     request fails.
  * @private
@@ -790,16 +756,16 @@ VolumeManager.prototype.onTimeout_ = function(key) {
 /**
  * @param {string} key Key produced by |makeRequestKey_|.
  * @param {util.VolumeError|'success'} status Status received from the API.
- * @param {string=} opt_mountPath Mount path.
+ * @param {VolumeInfo=} opt_volumeInfo Volume info of the mounted volume.
  * @private
  */
-VolumeManager.prototype.finishRequest_ = function(key, status, opt_mountPath) {
+VolumeManager.prototype.finishRequest_ = function(key, status, opt_volumeInfo) {
   var request = this.requests_[key];
   if (!request)
     return;
 
   clearTimeout(request.timeout);
-  this.invokeRequestCallbacks_(request, status, opt_mountPath);
+  this.invokeRequestCallbacks_(request, status, opt_volumeInfo);
   delete this.requests_[key];
 };
 
@@ -807,18 +773,18 @@ VolumeManager.prototype.finishRequest_ = function(key, status, opt_mountPath) {
  * @param {Object} request Structure created in |startRequest_|.
  * @param {util.VolumeError|string} status If status === 'success'
  *     success callbacks are called.
- * @param {string=} opt_mountPath Mount path. Required if success.
+ * @param {VolumeInfo=} opt_volumeInfo Volume info of the mounted volume.
  * @private
  */
-VolumeManager.prototype.invokeRequestCallbacks_ = function(request, status,
-                                                           opt_mountPath) {
+VolumeManager.prototype.invokeRequestCallbacks_ = function(
+    request, status, opt_volumeInfo) {
   var callEach = function(callbacks, self, args) {
     for (var i = 0; i < callbacks.length; i++) {
       callbacks[i].apply(self, args);
     }
   };
   if (status === 'success') {
-    callEach(request.successCallbacks, this, [opt_mountPath]);
+    callEach(request.successCallbacks, this, [opt_volumeInfo]);
   } else {
     volumeManagerUtil.validateError(status);
     callEach(request.errorCallbacks, this, [status]);