changed behaviour to allow falsy values (ie. empty string), added more test cases and modified README.md

This commit is contained in:
Barry Tulchinsky 2013-12-22 20:58:00 -05:00
parent 55c08e6f08
commit 7ae907cd5b
3 changed files with 460 additions and 20 deletions

View File

@ -344,3 +344,27 @@ Asynchronous utimes(3). Callback gets no additional arguments.
#### fs.futimes(fd, atime, mtime, callback)
Asynchronous futimes(3). Callback gets no additional arguments.
#### fs.setxattr(path, name, value, [flag], callback)
Asynchronous setxattr(2). Sets an extended attribute of a file or directory.
The optional flag parameter can be set to the following:
XATTR_CREATE: ensures that the extended attribute with the given name will be new and not previously set. If an attribute with the given name already exists, it will return EExists error to the callback.
XATTR_REPLACE: ensures that an extended attribute with the given name already exists. If an attribute with the given name does not exist, it will return an ENoAttr error to the callback.
Callback gets no additional arguments.
#### fs.getxattr(path, name, callback)
Asynchronous getxattr(2). Gets an extended attribute value for a file or directory.
Callback gets `(error, value)`, where value is the value for the extended attribute.
#### fs.fsetxattr(fd, name, value, [flag], callback)
Asynchronous fsetxattr(2). See `fs.setxattr` for flag options. Callback gets no additional arguments.
#### fs.fgetxattr(fs, name, callback)
Asynchronous fgetxattr(2). Callback gets `(error, value)`, See `fs.getxattr`.

166
src/fs.js
View File

@ -1123,15 +1123,18 @@ define(function(require) {
function setxattr_file (context, path, name, value, flag, callback) {
path = normalize(path);
var undefined;
function set_xattr (error, node) {
var xattr = (node ? node.xattrs[name] : null);
if (error) {
callback (error);
}
else if (flag === XATTR_CREATE && node.xattrs[name]) {
else if (flag === XATTR_CREATE && (xattr != null || xattr != undefined)) {
callback(new EExists('attribute already exists'));
}
else if (flag === XATTR_REPLACE && !node.xattrs[name]) {
else if (flag === XATTR_REPLACE && (xattr == null || xattr == undefined)) {
callback(new ENoAttr('attribute does not exist'));
}
else {
@ -1146,10 +1149,11 @@ define(function(require) {
else if (!name) {
callback(new EInvalid('attribute name cannot be an empty string'));
}
else if (!value) {
callback(new EInvalid('value cannot be empty'));
else if (value == null || value == undefined) {
callback(new EInvalid('value cannot be null or undefined'));
}
else if (!!flag && flag !== XATTR_CREATE && flag !== XATTR_REPLACE) {
else if ((flag != null || flag != undefined) &&
flag !== XATTR_CREATE && flag !== XATTR_REPLACE) {
callback(new EInvalid('invalid flag, must be null, XATTR_CREATE or XATTR_REPLACE'));
}
else {
@ -1157,14 +1161,56 @@ define(function(require) {
}
}
function fsetxattr_file (context, ofd, name, value, flag, callback) {
var undefined;
function set_xattr (error, node) {
var xattr = (node ? node.xattrs[name] : null);
if (error) {
callback(error);
}
else if (flag === XATTR_CREATE && (xattr != null || xattr != undefined)) {
callback(new EExists('attribute already exists'));
}
else if (flag === XATTR_REPLACE && (xattr == null || xattr == undefined)) {
callback(new ENoAttr('attribute does not exist'));
}
else {
node.xattrs[name] = value;
context.put(node.id, node, callback);
}
}
if (typeof name != 'string') {
callback(new EInvalid('attribute name must be a string'));
}
else if (!name) {
callback(new EInvalid('attribute name cannot be an empty string'));
}
else if (value == null || value == undefined) {
callback(new EInvalid('value cannot be empty'));
}
else if ((flag != null || flag != undefined) &&
flag !== XATTR_CREATE && flag !== XATTR_REPLACE) {
callback(new EInvalid('invalid flag, must be null, XATTR_CREATE or XATTR_REPLACE'));
}
else {
context.get(ofd.id, set_xattr);
}
}
function getxattr_file (context, path, name, callback) {
path = normalize(path);
var undefined;
function get_xattr(error, node) {
var xattr = (node ? node.xattrs[name] : null);
if (error) {
callback (error);
}
else if (!node.xattrs[name]) {
else if (xattr == null || xattr == undefined) {
callback(new ENoAttr('attribute does not exist'));
}
else {
@ -1183,6 +1229,34 @@ define(function(require) {
}
}
function fgetxattr_file (context, ofd, name, callback) {
var undefined;
function get_xattr (error, node) {
var xattr = (node ? node.xattrs[name] : null);
if (error) {
callback(error);
}
else if (xattr == null || xattr == undefined) {
callback(new ENoAttr('attribute does not exist'));
}
else {
callback(null, node.xattrs[name]);
}
}
if (typeof name != 'string') {
callback(new EInvalid('attribute name must be a string'));
}
else if (!name) {
callback(new EInvalid('attribute name cannot be an empty string'));
}
else {
context.get(ofd.id, get_xattr);
}
}
function validate_flags(flags) {
if(!_(O_FLAGS).has(flags)) {
return null;
@ -1596,10 +1670,10 @@ define(function(require) {
});
}
function _getxattr(context, path, name, callback) {
if(!nullCheck(path, callback)) return;
function _getxattr (context, path, name, callback) {
if (!nullCheck(path, callback)) return;
function fetch_value(error, value) {
function fetch_value (error, value) {
if (error) {
callback(error);
}
@ -1611,8 +1685,29 @@ define(function(require) {
getxattr_file(context, path, name, fetch_value);
}
function _setxattr(context, path, name, value, flag, callback) {
if(!nullCheck(path, callback)) return;
function _fgetxattr (fs, context, fd, name, callback) {
function get_result (error, value) {
if (error) {
callback(error);
}
else {
callback(null, value);
}
}
var ofd = fs.openFiles[fd];
if (!ofd) {
callback(new EBadFileDescriptor('invalid file descriptor'));
}
else {
fgetxattr_file(context, ofd, name, get_result);
}
}
function _setxattr (context, path, name, value, flag, callback) {
if (!nullCheck(path, callback)) return;
function check_result (error) {
if (error) {
@ -1626,6 +1721,29 @@ define(function(require) {
setxattr_file(context, path, name, value, flag, check_result);
}
function _fsetxattr (fs, context, fd, name, value, flag, callback) {
function check_result (error) {
if (error) {
callback(error);
}
else {
callback(null);
}
}
var ofd = fs.openFiles[fd];
if (!ofd) {
callback(new EBadFileDescriptor('invalid file descriptor'));
}
else if (!_(ofd.flags).contains(O_WRITE)) {
callback(new EBadFileDescriptor('descriptor does not permit writing'));
}
else {
fsetxattr_file(context, ofd, name, value, flag, check_result);
}
}
function _lseek(fs, context, fd, offset, whence, callback) {
function check_result(error, offset) {
if(error) {
@ -2116,6 +2234,32 @@ define(function(require) {
callback(error);
}
};
FileSystem.prototype.fsetxattr = function (fd, name, value, flag, callback) {
var callback = maybeCallback(arguments[arguments.length - 1]);
var _flag = (typeof flag != 'function') ? flag : null;
var fs = this;
var error = fs.queueOrRun(
function () {
var context = fs.provider.getReadWriteContext();
_fsetxattr(fs, context, fd, name, value, _flag, callback);
}
);
if (error) {
callback(error);
}
};
FileSystem.prototype.fgetxattr = function (fd, name, callback) {
callback = maybeCallback(callback);
var fs = this;
var error = fs.queueOrRun(
function () {
var context = fs.provider.getReadWriteContext();
_fgetxattr(fs, context, fd, name, callback);
}
);
};
return FileSystem;
});

View File

@ -67,7 +67,7 @@ define(["IDBFS"], function(IDBFS) {
});
});
it('should error when setting with a falsy value', function () {
it('should error when setting with a null value', function () {
var complete = false;
var _error;
var that = this;
@ -75,7 +75,7 @@ define(["IDBFS"], function(IDBFS) {
that.fs.writeFile('/testfile', '', function (error) {
if (error) throw error;
that.fs.setxattr('/testfile', 'test', '', function (error) {
that.fs.setxattr('/testfile', 'test', null, function (error) {
_error = error;
complete = true;
});
@ -167,7 +167,7 @@ define(["IDBFS"], function(IDBFS) {
});
});
it ('should error when getting an attribute with a falsy name', function (error) {
it ('should error when getting an attribute with a name that is empty', function (error) {
var complete = false;
var _error;
var that = this;
@ -191,17 +191,15 @@ define(["IDBFS"], function(IDBFS) {
});
});
it('should error when getting an attribute when a name is not a string', function (error) {
it('should error when getting an attribute where the name is not a string', function (error) {
var complete = false;
var _error;
// var that = this;
var that = this;
var fs = this.fs;
fs.writeFile('/testfile', '', function (error) {
that.fs.writeFile('/testfile', '', function (error) {
if (error) throw error;
fs.getxattr('/testfile', 89, function (error, value) {
that.fs.getxattr('/testfile', 89, function (error, value) {
_error = error;
complete = true;
});
@ -216,5 +214,279 @@ define(["IDBFS"], function(IDBFS) {
expect(_error.name).toEqual('EInvalid');
});
});
it('should error when getting an attribute that does not exist', function (error) {
var complete = false;
var _error;
var that = this;
that.fs.writeFile('/testfile', '', function (error) {
if (error) throw error;
that.fs.getxattr('/testfile', 'test', function (error, value) {
_error = error;
complete = true;
});
});
waitsFor(function () {
return complete;
}, 'test to complete', DEFAULT_TIMEOUT);
runs(function () {
expect(_error).toBeDefined();
expect(_error.name).toEqual('ENoAttr');
});
});
it('should error when file descriptor is invalid', function (error) {
var completeSet, completeGet;
var _errorSet, _errorGet;
var that = this;
var _value;
completeSet = completeGet = false;
that.fs.fsetxattr(1, 'test', 'value', function (error) {
_errorSet = error;
completeSet = true;
});
that.fs.fgetxattr(1, 'test', function (error, value) {
_errorGet = error;
_value = value;
completeGet = true;
});
waitsFor(function () {
return completeSet && completeGet;
}, 'test to complete', DEFAULT_TIMEOUT);
runs(function () {
expect(_value).toEqual(null);
expect(_errorSet).toBeDefined();
expect(_errorSet.name).toEqual('EBadFileDescriptor');
expect(_errorGet).toBeDefined();
expect(_errorGet.name).toEqual('EBadFileDescriptor');
});
});
it('should set and get an extended attribute of a path', function (error) {
var complete = false;
var _errorSet;
var that = this;
var name = 'test';
var _value;;
that.fs.writeFile('/testfile', '', function (error) {
if (error) throw error;
that.fs.setxattr('/testfile', name, 'somevalue', function (error) {
_errorSet = error;
that.fs.getxattr('/testfile', name, function (error, value) {
_errorGet = error;
_value = value;
complete = true;
});
});
});
waitsFor(function () {
return complete;
}, 'test to complete', DEFAULT_TIMEOUT);
runs(function () {
expect(_errorSet).toEqual(null);
expect(_errorGet).toEqual(null);
expect(_value).toEqual('somevalue');
});
});
it('should set and get an empty string as a value', function (error) {
var complete = false;
var _error;
var _value;
var that = this;
that.fs.writeFile('/testfile', '', function (error) {
if (error) throw error;
that.fs.setxattr('/testfile', 'test', '', function (error) {
_error = error;
that.fs.getxattr('/testfile', 'test', function (error, value) {
_error = error;
_value = value;
complete = true;
});
});
});
waitsFor(function () {
return complete;
}, 'test to complete', DEFAULT_TIMEOUT);
runs(function () {
expect(_error).toEqual(null);
expect(_value).toBeDefined();
expect(_value).toEqual('');
});
});
it('should set and get an extended attribute for a valid file descriptor', function (error) {
var complete = false;
var _errorSet, _errorGet;
var _value;
var that = this;
var ofd;
that.fs.open('/testfile', 'w', function (error, result) {
if (error) throw error;
ofd = result;
that.fs.fsetxattr(ofd, 'test', 'value', function (error) {
_errorSet = error;
that.fs.fgetxattr(ofd, 'test', function (error, value) {
_errorGet = error;
_value = value;
complete = true;
});
});
});
waitsFor(function () {
return complete;
}, 'test to complete', DEFAULT_TIMEOUT);
runs(function () {
expect(_errorSet).toEqual(null);
expect(_errorGet).toEqual(null);
expect(_value).toBeDefined();
expect(_value).toEqual('value');
});
});
it('should set/get an object to an extended attribute', function (error) {
var complete = false;
var _error;
var that = this;
var value;
that.fs.writeFile('/testfile', '', function (error) {
if (error) throw error;
that.fs.setxattr('/testfile', 'test', { key1: 'test', key2: 'value', key3: 87 }, function (error) {
_error = error;
that.fs.getxattr('/testfile', 'test', function (error, value) {
_error = error;
_value = value;
complete = true;
});
});
});
waitsFor(function () {
return complete;
}, 'test to complete', DEFAULT_TIMEOUT);
runs(function () {
expect(_error).toEqual(null);
expect(_value).toEqual({ key1: 'test', key2: 'value', key3: 87 });
});
});
it('should update/overwrite an existing extended attribute', function (error) {
var complete = false;
var _error;
var that = this;
var _value1, _value2, _value3;
that.fs.writeFile('/testfile', '', function (error) {
if (error) throw error;
that.fs.setxattr('/testfile', 'test', 'value', function (error) {
_error = error;
that.fs.getxattr('/testfile', 'test', function (error, value) {
_error = error;
_value1 = value;
that.fs.setxattr('/testfile', 'test', { o: 'object', t: 'test' }, function (error) {
_error = error;
that.fs.getxattr('/testfile', 'test', function (error, value) {
_error = error;
_value2 = value;
that.fs.setxattr('/testfile', 'test', 100, 'REPLACE', function (error) {
_error = error;
that.fs.getxattr('/testfile', 'test', function (error, value) {
_error = error;
_value3 = value;
complete = true;
});
});
});
});
});
})
});
waitsFor(function () {
return complete;
}, 'test to complete' , DEFAULT_TIMEOUT);
runs(function () {
expect(_error).toEqual(null);
expect(_value1).toEqual('value');
expect(_value2).toEqual({ o: 'object', t: 'test' });
expect(_value3).toEqual(100);
});
});
it('should set multiple extended attributes for a path', function (error) {
var complete = false;
var _error;
var that = this;
var _value1, _value2;
that.fs.writeFile('/testfile', '', function (error) {
if (error) throw error;
that.fs.setxattr('/testfile', 'test', 89, function (error) {
_error = error;
that.fs.setxattr('/testfile', 'other', 'attribute', function (error) {
_error = error;
that.fs.getxattr('/testfile', 'test', function (error, value) {
_error = error;
_value1 = value;
that.fs.getxattr('/testfile', 'other', function (error, value) {
_error = error;
_value2 = value;
complete = true;
});
});
});
});
});
waitsFor(function () {
return complete;
}, 'test to complete', DEFAULT_TIMEOUT);
runs(function () {
expect(_error).toEqual(null);
expect(_value1).toEqual(89);
expect(_value2).toEqual('attribute');
});
});
});
});