ReactOS  0.4.15-dev-4914-g2220e56
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 
49 static
50 VOID
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 */
90 static
91 BOOL
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  {
120  Error = GetLastError();
122  && (Error != ERROR_FILE_NOT_FOUND))
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 */
191 static
192 BOOL
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  {
224  Error = GetLastError();
226  && (Error != ERROR_FILE_NOT_FOUND))
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 
293 int 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 }
BOOL WINAPI FindNextFileW(IN HANDLE hFindFile, OUT LPWIN32_FIND_DATAW lpFindFileData)
Definition: find.c:382
static int argc
Definition: ServiceArgs.c:12
#define INIT_CON_SCREEN(pStream)
Definition: screen.h:49
#define ERROR_SUCCESS
Definition: deptool.c:10
#define STRING_CONSOLE_ERROR
Definition: resource.h:6
#define TRUE
Definition: types.h:120
#define FILE_ATTRIBUTE_SYSTEM
Definition: nt_native.h:704
#define LANG_NEUTRAL
Definition: nls.h:22
static VOID ErrorMessage(DWORD dwErrorCode, LPWSTR szFormat,...)
Definition: attrib.c:51
#define SUBLANG_DEFAULT
Definition: nls.h:168
#define ARRAYSIZE(array)
Definition: filtermapper.c:47
#define INVALID_HANDLE_VALUE
Definition: compat.h:590
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1040
DWORD WINAPI GetFullPathNameW(IN LPCWSTR lpFileName, IN DWORD nBufferLength, OUT LPWSTR lpBuffer, OUT LPWSTR *lpFilePart)
Definition: path.c:1106
#define argv
Definition: mplay32.c:18
DWORD WINAPI FormatMessageW(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, __ms_va_list *args)
Definition: format_msg.c:583
#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)
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
int32_t INT
Definition: typedefs.h:58
CON_SCREEN StdOutScreen
Definition: attrib.c:47
#define L(x)
Definition: ntvdm.h:50
#define va_end(ap)
Definition: acmsvcex.h:90
#define FALSE
Definition: types.h:117
#define UNICODE_NULL
unsigned int BOOL
Definition: ntddk_ex.h:94
WORD WORD PSZ PSZ pszFileName
Definition: vdmdbg.h:41
#define FORMAT_MESSAGE_ALLOCATE_BUFFER
Definition: winbase.h:416
#define GetCurrentDirectory
Definition: winbase.h:3666
#define STRING_ATTRIB_HELP
Definition: resource.h:7
#define STRING_ERROR_INVALID_PARAM_FORMAT
Definition: resource.h:5
char * va_list
Definition: acmsvcex.h:78
void ConResPuts(FILE *fp, UINT nID)
Definition: fc.c:27
#define ERROR_FILE_NOT_FOUND
Definition: disk.h:79
#define FORMAT_MESSAGE_FROM_SYSTEM
Definition: winbase.h:420
int wmain(int argc, WCHAR *argv[])
Definition: attrib.c:293
#define FILE_ATTRIBUTE_DIRECTORY
Definition: nt_native.h:705
void ConResPrintf(FILE *fp, UINT nID,...)
Definition: fc.c:33
#define SetFileAttributes
Definition: winbase.h:3770
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define MAX_PATH
Definition: compat.h:34
#define FILE_ATTRIBUTE_READONLY
Definition: nt_native.h:702
unsigned long DWORD
Definition: ntddk_ex.h:95
va_start(ap, x)
BOOL Error
Definition: chkdsk.c:66
#define FILE_ATTRIBUTE_ARCHIVE
Definition: nt_native.h:706
#define wcsicmp
Definition: compat.h:15
_CRTIMP wchar_t *__cdecl wcscpy(_Out_writes_z_(_String_length_(_Source)+1) wchar_t *_Dest, _In_z_ const wchar_t *_Source)
#define STRING_FILE_NOT_FOUND
Definition: resource.h:8
static BOOL ChangeAttribute(LPWSTR pszPath, LPWSTR pszFile, BOOL bRecurse, BOOL bDirectories, DWORD dwMask, DWORD dwAttrib)
Definition: attrib.c:193
GLenum GLsizei len
Definition: glext.h:6722
#define ERROR_SHARING_VIOLATION
Definition: winerror.h:135
void ConPrintf(FILE *fp, LPCWSTR psz,...)
Definition: fc.c:20
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
#define GetModuleHandle
Definition: winbase.h:3688
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
LPCWSTR szPath
Definition: env.c:37
HLOCAL NTAPI LocalFree(HLOCAL hMem)
Definition: heapmem.c:1577
_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 FILE_ATTRIBUTE_HIDDEN
Definition: nt_native.h:703
#define NULL
Definition: types.h:112
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define StdOut
Definition: fc.c:14
#define ConInitStdStreams()
Definition: fc.c:13
#define MAKELANGID(p, s)
Definition: nls.h:15
#define towupper(c)
Definition: wctype.h:99
GLfloat GLfloat p
Definition: glext.h:8902
WCHAR * LPWSTR
Definition: xmlstorage.h:184
static BOOL PrintAttribute(LPWSTR pszPath, LPWSTR pszFile, BOOL bRecurse, BOOL bDirectories)
Definition: attrib.c:92
HANDLE WINAPI FindFirstFileW(IN LPCWSTR lpFileName, OUT LPWIN32_FIND_DATAW lpFindFileData)
Definition: find.c:320
#define RC_STRING_MAX_SIZE
Definition: resource.h:3
BOOL WINAPI FindClose(HANDLE hFindFile)
Definition: find.c:502