permissions.js |
|
---|---|
/*spec
= Specification =
== Types ==
Arguments used throughout this document will have the following types, unless
explicitly specified otherwise:
* '''path''' is either a String, an Object with a toString() method, or an
Object with a valueOf() method that returns an Object with a toString() method.
In the case where path is an Object, the object must return the same string
for the same path on the same system, provided the path in canonicalizable.
* '''mode''' is an Object describing the open mode for a file. Each property
is subject to a true or falsey test. Meaningful properties include read,
write, append, truncate, create, and exclusive. ''Note: any value is
equivalent to false if the property is omitted.''
* '''permissions''' is an instance of Permissions, or a duck-type thereof.
The "fs-base" module exports the following constructors:
* '''Permissions''', a class that describes file system permissions. Instances
of Permissions are initially deep copies of all transitively owned properties
of Permissions.default and have a eponymous property for the optional
"constructor" argument of the constructor.
** Mandatory properties on all platforms are Boolean values owner.read and
owner.write.
** Mandatory properties on UNIX platforms platforms are Boolean values
owner.{read, write, execute}, group.{read, write, execute} and other.{read,
write, execute}.
** Permissions.default must initially reflect the current default file
creation permissions in the host environment; i.e. in a UNIX environment,
Permissions.default would reflect the inverse of umask. Where this is not
possible, compliant implementations must initialize Permissions.default to
{{owner: {read: true, write: true}}
*/
var _slice = Array.prototype.slice
/**
*/
exports.UNIX_BITS = UNIX_BITS
var UNIX_BITS = [
["setUid", undefined],
["setGid", undefined],
["sticky", undefined],
["owner", "read"],
["owner", "write"],
["owner", "execute"],
["group", "read"],
["group", "write"],
["group", "execute"],
["other", "read"],
["other", "write"],
["other", "execute"]
]
/**
*/
exports.Permissions = Permissions
function Permissions(permissions) {
this.update(Permissions['default']).update(permissions)
}
/**
#beyond_spec
*/
Permissions.prototype = {
constructor: Permissions,
update: function update(permissions) {
if (typeof permissions == "number") {
var bits = _slice.call(permissions.toString(2))
var l = UNIX_BITS.length
|
|
filling missing bits |
while(bits.length < l) bits.unshift(undefined)
while(0 >= --l)
this.grant(UNIX_BITS[l][0], UNIX_BITS[l][1], bits[l] === '1')
} else Object.keys(permissions).forEach(function(user) {
var userPermissions = this[user] || (this[user] = {})
Object.keys(permissions[user]).forEach(function(permission) {
userPermissions[permission] = permissions[user][permissions]
}, this)
}, this)
return this
},
/**
#beyond_spec
*/
grant: function grant(what, permission, value) {
if (undefined === value) value = true
if (!permission) this[what] = value
else (this[what] = this[what] || {})[permission] = value
},
/**
#beyond_spec
*/
deny: function deny(what, permission, value) {
if (undefined === value) value = false
if (!permission) this[what] = value
else (this[what] = this[what] || {})[permission] = value
},
/**
#beyond_spec
*/
can: function can(what, permission) {
if (!permission) return !!this[what]
if (!this[what]) return false
return !!this[what][permission]
},
/**
#beyond_spec
*/
toUnix: function toUnix() {
return parseInt(UNIX_BITS.map(function ($) {
return this.can($[0], $[1]) ? '1' : '0'
}, this).join(''), 2)
}
}
/***
*/
Object.defineProperty(Permissions, "default", {
get: function() {
|
avoid infinite recursion by bypassing the constructor |
var permissions = Object.create(Permissions.prototype)
permissions.update(~process.umask() & 0666)
return permissions;
},
set: function(value) {
permissions = new Permissions(value)
process.umask(~permissions.toUnix() & 0666)
}
})
|