Repositorio del curso CCOM4030 el semestre B91 del proyecto Artesanías con el Instituto de Cultura

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. var common = require('./common');
  2. var fs = require('fs');
  3. var path = require('path');
  4. var PERMS = (function (base) {
  5. return {
  6. OTHER_EXEC : base.EXEC,
  7. OTHER_WRITE : base.WRITE,
  8. OTHER_READ : base.READ,
  9. GROUP_EXEC : base.EXEC << 3,
  10. GROUP_WRITE : base.WRITE << 3,
  11. GROUP_READ : base.READ << 3,
  12. OWNER_EXEC : base.EXEC << 6,
  13. OWNER_WRITE : base.WRITE << 6,
  14. OWNER_READ : base.READ << 6,
  15. // Literal octal numbers are apparently not allowed in "strict" javascript. Using parseInt is
  16. // the preferred way, else a jshint warning is thrown.
  17. STICKY : parseInt('01000', 8),
  18. SETGID : parseInt('02000', 8),
  19. SETUID : parseInt('04000', 8),
  20. TYPE_MASK : parseInt('0770000', 8)
  21. };
  22. })({
  23. EXEC : 1,
  24. WRITE : 2,
  25. READ : 4
  26. });
  27. //@
  28. //@ ### chmod(octal_mode || octal_string, file)
  29. //@ ### chmod(symbolic_mode, file)
  30. //@
  31. //@ Available options:
  32. //@
  33. //@ + `-v`: output a diagnostic for every file processed//@
  34. //@ + `-c`: like verbose but report only when a change is made//@
  35. //@ + `-R`: change files and directories recursively//@
  36. //@
  37. //@ Examples:
  38. //@
  39. //@ ```javascript
  40. //@ chmod(755, '/Users/brandon');
  41. //@ chmod('755', '/Users/brandon'); // same as above
  42. //@ chmod('u+x', '/Users/brandon');
  43. //@ ```
  44. //@
  45. //@ Alters the permissions of a file or directory by either specifying the
  46. //@ absolute permissions in octal form or expressing the changes in symbols.
  47. //@ This command tries to mimic the POSIX behavior as much as possible.
  48. //@ Notable exceptions:
  49. //@
  50. //@ + In symbolic modes, 'a-r' and '-r' are identical. No consideration is
  51. //@ given to the umask.
  52. //@ + There is no "quiet" option since default behavior is to run silent.
  53. function _chmod(options, mode, filePattern) {
  54. if (!filePattern) {
  55. if (options.length > 0 && options.charAt(0) === '-') {
  56. // Special case where the specified file permissions started with - to subtract perms, which
  57. // get picked up by the option parser as command flags.
  58. // If we are down by one argument and options starts with -, shift everything over.
  59. filePattern = mode;
  60. mode = options;
  61. options = '';
  62. }
  63. else {
  64. common.error('You must specify a file.');
  65. }
  66. }
  67. options = common.parseOptions(options, {
  68. 'R': 'recursive',
  69. 'c': 'changes',
  70. 'v': 'verbose'
  71. });
  72. if (typeof filePattern === 'string') {
  73. filePattern = [ filePattern ];
  74. }
  75. var files;
  76. if (options.recursive) {
  77. files = [];
  78. common.expand(filePattern).forEach(function addFile(expandedFile) {
  79. var stat = fs.lstatSync(expandedFile);
  80. if (!stat.isSymbolicLink()) {
  81. files.push(expandedFile);
  82. if (stat.isDirectory()) { // intentionally does not follow symlinks.
  83. fs.readdirSync(expandedFile).forEach(function (child) {
  84. addFile(expandedFile + '/' + child);
  85. });
  86. }
  87. }
  88. });
  89. }
  90. else {
  91. files = common.expand(filePattern);
  92. }
  93. files.forEach(function innerChmod(file) {
  94. file = path.resolve(file);
  95. if (!fs.existsSync(file)) {
  96. common.error('File not found: ' + file);
  97. }
  98. // When recursing, don't follow symlinks.
  99. if (options.recursive && fs.lstatSync(file).isSymbolicLink()) {
  100. return;
  101. }
  102. var perms = fs.statSync(file).mode;
  103. var type = perms & PERMS.TYPE_MASK;
  104. var newPerms = perms;
  105. if (isNaN(parseInt(mode, 8))) {
  106. // parse options
  107. mode.split(',').forEach(function (symbolicMode) {
  108. /*jshint regexdash:true */
  109. var pattern = /([ugoa]*)([=\+-])([rwxXst]*)/i;
  110. var matches = pattern.exec(symbolicMode);
  111. if (matches) {
  112. var applyTo = matches[1];
  113. var operator = matches[2];
  114. var change = matches[3];
  115. var changeOwner = applyTo.indexOf('u') != -1 || applyTo === 'a' || applyTo === '';
  116. var changeGroup = applyTo.indexOf('g') != -1 || applyTo === 'a' || applyTo === '';
  117. var changeOther = applyTo.indexOf('o') != -1 || applyTo === 'a' || applyTo === '';
  118. var changeRead = change.indexOf('r') != -1;
  119. var changeWrite = change.indexOf('w') != -1;
  120. var changeExec = change.indexOf('x') != -1;
  121. var changeSticky = change.indexOf('t') != -1;
  122. var changeSetuid = change.indexOf('s') != -1;
  123. var mask = 0;
  124. if (changeOwner) {
  125. mask |= (changeRead ? PERMS.OWNER_READ : 0) + (changeWrite ? PERMS.OWNER_WRITE : 0) + (changeExec ? PERMS.OWNER_EXEC : 0) + (changeSetuid ? PERMS.SETUID : 0);
  126. }
  127. if (changeGroup) {
  128. mask |= (changeRead ? PERMS.GROUP_READ : 0) + (changeWrite ? PERMS.GROUP_WRITE : 0) + (changeExec ? PERMS.GROUP_EXEC : 0) + (changeSetuid ? PERMS.SETGID : 0);
  129. }
  130. if (changeOther) {
  131. mask |= (changeRead ? PERMS.OTHER_READ : 0) + (changeWrite ? PERMS.OTHER_WRITE : 0) + (changeExec ? PERMS.OTHER_EXEC : 0);
  132. }
  133. // Sticky bit is special - it's not tied to user, group or other.
  134. if (changeSticky) {
  135. mask |= PERMS.STICKY;
  136. }
  137. switch (operator) {
  138. case '+':
  139. newPerms |= mask;
  140. break;
  141. case '-':
  142. newPerms &= ~mask;
  143. break;
  144. case '=':
  145. newPerms = type + mask;
  146. // According to POSIX, when using = to explicitly set the permissions, setuid and setgid can never be cleared.
  147. if (fs.statSync(file).isDirectory()) {
  148. newPerms |= (PERMS.SETUID + PERMS.SETGID) & perms;
  149. }
  150. break;
  151. }
  152. if (options.verbose) {
  153. log(file + ' -> ' + newPerms.toString(8));
  154. }
  155. if (perms != newPerms) {
  156. if (!options.verbose && options.changes) {
  157. log(file + ' -> ' + newPerms.toString(8));
  158. }
  159. fs.chmodSync(file, newPerms);
  160. }
  161. }
  162. else {
  163. common.error('Invalid symbolic mode change: ' + symbolicMode);
  164. }
  165. });
  166. }
  167. else {
  168. // they gave us a full number
  169. newPerms = type + parseInt(mode, 8);
  170. // POSIX rules are that setuid and setgid can only be added using numeric form, but not cleared.
  171. if (fs.statSync(file).isDirectory()) {
  172. newPerms |= (PERMS.SETUID + PERMS.SETGID) & perms;
  173. }
  174. fs.chmodSync(file, newPerms);
  175. }
  176. });
  177. }
  178. module.exports = _chmod;