[CMD] Code formatting; use LPCTSTR where possible; use a MAX_PATH sized dircmd buffer.
[reactos.git] / base / shell / cmd / dir.c
index b2433d9..965cf74 100644 (file)
  *    27-Feb-2005 (Konstantinos Paliouras <squarious@gmail.com>)
  *        Implemented all the switches that were missing, and made
  *        the ros dir very similar to windows dir. Major part of
- *        the code is rewritten. /p is removed, to be rewriten in
+ *        the code is rewritten. /p is removed, to be rewritten in
  *        the main cmd code.
  *
  *    1-Jul-2004 (Brandon Turner <turnerb7@msu.edu>)
  *        Removed variables formerly in use to handle pagination
  *        Pagination belongs to ConOutPrintfPaging
  *        Removed already commented out code of old pagination
+ *
+ *    25-Aug-2015 (Pierre Schweitzer)
+ *        Implemented /R switch
  */
 
 #include "precomp.h"
 
 #ifdef INCLUDE_CMD_DIR
 
-
-
 /* Time Field enumeration */
 enum ETimeField
 {
@@ -162,8 +163,8 @@ enum EOrderBy
 typedef struct _DirSwitchesFlags
 {
     BOOL bBareFormat;   /* Bare Format */
-    BOOL bTSeperator;   /* Thousands seperator */
-    BOOL bWideList;     /* Wide list format    */
+    BOOL bTSeparator;   /* Thousands separator */
+    BOOL bWideList;     /* Wide list format */
     BOOL bWideListColSort;  /* Wide list format but sorted by column */
     BOOL bLowerCase;    /* Uses lower case */
     BOOL bNewLongList;  /* New long list */
@@ -172,6 +173,7 @@ typedef struct _DirSwitchesFlags
     BOOL bRecursive;    /* Displays files in specified directory and all sub */
     BOOL bShortName;    /* Displays the sort name of files if exist */
     BOOL b4Digit;       /* Four digit year */
+    BOOL bDataStreams;  /* Displays alternate data streams */
     struct
     {
         DWORD dwAttribVal;  /* The desired state of attribute */
@@ -189,9 +191,21 @@ typedef struct _DirSwitchesFlags
     } stTimeField;                  /* The time field to display or use for sorting */
 } DIRSWITCHFLAGS, *LPDIRSWITCHFLAGS;
 
-typedef struct _DIRFINDLISTNODE
+typedef struct _DIRFINDSTREAMNODE
+{
+    WIN32_FIND_STREAM_DATA stStreamInfo;
+    struct _DIRFINDSTREAMNODE *ptrNext;
+} DIRFINDSTREAMNODE, *PDIRFINDSTREAMNODE;
+
+typedef struct _DIRFINDINFO
 {
     WIN32_FIND_DATA stFindInfo;
+    PDIRFINDSTREAMNODE ptrHead;
+} DIRFINDINFO, *PDIRFINDINFO;
+
+typedef struct _DIRFINDLISTNODE
+{
+    DIRFINDINFO stInfo;
     struct _DIRFINDLISTNODE *ptrNext;
 } DIRFINDLISTNODE, *PDIRFINDLISTNODE;
 
@@ -199,7 +213,7 @@ typedef BOOL
 (WINAPI *PGETFREEDISKSPACEEX)(LPCTSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER);
 
 /* Globally save the # of dirs, files and bytes,
- * probabaly later pass them to functions. Rob Lake  */
+ * probably later pass them to functions. Rob Lake  */
 static ULONG recurse_dir_cnt;
 static ULONG recurse_file_cnt;
 static ULONGLONG recurse_bytes;
@@ -228,8 +242,8 @@ DirReadParam(LPTSTR Line,               /* [IN] The line with the parameters & s
              LPDIRSWITCHFLAGS lpFlags)  /* [IN/OUT] The flags after calculating switches */
 {
     TCHAR cCurSwitch;   /* The current switch */
-    TCHAR cCurChar;     /* Current examing character */
-    TCHAR cCurUChar;    /* Current upper examing character */
+    TCHAR cCurChar;     /* Current examined character */
+    TCHAR cCurUChar;    /* Current upper examined character */
     BOOL bNegative;     /* Negative switch */
     BOOL bPNegative;    /* Negative switch parameter */
     BOOL bIntoQuotes;   /* A flag showing if we are in quotes (") */
@@ -264,7 +278,7 @@ DirReadParam(LPTSTR Line,               /* [IN] The line with the parameters & s
         /* When a switch is expecting */
         if (cCurSwitch == _T('/'))
         {
-            while (*Line == _T(' '))
+            while (_istspace(*Line))
                 Line++;
 
             bNegative = (*Line == _T('-'));
@@ -310,7 +324,7 @@ DirReadParam(LPTSTR Line,               /* [IN] The line with the parameters & s
             else if (cCurUChar == _T('B'))
                 lpFlags->bBareFormat = ! bNegative;
             else if (cCurUChar == _T('C'))
-                lpFlags->bTSeperator = ! bNegative;
+                lpFlags->bTSeparator = ! bNegative;
             else if (cCurUChar == _T('W'))
                 lpFlags->bWideList = ! bNegative;
             else if (cCurUChar == _T('D'))
@@ -325,6 +339,8 @@ DirReadParam(LPTSTR Line,               /* [IN] The line with the parameters & s
                 lpFlags->bRecursive = ! bNegative;
             else if (cCurUChar == _T('X'))
                 lpFlags->bShortName = ! bNegative;
+            else if (cCurUChar == _T('R'))
+                lpFlags->bDataStreams = ! bNegative;
             else if (cCurChar == _T('4'))
                 lpFlags->b4Digit = ! bNegative;
             else if (cCurChar == _T('?'))
@@ -334,12 +350,12 @@ DirReadParam(LPTSTR Line,               /* [IN] The line with the parameters & s
             }
             else
             {
-                error_invalid_switch ((TCHAR)_totupper (*Line));
+                error_invalid_switch ((TCHAR)_totupper(*Line));
                 return FALSE;
             }
 
             /* Make sure there's no extra characters at the end of the switch */
-            if (Line[1] && Line[1] != _T('/') && Line[1] != _T(' '))
+            if (Line[1] && Line[1] != _T('/') && !_istspace(Line[1]))
             {
                 error_parameter_format(Line[1]);
                 return FALSE;
@@ -354,7 +370,7 @@ DirReadParam(LPTSTR Line,               /* [IN] The line with the parameters & s
 
             if (cCurChar == _T('/'))
                 cCurSwitch = _T('/');
-            else if (cCurChar == _T(' '))
+            else if (_istspace(cCurChar))
                 /* do nothing */;
             else
             {
@@ -363,7 +379,7 @@ DirReadParam(LPTSTR Line,               /* [IN] The line with the parameters & s
                 bIntoQuotes = FALSE;
                 while (*Line)
                 {
-                    if (!bIntoQuotes && (*Line == _T('/') || *Line == _T(' ')))
+                    if (!bIntoQuotes && (*Line == _T('/') || _istspace(*Line)))
                         break;
                     bIntoQuotes ^= (*Line == _T('"'));
                     Line++;
@@ -371,10 +387,10 @@ DirReadParam(LPTSTR Line,               /* [IN] The line with the parameters & s
                 ptrEnd = Line;
 
                 /* Copy it to the entries list */
-                temp = cmd_alloc((ptrEnd - ptrStart + 1) * sizeof (TCHAR));
+                temp = cmd_alloc((ptrEnd - ptrStart + 1) * sizeof(TCHAR));
                 if (!temp)
                     return FALSE;
-                memcpy(temp, ptrStart, (ptrEnd - ptrStart) * sizeof (TCHAR));
+                memcpy(temp, ptrStart, (ptrEnd - ptrStart) * sizeof(TCHAR));
                 temp[ptrEnd - ptrStart] = _T('\0');
                 StripQuotes(temp);
                 if (!add_entry(entries, params, temp))
@@ -394,16 +410,16 @@ DirReadParam(LPTSTR Line,               /* [IN] The line with the parameters & s
             /* We are waiting for switch parameters */
 
             /* Check if there are no more switch parameters */
-            if ((cCurChar == _T('/')) || ( cCurChar == _T(' ')))
+            if ((cCurChar == _T('/')) || _istspace(cCurChar))
             {
-                /* Wrong desicion path, reprocess current character */
+                /* Wrong decision path, reprocess current character */
                 cCurSwitch = _T(' ');
                 continue;
             }
             /* Process parameter switch */
-            switch(cCurSwitch)
+            switch (cCurSwitch)
             {
-            case _T('A'):      /* Switch parameters for /A (attributes filter) */
+            case _T('A'):   /* Switch parameters for /A (attributes filter) */
                 if (cCurChar == _T('-'))
                     bPNegative = TRUE;
                 else if (cCurUChar == _T('D'))
@@ -452,7 +468,7 @@ DirReadParam(LPTSTR Line,               /* [IN] The line with the parameters & s
                     return FALSE;
                 }
                 break;
-            case _T('T'):      /* Switch parameters for /T (time field) */
+            case _T('T'):   /* Switch parameters for /T (time field) */
                 if (cCurUChar == _T('C'))
                     lpFlags->stTimeField.eTimeField= TF_CREATIONDATE ;
                 else if (cCurUChar == _T('A'))
@@ -510,7 +526,7 @@ DirReadParam(LPTSTR Line,               /* [IN] The line with the parameters & s
 
 
             }
-            /* We check if we calculated the negative value and realese the flag */
+            /* We check if we calculated the negative value and release the flag */
             if ((cCurChar != _T('-')) && bPNegative)
                 bPNegative = FALSE;
         }
@@ -532,18 +548,18 @@ DirReadParam(LPTSTR Line,               /* [IN] The line with the parameters & s
 }
 
 /* Print either with or without paging, depending on /P switch */
-static INT
+static BOOL
 DirPrintf(LPDIRSWITCHFLAGS lpFlags, LPTSTR szFormat, ...)
 {
-    INT iReturn = 0;
+    BOOL Done = TRUE;
     va_list arg_ptr;
     va_start(arg_ptr, szFormat);
     if (lpFlags->bPause)
-        iReturn = ConPrintfPaging(FALSE, szFormat, arg_ptr, STD_OUTPUT_HANDLE);
+        Done = ConPrintfVPaging(&StdOutPager, FALSE, szFormat, arg_ptr);
     else
-        ConPrintf(szFormat, arg_ptr, STD_OUTPUT_HANDLE);
+        ConPrintfV(StdOut, szFormat, arg_ptr);
     va_end(arg_ptr);
-    return iReturn;
+    return Done;
 }
 
 
@@ -553,7 +569,7 @@ DirPrintf(LPDIRSWITCHFLAGS lpFlags, LPTSTR szFormat, ...)
  * print the header for the dir command
  */
 static BOOL
-PrintDirectoryHeader(LPTSTR szPath, LPDIRSWITCHFLAGS lpFlags)
+PrintDirectoryHeader(LPCTSTR szPath, LPDIRSWITCHFLAGS lpFlags)
 {
     TCHAR szMsg[RC_STRING_MAX_SIZE];
     TCHAR szFullDir[MAX_PATH];
@@ -565,7 +581,7 @@ PrintDirectoryHeader(LPTSTR szPath, LPDIRSWITCHFLAGS lpFlags)
     if (lpFlags->bBareFormat)
         return TRUE;
 
-    if (GetFullPathName(szPath, sizeof(szFullDir) / sizeof(TCHAR), szFullDir, &pszFilePart) == 0)
+    if (GetFullPathName(szPath, ARRAYSIZE(szFullDir), szFullDir, &pszFilePart) == 0)
     {
         ErrorMessage(GetLastError(), _T("Failed to build full directory path"));
         return FALSE;
@@ -574,28 +590,28 @@ PrintDirectoryHeader(LPTSTR szPath, LPDIRSWITCHFLAGS lpFlags)
     if (pszFilePart != NULL)
     *pszFilePart = _T('\0');
 
-    /* get the media ID of the drive */
-    if (!GetVolumePathName(szFullDir, szRootName, sizeof(szRootName) / sizeof(TCHAR)) ||
-        !GetVolumeInformation(szRootName, szVolName, 80, &dwSerialNr,
-                              NULL, NULL, NULL, 0))
+    /* Get the media ID of the drive */
+    if (!GetVolumePathName(szFullDir, szRootName, ARRAYSIZE(szRootName)) ||
+        !GetVolumeInformation(szRootName, szVolName, ARRAYSIZE(szVolName),
+                              &dwSerialNr, NULL, NULL, NULL, 0))
     {
         return TRUE;
     }
 
-    /* print drive info */
+    /* Print drive info */
     if (szVolName[0] != _T('\0'))
     {
-        LoadString(CMD_ModuleHandle, STRING_DIR_HELP2, szMsg, RC_STRING_MAX_SIZE);
-        DirPrintf(lpFlags, szMsg, szRootName[0], szVolName);
+        LoadString(CMD_ModuleHandle, STRING_DIR_HELP2, szMsg, ARRAYSIZE(szMsg));
+        DirPrintf(lpFlags, szMsg, _totupper(szRootName[0]), szVolName);
     }
     else
     {
-        LoadString(CMD_ModuleHandle, STRING_DIR_HELP3, szMsg, RC_STRING_MAX_SIZE);
-        DirPrintf(lpFlags, szMsg, szRootName[0]);
+        LoadString(CMD_ModuleHandle, STRING_DIR_HELP3, szMsg, ARRAYSIZE(szMsg));
+        DirPrintf(lpFlags, szMsg, _totupper(szRootName[0]));
     }
 
-    /* print the volume serial number if the return was successful */
-    LoadString(CMD_ModuleHandle, STRING_DIR_HELP4, (LPTSTR) szMsg, RC_STRING_MAX_SIZE);
+    /* Print the volume serial number if the return was successful */
+    LoadString(CMD_ModuleHandle, STRING_DIR_HELP4, szMsg, ARRAYSIZE(szMsg));
     DirPrintf(lpFlags, szMsg, HIWORD(dwSerialNr), LOWORD(dwSerialNr));
 
     return TRUE;
@@ -713,7 +729,7 @@ GetUserDiskFreeSpace(LPCTSTR lpRoot,
 #endif
         if (pGetFreeDiskSpaceEx != NULL)
         {
-            if (pGetFreeDiskSpaceEx(lpRoot, lpFreeSpace, &TotalNumberOfBytes, &TotalNumberOfFreeBytes) == TRUE)
+            if (pGetFreeDiskSpaceEx(lpRoot, lpFreeSpace, &TotalNumberOfBytes, &TotalNumberOfFreeBytes) != FALSE)
                 return;
         }
     }
@@ -734,7 +750,7 @@ GetUserDiskFreeSpace(LPCTSTR lpRoot,
  * Just copied Tim's Code and patched it a bit
  */
 static INT
-PrintSummary(LPTSTR szPath,
+PrintSummary(LPCTSTR szPath,
              ULONG ulFiles,
              ULONG ulDirs,
              ULONGLONG u64Bytes,
@@ -759,11 +775,11 @@ PrintSummary(LPTSTR szPath,
 
     /* Print recursive specific results */
 
-    /* Take this code offline to fix /S does not print duoble info */
+    /* Take this code offline to fix /S does not print double info */
     if (TotalSummary && lpFlags->bRecursive)
     {
-        ConvertULargeInteger(u64Bytes, szBuffer, sizeof(szBuffer), lpFlags->bTSeperator);
-        LoadString(CMD_ModuleHandle, STRING_DIR_HELP5, szMsg, RC_STRING_MAX_SIZE);
+        ConvertULargeInteger(u64Bytes, szBuffer, ARRAYSIZE(szBuffer), lpFlags->bTSeparator);
+        LoadString(CMD_ModuleHandle, STRING_DIR_HELP5, szMsg, ARRAYSIZE(szMsg));
         DirPrintf(lpFlags, szMsg, ulFiles, szBuffer);
     }
     else
@@ -771,17 +787,17 @@ PrintSummary(LPTSTR szPath,
         /* Print File Summary */
         /* Condition to print summary is:
         If we are not in bare format and if we have results! */
-        ConvertULargeInteger(u64Bytes, szBuffer, 20, lpFlags->bTSeperator);
-        LoadString(CMD_ModuleHandle, STRING_DIR_HELP8, szMsg, RC_STRING_MAX_SIZE);
+        ConvertULargeInteger(u64Bytes, szBuffer, ARRAYSIZE(szBuffer), lpFlags->bTSeparator);
+        LoadString(CMD_ModuleHandle, STRING_DIR_HELP8, szMsg, ARRAYSIZE(szMsg));
         DirPrintf(lpFlags, szMsg, ulFiles, szBuffer);
     }
 
-    /* Print total directories and freespace */
+    /* Print total directories and free space */
     if (!lpFlags->bRecursive || TotalSummary)
     {
         GetUserDiskFreeSpace(szPath, &uliFree);
-        ConvertULargeInteger(uliFree.QuadPart, szBuffer, sizeof(szBuffer), lpFlags->bTSeperator);
-        LoadString(CMD_ModuleHandle, STRING_DIR_HELP6, (LPTSTR) szMsg, RC_STRING_MAX_SIZE);
+        ConvertULargeInteger(uliFree.QuadPart, szBuffer, ARRAYSIZE(szBuffer), lpFlags->bTSeparator);
+        LoadString(CMD_ModuleHandle, STRING_DIR_HELP6, szMsg, ARRAYSIZE(szMsg));
         DirPrintf(lpFlags, szMsg, ulDirs, szBuffer);
     }
 
@@ -838,9 +854,9 @@ getName(const TCHAR* file, TCHAR * dest)
  * The function that prints in new style
  */
 static VOID
-DirPrintNewList(LPWIN32_FIND_DATA ptrFiles[],   /* [IN]Files' Info */
+DirPrintNewList(PDIRFINDINFO ptrFiles[],        /* [IN]Files' Info */
                 DWORD dwCount,                  /* [IN] The quantity of files */
-                TCHAR *szCurPath,               /* [IN] Full path of current directory */
+                LPCTSTR szCurPath,              /* [IN] Full path of current directory */
                 LPDIRSWITCHFLAGS lpFlags)       /* [IN] The flags used */
 {
     DWORD i;
@@ -850,17 +866,18 @@ DirPrintNewList(LPWIN32_FIND_DATA ptrFiles[],   /* [IN]Files' Info */
     TCHAR szTime[20];
     INT iSizeFormat;
     ULARGE_INTEGER u64FileSize;
+    PDIRFINDSTREAMNODE ptrCurStream;
 
-    for (i = 0; i < dwCount && !bCtrlBreak; i++)
+    for (i = 0; i < dwCount && !CheckCtrlBreak(BREAK_INPUT); i++)
     {
         /* Calculate size */
-        if (ptrFiles[i]->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
+        if (ptrFiles[i]->stFindInfo.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
         {
             /* Junction */
             iSizeFormat = -14;
             _tcscpy(szSize, _T("<JUNCTION>"));
         }
-        else if (ptrFiles[i]->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+        else if (ptrFiles[i]->stFindInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
         {
             /* Directory */
             iSizeFormat = -14;
@@ -870,18 +887,18 @@ DirPrintNewList(LPWIN32_FIND_DATA ptrFiles[],   /* [IN]Files' Info */
         {
             /* File */
             iSizeFormat = 14;
-            u64FileSize.HighPart = ptrFiles[i]->nFileSizeHigh;
-            u64FileSize.LowPart = ptrFiles[i]->nFileSizeLow;
-            ConvertULargeInteger(u64FileSize.QuadPart, szSize, 20, lpFlags->bTSeperator);
+            u64FileSize.HighPart = ptrFiles[i]->stFindInfo.nFileSizeHigh;
+            u64FileSize.LowPart = ptrFiles[i]->stFindInfo.nFileSizeLow;
+            ConvertULargeInteger(u64FileSize.QuadPart, szSize, 20, lpFlags->bTSeparator);
         }
 
         /* Calculate short name */
         szShortName[0] = _T('\0');
         if (lpFlags->bShortName)
-            _stprintf(szShortName, _T(" %-12s"), ptrFiles[i]->cAlternateFileName);
+            _stprintf(szShortName, _T(" %-12s"), ptrFiles[i]->stFindInfo.cAlternateFileName);
 
         /* Format date and time */
-        DirPrintFileDateTime(szDate, szTime, ptrFiles[i], lpFlags);
+        DirPrintFileDateTime(szDate, szTime, &ptrFiles[i]->stFindInfo, lpFlags);
 
         /* Print the line */
         DirPrintf(lpFlags, _T("%10s  %-6s    %*s%s %s\n"),
@@ -890,7 +907,25 @@ DirPrintNewList(LPWIN32_FIND_DATA ptrFiles[],   /* [IN]Files' Info */
                   iSizeFormat,
                   szSize,
                   szShortName,
-                  ptrFiles[i]->cFileName);
+                  ptrFiles[i]->stFindInfo.cFileName);
+
+        /* Now, loop on the streams */
+        ptrCurStream = ptrFiles[i]->ptrHead;
+        while (ptrCurStream)
+        {
+            ConvertULargeInteger(ptrCurStream->stStreamInfo.StreamSize.QuadPart, szSize, 20, lpFlags->bTSeparator);
+
+            /* Print the line */
+            DirPrintf(lpFlags, _T("%10s  %-6s    %*s%s %s%s\n"),
+                      L"",
+                      L"",
+                      16,
+                      szSize,
+                      L"",
+                      ptrFiles[i]->stFindInfo.cFileName,
+                      ptrCurStream->stStreamInfo.cStreamName);
+            ptrCurStream = ptrCurStream->ptrNext;
+        }
     }
 }
 
@@ -901,9 +936,9 @@ DirPrintNewList(LPWIN32_FIND_DATA ptrFiles[],   /* [IN]Files' Info */
  * The function that prints in wide list
  */
 static VOID
-DirPrintWideList(LPWIN32_FIND_DATA ptrFiles[],  /* [IN] Files' Info */
+DirPrintWideList(PDIRFINDINFO ptrFiles[],       /* [IN] Files' Info */
                  DWORD dwCount,                 /* [IN] The quantity of files */
-                 TCHAR *szCurPath,              /* [IN] Full path of current directory */
+                 LPCTSTR szCurPath,             /* [IN] Full path of current directory */
                  LPDIRSWITCHFLAGS lpFlags)      /* [IN] The flags used */
 {
     SHORT iScreenWidth;
@@ -919,21 +954,21 @@ DirPrintWideList(LPWIN32_FIND_DATA ptrFiles[],  /* [IN] Files' Info */
     iLongestName = 1;
     for (i = 0; i < dwCount; i++)
     {
-        if (ptrFiles[i]->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+        if (ptrFiles[i]->stFindInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
         {
-            /* Directories need 2 additinal characters for brackets */
-            if ((_tcslen(ptrFiles[i]->cFileName) + 2) > iLongestName)
-                iLongestName = _tcslen(ptrFiles[i]->cFileName) + 2;
+            /* Directories need 2 additional characters for brackets */
+            if ((_tcslen(ptrFiles[i]->stFindInfo.cFileName) + 2) > iLongestName)
+                iLongestName = _tcslen(ptrFiles[i]->stFindInfo.cFileName) + 2;
         }
         else
         {
-            if (_tcslen(ptrFiles[i]->cFileName) > iLongestName)
-                iLongestName = _tcslen(ptrFiles[i]->cFileName);
+            if (_tcslen(ptrFiles[i]->stFindInfo.cFileName) > iLongestName)
+                iLongestName = _tcslen(ptrFiles[i]->stFindInfo.cFileName);
         }
     }
 
     /* Count the highest number of columns */
-    GetScreenSize(&iScreenWidth, 0);
+    GetScreenSize(&iScreenWidth, NULL);
     iColumns = (USHORT)(iScreenWidth / iLongestName);
 
     /* Check if there is enough space for spaces between names */
@@ -946,7 +981,7 @@ DirPrintWideList(LPWIN32_FIND_DATA ptrFiles[],  /* [IN] Files' Info */
     /* Calculate the lines that will be printed */
     iLines = (USHORT)((dwCount + iColumns - 1) / iColumns);
 
-    for (i = 0; i < iLines && !bCtrlBreak; i++)
+    for (i = 0; i < iLines && !CheckCtrlBreak(BREAK_INPUT); i++)
     {
         for (j = 0; j < iColumns; j++)
         {
@@ -963,10 +998,10 @@ DirPrintWideList(LPWIN32_FIND_DATA ptrFiles[],  /* [IN] Files' Info */
 
             if (temp >= dwCount) break;
 
-            if (ptrFiles[temp]->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-                _stprintf(szTempFname, _T("[%s]"), ptrFiles[temp]->cFileName);
+            if (ptrFiles[temp]->stFindInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+                _stprintf(szTempFname, _T("[%s]"), ptrFiles[temp]->stFindInfo.cFileName);
             else
-                _stprintf(szTempFname, _T("%s"), ptrFiles[temp]->cFileName);
+                _stprintf(szTempFname, _T("%s"), ptrFiles[temp]->stFindInfo.cFileName);
 
             DirPrintf(lpFlags, _T("%-*s"), iLongestName + 1, szTempFname);
         }
@@ -983,9 +1018,9 @@ DirPrintWideList(LPWIN32_FIND_DATA ptrFiles[],  /* [IN] Files' Info */
  * The function that prints in old style
  */
 static VOID
-DirPrintOldList(LPWIN32_FIND_DATA ptrFiles[],   /* [IN] Files' Info */
+DirPrintOldList(PDIRFINDINFO ptrFiles[],        /* [IN] Files' Info */
                 DWORD dwCount,                  /* [IN] The quantity of files */
-                TCHAR * szCurPath,              /* [IN] Full path of current directory */
+                LPCTSTR szCurPath,              /* [IN] Full path of current directory */
                 LPDIRSWITCHFLAGS lpFlags)       /* [IN] The flags used */
 {
     DWORD i;                        /* An indexer for "for"s */
@@ -996,26 +1031,26 @@ DirPrintOldList(LPWIN32_FIND_DATA ptrFiles[],   /* [IN] Files' Info */
     int iSizeFormat;                /* The format of size field */
     ULARGE_INTEGER u64FileSize;     /* The file size */
 
-    for (i = 0; i < dwCount && !bCtrlBreak; i++)
+    for (i = 0; i < dwCount && !CheckCtrlBreak(BREAK_INPUT); i++)
     {
         /* Broke 8.3 format */
-        if (*ptrFiles[i]->cAlternateFileName )
+        if (*ptrFiles[i]->stFindInfo.cAlternateFileName )
         {
             /* If the file is long named then we read the alter name */
-            getName( ptrFiles[i]->cAlternateFileName, szName);
-            _tcscpy(szExt, getExt( ptrFiles[i]->cAlternateFileName));
+            getName( ptrFiles[i]->stFindInfo.cAlternateFileName, szName);
+            _tcscpy(szExt, getExt( ptrFiles[i]->stFindInfo.cAlternateFileName));
         }
         else
         {
             /* If the file is not long name we read its original name */
-            getName( ptrFiles[i]->cFileName, szName);
-            _tcscpy(szExt, getExt( ptrFiles[i]->cFileName));
+            getName( ptrFiles[i]->stFindInfo.cFileName, szName);
+            _tcscpy(szExt, getExt( ptrFiles[i]->stFindInfo.cFileName));
         }
 
         /* Calculate size */
-        if (ptrFiles[i]->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+        if (ptrFiles[i]->stFindInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
         {
-            /* Directory, no size it's a directory*/
+            /* Directory, no size it's a directory */
             iSizeFormat = -17;
             _tcscpy(szSize, _T("<DIR>"));
         }
@@ -1023,13 +1058,13 @@ DirPrintOldList(LPWIN32_FIND_DATA ptrFiles[],   /* [IN] Files' Info */
         {
             /* File */
             iSizeFormat = 17;
-            u64FileSize.HighPart = ptrFiles[i]->nFileSizeHigh;
-            u64FileSize.LowPart = ptrFiles[i]->nFileSizeLow;
-            ConvertULargeInteger(u64FileSize.QuadPart, szSize, 20, lpFlags->bTSeperator);
+            u64FileSize.HighPart = ptrFiles[i]->stFindInfo.nFileSizeHigh;
+            u64FileSize.LowPart = ptrFiles[i]->stFindInfo.nFileSizeLow;
+            ConvertULargeInteger(u64FileSize.QuadPart, szSize, 20, lpFlags->bTSeparator);
         }
 
         /* Format date and time */
-        DirPrintFileDateTime(szDate,szTime,ptrFiles[i],lpFlags);
+        DirPrintFileDateTime(szDate,szTime,&ptrFiles[i]->stFindInfo,lpFlags);
 
         /* Print the line */
         DirPrintf(lpFlags, _T("%-8s %-3s  %*s %s  %s\n"),
@@ -1048,17 +1083,17 @@ DirPrintOldList(LPWIN32_FIND_DATA ptrFiles[],   /* [IN] Files' Info */
  * The function that prints in bare format
  */
 static VOID
-DirPrintBareList(LPWIN32_FIND_DATA ptrFiles[],  /* [IN] Files' Info */
+DirPrintBareList(PDIRFINDINFO ptrFiles[],       /* [IN] Files' Info */
                  DWORD dwCount,                 /* [IN] The number of files */
-                 LPTSTR lpCurPath,              /* [IN] Full path of current directory */
+                 LPCTSTR szCurPath,             /* [IN] Full path of current directory */
                  LPDIRSWITCHFLAGS lpFlags)      /* [IN] The flags used */
 {
     DWORD i;
 
-    for (i = 0; i < dwCount && !bCtrlBreak; i++)
+    for (i = 0; i < dwCount && !CheckCtrlBreak(BREAK_INPUT); i++)
     {
-        if ((_tcscmp(ptrFiles[i]->cFileName, _T(".")) == 0) ||
-            (_tcscmp(ptrFiles[i]->cFileName, _T("..")) == 0))
+        if ((_tcscmp(ptrFiles[i]->stFindInfo.cFileName, _T(".")) == 0) ||
+            (_tcscmp(ptrFiles[i]->stFindInfo.cFileName, _T("..")) == 0))
         {
             /* at bare format we don't print "." and ".." folder */
             continue;
@@ -1066,12 +1101,12 @@ DirPrintBareList(LPWIN32_FIND_DATA ptrFiles[],  /* [IN] Files' Info */
         if (lpFlags->bRecursive)
         {
             /* at recursive mode we print full path of file */
-            DirPrintf(lpFlags, _T("%s\\%s\n"), lpCurPath, ptrFiles[i]->cFileName);
+            DirPrintf(lpFlags, _T("%s\\%s\n"), szCurPath, ptrFiles[i]->stFindInfo.cFileName);
         }
         else
         {
             /* if we are not in recursive mode we print the file names */
-            DirPrintf(lpFlags, _T("%s\n"), ptrFiles[i]->cFileName);
+            DirPrintf(lpFlags, _T("%s\n"), ptrFiles[i]->stFindInfo.cFileName);
         }
     }
 }
@@ -1083,9 +1118,9 @@ DirPrintBareList(LPWIN32_FIND_DATA ptrFiles[],  /* [IN] Files' Info */
  * The functions that prints the files list
  */
 static VOID
-DirPrintFiles(LPWIN32_FIND_DATA ptrFiles[], /* [IN] Files' Info */
+DirPrintFiles(PDIRFINDINFO ptrFiles[],      /* [IN] Files' Info */
               DWORD dwCount,                /* [IN] The quantity of files */
-              TCHAR *szCurPath,             /* [IN] Full path of current directory */
+              LPCTSTR szCurPath,            /* [IN] Full path of current directory */
               LPDIRSWITCHFLAGS lpFlags)     /* [IN] The flags used */
 {
     TCHAR szMsg[RC_STRING_MAX_SIZE];
@@ -1099,10 +1134,10 @@ DirPrintFiles(LPWIN32_FIND_DATA ptrFiles[], /* [IN] Files' Info */
     /* Condition to print header:
        We are not printing in bare format
        and if we are in recursive mode... we must have results */
-    if (!(lpFlags->bBareFormat ) && !((lpFlags->bRecursive) && (dwCount <= 0)))
+    if (!lpFlags->bBareFormat && !(lpFlags->bRecursive && (dwCount <= 0)))
     {
-        LoadString(CMD_ModuleHandle, STRING_DIR_HELP7, szMsg, RC_STRING_MAX_SIZE);
-        if (DirPrintf(lpFlags, szMsg, szTemp))
+        LoadString(CMD_ModuleHandle, STRING_DIR_HELP7, szMsg, ARRAYSIZE(szMsg));
+        if (!DirPrintf(lpFlags, szMsg, szTemp))
             return;
     }
 
@@ -1139,30 +1174,30 @@ DirPrintFiles(LPWIN32_FIND_DATA ptrFiles[], /* [IN] Files' Info */
  * Compares 2 files based on the order criteria
  */
 static BOOL
-CompareFiles(LPWIN32_FIND_DATA lpFile1, /* [IN] A pointer to WIN32_FIND_DATA of file 1 */
-             LPWIN32_FIND_DATA lpFile2, /* [IN] A pointer to WIN32_FIND_DATA of file 2 */
-             LPDIRSWITCHFLAGS lpFlags)  /* [IN] The flags that we use to list */
+CompareFiles(PDIRFINDINFO lpFile1,          /* [IN] A pointer to WIN32_FIND_DATA of file 1 */
+             PDIRFINDINFO lpFile2,          /* [IN] A pointer to WIN32_FIND_DATA of file 2 */
+             LPDIRSWITCHFLAGS lpFlags)      /* [IN] The flags that we use to list */
 {
   ULARGE_INTEGER u64File1;
   ULARGE_INTEGER u64File2;
   int i;
   long iComp = 0;   /* The comparison result */
 
-    /* Calculate critiries by order given from user */
-    for (i = 0;i < lpFlags->stOrderBy.sCriteriaCount;i++)
+    /* Calculate criteria by order given from user */
+    for (i = 0; i < lpFlags->stOrderBy.sCriteriaCount; i++)
     {
 
         /* Calculate criteria */
-        switch(lpFlags->stOrderBy.eCriteria[i])
+        switch (lpFlags->stOrderBy.eCriteria[i])
         {
-        case ORDER_SIZE:               /* Order by size /o:s */
+        case ORDER_SIZE:        /* Order by size /o:s */
             /* concat the 32bit integers to a 64bit */
-            u64File1.LowPart = lpFile1->nFileSizeLow;
-            u64File1.HighPart = lpFile1->nFileSizeHigh;
-            u64File2.LowPart = lpFile2->nFileSizeLow;
-            u64File2.HighPart = lpFile2->nFileSizeHigh;
+            u64File1.LowPart = lpFile1->stFindInfo.nFileSizeLow;
+            u64File1.HighPart = lpFile1->stFindInfo.nFileSizeHigh;
+            u64File2.LowPart = lpFile2->stFindInfo.nFileSizeLow;
+            u64File2.HighPart = lpFile2->stFindInfo.nFileSizeHigh;
 
-            /* In case that differnce is too big for a long */
+            /* In case that difference is too big for a long */
             if (u64File1.QuadPart < u64File2.QuadPart)
                 iComp = -1;
             else if (u64File1.QuadPart > u64File2.QuadPart)
@@ -1171,47 +1206,47 @@ CompareFiles(LPWIN32_FIND_DATA lpFile1, /* [IN] A pointer to WIN32_FIND_DATA of
                 iComp = 0;
             break;
 
-        case ORDER_DIRECTORY:  /* Order by directory attribute /o:g */
-            iComp = ((lpFile2->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)-
-                (lpFile1->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY));
+        case ORDER_DIRECTORY:   /* Order by directory attribute /o:g */
+            iComp = ((lpFile2->stFindInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)-
+                (lpFile1->stFindInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY));
             break;
 
-        case ORDER_EXTENSION:  /* Order by extension name /o:e */
-            iComp = _tcsicmp(getExt(lpFile1->cFileName),getExt(lpFile2->cFileName));
+        case ORDER_EXTENSION:   /* Order by extension name /o:e */
+            iComp = _tcsicmp(getExt(lpFile1->stFindInfo.cFileName),getExt(lpFile2->stFindInfo.cFileName));
             break;
 
-        case ORDER_NAME:               /* Order by filename /o:n */
-            iComp = _tcsicmp(lpFile1->cFileName, lpFile2->cFileName);
+        case ORDER_NAME:        /* Order by filename /o:n */
+            iComp = _tcsicmp(lpFile1->stFindInfo.cFileName, lpFile2->stFindInfo.cFileName);
             break;
 
-        case ORDER_TIME:               /* Order by file's time /o:t */
+        case ORDER_TIME:        /* Order by file's time /o:t */
             /* We compare files based on the time field selected by /t */
-            switch(lpFlags->stTimeField.eTimeField)
+            switch (lpFlags->stTimeField.eTimeField)
             {
             case TF_CREATIONDATE:
                 /* concat the 32bit integers to a 64bit */
-                u64File1.LowPart = lpFile1->ftCreationTime.dwLowDateTime;
-                u64File1.HighPart = lpFile1->ftCreationTime.dwHighDateTime ;
-                u64File2.LowPart = lpFile2->ftCreationTime.dwLowDateTime;
-                u64File2.HighPart = lpFile2->ftCreationTime.dwHighDateTime ;
+                u64File1.LowPart = lpFile1->stFindInfo.ftCreationTime.dwLowDateTime;
+                u64File1.HighPart = lpFile1->stFindInfo.ftCreationTime.dwHighDateTime ;
+                u64File2.LowPart = lpFile2->stFindInfo.ftCreationTime.dwLowDateTime;
+                u64File2.HighPart = lpFile2->stFindInfo.ftCreationTime.dwHighDateTime ;
                 break;
             case TF_LASTACCESSEDDATE :
                 /* concat the 32bit integers to a 64bit */
-                u64File1.LowPart = lpFile1->ftLastAccessTime.dwLowDateTime;
-                u64File1.HighPart = lpFile1->ftLastAccessTime.dwHighDateTime ;
-                u64File2.LowPart = lpFile2->ftLastAccessTime.dwLowDateTime;
-                u64File2.HighPart = lpFile2->ftLastAccessTime.dwHighDateTime ;
+                u64File1.LowPart = lpFile1->stFindInfo.ftLastAccessTime.dwLowDateTime;
+                u64File1.HighPart = lpFile1->stFindInfo.ftLastAccessTime.dwHighDateTime ;
+                u64File2.LowPart = lpFile2->stFindInfo.ftLastAccessTime.dwLowDateTime;
+                u64File2.HighPart = lpFile2->stFindInfo.ftLastAccessTime.dwHighDateTime ;
                 break;
             case TF_MODIFIEDDATE:
                 /* concat the 32bit integers to a 64bit */
-                u64File1.LowPart = lpFile1->ftLastWriteTime.dwLowDateTime;
-                u64File1.HighPart = lpFile1->ftLastWriteTime.dwHighDateTime ;
-                u64File2.LowPart = lpFile2->ftLastWriteTime.dwLowDateTime;
-                u64File2.HighPart = lpFile2->ftLastWriteTime.dwHighDateTime ;
+                u64File1.LowPart = lpFile1->stFindInfo.ftLastWriteTime.dwLowDateTime;
+                u64File1.HighPart = lpFile1->stFindInfo.ftLastWriteTime.dwHighDateTime ;
+                u64File2.LowPart = lpFile2->stFindInfo.ftLastWriteTime.dwLowDateTime;
+                u64File2.HighPart = lpFile2->stFindInfo.ftLastWriteTime.dwHighDateTime ;
                 break;
             }
 
-            /* In case that differnce is too big for a long */
+            /* In case that difference is too big for a long */
             if (u64File1.QuadPart < u64File2.QuadPart)
                 iComp = -1;
             else if (u64File1.QuadPart > u64File2.QuadPart)
@@ -1240,12 +1275,12 @@ CompareFiles(LPWIN32_FIND_DATA lpFile1, /* [IN] A pointer to WIN32_FIND_DATA of
  * Sort files by the order criterias using quicksort method
  */
 static VOID
-QsortFiles(LPWIN32_FIND_DATA ptrArray[],    /* [IN/OUT] The array with file info pointers */
+QsortFiles(PDIRFINDINFO ptrArray[],         /* [IN/OUT] The array with file info pointers */
            int i,                           /* [IN]     The index of first item in array */
            int j,                           /* [IN]     The index to last item in array */
            LPDIRSWITCHFLAGS lpFlags)        /* [IN]     The flags that we will use to sort */
 {
-    LPWIN32_FIND_DATA lpTemp;   /* A temporary pointer */
+    PDIRFINDINFO lpTemp;   /* A temporary pointer */
     BOOL Way;
 
     if (i < j)
@@ -1277,23 +1312,45 @@ QsortFiles(LPWIN32_FIND_DATA ptrArray[],    /* [IN/OUT] The array with file info
     }
 }
 
+static VOID
+DirNodeCleanup(PDIRFINDLISTNODE ptrStartNode,
+               PDWORD pdwCount)
+{
+    PDIRFINDLISTNODE ptrNextNode;
+    PDIRFINDSTREAMNODE ptrFreeNode;
+    while (ptrStartNode)
+    {
+        ptrNextNode = ptrStartNode->ptrNext;
+        while (ptrStartNode->stInfo.ptrHead)
+        {
+            ptrFreeNode = ptrStartNode->stInfo.ptrHead;
+            ptrStartNode->stInfo.ptrHead = ptrFreeNode->ptrNext;
+            cmd_free(ptrFreeNode);
+        }
+        cmd_free(ptrStartNode);
+        ptrStartNode = ptrNextNode;
+        --(*pdwCount);
+    }
+}
+
 /*
  * DirList
  *
- * The functions that does everything except for printing results
+ * The function that does everything except for printing results
  */
 static INT
 DirList(LPTSTR szPath,              /* [IN] The path that dir starts */
         LPDIRSWITCHFLAGS lpFlags)   /* [IN] The flags of the listing */
 {
-    BOOL fPoint;                        /* If szPath is a file with extension fPoint will be True*/
+    BOOL fPoint;                        /* If szPath is a file with extension fPoint will be True */
     HANDLE hSearch;                     /* The handle of the search */
-    HANDLE hRecSearch;                  /* The handle for searching recursivly */
+    HANDLE hRecSearch;                  /* The handle for searching recursively */
+    HANDLE hStreams;                    /* The handle for alternate streams */
     WIN32_FIND_DATA wfdFileInfo;        /* The info of file that found */
-    LPWIN32_FIND_DATA * ptrFileArray;   /* An array of pointers with all the files */
+    PDIRFINDINFO * ptrFileArray;        /* An array of pointers with all the files */
     PDIRFINDLISTNODE ptrStartNode;      /* The pointer to the first node */
-    PDIRFINDLISTNODE ptrNextNode;       /* A pointer used for relatives refernces */
-    TCHAR szFullPath[MAX_PATH];         /* The full path that we are listing with trailing \ */
+    PDIRFINDLISTNODE ptrNextNode;       /* A pointer used for relatives references */
+    TCHAR szFullPath[MAX_PATH];         /* The full path that we are listing with trailing '\' */
     TCHAR szSubPath[MAX_PATH];
     LPTSTR pszFilePart;
     DWORD dwCount;                      /* A counter of files found in directory */
@@ -1301,8 +1358,12 @@ DirList(LPTSTR szPath,              /* [IN] The path that dir starts */
     DWORD dwCountDirs;                  /* Counter for directories */
     ULONGLONG u64CountBytes;            /* Counter for bytes */
     ULARGE_INTEGER u64Temp;             /* A temporary counter */
+    WIN32_FIND_STREAM_DATA wfsdStreamInfo;
+    PDIRFINDSTREAMNODE * ptrCurNode;    /* The pointer to the first stream */
+    static HANDLE (WINAPI *pFindFirstStreamW)(LPCWSTR, STREAM_INFO_LEVELS, LPVOID, DWORD);
+    static BOOL (WINAPI *pFindNextStreamW)(HANDLE, LPVOID);
 
-    /* Initialize Variables */
+    /* Initialize variables */
     ptrStartNode = NULL;
     ptrNextNode = NULL;
     dwCount = 0;
@@ -1312,7 +1373,7 @@ DirList(LPTSTR szPath,              /* [IN] The path that dir starts */
     fPoint= FALSE;
 
     /* Create szFullPath */
-    if (GetFullPathName(szPath, sizeof(szFullPath) / sizeof(TCHAR), szFullPath, &pszFilePart) == 0)
+    if (GetFullPathName(szPath, ARRAYSIZE(szFullPath), szFullPath, &pszFilePart) == 0)
     {
         _tcscpy (szFullPath, szPath);
         pszFilePart = NULL;
@@ -1333,11 +1394,12 @@ DirList(LPTSTR szPath,              /* [IN] The path that dir starts */
     if (ptrStartNode == NULL)
     {
         WARN("DEBUG: Cannot allocate memory for ptrStartNode!\n");
-        return 1;      /* Error cannot allocate memory for 1st object */
+        return 1;   /* Error cannot allocate memory for 1st object */
     }
+    ptrStartNode->stInfo.ptrHead = NULL;
     ptrNextNode = ptrStartNode;
 
-    /*Checking ir szPath is a File with/wout extension*/
+    /* Checking if szPath is a File with/wout extension */
     if (szPath[_tcslen(szPath) - 1] == _T('.'))
         fPoint= TRUE;
 
@@ -1347,8 +1409,8 @@ DirList(LPTSTR szPath,              /* [IN] The path that dir starts */
     {
         do
         {
-            /*If retrieved FileName has extension,and szPath doesnt have extension then JUMP the retrieved FileName*/
-            if (_tcschr(wfdFileInfo.cFileName,_T('.'))&&(fPoint==TRUE))
+            /* If retrieved FileName has extension,and szPath doesnt have extension then JUMP the retrieved FileName */
+            if (_tcschr(wfdFileInfo.cFileName,_T('.')) && (fPoint != FALSE))
             {
                 continue;
             /* Here we filter all the specified attributes */
@@ -1360,52 +1422,97 @@ DirList(LPTSTR szPath,              /* [IN] The path that dir starts */
                 if (ptrNextNode->ptrNext == NULL)
                 {
                     WARN("DEBUG: Cannot allocate memory for ptrNextNode->ptrNext!\n");
-                    while (ptrStartNode)
-                    {
-                        ptrNextNode = ptrStartNode->ptrNext;
-                        cmd_free(ptrStartNode);
-                        ptrStartNode = ptrNextNode;
-                        dwCount--;
-                    }
+                    DirNodeCleanup(ptrStartNode, &dwCount);
                     FindClose(hSearch);
                     return 1;
                 }
 
-                /* If cmd_alloc fails we go to next file in hope it works,
-                   without braking the linked list! */
-                if (ptrNextNode->ptrNext)
+                /* Copy the info of search at linked list */
+                memcpy(&ptrNextNode->ptrNext->stInfo.stFindInfo,
+                       &wfdFileInfo,
+                       sizeof(WIN32_FIND_DATA));
+
+                /* If lower case is selected do it here */
+                if (lpFlags->bLowerCase)
                 {
-                    /* Copy the info of search at linked list */
-                    memcpy(&ptrNextNode->ptrNext->stFindInfo,
-                           &wfdFileInfo,
-                           sizeof(WIN32_FIND_DATA));
+                    _tcslwr(ptrNextNode->ptrNext->stInfo.stFindInfo.cAlternateFileName);
+                    _tcslwr(ptrNextNode->ptrNext->stInfo.stFindInfo.cFileName);
+                }
 
-                    /* If lower case is selected do it here */
-                    if (lpFlags->bLowerCase)
+                /* No streams (yet?) */
+                ptrNextNode->ptrNext->stInfo.ptrHead = NULL;
+
+                /* Alternate streams are only displayed with new long list */
+                if (lpFlags->bNewLongList && lpFlags->bDataStreams)
+                {
+                    if (!pFindFirstStreamW)
                     {
-                        _tcslwr(ptrNextNode->ptrNext->stFindInfo.cAlternateFileName);
-                        _tcslwr(ptrNextNode->ptrNext->stFindInfo.cFileName);
+                        pFindFirstStreamW = (PVOID)GetProcAddress(GetModuleHandle(_T("kernel32")), "FindFirstStreamW");
+                        pFindNextStreamW = (PVOID)GetProcAddress(GetModuleHandle(_T("kernel32")), "FindNextStreamW");
                     }
 
-                    /* Continue at next node at linked list */
-                    ptrNextNode = ptrNextNode->ptrNext;
-                    dwCount ++;
-
-                    /* Grab statistics */
-                    if (wfdFileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+                    /* Try to get stream information */
+                    if (pFindFirstStreamW && pFindNextStreamW)
                     {
-                        /* Directory */
-                        dwCountDirs++;
+                        hStreams = pFindFirstStreamW(wfdFileInfo.cFileName, FindStreamInfoStandard, &wfsdStreamInfo, 0);
                     }
                     else
                     {
-                        /* File */
-                        dwCountFiles++;
-                        u64Temp.HighPart = wfdFileInfo.nFileSizeHigh;
-                        u64Temp.LowPart = wfdFileInfo.nFileSizeLow;
-                        u64CountBytes += u64Temp.QuadPart;
+                        hStreams = INVALID_HANDLE_VALUE;
+                        ERR("FindFirstStreamW not supported!\n");
+                    }
+
+                    if (hStreams != INVALID_HANDLE_VALUE)
+                    {
+                        /* We totally ignore first stream. It contains data about ::$DATA */
+                        ptrCurNode = &ptrNextNode->ptrNext->stInfo.ptrHead;
+                        while (pFindNextStreamW(hStreams, &wfsdStreamInfo))
+                        {
+                            *ptrCurNode = cmd_alloc(sizeof(DIRFINDSTREAMNODE));
+                            if (*ptrCurNode == NULL)
+                            {
+                                WARN("DEBUG: Cannot allocate memory for *ptrCurNode!\n");
+                                DirNodeCleanup(ptrStartNode, &dwCount);
+                                FindClose(hStreams);
+                                FindClose(hSearch);
+                                return 1;
+                            }
+
+                            memcpy(&(*ptrCurNode)->stStreamInfo, &wfsdStreamInfo,
+                                   sizeof(WIN32_FIND_STREAM_DATA));
+
+                            /* If lower case is selected do it here */
+                            if (lpFlags->bLowerCase)
+                            {
+                                _tcslwr((*ptrCurNode)->stStreamInfo.cStreamName);
+                            }
+
+                            ptrCurNode = &(*ptrCurNode)->ptrNext;
+                        }
+
+                        FindClose(hStreams);
+                        *ptrCurNode = NULL;
                     }
                 }
+
+                /* Continue at next node at linked list */
+                ptrNextNode = ptrNextNode->ptrNext;
+                dwCount++;
+
+                /* Grab statistics */
+                if (wfdFileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+                {
+                    /* Directory */
+                    dwCountDirs++;
+                }
+                else
+                {
+                    /* File */
+                    dwCountFiles++;
+                    u64Temp.HighPart = wfdFileInfo.nFileSizeHigh;
+                    u64Temp.LowPart = wfdFileInfo.nFileSizeLow;
+                    u64CountBytes += u64Temp.QuadPart;
+                }
             }
         } while (FindNextFile(hSearch, &wfdFileInfo));
         FindClose(hSearch);
@@ -1415,17 +1522,11 @@ DirList(LPTSTR szPath,              /* [IN] The path that dir starts */
     ptrNextNode->ptrNext = NULL;
 
     /* Calculate and allocate space need for making an array of pointers */
-    ptrFileArray = cmd_alloc(sizeof(LPWIN32_FIND_DATA) * dwCount);
+    ptrFileArray = cmd_alloc(sizeof(PDIRFINDINFO) * dwCount);
     if (ptrFileArray == NULL)
     {
         WARN("DEBUG: Cannot allocate memory for ptrFileArray!\n");
-        while (ptrStartNode)
-        {
-            ptrNextNode = ptrStartNode->ptrNext;
-            cmd_free(ptrStartNode);
-            ptrStartNode = ptrNextNode;
-            dwCount --;
-        }
+        DirNodeCleanup(ptrStartNode, &dwCount);
         return 1;
     }
 
@@ -1437,12 +1538,12 @@ DirList(LPTSTR szPath,              /* [IN] The path that dir starts */
     dwCount = 0;
     while (ptrNextNode->ptrNext)
     {
-        *(ptrFileArray + dwCount) = &ptrNextNode->ptrNext->stFindInfo;
+        ptrFileArray[dwCount] = &ptrNextNode->ptrNext->stInfo;
         ptrNextNode = ptrNextNode->ptrNext;
         dwCount++;
     }
 
-    /* Sort Data if requested*/
+    /* Sort Data if requested */
     if (lpFlags->stOrderBy.sCriteriaCount > 0)
         QsortFiles(ptrFileArray, 0, dwCount-1, lpFlags);
 
@@ -1463,41 +1564,37 @@ DirList(LPTSTR szPath,              /* [IN] The path that dir starts */
 
     /* Free array */
     cmd_free(ptrFileArray);
+
     /* Free linked list */
-    while (ptrStartNode)
-    {
-        ptrNextNode = ptrStartNode->ptrNext;
-        cmd_free(ptrStartNode);
-        ptrStartNode = ptrNextNode;
-        dwCount --;
-    }
+    DirNodeCleanup(ptrStartNode, &dwCount);
 
     if (CheckCtrlBreak(BREAK_INPUT))
         return 1;
 
-
-    /* Add statistics to recursive statistics*/
+    /* Add statistics to recursive statistics */
     recurse_dir_cnt += dwCountDirs;
     recurse_file_cnt += dwCountFiles;
     recurse_bytes += u64CountBytes;
 
-    /* Do the recursive job if requested
-       the recursive is be done on ALL(indepent of their attribs)
-       directoried of the current one.*/
+    /*
+     * Do the recursive job if requested.
+     * The recursion is done on ALL (independent of their attributes)
+     * directories of the current one.
+     */
     if (lpFlags->bRecursive)
     {
         /* The new search is involving any *.* file */
         memcpy(szSubPath, szFullPath, (pszFilePart - szFullPath) * sizeof(TCHAR));
         _tcscpy(&szSubPath[pszFilePart - szFullPath], _T("*.*"));
 
-        hRecSearch = FindFirstFile (szSubPath, &wfdFileInfo);
+        hRecSearch = FindFirstFile(szSubPath, &wfdFileInfo);
         if (hRecSearch != INVALID_HANDLE_VALUE)
         {
             do
             {
                 /* We search for directories other than "." and ".." */
-                if ((_tcsicmp(wfdFileInfo.cFileName, _T(".")) != 0) &&
-                    (_tcsicmp(wfdFileInfo.cFileName, _T("..")) != 0 ) &&
+                if ((_tcsicmp(wfdFileInfo.cFileName, _T("."))  != 0) &&
+                    (_tcsicmp(wfdFileInfo.cFileName, _T("..")) != 0) &&
                     (wfdFileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
                 {
                     /* Concat the path and the directory to do recursive */
@@ -1513,7 +1610,7 @@ DirList(LPTSTR szPath,              /* [IN] The path that dir starts */
                         return 1;
                     }
                 }
-            } while(FindNextFile(hRecSearch, &wfdFileInfo));
+            } while (FindNextFile(hRecSearch, &wfdFileInfo));
         }
         FindClose(hRecSearch);
     }
@@ -1529,7 +1626,7 @@ DirList(LPTSTR szPath,              /* [IN] The path that dir starts */
 INT
 CommandDir(LPTSTR rest)
 {
-    TCHAR   dircmd[256];    /* A variable to store the DIRCMD enviroment variable */
+    TCHAR   dircmd[MAX_PATH];   /* A variable to store the DIRCMD environment variable */
     TCHAR   path[MAX_PATH];
     TCHAR   prev_volume[MAX_PATH];
     LPTSTR* params = NULL;
@@ -1540,15 +1637,16 @@ CommandDir(LPTSTR rest)
     INT ret = 1;
     BOOL ChangedVolume;
 
-    /* Initialize Switch Flags < Default switches are setted here!> */
+    /* Initialize Switch Flags < Default switches are set here! > */
     stFlags.b4Digit = TRUE;
     stFlags.bBareFormat = FALSE;
+    stFlags.bDataStreams = FALSE;
     stFlags.bLowerCase = FALSE;
     stFlags.bNewLongList = TRUE;
     stFlags.bPause = FALSE;
     stFlags.bRecursive = FALSE;
     stFlags.bShortName = FALSE;
-    stFlags.bTSeperator = TRUE;
+    stFlags.bTSeparator = TRUE;
     stFlags.bUser = FALSE;
     stFlags.bWideList = FALSE;
     stFlags.bWideListColSort = FALSE;
@@ -1559,8 +1657,8 @@ CommandDir(LPTSTR rest)
 
     nErrorLevel = 0;
 
-    /* read the parameters from the DIRCMD environment variable */
-    if (GetEnvironmentVariable (_T("DIRCMD"), dircmd, 256))
+    /* Read the parameters from the DIRCMD environment variable */
+    if (GetEnvironmentVariable (_T("DIRCMD"), dircmd, ARRAYSIZE(dircmd)))
     {
         if (!DirReadParam(dircmd, &params, &entries, &stFlags))
         {
@@ -1569,14 +1667,14 @@ CommandDir(LPTSTR rest)
         }
     }
 
-    /* read the parameters */
+    /* Read the parameters */
     if (!DirReadParam(rest, &params, &entries, &stFlags) || CheckCtrlBreak(BREAK_INPUT))
     {
         nErrorLevel = 1;
         goto cleanup;
     }
 
-    /* default to current directory */
+    /* Default to current directory */
     if (entries == 0)
     {
         if (!add_entry(&entries, &params, _T("*")))
@@ -1592,7 +1690,7 @@ CommandDir(LPTSTR rest)
     if (stFlags.bPause)
         ConOutPrintfPaging(TRUE, _T(""));
 
-    for(loop = 0; loop < (UINT)entries; loop++)
+    for (loop = 0; loop < (UINT)entries; loop++)
     {
         if (CheckCtrlBreak(BREAK_INPUT))
         {
@@ -1608,36 +1706,37 @@ CommandDir(LPTSTR rest)
            Uncomment this to show the final state of switch flags*/
         {
             int i;
-            TRACE("Attributes mask/value %x/%x\n",stFlags.stAttribs.dwAttribMask,stFlags.stAttribs.dwAttribVal  );
-            TRACE("(B) Bare format : %i\n", stFlags.bBareFormat );
-            TRACE("(C) Thousand : %i\n", stFlags.bTSeperator );
-            TRACE("(W) Wide list : %i\n", stFlags.bWideList );
-            TRACE("(D) Wide list sort by column : %i\n", stFlags.bWideListColSort );
-            TRACE("(L) Lowercase : %i\n", stFlags.bLowerCase );
-            TRACE("(N) New : %i\n", stFlags.bNewLongList );
-            TRACE("(O) Order : %i\n", stFlags.stOrderBy.sCriteriaCount );
+            TRACE("Attributes mask/value %x/%x\n",stFlags.stAttribs.dwAttribMask,stFlags.stAttribs.dwAttribVal);
+            TRACE("(B) Bare format : %i\n", stFlags.bBareFormat);
+            TRACE("(C) Thousand : %i\n", stFlags.bTSeparator);
+            TRACE("(W) Wide list : %i\n", stFlags.bWideList);
+            TRACE("(D) Wide list sort by column : %i\n", stFlags.bWideListColSort);
+            TRACE("(L) Lowercase : %i\n", stFlags.bLowerCase);
+            TRACE("(N) New : %i\n", stFlags.bNewLongList);
+            TRACE("(O) Order : %i\n", stFlags.stOrderBy.sCriteriaCount);
             for (i =0;i<stFlags.stOrderBy.sCriteriaCount;i++)
-                TRACE(" Order Criteria [%i]: %i (Reversed: %i)\n",i, stFlags.stOrderBy.eCriteria[i], stFlags.stOrderBy.bCriteriaRev[i] );
-            TRACE("(P) Pause : %i\n", stFlags.bPause  );
-            TRACE("(Q) Owner : %i\n", stFlags.bUser );
-            TRACE("(S) Recursive : %i\n", stFlags.bRecursive );
-            TRACE("(T) Time field : %i\n", stFlags.stTimeField.eTimeField );
-            TRACE("(X) Short names : %i\n", stFlags.bShortName );
-            TRACE("Parameter : %s\n", debugstr_aw(params[loop]) );
+                TRACE(" Order Criteria [%i]: %i (Reversed: %i)\n",i, stFlags.stOrderBy.eCriteria[i], stFlags.stOrderBy.bCriteriaRev[i]);
+            TRACE("(P) Pause : %i\n", stFlags.bPause);
+            TRACE("(Q) Owner : %i\n", stFlags.bUser);
+            TRACE("(R) Data stream : %i\n", stFlags.bDataStreams);
+            TRACE("(S) Recursive : %i\n", stFlags.bRecursive);
+            TRACE("(T) Time field : %i\n", stFlags.stTimeField.eTimeField);
+            TRACE("(X) Short names : %i\n", stFlags.bShortName);
+            TRACE("Parameter : %s\n", debugstr_aw(params[loop]));
         }
 
         /* Print the drive header if the volume changed */
         ChangedVolume = TRUE;
 
         if (!stFlags.bBareFormat &&
-            GetVolumePathName(params[loop], path, sizeof(path) / sizeof(TCHAR)))
+            GetVolumePathName(params[loop], path, ARRAYSIZE(path)))
         {
             if (!_tcscmp(path, prev_volume))
                 ChangedVolume = FALSE;
             else
                 _tcscpy(prev_volume, path);
         }
-        else if (GetFullPathName(params[loop], sizeof(path) / sizeof(TCHAR), path, &pszFilePart) != 0)
+        else if (GetFullPathName(params[loop], ARRAYSIZE(path), path, &pszFilePart) != 0)
         {
             if (pszFilePart != NULL)
                 *pszFilePart = _T('\0');
@@ -1647,23 +1746,22 @@ CommandDir(LPTSTR rest)
             _tcscpy(path, params[loop]);
         }
 
-        if (ChangedVolume && !stFlags.bBareFormat)
+        /* Print the header */
+        if (ChangedVolume && !stFlags.bBareFormat &&
+            !PrintDirectoryHeader(params[loop], &stFlags))
         {
-            if (!PrintDirectoryHeader (params[loop], &stFlags))
-            {
-                nErrorLevel = 1;
-                goto cleanup;
-            }
+            nErrorLevel = 1;
+            goto cleanup;
         }
 
-        /* do the actual dir */
-        if (DirList (params[loop], &stFlags))
+        /* Perform the actual directory listing */
+        if (DirList(params[loop], &stFlags) != 0)
         {
             nErrorLevel = 1;
             goto cleanup;
         }
 
-        /* print the footer */
+        /* Print the footer */
         PrintSummary(path,
                      recurse_file_cnt,
                      recurse_dir_cnt,