- Remove the remaining __USE_W32API, deprecated for ages.
[reactos.git] / reactos / base / shell / cmd / attrib.c
1 /*
2 * ATTRIB.C - attrib internal command.
3 *
4 *
5 * History:
6 *
7 * 04-Dec-1998 Eric Kohl
8 * started
9 *
10 * 09-Dec-1998 Eric Kohl
11 * implementation works, except recursion ("attrib /s").
12 *
13 * 05-Jan-1999 Eric Kohl
14 * major rewrite.
15 * fixed recursion ("attrib /s").
16 * started directory support ("attrib /s /d").
17 * updated help text.
18 *
19 * 14-Jan-1999 Eric Kohl
20 * Unicode ready!
21 *
22 * 19-Jan-1999 Eric Kohl
23 * Redirection ready!
24 *
25 * 21-Jan-1999 Eric Kohl
26 * Added check for invalid filenames.
27 *
28 * 23-Jan-1999 Eric Kohl
29 * Added handling of multiple filenames.
30 *
31 * 02-Apr-2005 (Magnus Olsen) <magnus@greatlord.com>)
32 * Remove all hardcode string to En.rc
33 */
34
35 #include <precomp.h>
36
37 #ifdef INCLUDE_CMD_ATTRIB
38
39
40 static VOID
41 PrintAttribute (LPTSTR pszPath, LPTSTR pszFile, BOOL bRecurse)
42 {
43 WIN32_FIND_DATA findData;
44 HANDLE hFind;
45 TCHAR szFullName[MAX_PATH];
46 LPTSTR pszFileName;
47
48 /* prepare full file name buffer */
49 _tcscpy (szFullName, pszPath);
50 pszFileName = szFullName + _tcslen (szFullName);
51
52 /* display all subdirectories */
53 if (bRecurse)
54 {
55 /* append file name */
56 _tcscpy (pszFileName, pszFile);
57
58 hFind = FindFirstFile (szFullName, &findData);
59 if (hFind == INVALID_HANDLE_VALUE)
60 {
61 ErrorMessage (GetLastError (), pszFile);
62 return;
63 }
64
65 do
66 {
67 if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
68 continue;
69
70 if (!_tcscmp (findData.cFileName, _T(".")) ||
71 !_tcscmp (findData.cFileName, _T("..")))
72 continue;
73
74 _tcscpy (pszFileName, findData.cFileName);
75 _tcscat (pszFileName, _T("\\"));
76 PrintAttribute (szFullName, pszFile, bRecurse);
77 }
78 while (FindNextFile (hFind, &findData));
79 FindClose (hFind);
80 }
81
82 /* append file name */
83 _tcscpy (pszFileName, pszFile);
84
85 /* display current directory */
86 hFind = FindFirstFile (szFullName, &findData);
87 if (hFind == INVALID_HANDLE_VALUE)
88 {
89 ErrorMessage (GetLastError (), pszFile);
90 return;
91 }
92
93 do
94 {
95 if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
96 continue;
97
98 _tcscpy (pszFileName, findData.cFileName);
99
100 ConOutPrintf (_T("%c %c%c%c %s\n"),
101 (findData.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) ? _T('A') : _T(' '),
102 (findData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) ? _T('S') : _T(' '),
103 (findData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ? _T('H') : _T(' '),
104 (findData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? _T('R') : _T(' '),
105 szFullName);
106 }
107 while (FindNextFile (hFind, &findData));
108 FindClose (hFind);
109 }
110
111
112 static VOID
113 ChangeAttribute (LPTSTR pszPath, LPTSTR pszFile, DWORD dwMask,
114 DWORD dwAttrib, BOOL bRecurse, BOOL bDirectories)
115 {
116 WIN32_FIND_DATA findData;
117 HANDLE hFind;
118 DWORD dwAttribute;
119 TCHAR szFullName[MAX_PATH];
120 LPTSTR pszFileName;
121
122
123 /* prepare full file name buffer */
124 _tcscpy (szFullName, pszPath);
125 pszFileName = szFullName + _tcslen (szFullName);
126
127 /* change all subdirectories */
128 if (bRecurse)
129 {
130 /* append file name */
131 _tcscpy (pszFileName, _T("*.*"));
132
133 hFind = FindFirstFile (szFullName, &findData);
134 if (hFind == INVALID_HANDLE_VALUE)
135 {
136 ErrorMessage (GetLastError (), pszFile);
137 nErrorLevel = 1;
138 return;
139 }
140
141 do
142 {
143 if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
144 {
145 if (!_tcscmp (findData.cFileName, _T(".")) ||
146 !_tcscmp (findData.cFileName, _T("..")))
147 continue;
148
149 _tcscpy (pszFileName, findData.cFileName);
150 _tcscat (pszFileName, _T("\\"));
151
152 ChangeAttribute (szFullName, pszFile, dwMask,
153 dwAttrib, bRecurse, bDirectories);
154 }
155 }
156 while (FindNextFile (hFind, &findData));
157 FindClose (hFind);
158 }
159
160 /* append file name */
161 _tcscpy (pszFileName, pszFile);
162
163 hFind = FindFirstFile (szFullName, &findData);
164 if (hFind == INVALID_HANDLE_VALUE)
165 {
166 ErrorMessage (GetLastError (), pszFile);
167 nErrorLevel = 1;
168 return;
169 }
170
171 do
172 {
173 if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
174 continue;
175
176 _tcscpy (pszFileName, findData.cFileName);
177
178 dwAttribute = GetFileAttributes (szFullName);
179
180 if (dwAttribute != 0xFFFFFFFF)
181 {
182 dwAttribute = (dwAttribute & ~dwMask) | dwAttrib;
183 SetFileAttributes (szFullName, dwAttribute);
184 }
185 }
186 while (FindNextFile (hFind, &findData));
187 FindClose (hFind);
188 }
189
190
191 INT CommandAttrib (LPTSTR param)
192 {
193 LPTSTR *arg;
194 INT argc, i;
195 TCHAR szPath[MAX_PATH];
196 TCHAR szFileName [MAX_PATH];
197 BOOL bRecurse = FALSE;
198 BOOL bDirectories = FALSE;
199 DWORD dwAttrib = 0;
200 DWORD dwMask = 0;
201
202 /* initialize strings */
203 szPath[0] = _T('\0');
204 szFileName[0] = _T('\0');
205
206 /* print help */
207 if (!_tcsncmp (param, _T("/?"), 2))
208 {
209 ConOutResPaging(TRUE,STRING_ATTRIB_HELP);
210 return 0;
211 }
212
213 nErrorLevel = 0;
214
215 /* build parameter array */
216 arg = split (param, &argc, FALSE);
217
218 /* check for options */
219 for (i = 0; i < argc; i++)
220 {
221 if (_tcsicmp (arg[i], _T("/s")) == 0)
222 bRecurse = TRUE;
223 else if (_tcsicmp (arg[i], _T("/d")) == 0)
224 bDirectories = TRUE;
225 }
226
227 /* create attributes and mask */
228 for (i = 0; i < argc; i++)
229 {
230 if (*arg[i] == _T('+'))
231 {
232 if (_tcslen (arg[i]) != 2)
233 {
234 error_invalid_parameter_format (arg[i]);
235 freep (arg);
236 return -1;
237 }
238
239 switch ((TCHAR)_totupper (arg[i][1]))
240 {
241 case _T('A'):
242 dwMask |= FILE_ATTRIBUTE_ARCHIVE;
243 dwAttrib |= FILE_ATTRIBUTE_ARCHIVE;
244 break;
245
246 case _T('H'):
247 dwMask |= FILE_ATTRIBUTE_HIDDEN;
248 dwAttrib |= FILE_ATTRIBUTE_HIDDEN;
249 break;
250
251 case _T('R'):
252 dwMask |= FILE_ATTRIBUTE_READONLY;
253 dwAttrib |= FILE_ATTRIBUTE_READONLY;
254 break;
255
256 case _T('S'):
257 dwMask |= FILE_ATTRIBUTE_SYSTEM;
258 dwAttrib |= FILE_ATTRIBUTE_SYSTEM;
259 break;
260
261 default:
262 error_invalid_parameter_format (arg[i]);
263 freep (arg);
264 return -1;
265 }
266 }
267 else if (*arg[i] == _T('-'))
268 {
269 if (_tcslen (arg[i]) != 2)
270 {
271 error_invalid_parameter_format (arg[i]);
272 freep (arg);
273 return -1;
274 }
275
276 switch ((TCHAR)_totupper (arg[i][1]))
277 {
278 case _T('A'):
279 dwMask |= FILE_ATTRIBUTE_ARCHIVE;
280 dwAttrib &= ~FILE_ATTRIBUTE_ARCHIVE;
281 break;
282
283 case _T('H'):
284 dwMask |= FILE_ATTRIBUTE_HIDDEN;
285 dwAttrib &= ~FILE_ATTRIBUTE_HIDDEN;
286 break;
287
288 case _T('R'):
289 dwMask |= FILE_ATTRIBUTE_READONLY;
290 dwAttrib &= ~FILE_ATTRIBUTE_READONLY;
291 break;
292
293 case _T('S'):
294 dwMask |= FILE_ATTRIBUTE_SYSTEM;
295 dwAttrib &= ~FILE_ATTRIBUTE_SYSTEM;
296 break;
297
298 default:
299 error_invalid_parameter_format (arg[i]);
300 freep (arg);
301 return -1;
302 }
303 }
304 }
305
306 if (argc == 0)
307 {
308 DWORD len;
309
310 len = GetCurrentDirectory (MAX_PATH, szPath);
311 if (szPath[len-1] != _T('\\'))
312 {
313 szPath[len] = _T('\\');
314 szPath[len + 1] = 0;
315 }
316 _tcscpy (szFileName, _T("*.*"));
317 PrintAttribute (szPath, szFileName, bRecurse);
318 freep (arg);
319 return 0;
320 }
321
322 /* get full file name */
323 for (i = 0; i < argc; i++)
324 {
325 if ((*arg[i] != _T('+')) && (*arg[i] != _T('-')) && (*arg[i] != _T('/')))
326 {
327 LPTSTR p;
328 GetFullPathName (arg[i], MAX_PATH, szPath, NULL);
329 p = _tcsrchr (szPath, _T('\\')) + 1;
330 _tcscpy (szFileName, p);
331 *p = _T('\0');
332
333 if (dwMask == 0)
334 PrintAttribute (szPath, szFileName, bRecurse);
335 else
336 ChangeAttribute (szPath, szFileName, dwMask,
337 dwAttrib, bRecurse, bDirectories);
338 }
339 }
340
341 freep (arg);
342 return 0;
343 }
344
345 #endif /* INCLUDE_CMD_ATTRIB */