1 | var common = require('./common');
|
2 | var fs = require('fs');
|
3 | var path = require('path');
|
4 |
|
5 | var PERMS = (function (base) {
|
6 | return {
|
7 | OTHER_EXEC: base.EXEC,
|
8 | OTHER_WRITE: base.WRITE,
|
9 | OTHER_READ: base.READ,
|
10 |
|
11 | GROUP_EXEC: base.EXEC << 3,
|
12 | GROUP_WRITE: base.WRITE << 3,
|
13 | GROUP_READ: base.READ << 3,
|
14 |
|
15 | OWNER_EXEC: base.EXEC << 6,
|
16 | OWNER_WRITE: base.WRITE << 6,
|
17 | OWNER_READ: base.READ << 6,
|
18 |
|
19 |
|
20 | STICKY: parseInt('01000', 8),
|
21 | SETGID: parseInt('02000', 8),
|
22 | SETUID: parseInt('04000', 8),
|
23 |
|
24 | TYPE_MASK: parseInt('0770000', 8),
|
25 | };
|
26 | }({
|
27 | EXEC: 1,
|
28 | WRITE: 2,
|
29 | READ: 4,
|
30 | }));
|
31 |
|
32 | common.register('chmod', _chmod, {
|
33 | });
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 |
|
56 |
|
57 |
|
58 |
|
59 |
|
60 |
|
61 |
|
62 | function _chmod(options, mode, filePattern) {
|
63 | if (!filePattern) {
|
64 | if (options.length > 0 && options.charAt(0) === '-') {
|
65 |
|
66 |
|
67 |
|
68 | [].unshift.call(arguments, '');
|
69 | } else {
|
70 | common.error('You must specify a file.');
|
71 | }
|
72 | }
|
73 |
|
74 | options = common.parseOptions(options, {
|
75 | 'R': 'recursive',
|
76 | 'c': 'changes',
|
77 | 'v': 'verbose',
|
78 | });
|
79 |
|
80 | filePattern = [].slice.call(arguments, 2);
|
81 |
|
82 | var files;
|
83 |
|
84 |
|
85 | if (options.recursive) {
|
86 | files = [];
|
87 | filePattern.forEach(function addFile(expandedFile) {
|
88 | var stat = common.statNoFollowLinks(expandedFile);
|
89 |
|
90 | if (!stat.isSymbolicLink()) {
|
91 | files.push(expandedFile);
|
92 |
|
93 | if (stat.isDirectory()) {
|
94 | fs.readdirSync(expandedFile).forEach(function (child) {
|
95 | addFile(expandedFile + '/' + child);
|
96 | });
|
97 | }
|
98 | }
|
99 | });
|
100 | } else {
|
101 | files = filePattern;
|
102 | }
|
103 |
|
104 | files.forEach(function innerChmod(file) {
|
105 | file = path.resolve(file);
|
106 | if (!fs.existsSync(file)) {
|
107 | common.error('File not found: ' + file);
|
108 | }
|
109 |
|
110 |
|
111 | if (options.recursive && common.statNoFollowLinks(file).isSymbolicLink()) {
|
112 | return;
|
113 | }
|
114 |
|
115 | var stat = common.statFollowLinks(file);
|
116 | var isDir = stat.isDirectory();
|
117 | var perms = stat.mode;
|
118 | var type = perms & PERMS.TYPE_MASK;
|
119 |
|
120 | var newPerms = perms;
|
121 |
|
122 | if (isNaN(parseInt(mode, 8))) {
|
123 |
|
124 | mode.split(',').forEach(function (symbolicMode) {
|
125 | var pattern = /([ugoa]*)([=\+-])([rwxXst]*)/i;
|
126 | var matches = pattern.exec(symbolicMode);
|
127 |
|
128 | if (matches) {
|
129 | var applyTo = matches[1];
|
130 | var operator = matches[2];
|
131 | var change = matches[3];
|
132 |
|
133 | var changeOwner = applyTo.indexOf('u') !== -1 || applyTo === 'a' || applyTo === '';
|
134 | var changeGroup = applyTo.indexOf('g') !== -1 || applyTo === 'a' || applyTo === '';
|
135 | var changeOther = applyTo.indexOf('o') !== -1 || applyTo === 'a' || applyTo === '';
|
136 |
|
137 | var changeRead = change.indexOf('r') !== -1;
|
138 | var changeWrite = change.indexOf('w') !== -1;
|
139 | var changeExec = change.indexOf('x') !== -1;
|
140 | var changeExecDir = change.indexOf('X') !== -1;
|
141 | var changeSticky = change.indexOf('t') !== -1;
|
142 | var changeSetuid = change.indexOf('s') !== -1;
|
143 |
|
144 | if (changeExecDir && isDir) {
|
145 | changeExec = true;
|
146 | }
|
147 |
|
148 | var mask = 0;
|
149 | if (changeOwner) {
|
150 | mask |= (changeRead ? PERMS.OWNER_READ : 0) + (changeWrite ? PERMS.OWNER_WRITE : 0) + (changeExec ? PERMS.OWNER_EXEC : 0) + (changeSetuid ? PERMS.SETUID : 0);
|
151 | }
|
152 | if (changeGroup) {
|
153 | mask |= (changeRead ? PERMS.GROUP_READ : 0) + (changeWrite ? PERMS.GROUP_WRITE : 0) + (changeExec ? PERMS.GROUP_EXEC : 0) + (changeSetuid ? PERMS.SETGID : 0);
|
154 | }
|
155 | if (changeOther) {
|
156 | mask |= (changeRead ? PERMS.OTHER_READ : 0) + (changeWrite ? PERMS.OTHER_WRITE : 0) + (changeExec ? PERMS.OTHER_EXEC : 0);
|
157 | }
|
158 |
|
159 |
|
160 | if (changeSticky) {
|
161 | mask |= PERMS.STICKY;
|
162 | }
|
163 |
|
164 | switch (operator) {
|
165 | case '+':
|
166 | newPerms |= mask;
|
167 | break;
|
168 |
|
169 | case '-':
|
170 | newPerms &= ~mask;
|
171 | break;
|
172 |
|
173 | case '=':
|
174 | newPerms = type + mask;
|
175 |
|
176 |
|
177 |
|
178 | if (common.statFollowLinks(file).isDirectory()) {
|
179 | newPerms |= (PERMS.SETUID + PERMS.SETGID) & perms;
|
180 | }
|
181 | break;
|
182 | default:
|
183 | common.error('Could not recognize operator: `' + operator + '`');
|
184 | }
|
185 |
|
186 | if (options.verbose) {
|
187 | console.log(file + ' -> ' + newPerms.toString(8));
|
188 | }
|
189 |
|
190 | if (perms !== newPerms) {
|
191 | if (!options.verbose && options.changes) {
|
192 | console.log(file + ' -> ' + newPerms.toString(8));
|
193 | }
|
194 | fs.chmodSync(file, newPerms);
|
195 | perms = newPerms;
|
196 | }
|
197 | } else {
|
198 | common.error('Invalid symbolic mode change: ' + symbolicMode);
|
199 | }
|
200 | });
|
201 | } else {
|
202 |
|
203 | newPerms = type + parseInt(mode, 8);
|
204 |
|
205 |
|
206 |
|
207 | if (common.statFollowLinks(file).isDirectory()) {
|
208 | newPerms |= (PERMS.SETUID + PERMS.SETGID) & perms;
|
209 | }
|
210 |
|
211 | fs.chmodSync(file, newPerms);
|
212 | }
|
213 | });
|
214 | return '';
|
215 | }
|
216 | module.exports = _chmod;
|