Stat implementation, updated tests.

This commit is contained in:
Alan Kligman 2013-07-12 11:11:05 -04:00
parent 19b21e10de
commit c3c9751ff4
5 changed files with 960 additions and 435 deletions

1068
dist/idbfs.js vendored

File diff suppressed because it is too large Load Diff

View File

@ -18,15 +18,25 @@ require.config({
require(["src/file-system"], function(IDBFS) { require(["src/file-system"], function(IDBFS) {
var flags = 'FORMAT'; var flags = 'FORMAT';
//var flags = undefined; //var flags;
var fs = new IDBFS.FileSystem('local', flags); var fs = new IDBFS.FileSystem('local', flags);
fs.promise.otherwise( fs.stat('/', function(error, result) {
function(error) { console.log('stat /', error, result);
console.error(error); });
} fs.stat('/tmp', function(error, result) {
); console.log('stat /tmp', error, result);
});
/*
fs.mkdir('/tmp', function(error) {
if(error) throw error;
fs.stat('/tmp', function(error, result) {
console.log('stat /tmp', error, result);
});
});
*/
/*
function make_tmp_directory() { function make_tmp_directory() {
return fs.mkdir('/tmp'); return fs.mkdir('/tmp');
}; };
@ -69,7 +79,7 @@ fs.promise.then(make_tmp_directory)
.then(write_data) .then(write_data)
.then(function() { console.log('done'); }) .then(function() { console.log('done'); })
.otherwise(function(error) { console.error(error, error.message, error.stack); }); .otherwise(function(error) { console.error(error, error.message, error.stack); });
*/
}); });
</script> </script>
</html> </html>

View File

@ -91,6 +91,13 @@ define(function(require) {
EIO.prototype.name = "EIO"; EIO.prototype.name = "EIO";
EIO.prototype.constructor = EIO; EIO.prototype.constructor = EIO;
function EFileSystemError(message){
this.message = message || '';
};
EFileSystemError.prototype = new Error();
EFileSystemError.prototype.name = "EFileSystemError";
EFileSystemError.prototype.constructor = EFileSystemError;
return { return {
EExists: EExists, EExists: EExists,
EIsDirectory: EIsDirectory, EIsDirectory: EIsDirectory,

View File

@ -24,6 +24,7 @@ define(function(require) {
var ENotMounted = require('src/error').ENotMounted; var ENotMounted = require('src/error').ENotMounted;
var EInvalid = require('src/error').EInvalid; var EInvalid = require('src/error').EInvalid;
var EIO = require('src/error').EIO; var EIO = require('src/error').EIO;
var EFileSystemError = require('src/error').EFileSystemError;
var FS_FORMAT = require('src/constants').FS_FORMAT; var FS_FORMAT = require('src/constants').FS_FORMAT;
var MODE_FILE = require('src/constants').MODE_FILE; var MODE_FILE = require('src/constants').MODE_FILE;
@ -34,7 +35,7 @@ define(function(require) {
var IDB_RO = require('src/constants').IDB_RO; var IDB_RO = require('src/constants').IDB_RO;
var FILE_STORE_NAME = require('src/constants').FILE_STORE_NAME; var FILE_STORE_NAME = require('src/constants').FILE_STORE_NAME;
var METADATA_STORE_NAME = require('src/constants').METADATA_STORE_NAME; var METADATA_STORE_NAME = require('src/constants').METADATA_STORE_NAME;
var FS_READY = require('src/constants').READY; var FS_READY = require('src/constants').FS_READY;
var FS_PENDING = require('src/constants').FS_PENDING; var FS_PENDING = require('src/constants').FS_PENDING;
var FS_ERROR = require('src/constants').FS_ERROR; var FS_ERROR = require('src/constants').FS_ERROR;
var O_READ = require('src/constants').O_READ; var O_READ = require('src/constants').O_READ;
@ -81,7 +82,9 @@ define(function(require) {
this.xattrs = xattrs || {}; // extended attributes this.xattrs = xattrs || {}; // extended attributes
this.nlinks = nlinks || 0; // links count this.nlinks = nlinks || 0; // links count
this.version = version || 0; // node version this.version = version || 0; // node version
this.data = hash(guid()) // id for data object this.blksize = undefined; // block size
this.nblocks = 1; // blocks count
this.data = hash(guid()); // id for data object
}; };
/* /*
@ -96,6 +99,7 @@ define(function(require) {
return callback(new ENoEntry('path is an empty string')); return callback(new ENoEntry('path is an empty string'));
} }
var name = basename(path); var name = basename(path);
var parentPath = dirname(path);
if(ROOT_DIRECTORY_NAME == name) { if(ROOT_DIRECTORY_NAME == name) {
function check_root_directory_node(error, rootDirectoryNode) { function check_root_directory_node(error, rootDirectoryNode) {
@ -137,7 +141,6 @@ define(function(require) {
} }
}; };
var parentPath = dirname(path);
find_node(objectStore, parentPath, read_parent_directory_data); find_node(objectStore, parentPath, read_parent_directory_data);
} }
}; };
@ -538,6 +541,22 @@ define(function(require) {
}; };
}; };
function stat_file(objectStore, path, callback) {
path = normalize(path);
var name = basename(path);
var parentPath = dirname(path);
find_node(objectStore, path, check_file);
function check_file(error, result) {
if(error) {
callback(error);
} else {
callback(undefined, result);
}
};
};
/* /*
* FileSystem * FileSystem
*/ */
@ -606,6 +625,7 @@ define(function(require) {
this.db = null; this.db = null;
this.nextDescriptor = nextDescriptor; this.nextDescriptor = nextDescriptor;
this.openFiles = openFiles; this.openFiles = openFiles;
this.name = name;
}; };
FileSystem.prototype._allocate_descriptor = function _allocate_descriptor(openFileDescription) { FileSystem.prototype._allocate_descriptor = function _allocate_descriptor(openFileDescription) {
var fd = this.nextDescriptor ++; var fd = this.nextDescriptor ++;
@ -615,7 +635,7 @@ define(function(require) {
FileSystem.prototype._release_descriptor = function _release_descriptor(fd) { FileSystem.prototype._release_descriptor = function _release_descriptor(fd) {
delete this.openFiles[fd]; delete this.openFiles[fd];
}; };
FileSystem.prototype.open = function open(path, flags) { FileSystem.prototype.open = function open(path, flags, callback) {
var that = this; var that = this;
var deferred = when.defer(); var deferred = when.defer();
var transaction = this.db.transaction([FILE_STORE_NAME], IDB_RW); var transaction = this.db.transaction([FILE_STORE_NAME], IDB_RW);
@ -644,11 +664,11 @@ define(function(require) {
flags = O_FLAGS[flags]; flags = O_FLAGS[flags];
} }
open_file(this, files, path, flags, check_result);
return deferred.promise; open_file(this, files, path, flags, check_result);
deferred.then(callback);
}; };
FileSystem.prototype.close = function close(fd) { FileSystem.prototype.close = function close(fd, callback) {
var deferred = when.defer(); var deferred = when.defer();
if(!_(this.openFiles).has(fd)) { if(!_(this.openFiles).has(fd)) {
@ -658,11 +678,14 @@ define(function(require) {
deferred.resolve(); deferred.resolve();
} }
return deferred.promise; deferred.then(callback);
}; };
FileSystem.prototype.mkdir = function mkdir(path) { FileSystem.prototype.mkdir = function mkdir(path, callback) {
var that = this;
this.promise.then(
function() {
var deferred = when.defer(); var deferred = when.defer();
var transaction = this.db.transaction([FILE_STORE_NAME], IDB_RW); var transaction = that.db.transaction([FILE_STORE_NAME], IDB_RW);
var files = transaction.objectStore(FILE_STORE_NAME); var files = transaction.objectStore(FILE_STORE_NAME);
function check_result(error) { function check_result(error) {
@ -675,9 +698,21 @@ define(function(require) {
}; };
make_directory(files, path, check_result); make_directory(files, path, check_result);
return deferred.promise; deferred.promise.then(
function() {
callback();
},
function(error) {
callback(error);
}
);
},
function() {
callback(new EFileSystemError('unknown error'));
}
);
}; };
FileSystem.prototype.rmdir = function rmdir(path) { FileSystem.prototype.rmdir = function rmdir(path, callback) {
var deferred = when.defer(); var deferred = when.defer();
var transaction = this.db.transaction([FILE_STORE_NAME], IDB_RW); var transaction = this.db.transaction([FILE_STORE_NAME], IDB_RW);
var files = transaction.objectStore(FILE_STORE_NAME); var files = transaction.objectStore(FILE_STORE_NAME);
@ -692,27 +727,66 @@ define(function(require) {
}; };
remove_directory(files, path, check_result); remove_directory(files, path, check_result);
return deferred.promise; deferred.then(callback);
}; };
FileSystem.prototype.stat = function stat(path) { FileSystem.prototype.readdir = function readdir(path, callback) {
}; };
FileSystem.prototype.fstat = function fstat(fd) { FileSystem.prototype.stat = function stat(path, 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);
function check_result(error, result) {
if(error) {
// if(transaction.error) transaction.abort();
deferred.reject(error);
} else {
var stats = {
dev: that.name,
nlinks: result.nlinks,
atime: result.atime,
mtime: result.mtime,
ctime: result.ctime
};
deferred.resolve(stats);
}
};
stat_file(files, path, check_result);
deferred.promise.then(
function(result) {
callback(undefined, result);
},
function(error) {
callback(error);
}
);
},
function() {
callback(new EFileSystemError('unknown error'));
}
);
};
FileSystem.prototype.fstat = function fstat(fd, callback) {
}; };
FileSystem.prototype.link = function link(oldpath, newpath) { FileSystem.prototype.link = function link(oldpath, newpath, callback) {
}; };
FileSystem.prototype.unlink = function unlink(path) { FileSystem.prototype.unlink = function unlink(path, callback) {
}; };
FileSystem.prototype.getxattr = function getxattr(path, name) { FileSystem.prototype.getxattr = function getxattr(path, name, callback) {
}; };
FileSystem.prototype.setxattr = function setxattr(path, name, value) { FileSystem.prototype.setxattr = function setxattr(path, name, value, callback) {
}; };
FileSystem.prototype.read = function read(fd, buffer, offset, length, position) { FileSystem.prototype.read = function read(fd, buffer, offset, length, position, callback) {
var deferred = when.defer(); var deferred = when.defer();
var transaction = this.db.transaction([FILE_STORE_NAME], IDB_RW); var transaction = this.db.transaction([FILE_STORE_NAME], IDB_RW);
var files = transaction.objectStore(FILE_STORE_NAME); var files = transaction.objectStore(FILE_STORE_NAME);
@ -722,6 +796,7 @@ define(function(require) {
function check_result(error, nbytes) { function check_result(error, nbytes) {
if(error) { if(error) {
// if(transaction.error) transaction.abort();
deferred.reject(error); deferred.reject(error);
} else { } else {
deferred.resolve(nbytes); deferred.resolve(nbytes);
@ -742,7 +817,7 @@ define(function(require) {
return deferred.promise; return deferred.promise;
}; };
FileSystem.prototype.write = function write(fd, buffer, offset, length, position) { FileSystem.prototype.write = function write(fd, buffer, offset, length, position, callback) {
var deferred = when.defer(); var deferred = when.defer();
var transaction = this.db.transaction([FILE_STORE_NAME], IDB_RW); var transaction = this.db.transaction([FILE_STORE_NAME], IDB_RW);
var files = transaction.objectStore(FILE_STORE_NAME); var files = transaction.objectStore(FILE_STORE_NAME);

View File

@ -1,15 +1,130 @@
var TEST_DATABASE_NAME = 'test'; var TEST_DATABASE_NAME = 'test';
var DEFAULT_TIMEOUT = 5000;
describe("file system", function() { var next_id = 1;
function mk_db_name() {
return TEST_DATABASE_NAME + next_id++;
};
describe("IDBFS", function() {
it("is defined", function() {
expect(typeof IDBFS).not.toEqual(undefined);
});
it("has FileSystem constructor", function() {
expect(typeof IDBFS.FileSystem).toEqual('function');
});
});
describe("new fs", function() {
beforeEach(function() { beforeEach(function() {
this.fs = new IDBFS.FileSystem(TEST_DATABASE_NAME, 'FORMAT'); this.db_name = mk_db_name();
this.fs = new IDBFS.FileSystem(this.db_name, 'FORMAT');
}); });
afterEach(function() { afterEach(function() {
indexedDB.deleteDatabase(TEST_DATABASE_NAME); indexedDB.deleteDatabase(this.db_name);
delete this.fs;
}); });
it("is created", function() { it("is an object", function() {
expect(typeof this.fs).toEqual('object'); expect(typeof this.fs).toEqual('object');
}); });
var api_methods = [
"mkdir",
"rmdir",
"readdir",
"link",
"unlink",
"open",
"close",
"read",
"write",
"setxattr",
"getxattr",
"stat",
"fstat",
];
api_methods.forEach(function(method) {
it("has method " + method, function() {
expect(typeof this.fs[method]).toEqual('function');
});
});
it('should have a root directory', function() {
var complete = false;
var _error, _result;
this.fs.stat('/', function(error, result) {
_error = error;
_result = result;
complete = true;
});
waitsFor(function() {
return complete;
}, 'stat to complete', DEFAULT_TIMEOUT);
runs(function() {
expect(_result).toBeDefined();
});
});
});
describe('stat', 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;
});
describe('on path that does not exist', function() {
it('should return an error', function() {
var complete = false;
var _error, _result;
this.fs.stat('/tmp', function(error, result) {
_error = error;
_result = result;
complete = true;
});
waitsFor(function() {
return complete;
}, 'stat to complete', DEFAULT_TIMEOUT);
runs(function() {
expect(_error).toBeDefined();
});
});
it('should not return a result', function() {
var complete = false;
var _error, _result;
this.fs.stat('/tmp', function(error, result) {
jasmine.log(error, result);
_error = error;
_result = result;
complete = true;
});
waitsFor(function() {
return complete;
}, 'stat to complete', DEFAULT_TIMEOUT);
runs(function() {
expect(_result).not.toBeDefined();
});
});
});
}); });