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
3 // found in the LICENSE file.
5 // Custom binding for the fileSystem API.
7 var binding
= require('binding').Binding
.create('fileSystem');
9 var fileSystemNatives
= requireNative('file_system_natives');
10 var GetIsolatedFileSystem
= fileSystemNatives
.GetIsolatedFileSystem
;
11 var lastError
= require('lastError');
12 var sendRequest
= require('sendRequest').sendRequest
;
13 var GetModuleSystem
= requireNative('v8_context').GetModuleSystem
;
14 // TODO(sammc): Don't require extension. See http://crbug.com/235689.
15 var GetExtensionViews
= requireNative('runtime').GetExtensionViews
;
17 // Fallback to using the current window if no background page is running.
18 var backgroundPage
= GetExtensionViews(-1, 'BACKGROUND')[0] || window
;
19 var backgroundPageModuleSystem
= GetModuleSystem(backgroundPage
);
21 // All windows use the bindFileEntryCallback from the background page so their
22 // FileEntry objects have the background page's context as their own. This
23 // allows them to be used from other windows (including the background page)
24 // after the original window is closed.
25 if (window
== backgroundPage
) {
26 var bindFileEntryCallback = function(functionName
, apiFunctions
) {
27 apiFunctions
.setCustomCallback(functionName
,
28 function(name
, request
, response
) {
29 if (request
.callback
&& response
) {
30 var callback
= request
.callback
;
31 request
.callback
= null;
36 var getEntryError = function(fileError
) {
40 'fileSystem.' + functionName
,
41 'Error getting fileEntry, code: ' + fileError
.code
,
47 // Loop through the response entries and asynchronously get the
48 // FileEntry for each. We use hasError to ensure that only the first
49 // error is reported. Note that an error can occur either during the
50 // loop or in the asynchronous error callback to getFile.
51 $Array
.forEach(response
.entries
, function(entry
) {
54 var fileSystemId
= entry
.fileSystemId
;
55 var baseName
= entry
.baseName
;
57 var fs
= GetIsolatedFileSystem(fileSystemId
);
60 var getEntryCallback = function(fileEntry
) {
63 entryIdManager
.registerEntry(id
, fileEntry
);
64 entries
.push(fileEntry
);
65 // Once all entries are ready, pass them to the callback. In the
66 // event of an error, this condition will never be satisfied so
67 // the callback will not be called with any entries.
68 if (entries
.length
== response
.entries
.length
) {
69 if (response
.multiple
) {
76 // TODO(koz): fs.root.getFile() makes a trip to the browser process,
77 // but it might be possible avoid that by calling
78 // WebFrame::createFileEntry().
79 if (entry
.isDirectory
) {
80 fs
.root
.getDirectory(baseName
, {}, getEntryCallback
,
83 fs
.root
.getFile(baseName
, {}, getEntryCallback
, getEntryError
);
88 lastError
.run('fileSystem.' + functionName
,
89 'Error getting fileEntry: ' + e
.stack
,
98 var entryIdManager
= require('entryIdManager');
100 // Force the fileSystem API to be loaded in the background page. Using
101 // backgroundPageModuleSystem.require('fileSystem') is insufficient as
102 // requireNative is only allowed while lazily loading an API.
103 backgroundPage
.chrome
.fileSystem
;
104 var bindFileEntryCallback
= backgroundPageModuleSystem
.require(
105 'fileSystem').bindFileEntryCallback
;
106 var entryIdManager
= backgroundPageModuleSystem
.require('entryIdManager');
109 binding
.registerCustomHook(function(bindingsAPI
) {
110 var apiFunctions
= bindingsAPI
.apiFunctions
;
111 var fileSystem
= bindingsAPI
.compiledApi
;
113 function bindFileEntryFunction(functionName
) {
114 apiFunctions
.setUpdateArgumentsPostValidate(
115 functionName
, function(fileEntry
, callback
) {
116 var fileSystemName
= fileEntry
.filesystem
.name
;
117 var relativePath
= $String
.slice(fileEntry
.fullPath
, 1);
118 return [fileSystemName
, relativePath
, callback
];
121 $Array
.forEach(['getDisplayPath', 'getWritableEntry', 'isWritableEntry'],
122 bindFileEntryFunction
);
124 $Array
.forEach(['getWritableEntry', 'chooseEntry', 'restoreEntry'],
125 function(functionName
) {
126 bindFileEntryCallback(functionName
, apiFunctions
);
129 apiFunctions
.setHandleRequest('retainEntry', function(fileEntry
) {
130 var id
= entryIdManager
.getEntryId(fileEntry
);
133 var fileSystemName
= fileEntry
.filesystem
.name
;
134 var relativePath
= $String
.slice(fileEntry
.fullPath
, 1);
136 sendRequest(this.name
, [id
, fileSystemName
, relativePath
],
137 this.definition
.parameters
, {});
141 apiFunctions
.setHandleRequest('isRestorable',
142 function(id
, callback
) {
143 var savedEntry
= entryIdManager
.getEntryById(id
);
147 sendRequest(this.name
, [id
, callback
], this.definition
.parameters
, {});
151 apiFunctions
.setUpdateArgumentsPostValidate('restoreEntry',
152 function(id
, callback
) {
153 var savedEntry
= entryIdManager
.getEntryById(id
);
155 // We already have a file entry for this id so pass it to the callback and
156 // send a request to the browser to move it to the back of the LRU.
157 callback(savedEntry
);
158 return [id
, false, null];
160 // Ask the browser process for a new file entry for this id, to be passed
162 return [id
, true, callback
];
166 // TODO(benwells): Remove these deprecated versions of the functions.
167 fileSystem
.getWritableFileEntry = function() {
168 console
.log("chrome.fileSystem.getWritableFileEntry is deprecated");
169 console
.log("Please use chrome.fileSystem.getWritableEntry instead");
170 $Function
.apply(fileSystem
.getWritableEntry
, this, arguments
);
173 fileSystem
.isWritableFileEntry = function() {
174 console
.log("chrome.fileSystem.isWritableFileEntry is deprecated");
175 console
.log("Please use chrome.fileSystem.isWritableEntry instead");
176 $Function
.apply(fileSystem
.isWritableEntry
, this, arguments
);
179 fileSystem
.chooseFile = function() {
180 console
.log("chrome.fileSystem.chooseFile is deprecated");
181 console
.log("Please use chrome.fileSystem.chooseEntry instead");
182 $Function
.apply(fileSystem
.chooseEntry
, this, arguments
);
186 exports
.bindFileEntryCallback
= bindFileEntryCallback
;
187 exports
.binding
= binding
.generate();