diff --git a/examples/refactoring-test.html b/examples/refactoring-test.html
index 7a1148d..865739c 100644
--- a/examples/refactoring-test.html
+++ b/examples/refactoring-test.html
@@ -39,10 +39,36 @@ function create_tmp_file() {
return fs.open('/tmp/1', 'w+');
};
+function print_fd(fd) {
+ console.log(fd);
+ return fd;
+};
+
+function write_data(fd) {
+ var data = new Uint8Array([1, 2, 3, 4]);
+ return fs.write(fd, data, 0, 4);
+};
+
+function close_tmp_file(fd) {
+ return fs.close(fd);
+};
+
fs.promise.then(make_tmp_directory)
+ .then(function() {
+ var fd = fs.open('/tmp/1', 'w+');
+
+ function write_data() {
+ var data = new Uint8Array([1, 2, 3, 4]);
+ return fs.write(fd, data, 0, 4);
+ };
+
+ fd.promise.then(write_data);
+ })
.then(create_tmp_file)
+ .then(print_fd)
+ .then(write_data)
.then(function() { console.log('done'); })
- .otherwise(function(error) { console.error(error, error.message); });
+ .otherwise(function(error) { console.error(error, error.message, error.stack); });
});
diff --git a/examples/test5.html b/examples/test5.html
index e89175b..b293f6b 100644
--- a/examples/test5.html
+++ b/examples/test5.html
@@ -2,6 +2,12 @@ var write_buffer = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
var read_buffer = new Uint8Array(16);
var fs = new FileSystem('local');
+fs.mkdir('/tmp');
+fs.open('/tmp/', 'w+', function(error, fd) {
+ if(error) return console.error(error);
+ fs.write(fd, ...);
+ fs.read(fd, ...);
+});
fs.then(
function() {
diff --git a/src/descriptor.js b/src/descriptor.js
deleted file mode 100644
index 50e8de5..0000000
--- a/src/descriptor.js
+++ /dev/null
@@ -1,16 +0,0 @@
-define(function(require) {
-
- function Descriptor(db, id, flags, mode, size) {
- this.db = db;
- this.id = id;
- this.flags = flags;
- this.mode = mode;
- this.size = size || 0;
- this.position = 0;
- };
-
- return {
- Descriptor: Descriptor
- }
-
-});
\ No newline at end of file
diff --git a/src/directory.js b/src/directory.js
deleted file mode 100644
index 5db0b7e..0000000
--- a/src/directory.js
+++ /dev/null
@@ -1,192 +0,0 @@
-define(function(require) {
-
- var read_object = require('src/object-store').read_object;
- var write_object = require('src/object-store').write_object;
- var delete_object = require('src/object-store').delete_object;
- var find_node = require('src/object-store').find_node;
-
- var ENoEntry = require('src/error').ENoEntry;
- var ENotDirectory = require('src/error').ENotDirectory;
- var EExists = require('src/error').EExists;
-
- var MODE_FILE = require('src/constants').MODE_FILE;
- var MODE_DIRECTORY = require('src/constants').MODE_DIRECTORY;
- var ROOT_DIRECTORY_NAME = require('src/constants').ROOT_DIRECTORY_NAME;
- var ROOT_NODE_ID = require('src/constants').ROOT_NODE_ID;
-
- var Node = require('src/file').Node;
- var DirectoryEntry = require('src/file').DirectoryEntry;
-
- var normalize = require('src/path').normalize;
- var dirname = require('src/path').dirname;
- var basename = require('src/path').basename;
-
- // Note: this should only be invoked when formatting a new file system
- function make_root_directory(objectStore, callback) {
- var directoryNode;
- var directoryData;
-
- function write_directory_node(error, existingNode) {
- if(!error && existingNode) {
- callback(new EExists());
- } else if(error && !error instanceof ENoEntry) {
- callback(error);
- } else {
- directoryNode = new Node(ROOT_NODE_ID, MODE_DIRECTORY);
- directoryNode.links += 1;
- write_object(objectStore, directoryNode, directoryNode.id, write_directory_data);
- }
- };
-
- function write_directory_data(error) {
- if(error) {
- callback(error);
- } else {
- directoryData = {};
- write_object(objectStore, directoryData, directoryNode.data, callback);
- }
- };
-
- find_node(objectStore, ROOT_DIRECTORY_NAME, write_directory_node);
- }
-
- function make_directory(objectStore, path, callback) {
- path = normalize(path);
- var name = basename(path);
- var parentPath = dirname(path);
-
- var directoryNode;
- var directoryData;
- var parentDirectoryNode;
- var parentDirectoryData;
-
- function check_if_directory_exists(error, result) {
- if(!error && result) {
- callback(new EExists());
- } else if(error && !error instanceof ENoEntry) {
- callback(error);
- } else {
- find_node(objectStore, parentPath, read_parent_directory_data);
- }
- }
-
- function read_parent_directory_data(error, result) {
- if(error) {
- callback(error);
- } else {
- parentDirectoryNode = result;
- read_object(objectStore, parentDirectoryNode.data, write_directory_node);
- }
- };
-
- function write_directory_node(error, result) {
- if(error) {
- callback(error);
- } else {
- parentDirectoryData = result;
- directoryNode = new Node(undefined, MODE_DIRECTORY);
- directoryNode.links += 1;
- write_object(objectStore, directoryNode, directoryNode.id, write_directory_data);
- }
- };
-
- function write_directory_data(error) {
- if(error) {
- callback(error);
- } else {
- directoryData = {};
- write_object(objectStore, directoryData, directoryNode.data, update_parent_directory_data);
- }
- };
-
- function update_parent_directory_data(error) {
- if(error) {
- callback(error);
- } else {
- parentDirectoryData[name] = new DirectoryEntry(directoryNode.id, MODE_DIRECTORY);
- write_object(objectStore, parentDirectoryData, parentDirectoryNode.data, callback);
- }
- }
-
- find_node(objectStore, path, check_if_directory_exists);
- };
-
- function remove_directory(objectStore, path, callback) {
- path = normalize(path);
- var name = basename(path);
- var parentPath = dirname(path);
-
- var directoryNode;
- var directoryData;
- var parentDirectoryNode;
- var parentDirectoryData;
-
- function check_if_directory_exists(error, result) {
- if(error) {
- callback(error);
- } else if(!result) {
- callback(new ENoEntry());
- } else {
- directoryNode = result;
- read_object(objectStore, directoryNode.data, check_if_directory_is_empty);
- }
- }
-
- function check_if_directory_is_empty(error, result) {
- if(error) {
- callback(error);
- } else {
- directoryData = result;
- if(_(directoryData).size() > 0) {
- callback(new ENotEmpty());
- } else {
- find_node(objectStore, parentPath, read_parent_directory_data);
- }
- }
- };
-
- function read_parent_directory_data(error, result) {
- if(error) {
- callback(error);
- } else {
- 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) {
- callback(error);
- } else {
- parentDirectoryData = result;
- delete parentDirectoryData[name];
- write_object(objectStore, parentDirectoryData, parentDirectoryNode.data, remove_directory_node);
- }
- };
-
- function remove_directory_node(error) {
- if(error) {
- callback(error);
- } else {
- delete_object(objectStore, directoryNode.id, remove_directory_data);
- }
- };
-
- function remove_directory_data(error) {
- if(error) {
- callback(error);
- } else {
- delete_object(objectStore, directoryNode.data, callback);
- }
- };
-
- find_node(objectStore, path, check_if_directory_exists);
- };
-
- return {
- make_directory: make_directory,
- make_root_directory: make_root_directory,
- remove_directory: remove_directory,
- };
-
-});
\ No newline at end of file
diff --git a/src/file-system.js b/src/file-system.js
index c3b0943..582a6ed 100644
--- a/src/file-system.js
+++ b/src/file-system.js
@@ -5,6 +5,10 @@ define(function(require) {
var _ = require('lodash');
var when = require('when');
+ var normalize = require('src/path').normalize;
+ var dirname = require('src/path').dirname;
+ var basename = require('src/path').basename;
+
var guid = require('src/shared').guid;
var hash = require('src/shared').hash;
var nop = require('src/shared').nop;
@@ -19,9 +23,13 @@ define(function(require) {
var ENotImplemented = require('src/error').ENotImplemented;
var ENotMounted = require('src/error').ENotMounted;
var EInvalid = require('src/error').EInvalid;
+ var EIO = require('src/error').EIO;
var FS_FORMAT = require('src/constants').FS_FORMAT;
-
+ var MODE_FILE = require('src/constants').MODE_FILE;
+ var MODE_DIRECTORY = require('src/constants').MODE_DIRECTORY;
+ var ROOT_DIRECTORY_NAME = require('src/constants').ROOT_DIRECTORY_NAME;
+ var ROOT_NODE_ID = require('src/constants').ROOT_NODE_ID;
var IDB_RW = require('src/constants').IDB_RW;
var IDB_RO = require('src/constants').IDB_RO;
var FILE_STORE_NAME = require('src/constants').FILE_STORE_NAME;
@@ -29,12 +37,506 @@ define(function(require) {
var FS_READY = require('src/constants').READY;
var FS_PENDING = require('src/constants').FS_PENDING;
var FS_ERROR = require('src/constants').FS_ERROR;
+ var O_READ = require('src/constants').O_READ;
+ var O_WRITE = require('src/constants').O_WRITE;
+ var O_CREATE = require('src/constants').O_CREATE;
+ var O_EXCLUSIVE = require('src/constants').O_EXCLUSIVE;
+ var O_TRUNCATE = require('src/constants').O_TRUNCATE;
+ var O_APPEND = require('src/constants').O_APPEND;
+ var O_FLAGS = require('src/constants').O_FLAGS;
- var make_root_directory = require('src/directory').make_root_directory;
- var make_directory = require('src/directory').make_directory;
- var remove_directory = require('src/directory').remove_directory;
+ /*
+ * DirectoryEntry
+ */
- var open_file = require('src/file').open_file;
+ function DirectoryEntry(id, type) {
+ this.id = id;
+ this.type = type || MODE_FILE;
+ };
+
+ /*
+ * OpenFileDescription
+ */
+
+ function OpenFileDescription(id, flags, position) {
+ this.id = id;
+ this.flags = flags;
+ this.position = position;
+ };
+
+ /*
+ * Node
+ */
+
+ function Node(id, mode, size, atime, ctime, mtime, flags, xattrs, nlinks, version) {
+ var now = Date.now();
+
+ 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
+ this.ctime = ctime || now; // creation time
+ this.mtime = mtime || now; // modified time
+ this.flags = flags || []; // file flags
+ this.xattrs = xattrs || {}; // extended attributes
+ this.nlinks = nlinks || 0; // links count
+ this.version = version || 0; // node version
+ this.data = hash(guid()) // id for data object
+ };
+
+ /*
+ * find_node
+ */
+
+ // in: file or directory path
+ // out: node structure, or error
+ function find_node(objectStore, path, callback) {
+ path = normalize(path);
+ if(!path) {
+ return callback(new ENoEntry('path is an empty string'));
+ }
+ var name = basename(path);
+
+ if(ROOT_DIRECTORY_NAME == name) {
+ function check_root_directory_node(error, rootDirectoryNode) {
+ if(error) {
+ callback(error);
+ } else if(!rootDirectoryNode) {
+ callback(new ENoEntry('path does not exist'));
+ } else {
+ callback(undefined, rootDirectoryNode);
+ }
+ };
+
+ read_object(objectStore, ROOT_NODE_ID, check_root_directory_node);
+ } else {
+ // in: parent directory node
+ // out: parent directory data
+ function read_parent_directory_data(error, parentDirectoryNode) {
+ if(error) {
+ callback(error);
+ } else if(!_(parentDirectoryNode).has('data') || !parentDirectoryNode.type == MODE_DIRECTORY) {
+ callback(new ENotDirectory('a component of the path prefix is not a directory'));
+ } else {
+ read_object(objectStore, parentDirectoryNode.data, get_node_id_from_parent_directory_data);
+ }
+ };
+
+ // in: parent directory data
+ // out: searched node id
+ function get_node_id_from_parent_directory_data(error, parentDirectoryData) {
+ if(error) {
+ callback(error);
+ } else {
+ if(!_(parentDirectoryData).has(name)) {
+ callback(new ENoEntry('path does not exist'));
+ } else {
+ var nodeId = parentDirectoryData[name].id;
+ read_object(objectStore, nodeId, callback);
+ }
+ }
+ };
+
+ var parentPath = dirname(path);
+ find_node(objectStore, parentPath, read_parent_directory_data);
+ }
+ };
+
+ /*
+ * read_object
+ */
+
+ function read_object(objectStore, id, callback) {
+ var getRequest = objectStore.get(id);
+ getRequest.onsuccess = function onsuccess(event) {
+ var result = event.target.result;
+ callback(undefined, result);
+ };
+ getRequest.onerror = function onerror(error) {
+ callback(error);
+ };
+ };
+
+ /*
+ * write_object
+ */
+
+ function write_object(objectStore, object, id, callback) {
+ var putRequest = objectStore.put(object, id);
+ putRequest.onsuccess = function onsuccess(event) {
+ var result = event.target.result;
+ callback(undefined, result);
+ };
+ putRequest.onerror = function onerror(error) {
+ callback(error);
+ };
+ };
+
+ /*
+ * delete_object
+ */
+
+ function delete_object(objectStore, id, callback) {
+ var deleteRequest = objectStore.delete(id);
+ deleteRequest.onsuccess = function onsuccess(event) {
+ var result = event.target.result;
+ callback(undefined, result);
+ };
+ deleteRequest.onerror = function(error) {
+ callback(error);
+ };
+ };
+
+ /*
+ * make_root_directory
+ */
+
+ // Note: this should only be invoked when formatting a new file system
+ function make_root_directory(objectStore, callback) {
+ var directoryNode;
+ var directoryData;
+
+ function write_directory_node(error, existingNode) {
+ if(!error && existingNode) {
+ callback(new EExists());
+ } else if(error && !error instanceof ENoEntry) {
+ callback(error);
+ } else {
+ directoryNode = new Node(ROOT_NODE_ID, MODE_DIRECTORY);
+ directoryNode.nlinks += 1;
+ write_object(objectStore, directoryNode, directoryNode.id, write_directory_data);
+ }
+ };
+
+ function write_directory_data(error) {
+ if(error) {
+ callback(error);
+ } else {
+ directoryData = {};
+ write_object(objectStore, directoryData, directoryNode.data, callback);
+ }
+ };
+
+ find_node(objectStore, ROOT_DIRECTORY_NAME, write_directory_node);
+ };
+
+ /*
+ * make_directory
+ */
+
+ function make_directory(objectStore, path, callback) {
+ path = normalize(path);
+ var name = basename(path);
+ var parentPath = dirname(path);
+
+ var directoryNode;
+ var directoryData;
+ var parentDirectoryNode;
+ var parentDirectoryData;
+
+ function check_if_directory_exists(error, result) {
+ if(!error && result) {
+ callback(new EExists());
+ } else if(error && !error instanceof ENoEntry) {
+ callback(error);
+ } else {
+ find_node(objectStore, parentPath, read_parent_directory_data);
+ }
+ }
+
+ function read_parent_directory_data(error, result) {
+ if(error) {
+ callback(error);
+ } else {
+ parentDirectoryNode = result;
+ read_object(objectStore, parentDirectoryNode.data, write_directory_node);
+ }
+ };
+
+ function write_directory_node(error, result) {
+ if(error) {
+ callback(error);
+ } else {
+ parentDirectoryData = result;
+ directoryNode = new Node(undefined, MODE_DIRECTORY);
+ directoryNode.nlinks += 1;
+ write_object(objectStore, directoryNode, directoryNode.id, write_directory_data);
+ }
+ };
+
+ function write_directory_data(error) {
+ if(error) {
+ callback(error);
+ } else {
+ directoryData = {};
+ write_object(objectStore, directoryData, directoryNode.data, update_parent_directory_data);
+ }
+ };
+
+ function update_parent_directory_data(error) {
+ if(error) {
+ callback(error);
+ } else {
+ parentDirectoryData[name] = new DirectoryEntry(directoryNode.id, MODE_DIRECTORY);
+ write_object(objectStore, parentDirectoryData, parentDirectoryNode.data, callback);
+ }
+ }
+
+ find_node(objectStore, path, check_if_directory_exists);
+ };
+
+ /*
+ * remove_directory
+ */
+
+ function remove_directory(objectStore, path, callback) {
+ path = normalize(path);
+ var name = basename(path);
+ var parentPath = dirname(path);
+
+ var directoryNode;
+ var directoryData;
+ var parentDirectoryNode;
+ var parentDirectoryData;
+
+ function check_if_directory_exists(error, result) {
+ if(error) {
+ callback(error);
+ } else if(!result) {
+ callback(new ENoEntry());
+ } else {
+ directoryNode = result;
+ read_object(objectStore, directoryNode.data, check_if_directory_is_empty);
+ }
+ }
+
+ function check_if_directory_is_empty(error, result) {
+ if(error) {
+ callback(error);
+ } else {
+ directoryData = result;
+ if(_(directoryData).size() > 0) {
+ callback(new ENotEmpty());
+ } else {
+ find_node(objectStore, parentPath, read_parent_directory_data);
+ }
+ }
+ };
+
+ function read_parent_directory_data(error, result) {
+ if(error) {
+ callback(error);
+ } else {
+ 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) {
+ callback(error);
+ } else {
+ parentDirectoryData = result;
+ delete parentDirectoryData[name];
+ write_object(objectStore, parentDirectoryData, parentDirectoryNode.data, remove_directory_node);
+ }
+ };
+
+ function remove_directory_node(error) {
+ if(error) {
+ callback(error);
+ } else {
+ delete_object(objectStore, directoryNode.id, remove_directory_data);
+ }
+ };
+
+ function remove_directory_data(error) {
+ if(error) {
+ callback(error);
+ } 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);
+ var name = basename(path);
+ var parentPath = dirname(path);
+
+ var directoryNode;
+ var directoryData;
+ var directoryEntry;
+ var fileNode;
+ var fileData;
+
+ find_node(objectStore, parentPath, read_directory_data);
+
+ function read_directory_data(error, result) {
+ if(error) {
+ callback(error);
+ } else {
+ directoryNode = result;
+ read_object(objectStore, directoryNode.data, check_if_file_exists);
+ }
+ };
+
+ function check_if_file_exists(error, result) {
+ if(error) {
+ callback(error);
+ } else {
+ 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'))
+ } else {
+ directoryEntry = directoryData[name];
+ if(directoryEntry.type == MODE_DIRECTORY) {
+ callback(new EIsDirectory('the named file is a directory and O_WRITE is set'))
+ } else {
+ read_object(objectStore, directoryEntry.id, set_file_node);
+ }
+ }
+ } else {
+ if(!_(flags).contains(O_CREATE)) {
+ callback(new ENoEntry('O_CREATE is not set and the named file does not exist'));
+ } else {
+ write_file_node();
+ }
+ }
+ }
+ };
+
+ function set_file_node(error, result) {
+ if(error) {
+ callback(error);
+ } else {
+ 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) {
+ callback(error);
+ } else {
+ fileData = {};
+ write_object(objectStore, fileData, fileNode.data, update_directory_data);
+ }
+ };
+
+ function update_directory_data(error) {
+ if(error) {
+ callback(error);
+ } else {
+ directoryData[name] = new DirectoryEntry(fileNode.id, MODE_FILE);
+ write_object(objectStore, directoryData, directoryNode.data, handle_update_result);
+ }
+ };
+
+ function handle_update_result(error) {
+ if(error) {
+ callback(error);
+ } else {
+ callback(undefined, fileNode);
+ }
+ };
+ };
+
+ function write_data(objectStore, ofd, buffer, offset, length, position, callback) {
+ var fileNode;
+ var fileData;
+
+ read_object(objectStore, ofd.id, read_file_data);
+
+ function read_file_data(error, result) {
+ if(error) {
+ callback(error);
+ } else {
+ fileNode = result;
+ read_object(objectStore, fileNode.data, update_file_data);
+ }
+ };
+
+ function update_file_data(error, result) {
+ if(error) {
+ callback(error);
+ } else {
+ fileData = result;
+ var _position = (undefined !== position) ? position : ofd.position;
+ var newSize = Math.max(fileData.length, _position + length);
+ var newData = new Uint8Array(newSize);
+ if(fileData) {
+ newData.set(fileData);
+ }
+ newData.set(buffer, _position);
+ if(undefined === position) {
+ ofd.position += length;
+ }
+
+ fileNode.size = newSize;
+ fileNode.mtime = Date.now();
+ fileNode.version += 1;
+
+ write_object(objectStore, fileNode.data, update_file_node);
+ }
+ };
+
+ function update_file_node(error) {
+ if(error) {
+ callback(error);
+ } else {
+ write_object(objectStore, fileNode.id, return_nbytes);
+ }
+ };
+
+ function return_nbytes(error) {
+ if(error) {
+ callback(error);
+ } else {
+ callback(undefined, nbytes);
+ }
+ };
+ };
+
+ function read_data(objectStore, ofd, buffer, offset, length, position, callback) {
+ var fileNode;
+ var fileData;
+
+ read_object(objectStore, ofd.id, read_file_data);
+
+ function read_file_data(error, result) {
+ if(error) {
+ callback(error);
+ } else {
+ fileNode = result;
+ read_object(objectStore, fileNode.data, handle_file_data);
+ }
+ };
+
+ function handle_file_data(error, result) {
+ if(error) {
+ callback(error);
+ } else {
+ fileData = result;
+ var _position = (undefined !== position) ? position : ofd.position;
+ length = (_position + length > buffer.length) ? length - _position : length;
+ var dataView = fileData.subarray(_position, _position + length);
+ if(undefined === position) {
+ ofd.position += length;
+ }
+ callback(undefined, length);
+ }
+ };
+ };
/*
* FileSystem
@@ -97,29 +599,66 @@ define(function(require) {
deferred.reject(error);
};
+ var nextDescriptor = 1;
+ var openFiles = {};
+
this.readyState = FS_PENDING;
this.db = null;
+ this.nextDescriptor = nextDescriptor;
+ this.openFiles = openFiles;
+ };
+ FileSystem.prototype._allocate_descriptor = function _allocate_descriptor(openFileDescription) {
+ var fd = this.nextDescriptor ++;
+ this.openFiles[fd] = openFileDescription;
+ return fd;
+ };
+ FileSystem.prototype._release_descriptor = function _release_descriptor(fd) {
+ delete this.openFiles[fd];
};
FileSystem.prototype.open = function open(path, flags) {
+ var that = this;
var deferred = when.defer();
var transaction = this.db.transaction([FILE_STORE_NAME], IDB_RW);
var files = transaction.objectStore(FILE_STORE_NAME);
- function check_result(error, fd) {
+ function check_result(error, fileNode) {
if(error) {
// if(transaction.error) transaction.abort();
deferred.reject(error);
} else {
- deferred.resolve();
+ var position;
+ if(_(flags).contains(O_APPEND)) {
+ position = fileNode.size;
+ } else {
+ position = 0;
+ }
+ var openFileDescription = new OpenFileDescription(fileNode.id, flags, position);
+ var fd = that._allocate_descriptor(openFileDescription);
+ deferred.resolve(fd);
}
};
- open_file(files, path, flags, check_result);
+ if(!_(O_FLAGS).has(flags)) {
+ deferred.reject(new EInvalid('flags is not valid'));
+ } else {
+ flags = O_FLAGS[flags];
+ }
+
+ open_file(this, files, path, flags, check_result);
return deferred.promise;
};
- FileSystem.prototype.opendir = function opendir(path) {
+ FileSystem.prototype.close = function close(fd) {
+ var deferred = when.defer();
+ if(!_(this.openFiles).has(fd)) {
+ deferred.reject(new EBadFileDescriptor('invalid file descriptor'));
+ } else {
+ this._release_descriptor(fd);
+ deferred.resolve();
+ }
+
+ return deferred.promise;
};
FileSystem.prototype.mkdir = function mkdir(path) {
var deferred = when.defer();
@@ -128,7 +667,7 @@ define(function(require) {
function check_result(error) {
if(error) {
- if(transaction.error) transaction.abort();
+ // if(transaction.error) transaction.abort();
deferred.reject(error);
} else {
deferred.resolve();
@@ -145,7 +684,7 @@ define(function(require) {
function check_result(error) {
if(error) {
- if(transaction.error) transaction.abort();
+ // if(transaction.error) transaction.abort();
deferred.reject(error);
} else {
deferred.resolve();
@@ -157,6 +696,9 @@ define(function(require) {
};
FileSystem.prototype.stat = function stat(path) {
+ };
+ FileSystem.prototype.fstat = function fstat(fd) {
+
};
FileSystem.prototype.link = function link(oldpath, newpath) {
@@ -169,6 +711,71 @@ define(function(require) {
};
FileSystem.prototype.setxattr = function setxattr(path, name, value) {
+ };
+ FileSystem.prototype.read = function read(fd, buffer, offset, length, position) {
+ var deferred = when.defer();
+ var transaction = this.db.transaction([FILE_STORE_NAME], IDB_RW);
+ var files = transaction.objectStore(FILE_STORE_NAME);
+
+ offset = (undefined === offset) ? 0 : offset;
+ length = (undefined === length) ? buffer.length - offset : length;
+
+ function check_result(error, nbytes) {
+ if(error) {
+ deferred.reject(error);
+ } else {
+ deferred.resolve(nbytes);
+ }
+ };
+
+ var ofd = this.openFiles[fd];
+
+ if(!ofd) {
+ deferred.reject(new EBadFileDescriptor('invalid file descriptor'));
+ } else if(!_(flags).contains(O_READ)) {
+ deferred.reject(new EBadFileDescriptor('descriptor does not permit reading'));
+ } else {
+ read_data(files, ofd, buffer, offset, length, position, check_result);
+ }
+
+ // TODO: check buffer length
+
+ return deferred.promise;
+ };
+ FileSystem.prototype.write = function write(fd, buffer, offset, length, position) {
+ var deferred = when.defer();
+ var transaction = this.db.transaction([FILE_STORE_NAME], IDB_RW);
+ var files = transaction.objectStore(FILE_STORE_NAME);
+
+ offset = (undefined === offset) ? 0 : offset;
+ length = (undefined === length) ? buffer.length - offset : length;
+
+ function check_result(error, nbytes) {
+ if(error) {
+ deferred.reject(error);
+ } else {
+ deferred.resolve(nbytes);
+ }
+ };
+
+ var ofd = this.openFiles[fd];
+
+ if(!ofd) {
+ deferred.reject(new EBadFileDescriptor('invalid file descriptor'));
+ } else if(!_(flags).contains(O_WRITE)) {
+ deferred.reject(new EBadFileDescriptor('descriptor does not permit writing'));
+ } else if(buffer.length - offset < length) {
+ deferred.reject(new EIO('intput buffer is too small'));
+ } else {
+ write_data(files, ofd, buffer, offset, length, position, check_result);
+ }
+
+ // TODO: check buffer length
+
+ return deferred.promise;
+ };
+ FileSystem.prototype.seek = function seek(fd, offset, origin) {
+
};
return {
diff --git a/src/file.js b/src/file.js
deleted file mode 100644
index bb0df9b..0000000
--- a/src/file.js
+++ /dev/null
@@ -1,135 +0,0 @@
-define(function(require) {
-
- var _ = require('lodash');
-
- var normalize = require('src/path').normalize;
- var dirname = require('src/path').dirname;
- var basename = require('src/path').basename;
-
- var MODE_FILE = require('src/constants').MODE_FILE;
-
- var guid = require('src/shared').guid;
- var hash = require('src/shared').hash;
-
- var read_object = require('src/object-store').read_object;
- var write_object = require('src/object-store').write_object;
- var delete_object = require('src/object-store').delete_object;
- var find_node = require('src/object-store').find_node;
-
- var O_READ = require('src/constants').O_READ;
- var O_WRITE = require('src/constants').O_WRITE;
- var O_CREATE = require('src/constants').O_CREATE;
- var O_EXCLUSIVE = require('src/constants').O_EXCLUSIVE;
- var O_TRUNCATE = require('src/constants').O_TRUNCATE;
- var O_APPEND = require('src/constants').O_APPEND;
- var O_FLAGS = require('src/constants').O_FLAGS;
-
- var EInvalid = require('src/error').EInvalid;
-
- function DirectoryEntry(id, type) {
- this.id = id;
- this.type = type || MODE_FILE;
- };
-
- function Node(id, mode, size, atime, ctime, mtime, flags, xattrs, links, version) {
- var now = Date.now();
-
- 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
- this.ctime = ctime || now; // creation time
- this.mtime = mtime || now; // modified time
- this.flags = flags || []; // file flags
- this.xattrs = xattrs || {}; // extended attributes
- this.links = links || 0; // links count
- this.version = version || 0; // node version
- this.data = hash(this.id) // id for data object
- };
-
- function open_file(objectStore, path, flags, callback) {
- path = normalize(path);
- var name = basename(path);
- var parentPath = dirname(path);
-
- var directoryNode;
- var directoryData;
- var fileNode;
- var fileData;
-
- if(!_(O_FLAGS).has(flags)) {
- return callback(new EInvalid('flags is not valid'));
- } else {
- flags = O_FLAGS[flags];
- }
-
- find_node(objectStore, parentPath, read_directory_data);
-
- function read_directory_data(error, result) {
- if(error) {
- callback(error);
- } else {
- directoryNode = result;
- read_object(objectStore, directoryNode.data, check_if_file_exists);
- }
- };
-
- function check_if_file_exists(error, result) {
- if(error) {
- callback(error);
- } else {
- 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'))
- }
- } else {
- if(!_(flags).contains(O_CREATE)) {
- callback(new ENoEntry('O_CREATE is not set and the named file does not exist'));
- } else {
- write_file_node();
- }
- }
- }
- };
-
- function write_file_node() {
- fileNode = new Node(undefined, MODE_FILE);
- fileNode.links += 1;
- write_object(objectStore, fileNode, fileNode.id, write_file_data);
- };
-
- function write_file_data(error) {
- if(error) {
- callback(error);
- } else {
- fileData = {};
- write_object(objectStore, fileData, fileNode.data, update_directory_data);
- }
- };
-
- function update_directory_data(error) {
- if(error) {
- callback(error);
- } else {
- directoryData[name] = new DirectoryEntry(fileNode.id, MODE_FILE);
- write_object(objectStore, directoryData, directoryNode.data, create_file_descriptor);
- }
- };
-
- function create_file_descriptor(error) {
- if(error) {
- console.log(error);
- } else {
- callback(undefined, '!');
- }
- };
- };
-
- return {
- Node: Node,
- open_file: open_file,
- DirectoryEntry: DirectoryEntry,
- };
-
-});
\ No newline at end of file
diff --git a/src/object-store.js b/src/object-store.js
deleted file mode 100644
index 8e6e944..0000000
--- a/src/object-store.js
+++ /dev/null
@@ -1,110 +0,0 @@
-define(function(require) {
-
- var ENoEntry = require('src/error').ENoEntry;
- var ENotDirectory = require('src/error').ENotDirectory;
- var EExists = require('src/error').EExists;
-
- var normalize = require('src/path').normalize;
- var dirname = require('src/path').dirname;
- var basename = require('src/path').basename;
-
- var ROOT_DIRECTORY_NAME = require('src/constants').ROOT_DIRECTORY_NAME;
- var ROOT_NODE_ID = require('src/constants').ROOT_NODE_ID;
-
- var MODE_DIRECTORY = require('src/constants').MODE_DIRECTORY;
-
- // in: file or directory path
- // out: node structure, or error
- function find_node(objectStore, path, callback) {
- path = normalize(path);
- if(!path) {
- return callback(new ENoEntry('path is an empty string'));
- }
- var name = basename(path);
-
- if(ROOT_DIRECTORY_NAME == name) {
- function check_root_directory_node(error, rootDirectoryNode) {
- if(error) {
- callback(error);
- } else if(!rootDirectoryNode) {
- callback(new ENoEntry('path does not exist'));
- } else {
- callback(undefined, rootDirectoryNode);
- }
- };
-
- read_object(objectStore, ROOT_NODE_ID, check_root_directory_node);
- } else {
- // in: parent directory node
- // out: parent directory data
- function read_parent_directory_data(error, parentDirectoryNode) {
- if(error) {
- callback(error);
- } else if(!_(parentDirectoryNode).has('data') || !parentDirectoryNode.type == MODE_DIRECTORY) {
- callback(new ENotDirectory('a component of the path prefix is not a directory'));
- } else {
- read_object(objectStore, parentDirectoryNode.data, get_node_id_from_parent_directory_data);
- }
- };
-
- // in: parent directory data
- // out: searched node id
- function get_node_id_from_parent_directory_data(error, parentDirectoryData) {
- if(error) {
- callback(error);
- } else {
- if(!_(parentDirectoryData).has(name)) {
- callback(new ENoEntry('path does not exist'));
- } else {
- var nodeId = parentDirectoryData[name].id;
- read_object(objectStore, nodeId, callback);
- }
- }
- };
-
- var parentPath = dirname(path);
- find_node(objectStore, parentPath, read_parent_directory_data);
- }
- };
-
- function read_object(objectStore, id, callback) {
- var getRequest = objectStore.get(id);
- getRequest.onsuccess = function onsuccess(event) {
- var result = event.target.result;
- callback(undefined, result);
- };
- getRequest.onerror = function onerror(error) {
- callback(error);
- };
- };
-
- function write_object(objectStore, object, id, callback) {
- var putRequest = objectStore.put(object, id);
- putRequest.onsuccess = function onsuccess(event) {
- var result = event.target.result;
- callback(undefined, result);
- };
- putRequest.onerror = function onerror(error) {
- callback(error);
- };
- };
-
- function delete_object(objectStore, id, callback) {
- var deleteRequest = objectStore.delete(id);
- deleteRequest.onsuccess = function onsuccess(event) {
- var result = event.target.result;
- callback(undefined, result);
- };
- deleteRequest.onerror = function(error) {
- callback(error);
- };
- };
-
- return {
- read_object: read_object,
- write_object: write_object,
- delete_object: delete_object,
- find_node: find_node
- };
-
-});
\ No newline at end of file