index.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. /**
  2. * Module exports.
  3. */
  4. module.exports = Mode;
  5. /**
  6. * Constants (defined in `stat.h`).
  7. */
  8. var S_IFMT = 61440; /* 0170000 type of file */
  9. var S_IFIFO = 4096; /* 0010000 named pipe (fifo) */
  10. var S_IFCHR = 8192; /* 0020000 character special */
  11. var S_IFDIR = 16384; /* 0040000 directory */
  12. var S_IFBLK = 24576; /* 0060000 block special */
  13. var S_IFREG = 32768; /* 0100000 regular */
  14. var S_IFLNK = 40960; /* 0120000 symbolic link */
  15. var S_IFSOCK = 49152; /* 0140000 socket */
  16. var S_IFWHT = 57344; /* 0160000 whiteout */
  17. var S_ISUID = 2048; /* 0004000 set user id on execution */
  18. var S_ISGID = 1024; /* 0002000 set group id on execution */
  19. var S_ISVTX = 512; /* 0001000 save swapped text even after use */
  20. var S_IRUSR = 256; /* 0000400 read permission, owner */
  21. var S_IWUSR = 128; /* 0000200 write permission, owner */
  22. var S_IXUSR = 64; /* 0000100 execute/search permission, owner */
  23. var S_IRGRP = 32; /* 0000040 read permission, group */
  24. var S_IWGRP = 16; /* 0000020 write permission, group */
  25. var S_IXGRP = 8; /* 0000010 execute/search permission, group */
  26. var S_IROTH = 4; /* 0000004 read permission, others */
  27. var S_IWOTH = 2; /* 0000002 write permission, others */
  28. var S_IXOTH = 1; /* 0000001 execute/search permission, others */
  29. /**
  30. * `Mode` class.
  31. *
  32. * @param {fs.Stat} stat a "stat" object (anything with a `mode` Number property)
  33. * @api public
  34. */
  35. function Mode (stat) {
  36. if (!(this instanceof Mode)) return new Mode(stat);
  37. if (!stat) throw new TypeError('must pass in a "stat" object');
  38. if ('number' != typeof stat.mode) stat.mode = 0;
  39. this.stat = stat;
  40. this.owner = new Owner(stat);
  41. this.group = new Group(stat);
  42. this.others = new Others(stat);
  43. }
  44. /**
  45. * Returns the Number value of the `mode`.
  46. *
  47. * @return {Number}
  48. * @api public
  49. */
  50. Mode.prototype.valueOf = function () {
  51. return this.stat.mode;
  52. };
  53. /**
  54. * Returns a String representation of the `mode`.
  55. * The output resembles something similiar to what `ls -l` would output.
  56. *
  57. * http://en.wikipedia.org/wiki/Unix_file_types
  58. *
  59. * @return {String}
  60. * @api public
  61. */
  62. Mode.prototype.toString = function () {
  63. var str = [];
  64. // file type
  65. if (this.isDirectory()) {
  66. str.push('d');
  67. } else if (this.isFile()) {
  68. str.push('-');
  69. } else if (this.isBlockDevice()) {
  70. str.push('b');
  71. } else if (this.isCharacterDevice()) {
  72. str.push('c');
  73. } else if (this.isSymbolicLink()) {
  74. str.push('l');
  75. } else if (this.isFIFO()) {
  76. str.push('p');
  77. } else if (this.isSocket()) {
  78. str.push('s');
  79. } else {
  80. throw new TypeError('unexpected "file type"');
  81. }
  82. // owner read, write, execute
  83. str.push(this.owner.read ? 'r' : '-');
  84. str.push(this.owner.write ? 'w' : '-');
  85. if (this.setuid) {
  86. str.push(this.owner.execute ? 's' : 'S');
  87. } else {
  88. str.push(this.owner.execute ? 'x' : '-');
  89. }
  90. // group read, write, execute
  91. str.push(this.group.read ? 'r' : '-');
  92. str.push(this.group.write ? 'w' : '-');
  93. if (this.setgid) {
  94. str.push(this.group.execute ? 's' : 'S');
  95. } else {
  96. str.push(this.group.execute ? 'x' : '-');
  97. }
  98. // others read, write, execute
  99. str.push(this.others.read ? 'r' : '-');
  100. str.push(this.others.write ? 'w' : '-');
  101. if (this.sticky) {
  102. str.push(this.others.execute ? 't' : 'T');
  103. } else {
  104. str.push(this.others.execute ? 'x' : '-');
  105. }
  106. return str.join('');
  107. };
  108. /**
  109. * Returns an octal representation of the `mode`, eg. "0754".
  110. *
  111. * http://en.wikipedia.org/wiki/File_system_permissions#Numeric_notation
  112. *
  113. * @return {String}
  114. * @api public
  115. */
  116. Mode.prototype.toOctal = function () {
  117. var octal = this.stat.mode & 4095 /* 07777 */;
  118. return ('0000' + octal.toString(8)).slice(-4);
  119. };
  120. Mode.prototype._checkModeProperty = function (property, set) {
  121. var mode = this.stat.mode;
  122. if (set) {
  123. this.stat.mode = (mode | S_IFMT) & property | mode & ~S_IFMT;
  124. }
  125. return (mode & S_IFMT) === property;
  126. };
  127. Mode.prototype.isDirectory = function (v) {
  128. return this._checkModeProperty(S_IFDIR, v);
  129. };
  130. Mode.prototype.isFile = function (v) {
  131. return this._checkModeProperty(S_IFREG, v);
  132. };
  133. Mode.prototype.isBlockDevice = function (v) {
  134. return this._checkModeProperty(S_IFBLK, v);
  135. };
  136. Mode.prototype.isCharacterDevice = function (v) {
  137. return this._checkModeProperty(S_IFCHR, v);
  138. };
  139. Mode.prototype.isSymbolicLink = function (v) {
  140. return this._checkModeProperty(S_IFLNK, v);
  141. };
  142. Mode.prototype.isFIFO = function (v) {
  143. return this._checkModeProperty(S_IFIFO, v);
  144. };
  145. Mode.prototype.isSocket = function (v) {
  146. return this._checkModeProperty(S_IFSOCK, v);
  147. };
  148. _define(Mode.prototype, 'setuid',
  149. function () {
  150. return Boolean(this.stat.mode & S_ISUID);
  151. },
  152. function (v) {
  153. if (v) {
  154. this.stat.mode |= S_ISUID;
  155. } else {
  156. this.stat.mode &= ~S_ISUID;
  157. }
  158. }
  159. );
  160. _define(Mode.prototype, 'setgid',
  161. function () {
  162. return Boolean(this.stat.mode & S_ISGID);
  163. },
  164. function (v) {
  165. if (v) {
  166. this.stat.mode |= S_ISGID;
  167. } else {
  168. this.stat.mode &= ~S_ISGID;
  169. }
  170. }
  171. );
  172. _define(Mode.prototype, 'sticky',
  173. function () {
  174. return Boolean(this.stat.mode & S_ISVTX);
  175. },
  176. function (v) {
  177. if (v) {
  178. this.stat.mode |= S_ISVTX;
  179. } else {
  180. this.stat.mode &= ~S_ISVTX;
  181. }
  182. }
  183. );
  184. function Owner (stat) {
  185. _define(this, 'read',
  186. function () {
  187. return Boolean(stat.mode & S_IRUSR);
  188. },
  189. function (v) {
  190. if (v) {
  191. stat.mode |= S_IRUSR;
  192. } else {
  193. stat.mode &= ~S_IRUSR;
  194. }
  195. }
  196. );
  197. _define(this, 'write',
  198. function () {
  199. return Boolean(stat.mode & S_IWUSR);
  200. },
  201. function (v) {
  202. if (v) {
  203. stat.mode |= S_IWUSR;
  204. } else {
  205. stat.mode &= ~S_IWUSR;
  206. }
  207. }
  208. );
  209. _define(this, 'execute',
  210. function () {
  211. return Boolean(stat.mode & S_IXUSR);
  212. },
  213. function (v) {
  214. if (v) {
  215. stat.mode |= S_IXUSR;
  216. } else {
  217. stat.mode &= ~S_IXUSR;
  218. }
  219. }
  220. );
  221. }
  222. function Group (stat) {
  223. _define(this, 'read',
  224. function () {
  225. return Boolean(stat.mode & S_IRGRP);
  226. },
  227. function (v) {
  228. if (v) {
  229. stat.mode |= S_IRGRP;
  230. } else {
  231. stat.mode &= ~S_IRGRP;
  232. }
  233. }
  234. );
  235. _define(this, 'write',
  236. function () {
  237. return Boolean(stat.mode & S_IWGRP);
  238. },
  239. function (v) {
  240. if (v) {
  241. stat.mode |= S_IWGRP;
  242. } else {
  243. stat.mode &= ~S_IWGRP;
  244. }
  245. }
  246. );
  247. _define(this, 'execute',
  248. function () {
  249. return Boolean(stat.mode & S_IXGRP);
  250. },
  251. function (v) {
  252. if (v) {
  253. stat.mode |= S_IXGRP;
  254. } else {
  255. stat.mode &= ~S_IXGRP;
  256. }
  257. }
  258. );
  259. }
  260. function Others (stat) {
  261. _define(this, 'read',
  262. function () {
  263. return Boolean(stat.mode & S_IROTH);
  264. },
  265. function (v) {
  266. if (v) {
  267. stat.mode |= S_IROTH;
  268. } else {
  269. stat.mode &= ~S_IROTH;
  270. }
  271. }
  272. );
  273. _define(this, 'write',
  274. function () {
  275. return Boolean(stat.mode & S_IWOTH);
  276. },
  277. function (v) {
  278. if (v) {
  279. stat.mode |= S_IWOTH;
  280. } else {
  281. stat.mode &= ~S_IWOTH;
  282. }
  283. }
  284. );
  285. _define(this, 'execute',
  286. function () {
  287. return Boolean(stat.mode & S_IXOTH);
  288. },
  289. function (v) {
  290. if (v) {
  291. stat.mode |= S_IXOTH;
  292. } else {
  293. stat.mode &= ~S_IXOTH;
  294. }
  295. }
  296. );
  297. }
  298. function _define (obj, name, get, set) {
  299. Object.defineProperty(obj, name, {
  300. enumerable: true,
  301. configurable: true,
  302. get: get,
  303. set: set
  304. });
  305. }