Merge pull request #6 from humphd/utf8

Add fs.readFile, fs.writeFile with tests
This commit is contained in:
Alan K 2013-11-11 20:01:30 -08:00
commit c590f930e5
13 changed files with 5412 additions and 205 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
node_modules
*~

View File

@ -97,12 +97,46 @@ Write bytes from `buffer` to the file specified by `fd`, where `offset` and `len
The callback gets `(error, nbytes)`, where `nbytes` is the number of bytes written.
#### fs.writeFile(filename, data, [options], callback)
Asynchronously writes data to a file. `data` can be a string or a buffer, in which case any encoding option is ignored. The `options` argument is optional, and can take the form `"utf8"` (i.e., an encoding) or be an object literal: `{ encoding: "utf8", flag: "w" }`. If no encoding is specified, and `data` is a string, the encoding defaults to `'utf8'`. The callback gets `(error)`.
```javascript
// Write UTF8 text file
fs.writeFile('/myfile.txt', "...data...", function (err) {
if (err) throw err;
});
// Write binary file
fs.writeFile('/myfile', buffer, function (err) {
if (err) throw err;
});
```
#### fs.read(fd, buffer, offset, length, position, callback)
Read bytes from the file specified by `fd` into `buffer`, where `offset` and `length` describe the part of the buffer to be used. The `position` refers to the offset from the beginning of the file where this data should be read. If `position` is `null`, the data will be written at the current position. See pread(2).
The callback gets `(error, nbytes)`, where `nbytes` is the number of bytes read.
#### fs.readFile(filename, [options], callback)
Asynchronously reads the entire contents of a file. The `options` argument is optional, and can take the form `"utf8"` (i.e., an encoding) or be an object literal: `{ encoding: "utf8", flag: "r" }`. If no encoding is specified, the raw binary buffer is returned on the callback. The callback gets `(error, data)`, where data is the contents of the file.
```javascript
// Read UTF8 text file
fs.readFile('/myfile.txt', 'utf8', function (err, data) {
if (err) throw err;
console.log(data);
});
// Read binary file
fs.readFile('/myfile.txt', function (err, data) {
if (err) throw err;
console.log(data);
});
```
#### fs.lseek(fd, offset, whence, callback)
Asynchronous lseek(2), where `whence` can be `SET`, `CUR`, or `END`. Callback gets `(error, pos)`, where `pos` is the resulting offset, in bytes, from the beginning of the file.

2712
dist/idbfs.js vendored

File diff suppressed because one or more lines are too long

7
dist/idbfs.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -16,6 +16,11 @@ module.exports = function(grunt) {
}
},
jshint: {
// Don't bother with src/path.js
all: ['gruntfile.js', 'src/constants.js', 'src/error.js', 'src/fs.js', 'srs/shared.js']
},
requirejs: {
develop: {
options: {
@ -40,9 +45,11 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-requirejs');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.registerTask('develop', ['clean', 'requirejs']);
grunt.registerTask('release', ['develop', 'uglify']);
grunt.registerTask('check', ['jshint']);
grunt.registerTask('default', ['develop']);
};

43
lib/encoding-indexes.js Normal file

File diff suppressed because one or more lines are too long

2318
lib/encoding.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -10,6 +10,7 @@
"grunt-contrib-compress": "~0.4.1",
"grunt-contrib-connect": "~0.1.2",
"grunt-contrib-jasmine": "~0.3.3",
"grunt-contrib-concat": "~0.1.3"
"grunt-contrib-concat": "~0.1.3",
"grunt-contrib-jshint": "~0.7.1"
}
}

View File

@ -48,7 +48,7 @@ define(function(require) {
FS_READY: 'READY',
FS_PENDING: 'PENDING',
FS_ERROR: 'ERROR',
FS_ERROR: 'ERROR'
};
});

View File

@ -16,84 +16,84 @@ define(function(require) {
function EExists(message){
this.message = message || '';
};
}
EExists.prototype = new Error();
EExists.prototype.name = "EExists";
EExists.prototype.constructor = EExists;
function EIsDirectory(message){
this.message = message || '';
};
}
EIsDirectory.prototype = new Error();
EIsDirectory.prototype.name = "EIsDirectory";
EIsDirectory.prototype.constructor = EIsDirectory;
function ENoEntry(message){
this.message = message || '';
};
}
ENoEntry.prototype = new Error();
ENoEntry.prototype.name = "ENoEntry";
ENoEntry.prototype.constructor = ENoEntry;
function EBusy(message){
this.message = message || '';
};
}
EBusy.prototype = new Error();
EBusy.prototype.name = "EBusy";
EBusy.prototype.constructor = EBusy;
function ENotEmpty(message){
this.message = message || '';
};
}
ENotEmpty.prototype = new Error();
ENotEmpty.prototype.name = "ENotEmpty";
ENotEmpty.prototype.constructor = ENotEmpty;
function ENotDirectory(message){
this.message = message || '';
};
}
ENotDirectory.prototype = new Error();
ENotDirectory.prototype.name = "ENotDirectory";
ENotDirectory.prototype.constructor = ENotDirectory;
function EBadFileDescriptor(message){
this.message = message || '';
};
}
EBadFileDescriptor.prototype = new Error();
EBadFileDescriptor.prototype.name = "EBadFileDescriptor";
EBadFileDescriptor.prototype.constructor = EBadFileDescriptor;
function ENotImplemented(message){
this.message = message || '';
};
}
ENotImplemented.prototype = new Error();
ENotImplemented.prototype.name = "ENotImplemented";
ENotImplemented.prototype.constructor = ENotImplemented;
function ENotMounted(message){
this.message = message || '';
};
}
ENotMounted.prototype = new Error();
ENotMounted.prototype.name = "ENotMounted";
ENotMounted.prototype.constructor = ENotMounted;
function EInvalid(message){
this.message = message || '';
};
}
EInvalid.prototype = new Error();
EInvalid.prototype.name = "EInvalid";
EInvalid.prototype.constructor = EInvalid;
function EIO(message){
this.message = message || '';
};
}
EIO.prototype = new Error();
EIO.prototype.name = "EIO";
EIO.prototype.constructor = EIO;
function EFileSystemError(message){
this.message = message || '';
};
}
EFileSystemError.prototype = new Error();
EFileSystemError.prototype.name = "EFileSystemError";
EFileSystemError.prototype.constructor = EFileSystemError;
@ -109,7 +109,7 @@ define(function(require) {
ENotImplemented: ENotImplemented,
ENotMounted: ENotMounted,
EInvalid: EInvalid,
EIO: EIO,
EIO: EIO
};
});

305
src/fs.js
View File

@ -5,6 +5,11 @@ define(function(require) {
var _ = require('lodash');
var when = require('when');
// TextEncoder and TextDecoder will either already be present, or use this shim.
// Because of the way the spec is defined, we need to get them off the global.
require('encoding-indexes');
require('encoding');
var normalize = require('src/path').normalize;
var dirname = require('src/path').dirname;
var basename = require('src/path').basename;
@ -53,7 +58,7 @@ define(function(require) {
function DirectoryEntry(id, type) {
this.id = id;
this.type = type || MODE_FILE;
};
}
/*
* OpenFileDescription
@ -63,7 +68,7 @@ define(function(require) {
this.id = id;
this.flags = flags;
this.position = position;
};
}
/*
* Node
@ -72,7 +77,7 @@ define(function(require) {
function Node(id, mode, size, atime, ctime, mtime, flags, xattrs, nlinks, version) {
var now = Date.now();
this.id = id || hash(guid()),
this.id = id || hash(guid());
this.mode = mode || MODE_FILE; // node type (file, directory, etc)
this.size = size || 0; // size (bytes for files, entries for directories)
this.atime = atime || now; // access time
@ -85,7 +90,7 @@ define(function(require) {
this.blksize = undefined; // block size
this.nblocks = 1; // blocks count
this.data = hash(guid()); // id for data object
};
}
/*
* Stats
@ -100,7 +105,7 @@ define(function(require) {
this.mtime = fileNode.mtime;
this.ctime = fileNode.ctime;
this.type = fileNode.mode;
};
}
/*
* find_node
@ -125,7 +130,7 @@ define(function(require) {
} else {
callback(undefined, rootDirectoryNode);
}
};
}
read_object(objectStore, ROOT_NODE_ID, check_root_directory_node);
} else {
@ -139,7 +144,7 @@ define(function(require) {
} else {
read_object(objectStore, parentDirectoryNode.data, get_node_id_from_parent_directory_data);
}
};
}
// in: parent directory data
// out: searched node id
@ -154,11 +159,11 @@ define(function(require) {
read_object(objectStore, nodeId, callback);
}
}
};
}
find_node(objectStore, parentPath, read_parent_directory_data);
}
};
}
/*
* read_object
@ -177,7 +182,7 @@ define(function(require) {
} catch(error) {
callback(new EIO(error.message));
}
};
}
/*
* write_object
@ -196,7 +201,7 @@ define(function(require) {
} catch(error) {
callback(new EIO(error.message));
}
};
}
/*
* delete_object
@ -211,7 +216,7 @@ define(function(require) {
deleteRequest.onerror = function(error) {
callback(error);
};
};
}
/*
* make_root_directory
@ -232,7 +237,7 @@ define(function(require) {
directoryNode.nlinks += 1;
write_object(objectStore, directoryNode, directoryNode.id, write_directory_data);
}
};
}
function write_directory_data(error) {
if(error) {
@ -241,10 +246,10 @@ define(function(require) {
directoryData = {};
write_object(objectStore, directoryData, directoryNode.data, callback);
}
};
}
find_node(objectStore, ROOT_DIRECTORY_NAME, write_directory_node);
};
}
/*
* make_directory
@ -277,7 +282,7 @@ define(function(require) {
parentDirectoryNode = result;
read_object(objectStore, parentDirectoryNode.data, write_directory_node);
}
};
}
function write_directory_node(error, result) {
if(error) {
@ -288,7 +293,7 @@ define(function(require) {
directoryNode.nlinks += 1;
write_object(objectStore, directoryNode, directoryNode.id, write_directory_data);
}
};
}
function write_directory_data(error) {
if(error) {
@ -297,7 +302,7 @@ define(function(require) {
directoryData = {};
write_object(objectStore, directoryData, directoryNode.data, update_parent_directory_data);
}
};
}
function update_parent_directory_data(error) {
if(error) {
@ -309,7 +314,7 @@ define(function(require) {
}
find_node(objectStore, path, check_if_directory_exists);
};
}
/*
* remove_directory
@ -349,7 +354,7 @@ define(function(require) {
find_node(objectStore, parentPath, read_parent_directory_data);
}
}
};
}
function read_parent_directory_data(error, result) {
if(error) {
@ -358,7 +363,7 @@ define(function(require) {
parentDirectoryNode = result;
read_object(objectStore, parentDirectoryNode.data, remove_directory_entry_from_parent_directory_node);
}
};
}
function remove_directory_entry_from_parent_directory_node(error, result) {
if(error) {
@ -368,7 +373,7 @@ define(function(require) {
delete parentDirectoryData[name];
write_object(objectStore, parentDirectoryData, parentDirectoryNode.data, remove_directory_node);
}
};
}
function remove_directory_node(error) {
if(error) {
@ -376,7 +381,7 @@ define(function(require) {
} else {
delete_object(objectStore, directoryNode.id, remove_directory_data);
}
};
}
function remove_directory_data(error) {
if(error) {
@ -384,10 +389,10 @@ define(function(require) {
} else {
delete_object(objectStore, directoryNode.data, callback);
}
};
}
find_node(objectStore, path, check_if_directory_exists);
};
}
function open_file(fs, objectStore, path, flags, callback) {
path = normalize(path);
@ -402,7 +407,7 @@ define(function(require) {
if(ROOT_DIRECTORY_NAME == name) {
if(_(flags).contains(O_WRITE)) {
callback(new EIsDirectory('the named file is a directory and O_WRITE is set'))
callback(new EIsDirectory('the named file is a directory and O_WRITE is set'));
} else {
find_node(objectStore, path, set_file_node);
}
@ -417,7 +422,7 @@ define(function(require) {
directoryNode = result;
read_object(objectStore, directoryNode.data, check_if_file_exists);
}
};
}
function check_if_file_exists(error, result) {
if(error) {
@ -426,11 +431,11 @@ define(function(require) {
directoryData = result;
if(_(directoryData).has(name)) {
if(_(flags).contains(O_EXCLUSIVE)) {
callback(new ENoEntry('O_CREATE and O_EXCLUSIVE are set, and the named file exists'))
callback(new ENoEntry('O_CREATE and O_EXCLUSIVE are set, and the named file exists'));
} else {
directoryEntry = directoryData[name];
if(directoryEntry.type == MODE_DIRECTORY && _(flags).contains(O_WRITE)) {
callback(new EIsDirectory('the named file is a directory and O_WRITE is set'))
callback(new EIsDirectory('the named file is a directory and O_WRITE is set'));
} else {
read_object(objectStore, directoryEntry.id, set_file_node);
}
@ -443,7 +448,7 @@ define(function(require) {
}
}
}
};
}
function set_file_node(error, result) {
if(error) {
@ -452,13 +457,13 @@ define(function(require) {
fileNode = result;
callback(undefined, fileNode);
}
};
}
function write_file_node() {
fileNode = new Node(undefined, MODE_FILE);
fileNode.nlinks += 1;
write_object(objectStore, fileNode, fileNode.id, write_file_data);
};
}
function write_file_data(error) {
if(error) {
@ -467,7 +472,7 @@ define(function(require) {
fileData = new Uint8Array(0);
write_object(objectStore, fileData, fileNode.data, update_directory_data);
}
};
}
function update_directory_data(error) {
if(error) {
@ -476,7 +481,7 @@ define(function(require) {
directoryData[name] = new DirectoryEntry(fileNode.id, MODE_FILE);
write_object(objectStore, directoryData, directoryNode.data, handle_update_result);
}
};
}
function handle_update_result(error) {
if(error) {
@ -484,8 +489,8 @@ define(function(require) {
} else {
callback(undefined, fileNode);
}
};
};
}
}
function write_data(objectStore, ofd, buffer, offset, length, position, callback) {
var fileNode;
@ -500,7 +505,7 @@ define(function(require) {
fileNode = result;
read_object(objectStore, fileNode.data, update_file_data);
}
};
}
function update_file_data(error, result) {
if(error) {
@ -524,7 +529,7 @@ define(function(require) {
write_object(objectStore, newData, fileNode.data, update_file_node);
}
};
}
function update_file_node(error) {
if(error) {
@ -532,7 +537,7 @@ define(function(require) {
} else {
write_object(objectStore, fileNode, fileNode.id, return_nbytes);
}
};
}
function return_nbytes(error) {
if(error) {
@ -540,8 +545,8 @@ define(function(require) {
} else {
callback(undefined, length);
}
};
};
}
}
function read_data(objectStore, ofd, buffer, offset, length, position, callback) {
var fileNode;
@ -556,7 +561,7 @@ define(function(require) {
fileNode = result;
read_object(objectStore, fileNode.data, handle_file_data);
}
};
}
function handle_file_data(error, result) {
if(error) {
@ -572,8 +577,8 @@ define(function(require) {
}
callback(undefined, length);
}
};
};
}
}
function stat_file(objectStore, path, callback) {
path = normalize(path);
@ -587,8 +592,8 @@ define(function(require) {
} else {
callback(undefined, result);
}
};
};
}
}
function fstat_file(objectStore, ofd, callback) {
read_object(objectStore, ofd.id, check_file);
@ -599,8 +604,8 @@ define(function(require) {
} else {
callback(undefined, result);
}
};
};
}
}
function link_node(objectStore, oldpath, newpath, callback) {
oldpath = normalize(oldpath);
@ -626,7 +631,7 @@ define(function(require) {
oldDirectoryNode = result;
read_object(objectStore, oldDirectoryNode.data, check_if_old_file_exists);
}
};
}
function check_if_old_file_exists(error, result) {
if(error) {
@ -639,7 +644,7 @@ define(function(require) {
find_node(objectStore, newParentPath, read_new_directory_data);
}
}
};
}
function read_new_directory_data(error, result) {
if(error) {
@ -648,7 +653,7 @@ define(function(require) {
newDirectoryNode = result;
read_object(objectStore, newDirectoryNode.data, check_if_new_file_exists);
}
};
}
function check_if_new_file_exists(error, result) {
if(error) {
@ -662,7 +667,7 @@ define(function(require) {
write_object(objectStore, newDirectoryData, newDirectoryNode.data, read_directory_entry);
}
}
};
}
function read_directory_entry(error, result) {
if(error) {
@ -677,11 +682,11 @@ define(function(require) {
callback(error);
} else {
fileNode = result;
fileNode.nlinks += 1
fileNode.nlinks += 1;
write_object(objectStore, fileNode, fileNode.id, callback);
}
};
};
}
}
function unlink_node(objectStore, path, callback) {
path = normalize(path);
@ -701,7 +706,7 @@ define(function(require) {
directoryNode = result;
read_object(objectStore, directoryNode.data, check_if_file_exists);
}
};
}
function check_if_file_exists(error, result) {
if(error) {
@ -714,7 +719,7 @@ define(function(require) {
read_object(objectStore, directoryData[name].id, update_file_node);
}
}
};
}
function update_file_node(error, result) {
if(error) {
@ -728,7 +733,7 @@ define(function(require) {
write_object(objectStore, fileNode, fileNode.id, update_directory_data);
}
}
};
}
function delete_file_data(error) {
if(error) {
@ -736,7 +741,7 @@ define(function(require) {
} else {
delete_object(objectStore, fileNode.data, update_directory_data);
}
};
}
function update_directory_data(error) {
if(error) {
@ -746,7 +751,7 @@ define(function(require) {
write_object(objectStore, directoryData, directoryNode.data, callback);
}
}
};
}
function read_directory(objectStore, path, callback) {
path = normalize(path);
@ -764,7 +769,7 @@ define(function(require) {
directoryNode = result;
read_object(objectStore, directoryNode.data, handle_directory_data);
}
};
}
function handle_directory_data(error, result) {
if(error) {
@ -774,8 +779,16 @@ define(function(require) {
var files = Object.keys(directoryData);
callback(undefined, files);
}
};
};
}
}
function validate_flags(flags) {
if(!_(O_FLAGS).has(flags)) {
return null;
} else {
return O_FLAGS[flags];
}
}
/*
* FileSystem
@ -818,7 +831,7 @@ define(function(require) {
that.readyState = FS_READY;
deferred.resolve();
}
};
}
if(format) {
var clearRequest = files.clear();
@ -845,7 +858,7 @@ define(function(require) {
this.nextDescriptor = nextDescriptor;
this.openFiles = openFiles;
this.name = name;
};
}
FileSystem.prototype._allocate_descriptor = function _allocate_descriptor(openFileDescription) {
var fd = this.nextDescriptor ++;
this.openFiles[fd] = openFileDescription;
@ -877,12 +890,11 @@ define(function(require) {
var fd = that._allocate_descriptor(openFileDescription);
deferred.resolve(fd);
}
};
}
if(!_(O_FLAGS).has(flags)) {
flags = validate_flags(flags);
if(!flags) {
deferred.reject(new EInvalid('flags is not valid'));
} else {
flags = O_FLAGS[flags];
}
open_file(this, files, path, flags, check_result);
@ -934,7 +946,7 @@ define(function(require) {
} else {
deferred.resolve();
}
};
}
make_directory(files, path, check_result);
deferred.promise.then(
@ -966,7 +978,7 @@ define(function(require) {
} else {
deferred.resolve();
}
};
}
remove_directory(files, path, check_result);
deferred.promise.then(
@ -999,7 +1011,7 @@ define(function(require) {
var stats = new Stats(result, that.name);
deferred.resolve(stats);
}
};
}
stat_file(files, path, check_result);
deferred.promise.then(
@ -1032,7 +1044,7 @@ define(function(require) {
var stats = new Stats(result, that.name);
deferred.resolve(stats);
}
};
}
var ofd = that.openFiles[fd];
@ -1071,7 +1083,7 @@ define(function(require) {
} else {
deferred.resolve();
}
};
}
link_node(files, oldpath, newpath, check_result);
@ -1104,7 +1116,7 @@ define(function(require) {
} else {
deferred.resolve();
}
};
}
unlink_node(files, path, check_result);
@ -1140,7 +1152,7 @@ define(function(require) {
} else {
deferred.resolve(nbytes);
}
};
}
var ofd = that.openFiles[fd];
@ -1166,6 +1178,79 @@ define(function(require) {
}
);
};
FileSystem.prototype.readFile = function readFile(path, options, callback) {
var that = this;
this.promise.then(
function() {
var deferred = when.defer();
var transaction = that.db.transaction([FILE_STORE_NAME], IDB_RO);
var files = transaction.objectStore(FILE_STORE_NAME);
if(!options) {
options = { encoding: null, flag: 'r' };
} else if(typeof options === "function") {
callback = options;
options = { encoding: null, flag: 'r' };
} else if(typeof options === "string") {
options = { encoding: options, flag: 'r' };
}
var flags = validate_flags(options.flag || 'r');
if(!flags) {
deferred.reject(new EInvalid('flags is not valid'));
}
open_file(this, files, path, flags, function(err, fileNode) {
if(err) {
// TODO: abort transaction?
return deferred.reject(err);
}
var ofd = new OpenFileDescription(fileNode.id, flags, 0);
var fd = that._allocate_descriptor(ofd);
fstat_file(files, ofd, function(err2, fstatResult) {
if(err2) {
// TODO: abort transaction?
return deferred.reject(err2);
}
var stats = new Stats(fstatResult, that.name);
var size = stats.size;
var buffer = new Uint8Array(size);
read_data(files, ofd, buffer, 0, size, 0, function(err3, nbytes) {
if(err3) {
// TODO: abort transaction?
return deferred.reject(err3);
}
that._release_descriptor(fd);
var data;
if(options.encoding === 'utf8') {
data = new TextDecoder('utf-8').decode(buffer);
} else {
data = buffer;
}
deferred.resolve(data);
});
});
});
deferred.promise.then(
function(result) {
callback(undefined, result);
},
function(error) {
callback(error);
}
);
},
function() {
callback(new EFileSystemError('unknown error'));
}
);
};
FileSystem.prototype.write = function write(fd, buffer, offset, length, position, callback) {
var that = this;
this.promise.then(
@ -1183,7 +1268,7 @@ define(function(require) {
} else {
deferred.resolve(nbytes);
}
};
}
var ofd = that.openFiles[fd];
@ -1211,6 +1296,64 @@ define(function(require) {
}
);
};
FileSystem.prototype.writeFile = function writeFile(path, data, options, callback) {
var that = this;
this.promise.then(
function() {
var deferred = when.defer();
var transaction = that.db.transaction([FILE_STORE_NAME], IDB_RW);
var files = transaction.objectStore(FILE_STORE_NAME);
if(!options) {
options = { encoding: 'utf8', flag: 'w' };
} else if(typeof options === "function") {
callback = options;
options = { encoding: 'utf8', flag: 'w' };
} else if(typeof options === "string") {
options = { encoding: options, flag: 'w' };
}
var flags = validate_flags(options.flag || 'w');
if(!flags) {
deferred.reject(new EInvalid('flags is not valid'));
}
if(typeof data === "string" && options.encoding === 'utf8') {
data = new TextEncoder('utf-8').encode(data);
}
open_file(this, files, path, flags, function(err, fileNode) {
if(err) {
// TODO: abort transaction?
return deferred.reject(err);
}
var ofd = new OpenFileDescription(fileNode.id, flags, 0);
var fd = that._allocate_descriptor(ofd);
write_data(files, ofd, data, 0, data.length, 0, function(err2, nbytes) {
if(err2) {
// TODO: abort transaction?
return deferred.reject(err2);
}
that._release_descriptor(fd);
deferred.resolve();
});
});
deferred.promise.then(
function() {
callback(undefined);
},
function(error) {
callback(error);
}
);
},
function() {
callback(new EFileSystemError('unknown error'));
}
);
};
FileSystem.prototype.getxattr = function getxattr(path, name, callback) {
};
@ -1229,7 +1372,7 @@ define(function(require) {
} else {
deferred.resolve(offset);
}
};
}
var ofd = that.openFiles[fd];
@ -1266,7 +1409,7 @@ define(function(require) {
deferred.resolve(ofd.position);
}
}
};
}
fstat_file(files, ofd, update_descriptor_position);
} else {
@ -1302,7 +1445,7 @@ define(function(require) {
} else {
deferred.resolve(files);
}
};
}
read_directory(files, path, check_result);
@ -1347,7 +1490,7 @@ define(function(require) {
return {
FileSystem: FileSystem,
FileSystem: FileSystem
};
});

View File

@ -7,18 +7,18 @@ define(function(require) {
var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
return v.toString(16);
}).toUpperCase();
};
}
function hash(string) {
return Crypto.SHA256(string).toString(Crypto.enc.hex);
};
}
function nop() {};
function nop() {}
return {
guid: guid,
hash: hash,
nop: nop,
nop: nop
};
});

View File

@ -714,6 +714,153 @@ describe('fs.write', function() {
});
});
describe('fs.writeFile, fs.readFile', function() {
beforeEach(function() {
this.db_name = mk_db_name();
this.fs = new IDBFS.FileSystem(this.db_name, 'FORMAT');
});
afterEach(function() {
indexedDB.deleteDatabase(this.db_name);
delete this.fs;
});
it('should be a function', function() {
expect(typeof this.fs.writeFile).toEqual('function');
expect(typeof this.fs.readFile).toEqual('function');
});
it('should error when path is wrong to readFile', function() {
var complete = false;
var _error, _result;
var that = this;
var contents = "This is a file.";
that.fs.readFile('/no-such-file', 'utf8', function(error, data) {
_error = error;
_result = data;
complete = true;
});
waitsFor(function() {
return complete;
}, 'test to complete', DEFAULT_TIMEOUT);
runs(function() {
expect(_error).toBeDefined();
expect(_result).not.toBeDefined();
});
});
it('should write, read a utf8 file without specifying utf8 in writeFile', function() {
var complete = false;
var _error, _result;
var that = this;
var contents = "This is a file.";
that.fs.writeFile('/myfile', contents, function(error) {
if(error) throw error;
that.fs.readFile('/myfile', 'utf8', function(error2, data) {
if(error2) throw error2;
_result = data;
complete = true;
});
});
waitsFor(function() {
return complete;
}, 'test to complete', DEFAULT_TIMEOUT);
runs(function() {
expect(_error).not.toBeDefined();
expect(_result).toEqual(contents);
});
});
it('should write, read a utf8 file with "utf8" option to writeFile', function() {
var complete = false;
var _error, _result;
var that = this;
var contents = "This is a file.";
that.fs.writeFile('/myfile', contents, 'utf8', function(error) {
if(error) throw error;
that.fs.readFile('/myfile', 'utf8', function(error2, data) {
if(error2) throw error2;
_result = data;
complete = true;
});
});
waitsFor(function() {
return complete;
}, 'test to complete', DEFAULT_TIMEOUT);
runs(function() {
expect(_error).not.toBeDefined();
expect(_result).toEqual(contents);
});
});
it('should write, read a utf8 file with {encoding: "utf8"} option to writeFile', function() {
var complete = false;
var _error, _result;
var that = this;
var contents = "This is a file.";
that.fs.writeFile('/myfile', contents, { encoding: 'utf8' }, function(error) {
if(error) throw error;
that.fs.readFile('/myfile', 'utf8', function(error2, data) {
if(error2) throw error2;
_result = data;
complete = true;
});
});
waitsFor(function() {
return complete;
}, 'test to complete', DEFAULT_TIMEOUT);
runs(function() {
expect(_error).not.toBeDefined();
expect(_result).toEqual(contents);
});
});
it('should write, read a binary file', function() {
var complete = false;
var _error, _result;
var that = this;
// String and utf8 binary encoded versions of the same thing:
var contents = "This is a file.";
var binary = new Uint8Array([84, 104, 105, 115, 32, 105, 115, 32, 97, 32, 102, 105, 108, 101, 46]);
that.fs.writeFile('/myfile', binary, function(error) {
if(error) throw error;
that.fs.readFile('/myfile', function(error2, data) {
if(error2) throw error2;
_result = data;
complete = true;
});
});
waitsFor(function() {
return complete;
}, 'test to complete', DEFAULT_TIMEOUT);
runs(function() {
expect(_error).not.toBeDefined();
expect(_result).toEqual(binary);
});
});
});
describe('fs.read', function() {
beforeEach(function() {
this.db_name = mk_db_name();