Merge pull request #6 from humphd/utf8
Add fs.readFile, fs.writeFile with tests
This commit is contained in:
commit
c590f930e5
|
@ -1 +1,2 @@
|
|||
node_modules
|
||||
*~
|
||||
|
|
34
README.md
34
README.md
|
@ -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.
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -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']);
|
||||
};
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ define(function(require) {
|
|||
|
||||
FS_READY: 'READY',
|
||||
FS_PENDING: 'PENDING',
|
||||
FS_ERROR: 'ERROR',
|
||||
FS_ERROR: 'ERROR'
|
||||
};
|
||||
|
||||
});
|
28
src/error.js
28
src/error.js
|
@ -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
305
src/fs.js
|
@ -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
|
||||
};
|
||||
|
||||
});
|
|
@ -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
|
||||
};
|
||||
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue