2 * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 var privUtils_ = xwalk.utils;
18 var privilege_ = privUtils_.privilege;
19 var type_ = privUtils_.type;
20 var converter_ = privUtils_.converter;
21 var validator_ = privUtils_.validator;
22 var types_ = validator_.Types;
23 var native_ = new xwalk.utils.NativeManager(extension);
26 * Create new array-like object of numbers: UTF-16 char codes from string.
27 * As type pass Array, Uint8Array, etc.
28 * Useful for passing data through crosswalk.
30 function StringToArray(str, type) {
32 var output = new type(len);
33 for (var i = 0; i < len; i++) {
34 output[i] = str.charCodeAt(i);
40 * Pass array-like object of numbers (Array, Uint8Array, etc.), returns string.
41 * Each char has codepoint equal to value from array cropped with & 0xFF
42 * Useful for passing data through crosswalk.
44 function ArrayToString(data) {
46 var len = data.length;
47 for (var i = 0; i < len; i++) {
48 output += String.fromCharCode(data[i] & 0xff); // conversion to octet
53 function SetReadOnlyProperty(obj, n, v) {
54 Object.defineProperty(obj, n, { value: v, writable: false });
57 var FileSystemStorageType = { INTERNAL: 'INTERNAL', EXTERNAL: 'EXTERNAL' };
59 var FileSystemStorageState = {
62 UNMOUNTABLE: 'UNMOUNTABLE'
65 var FileMode = { a: 'a', r: 'r', rw: 'rw', rwo: 'rwo', w: 'w' };
67 var BaseSeekPosition = { BEGIN: 'BEGIN', CURRENT: 'CURRENT', END: 'END' };
69 var tizen24home = '/opt/usr/media';
71 // this variable need to match same variable in
72 // common/filesystem/filesystem_provider_storage.cc
73 var kVirtualRootImages = 'images';
75 var commonFS_ = (function() {
76 var cacheReady = false;
77 var listenerRegistered = false;
78 var cacheVirtualToReal = {};
79 var cacheStorages = [];
80 var uriPrefix = 'file://';
81 // special condition for previous versions paths
82 // (global paths usage issue workaround)
83 var isAppForEarlierVersion = privUtils_.isAppVersionEarlierThan('3.0');
84 var homeDir = undefined;
86 function clearCache() {
87 cacheVirtualToReal = {};
92 // initalize home directory for correct mapping global paths from tizen 2.4
93 // (global paths usage issue workaround)
94 function initHomeDir(aPath) {
95 if (homeDir || !isAppForEarlierVersion) {
98 var imagesPath = cacheVirtualToReal[kVirtualRootImages].path;
100 if (imagesPath[imagesPath.length - 1] === '/') {
113 function initCache() {
117 var result = native_.callSync('Filesystem_fetchAllStorages', {});
118 if (native_.isFailure(result)) {
119 throw native_.getErrorObject(result);
121 var virtualRoots = native_.getResultObject(result);
123 for (var i = 0; i < virtualRoots.length; ++i) {
124 cacheVirtualToReal[virtualRoots[i].name] = {
125 path: virtualRoots[i].path,
126 label: virtualRoots[i].name,
127 type: virtualRoots[i].type,
128 state: virtualRoots[i].state
131 // initalize home directory for correct mapping global paths from tizen 2.4
132 // (global paths usage issue workaround)
135 var result = native_.callSync('FileSystemManager_fetchStorages', {});
136 if (native_.isFailure(result)) {
137 throw native_.getErrorObject(result);
140 var storages = native_.getResultObject(result);
141 for (var i = 0; i < storages.length; ++i) {
143 path: storages[i].path,
144 label: storages[i].name,
145 type: storages[i].type,
146 state: storages[i].state,
147 storage_id: storages[i].storage_id
151 if (!listenerRegistered) {
153 tizen.filesystem.addStorageStateChangeListener(function() {
156 listenerRegistered = true;
159 'Failed to register storage change listener, ' +
160 'storage information may be corrupted: ' +
169 function mergeMultipleSlashes(str) {
170 var retStr = str.replace(/(^(file\:\/\/\/)|^(file\:\/\/)|\/)\/{0,}/g, '$1');
174 function removeDotsFromPath(str) {
175 if (str === undefined) {
179 var _pathTokens = str.split('/');
180 var _correctDir = [];
181 var _fileRealPath = _pathTokens[0];
182 _correctDir.push(_pathTokens[0]);
183 for (var i = 1; i < _pathTokens.length; ++i) {
184 if (_pathTokens[i] == '..') {
185 if (_fileRealPath == '') {
186 _fileRealPath = undefined;
189 var _lastDir = _correctDir.pop();
190 _fileRealPath = _fileRealPath.substring(
192 _fileRealPath.length - _lastDir.length - 1
194 } else if (_pathTokens[i] != '.') {
195 _fileRealPath += '/' + _pathTokens[i];
196 _correctDir.push(_pathTokens[i]);
199 return _fileRealPath;
202 function checkPathWithoutDots(aPath) {
203 if (-1 !== aPath.indexOf('/../')) {
206 if (-1 !== aPath.indexOf('/./')) {
209 // check if path ends with '/.' or '/..'
210 if (aPath.match(/\/\.\.?$/)) {
213 // check if path starts with './' or '../'
214 if (aPath.match(/^\.\.?\//)) {
220 function convertForEarlierVersionPath(aPath) {
221 if (isAppForEarlierVersion) {
222 if (aPath && aPath.indexOf(tizen24home) === 0) {
223 privUtils_.log('Converting 2.4 style path to 3.0 pattern');
224 aPath = homeDir + aPath.substr(tizen24home.length);
230 function toRealPath(aPath) {
231 var _fileRealPath = '';
233 aPath = mergeMultipleSlashes(aPath);
235 if (aPath.indexOf(uriPrefix) === 0) {
236 _fileRealPath = aPath.substr(uriPrefix.length);
237 } else if (aPath[0] !== '/') {
241 var _pathTokens = aPath.split('/');
243 if (cacheVirtualToReal[_pathTokens[0]]) {
244 _fileRealPath = cacheVirtualToReal[_pathTokens[0]].path;
245 for (var i = 1; i < _pathTokens.length; ++i) {
246 _fileRealPath += '/' + _pathTokens[i];
249 // If path token is not present in cache then it is invalid
250 _fileRealPath = undefined;
252 for (var j = 0; j < cacheStorages.length; ++j) {
253 if (cacheStorages[j].label === _pathTokens[0]) {
254 _fileRealPath = cacheStorages[j].path;
255 for (var i = 1; i < _pathTokens.length; ++i) {
256 _fileRealPath += '/' + _pathTokens[i];
263 _fileRealPath = aPath;
265 // removeDotsFromPath execution here, results with '.' and '..' beeing
266 // supported in paths, next methods throw an error when getting argument
267 // with '.' or '..' in it
268 // (see commonFS_.checkPathWithoutDots() method)
269 _fileRealPath = removeDotsFromPath(_fileRealPath);
270 // convert path to be compatibile with previous version of Tizen
271 // (global paths usage issue workaround)
272 _fileRealPath = convertForEarlierVersionPath(_fileRealPath);
273 // if path is valid try to cut last '/' if it is present
275 _fileRealPath = mergeMultipleSlashes(_fileRealPath);
277 return _fileRealPath;
280 function toVirtualPath(aPath) {
281 aPath = mergeMultipleSlashes(aPath);
282 var _virtualPath = aPath;
284 if (_virtualPath.indexOf(uriPrefix) === 0) {
285 _virtualPath = _virtualPath.substr(uriPrefix.length);
289 // find virtual root with longest path
291 var foundVirtualRoot;
292 var foundVirtualPath;
293 for (var virtual_root in cacheVirtualToReal) {
294 var real_root_path = cacheVirtualToReal[virtual_root].path;
295 if (_virtualPath.indexOf(real_root_path, 0) === 0) {
296 var currentLength = real_root_path.length;
297 if (currentLength > foundLength) {
298 foundLength = currentLength;
299 foundVirtualRoot = virtual_root;
300 foundVirtualPath = real_root_path;
304 if (foundLength != 0) {
305 return _virtualPath.replace(foundVirtualPath, foundVirtualRoot);
310 function getFileInfo(aStatObj, secondIter, aMode) {
313 _fileParentPath = '',
315 var aPath = toVirtualPath(aStatObj.path);
317 _result.readOnly = aStatObj.readOnly;
318 _result.isFile = aStatObj.isFile;
319 _result.isDirectory = aStatObj.isDirectory;
320 _result.created = new Date(aStatObj.ctime * 1000);
321 _result.modified = new Date(aStatObj.mtime * 1000);
322 _result.fullPath = aPath;
323 _result.fileSize = aStatObj.size;
324 _result.mode = aMode;
325 if (_result.isDirectory) {
327 _result.length = aStatObj.nlink;
332 _result.length = undefined;
335 _pathTokens = aPath.split('/');
336 if (_pathTokens.length > 1) {
337 var last = _pathTokens.length - 1;
339 if (_pathTokens[last] === '') {
340 // 'abc/d/e/' case with trailing '/' sign
341 last = _pathTokens.length - 2;
344 for (i = 0; i < last; ++i) {
345 _fileParentPath += _pathTokens[i] + '/';
348 _result.path = _fileParentPath;
349 _result.name = secondIter
351 : _pathTokens[last] + lastToken;
352 _result.parent = secondIter ? null : _fileParentPath;
355 _result.path = _pathTokens[last] + lastToken;
357 _result.parent = secondIter ? null : _fileParentPath;
360 _result.parent = null;
361 _result.path = aPath;
367 function isLocationAllowed(aPath) {
372 if (aPath.indexOf(cacheVirtualToReal.ringtones.path) === 0) {
375 if (aPath.indexOf(cacheVirtualToReal['wgt-package'].path) === 0) {
382 function toCanonicalPath(path) {
383 var result = native_.callSync('FileSystemManager_getCanonicalPath', {
386 if (native_.isFailure(result)) {
387 throw native_.getErrorObject(result);
390 return native_.getResultObject(result);
393 function f_isSubDir(fullPathToCheck, fullPath) {
394 var fullCanonicalPathToCheck = toCanonicalPath(toRealPath(fullPathToCheck));
395 var fullCanonicalPath = toCanonicalPath(toRealPath(fullPath));
397 if (fullCanonicalPathToCheck === fullCanonicalPath) {
401 return fullCanonicalPathToCheck.indexOf(fullCanonicalPath) === 0;
404 function f_isCorrectRelativePath(relativePath) {
406 0 !== relativePath.indexOf('/') &&
407 0 !== relativePath.indexOf('\\') &&
408 -1 === relativePath.indexOf('?') &&
409 -1 === relativePath.indexOf('*') &&
410 -1 === relativePath.indexOf(':') &&
411 -1 === relativePath.indexOf('"') &&
412 -1 === relativePath.indexOf('<') &&
413 -1 === relativePath.indexOf('>')
417 function cloneStorage(storage) {
418 return { label: storage.label, type: storage.type, state: storage.state };
421 function getStorage(label) {
423 for (var i = 0; i < cacheStorages.length; ++i) {
424 if (cacheStorages[i].label === label) {
425 return cloneStorage(cacheStorages[i]);
429 for (var key in cacheVirtualToReal) {
430 if (cacheVirtualToReal.hasOwnProperty(key)) {
431 if (cacheVirtualToReal[key].label === label) {
432 return cloneStorage(cacheVirtualToReal[key]);
440 function getAllStorages() {
443 for (var i = 0; i < cacheStorages.length; ++i) {
444 ret.push(cloneStorage(cacheStorages[i]));
447 for (var key in cacheVirtualToReal) {
448 if (cacheVirtualToReal.hasOwnProperty(key)) {
449 ret.push(cloneStorage(cacheVirtualToReal[key]));
457 clearCache: clearCache,
458 checkPathWithoutDots: checkPathWithoutDots,
459 toRealPath: toRealPath,
460 toVirtualPath: toVirtualPath,
461 getFileInfo: getFileInfo,
462 isLocationAllowed: isLocationAllowed,
463 f_isSubDir: f_isSubDir,
464 f_isCorrectRelativePath: f_isCorrectRelativePath,
465 getStorage: getStorage,
466 getAllStorages: getAllStorages,
467 mergeMultipleSlashes: mergeMultipleSlashes