https://git.reactos.org/?p=reactos.git;a=commitdiff;h=f83f650dd695cf6dbb849…
commit f83f650dd695cf6dbb8490588e9d63c4fe9cfafa
Author:     Doug Lyons <douglyons(a)douglyons.com>
AuthorDate: Sun Dec 8 09:24:28 2019 -0600
Commit:     Victor Perevertkin <victor(a)perevertkin.ru>
CommitDate: Tue Dec 28 02:03:54 2021 +0300
    attrib command improvements
---
 base/applications/cmdutils/attrib/attrib.c | 217 ++++++++++++++++-------------
 1 file changed, 117 insertions(+), 100 deletions(-)
diff --git a/base/applications/cmdutils/attrib/attrib.c
b/base/applications/cmdutils/attrib/attrib.c
index 4691821c3c6..0b226898185 100644
--- a/base/applications/cmdutils/attrib/attrib.c
+++ b/base/applications/cmdutils/attrib/attrib.c
@@ -86,17 +86,22 @@ ErrorMessage(
         ConPrintf(StdOut, L"%s\n", szMsg);
 }
+/* Returns TRUE if anything found and listed, FALSE otherwise */
 static
-INT
+BOOL
 PrintAttribute(
     LPWSTR pszPath,
     LPWSTR pszFile,
-    BOOL bRecurse)
+    BOOL  bRecurse,
+    BOOL  bDirectories)
 {
     WIN32_FIND_DATAW findData;
     HANDLE hFind;
     WCHAR  szFullName[MAX_PATH];
     LPWSTR pszFileName;
+    BOOL   bFound = FALSE;
+    BOOL   bIsDir;
+    BOOL   bExactMatch;
     /* prepare full file name buffer */
     wcscpy(szFullName, pszPath);
@@ -105,14 +110,16 @@ PrintAttribute(
     /* display all subdirectories */
     if (bRecurse)
     {
-        /* append file name */
-        wcscpy(pszFileName, pszFile);
+        /* append *.* */
+        wcscpy(pszFileName, L"*.*");
         hFind = FindFirstFileW(szFullName, &findData);
         if (hFind == INVALID_HANDLE_VALUE)
         {
-            ErrorMessage(GetLastError(), pszFile);
-            return 1;
+            if ((GetLastError() != ERROR_DIRECTORY) && (GetLastError() !=
ERROR_SHARING_VIOLATION)
+                  && (GetLastError() != ERROR_FILE_NOT_FOUND))
+                ErrorMessage(GetLastError(), pszFile);
+            return FALSE;
         }
         do
@@ -120,31 +127,39 @@ PrintAttribute(
             if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
                 continue;
-            if (!wcscmp(findData.cFileName, L".") ||
-                !wcscmp(findData.cFileName, L".."))
+            if (!wcscmp(findData.cFileName, L".") ||
!wcscmp(findData.cFileName, L".."))
                 continue;
             wcscpy(pszFileName, findData.cFileName);
             wcscat(pszFileName, L"\\");
-            PrintAttribute(szFullName, pszFile, bRecurse);
+            bFound = PrintAttribute(szFullName, pszFile, bRecurse,
+                                    bDirectories) || bFound;
         }
-        while(FindNextFileW(hFind, &findData));
+        while (FindNextFileW(hFind, &findData));
         FindClose(hFind);
     }
     /* append file name */
     wcscpy(pszFileName, pszFile);
-    /* display current directory */
+    /* search current directory */
     hFind = FindFirstFileW(szFullName, &findData);
     if (hFind == INVALID_HANDLE_VALUE)
     {
-        ErrorMessage(GetLastError(), pszFile);
-        return 1;
+        return bFound;
     }
     do
     {
+        bIsDir = findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
+        bExactMatch = wcsicmp(findData.cFileName, pszFile) == 0;
+
+        if (bIsDir && !bDirectories && !bExactMatch)
+            continue;
+
+        if (!wcscmp(findData.cFileName, L".") || !wcscmp(findData.cFileName,
L".."))
+            continue;
+
         wcscpy(pszFileName, findData.cFileName);
         ConPrintf(StdOut,
@@ -154,129 +169,112 @@ PrintAttribute(
                   (findData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ? L'H'
: L' ',
                   (findData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ?
L'R' : L' ',
                   szFullName);
+        bFound = TRUE;
     }
     while(FindNextFileW(hFind, &findData));
     FindClose(hFind);
-    return 0;
+    return bFound;
 }
+/* Returns TRUE if anything changed, FALSE otherwise */
 static
 BOOL
 ChangeAttribute(
     LPWSTR pszPath,
     LPWSTR pszFile,
+    BOOL  bRecurse,
+    BOOL  bDirectories,
     DWORD dwMask,
-    DWORD dwAttrib,
-    BOOL bRecurse,
-    BOOL bDirectories)
+    DWORD dwAttrib)
 {
     WIN32_FIND_DATAW findData;
     HANDLE hFind;
-    DWORD  dwAttribute;
     WCHAR  szFullName[MAX_PATH];
     LPWSTR pszFileName;
-    BOOL bWildcard = (wcschr(pszFile, L'*') || wcschr(pszFile, L'?'));
+    BOOL   bFound = FALSE;
+    BOOL   bIsDir;
+    BOOL   bExactMatch;
+    DWORD  dwAttribute;
     /* prepare full file name buffer */
     wcscpy(szFullName, pszPath);
     pszFileName = szFullName + wcslen(szFullName);
+    /* display all subdirectories */
+    if (bRecurse)
+    {
+        /* append *.* */
+        wcscpy(pszFileName, L"*.*");
+
+        hFind = FindFirstFileW(szFullName, &findData);
+        if (hFind == INVALID_HANDLE_VALUE)
+        {
+            if ((GetLastError() != ERROR_DIRECTORY) && (GetLastError() !=
ERROR_SHARING_VIOLATION)
+                  && (GetLastError() != ERROR_FILE_NOT_FOUND))
+                ErrorMessage(GetLastError(), pszFile);
+            return FALSE;
+        }
+
+        do
+        {
+            if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
+                continue;
+
+            if (!wcscmp(findData.cFileName, L".") ||
!wcscmp(findData.cFileName, L".."))
+                continue;
+
+            wcscpy(pszFileName, findData.cFileName);
+            wcscat(pszFileName, L"\\");
+            bFound = ChangeAttribute(szFullName, pszFile, bRecurse, bDirectories,
+                                     dwMask, dwAttrib) || bFound;
+        }
+        while (FindNextFileW(hFind, &findData));
+        FindClose(hFind);
+    }
+
     /* append file name */
     wcscpy(pszFileName, pszFile);
+    /* search current directory */
     hFind = FindFirstFileW(szFullName, &findData);
     if (hFind == INVALID_HANDLE_VALUE)
-        return FALSE;
-
-    dwAttribute = findData.dwFileAttributes;
-
-    if (!bWildcard)
     {
-        FindClose(hFind);
-        if (dwAttribute & FILE_ATTRIBUTE_DIRECTORY)
-        {
-            dwAttribute = (dwAttribute & ~dwMask) | dwAttrib;
-            SetFileAttributes(szFullName, dwAttribute);
-            if (bRecurse)
-            {
-                if (bDirectories)
-                {
-                    ChangeAttribute(szFullName, L"*", dwMask, dwAttrib,
-                                    bRecurse, bDirectories);
-                }
-                else
-                {
-                    if (!ChangeAttribute(szFullName, L"*", dwMask, dwAttrib,
-                                         bRecurse, FALSE))
-                    {
-                        return FALSE;
-                    }
-                }
-            }
-            else
-            {
-                if (!bDirectories)
-                {
-                    ChangeAttribute(szFullName, L"*", dwMask, dwAttrib,
-                                    bRecurse, FALSE);
-                }
-            }
-            return TRUE;
-        }
-        else
-        {
-            dwAttribute = (dwAttribute & ~dwMask) | dwAttrib;
-            SetFileAttributes(szFullName, dwAttribute);
-            return TRUE;
-        }
+        return bFound;
     }
-    else
+
+    do
     {
-        if ((dwAttribute & FILE_ATTRIBUTE_DIRECTORY) && (!bRecurse ||
!bDirectories))
-            return FALSE;
+        bIsDir = findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
+        bExactMatch = wcsicmp(findData.cFileName, pszFile) == 0;
-        do
-        {
-            dwAttribute = findData.dwFileAttributes;
-            if (dwAttribute & FILE_ATTRIBUTE_DIRECTORY)
-            {
-                if (!bDirectories)
-                    continue;
-
-                if (!wcscmp(findData.cFileName, L".") ||
-                    !wcscmp(findData.cFileName, L".."))
-                    continue;
-
-                wcscpy(pszFileName, findData.cFileName);
-                dwAttribute = (dwAttribute & ~dwMask) | dwAttrib;
-                SetFileAttributes(szFullName, dwAttribute);
-
-                if (bRecurse)
-                {
-                    ChangeAttribute(szFullName, findData.cFileName, dwMask,
-                                    dwAttrib, bRecurse, FALSE);
-                }
-            }
-            else
-            {
-                wcscpy(pszFileName, findData.cFileName);
-                dwAttribute = (dwAttribute & ~dwMask) | dwAttrib;
-                SetFileAttributes(szFullName, dwAttribute);
-            }
-        } while (FindNextFileW(hFind, &findData));
+        if (bIsDir && !bDirectories && !bExactMatch)
+            continue;
-        FindClose(hFind);
+        if (!wcscmp(findData.cFileName, L".") || !wcscmp(findData.cFileName,
L".."))
+            continue;
+
+        if (bRecurse && bIsDir && !bDirectories)
+            continue;
+
+        wcscpy(pszFileName, findData.cFileName);
+
+        dwAttribute = (findData.dwFileAttributes & ~dwMask) | dwAttrib;
+
+        SetFileAttributes(szFullName, dwAttribute);
+        bFound = TRUE;
     }
+    while(FindNextFileW(hFind, &findData));
+    FindClose(hFind);
-    return TRUE;
+    return bFound;
 }
 int wmain(int argc, WCHAR *argv[])
 {
     INT    i;
-    WCHAR  szPath[MAX_PATH];
+    WCHAR  szPath[MAX_PATH] = L""; // For case we only use 'attrib +h
/s' there is no szPath
     WCHAR  szFileName [MAX_PATH];
     BOOL   bRecurse = FALSE;
     BOOL   bDirectories = FALSE;
@@ -389,7 +387,7 @@ int wmain(int argc, WCHAR *argv[])
             szPath[len + 1] = UNICODE_NULL;
         }
         wcscpy(szFileName, L"*.*");
-        PrintAttribute(szPath, szFileName, bRecurse);
+        PrintAttribute(szPath, szFileName, bRecurse, bDirectories);
         return 0;
     }
@@ -405,14 +403,33 @@ int wmain(int argc, WCHAR *argv[])
         if (dwMask == 0)
         {
-            PrintAttribute(szPath, szFileName, bRecurse);
+            if (!PrintAttribute(szPath, szFileName, bRecurse, bDirectories))
+            {
+                ConResPrintf(StdOut, STRING_FILE_NOT_FOUND, argv[i]);
+            }
         }
-        else if (!ChangeAttribute(szPath, szFileName, dwMask,
-                                  dwAttrib, bRecurse, bDirectories))
+        else if (!ChangeAttribute(szPath, szFileName, bRecurse, bDirectories, dwMask,
dwAttrib))
         {
             ConResPrintf(StdOut, STRING_FILE_NOT_FOUND, argv[i]);
         }
     }
+// Code below handles the special case of 'attrib +h /s' and similar
+
+    if (bRecurse && dwMask && (wcscmp(szPath, L"") == 0))
+        {
+            DWORD len;
+
+            len = GetCurrentDirectory(MAX_PATH, szPath);
+            if (szPath[len-1] != L'\\')
+            {
+                szPath[len] = L'\\';
+                szPath[len + 1] = UNICODE_NULL;
+            }
+            wcscpy(szFileName, L"*.*");
+            if (!ChangeAttribute(szPath, szFileName, bRecurse, bDirectories, dwMask,
dwAttrib))
+                ConResPrintf(StdOut, STRING_FILE_NOT_FOUND, szFileName);
+        }
+
     return 0;
 }