ReactOS  0.4.13-dev-259-g5ca9c9c
dir.c
Go to the documentation of this file.
1 /*
2  * DIR.C - dir internal command.
3  *
4  *
5  * History:
6  *
7  * 01/29/97 (Tim Norman)
8  * started.
9  *
10  * 06/13/97 (Tim Norman)
11  * Fixed code.
12  *
13  * 07/12/97 (Tim Norman)
14  * Fixed bug that caused the root directory to be unlistable
15  *
16  * 07/12/97 (Marc Desrochers)
17  * Changed to use maxx, maxy instead of findxy()
18  *
19  * 06/08/98 (Rob Lake)
20  * Added compatibility for /w in dir
21  *
22  * 06/09/98 (Rob Lake)
23  * Compatibility for dir/s started
24  * Tested that program finds directories off root fine
25  *
26  * 06/10/98 (Rob Lake)
27  * do_recurse saves the cwd and also stores it in Root
28  * build_tree adds the cwd to the beginning of its' entries
29  * Program runs fine, added print_tree -- works fine.. as EXE,
30  * program won't work properly as COM.
31  *
32  * 06/11/98 (Rob Lake)
33  * Found problem that caused COM not to work
34  *
35  * 06/12/98 (Rob Lake)
36  * debugged...
37  * added free mem routine
38  *
39  * 06/13/98 (Rob Lake)
40  * debugged the free mem routine
41  * debugged whole thing some more
42  * Notes:
43  * ReadDir stores Root name and _Read_Dir does the hard work
44  * PrintDir prints Root and _Print_Dir does the hard work
45  * KillDir kills Root _after_ _Kill_Dir does the hard work
46  * Integrated program into DIR.C(this file) and made some same
47  * changes throughout
48  *
49  * 06/14/98 (Rob Lake)
50  * Cleaned up code a bit, added comments
51  *
52  * 06/16/98 (Rob Lake)
53  * Added error checking to my previously added routines
54  *
55  * 06/17/98 (Rob Lake)
56  * Rewrote recursive functions, again! Most other recursive
57  * functions are now obsolete -- ReadDir, PrintDir, _Print_Dir,
58  * KillDir and _Kill_Dir. do_recurse does what PrintDir did
59  * and _Read_Dir did what it did before along with what _Print_Dir
60  * did. Makes /s a lot faster!
61  * Reports 2 more files/dirs that MS-DOS actually reports
62  * when used in root directory(is this because dir defaults
63  * to look for read only files?)
64  * Added support for /b, /a and /l
65  * Made error message similar to DOS error messages
66  * Added help screen
67  *
68  * 06/20/98 (Rob Lake)
69  * Added check for /-(switch) to turn off previously defined
70  * switches.
71  * Added ability to check for DIRCMD in environment and
72  * process it
73  *
74  * 06/21/98 (Rob Lake)
75  * Fixed up /B
76  * Now can dir *.ext/X, no spaces!
77  *
78  * 06/29/98 (Rob Lake)
79  * error message now found in command.h
80  *
81  * 07/08/1998 (John P. Price)
82  * removed extra returns; closer to MSDOS
83  * fixed wide display so that an extra return is not displayed
84  * when there is five filenames in the last line.
85  *
86  * 07/12/98 (Rob Lake)
87  * Changed error messages
88  *
89  * 27-Jul-1998 (John P Price <linux-guru@gcfl.net>)
90  * added config.h include
91  *
92  *
93  * 04-Dec-1998 (Eric Kohl)
94  * Converted source code to Win32, except recursive dir ("dir /s").
95  *
96  * 10-Dec-1998 (Eric Kohl)
97  * Fixed recursive dir ("dir /s").
98  *
99  * 14-Dec-1998 (Eric Kohl)
100  * Converted to Win32 directory functions and
101  * fixed some output bugs. There are still some more ;)
102  *
103  * 10-Jan-1999 (Eric Kohl)
104  * Added "/N" and "/4" options, "/O" is a dummy.
105  * Added locale support.
106  *
107  * 20-Jan-1999 (Eric Kohl)
108  * Redirection safe!
109  *
110  * 01-Mar-1999 (Eric Kohl)
111  * Replaced all runtime io functions by their Win32 counterparts.
112  *
113  * 23-Feb-2001 (Carl Nettelblad <cnettel@hem.passagen.se>)
114  * dir /s now works in deeper trees
115  *
116  * 28-Jan-2004 (Michael Fritscher <michael@fritscher.net>)
117  * Fix for /p, so it is working under Windows in GUI-mode, too.
118  *
119  * 30-Apr-2004 (Filip Navara <xnavara@volny.cz>)
120  * Fix /w to print long names.
121  *
122  * 27-Feb-2005 (Konstantinos Paliouras <squarious@gmail.com>)
123  * Implemented all the switches that were missing, and made
124  * the ROS dir very similar to windows dir. Major part of
125  * the code is rewritten. /p is removed, to be rewritten in
126  * the main cmd code.
127  *
128  * 1-Jul-2004 (Brandon Turner <turnerb7@msu.edu>)
129  * Added /p back in using ConOutPrintfPaging
130  *
131  * 3-Feb-2007 (Paolo Devoti devotip at gmail)
132  * Removed variables formerly in use to handle pagination
133  * Pagination belongs to ConOutPrintfPaging
134  * Removed already commented out code of old pagination
135  *
136  * 25-Aug-2015 (Pierre Schweitzer)
137  * Implemented /R switch
138  *
139  * 6-Aug-2018 (Hermes Belusca-Maito and Katayama Hirofumi MZ)
140  * Fix handling of patterns containing trailing dots.
141  */
142 
143 #include "precomp.h"
144 
145 #ifdef INCLUDE_CMD_DIR
146 
147 /* Time Field enumeration */
149 {
153 };
154 
155 /* Ordered by enumeration */
157 {
163 };
164 
165 /* The struct for holding the switches */
166 typedef struct _DirSwitchesFlags
167 {
168  BOOL bBareFormat; /* Bare Format */
169  BOOL bTSeparator; /* Thousands separator */
170  BOOL bWideList; /* Wide list format */
171  BOOL bWideListColSort; /* Wide list format but sorted by column */
172  BOOL bLowerCase; /* Uses lower case */
173  BOOL bNewLongList; /* New long list */
174  BOOL bPause; /* Pause per page */
175  BOOL bUser; /* Displays the owner of file */
176  BOOL bRecursive; /* Displays files in specified directory and all sub */
177  BOOL bShortName; /* Displays the sort name of files if exist */
178  BOOL b4Digit; /* Four digit year */
179  BOOL bDataStreams; /* Displays alternate data streams */
180  struct
181  {
182  DWORD dwAttribVal; /* The desired state of attribute */
183  DWORD dwAttribMask; /* Which attributes to check */
184  } stAttribs; /* Displays files with this attributes only */
185  struct
186  {
187  enum EOrderBy eCriteria[3]; /* Criterias used to order by */
188  BOOL bCriteriaRev[3]; /* If the criteria is in reversed order */
189  short sCriteriaCount; /* The quantity of criterias */
190  } stOrderBy; /* Ordered by criterias */
191  struct
192  {
193  enum ETimeField eTimeField; /* The time field that will be used for */
194  } stTimeField; /* The time field to display or use for sorting */
196 
197 typedef struct _DIRFINDSTREAMNODE
198 {
199  WIN32_FIND_STREAM_DATA stStreamInfo;
202 
203 typedef struct _DIRFINDINFO
204 {
208 
209 typedef struct _DIRFINDLISTNODE
210 {
214 
215 typedef BOOL
217 
218 /* Globally save the # of dirs, files and bytes,
219  * probably later pass them to functions. Rob Lake */
223 
224 /*
225  * help
226  *
227  * displays help screen for dir
228  * Rob Lake
229  */
230 static VOID
232 {
234 }
235 
236 /* Check whether this is a dot-directory "." or "..", speed-optimized */
238 BOOL
240  IN LPCTSTR pszPath)
241 {
242  return ( pszPath[0] == _T('.') &&
243  ( pszPath[1] == 0 || /* pszPath[1] == _T('\\') || */
244  (pszPath[1] == _T('.') && (pszPath[2] == 0 /* || pszPath[2] == _T('\\') */))
245  ) );
246 }
247 
249 BOOL
251  IN const TCHAR* pPath,
252  IN SIZE_T Length)
253 {
254  return ((Length == 1 && pPath[0] == _T('.')) ||
255  (Length == 2 && pPath[0] == _T('.') && pPath[1] == _T('.')));
256 }
257 
258 /*
259  * DirReadParameters
260  *
261  * Parse the parameters and switches of the command line and exports them
262  */
263 static BOOL
264 DirReadParam(LPTSTR Line, /* [IN] The line with the parameters & switches */
265  LPTSTR** params, /* [OUT] The parameters after parsing */
266  LPINT entries, /* [OUT] The number of parameters after parsing */
267  LPDIRSWITCHFLAGS lpFlags) /* [IN/OUT] The flags after calculating switches */
268 {
269  TCHAR cCurSwitch; /* The current switch */
270  TCHAR cCurChar; /* Current examined character */
271  TCHAR cCurUChar; /* Current upper examined character */
272  BOOL bNegative; /* Negative switch */
273  BOOL bPNegative; /* Negative switch parameter */
274  BOOL bIntoQuotes; /* A flag showing if we are in quotes (") */
275  LPTSTR ptrStart; /* A pointer to the first character of a parameter */
276  LPTSTR ptrEnd; /* A pointer to the last character of a parameter */
277  BOOL bOrderByNoPar; /* A flag to indicate /O with no switch parameter */
278  LPTSTR temp;
279 
280  /* Initialize parameter array */
281  *params = NULL;
282  *entries = 0;
283 
284  /* Initialize variables; */
285  cCurSwitch = _T(' ');
286  bNegative = FALSE;
287  bPNegative = FALSE;
288 
289  /* We suppose that switch parameters
290  were given to avoid setting them to default
291  if the switch was not given */
292  bOrderByNoPar = FALSE;
293 
294  /* Main Loop (see README_DIR.txt) */
295  /* scan the command line char per char, and we process its char */
296  while (*Line)
297  {
298  /* we save current character as it is and its upper case */
299  cCurChar = *Line;
300  cCurUChar = _totupper(*Line);
301 
302  /* 1st section (see README_DIR.txt) */
303  /* When a switch is expecting */
304  if (cCurSwitch == _T('/'))
305  {
306  while (_istspace(*Line))
307  Line++;
308 
309  bNegative = (*Line == _T('-'));
310  Line += bNegative;
311 
312  cCurChar = *Line;
313  cCurUChar = _totupper(*Line);
314 
315  if ((cCurUChar == _T('A')) ||(cCurUChar == _T('T')) || (cCurUChar == _T('O')))
316  {
317  /* If positive, prepare for parameters... if negative, reset to defaults */
318  switch (cCurUChar)
319  {
320  case _T('A'):
321  lpFlags->stAttribs.dwAttribVal = 0L;
322  lpFlags->stAttribs.dwAttribMask = 0L;
323  if (bNegative)
324  lpFlags->stAttribs.dwAttribMask = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
325  break;
326  case _T('T'):
327  if (bNegative)
328  lpFlags->stTimeField.eTimeField = TF_MODIFIEDDATE;
329  break;
330  case _T('O'):
331  bOrderByNoPar = !bNegative;
332  lpFlags->stOrderBy.sCriteriaCount = 0;
333  break;
334  }
335 
336  if (!bNegative)
337  {
338  /* Positive switch, so it can take parameters. */
339  cCurSwitch = cCurUChar;
340  Line++;
341  /* Skip optional leading colon */
342  if (*Line == _T(':'))
343  Line++;
344  continue;
345  }
346  }
347  else if (cCurUChar == _T('L'))
348  lpFlags->bLowerCase = ! bNegative;
349  else if (cCurUChar == _T('B'))
350  lpFlags->bBareFormat = ! bNegative;
351  else if (cCurUChar == _T('C'))
352  lpFlags->bTSeparator = ! bNegative;
353  else if (cCurUChar == _T('W'))
354  lpFlags->bWideList = ! bNegative;
355  else if (cCurUChar == _T('D'))
356  lpFlags->bWideListColSort = ! bNegative;
357  else if (cCurUChar == _T('N'))
358  lpFlags->bNewLongList = ! bNegative;
359  else if (cCurUChar == _T('P'))
360  lpFlags->bPause = ! bNegative;
361  else if (cCurUChar == _T('Q'))
362  lpFlags->bUser = ! bNegative;
363  else if (cCurUChar == _T('S'))
364  lpFlags->bRecursive = ! bNegative;
365  else if (cCurUChar == _T('X'))
366  lpFlags->bShortName = ! bNegative;
367  else if (cCurUChar == _T('R'))
368  lpFlags->bDataStreams = ! bNegative;
369  else if (cCurChar == _T('4'))
370  lpFlags->b4Digit = ! bNegative;
371  else if (cCurChar == _T('?'))
372  {
373  DirHelp();
374  return FALSE;
375  }
376  else
377  {
379  return FALSE;
380  }
381 
382  /* Make sure there's no extra characters at the end of the switch */
383  if (Line[1] && Line[1] != _T('/') && !_istspace(Line[1]))
384  {
386  return FALSE;
387  }
388 
389  cCurSwitch = _T(' ');
390  }
391  else if (cCurSwitch == _T(' '))
392  {
393  /* 2nd section (see README_DIR.txt) */
394  /* We are expecting parameter or the unknown */
395 
396  if (cCurChar == _T('/'))
397  cCurSwitch = _T('/');
398  else if (_istspace(cCurChar))
399  /* do nothing */;
400  else
401  {
402  /* This is a file/directory name parameter. Find its end */
403  ptrStart = Line;
404  bIntoQuotes = FALSE;
405  while (*Line)
406  {
407  if (!bIntoQuotes && (*Line == _T('/') || _istspace(*Line)))
408  break;
409  bIntoQuotes ^= (*Line == _T('"'));
410  Line++;
411  }
412  ptrEnd = Line;
413 
414  /* Copy it to the entries list */
415  temp = cmd_alloc((ptrEnd - ptrStart + 1) * sizeof(TCHAR));
416  if (!temp)
417  return FALSE;
418  memcpy(temp, ptrStart, (ptrEnd - ptrStart) * sizeof(TCHAR));
419  temp[ptrEnd - ptrStart] = _T('\0');
420  StripQuotes(temp);
421  if (!add_entry(entries, params, temp))
422  {
423  cmd_free(temp);
424  freep(*params);
425  return FALSE;
426  }
427 
428  cmd_free(temp);
429  continue;
430  }
431  }
432  else
433  {
434  /* 3rd section (see README_DIR.txt) */
435  /* We are waiting for switch parameters */
436 
437  /* Check if there are no more switch parameters */
438  if ((cCurChar == _T('/')) || _istspace(cCurChar))
439  {
440  /* Wrong decision path, reprocess current character */
441  cCurSwitch = _T(' ');
442  continue;
443  }
444  /* Process parameter switch */
445  switch (cCurSwitch)
446  {
447  case _T('A'): /* Switch parameters for /A (attributes filter) */
448  if (cCurChar == _T('-'))
449  bPNegative = TRUE;
450  else if (cCurUChar == _T('D'))
451  {
452  lpFlags->stAttribs.dwAttribMask |= FILE_ATTRIBUTE_DIRECTORY;
453  if (bPNegative)
454  lpFlags->stAttribs.dwAttribVal &= ~FILE_ATTRIBUTE_DIRECTORY;
455  else
456  lpFlags->stAttribs.dwAttribVal |= FILE_ATTRIBUTE_DIRECTORY;
457  }
458  else if (cCurUChar == _T('R'))
459  {
460  lpFlags->stAttribs.dwAttribMask |= FILE_ATTRIBUTE_READONLY;
461  if (bPNegative)
462  lpFlags->stAttribs.dwAttribVal &= ~FILE_ATTRIBUTE_READONLY;
463  else
464  lpFlags->stAttribs.dwAttribVal |= FILE_ATTRIBUTE_READONLY;
465  }
466  else if (cCurUChar == _T('H'))
467  {
468  lpFlags->stAttribs.dwAttribMask |= FILE_ATTRIBUTE_HIDDEN;
469  if (bPNegative)
470  lpFlags->stAttribs.dwAttribVal &= ~FILE_ATTRIBUTE_HIDDEN;
471  else
472  lpFlags->stAttribs.dwAttribVal |= FILE_ATTRIBUTE_HIDDEN;
473  }
474  else if (cCurUChar == _T('A'))
475  {
476  lpFlags->stAttribs.dwAttribMask |= FILE_ATTRIBUTE_ARCHIVE;
477  if (bPNegative)
478  lpFlags->stAttribs.dwAttribVal &= ~FILE_ATTRIBUTE_ARCHIVE;
479  else
480  lpFlags->stAttribs.dwAttribVal |= FILE_ATTRIBUTE_ARCHIVE;
481  }
482  else if (cCurUChar == _T('S'))
483  {
484  lpFlags->stAttribs.dwAttribMask |= FILE_ATTRIBUTE_SYSTEM;
485  if (bPNegative)
486  lpFlags->stAttribs.dwAttribVal &= ~FILE_ATTRIBUTE_SYSTEM;
487  else
488  lpFlags->stAttribs.dwAttribVal |= FILE_ATTRIBUTE_SYSTEM;
489  }
490  else
491  {
493  return FALSE;
494  }
495  break;
496  case _T('T'): /* Switch parameters for /T (time field) */
497  if (cCurUChar == _T('C'))
498  lpFlags->stTimeField.eTimeField= TF_CREATIONDATE ;
499  else if (cCurUChar == _T('A'))
500  lpFlags->stTimeField.eTimeField= TF_LASTACCESSEDDATE ;
501  else if (cCurUChar == _T('W'))
502  lpFlags->stTimeField.eTimeField= TF_MODIFIEDDATE ;
503  else
504  {
506  return FALSE;
507  }
508  break;
509  case _T('O'): /* Switch parameters for /O (order) */
510  /* Ok a switch parameter was given */
511  bOrderByNoPar = FALSE;
512 
513  if (cCurChar == _T('-'))
514  bPNegative = TRUE;
515  else if (cCurUChar == _T('N'))
516  {
517  if (lpFlags->stOrderBy.sCriteriaCount < 3) lpFlags->stOrderBy.sCriteriaCount++;
518  lpFlags->stOrderBy.bCriteriaRev[lpFlags->stOrderBy.sCriteriaCount - 1] = bPNegative;
519  lpFlags->stOrderBy.eCriteria[lpFlags->stOrderBy.sCriteriaCount - 1] = ORDER_NAME;
520  }
521  else if (cCurUChar == _T('S'))
522  {
523  if (lpFlags->stOrderBy.sCriteriaCount < 3) lpFlags->stOrderBy.sCriteriaCount++;
524  lpFlags->stOrderBy.bCriteriaRev[lpFlags->stOrderBy.sCriteriaCount - 1] = bPNegative;
525  lpFlags->stOrderBy.eCriteria[lpFlags->stOrderBy.sCriteriaCount - 1] = ORDER_SIZE;
526  }
527  else if (cCurUChar == _T('G'))
528  {
529  if (lpFlags->stOrderBy.sCriteriaCount < 3) lpFlags->stOrderBy.sCriteriaCount++;
530  lpFlags->stOrderBy.bCriteriaRev[lpFlags->stOrderBy.sCriteriaCount - 1] = bPNegative;
531  lpFlags->stOrderBy.eCriteria[lpFlags->stOrderBy.sCriteriaCount - 1] = ORDER_DIRECTORY;
532  }
533  else if (cCurUChar == _T('E'))
534  {
535  if (lpFlags->stOrderBy.sCriteriaCount < 3) lpFlags->stOrderBy.sCriteriaCount++;
536  lpFlags->stOrderBy.bCriteriaRev[lpFlags->stOrderBy.sCriteriaCount - 1] = bPNegative;
537  lpFlags->stOrderBy.eCriteria[lpFlags->stOrderBy.sCriteriaCount - 1] = ORDER_EXTENSION;
538  }
539  else if (cCurUChar == _T('D'))
540  {
541  if (lpFlags->stOrderBy.sCriteriaCount < 3) lpFlags->stOrderBy.sCriteriaCount++;
542  lpFlags->stOrderBy.bCriteriaRev[lpFlags->stOrderBy.sCriteriaCount - 1] = bPNegative;
543  lpFlags->stOrderBy.eCriteria[lpFlags->stOrderBy.sCriteriaCount - 1] = ORDER_TIME;
544  }
545 
546  else
547  {
549  return FALSE;
550  }
551 
552 
553  }
554  /* We check if we calculated the negative value and release the flag */
555  if ((cCurChar != _T('-')) && bPNegative)
556  bPNegative = FALSE;
557  }
558 
559  Line++;
560  }
561 
562  /* /O with no switch parameters acts like /O:GN */
563  if (bOrderByNoPar)
564  {
565  lpFlags->stOrderBy.sCriteriaCount = 2;
566  lpFlags->stOrderBy.eCriteria[0] = ORDER_DIRECTORY;
567  lpFlags->stOrderBy.bCriteriaRev[0] = FALSE;
568  lpFlags->stOrderBy.eCriteria[1] = ORDER_NAME;
569  lpFlags->stOrderBy.bCriteriaRev[1] = FALSE;
570  }
571 
572  return TRUE;
573 }
574 
575 /* Print either with or without paging, depending on /P switch */
576 static BOOL
577 DirPrintf(LPDIRSWITCHFLAGS lpFlags, LPTSTR szFormat, ...)
578 {
579  BOOL Done = TRUE;
580  va_list arg_ptr;
581  va_start(arg_ptr, szFormat);
582  if (lpFlags->bPause)
583  Done = ConPrintfVPaging(&StdOutPager, FALSE, szFormat, arg_ptr);
584  else
585  ConPrintfV(StdOut, szFormat, arg_ptr);
586  va_end(arg_ptr);
587  return Done;
588 }
589 
590 
591 /*
592  * PrintDirectoryHeader
593  *
594  * print the header for the dir command
595  */
596 static BOOL
598 {
599  TCHAR szMsg[RC_STRING_MAX_SIZE];
600  LPCTSTR szFullDir;
601  TCHAR szRootName[MAX_PATH];
602  TCHAR szVolName[80];
603  DWORD dwSerialNr;
604 
605  if (lpFlags->bBareFormat)
606  return TRUE;
607 
608  szFullDir = szPath;
609 
610  /* Get the media ID of the drive */
611  if (!GetVolumePathName(szFullDir, szRootName, ARRAYSIZE(szRootName)) ||
612  !GetVolumeInformation(szRootName, szVolName, ARRAYSIZE(szVolName),
613  &dwSerialNr, NULL, NULL, NULL, 0))
614  {
615  return TRUE;
616  }
617 
618  /* Print drive info */
619  if (szVolName[0] != _T('\0'))
620  {
622  DirPrintf(lpFlags, szMsg, _totupper(szRootName[0]), szVolName);
623  }
624  else
625  {
627  DirPrintf(lpFlags, szMsg, _totupper(szRootName[0]));
628  }
629 
630  /* Print the volume serial number if the return was successful */
632  DirPrintf(lpFlags, szMsg, HIWORD(dwSerialNr), LOWORD(dwSerialNr));
633 
634  return TRUE;
635 }
636 
637 
638 static VOID
640  TCHAR *lpTime,
641  LPWIN32_FIND_DATA lpFile,
642  LPDIRSWITCHFLAGS lpFlags)
643 {
644  FILETIME ft;
645  SYSTEMTIME dt;
646 
647  /* Select the right time field */
648  switch (lpFlags->stTimeField.eTimeField)
649  {
650  case TF_CREATIONDATE:
651  if (!FileTimeToLocalFileTime(&lpFile->ftCreationTime, &ft))
652  return;
653  FileTimeToSystemTime(&ft, &dt);
654  break;
655 
656  case TF_LASTACCESSEDDATE :
657  if (!FileTimeToLocalFileTime(&lpFile->ftLastAccessTime, &ft))
658  return;
659  FileTimeToSystemTime(&ft, &dt);
660  break;
661 
662  case TF_MODIFIEDDATE:
663  if (!FileTimeToLocalFileTime(&lpFile->ftLastWriteTime, &ft))
664  return;
665  FileTimeToSystemTime(&ft, &dt);
666  break;
667  }
668 
669  FormatDate(lpDate, &dt, lpFlags->b4Digit);
670  FormatTime(lpTime, &dt);
671 }
672 
673 INT
674 FormatDate(TCHAR *lpDate, LPSYSTEMTIME dt, BOOL b4Digit)
675 {
676  /* Format date */
677  WORD wYear = b4Digit ? dt->wYear : dt->wYear%100;
678  switch (nDateFormat)
679  {
680  case 0: /* mmddyy */
681  default:
682  return _stprintf(lpDate, _T("%02d%c%02d%c%0*d"),
683  dt->wMonth, cDateSeparator,
684  dt->wDay, cDateSeparator,
685  b4Digit?4:2, wYear);
686  break;
687 
688  case 1: /* ddmmyy */
689  return _stprintf(lpDate, _T("%02d%c%02d%c%0*d"),
690  dt->wDay, cDateSeparator, dt->wMonth,
691  cDateSeparator, b4Digit?4:2, wYear);
692  break;
693 
694  case 2: /* yymmdd */
695  return _stprintf(lpDate, _T("%0*d%c%02d%c%02d"),
696  b4Digit?4:2, wYear, cDateSeparator,
697  dt->wMonth, cDateSeparator, dt->wDay);
698  break;
699  }
700 }
701 
702 INT
704 {
705  /* Format Time */
706  switch (nTimeFormat)
707  {
708  case 0: /* 12 hour format */
709  default:
710  return _stprintf(lpTime,_T("%02d%c%02u %cM"),
711  (dt->wHour == 0 ? 12 : (dt->wHour <= 12 ? dt->wHour : dt->wHour - 12)),
713  dt->wMinute, (dt->wHour <= 11 ? _T('A') : _T('P')));
714  break;
715 
716  case 1: /* 24 hour format */
717  return _stprintf(lpTime, _T("%02d%c%02u"),
718  dt->wHour, cTimeSeparator, dt->wMinute);
719  break;
720  }
721 }
722 
723 
724 static VOID
726  PULARGE_INTEGER lpFreeSpace)
727 {
728  PGETFREEDISKSPACEEX pGetFreeDiskSpaceEx;
730  DWORD dwSecPerCl;
731  DWORD dwBytPerSec;
732  DWORD dwFreeCl;
733  DWORD dwTotCl;
734  ULARGE_INTEGER TotalNumberOfBytes, TotalNumberOfFreeBytes;
735 
736  lpFreeSpace->QuadPart = 0;
737 
738  hInstance = GetModuleHandle(_T("KERNEL32"));
739  if (hInstance != NULL)
740  {
741  pGetFreeDiskSpaceEx = (PGETFREEDISKSPACEEX)GetProcAddress(hInstance,
742 #ifdef _UNICODE
743  "GetDiskFreeSpaceExW");
744 #else
745  "GetDiskFreeSpaceExA");
746 #endif
747  if (pGetFreeDiskSpaceEx != NULL)
748  {
749  if (pGetFreeDiskSpaceEx(lpRoot, lpFreeSpace, &TotalNumberOfBytes, &TotalNumberOfFreeBytes) != FALSE)
750  return;
751  }
752  }
753 
754  GetDiskFreeSpace(lpRoot,
755  &dwSecPerCl,
756  &dwBytPerSec,
757  &dwFreeCl,
758  &dwTotCl);
759 
760  lpFreeSpace->QuadPart = dwSecPerCl * dwBytPerSec * dwFreeCl;
761 }
762 
763 
764 /*
765  * print_summary: prints dir summary
766  * Added by Rob Lake 06/17/98 to compact code
767  * Just copied Tim's Code and patched it a bit
768  */
769 static INT
771  ULONG ulFiles,
772  ULONG ulDirs,
773  ULONGLONG u64Bytes,
774  LPDIRSWITCHFLAGS lpFlags,
775  BOOL TotalSummary)
776 {
777  TCHAR szMsg[RC_STRING_MAX_SIZE];
778  TCHAR szBuffer[64];
779  ULARGE_INTEGER uliFree;
780 
781  /* Here we check if we didn't find anything */
782  if (!(ulFiles + ulDirs))
783  {
784  if (!lpFlags->bRecursive || (TotalSummary && lpFlags->bRecursive))
786  return 1;
787  }
788 
789  /* In bare format we don't print results */
790  if (lpFlags->bBareFormat)
791  return 0;
792 
793  /* Print recursive specific results */
794 
795  /* Take this code offline to fix /S does not print double info */
796  if (TotalSummary && lpFlags->bRecursive)
797  {
798  ConvertULargeInteger(u64Bytes, szBuffer, ARRAYSIZE(szBuffer), lpFlags->bTSeparator);
800  DirPrintf(lpFlags, szMsg, ulFiles, szBuffer);
801  }
802  else
803  {
804  /* Print File Summary */
805  /* Condition to print summary is:
806  If we are not in bare format and if we have results! */
807  ConvertULargeInteger(u64Bytes, szBuffer, ARRAYSIZE(szBuffer), lpFlags->bTSeparator);
809  DirPrintf(lpFlags, szMsg, ulFiles, szBuffer);
810  }
811 
812  /* Print total directories and free space */
813  if (!lpFlags->bRecursive || TotalSummary)
814  {
815  GetUserDiskFreeSpace(szPath, &uliFree);
816  ConvertULargeInteger(uliFree.QuadPart, szBuffer, ARRAYSIZE(szBuffer), lpFlags->bTSeparator);
818  DirPrintf(lpFlags, szMsg, ulDirs, szBuffer);
819  }
820 
821  return 0;
822 }
823 
824 /*
825  * getExt
826  *
827  * Get the extension of a filename
828  */
830 {
831  static TCHAR *NoExt = _T("");
832  TCHAR* lastdot = _tcsrchr(file, _T('.'));
833  return (lastdot != NULL ? lastdot + 1 : NoExt);
834 }
835 
836 /*
837  * getName
838  *
839  * Get the name of the file without extension
840  */
841 static LPTSTR
843 {
844  INT_PTR iLen;
845  LPTSTR end;
846 
847  /* Check for dot-directories "." and ".." */
848  if (IsDotDirectory(file))
849  {
850  _tcscpy(dest, file);
851  return dest;
852  }
853 
854  end = _tcsrchr(file, _T('.'));
855  if (!end)
856  iLen = _tcslen(file);
857  else
858  iLen = (end - file);
859 
860  _tcsncpy(dest, file, iLen);
861  *(dest + iLen) = _T('\0');
862 
863  return dest;
864 }
865 
866 
867 /*
868  * DirPrintNewList
869  *
870  * The function that prints in new style
871  */
872 static VOID
873 DirPrintNewList(PDIRFINDINFO ptrFiles[], /* [IN]Files' Info */
874  DWORD dwCount, /* [IN] The quantity of files */
875  LPCTSTR szCurPath, /* [IN] Full path of current directory */
876  LPDIRSWITCHFLAGS lpFlags) /* [IN] The flags used */
877 {
878  DWORD i;
879  TCHAR szSize[30];
880  TCHAR szShortName[15];
881  TCHAR szDate[20];
882  TCHAR szTime[20];
883  INT iSizeFormat;
884  ULARGE_INTEGER u64FileSize;
885  PDIRFINDSTREAMNODE ptrCurStream;
886 
887  for (i = 0; i < dwCount && !CheckCtrlBreak(BREAK_INPUT); i++)
888  {
889  /* Calculate size */
890  if (ptrFiles[i]->stFindInfo.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
891  {
892  /* Junction */
893  iSizeFormat = -14;
894  _tcscpy(szSize, _T("<JUNCTION>"));
895  }
896  else if (ptrFiles[i]->stFindInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
897  {
898  /* Directory */
899  iSizeFormat = -14;
900  _tcscpy(szSize, _T("<DIR>"));
901  }
902  else
903  {
904  /* File */
905  iSizeFormat = 14;
906  u64FileSize.HighPart = ptrFiles[i]->stFindInfo.nFileSizeHigh;
907  u64FileSize.LowPart = ptrFiles[i]->stFindInfo.nFileSizeLow;
908  ConvertULargeInteger(u64FileSize.QuadPart, szSize, 20, lpFlags->bTSeparator);
909  }
910 
911  /* Calculate short name */
912  szShortName[0] = _T('\0');
913  if (lpFlags->bShortName)
914  _stprintf(szShortName, _T(" %-12s"), ptrFiles[i]->stFindInfo.cAlternateFileName);
915 
916  /* Format date and time */
917  DirPrintFileDateTime(szDate, szTime, &ptrFiles[i]->stFindInfo, lpFlags);
918 
919  /* Print the line */
920  DirPrintf(lpFlags, _T("%10s %-6s %*s%s %s\n"),
921  szDate,
922  szTime,
923  iSizeFormat,
924  szSize,
925  szShortName,
926  ptrFiles[i]->stFindInfo.cFileName);
927 
928  /* Now, loop on the streams */
929  ptrCurStream = ptrFiles[i]->ptrHead;
930  while (ptrCurStream)
931  {
932  ConvertULargeInteger(ptrCurStream->stStreamInfo.StreamSize.QuadPart, szSize, 20, lpFlags->bTSeparator);
933 
934  /* Print the line */
935  DirPrintf(lpFlags, _T("%10s %-6s %*s%s %s%s\n"),
936  L"",
937  L"",
938  16,
939  szSize,
940  L"",
941  ptrFiles[i]->stFindInfo.cFileName,
942  ptrCurStream->stStreamInfo.cStreamName);
943  ptrCurStream = ptrCurStream->ptrNext;
944  }
945  }
946 }
947 
948 
949 /*
950  * DirPrintWideList
951  *
952  * The function that prints in wide list
953  */
954 static VOID
955 DirPrintWideList(PDIRFINDINFO ptrFiles[], /* [IN] Files' Info */
956  DWORD dwCount, /* [IN] The quantity of files */
957  LPCTSTR szCurPath, /* [IN] Full path of current directory */
958  LPDIRSWITCHFLAGS lpFlags) /* [IN] The flags used */
959 {
960  SHORT iScreenWidth;
961  USHORT iColumns;
962  USHORT iLines;
963  UINT_PTR iLongestName;
964  TCHAR szTempFname[MAX_PATH];
965  DWORD i;
966  DWORD j;
967  DWORD temp;
968 
969  /* Calculate longest name */
970  iLongestName = 1;
971  for (i = 0; i < dwCount; i++)
972  {
973  if (ptrFiles[i]->stFindInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
974  {
975  /* Directories need 2 additional characters for brackets */
976  if ((_tcslen(ptrFiles[i]->stFindInfo.cFileName) + 2) > iLongestName)
977  iLongestName = _tcslen(ptrFiles[i]->stFindInfo.cFileName) + 2;
978  }
979  else
980  {
981  if (_tcslen(ptrFiles[i]->stFindInfo.cFileName) > iLongestName)
982  iLongestName = _tcslen(ptrFiles[i]->stFindInfo.cFileName);
983  }
984  }
985 
986  /* Count the highest number of columns */
987  GetScreenSize(&iScreenWidth, NULL);
988  iColumns = (USHORT)(iScreenWidth / iLongestName);
989 
990  /* Check if there is enough space for spaces between names */
991  if (((iLongestName * iColumns) + iColumns) >= (UINT)iScreenWidth)
992  iColumns --;
993 
994  /* A last check at iColumns to avoid division by zero */
995  if (!iColumns) iColumns = 1;
996 
997  /* Calculate the lines that will be printed */
998  iLines = (USHORT)((dwCount + iColumns - 1) / iColumns);
999 
1000  for (i = 0; i < iLines && !CheckCtrlBreak(BREAK_INPUT); i++)
1001  {
1002  for (j = 0; j < iColumns; j++)
1003  {
1004  if (lpFlags->bWideListColSort)
1005  {
1006  /* Print Column sorted */
1007  temp = (j * iLines) + i;
1008  }
1009  else
1010  {
1011  /* Print Line sorted */
1012  temp = (i * iColumns) + j;
1013  }
1014 
1015  if (temp >= dwCount) break;
1016 
1017  if (ptrFiles[temp]->stFindInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1018  _stprintf(szTempFname, _T("[%s]"), ptrFiles[temp]->stFindInfo.cFileName);
1019  else
1020  _stprintf(szTempFname, _T("%s"), ptrFiles[temp]->stFindInfo.cFileName);
1021 
1022  DirPrintf(lpFlags, _T("%-*s"), iLongestName + 1, szTempFname);
1023  }
1024 
1025  /* Add a new line after the last item in the column */
1026  DirPrintf(lpFlags, _T("\n"));
1027  }
1028 }
1029 
1030 
1031 /*
1032  * DirPrintOldList
1033  *
1034  * The function that prints in old style
1035  */
1036 static VOID
1037 DirPrintOldList(PDIRFINDINFO ptrFiles[], /* [IN] Files' Info */
1038  DWORD dwCount, /* [IN] The quantity of files */
1039  LPCTSTR szCurPath, /* [IN] Full path of current directory */
1040  LPDIRSWITCHFLAGS lpFlags) /* [IN] The flags used */
1041 {
1042  DWORD i; /* An indexer for "for"s */
1043  TCHAR szName[10]; /* The name of file */
1044  TCHAR szExt[5]; /* The extension of file */
1045  TCHAR szDate[30],szTime[30]; /* Used to format time and date */
1046  TCHAR szSize[30]; /* The size of file */
1047  int iSizeFormat; /* The format of size field */
1048  ULARGE_INTEGER u64FileSize; /* The file size */
1049 
1050  for (i = 0; i < dwCount && !CheckCtrlBreak(BREAK_INPUT); i++)
1051  {
1052  /* Broke 8.3 format */
1053  if (*ptrFiles[i]->stFindInfo.cAlternateFileName )
1054  {
1055  /* If the file is long named then we read the alter name */
1056  getName( ptrFiles[i]->stFindInfo.cAlternateFileName, szName);
1057  _tcscpy(szExt, getExt( ptrFiles[i]->stFindInfo.cAlternateFileName));
1058  }
1059  else
1060  {
1061  /* If the file is not long name we read its original name */
1062  getName( ptrFiles[i]->stFindInfo.cFileName, szName);
1063  _tcscpy(szExt, getExt( ptrFiles[i]->stFindInfo.cFileName));
1064  }
1065 
1066  /* Calculate size */
1067  if (ptrFiles[i]->stFindInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1068  {
1069  /* Directory, no size it's a directory */
1070  iSizeFormat = -17;
1071  _tcscpy(szSize, _T("<DIR>"));
1072  }
1073  else
1074  {
1075  /* File */
1076  iSizeFormat = 17;
1077  u64FileSize.HighPart = ptrFiles[i]->stFindInfo.nFileSizeHigh;
1078  u64FileSize.LowPart = ptrFiles[i]->stFindInfo.nFileSizeLow;
1079  ConvertULargeInteger(u64FileSize.QuadPart, szSize, 20, lpFlags->bTSeparator);
1080  }
1081 
1082  /* Format date and time */
1083  DirPrintFileDateTime(szDate,szTime,&ptrFiles[i]->stFindInfo,lpFlags);
1084 
1085  /* Print the line */
1086  DirPrintf(lpFlags, _T("%-8s %-3s %*s %s %s\n"),
1087  szName, /* The file's 8.3 name */
1088  szExt, /* The file's 8.3 extension */
1089  iSizeFormat, /* print format for size column */
1090  szSize, /* The size of file or "<DIR>" for dirs */
1091  szDate, /* The date of file/dir */
1092  szTime); /* The time of file/dir */
1093  }
1094 }
1095 
1096 /*
1097  * DirPrintBareList
1098  *
1099  * The function that prints in bare format
1100  */
1101 static VOID
1102 DirPrintBareList(PDIRFINDINFO ptrFiles[], /* [IN] Files' Info */
1103  DWORD dwCount, /* [IN] The number of files */
1104  LPCTSTR szCurPath, /* [IN] Full path of current directory */
1105  LPDIRSWITCHFLAGS lpFlags) /* [IN] The flags used */
1106 {
1107  DWORD i;
1108 
1109  for (i = 0; i < dwCount && !CheckCtrlBreak(BREAK_INPUT); i++)
1110  {
1111  if (IsDotDirectory(ptrFiles[i]->stFindInfo.cFileName))
1112  {
1113  /* At bare format we don't print the dot-directories "." and ".." */
1114  continue;
1115  }
1116  if (lpFlags->bRecursive)
1117  {
1118  /* At recursive mode we print full path of file */
1119  DirPrintf(lpFlags, _T("%s\\%s\n"), szCurPath, ptrFiles[i]->stFindInfo.cFileName);
1120  }
1121  else
1122  {
1123  /* If we are not in recursive mode we print the file names */
1124  DirPrintf(lpFlags, _T("%s\n"), ptrFiles[i]->stFindInfo.cFileName);
1125  }
1126  }
1127 }
1128 
1129 
1130 /*
1131  * DirPrintFiles
1132  *
1133  * The functions that prints the files list
1134  */
1135 static VOID
1136 DirPrintFiles(PDIRFINDINFO ptrFiles[], /* [IN] Files' Info */
1137  DWORD dwCount, /* [IN] The quantity of files */
1138  LPCTSTR szCurPath, /* [IN] Full path of current directory */
1139  LPDIRSWITCHFLAGS lpFlags) /* [IN] The flags used */
1140 {
1141  TCHAR szMsg[RC_STRING_MAX_SIZE];
1142  TCHAR szTemp[MAX_PATH]; /* A buffer to format the directory header */
1143 
1144  /* Print trailing backslash for root directory of drive */
1145  _tcscpy(szTemp, szCurPath);
1146  if (_tcslen(szTemp) == 2 && szTemp[1] == _T(':'))
1147  _tcscat(szTemp, _T("\\"));
1148 
1149  /* Condition to print header:
1150  We are not printing in bare format
1151  and if we are in recursive mode... we must have results */
1152  if (!lpFlags->bBareFormat && !(lpFlags->bRecursive && (dwCount <= 0)))
1153  {
1155  if (!DirPrintf(lpFlags, szMsg, szTemp))
1156  return;
1157  }
1158 
1159  if (lpFlags->bBareFormat)
1160  {
1161  /* Bare format */
1162  DirPrintBareList(ptrFiles, dwCount, szCurPath, lpFlags);
1163  }
1164  else if (lpFlags->bShortName)
1165  {
1166  /* New list style / Short names */
1167  DirPrintNewList(ptrFiles, dwCount, szCurPath, lpFlags);
1168  }
1169  else if (lpFlags->bWideListColSort || lpFlags->bWideList)
1170  {
1171  /* Wide list */
1172  DirPrintWideList(ptrFiles, dwCount, szCurPath, lpFlags);
1173  }
1174  else if (lpFlags->bNewLongList )
1175  {
1176  /* New list style*/
1177  DirPrintNewList(ptrFiles, dwCount, szCurPath, lpFlags);
1178  }
1179  else
1180  {
1181  /* If nothing is selected old list is the default */
1182  DirPrintOldList(ptrFiles, dwCount, szCurPath, lpFlags);
1183  }
1184 }
1185 
1186 /*
1187  * CompareFiles
1188  *
1189  * Compares 2 files based on the order criteria
1190  */
1191 static BOOL
1192 CompareFiles(PDIRFINDINFO lpFile1, /* [IN] A pointer to WIN32_FIND_DATA of file 1 */
1193  PDIRFINDINFO lpFile2, /* [IN] A pointer to WIN32_FIND_DATA of file 2 */
1194  LPDIRSWITCHFLAGS lpFlags) /* [IN] The flags that we use to list */
1195 {
1196  ULARGE_INTEGER u64File1;
1197  ULARGE_INTEGER u64File2;
1198  int i;
1199  long iComp = 0; /* The comparison result */
1200 
1201  /* Calculate criteria by order given from user */
1202  for (i = 0; i < lpFlags->stOrderBy.sCriteriaCount; i++)
1203  {
1204 
1205  /* Calculate criteria */
1206  switch (lpFlags->stOrderBy.eCriteria[i])
1207  {
1208  case ORDER_SIZE: /* Order by size /o:s */
1209  /* concat the 32bit integers to a 64bit */
1210  u64File1.LowPart = lpFile1->stFindInfo.nFileSizeLow;
1211  u64File1.HighPart = lpFile1->stFindInfo.nFileSizeHigh;
1212  u64File2.LowPart = lpFile2->stFindInfo.nFileSizeLow;
1213  u64File2.HighPart = lpFile2->stFindInfo.nFileSizeHigh;
1214 
1215  /* In case that difference is too big for a long */
1216  if (u64File1.QuadPart < u64File2.QuadPart)
1217  iComp = -1;
1218  else if (u64File1.QuadPart > u64File2.QuadPart)
1219  iComp = 1;
1220  else
1221  iComp = 0;
1222  break;
1223 
1224  case ORDER_DIRECTORY: /* Order by directory attribute /o:g */
1225  iComp = ((lpFile2->stFindInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)-
1226  (lpFile1->stFindInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY));
1227  break;
1228 
1229  case ORDER_EXTENSION: /* Order by extension name /o:e */
1230  iComp = _tcsicmp(getExt(lpFile1->stFindInfo.cFileName),getExt(lpFile2->stFindInfo.cFileName));
1231  break;
1232 
1233  case ORDER_NAME: /* Order by filename /o:n */
1234  iComp = _tcsicmp(lpFile1->stFindInfo.cFileName, lpFile2->stFindInfo.cFileName);
1235  break;
1236 
1237  case ORDER_TIME: /* Order by file's time /o:t */
1238  /* We compare files based on the time field selected by /t */
1239  switch (lpFlags->stTimeField.eTimeField)
1240  {
1241  case TF_CREATIONDATE:
1242  /* concat the 32bit integers to a 64bit */
1243  u64File1.LowPart = lpFile1->stFindInfo.ftCreationTime.dwLowDateTime;
1244  u64File1.HighPart = lpFile1->stFindInfo.ftCreationTime.dwHighDateTime ;
1245  u64File2.LowPart = lpFile2->stFindInfo.ftCreationTime.dwLowDateTime;
1246  u64File2.HighPart = lpFile2->stFindInfo.ftCreationTime.dwHighDateTime ;
1247  break;
1248  case TF_LASTACCESSEDDATE :
1249  /* concat the 32bit integers to a 64bit */
1250  u64File1.LowPart = lpFile1->stFindInfo.ftLastAccessTime.dwLowDateTime;
1251  u64File1.HighPart = lpFile1->stFindInfo.ftLastAccessTime.dwHighDateTime ;
1252  u64File2.LowPart = lpFile2->stFindInfo.ftLastAccessTime.dwLowDateTime;
1253  u64File2.HighPart = lpFile2->stFindInfo.ftLastAccessTime.dwHighDateTime ;
1254  break;
1255  case TF_MODIFIEDDATE:
1256  /* concat the 32bit integers to a 64bit */
1257  u64File1.LowPart = lpFile1->stFindInfo.ftLastWriteTime.dwLowDateTime;
1258  u64File1.HighPart = lpFile1->stFindInfo.ftLastWriteTime.dwHighDateTime ;
1259  u64File2.LowPart = lpFile2->stFindInfo.ftLastWriteTime.dwLowDateTime;
1260  u64File2.HighPart = lpFile2->stFindInfo.ftLastWriteTime.dwHighDateTime ;
1261  break;
1262  }
1263 
1264  /* In case that difference is too big for a long */
1265  if (u64File1.QuadPart < u64File2.QuadPart)
1266  iComp = -1;
1267  else if (u64File1.QuadPart > u64File2.QuadPart)
1268  iComp = 1;
1269  else
1270  iComp = 0;
1271  break;
1272  }
1273 
1274  /* Reverse if desired */
1275  if (lpFlags->stOrderBy.bCriteriaRev[i])
1276  iComp *= -1;
1277 
1278  /* If that criteria was enough for distinguishing
1279  the files/dirs,there is no need to calculate the others*/
1280  if (iComp != 0) break;
1281  }
1282 
1283  /* Translate the value of iComp to boolean */
1284  return iComp > 0;
1285 }
1286 
1287 /*
1288  * QsortFiles
1289  *
1290  * Sort files by the order criterias using quicksort method
1291  */
1292 static VOID
1293 QsortFiles(PDIRFINDINFO ptrArray[], /* [IN/OUT] The array with file info pointers */
1294  int i, /* [IN] The index of first item in array */
1295  int j, /* [IN] The index to last item in array */
1296  LPDIRSWITCHFLAGS lpFlags) /* [IN] The flags that we will use to sort */
1297 {
1298  PDIRFINDINFO lpTemp; /* A temporary pointer */
1299  BOOL Way;
1300 
1301  if (i < j)
1302  {
1303  int First = i, Last = j, Temp;
1304  Way = TRUE;
1305  while (i != j)
1306  {
1307  if (Way == CompareFiles(ptrArray[i], ptrArray[j], lpFlags))
1308  {
1309  /* Swap the pointers of the array */
1310  lpTemp = ptrArray[i];
1311  ptrArray[i]= ptrArray[j];
1312  ptrArray[j] = lpTemp;
1313 
1314  /* Swap the indexes for inverting sorting */
1315  Temp = i;
1316  i = j;
1317  j =Temp;
1318 
1319  Way = !Way;
1320  }
1321 
1322  j += (!Way - Way);
1323  }
1324 
1325  QsortFiles(ptrArray,First, i-1, lpFlags);
1326  QsortFiles(ptrArray,i+1,Last, lpFlags);
1327  }
1328 }
1329 
1330 static VOID
1332  PDWORD pdwCount)
1333 {
1334  PDIRFINDLISTNODE ptrNextNode;
1335  PDIRFINDSTREAMNODE ptrFreeNode;
1336  while (ptrStartNode)
1337  {
1338  ptrNextNode = ptrStartNode->ptrNext;
1339  while (ptrStartNode->stInfo.ptrHead)
1340  {
1341  ptrFreeNode = ptrStartNode->stInfo.ptrHead;
1342  ptrStartNode->stInfo.ptrHead = ptrFreeNode->ptrNext;
1343  cmd_free(ptrFreeNode);
1344  }
1345  cmd_free(ptrStartNode);
1346  ptrStartNode = ptrNextNode;
1347  --(*pdwCount);
1348  }
1349 }
1350 
1351 /*
1352  * DirList
1353  *
1354  * The function that does everything except for printing results
1355  */
1356 static INT
1357 DirList(IN OUT LPTSTR szFullPath, /* [IN] The full path we are listing with trailing '\', where dir starts */
1358  IN LPTSTR pszFilePart, /* [IN] Pointer in the szFullPath buffer where the file (pattern) part starts*/
1359  LPDIRSWITCHFLAGS lpFlags) /* [IN] The flags of the listing */
1360 {
1361  HANDLE hSearch; /* The handle of the search */
1362  HANDLE hRecSearch; /* The handle for searching recursively */
1363  HANDLE hStreams; /* The handle for alternate streams */
1364  WIN32_FIND_DATA wfdFileInfo; /* The info of file that found */
1365  PDIRFINDINFO * ptrFileArray; /* An array of pointers with all the files */
1366  PDIRFINDLISTNODE ptrStartNode; /* The pointer to the first node */
1367  PDIRFINDLISTNODE ptrNextNode; /* A pointer used for relatives references */
1368  TCHAR szSubPath[MAX_PATH]; /* The full path used for the recursive search */
1369  LPTSTR pszSubFilePart;
1370  TCHAR cPathSep;
1371  DWORD dwCount; /* A counter of files found in directory */
1372  DWORD dwCountFiles; /* Counter for files */
1373  DWORD dwCountDirs; /* Counter for directories */
1374  ULONGLONG u64CountBytes; /* Counter for bytes */
1375  ULARGE_INTEGER u64Temp; /* A temporary counter */
1376  WIN32_FIND_STREAM_DATA wfsdStreamInfo;
1377  PDIRFINDSTREAMNODE * ptrCurNode; /* The pointer to the first stream */
1378  static HANDLE (WINAPI *pFindFirstStreamW)(LPCWSTR, STREAM_INFO_LEVELS, LPVOID, DWORD);
1379  static BOOL (WINAPI *pFindNextStreamW)(HANDLE, LPVOID);
1380 
1381  /* Initialize variables */
1382  ptrStartNode = NULL;
1383  ptrNextNode = NULL;
1384  dwCount = 0;
1385  dwCountFiles = 0;
1386  dwCountDirs = 0;
1387  u64CountBytes = 0;
1388 
1389  /* Prepare the linked list, first node is allocated */
1390  ptrStartNode = cmd_alloc(sizeof(DIRFINDLISTNODE));
1391  if (ptrStartNode == NULL)
1392  {
1393  WARN("Cannot allocate memory for ptrStartNode!\n");
1394  return 1; /* Error cannot allocate memory for 1st object */
1395  }
1396  ptrStartNode->stInfo.ptrHead = NULL;
1397  ptrNextNode = ptrStartNode;
1398 
1399  /* Collect the results for the current directory */
1400  hSearch = FindFirstFile(szFullPath, &wfdFileInfo);
1401  if (hSearch != INVALID_HANDLE_VALUE)
1402  {
1403  do
1404  {
1405  if ((wfdFileInfo.dwFileAttributes & lpFlags->stAttribs.dwAttribMask) ==
1406  (lpFlags->stAttribs.dwAttribMask & lpFlags->stAttribs.dwAttribVal))
1407  {
1408  ptrNextNode->ptrNext = cmd_alloc(sizeof(DIRFINDLISTNODE));
1409  if (ptrNextNode->ptrNext == NULL)
1410  {
1411  WARN("Cannot allocate memory for ptrNextNode->ptrNext!\n");
1412  DirNodeCleanup(ptrStartNode, &dwCount);
1413  FindClose(hSearch);
1414  return 1;
1415  }
1416 
1417  /* Copy the info of search at linked list */
1418  memcpy(&ptrNextNode->ptrNext->stInfo.stFindInfo,
1419  &wfdFileInfo,
1420  sizeof(WIN32_FIND_DATA));
1421 
1422  /* If lower case is selected do it here */
1423  if (lpFlags->bLowerCase)
1424  {
1425  _tcslwr(ptrNextNode->ptrNext->stInfo.stFindInfo.cAlternateFileName);
1426  _tcslwr(ptrNextNode->ptrNext->stInfo.stFindInfo.cFileName);
1427  }
1428 
1429  /* No streams (yet?) */
1430  ptrNextNode->ptrNext->stInfo.ptrHead = NULL;
1431 
1432  /* Alternate streams are only displayed with new long list */
1433  if (lpFlags->bNewLongList && lpFlags->bDataStreams)
1434  {
1435  if (!pFindFirstStreamW)
1436  {
1437  pFindFirstStreamW = (PVOID)GetProcAddress(GetModuleHandle(_T("kernel32")), "FindFirstStreamW");
1438  pFindNextStreamW = (PVOID)GetProcAddress(GetModuleHandle(_T("kernel32")), "FindNextStreamW");
1439  }
1440 
1441  /* Try to get stream information */
1442  if (pFindFirstStreamW && pFindNextStreamW)
1443  {
1444  hStreams = pFindFirstStreamW(wfdFileInfo.cFileName, FindStreamInfoStandard, &wfsdStreamInfo, 0);
1445  }
1446  else
1447  {
1448  hStreams = INVALID_HANDLE_VALUE;
1449  ERR("FindFirstStreamW not supported!\n");
1450  }
1451 
1452  if (hStreams != INVALID_HANDLE_VALUE)
1453  {
1454  /* We totally ignore first stream. It contains data about ::$DATA */
1455  ptrCurNode = &ptrNextNode->ptrNext->stInfo.ptrHead;
1456  while (pFindNextStreamW(hStreams, &wfsdStreamInfo))
1457  {
1458  *ptrCurNode = cmd_alloc(sizeof(DIRFINDSTREAMNODE));
1459  if (*ptrCurNode == NULL)
1460  {
1461  WARN("Cannot allocate memory for *ptrCurNode!\n");
1462  DirNodeCleanup(ptrStartNode, &dwCount);
1463  FindClose(hStreams);
1464  FindClose(hSearch);
1465  return 1;
1466  }
1467 
1468  memcpy(&(*ptrCurNode)->stStreamInfo, &wfsdStreamInfo,
1469  sizeof(WIN32_FIND_STREAM_DATA));
1470 
1471  /* If lower case is selected do it here */
1472  if (lpFlags->bLowerCase)
1473  {
1474  _tcslwr((*ptrCurNode)->stStreamInfo.cStreamName);
1475  }
1476 
1477  ptrCurNode = &(*ptrCurNode)->ptrNext;
1478  }
1479 
1480  FindClose(hStreams);
1481  *ptrCurNode = NULL;
1482  }
1483  }
1484 
1485  /* Continue at next node at linked list */
1486  ptrNextNode = ptrNextNode->ptrNext;
1487  dwCount++;
1488 
1489  /* Grab statistics */
1490  if (wfdFileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1491  {
1492  /* Directory */
1493  dwCountDirs++;
1494  }
1495  else
1496  {
1497  /* File */
1498  dwCountFiles++;
1499  u64Temp.HighPart = wfdFileInfo.nFileSizeHigh;
1500  u64Temp.LowPart = wfdFileInfo.nFileSizeLow;
1501  u64CountBytes += u64Temp.QuadPart;
1502  }
1503  }
1504  } while (FindNextFile(hSearch, &wfdFileInfo));
1505  FindClose(hSearch);
1506  }
1507 
1508  /* Terminate list */
1509  ptrNextNode->ptrNext = NULL;
1510 
1511  /* Calculate and allocate space need for making an array of pointers */
1512  ptrFileArray = cmd_alloc(sizeof(PDIRFINDINFO) * dwCount);
1513  if (ptrFileArray == NULL)
1514  {
1515  WARN("Cannot allocate memory for ptrFileArray!\n");
1516  DirNodeCleanup(ptrStartNode, &dwCount);
1517  return 1;
1518  }
1519 
1520  /*
1521  * Create an array of pointers from the linked list
1522  * this will be used to sort and print data, rather than the list
1523  */
1524  ptrNextNode = ptrStartNode;
1525  dwCount = 0;
1526  while (ptrNextNode->ptrNext)
1527  {
1528  ptrFileArray[dwCount] = &ptrNextNode->ptrNext->stInfo;
1529  ptrNextNode = ptrNextNode->ptrNext;
1530  dwCount++;
1531  }
1532 
1533  /* Sort Data if requested */
1534  if (lpFlags->stOrderBy.sCriteriaCount > 0)
1535  QsortFiles(ptrFileArray, 0, dwCount-1, lpFlags);
1536 
1537  /* Print Data */
1538  cPathSep = pszFilePart[-1];
1539  pszFilePart[-1] = _T('\0'); /* Truncate to directory name only */
1540  DirPrintFiles(ptrFileArray, dwCount, szFullPath, lpFlags);
1541 
1542  if (lpFlags->bRecursive)
1543  {
1544  PrintSummary(szFullPath,
1545  dwCountFiles,
1546  dwCountDirs,
1547  u64CountBytes,
1548  lpFlags,
1549  FALSE);
1550  }
1551  pszFilePart[-1] = cPathSep;
1552 
1553  /* Free array */
1554  cmd_free(ptrFileArray);
1555 
1556  /* Free linked list */
1557  DirNodeCleanup(ptrStartNode, &dwCount);
1558 
1560  return 1;
1561 
1562  /* Add statistics to recursive statistics */
1563  recurse_dir_cnt += dwCountDirs;
1564  recurse_file_cnt += dwCountFiles;
1565  recurse_bytes += u64CountBytes;
1566 
1567  /*
1568  * Do the recursive job if requested.
1569  * The recursion is done on ALL (independent of their attributes)
1570  * directories of the current one.
1571  */
1572  if (lpFlags->bRecursive)
1573  {
1574  /* The new search is involving any *.* file */
1575  memcpy(szSubPath, szFullPath, (pszFilePart - szFullPath) * sizeof(TCHAR));
1576  _tcscpy(&szSubPath[pszFilePart - szFullPath], _T("*.*"));
1577 
1578  hRecSearch = FindFirstFile(szSubPath, &wfdFileInfo);
1579  if (hRecSearch != INVALID_HANDLE_VALUE)
1580  {
1581  do
1582  {
1583  /* We search for directories other than "." and ".." */
1584  if (!IsDotDirectory(wfdFileInfo.cFileName) &&
1585  (wfdFileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
1586  {
1587  /* Concat the path and the directory to do recursive */
1588  memcpy(szSubPath, szFullPath, (pszFilePart - szFullPath) * sizeof(TCHAR));
1589  _tcscpy(&szSubPath[pszFilePart - szFullPath], wfdFileInfo.cFileName);
1590  _tcscat(szSubPath, _T("\\"));
1591  pszSubFilePart = &szSubPath[_tcslen(szSubPath)];
1592  _tcscat(pszSubFilePart, pszFilePart);
1593 
1594  /* We do the same for the directory */
1595  if (DirList(szSubPath, pszSubFilePart, lpFlags) != 0)
1596  {
1597  FindClose(hRecSearch);
1598  return 1;
1599  }
1600  }
1601  } while (FindNextFile(hRecSearch, &wfdFileInfo));
1602  }
1603  FindClose(hRecSearch);
1604  }
1605 
1606  return 0;
1607 }
1608 
1609 static VOID
1611  IN LPTSTR pszPattern,
1613  OUT LPTSTR pszFullPath,
1614  OUT LPTSTR* ppszPatternPart OPTIONAL)
1615 {
1616  LPTSTR pCurDir, pNextDir, ptr;
1617  LPTSTR pszPatternPart;
1618  TCHAR szNewPattern[MAX_PATH];
1619 
1620  /*
1621  * We are going to use GetFullPathName() to properly determine the actual
1622  * full path from the pattern. However, due to the fact GetFullPathName()
1623  * strips parts of the file name component in case the pattern contains
1624  * path specification with trailing dots, it is required to perform a
1625  * pre-treatment on the pattern and a post-treatment on the obtained path.
1626  * This is mandatory in order to use the correct file search criterion.
1627  *
1628  * One particular case is when the pattern specifies a dots-only directory
1629  * followed by either the "." or ".." special directories. In this case the
1630  * GetFullPathName() function may completely miss the dots-only directory.
1631  * An example is given by the pattern (C-string notation) "\\...\\." .
1632  * To cope with this problem we need to partially canonicalize the pattern
1633  * by collapsing any "." or ".." special directory that immediately follows
1634  * a dots-only directory. We collapse in addition consecutive backslashes.
1635  *
1636  * Finally, trailing dots are skipped by GetFullPathName(). Therefore
1637  * a pattern that matches files with no extension, for example: "*." ,
1638  * or: "dir\\noextfile." , are reduced to simply "*" or "dir\\noextfile",
1639  * that match files with extensions. Or, a pattern specifying a trailing
1640  * dots-only directory: "dir\\..." gets completely ignored and only the
1641  * full path to "dir" is returned.
1642  * To fix this second problem we need to restore the last part of the path
1643  * pattern using the pattern that has been first partially canonicalized.
1644  *
1645  * Note however that the "." or ".." special directories are always
1646  * interpreted correctly by GetFullPathName().
1647  */
1648 
1649  /* Make a copy of the path pattern */
1650  ASSERT(_tcslen(pszPattern) < ARRAYSIZE(szNewPattern));
1651  _tcscpy(szNewPattern, pszPattern);
1652  pszPattern = szNewPattern;
1653 
1654  TRACE("Original pszPattern: %S\n", pszPattern);
1655 
1656  /* Convert slashes into backslashes */
1657  pNextDir = pszPattern;
1658  while ((pNextDir = _tcschr(pNextDir, _T('/'))))
1659  *pNextDir++ = _T('\\');
1660 
1661  /*
1662  * Find any dots-only directory and collapse any "." or ".." special
1663  * directory that immediately follows it.
1664  * Note that we just start looking after the first path separator. Indeed,
1665  * dots-only directories that are not preceded by a path separator, and so
1666  * appear first in the pattern, for example: "...\dir", or: "..." , are
1667  * either correctly handled by GetFullPathName() because they are followed
1668  * by a non-pathological directory, or because they are handled when we
1669  * restore the trailing dots pattern piece in the next step.
1670  */
1671  pNextDir = pszPattern;
1672  while (pNextDir)
1673  {
1674  pCurDir = pNextDir;
1675 
1676  /* Find the next path separator in the pattern */
1677  pNextDir = _tcschr(pNextDir, _T('\\'));
1678  if (!pNextDir)
1679  break;
1680 
1681  /* Ignore the special "." and ".." directories that are correctly handled */
1682  if ((pNextDir - pCurDir == 0) || IsDotDirectoryN(pCurDir, pNextDir - pCurDir))
1683  {
1684  /* Found such a directory, ignore */
1685  ++pNextDir;
1686  continue;
1687  }
1688 
1689  /* Check whether this is a dots-only directory */
1690  for (ptr = pCurDir; ptr < pNextDir; ++ptr)
1691  {
1692  if (*ptr != _T('.'))
1693  break;
1694  }
1695  if (ptr < pNextDir)
1696  {
1697  /* Not a dots-only directory, ignore */
1698  ++pNextDir;
1699  continue;
1700  }
1701 
1702  /* Skip any consecutive backslashes */
1703  for (ptr = pNextDir; *ptr == _T('\\'); ++ptr) ;
1704 
1705  /* pCurDir is a dots-only directory, perform partial canonicalization */
1706 
1707  /* Remove any following "." directory */
1708  if (ptr[0] == _T('.') && (ptr[1] == _T('\\') || ptr[1] == 0))
1709  {
1710  memmove(pNextDir, ptr + 1, (_tcslen(ptr + 1) + 1) * sizeof(TCHAR));
1711  }
1712  /* Remove any following ".." directory */
1713  else if (ptr[0] == _T('.') && ptr[1] == _T('.') && (ptr[2] == _T('\\') || ptr[2] == 0))
1714  {
1715  /* Skip any consecutive backslashes before the next directory */
1716  for (ptr = ptr + 2; *ptr == _T('\\'); ++ptr) ;
1717 
1718  memmove(pCurDir, ptr, (_tcslen(ptr) + 1) * sizeof(TCHAR));
1719  pNextDir = pCurDir;
1720  }
1721  else
1722  {
1723  ++pNextDir;
1724 
1725  /* Collapse consecutive backslashes */
1726  if (ptr > pNextDir)
1727  memmove(pNextDir, ptr, (_tcslen(ptr) + 1) * sizeof(TCHAR));
1728  }
1729  }
1730 
1731  /* An empty pattern means we enumerate all files in the current directory */
1732  if (!*pszPattern)
1733  _tcscpy(pszPattern, _T("*"));
1734 
1735  TRACE("New pszPattern: %S\n", pszPattern);
1736 
1737  /* Create the full path */
1738  if (GetFullPathName(pszPattern, nBufferLength, pszFullPath, &pszPatternPart) == 0)
1739  {
1740  _tcscpy(pszFullPath, pszPattern);
1741  pszPatternPart = NULL;
1742  }
1743 
1744  TRACE("pszFullPath (1): %S\n", pszFullPath);
1745  TRACE("pszPatternPart (1): %S\n", pszPatternPart);
1746 
1747  /*
1748  * Restore the correct file name component in case the pattern contained
1749  * trailing dots that have been skipped by GetFullPathName().
1750  */
1751 
1752  /* Find the last path separator in the original szPath */
1753  pNextDir = _tcsrchr(pszPattern, _T('\\'));
1754  if (pNextDir)
1755  {
1756  /* Skip past the separator and look at the path */
1757  ++pNextDir;
1758  }
1759  else
1760  {
1761  /* The pattern is the path we need to look at */
1762  pNextDir = pszPattern;
1763  }
1764 
1765  /*
1766  * When pszPatternPart == NULL this means that pszFullPath should be a
1767  * directory; however it might have happened that the original pattern
1768  * was specifying a dots-only directory, that has been stripped off by
1769  * GetFullPathName(). In both these cases we need to restore these as
1770  * they are part of the actual directory path; the exception being if
1771  * these are the special "." or ".." directories.
1772  */
1773  if (pszPatternPart == NULL)
1774  {
1775  ASSERT(pszFullPath[_tcslen(pszFullPath)-1] == _T('\\'));
1776 
1777  /* Anything NOT being "." or ".." (the special directories) must be fully restored */
1778  if (*pNextDir && !IsDotDirectory(pNextDir))
1779  {
1780  pszPatternPart = &pszFullPath[_tcslen(pszFullPath)];
1781  _tcscpy(pszPatternPart, pNextDir);
1782  pszPatternPart = NULL;
1783  }
1784  }
1785  else if (_tcscmp(pNextDir, pszPatternPart) != 0)
1786  {
1787  /*
1788  * For example, pszPatternPart == "." or ".." and we do not need to
1789  * do anything for these, or pszPatternPart == "dir\\noextfile." and
1790  * we need to restore all the trailing points.
1791  */
1792  TRACE("pszPatternPart: %S is DIFFERENT from file criterion: %S\n", pszPatternPart, pNextDir);
1793 
1794  /* Anything NOT being "." or ".." (the special directories) must be fully restored */
1795  if (*pNextDir && !IsDotDirectory(pNextDir))
1796  {
1797  /* Restore the correct file criterion */
1798  _tcscpy(pszPatternPart, pNextDir);
1799  }
1800  }
1801 
1802  TRACE("pszFullPath (2): %S\n", pszFullPath);
1803 
1804  /*
1805  * If no wildcard or file was specified and this is a directory,
1806  * display all files in it.
1807  */
1808  if (pszPatternPart == NULL || IsExistingDirectory(pszFullPath))
1809  {
1810  pszPatternPart = &pszFullPath[_tcslen(pszFullPath)];
1811  if (pszPatternPart[-1] != _T('\\'))
1812  *pszPatternPart++ = _T('\\');
1813  _tcscpy(pszPatternPart, _T("*"));
1814  }
1815 
1816  TRACE("pszPatternPart (2): %S\n", pszPatternPart);
1817 
1818  if (ppszPatternPart)
1819  *ppszPatternPart = pszPatternPart;
1820 }
1821 
1822 /*
1823  * dir
1824  *
1825  * internal dir command
1826  */
1827 INT
1829 {
1830  TCHAR dircmd[MAX_PATH]; /* A variable to store the DIRCMD environment variable */
1831  TCHAR prev_volume[MAX_PATH];
1832  TCHAR szFullPath[MAX_PATH];
1833  LPTSTR* params = NULL;
1834  LPTSTR pszFilePart;
1835  TCHAR cPathSep;
1836  INT entries = 0;
1837  UINT loop = 0;
1838  DIRSWITCHFLAGS stFlags;
1839  INT ret = 1;
1840  BOOL ChangedVolume;
1841 
1842  /* Initialize Switch Flags < Default switches are set here! > */
1843  stFlags.b4Digit = TRUE;
1844  stFlags.bBareFormat = FALSE;
1845  stFlags.bDataStreams = FALSE;
1846  stFlags.bLowerCase = FALSE;
1847  stFlags.bNewLongList = TRUE;
1848  stFlags.bPause = FALSE;
1849  stFlags.bRecursive = FALSE;
1850  stFlags.bShortName = FALSE;
1851  stFlags.bTSeparator = TRUE;
1852  stFlags.bUser = FALSE;
1853  stFlags.bWideList = FALSE;
1854  stFlags.bWideListColSort = FALSE;
1855  stFlags.stTimeField.eTimeField = TF_MODIFIEDDATE;
1856  stFlags.stAttribs.dwAttribMask = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
1857  stFlags.stAttribs.dwAttribVal = 0L;
1858  stFlags.stOrderBy.sCriteriaCount = 0;
1859 
1860  nErrorLevel = 0;
1861 
1862  /* Read the parameters from the DIRCMD environment variable */
1863  if (GetEnvironmentVariable (_T("DIRCMD"), dircmd, ARRAYSIZE(dircmd)))
1864  {
1865  if (!DirReadParam(dircmd, &params, &entries, &stFlags))
1866  {
1867  nErrorLevel = 1;
1868  goto cleanup;
1869  }
1870  }
1871 
1872  /* Read the parameters */
1873  if (!DirReadParam(rest, &params, &entries, &stFlags) || CheckCtrlBreak(BREAK_INPUT))
1874  {
1875  nErrorLevel = 1;
1876  goto cleanup;
1877  }
1878 
1879  /* Default to current directory */
1880  if (entries == 0)
1881  {
1882  if (!add_entry(&entries, &params, _T("*")))
1883  {
1884  nErrorLevel = 1;
1885  goto cleanup;
1886  }
1887  }
1888 
1889  prev_volume[0] = _T('\0');
1890 
1891  /* Reset paging state */
1892  if (stFlags.bPause)
1893  ConOutPrintfPaging(TRUE, _T(""));
1894 
1895  for (loop = 0; loop < (UINT)entries; loop++)
1896  {
1898  {
1899  nErrorLevel = 1;
1900  goto cleanup;
1901  }
1902 
1903  recurse_dir_cnt = 0L;
1904  recurse_file_cnt = 0L;
1905  recurse_bytes = 0;
1906 
1907  /* <Debug :>
1908  Uncomment this to show the final state of switch flags*/
1909  {
1910  int i;
1911  TRACE("Attributes mask/value %x/%x\n",stFlags.stAttribs.dwAttribMask,stFlags.stAttribs.dwAttribVal);
1912  TRACE("(B) Bare format : %i\n", stFlags.bBareFormat);
1913  TRACE("(C) Thousand : %i\n", stFlags.bTSeparator);
1914  TRACE("(W) Wide list : %i\n", stFlags.bWideList);
1915  TRACE("(D) Wide list sort by column : %i\n", stFlags.bWideListColSort);
1916  TRACE("(L) Lowercase : %i\n", stFlags.bLowerCase);
1917  TRACE("(N) New : %i\n", stFlags.bNewLongList);
1918  TRACE("(O) Order : %i\n", stFlags.stOrderBy.sCriteriaCount);
1919  for (i =0;i<stFlags.stOrderBy.sCriteriaCount;i++)
1920  TRACE(" Order Criteria [%i]: %i (Reversed: %i)\n",i, stFlags.stOrderBy.eCriteria[i], stFlags.stOrderBy.bCriteriaRev[i]);
1921  TRACE("(P) Pause : %i\n", stFlags.bPause);
1922  TRACE("(Q) Owner : %i\n", stFlags.bUser);
1923  TRACE("(R) Data stream : %i\n", stFlags.bDataStreams);
1924  TRACE("(S) Recursive : %i\n", stFlags.bRecursive);
1925  TRACE("(T) Time field : %i\n", stFlags.stTimeField.eTimeField);
1926  TRACE("(X) Short names : %i\n", stFlags.bShortName);
1927  TRACE("Parameter : %s\n", debugstr_aw(params[loop]));
1928  }
1929 
1930  /* Print the drive header if the volume changed */
1931  ChangedVolume = TRUE;
1932 
1933  if (!stFlags.bBareFormat &&
1934  GetVolumePathName(params[loop], szFullPath, ARRAYSIZE(szFullPath)))
1935  {
1936  if (!_tcscmp(szFullPath, prev_volume))
1937  ChangedVolume = FALSE;
1938  else
1939  _tcscpy(prev_volume, szFullPath);
1940  }
1941 
1942  /* Resolve the pattern */
1943  ResolvePattern(params[loop], ARRAYSIZE(szFullPath), szFullPath, &pszFilePart);
1944 
1945  /* Print the header */
1946  cPathSep = pszFilePart[-1];
1947  pszFilePart[-1] = _T('\0'); /* Truncate to directory name only */
1948  if (ChangedVolume && !stFlags.bBareFormat &&
1949  !PrintDirectoryHeader(szFullPath, &stFlags))
1950  {
1951  nErrorLevel = 1;
1952  goto cleanup;
1953  }
1954  pszFilePart[-1] = cPathSep;
1955 
1956  /* Perform the actual directory listing */
1957  if (DirList(szFullPath, pszFilePart, &stFlags) != 0)
1958  {
1959  nErrorLevel = 1;
1960  goto cleanup;
1961  }
1962 
1963  /* Print the footer */
1964  pszFilePart[-1] = _T('\0'); /* Truncate to directory name only */
1965  PrintSummary(szFullPath,
1968  recurse_bytes,
1969  &stFlags,
1970  TRUE);
1971  }
1972 
1973  ret = 0;
1974 
1975 cleanup:
1976  freep(params);
1977 
1978  return ret;
1979 }
1980 
1981 #endif
1982 
1983 /* EOF */
INT nErrorLevel
Definition: cmd.c:157
BOOL bBareFormat
Definition: dir.c:168
FORCEINLINE BOOL IsDotDirectory(IN LPCTSTR pszPath)
Definition: dir.c:239
#define IN
Definition: typedefs.h:38
BOOL bLowerCase
Definition: dir.c:172
#define STRING_DIR_HELP1
Definition: resource.h:107
static VOID DirNodeCleanup(PDIRFINDLISTNODE ptrStartNode, PDWORD pdwCount)
Definition: dir.c:1331
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
BOOL CheckCtrlBreak(INT)
Definition: misc.c:132
#define TRUE
Definition: types.h:120
const CHAR * LPCTSTR
Definition: xmlstorage.h:193
#define BREAK_INPUT
Definition: cmd.h:33
INT CommandDir(LPTSTR rest)
Definition: dir.c:1828
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
static ULONGLONG recurse_bytes
Definition: dir.c:222
TCHAR szTime[64]
Definition: solitaire.cpp:18
#define _tcsicmp
Definition: xmlstorage.h:205
WORD wMonth
Definition: winbase.h:871
INT FormatDate(TCHAR *lpDate, LPSYSTEMTIME dt, BOOL b4Digit)
Definition: dir.c:674
enum ETimeField eTimeField
Definition: dir.c:193
struct _DirSwitchesFlags DIRSWITCHFLAGS
int _tcscmp(const _TCHAR *s1, const _TCHAR *s2)
Definition: tcscmp.h:8
#define FILE_ATTRIBUTE_SYSTEM
Definition: nt_native.h:704
VOID error_parameter_format(TCHAR)
Definition: error.c:63
#define WARN(fmt,...)
Definition: debug.h:111
_TCHAR * _tcsncpy(_TCHAR *dst, const _TCHAR *src, size_t n)
Definition: tcsncpy.h:9
EOrderBy
Definition: dir.c:156
static BOOL CompareFiles(PDIRFINDINFO lpFile1, PDIRFINDINFO lpFile2, LPDIRSWITCHFLAGS lpFlags)
Definition: dir.c:1192
static LPTSTR getName(const TCHAR *file, TCHAR *dest)
Definition: dir.c:842
#define STRING_DIR_HELP6
Definition: resource.h:112
#define debugstr_aw
Definition: precomp.h:43
#define ARRAYSIZE(array)
Definition: filtermapper.c:47
struct _DIRFINDINFO * PDIRFINDINFO
#define INVALID_HANDLE_VALUE
Definition: compat.h:391
_TCHAR * _tcscpy(_TCHAR *to, const _TCHAR *from)
Definition: tcscpy.h:8
$ULONG LowPart
Definition: ntbasedef.h:576
#define GetDiskFreeSpace
Definition: winbase.h:3621
#define STRING_DIR_HELP4
Definition: resource.h:110
VOID ConOutResPaging(BOOL StartPaging, UINT resID)
Definition: console.c:182
GLuint GLuint end
Definition: gl.h:1545
#define _totupper
Definition: tchar.h:1509
int32_t INT_PTR
Definition: typedefs.h:62
BOOL bShortName
Definition: dir.c:177
INT nTimeFormat
Definition: locale.c:21
BOOL WINAPI FileTimeToLocalFileTime(IN CONST FILETIME *lpFileTime, OUT LPFILETIME lpLocalFileTime)
Definition: time.c:211
#define BOOL
Definition: nt_native.h:43
static VOID StripQuotes(LPSTR in)
Definition: cmdcons.c:116
#define DWORD
Definition: nt_native.h:44
int32_t INT
Definition: typedefs.h:56
CHAR * LPTSTR
Definition: xmlstorage.h:192
#define STRING_DIR_HELP7
Definition: resource.h:113
WCHAR First[]
Definition: FormatMessage.c:11
WORD wYear
Definition: winbase.h:870
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
HINSTANCE hInstance
Definition: charmap.c:20
struct _DIRFINDLISTNODE DIRFINDLISTNODE
#define va_end(ap)
Definition: acmsvcex.h:90
ULONGLONG QuadPart
Definition: ms-dtyp.idl:185
GLenum const GLfloat * params
Definition: glext.h:5645
unsigned int BOOL
Definition: ntddk_ex.h:94
TCHAR * getExt(const TCHAR *file)
Definition: dir.c:829
short SHORT
Definition: pedump.c:59
static INT DirList(IN OUT LPTSTR szFullPath, IN LPTSTR pszFilePart, LPDIRSWITCHFLAGS lpFlags)
Definition: dir.c:1357
FORCEINLINE BOOL IsDotDirectoryN(IN const TCHAR *pPath, IN SIZE_T Length)
Definition: dir.c:250
static PVOID ptr
Definition: dispmode.c:27
WORD wMinute
Definition: winbase.h:875
size_t __cdecl _tcslen(const _TCHAR *str)
Definition: tcslen.h:9
BOOL bNewLongList
Definition: dir.c:173
static VOID freep(LPSTR *p)
Definition: cmdcons.c:98
smooth NULL
Definition: ftsmooth.c:416
static VOID DirPrintNewList(PDIRFINDINFO ptrFiles[], DWORD dwCount, LPCTSTR szCurPath, LPDIRSWITCHFLAGS lpFlags)
Definition: dir.c:873
#define _tcslwr
Definition: tchar.h:1465
static BOOL PrintDirectoryHeader(LPCTSTR szPath, LPDIRSWITCHFLAGS lpFlags)
Definition: dir.c:597
#define FORCEINLINE
Definition: ntbasedef.h:221
char * va_list
Definition: acmsvcex.h:78
BOOL bCriteriaRev[3]
Definition: dir.c:188
INT FormatTime(TCHAR *lpTime, LPSYSTEMTIME dt)
Definition: dir.c:703
TCHAR cTimeSeparator
Definition: locale.c:17
void * PVOID
Definition: retypes.h:9
#define FindFirstFile
Definition: winbase.h:3596
struct _ULARGE_INTEGER * PULARGE_INTEGER
Definition: drive.c:28
_TCHAR * _tcschr(const _TCHAR *s, _XINT c)
Definition: tcschr.h:4
#define FILE_ATTRIBUTE_REPARSE_POINT
Definition: ntifs_ex.h:381
_In_ LPCSTR _In_opt_ LPCSTR _In_ DWORD nBufferLength
Definition: winbase.h:3011
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 GLint GLint j
Definition: glfuncs.h:250
#define FILE_ATTRIBUTE_DIRECTORY
Definition: nt_native.h:705
char TCHAR
Definition: xmlstorage.h:189
#define _T(x)
Definition: vfdio.h:22
#define TRACE(s)
Definition: solgame.cpp:4
$ULONG HighPart
Definition: ntbasedef.h:577
BOOL IsExistingDirectory(LPCTSTR)
Definition: misc.c:507
BOOL WINAPI FileTimeToSystemTime(IN CONST FILETIME *lpFileTime, OUT LPSYSTEMTIME lpSystemTime)
Definition: time.c:178
INT ConvertULargeInteger(ULONGLONG num, LPTSTR des, UINT len, BOOL bPutSeparator)
Definition: cmd.c:188
struct _DIRFINDINFO DIRFINDINFO
static ULONG recurse_dir_cnt
Definition: dir.c:220
static VOID ResolvePattern(IN LPTSTR pszPattern, IN DWORD nBufferLength, OUT LPTSTR pszFullPath, OUT LPTSTR *ppszPatternPart OPTIONAL)
Definition: dir.c:1610
short sCriteriaCount
Definition: dir.c:189
#define RC_STRING_MAX_SIZE
Definition: resource.h:3
struct _DirSwitchesFlags::@64 stTimeField
static VOID DirPrintBareList(PDIRFINDINFO ptrFiles[], DWORD dwCount, LPCTSTR szCurPath, LPDIRSWITCHFLAGS lpFlags)
Definition: dir.c:1102
#define FindNextFile
Definition: winbase.h:3602
uint64_t ULONGLONG
Definition: typedefs.h:65
WIN32_FIND_DATA stFindInfo
Definition: dir.c:205
#define MAX_PATH
Definition: compat.h:26
#define WINAPI
Definition: msvc.h:8
const char file[]
Definition: icontest.c:11
#define FILE_ATTRIBUTE_READONLY
Definition: nt_native.h:702
DWORD dwAttribVal
Definition: dir.c:182
unsigned short WORD
Definition: ntddk_ex.h:93
PVOID HANDLE
Definition: typedefs.h:71
unsigned long DWORD
Definition: ntddk_ex.h:95
struct _DirSwitchesFlags::@62 stAttribs
BOOL bRecursive
Definition: dir.c:176
unsigned __int3264 UINT_PTR
Definition: mstsclib_h.h:274
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
VOID error_invalid_switch(TCHAR)
Definition: error.c:70
VOID error_file_not_found(VOID)
Definition: error.c:91
#define LPVOID
Definition: nt_native.h:45
static VOID DirPrintOldList(PDIRFINDINFO ptrFiles[], DWORD dwCount, LPCTSTR szCurPath, LPDIRSWITCHFLAGS lpFlags)
Definition: dir.c:1037
BOOL bPause
Definition: dir.c:174
DIRFINDINFO stInfo
Definition: dir.c:211
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
Definition: ncftp.h:79
#define FILE_ATTRIBUTE_ARCHIVE
Definition: nt_native.h:706
BOOL bDataStreams
Definition: dir.c:179
int ret
static const WCHAR L[]
Definition: oid.c:1250
TCHAR cDateSeparator
Definition: locale.c:16
static ULONG recurse_file_cnt
Definition: dir.c:221
static const WCHAR szDate[]
Definition: http.c:99
VOID GetScreenSize(PSHORT maxx, PSHORT maxy)
Definition: console.c:236
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define GetFullPathName
Definition: winbase.h:3635
static VOID DirHelp(VOID)
Definition: dir.c:231
BOOL __cdecl ConOutPrintfPaging(BOOL StartPaging, LPTSTR szFormat,...)
Definition: console.c:171
BOOL bTSeparator
Definition: dir.c:169
enum EOrderBy eCriteria[3]
Definition: dir.c:187
#define ERR(fmt,...)
Definition: debug.h:109
#define _stprintf
Definition: utility.h:124
struct _DirSwitchesFlags::@63 stOrderBy
static BOOL DirPrintf(LPDIRSWITCHFLAGS lpFlags, LPTSTR szFormat,...)
Definition: dir.c:577
DWORD dwAttribMask
Definition: dir.c:183
WORD wDay
Definition: winbase.h:873
ULONG_PTR SIZE_T
Definition: typedefs.h:78
BOOL(WINAPI * PGETFREEDISKSPACEEX)(LPCTSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER)
Definition: dir.c:216
#define cmd_alloc(size)
Definition: cmddbg.h:29
#define GetVolumeInformation
Definition: winbase.h:3667
#define cmd_free(ptr)
Definition: cmddbg.h:31
#define GetModuleHandle
Definition: winbase.h:3641
INT ConPrintfV(IN PCON_STREAM Stream, IN LPWSTR szStr, IN va_list args)
Definition: outstream.c:466
static VOID DirPrintFiles(PDIRFINDINFO ptrFiles[], DWORD dwCount, LPCTSTR szCurPath, LPDIRSWITCHFLAGS lpFlags)
Definition: dir.c:1136
unsigned short USHORT
Definition: pedump.c:61
PDIRFINDSTREAMNODE ptrHead
Definition: dir.c:206
static calc_node_t temp
Definition: rpn_ieee.c:38
LPCWSTR szPath
Definition: env.c:35
BOOL bWideList
Definition: dir.c:170
struct _DIRFINDSTREAMNODE DIRFINDSTREAMNODE
static VOID DirPrintWideList(PDIRFINDINFO ptrFiles[], DWORD dwCount, LPCTSTR szCurPath, LPDIRSWITCHFLAGS lpFlags)
Definition: dir.c:955
WORD wHour
Definition: winbase.h:874
struct _DIRFINDLISTNODE * ptrNext
Definition: dir.c:212
struct _DIRFINDSTREAMNODE * ptrNext
Definition: dir.c:200
#define GetVolumePathName
Definition: winbase.h:3669
#define FILE_ATTRIBUTE_HIDDEN
Definition: nt_native.h:703
#define va_start(ap, A)
Definition: acmsvcex.h:91
unsigned int UINT
Definition: ndis.h:50
DWORD * PDWORD
Definition: pedump.c:68
HANDLE CMD_ModuleHandle
Definition: cmd.c:164
struct _DirSwitchesFlags * LPDIRSWITCHFLAGS
static const WCHAR szName[]
Definition: msipriv.h:1194
BOOL bUser
Definition: dir.c:175
WIN32_FIND_STREAM_DATA stStreamInfo
Definition: dir.c:199
_TCHAR * _tcscat(_TCHAR *s, const _TCHAR *append)
Definition: tcscat.h:8
_TCHAR * _tcsrchr(const _TCHAR *s, _XINT c)
Definition: tcsrchr.h:4
#define OUT
Definition: typedefs.h:39
#define StdOut
Definition: stream.h:76
INT nDateFormat
Definition: locale.c:20
#define _istspace
Definition: tchar.h:1504
#define HIWORD(l)
Definition: typedefs.h:246
unsigned int ULONG
Definition: retypes.h:1
static VOID DirPrintFileDateTime(TCHAR *lpDate, TCHAR *lpTime, LPWIN32_FIND_DATA lpFile, LPDIRSWITCHFLAGS lpFlags)
Definition: dir.c:639
#define GetEnvironmentVariable
Definition: winbase.h:3628
static INT PrintSummary(LPCTSTR szPath, ULONG ulFiles, ULONG ulDirs, ULONGLONG u64Bytes, LPDIRSWITCHFLAGS lpFlags, BOOL TotalSummary)
Definition: dir.c:770
char * cleanup(char *str)
Definition: wpickclick.c:99
static BOOL DirReadParam(LPTSTR Line, LPTSTR **params, LPINT entries, LPDIRSWITCHFLAGS lpFlags)
Definition: dir.c:264
#define STRING_DIR_HELP8
Definition: resource.h:114
#define GetProcAddress(x, y)
Definition: compat.h:410
#define STRING_DIR_HELP3
Definition: resource.h:109
struct _DIRFINDLISTNODE * PDIRFINDLISTNODE
ETimeField
Definition: dir.c:148
static char * dest
Definition: rtl.c:135
#define STRING_DIR_HELP2
Definition: resource.h:108
#define _UNICODE
Definition: audio_test.c:1
CON_PAGER StdOutPager
Definition: console.c:30
static VOID QsortFiles(PDIRFINDINFO ptrArray[], int i, int j, LPDIRSWITCHFLAGS lpFlags)
Definition: dir.c:1293
BOOL b4Digit
Definition: dir.c:178
#define STRING_DIR_HELP5
Definition: resource.h:111
BOOL ConPrintfVPaging(PCON_PAGER Pager, BOOL StartPaging, LPTSTR szFormat, va_list arg_ptr)
Definition: console.c:155
#define LOWORD(l)
Definition: pedump.c:82
#define LoadString
Definition: winuser.h:5685
struct Line Line
BOOL bWideListColSort
Definition: dir.c:171
static VOID GetUserDiskFreeSpace(LPCTSTR lpRoot, PULARGE_INTEGER lpFreeSpace)
Definition: dir.c:725
BOOL add_entry(LPINT ac, LPSTR **arg, LPCSTR entry)
Definition: cmdcons.c:132
struct _DIRFINDSTREAMNODE * PDIRFINDSTREAMNODE
int * LPINT
Definition: windef.h:178
Definition: fci.c:126
BOOL WINAPI FindClose(HANDLE hFindFile)
Definition: find.c:502
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68