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