ReactOS 0.4.15-dev-5884-gab5aff5
attrib.c
Go to the documentation of this file.
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 <stdio.h>
36#include <stdlib.h>
37
38#include <windef.h>
39#include <winbase.h>
40#include <wincon.h>
41#include <winuser.h>
42
43#include <conutils.h>
44
45#include "resource.h"
46
48
49static
50VOID
52 DWORD dwErrorCode,
53 LPWSTR szFormat,
54 ...)
55{
57 WCHAR szMessage[1024];
58 LPWSTR szError;
59 va_list arg_ptr;
60
61 if (dwErrorCode == ERROR_SUCCESS)
62 return;
63
64 if (szFormat)
65 {
66 va_start(arg_ptr, szFormat);
67 vswprintf(szMessage, szFormat, arg_ptr);
68 va_end(arg_ptr);
69 }
70
73 (LPWSTR)&szError, 0, NULL))
74 {
75 ConPrintf(StdOut, L"%s %s\n", szError, szMessage);
76 if (szError)
77 LocalFree(szError);
78 return;
79 }
80
81 /* Fall back just in case the error is not defined */
83 if (szFormat)
84 ConPrintf(StdOut, L"%s -- %s\n", szMsg, szMessage);
85 else
86 ConPrintf(StdOut, L"%s\n", szMsg);
87}
88
89/* Returns TRUE if anything is printed, FALSE otherwise */
90static
91BOOL
93 LPWSTR pszPath,
94 LPWSTR pszFile,
95 BOOL bRecurse,
96 BOOL bDirectories)
97{
98 WIN32_FIND_DATAW findData;
99 HANDLE hFind;
100 WCHAR szFullName[MAX_PATH];
102 BOOL bFound = FALSE;
103 BOOL bIsDir;
104 BOOL bExactMatch;
105 DWORD Error;
106
107 /* prepare full file name buffer */
108 wcscpy(szFullName, pszPath);
109 pszFileName = szFullName + wcslen(szFullName);
110
111 /* display all subdirectories */
112 if (bRecurse)
113 {
114 /* append *.* */
115 wcscpy(pszFileName, L"*.*");
116
117 hFind = FindFirstFileW(szFullName, &findData);
118 if (hFind == INVALID_HANDLE_VALUE)
119 {
123 {
124 ErrorMessage(Error, pszFile);
125 }
126 return FALSE;
127 }
128
129 do
130 {
131 if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
132 continue;
133
134 if (!wcscmp(findData.cFileName, L".") ||
135 !wcscmp(findData.cFileName, L".."))
136 {
137 continue;
138 }
139
140 wcscpy(pszFileName, findData.cFileName);
141 wcscat(pszFileName, L"\\");
142 bFound |= PrintAttribute(szFullName, pszFile, bRecurse, bDirectories);
143 }
144 while (FindNextFileW(hFind, &findData));
145 FindClose(hFind);
146 }
147
148 /* append file name */
149 wcscpy(pszFileName, pszFile);
150
151 /* search current directory */
152 hFind = FindFirstFileW(szFullName, &findData);
153 if (hFind == INVALID_HANDLE_VALUE)
154 {
155 return bFound;
156 }
157
158 do
159 {
160 bIsDir = findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
161 bExactMatch = wcsicmp(findData.cFileName, pszFile) == 0;
162
163 if (bIsDir && !bDirectories && !bExactMatch)
164 continue;
165
166 if (!wcscmp(findData.cFileName, L".") ||
167 !wcscmp(findData.cFileName, L".."))
168 {
169 continue;
170 }
171
172 wcscpy(pszFileName, findData.cFileName);
173
175 L"%c %c%c%c %s\n",
176 (findData.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) ? L'A' : L' ',
177 (findData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) ? L'S' : L' ',
178 (findData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ? L'H' : L' ',
179 (findData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? L'R' : L' ',
180 szFullName);
181 bFound = TRUE;
182 }
183 while (FindNextFileW(hFind, &findData));
184 FindClose(hFind);
185
186 return bFound;
187}
188
189
190/* Returns TRUE if anything changed, FALSE otherwise */
191static
192BOOL
194 LPWSTR pszPath,
195 LPWSTR pszFile,
196 BOOL bRecurse,
197 BOOL bDirectories,
198 DWORD dwMask,
199 DWORD dwAttrib)
200{
201 WIN32_FIND_DATAW findData;
202 HANDLE hFind;
203 WCHAR szFullName[MAX_PATH];
205 BOOL bFound = FALSE;
206 BOOL bIsDir;
207 BOOL bExactMatch;
208 DWORD dwAttribute;
209 DWORD Error;
210
211 /* prepare full file name buffer */
212 wcscpy(szFullName, pszPath);
213 pszFileName = szFullName + wcslen(szFullName);
214
215 /* display all subdirectories */
216 if (bRecurse)
217 {
218 /* append *.* */
219 wcscpy(pszFileName, L"*.*");
220
221 hFind = FindFirstFileW(szFullName, &findData);
222 if (hFind == INVALID_HANDLE_VALUE)
223 {
227 {
228 ErrorMessage(Error, pszFile);
229 }
230 return FALSE;
231 }
232
233 do
234 {
235 if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
236 continue;
237
238 if (!wcscmp(findData.cFileName, L".") ||
239 !wcscmp(findData.cFileName, L".."))
240 {
241 continue;
242 }
243
244 wcscpy(pszFileName, findData.cFileName);
245 wcscat(pszFileName, L"\\");
246 bFound |= ChangeAttribute(szFullName, pszFile, bRecurse, bDirectories,
247 dwMask, dwAttrib);
248 }
249 while (FindNextFileW(hFind, &findData));
250 FindClose(hFind);
251 }
252
253 /* append file name */
254 wcscpy(pszFileName, pszFile);
255
256 /* search current directory */
257 hFind = FindFirstFileW(szFullName, &findData);
258 if (hFind == INVALID_HANDLE_VALUE)
259 {
260 return bFound;
261 }
262
263 do
264 {
265 bIsDir = findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
266 bExactMatch = wcsicmp(findData.cFileName, pszFile) == 0;
267
268 if (bIsDir && !bDirectories && !bExactMatch)
269 continue;
270
271 if (!wcscmp(findData.cFileName, L".") ||
272 !wcscmp(findData.cFileName, L".."))
273 {
274 continue;
275 }
276
277 if (bRecurse && bIsDir && !bDirectories)
278 continue;
279
280 wcscpy(pszFileName, findData.cFileName);
281
282 dwAttribute = (findData.dwFileAttributes & ~dwMask) | dwAttrib;
283
284 SetFileAttributes(szFullName, dwAttribute);
285 bFound = TRUE;
286 }
287 while (FindNextFileW(hFind, &findData));
288 FindClose(hFind);
289
290 return bFound;
291}
292
293int wmain(int argc, WCHAR *argv[])
294{
295 INT i;
296 WCHAR szPath[MAX_PATH] = L""; // For case we only use 'attrib +h /s' there is no szPath
297 WCHAR szFileName [MAX_PATH];
298 BOOL bRecurse = FALSE;
299 BOOL bDirectories = FALSE;
300 DWORD dwAttrib = 0;
301 DWORD dwMask = 0;
302 LPWSTR p;
303
304 /* Initialize the Console Standard Streams */
306
307 /* Print help */
308 if (argc > 1 && wcscmp(argv[1], L"/?") == 0)
309 {
311 return 0;
312 }
313
314 /* check for options */
315 for (i = 1; i < argc; i++)
316 {
317 if (wcsicmp(argv[i], L"/s") == 0)
318 bRecurse = TRUE;
319 else if (wcsicmp(argv[i], L"/d") == 0)
320 bDirectories = TRUE;
321 }
322
323 /* create attributes and mask */
324 for (i = 1; i < argc; i++)
325 {
326 if (*argv[i] == L'+')
327 {
328 if (wcslen(argv[i]) != 2)
329 {
331 return -1;
332 }
333
334 switch (towupper(argv[i][1]))
335 {
336 case L'A':
337 dwMask |= FILE_ATTRIBUTE_ARCHIVE;
338 dwAttrib |= FILE_ATTRIBUTE_ARCHIVE;
339 break;
340
341 case L'H':
342 dwMask |= FILE_ATTRIBUTE_HIDDEN;
343 dwAttrib |= FILE_ATTRIBUTE_HIDDEN;
344 break;
345
346 case L'R':
347 dwMask |= FILE_ATTRIBUTE_READONLY;
348 dwAttrib |= FILE_ATTRIBUTE_READONLY;
349 break;
350
351 case L'S':
352 dwMask |= FILE_ATTRIBUTE_SYSTEM;
353 dwAttrib |= FILE_ATTRIBUTE_SYSTEM;
354 break;
355
356 default:
358 return -1;
359 }
360 }
361 else if (*argv[i] == L'-')
362 {
363 if (wcslen(argv[i]) != 2)
364 {
366 return -1;
367 }
368
369 switch (towupper(argv[i][1]))
370 {
371 case L'A':
372 dwMask |= FILE_ATTRIBUTE_ARCHIVE;
373 dwAttrib &= ~FILE_ATTRIBUTE_ARCHIVE;
374 break;
375
376 case L'H':
377 dwMask |= FILE_ATTRIBUTE_HIDDEN;
378 dwAttrib &= ~FILE_ATTRIBUTE_HIDDEN;
379 break;
380
381 case L'R':
382 dwMask |= FILE_ATTRIBUTE_READONLY;
383 dwAttrib &= ~FILE_ATTRIBUTE_READONLY;
384 break;
385
386 case L'S':
387 dwMask |= FILE_ATTRIBUTE_SYSTEM;
388 dwAttrib &= ~FILE_ATTRIBUTE_SYSTEM;
389 break;
390
391 default:
393 return -1;
394 }
395 }
396 }
397
398 if (argc == 1)
399 {
400 DWORD len;
401
403 if (szPath[len-1] != L'\\')
404 {
405 szPath[len] = L'\\';
406 szPath[len + 1] = UNICODE_NULL;
407 }
408 wcscpy(szFileName, L"*.*");
409 PrintAttribute(szPath, szFileName, bRecurse, bDirectories);
410 return 0;
411 }
412
413 /* get full file name */
414 for (i = 1; i < argc; i++)
415 {
416 if (*argv[i] == L'+' || *argv[i] == L'-' || *argv[i] == L'/')
417 continue;
418
420 wcscpy(szFileName, p);
421 *p = 0;
422
423 if (dwMask == 0)
424 {
425 if (!PrintAttribute(szPath, szFileName, bRecurse, bDirectories))
426 {
428 }
429 }
430 else if (!ChangeAttribute(szPath, szFileName, bRecurse, bDirectories, dwMask, dwAttrib))
431 {
433 }
434 }
435
436// Code below handles the special case of 'attrib +h /s' and similar
437
438 if (bRecurse && dwMask && (wcscmp(szPath, L"") == 0))
439 {
440 DWORD len;
441
443 if (szPath[len-1] != L'\\')
444 {
445 szPath[len] = L'\\';
446 szPath[len + 1] = UNICODE_NULL;
447 }
448 wcscpy(szFileName, L"*.*");
449 if (!ChangeAttribute(szPath, szFileName, bRecurse, bDirectories, dwMask, dwAttrib))
451 }
452
453 return 0;
454}
static int argc
Definition: ServiceArgs.c:12
char * va_list
Definition: acmsvcex.h:78
#define va_end(ap)
Definition: acmsvcex.h:90
#define va_start(ap, A)
Definition: acmsvcex.h:91
static BOOL PrintAttribute(LPWSTR pszPath, LPWSTR pszFile, BOOL bRecurse, BOOL bDirectories)
Definition: attrib.c:92
CON_SCREEN StdOutScreen
Definition: attrib.c:47
static BOOL ChangeAttribute(LPWSTR pszPath, LPWSTR pszFile, BOOL bRecurse, BOOL bDirectories, DWORD dwMask, DWORD dwAttrib)
Definition: attrib.c:193
static VOID ErrorMessage(DWORD dwErrorCode, LPWSTR szFormat,...)
Definition: attrib.c:51
#define STRING_ATTRIB_HELP
Definition: resource.h:7
#define RC_STRING_MAX_SIZE
Definition: resource.h:3
#define STRING_ERROR_INVALID_PARAM_FORMAT
Definition: resource.h:5
#define STRING_CONSOLE_ERROR
Definition: resource.h:6
#define STRING_FILE_NOT_FOUND
Definition: resource.h:8
#define ConInitStdStreams()
Definition: fc.c:13
void ConPrintf(FILE *fp, LPCWSTR psz,...)
Definition: fc.c:20
#define StdOut
Definition: fc.c:14
void ConResPrintf(FILE *fp, UINT nID,...)
Definition: fc.c:33
void ConResPuts(FILE *fp, UINT nID)
Definition: fc.c:27
BOOL Error
Definition: chkdsk.c:66
#define ERROR_SUCCESS
Definition: deptool.c:10
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define ARRAYSIZE(array)
Definition: filtermapper.c:47
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
#define MAX_PATH
Definition: compat.h:34
#define wcsicmp
Definition: compat.h:15
HANDLE WINAPI FindFirstFileW(IN LPCWSTR lpFileName, OUT LPWIN32_FIND_DATAW lpFindFileData)
Definition: find.c:320
BOOL WINAPI FindClose(HANDLE hFindFile)
Definition: find.c:502
BOOL WINAPI FindNextFileW(IN HANDLE hFindFile, OUT LPWIN32_FIND_DATAW lpFindFileData)
Definition: find.c:382
DWORD WINAPI GetFullPathNameW(IN LPCWSTR lpFileName, IN DWORD nBufferLength, OUT LPWSTR lpBuffer, OUT LPWSTR *lpFilePart)
Definition: path.c:1106
DWORD WINAPI FormatMessageW(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, __ms_va_list *args)
Definition: format_msg.c:583
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLfloat GLfloat p
Definition: glext.h:8902
GLenum GLsizei len
Definition: glext.h:6722
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
HLOCAL NTAPI LocalFree(HLOCAL hMem)
Definition: heapmem.c:1594
static _Check_return_opt_ int __cdecl vswprintf(_Out_writes_z_(_SizeInWords) wchar_t *_DstBuf, _In_ size_t _SizeInWords, _In_z_ _Printf_format_string_ const wchar_t *_Format, va_list _ArgList)
Definition: stdio.h:977
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define ERROR_FILE_NOT_FOUND
Definition: disk.h:79
LPCWSTR szPath
Definition: env.c:37
#define argv
Definition: mplay32.c:18
#define FILE_ATTRIBUTE_READONLY
Definition: nt_native.h:702
#define FILE_ATTRIBUTE_HIDDEN
Definition: nt_native.h:703
#define FILE_ATTRIBUTE_SYSTEM
Definition: nt_native.h:704
#define FILE_ATTRIBUTE_ARCHIVE
Definition: nt_native.h:706
#define FILE_ATTRIBUTE_DIRECTORY
Definition: nt_native.h:705
#define UNICODE_NULL
#define L(x)
Definition: ntvdm.h:50
int wmain()
#define INIT_CON_SCREEN(pStream)
Definition: screen.h:49
_CRTIMP wchar_t *__cdecl wcscpy(_Out_writes_z_(_String_length_(_Source)+1) wchar_t *_Dest, _In_z_ const wchar_t *_Source)
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
_CRTIMP wchar_t *__cdecl wcscat(_Inout_updates_z_(_String_length_(_Dest)+_String_length_(_Source)+1) wchar_t *_Dest, _In_z_ const wchar_t *_Source)
#define LANG_NEUTRAL
Definition: nls.h:22
#define MAKELANGID(p, s)
Definition: nls.h:15
#define SUBLANG_DEFAULT
Definition: nls.h:168
#define towupper(c)
Definition: wctype.h:99
int32_t INT
Definition: typedefs.h:58
WORD WORD PSZ PSZ pszFileName
Definition: vdmdbg.h:44
DWORD WINAPI GetLastError(void)
Definition: except.c:1040
#define GetModuleHandle
Definition: winbase.h:3698
#define FORMAT_MESSAGE_FROM_SYSTEM
Definition: winbase.h:423
#define SetFileAttributes
Definition: winbase.h:3780
#define FORMAT_MESSAGE_ALLOCATE_BUFFER
Definition: winbase.h:419
#define GetCurrentDirectory
Definition: winbase.h:3676
#define ERROR_SHARING_VIOLATION
Definition: winerror.h:135
#define ERROR_DIRECTORY
Definition: winerror.h:295
int WINAPI LoadStringW(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_writes_to_(cchBufferMax, return+1) LPWSTR lpBuffer, _In_ int cchBufferMax)
__wchar_t WCHAR
Definition: xmlstorage.h:180
WCHAR * LPWSTR
Definition: xmlstorage.h:184