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 },
42 value: function(name, path, type, state) {
43 commonFS_.setVirtualPath(name, path, type, state);
49 FileSystemManager.prototype.openFile = function() {
50 var args = validator_.validateArgs(arguments, [
51 { name: 'path', type: types_.STRING },
52 { name: 'openMode', type: types_.ENUM, values: type_.getValues(FileMode) },
53 { name: 'makeParents', type: types_.BOOLEAN, optional: true }
56 if (!args.has.makeParents) {
57 args.makeParents = true;
61 path: commonFS_.toRealPath(args.path),
62 openMode: args.openMode,
63 makeParents: args.makeParents,
64 id: fileStreamManager.getNextFileHandleId()
68 throw new WebAPIException(
69 WebAPIException.NOT_FOUND_ERR,
70 'Invalid path: ' + args.path
74 var result = native_.callSync('FileSystemManagerOpenFile', data);
75 if (native_.isFailure(result)) {
76 throw native_.getErrorObject(result);
78 return new FileHandle(data.id, args.path, args.openMode);
82 FileSystemManager.prototype.createDirectory = function() {
83 var args = validator_.validateArgs(arguments, [
84 { name: 'path', type: types_.STRING },
85 { name: 'makeParents', type: types_.BOOLEAN, optional: true },
87 name: 'successCallback',
88 type: types_.FUNCTION,
92 { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
95 if (!args.has.makeParents) {
96 args.makeParents = true;
99 var data = { path: commonFS_.toRealPath(args.path), makeParents: args.makeParents };
102 throw new WebAPIException(
103 WebAPIException.INVALID_VALUES_ERR,
104 'Invalid path: ' + args.path
108 var callback = function(result) {
109 if (native_.isFailure(result)) {
110 native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
112 var path = native_.getResultObject(result);
113 native_.callIfPossible(args.successCallback, commonFS_.toVirtualPath(path));
117 var result = native_.call('FileSystemManagerCreateDirectory', data, callback);
118 if (native_.isFailure(result)) {
119 throw native_.getErrorObject(result);
123 FileSystemManager.prototype.deleteFile = function() {
124 var args = validator_.validateArgs(arguments, [
125 { name: 'path', type: types_.STRING },
127 name: 'successCallback',
128 type: types_.FUNCTION,
132 { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
135 var data = { path: commonFS_.toRealPath(args.path) };
138 throw new WebAPIException(
139 WebAPIException.INVALID_VALUES_ERR,
140 'Invalid path: ' + args.path
144 var callback = function(result) {
145 if (native_.isFailure(result)) {
146 native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
148 var path = native_.getResultObject(result);
149 native_.callIfPossible(args.successCallback, commonFS_.toVirtualPath(path));
153 var result = native_.call('FileSystemManagerDeleteFile', data, callback);
154 if (native_.isFailure(result)) {
155 throw native_.getErrorObject(result);
159 FileSystemManager.prototype.deleteDirectory = function() {
160 var args = validator_.validateArgs(arguments, [
161 { name: 'path', type: types_.STRING },
162 { name: 'recursive', type: types_.BOOLEAN, optional: true },
164 name: 'successCallback',
165 type: types_.FUNCTION,
169 { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
172 if (!args.has.recursive) {
173 args.recursive = true;
176 var realPath = commonFS_.toRealPath(args.path);
178 throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Invalid path.');
181 var data = { path: realPath, recursive: args.recursive };
183 var callback = function(result) {
184 if (native_.isFailure(result)) {
185 native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
187 var path = native_.getResultObject(result);
188 native_.callIfPossible(args.successCallback, commonFS_.toVirtualPath(path));
192 var result = native_.call('FileSystemManagerDeleteDirectory', data, callback);
193 if (native_.isFailure(result)) {
194 throw native_.getErrorObject(result);
198 FileSystemManager.prototype.copyFile = function() {
199 var args = validator_.validateArgs(arguments, [
200 { name: 'path', type: types_.STRING },
201 { name: 'destinationPath', type: types_.STRING },
202 { name: 'overwrite', type: types_.BOOLEAN, optional: true },
204 name: 'successCallback',
205 type: types_.FUNCTION,
209 { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
212 if (!args.has.overwrite) {
213 args.overwrite = false;
217 path: commonFS_.toRealPath(args.path),
218 destinationPath: commonFS_.toRealPath(args.destinationPath),
219 overwrite: args.overwrite
223 throw new WebAPIException(
224 WebAPIException.INVALID_VALUES_ERR,
225 'Invalid path: ' + args.path
228 if (!data.destinationPath) {
229 throw new WebAPIException(
230 WebAPIException.INVALID_VALUES_ERR,
231 'Invalid path: ' + args.destinationPath
235 var callback = function(result) {
236 if (native_.isFailure(result)) {
237 native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
239 var path = native_.getResultObject(result);
240 native_.callIfPossible(args.successCallback, commonFS_.toVirtualPath(path));
244 var result = native_.call('FileSystemManagerCopyFile', data, callback);
245 if (native_.isFailure(result)) {
246 throw native_.getErrorObject(result);
250 FileSystemManager.prototype.copyDirectory = function() {
251 var args = validator_.validateArgs(arguments, [
252 { name: 'path', type: types_.STRING },
253 { name: 'destinationPath', type: types_.STRING },
254 { name: 'overwrite', type: types_.BOOLEAN, optional: true },
256 name: 'successCallback',
257 type: types_.FUNCTION,
261 { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
264 var realPath = commonFS_.toRealPath(args.path);
265 var realDestinationPath = commonFS_.toRealPath(args.destinationPath);
266 if (!realPath || !realDestinationPath) {
267 throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Invalid path.');
270 if (!args.has.overwrite) {
271 args.overwrite = false;
276 destinationPath: realDestinationPath,
277 overwrite: args.overwrite
280 var callback = function(result) {
281 if (native_.isFailure(result)) {
282 native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
284 var path = native_.getResultObject(result);
285 native_.callIfPossible(args.successCallback, commonFS_.toVirtualPath(path));
289 var result = native_.call('FileSystemManagerCopyDirectory', data, callback);
290 if (native_.isFailure(result)) {
291 throw native_.getErrorObject(result);
295 FileSystemManager.prototype.moveFile = function() {
296 var args = validator_.validateArgs(arguments, [
297 { name: 'path', type: types_.STRING },
298 { name: 'destinationPath', type: types_.STRING },
299 { name: 'overwrite', type: types_.BOOLEAN, optional: true },
301 name: 'successCallback',
302 type: types_.FUNCTION,
306 { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
309 var realPath = commonFS_.toRealPath(args.path);
310 var realDestinationPath = commonFS_.toRealPath(args.destinationPath);
311 if (!realPath || !realDestinationPath) {
312 throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Invalid path.');
315 if (!args.has.overwrite) {
316 args.overwrite = false;
321 destinationPath: realDestinationPath,
322 overwrite: args.overwrite
325 var callback = function(result) {
326 if (native_.isFailure(result)) {
327 native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
329 var path = native_.getResultObject(result);
330 native_.callIfPossible(args.successCallback, commonFS_.toVirtualPath(path));
334 var result = native_.call('FileSystemManagerMoveFile', data, callback);
335 if (native_.isFailure(result)) {
336 throw native_.getErrorObject(result);
340 FileSystemManager.prototype.moveDirectory = function() {
341 var args = validator_.validateArgs(arguments, [
342 { name: 'path', type: types_.STRING },
343 { name: 'destinationPath', type: types_.STRING },
344 { name: 'overwrite', type: types_.BOOLEAN, optional: true },
346 name: 'successCallback',
347 type: types_.FUNCTION,
351 { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
354 var realPath = commonFS_.toRealPath(args.path);
355 var realDestinationPath = commonFS_.toRealPath(args.destinationPath);
356 if (!realPath || !realDestinationPath) {
357 throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Invalid path.');
360 if (!args.has.overwrite) {
361 args.overwrite = false;
366 destinationPath: realDestinationPath,
367 overwrite: args.overwrite
370 var callback = function(result) {
371 if (native_.isFailure(result)) {
372 native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
374 var path = native_.getResultObject(result);
375 native_.callIfPossible(args.successCallback, commonFS_.toVirtualPath(path));
379 var result = native_.call('FileSystemManagerMoveDirectory', data, callback);
380 if (native_.isFailure(result)) {
381 throw native_.getErrorObject(result);
385 FileSystemManager.prototype.rename = function() {
386 var args = validator_.validateArgs(arguments, [
387 { name: 'path', type: types_.STRING },
388 { name: 'newName', type: types_.STRING },
390 name: 'successCallback',
391 type: types_.FUNCTION,
395 { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
398 if (-1 !== args.newName.indexOf('/') || -1 !== args.newName.indexOf('\x00')) {
399 throw new WebAPIException(
400 WebAPIException.INVALID_VALUES_ERR,
401 'newName contains invalid character.'
405 var realPath = commonFS_.toRealPath(args.path);
407 throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Invalid path.');
410 var data = { path: realPath, newName: args.newName };
412 var callback = function(result) {
413 if (native_.isFailure(result)) {
414 native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
416 var path = native_.getResultObject(result);
417 native_.callIfPossible(args.successCallback, commonFS_.toVirtualPath(path));
421 var result = native_.call('FileSystemManagerRename', data, callback);
422 if (native_.isFailure(result)) {
423 throw native_.getErrorObject(result);
427 function throwIfNotDate(argument, name) {
428 if (argument instanceof Date) {
431 throw new WebAPIException(
432 WebAPIException.TYPE_MISMATCH_ERR,
433 'Argument "' + name + '" in a filter is not of type Date.'
437 FileSystemManager.prototype.listDirectory = function() {
438 var args = validator_.validateArgs(arguments, [
439 { name: 'path', type: types_.STRING },
440 { name: 'successCallback', type: types_.FUNCTION, optional: true },
441 { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true },
442 { name: 'filter', type: types_.DICTIONARY, optional: true, nullable: true }
445 if (!args.has.filter) {
449 if (args.filter.hasOwnProperty('startModified')) {
450 throwIfNotDate(args.filter.startModified, 'startModified');
451 args.filter.startModified = args.filter.startModified.getTime() / 1000;
453 if (args.filter.hasOwnProperty('endModified')) {
454 throwIfNotDate(args.filter.endModified, 'endModified');
455 args.filter.endModified = args.filter.endModified.getTime() / 1000;
457 if (args.filter.hasOwnProperty('startCreated')) {
458 throwIfNotDate(args.filter.startCreated, 'startCreated');
459 args.filter.startCreated = args.filter.startCreated.getTime() / 1000;
461 if (args.filter.hasOwnProperty('endCreated')) {
462 throwIfNotDate(args.filter.endCreated, 'endCreated');
463 args.filter.endCreated = args.filter.endCreated.getTime() / 1000;
466 var data = { path: commonFS_.toRealPath(args.path), filter: args.filter };
469 throw new WebAPIException(
470 WebAPIException.INVALID_VALUES_ERR,
471 'Invalid path: ' + args.path
475 var callback = function(result) {
476 if (native_.isFailure(result)) {
477 native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
479 var obj = native_.getResultObject(result);
480 var names = obj.names;
481 if (args.filter.hasOwnProperty('name')) {
482 var regex_name = stringToRegex(args.filter.name);
483 for (var i = names.length - 1; i >= 0; i--) {
484 if (!regex_name.test(names[i])) {
489 native_.callIfPossible(
490 args.successCallback,
492 commonFS_.toVirtualPath(obj.path)
497 var result = native_.call('FileSystemManagerListDirectory', data, callback);
498 if (native_.isFailure(result)) {
499 throw native_.getErrorObject(result);
503 FileSystemManager.prototype.toURI = function() {
504 var args = validator_.validateArgs(arguments, [
505 { name: 'path', type: types_.STRING }
508 // The toRealPath function will convert any string to absolute path, if possible.
509 // The function returns undefined for path, which starts with not-existing
511 var realPath = commonFS_.toRealPath(args.path);
514 throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Invalid path.');
517 return 'file://' + realPath;
520 FileSystemManager.prototype.isFile = function() {
521 var args = validator_.validateArgs(arguments, [
522 { name: 'path', type: types_.STRING }
524 // The toRealPath function will convert any string to absolute path, if possible.
525 // The function returns undefined for path, which starts with not-existing
527 var realPath = commonFS_.toRealPath(args.path);
530 throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Invalid path.');
533 var data = { path: realPath };
535 var result = native_.callSync('FileSystemManagerIsFile', data);
536 if (native_.isFailure(result)) {
537 throw native_.getErrorObject(result);
539 return native_.getResultObject(result);
543 FileSystemManager.prototype.isDirectory = function() {
544 var args = validator_.validateArgs(arguments, [
545 { name: 'path', type: types_.STRING }
547 // The toRealPath function will convert any string to absolute path, if possible.
548 // The function returns undefined for path, which starts with not-existing
550 var realPath = commonFS_.toRealPath(args.path);
553 throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Invalid path.');
556 var data = { path: realPath };
558 var result = native_.callSync('FileSystemManagerIsDirectory', data);
559 if (native_.isFailure(result)) {
560 throw native_.getErrorObject(result);
562 return native_.getResultObject(result);
566 FileSystemManager.prototype.pathExists = function() {
567 var args = validator_.validateArgs(arguments, [
568 { name: 'path', type: types_.STRING }
570 // The toRealPath function will convert any string to absolute path, if possible.
571 // The function returns undefined for path, which starts with not-existing
573 var realPath = commonFS_.toRealPath(args.path);
576 throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Invalid path.');
578 var data = { path: realPath };
580 var result = native_.callSync('FileSystemManagerPathExists', data);
581 if (native_.isFailure(result)) {
582 throw native_.getErrorObject(result);
584 return native_.getResultObject(result);
588 FileSystemManager.prototype.getDirName = function() {
589 var args = validator_.validateArgs(arguments, [
590 { name: 'path', type: types_.STRING }
592 var path = args.path;
594 path = commonFS_.mergeMultipleSlashes(path);
595 if (path.startsWith('file://')) {
596 path = path.substring('file://'.length - 1, path.length - 1);
599 if (path.startsWith('/') && 0 === path.lastIndexOf('/')) {
600 // handle the "/" and "/file.ext"
602 } else if (path.endsWith('/')) {
604 path = path.substring(0, path.length - 1);
607 var index = path.lastIndexOf('/');
609 path = path.substring(0, index); // cut the directory/file the path points to
615 privUtils_.deprecationWarn(
616 'FileSystemManager.resolve() is deprecated since Tizen 5.0. ' +
617 'Use FileHandle and FileSystemManager interfaces instead.',
621 var args = validator_.validateArgs(arguments, [
622 { name: 'location', type: types_.STRING },
623 { name: 'onsuccess', type: types_.FUNCTION },
624 { name: 'onerror', type: types_.FUNCTION, optional: true, nullable: true },
628 values: Object.keys(FileMode),
634 if (!args.has.mode) {
636 } else if ('rwo' == args.mode) {
637 throw new WebAPIException(
638 WebAPIException.INVALID_VALUES_ERR,
639 'rwo mode was introduced in version 5.0 and is not supported in earlier ' +
644 // resolving a path on unmounted storage should result in exception
645 var storage = commonFS_.getStorage(args.location.split('/')[0]);
646 if (storage && FileSystemStorageState.MOUNTED !== storage.state) {
647 setTimeout(function() {
648 native_.callIfPossible(
651 WebAPIException.NOT_FOUND_ERR,
652 'Storage is not mounted.'
659 // Validation against '.' and '..' directories used in path - not allowed
660 var result = commonFS_.checkPathWithoutDots(args.location);
662 // path contains dots - it is not allowed - return InvalidValuesError
663 setTimeout(function() {
664 native_.callIfPossible(
667 WebAPIException.INVALID_VALUES_ERR,
668 'Path contains \'.\' or \'..\' - it is not allowed.'
675 var _realPath = commonFS_.toRealPath(args.location);
678 // invalid real path means that virtual root does not exist
679 setTimeout(function() {
680 native_.callIfPossible(
682 new WebAPIException(WebAPIException.NOT_FOUND_ERR, 'Invalid path.')
688 var _isLocationAllowed = commonFS_.isLocationAllowed(_realPath);
690 if (args.mode !== 'r' && !_isLocationAllowed) {
691 setTimeout(function() {
692 native_.callIfPossible(
695 WebAPIException.INVALID_VALUES_ERR,
696 'Provided arguments are not valid.'
703 var data = { location: _realPath };
705 var callback = function(result) {
706 if (native_.isFailure(result)) {
707 native_.callIfPossible(args.onerror, native_.getErrorObject(result));
711 var aStatObj = native_.getResultObject(result);
712 var _result = commonFS_.getFileInfo(aStatObj, false, args.mode);
713 if (_result.readOnly && args.mode !== 'r') {
714 native_.callIfPossible(
716 new WebAPIException(WebAPIException.IO_ERR, 'File is read-only.')
719 native_.callIfPossible(args.onsuccess, new File(_result));
723 var ret = native_.call('FileStat', data, callback);
724 if (native_.isFailure(ret)) {
725 throw native_.getErrorObject(ret);
729 FileSystemManager.prototype.resolve = function() {
730 resolve.apply(this, arguments);
733 function getStorage() {
734 xwalk.utils.checkPrivilegeAccess(xwalk.utils.privilege.FILESYSTEM_READ);
735 var args = validator_.validateArgs(arguments, [
736 { name: 'label', type: types_.STRING },
737 { name: 'onsuccess', type: types_.FUNCTION },
738 { name: 'onerror', type: types_.FUNCTION, optional: true, nullable: true }
741 setTimeout(function() {
742 var storage = commonFS_.getStorage(args.label);
745 native_.callIfPossible(
747 new WebAPIException(WebAPIException.NOT_FOUND_ERR, 'Storage not found.')
750 native_.callIfPossible(args.onsuccess, new FileSystemStorage(storage));
755 FileSystemManager.prototype.getStorage = function() {
756 getStorage.apply(this, arguments);
759 function listStorages() {
760 xwalk.utils.checkPrivilegeAccess(xwalk.utils.privilege.FILESYSTEM_READ);
761 var args = validator_.validateArgs(arguments, [
762 { name: 'onsuccess', type: types_.FUNCTION },
763 { name: 'onerror', type: types_.FUNCTION, optional: true, nullable: true }
766 setTimeout(function() {
768 var cache = commonFS_.getAllStorages();
769 for (var i = 0; i < cache.length; ++i) {
770 storages.push(new FileSystemStorage(cache[i]));
773 native_.callIfPossible(args.onsuccess, storages);
777 FileSystemManager.prototype.listStorages = function() {
778 listStorages.apply(this, arguments);
784 function nextCallbackId() {
788 function _StorageStateChangeListener(result) {
789 commonFS_.clearCache();
790 var storage = new FileSystemStorage(result);
791 for (var id in callbacks) {
792 native_.callIfPossible(callbacks[id], storage);
796 function addStorageStateChangeListener() {
797 var args = validator_.validateArgs(arguments, [
798 { name: 'onsuccess', type: types_.FUNCTION },
799 { name: 'onerror', type: types_.FUNCTION, optional: true, nullable: true }
802 var register = false;
803 if (type_.isEmptyObject(callbacks)) {
807 var id = nextCallbackId();
808 callbacks[id] = args.onsuccess;
811 native_.addListener('StorageStateChangeListener', _StorageStateChangeListener);
812 var result = native_.callSync(
813 'FileSystemManagerAddStorageStateChangeListener',
817 if (native_.isFailure(result)) {
818 throw native_.getErrorObject(result);
825 FileSystemManager.prototype.addStorageStateChangeListener = function() {
826 return addStorageStateChangeListener.apply(this, arguments);
829 function removeStorageStateChangeListener() {
830 var args = validator_.validateArgs(arguments, [
831 { name: 'watchId', type: types_.LONG }
834 if (!arguments.length) {
835 throw new WebAPIException(WebAPIException.TYPE_MISMATCH_ERR, 'Missing watchId');
837 var id = args.watchId;
839 if (type_.isNullOrUndefined(callbacks[id])) {
843 delete callbacks[id];
845 if (type_.isEmptyObject(callbacks)) {
846 var result = native_.callSync(
847 'FileSystemManagerRemoveStorageStateChangeListener',
850 if (native_.isFailure(result)) {
851 throw native_.getErrorObject(result);
856 FileSystemManager.prototype.removeStorageStateChangeListener = function() {
857 removeStorageStateChangeListener.apply(this, arguments);
860 exports = new FileSystemManager();