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 function FileSystemStorage(data) {
18 Object.defineProperties(this, {
19 label: { value: data.label, writable: false, enumerable: true },
20 type: { value: data.type, writable: false, enumerable: true },
21 state: { value: data.state, writable: false, enumerable: true }
25 var FileStreamManager = function() {
29 FileStreamManager.prototype.getNextFileHandleId = function() {
33 var fileStreamManager = new FileStreamManager();
35 function FileSystemManager() {
36 var limits = native_.getResultObject(native_.callSync('FileSystemManagerGetLimits'));
37 Object.defineProperties(this, {
38 maxNameLength: { value: limits[0], writable: false, enumerable: true },
39 maxPathLength: { value: limits[1], writable: false, enumerable: true }
43 FileSystemManager.prototype.openFile = function() {
44 var args = validator_.validateArgs(arguments, [
45 { name: 'path', type: types_.STRING },
46 { name: 'openMode', type: types_.ENUM, values: type_.getValues(FileMode) },
47 { name: 'makeParents', type: types_.BOOLEAN, optional: true }
50 if (!args.has.makeParents) {
51 args.makeParents = true;
55 path: commonFS_.toRealPath(args.path),
56 openMode: args.openMode,
57 makeParents: args.makeParents,
58 id: fileStreamManager.getNextFileHandleId()
62 throw new WebAPIException(
63 WebAPIException.NOT_FOUND_ERR,
64 'Invalid path: ' + args.path
68 var result = native_.callSync('FileSystemManagerOpenFile', data);
69 if (native_.isFailure(result)) {
70 throw native_.getErrorObject(result);
72 return new FileHandle(data.id, args.path, args.openMode);
76 FileSystemManager.prototype.createDirectory = function() {
77 var args = validator_.validateArgs(arguments, [
78 { name: 'path', type: types_.STRING },
79 { name: 'makeParents', type: types_.BOOLEAN, optional: true },
81 name: 'successCallback',
82 type: types_.FUNCTION,
86 { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
89 if (!args.has.makeParents) {
90 args.makeParents = true;
93 var data = { path: commonFS_.toRealPath(args.path), makeParents: args.makeParents };
96 throw new WebAPIException(
97 WebAPIException.INVALID_VALUES_ERR,
98 'Invalid path: ' + args.path
102 var callback = function(result) {
103 if (native_.isFailure(result)) {
104 native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
106 var path = native_.getResultObject(result);
107 native_.callIfPossible(args.successCallback, commonFS_.toVirtualPath(path));
111 var result = native_.call('FileSystemManagerCreateDirectory', data, callback);
112 if (native_.isFailure(result)) {
113 throw native_.getErrorObject(result);
117 FileSystemManager.prototype.deleteFile = function() {
118 var args = validator_.validateArgs(arguments, [
119 { name: 'path', type: types_.STRING },
121 name: 'successCallback',
122 type: types_.FUNCTION,
126 { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
129 var data = { path: commonFS_.toRealPath(args.path) };
132 throw new WebAPIException(
133 WebAPIException.INVALID_VALUES_ERR,
134 'Invalid path: ' + args.path
138 var callback = function(result) {
139 if (native_.isFailure(result)) {
140 native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
142 var path = native_.getResultObject(result);
143 native_.callIfPossible(args.successCallback, commonFS_.toVirtualPath(path));
147 var result = native_.call('FileSystemManagerDeleteFile', data, callback);
148 if (native_.isFailure(result)) {
149 throw native_.getErrorObject(result);
153 FileSystemManager.prototype.deleteDirectory = function() {
154 var args = validator_.validateArgs(arguments, [
155 { name: 'path', type: types_.STRING },
156 { name: 'recursive', type: types_.BOOLEAN, optional: true },
158 name: 'successCallback',
159 type: types_.FUNCTION,
163 { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
166 if (!args.has.recursive) {
167 args.recursive = true;
170 var realPath = commonFS_.toRealPath(args.path);
172 throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Invalid path.');
175 var data = { path: realPath, recursive: args.recursive };
177 var callback = function(result) {
178 if (native_.isFailure(result)) {
179 native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
181 var path = native_.getResultObject(result);
182 native_.callIfPossible(args.successCallback, commonFS_.toVirtualPath(path));
186 var result = native_.call('FileSystemManagerDeleteDirectory', data, callback);
187 if (native_.isFailure(result)) {
188 throw native_.getErrorObject(result);
192 FileSystemManager.prototype.copyFile = function() {
193 var args = validator_.validateArgs(arguments, [
194 { name: 'path', type: types_.STRING },
195 { name: 'destinationPath', type: types_.STRING },
196 { name: 'overwrite', type: types_.BOOLEAN, optional: true },
198 name: 'successCallback',
199 type: types_.FUNCTION,
203 { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
206 if (!args.has.overwrite) {
207 args.overwrite = false;
211 path: commonFS_.toRealPath(args.path),
212 destinationPath: commonFS_.toRealPath(args.destinationPath),
213 overwrite: args.overwrite
217 throw new WebAPIException(
218 WebAPIException.INVALID_VALUES_ERR,
219 'Invalid path: ' + args.path
222 if (!data.destinationPath) {
223 throw new WebAPIException(
224 WebAPIException.INVALID_VALUES_ERR,
225 'Invalid path: ' + args.destinationPath
229 var callback = function(result) {
230 if (native_.isFailure(result)) {
231 native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
233 var path = native_.getResultObject(result);
234 native_.callIfPossible(args.successCallback, commonFS_.toVirtualPath(path));
238 var result = native_.call('FileSystemManagerCopyFile', data, callback);
239 if (native_.isFailure(result)) {
240 throw native_.getErrorObject(result);
244 FileSystemManager.prototype.copyDirectory = function() {
245 var args = validator_.validateArgs(arguments, [
246 { name: 'path', type: types_.STRING },
247 { name: 'destinationPath', type: types_.STRING },
248 { name: 'overwrite', type: types_.BOOLEAN, optional: true },
250 name: 'successCallback',
251 type: types_.FUNCTION,
255 { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
258 var realPath = commonFS_.toRealPath(args.path);
259 var realDestinationPath = commonFS_.toRealPath(args.destinationPath);
260 if (!realPath || !realDestinationPath) {
261 throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Invalid path.');
264 if (!args.has.overwrite) {
265 args.overwrite = false;
270 destinationPath: realDestinationPath,
271 overwrite: args.overwrite
274 var callback = function(result) {
275 if (native_.isFailure(result)) {
276 native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
278 var path = native_.getResultObject(result);
279 native_.callIfPossible(args.successCallback, commonFS_.toVirtualPath(path));
283 var result = native_.call('FileSystemManagerCopyDirectory', data, callback);
284 if (native_.isFailure(result)) {
285 throw native_.getErrorObject(result);
289 FileSystemManager.prototype.moveFile = function() {
290 var args = validator_.validateArgs(arguments, [
291 { name: 'path', type: types_.STRING },
292 { name: 'destinationPath', type: types_.STRING },
293 { name: 'overwrite', type: types_.BOOLEAN, optional: true },
295 name: 'successCallback',
296 type: types_.FUNCTION,
300 { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
303 var realPath = commonFS_.toRealPath(args.path);
304 var realDestinationPath = commonFS_.toRealPath(args.destinationPath);
305 if (!realPath || !realDestinationPath) {
306 throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Invalid path.');
309 if (!args.has.overwrite) {
310 args.overwrite = false;
315 destinationPath: realDestinationPath,
316 overwrite: args.overwrite
319 var callback = function(result) {
320 if (native_.isFailure(result)) {
321 native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
323 var path = native_.getResultObject(result);
324 native_.callIfPossible(args.successCallback, commonFS_.toVirtualPath(path));
328 var result = native_.call('FileSystemManagerMoveFile', data, callback);
329 if (native_.isFailure(result)) {
330 throw native_.getErrorObject(result);
334 FileSystemManager.prototype.moveDirectory = function() {
335 var args = validator_.validateArgs(arguments, [
336 { name: 'path', type: types_.STRING },
337 { name: 'destinationPath', type: types_.STRING },
338 { name: 'overwrite', type: types_.BOOLEAN, optional: true },
340 name: 'successCallback',
341 type: types_.FUNCTION,
345 { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
348 var realPath = commonFS_.toRealPath(args.path);
349 var realDestinationPath = commonFS_.toRealPath(args.destinationPath);
350 if (!realPath || !realDestinationPath) {
351 throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Invalid path.');
354 if (!args.has.overwrite) {
355 args.overwrite = false;
360 destinationPath: realDestinationPath,
361 overwrite: args.overwrite
364 var callback = function(result) {
365 if (native_.isFailure(result)) {
366 native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
368 var path = native_.getResultObject(result);
369 native_.callIfPossible(args.successCallback, commonFS_.toVirtualPath(path));
373 var result = native_.call('FileSystemManagerMoveDirectory', data, callback);
374 if (native_.isFailure(result)) {
375 throw native_.getErrorObject(result);
379 FileSystemManager.prototype.rename = function() {
380 var args = validator_.validateArgs(arguments, [
381 { name: 'path', type: types_.STRING },
382 { name: 'newName', type: types_.STRING },
384 name: 'successCallback',
385 type: types_.FUNCTION,
389 { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
392 if (-1 !== args.newName.indexOf('/') || -1 !== args.newName.indexOf('\x00')) {
393 throw new WebAPIException(
394 WebAPIException.INVALID_VALUES_ERR,
395 'newName contains invalid character.'
399 var realPath = commonFS_.toRealPath(args.path);
401 throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Invalid path.');
404 var data = { path: realPath, newName: args.newName };
406 var callback = function(result) {
407 if (native_.isFailure(result)) {
408 native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
410 var path = native_.getResultObject(result);
411 native_.callIfPossible(args.successCallback, commonFS_.toVirtualPath(path));
415 var result = native_.call('FileSystemManagerRename', data, callback);
416 if (native_.isFailure(result)) {
417 throw native_.getErrorObject(result);
421 function throwIfNotDate(argument, name) {
422 if (argument instanceof Date) {
425 throw new WebAPIException(
426 WebAPIException.TYPE_MISMATCH_ERR,
427 'Argument "' + name + '" in a filter is not of type Date.'
431 FileSystemManager.prototype.listDirectory = function() {
432 var args = validator_.validateArgs(arguments, [
433 { name: 'path', type: types_.STRING },
434 { name: 'successCallback', type: types_.FUNCTION, optional: true },
435 { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true },
436 { name: 'filter', type: types_.DICTIONARY, optional: true, nullable: true }
439 if (!args.has.filter) {
443 if (args.filter.hasOwnProperty('startModified')) {
444 throwIfNotDate(args.filter.startModified, 'startModified');
445 args.filter.startModified = args.filter.startModified.getTime() / 1000;
447 if (args.filter.hasOwnProperty('endModified')) {
448 throwIfNotDate(args.filter.endModified, 'endModified');
449 args.filter.endModified = args.filter.endModified.getTime() / 1000;
451 if (args.filter.hasOwnProperty('startCreated')) {
452 throwIfNotDate(args.filter.startCreated, 'startCreated');
453 args.filter.startCreated = args.filter.startCreated.getTime() / 1000;
455 if (args.filter.hasOwnProperty('endCreated')) {
456 throwIfNotDate(args.filter.endCreated, 'endCreated');
457 args.filter.endCreated = args.filter.endCreated.getTime() / 1000;
460 var data = { path: commonFS_.toRealPath(args.path), filter: args.filter };
463 throw new WebAPIException(
464 WebAPIException.INVALID_VALUES_ERR,
465 'Invalid path: ' + args.path
469 var callback = function(result) {
470 if (native_.isFailure(result)) {
471 native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
473 var obj = native_.getResultObject(result);
474 var names = obj.names;
475 if (args.filter.hasOwnProperty('name')) {
476 var regex_name = stringToRegex(args.filter.name);
477 for (var i = names.length - 1; i >= 0; i--) {
478 if (!regex_name.test(names[i])) {
483 native_.callIfPossible(
484 args.successCallback,
486 commonFS_.toVirtualPath(obj.path)
491 var result = native_.call('FileSystemManagerListDirectory', data, callback);
492 if (native_.isFailure(result)) {
493 throw native_.getErrorObject(result);
497 FileSystemManager.prototype.toURI = function() {
498 var args = validator_.validateArgs(arguments, [
499 { name: 'path', type: types_.STRING }
502 // The toRealPath function will convert any string to absolute path, if possible.
503 // The function returns undefined for path, which starts with not-existing
505 var realPath = commonFS_.toRealPath(args.path);
508 throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Invalid path.');
511 return 'file://' + realPath;
514 FileSystemManager.prototype.isFile = function() {
515 var args = validator_.validateArgs(arguments, [
516 { name: 'path', type: types_.STRING }
518 // The toRealPath function will convert any string to absolute path, if possible.
519 // The function returns undefined for path, which starts with not-existing
521 var realPath = commonFS_.toRealPath(args.path);
524 throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Invalid path.');
527 var data = { path: realPath };
529 var result = native_.callSync('FileSystemManagerIsFile', data);
530 if (native_.isFailure(result)) {
531 throw native_.getErrorObject(result);
533 return native_.getResultObject(result);
537 FileSystemManager.prototype.isDirectory = function() {
538 var args = validator_.validateArgs(arguments, [
539 { name: 'path', type: types_.STRING }
541 // The toRealPath function will convert any string to absolute path, if possible.
542 // The function returns undefined for path, which starts with not-existing
544 var realPath = commonFS_.toRealPath(args.path);
547 throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Invalid path.');
550 var data = { path: realPath };
552 var result = native_.callSync('FileSystemManagerIsDirectory', data);
553 if (native_.isFailure(result)) {
554 throw native_.getErrorObject(result);
556 return native_.getResultObject(result);
560 FileSystemManager.prototype.pathExists = function() {
561 var args = validator_.validateArgs(arguments, [
562 { name: 'path', type: types_.STRING }
564 // The toRealPath function will convert any string to absolute path, if possible.
565 // The function returns undefined for path, which starts with not-existing
567 var realPath = commonFS_.toRealPath(args.path);
570 throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Invalid path.');
572 var data = { path: realPath };
574 var result = native_.callSync('FileSystemManagerPathExists', data);
575 if (native_.isFailure(result)) {
576 throw native_.getErrorObject(result);
578 return native_.getResultObject(result);
582 FileSystemManager.prototype.getDirName = function() {
583 var args = validator_.validateArgs(arguments, [
584 { name: 'path', type: types_.STRING }
586 var path = args.path;
588 path = commonFS_.mergeMultipleSlashes(path);
589 if (path.startsWith('file://')) {
590 path = path.substring('file://'.length - 1, path.length - 1);
593 if (path.startsWith('/') && 0 === path.lastIndexOf('/')) {
594 // handle the "/" and "/file.ext"
596 } else if (path.endsWith('/')) {
598 path = path.substring(0, path.length - 1);
601 var index = path.lastIndexOf('/');
603 path = path.substring(0, index); // cut the directory/file the path points to
610 'DEPRECATION WARNING: FileSystemManager.resolve() is deprecated since ' +
611 'Tizen 5.0. Use FileHandle and FileSystemManager interfaces instead.'
614 var args = validator_.validateArgs(arguments, [
615 { name: 'location', type: types_.STRING },
616 { name: 'onsuccess', type: types_.FUNCTION },
617 { name: 'onerror', type: types_.FUNCTION, optional: true, nullable: true },
621 values: Object.keys(FileMode),
627 if (!args.has.mode) {
629 } else if ('rwo' == args.mode) {
630 throw new WebAPIException(
631 WebAPIException.INVALID_VALUES_ERR,
632 'rwo mode was introduced in version 5.0 and is not supported in earlier ' +
637 // resolving a path on unmounted storage should result in exception
638 var storage = commonFS_.getStorage(args.location.split('/')[0]);
639 if (storage && FileSystemStorageState.MOUNTED !== storage.state) {
640 setTimeout(function() {
641 native_.callIfPossible(
644 WebAPIException.NOT_FOUND_ERR,
645 'Storage is not mounted.'
652 // Validation against '.' and '..' directories used in path - not allowed
653 var result = commonFS_.checkPathWithoutDots(args.location);
655 // path contains dots - it is not allowed - return InvalidValuesError
656 setTimeout(function() {
657 native_.callIfPossible(
660 WebAPIException.INVALID_VALUES_ERR,
661 'Path contains \'.\' or \'..\' - it is not allowed.'
668 var _realPath = commonFS_.toRealPath(args.location);
671 // invalid real path means that virtual root does not exist
672 setTimeout(function() {
673 native_.callIfPossible(
675 new WebAPIException(WebAPIException.NOT_FOUND_ERR, 'Invalid path.')
681 var _isLocationAllowed = commonFS_.isLocationAllowed(_realPath);
683 if (args.mode !== 'r' && !_isLocationAllowed) {
684 setTimeout(function() {
685 native_.callIfPossible(
688 WebAPIException.INVALID_VALUES_ERR,
689 'Provided arguments are not valid.'
696 var data = { location: _realPath };
698 var callback = function(result) {
699 if (native_.isFailure(result)) {
700 native_.callIfPossible(args.onerror, native_.getErrorObject(result));
704 var aStatObj = native_.getResultObject(result);
705 var _result = commonFS_.getFileInfo(aStatObj, false, args.mode);
706 if (_result.readOnly && args.mode !== 'r') {
707 native_.callIfPossible(
709 new WebAPIException(WebAPIException.IO_ERR, 'File is read-only.')
712 native_.callIfPossible(args.onsuccess, new File(_result));
716 var ret = native_.call('FileStat', data, callback);
717 if (native_.isFailure(ret)) {
718 throw native_.getErrorObject(ret);
722 FileSystemManager.prototype.resolve = function() {
723 resolve.apply(this, arguments);
726 function getStorage() {
727 xwalk.utils.checkPrivilegeAccess(xwalk.utils.privilege.FILESYSTEM_READ);
728 var args = validator_.validateArgs(arguments, [
729 { name: 'label', type: types_.STRING },
730 { name: 'onsuccess', type: types_.FUNCTION },
731 { name: 'onerror', type: types_.FUNCTION, optional: true, nullable: true }
734 setTimeout(function() {
735 var storage = commonFS_.getStorage(args.label);
738 native_.callIfPossible(
740 new WebAPIException(WebAPIException.NOT_FOUND_ERR, 'Storage not found.')
743 native_.callIfPossible(args.onsuccess, new FileSystemStorage(storage));
748 FileSystemManager.prototype.getStorage = function() {
749 getStorage.apply(this, arguments);
752 function listStorages() {
753 xwalk.utils.checkPrivilegeAccess(xwalk.utils.privilege.FILESYSTEM_READ);
754 var args = validator_.validateArgs(arguments, [
755 { name: 'onsuccess', type: types_.FUNCTION },
756 { name: 'onerror', type: types_.FUNCTION, optional: true, nullable: true }
759 setTimeout(function() {
761 var cache = commonFS_.getAllStorages();
762 for (var i = 0; i < cache.length; ++i) {
763 storages.push(new FileSystemStorage(cache[i]));
766 native_.callIfPossible(args.onsuccess, storages);
770 FileSystemManager.prototype.listStorages = function() {
771 listStorages.apply(this, arguments);
777 function nextCallbackId() {
781 function _StorageStateChangeListener(result) {
782 commonFS_.clearCache();
783 var storage = new FileSystemStorage(result);
784 for (var id in callbacks) {
785 native_.callIfPossible(callbacks[id], storage);
789 function addStorageStateChangeListener() {
790 var args = validator_.validateArgs(arguments, [
791 { name: 'onsuccess', type: types_.FUNCTION },
792 { name: 'onerror', type: types_.FUNCTION, optional: true, nullable: true }
795 var register = false;
796 if (type_.isEmptyObject(callbacks)) {
800 var id = nextCallbackId();
801 callbacks[id] = args.onsuccess;
804 native_.addListener('StorageStateChangeListener', _StorageStateChangeListener);
805 var result = native_.callSync(
806 'FileSystemManagerAddStorageStateChangeListener',
810 if (native_.isFailure(result)) {
811 throw native_.getErrorObject(result);
818 FileSystemManager.prototype.addStorageStateChangeListener = function() {
819 return addStorageStateChangeListener.apply(this, arguments);
822 function removeStorageStateChangeListener() {
823 var args = validator_.validateArgs(arguments, [
824 { name: 'watchId', type: types_.LONG }
827 if (!arguments.length) {
828 throw new WebAPIException(WebAPIException.TYPE_MISMATCH_ERR, 'Missing watchId');
830 var id = args.watchId;
832 if (type_.isNullOrUndefined(callbacks[id])) {
836 delete callbacks[id];
838 if (type_.isEmptyObject(callbacks)) {
839 var result = native_.callSync(
840 'FileSystemManagerRemoveStorageStateChangeListener',
843 if (native_.isFailure(result)) {
844 throw native_.getErrorObject(result);
849 FileSystemManager.prototype.removeStorageStateChangeListener = function() {
850 removeStorageStateChangeListener.apply(this, arguments);
853 exports = new FileSystemManager();