OpenHue MCP Server

var common = require('./common'); var fs = require('fs'); var path = require('path'); var PERMS = (function (base) { return { OTHER_EXEC: base.EXEC, OTHER_WRITE: base.WRITE, OTHER_READ: base.READ, GROUP_EXEC: base.EXEC << 3, GROUP_WRITE: base.WRITE << 3, GROUP_READ: base.READ << 3, OWNER_EXEC: base.EXEC << 6, OWNER_WRITE: base.WRITE << 6, OWNER_READ: base.READ << 6, // Literal octal numbers are apparently not allowed in "strict" javascript. STICKY: parseInt('01000', 8), SETGID: parseInt('02000', 8), SETUID: parseInt('04000', 8), TYPE_MASK: parseInt('0770000', 8), }; }({ EXEC: 1, WRITE: 2, READ: 4, })); common.register('chmod', _chmod, { }); //@ //@ ### chmod([options,] octal_mode || octal_string, file) //@ ### chmod([options,] symbolic_mode, file) //@ //@ Available options: //@ //@ + `-v`: output a diagnostic for every file processed//@ //@ + `-c`: like verbose, but report only when a change is made//@ //@ + `-R`: change files and directories recursively//@ //@ //@ Examples: //@ //@ ```javascript //@ chmod(755, '/Users/brandon'); //@ chmod('755', '/Users/brandon'); // same as above //@ chmod('u+x', '/Users/brandon'); //@ chmod('-R', 'a-w', '/Users/brandon'); //@ ``` //@ //@ Alters the permissions of a file or directory by either specifying the //@ absolute permissions in octal form or expressing the changes in symbols. //@ This command tries to mimic the POSIX behavior as much as possible. //@ Notable exceptions: //@ //@ + In symbolic modes, `a-r` and `-r` are identical. No consideration is //@ given to the `umask`. //@ + There is no "quiet" option, since default behavior is to run silent. function _chmod(options, mode, filePattern) { if (!filePattern) { if (options.length > 0 && options.charAt(0) === '-') { // Special case where the specified file permissions started with - to subtract perms, which // get picked up by the option parser as command flags. // If we are down by one argument and options starts with -, shift everything over. [].unshift.call(arguments, ''); } else { common.error('You must specify a file.'); } } options = common.parseOptions(options, { 'R': 'recursive', 'c': 'changes', 'v': 'verbose', }); filePattern = [].slice.call(arguments, 2); var files; // TODO: replace this with a call to common.expand() if (options.recursive) { files = []; filePattern.forEach(function addFile(expandedFile) { var stat = common.statNoFollowLinks(expandedFile); if (!stat.isSymbolicLink()) { files.push(expandedFile); if (stat.isDirectory()) { // intentionally does not follow symlinks. fs.readdirSync(expandedFile).forEach(function (child) { addFile(expandedFile + '/' + child); }); } } }); } else { files = filePattern; } files.forEach(function innerChmod(file) { file = path.resolve(file); if (!fs.existsSync(file)) { common.error('File not found: ' + file); } // When recursing, don't follow symlinks. if (options.recursive && common.statNoFollowLinks(file).isSymbolicLink()) { return; } var stat = common.statFollowLinks(file); var isDir = stat.isDirectory(); var perms = stat.mode; var type = perms & PERMS.TYPE_MASK; var newPerms = perms; if (isNaN(parseInt(mode, 8))) { // parse options mode.split(',').forEach(function (symbolicMode) { var pattern = /([ugoa]*)([=\+-])([rwxXst]*)/i; var matches = pattern.exec(symbolicMode); if (matches) { var applyTo = matches[1]; var operator = matches[2]; var change = matches[3]; var changeOwner = applyTo.indexOf('u') !== -1 || applyTo === 'a' || applyTo === ''; var changeGroup = applyTo.indexOf('g') !== -1 || applyTo === 'a' || applyTo === ''; var changeOther = applyTo.indexOf('o') !== -1 || applyTo === 'a' || applyTo === ''; var changeRead = change.indexOf('r') !== -1; var changeWrite = change.indexOf('w') !== -1; var changeExec = change.indexOf('x') !== -1; var changeExecDir = change.indexOf('X') !== -1; var changeSticky = change.indexOf('t') !== -1; var changeSetuid = change.indexOf('s') !== -1; if (changeExecDir && isDir) { changeExec = true; } var mask = 0; if (changeOwner) { mask |= (changeRead ? PERMS.OWNER_READ : 0) + (changeWrite ? PERMS.OWNER_WRITE : 0) + (changeExec ? PERMS.OWNER_EXEC : 0) + (changeSetuid ? PERMS.SETUID : 0); } if (changeGroup) { mask |= (changeRead ? PERMS.GROUP_READ : 0) + (changeWrite ? PERMS.GROUP_WRITE : 0) + (changeExec ? PERMS.GROUP_EXEC : 0) + (changeSetuid ? PERMS.SETGID : 0); } if (changeOther) { mask |= (changeRead ? PERMS.OTHER_READ : 0) + (changeWrite ? PERMS.OTHER_WRITE : 0) + (changeExec ? PERMS.OTHER_EXEC : 0); } // Sticky bit is special - it's not tied to user, group or other. if (changeSticky) { mask |= PERMS.STICKY; } switch (operator) { case '+': newPerms |= mask; break; case '-': newPerms &= ~mask; break; case '=': newPerms = type + mask; // According to POSIX, when using = to explicitly set the // permissions, setuid and setgid can never be cleared. if (common.statFollowLinks(file).isDirectory()) { newPerms |= (PERMS.SETUID + PERMS.SETGID) & perms; } break; default: common.error('Could not recognize operator: `' + operator + '`'); } if (options.verbose) { console.log(file + ' -> ' + newPerms.toString(8)); } if (perms !== newPerms) { if (!options.verbose && options.changes) { console.log(file + ' -> ' + newPerms.toString(8)); } fs.chmodSync(file, newPerms); perms = newPerms; // for the next round of changes! } } else { common.error('Invalid symbolic mode change: ' + symbolicMode); } }); } else { // they gave us a full number newPerms = type + parseInt(mode, 8); // POSIX rules are that setuid and setgid can only be added using numeric // form, but not cleared. if (common.statFollowLinks(file).isDirectory()) { newPerms |= (PERMS.SETUID + PERMS.SETGID) & perms; } fs.chmodSync(file, newPerms); } }); return ''; } module.exports = _chmod;