ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

dir.c
Go to the documentation of this file.
00001 /*
00002  *  DIR.C - dir internal command.
00003  *
00004  *
00005  *  History:
00006  *
00007  *    01/29/97 (Tim Norman)
00008  *        started.
00009  *
00010  *    06/13/97 (Tim Norman)
00011  *      Fixed code.
00012  *
00013  *    07/12/97 (Tim Norman)
00014  *        Fixed bug that caused the root directory to be unlistable
00015  *
00016  *    07/12/97 (Marc Desrochers)
00017  *        Changed to use maxx, maxy instead of findxy()
00018  *
00019  *    06/08/98 (Rob Lake)
00020  *        Added compatibility for /w in dir
00021  *
00022  *    06/09/98 (Rob Lake)
00023  *        Compatibility for dir/s started
00024  *        Tested that program finds directories off root fine
00025  *
00026  *    06/10/98 (Rob Lake)
00027  *        do_recurse saves the cwd and also stores it in Root
00028  *        build_tree adds the cwd to the beginning of its' entries
00029  *        Program runs fine, added print_tree -- works fine.. as EXE,
00030  *        program won't work properly as COM.
00031  *
00032  *    06/11/98 (Rob Lake)
00033  *        Found problem that caused COM not to work
00034  *
00035  *    06/12/98 (Rob Lake)
00036  *        debugged...
00037  *        added free mem routine
00038  *
00039  *    06/13/98 (Rob Lake)
00040  *        debugged the free mem routine
00041  *        debugged whole thing some more
00042  *        Notes:
00043  *        ReadDir stores Root name and _Read_Dir does the hard work
00044  *        PrintDir prints Root and _Print_Dir does the hard work
00045  *        KillDir kills Root _after_ _Kill_Dir does the hard work
00046  *        Integrated program into DIR.C(this file) and made some same
00047  *        changes throughout
00048  *
00049  *    06/14/98 (Rob Lake)
00050  *        Cleaned up code a bit, added comments
00051  *
00052  *    06/16/98 (Rob Lake)
00053  *        Added error checking to my previously added routines
00054  *
00055  *    06/17/98 (Rob Lake)
00056  *        Rewrote recursive functions, again! Most other recursive
00057  *        functions are now obsolete -- ReadDir, PrintDir, _Print_Dir,
00058  *        KillDir and _Kill_Dir.  do_recurse does what PrintDir did
00059  *        and _Read_Dir did what it did before along with what _Print_Dir
00060  *        did.  Makes /s a lot faster!
00061  *        Reports 2 more files/dirs that MS-DOS actually reports
00062  *        when used in root directory(is this because dir defaults
00063  *        to look for read only files?)
00064  *        Added support for /b, /a and /l
00065  *        Made error message similar to DOS error messages
00066  *        Added help screen
00067  *
00068  *    06/20/98 (Rob Lake)
00069  *        Added check for /-(switch) to turn off previously defined
00070  *        switches.
00071  *        Added ability to check for DIRCMD in environment and
00072  *        process it
00073  *
00074  *    06/21/98 (Rob Lake)
00075  *        Fixed up /B
00076  *        Now can dir *.ext/X, no spaces!
00077  *
00078  *    06/29/98 (Rob Lake)
00079  *        error message now found in command.h
00080  *
00081  *    07/08/1998 (John P. Price)
00082  *        removed extra returns; closer to MSDOS
00083  *        fixed wide display so that an extra return is not displayed
00084  *        when there is five filenames in the last line.
00085  *
00086  *    07/12/98 (Rob Lake)
00087  *        Changed error messages
00088  *
00089  *    27-Jul-1998 (John P Price <linux-guru@gcfl.net>)
00090  *        added config.h include
00091  *
00092  *
00093  *    04-Dec-1998 (Eric Kohl)
00094  *        Converted source code to Win32, except recursive dir ("dir /s").
00095  *
00096  *    10-Dec-1998 (Eric Kohl)
00097  *        Fixed recursive dir ("dir /s").
00098  *
00099  *    14-Dec-1998 (Eric Kohl)
00100  *        Converted to Win32 directory functions and
00101  *        fixed some output bugs. There are still some more ;)
00102  *
00103  *    10-Jan-1999 (Eric Kohl)
00104  *        Added "/N" and "/4" options, "/O" is a dummy.
00105  *        Added locale support.
00106  *
00107  *    20-Jan-1999 (Eric Kohl)
00108  *        Redirection safe!
00109  *
00110  *    01-Mar-1999 (Eric Kohl)
00111  *        Replaced all runtime io functions by their Win32 counterparts.
00112  *
00113  *    23-Feb-2001 (Carl Nettelblad <cnettel@hem.passagen.se>)
00114  *        dir /s now works in deeper trees
00115  *
00116  *    28-Jan-2004 (Michael Fritscher <michael@fritscher.net>)
00117  *        Fix for /p, so it is working under Windows in GUI-mode, too.
00118  *
00119  *    30-Apr-2004 (Filip Navara <xnavara@volny.cz>)
00120  *        Fix /w to print long names.
00121  *
00122  *    27-Feb-2005 (Konstantinos Paliouras <squarious@gmail.com>)
00123  *        Implemented all the switches that were missing, and made
00124  *        the ros dir very similar to windows dir. Major part of
00125  *        the code is rewritten. /p is removed, to be rewriten in
00126  *        the main cmd code.
00127  *
00128  *    1-Jul-2004 (Brandon Turner <turnerb7@msu.edu>)
00129  *        Added /p back in using ConOutPrintfPaging
00130  *
00131  *    3-feb-2007 (Paolo Devoti devotip at gmail)
00132  *        Removed variables formerly in use to handle pagination
00133  *        Pagination belongs to ConOutPrintfPaging
00134  *        Removed already commented out code of old pagination
00135  */
00136 
00137 #include <precomp.h>
00138 
00139 #ifdef INCLUDE_CMD_DIR
00140 
00141 
00142 
00143 /* Time Field enumeration */
00144 enum ETimeField
00145 {
00146     TF_CREATIONDATE     = 0,
00147     TF_MODIFIEDDATE     = 1,
00148     TF_LASTACCESSEDDATE = 2
00149 };
00150 
00151 /* Ordered by enumeration */
00152 enum EOrderBy
00153 {
00154     ORDER_NAME      = 0,
00155     ORDER_SIZE      = 1,
00156     ORDER_DIRECTORY = 2,
00157     ORDER_EXTENSION = 3,
00158     ORDER_TIME      = 4
00159 };
00160 
00161 /* The struct for holding the switches */
00162 typedef struct _DirSwitchesFlags
00163 {
00164     BOOL bBareFormat;   /* Bare Format */
00165     BOOL bTSeperator;   /* Thousands seperator */
00166     BOOL bWideList;     /* Wide list format */
00167     BOOL bWideListColSort;  /* Wide list format but sorted by column */
00168     BOOL bLowerCase;    /* Uses lower case */
00169     BOOL bNewLongList;  /* New long list */
00170     BOOL bPause;        /* Pause per page */
00171     BOOL bUser;         /* Displays the owner of file */
00172     BOOL bRecursive;    /* Displays files in specified directory and all sub */
00173     BOOL bShortName;    /* Displays the sort name of files if exist */
00174     BOOL b4Digit;       /* Four digit year  */
00175     struct
00176     {
00177         DWORD dwAttribVal;  /* The desired state of attribute */
00178         DWORD dwAttribMask; /* Which attributes to check */
00179     } stAttribs;        /* Displays files with this attributes only */
00180     struct
00181     {
00182         enum EOrderBy eCriteria[3]; /* Criterias used to order by */
00183         BOOL bCriteriaRev[3];       /* If the criteria is in reversed order */
00184         short sCriteriaCount;       /* The quantity of criterias */
00185     } stOrderBy;        /* Ordered by criterias */
00186     struct
00187     {
00188         enum ETimeField eTimeField; /* The time field that will be used for */
00189     } stTimeField;      /* The time field to display or use for sorting */
00190 } DIRSWITCHFLAGS, *LPDIRSWITCHFLAGS;
00191 
00192 
00193 typedef struct _DIRFINDLISTNODE
00194 {
00195   WIN32_FIND_DATA stFindInfo;
00196   struct _DIRFINDLISTNODE *ptrNext;
00197 } DIRFINDLISTNODE, *PDIRFINDLISTNODE;
00198 
00199 
00200 typedef BOOL
00201 (WINAPI *PGETFREEDISKSPACEEX)(LPCTSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER);
00202 
00203 
00204 /* Globally save the # of dirs, files and bytes,
00205  * probabaly later pass them to functions. Rob Lake  */
00206 static ULONG recurse_dir_cnt;
00207 static ULONG recurse_file_cnt;
00208 static ULONGLONG recurse_bytes;
00209 
00210 
00211 /*
00212  * help
00213  *
00214  * displays help screen for dir
00215  * Rob Lake
00216  */
00217 static VOID
00218 DirHelp(VOID)
00219 {
00220   ConOutResPaging(TRUE, STRING_DIR_HELP1);
00221 }
00222 
00223 
00224 
00225 /*
00226  * DirReadParameters
00227  *
00228  * Parse the parameters and switches of the command line and exports them
00229  */
00230 static BOOL
00231 DirReadParam(LPTSTR Line,               /* [IN] The line with the parameters & switches */
00232             LPTSTR** params,            /* [OUT] The parameters after parsing */
00233             LPINT entries,              /* [OUT] The number of parameters after parsing */
00234             LPDIRSWITCHFLAGS lpFlags)   /* [IN/OUT] The flags after calculating switches */
00235 {
00236     TCHAR cCurSwitch;   /* The current switch */
00237     TCHAR cCurChar;     /* Current examing character */
00238     TCHAR cCurUChar;    /* Current upper examing character */
00239     BOOL bNegative;     /* Negative switch */
00240     BOOL bPNegative;    /* Negative switch parameter */
00241     BOOL bIntoQuotes;   /* A flag showing if we are in quotes (") */
00242     LPTSTR ptrStart;    /* A pointer to the first character of a parameter */
00243     LPTSTR ptrEnd;      /* A pointer to the last character of a parameter */
00244     BOOL bOrderByNoPar; /* A flag to indicate /O with no switch parameter */
00245     LPTSTR temp;
00246 
00247     /* Initialize parameter array */
00248     *params = NULL;
00249     *entries = 0;
00250 
00251     /* Initialize variables; */
00252     cCurSwitch = _T(' ');
00253     bNegative = FALSE;
00254     bPNegative = FALSE;
00255 
00256     /* We suppose that switch parameters
00257        were given to avoid setting them to default
00258        if the switch was not given */
00259     bOrderByNoPar = FALSE;
00260 
00261     /* Main Loop (see README_DIR.txt) */
00262     /* scan the command line char per char, and we process its char */
00263     while (*Line)
00264     {
00265         /* we save current character as it is and its upper case */
00266         cCurChar = *Line;
00267         cCurUChar = _totupper(*Line);
00268 
00269         /* 1st section (see README_DIR.txt) */
00270         /* When a switch is expecting */
00271         if (cCurSwitch == _T('/'))
00272         {
00273             while (*Line == _T(' '))
00274                 Line++;
00275 
00276             bNegative = (*Line == _T('-'));
00277             Line += bNegative;
00278 
00279             cCurChar = *Line;
00280             cCurUChar = _totupper(*Line);
00281 
00282             if ((cCurUChar == _T('A')) ||(cCurUChar == _T('T')) || (cCurUChar == _T('O')))
00283             {
00284                 /* If positive, prepare for parameters... if negative, reset to defaults */
00285                 switch (cCurUChar)
00286                 {
00287                 case _T('A'):
00288                     lpFlags->stAttribs.dwAttribVal = 0L;
00289                     lpFlags->stAttribs.dwAttribMask = 0L;
00290                     if (bNegative)
00291                         lpFlags->stAttribs.dwAttribMask = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
00292                     break;
00293                 case _T('T'):
00294                     if (bNegative)
00295                         lpFlags->stTimeField.eTimeField = TF_MODIFIEDDATE;
00296                     break;
00297                 case _T('O'):
00298                     bOrderByNoPar = !bNegative;
00299                     lpFlags->stOrderBy.sCriteriaCount = 0;
00300                     break;
00301                 }
00302 
00303                 if (!bNegative)
00304                 {
00305                     /* Positive switch, so it can take parameters. */
00306                     cCurSwitch = cCurUChar;
00307                     Line++;
00308                     /* Skip optional leading colon */
00309                     if (*Line == _T(':'))
00310                         Line++;
00311                     continue;
00312                 }
00313             }
00314             else if (cCurUChar == _T('L'))
00315                 lpFlags->bLowerCase = ! bNegative;
00316             else if (cCurUChar == _T('B'))
00317                 lpFlags->bBareFormat = ! bNegative;
00318             else if (cCurUChar == _T('C'))
00319                 lpFlags->bTSeperator = ! bNegative;
00320             else if (cCurUChar == _T('W'))
00321                 lpFlags->bWideList = ! bNegative;
00322             else if (cCurUChar == _T('D'))
00323                 lpFlags->bWideListColSort = ! bNegative;
00324             else if (cCurUChar == _T('N'))
00325                 lpFlags->bNewLongList = ! bNegative;
00326             else if (cCurUChar == _T('P'))
00327                 lpFlags->bPause = ! bNegative;
00328             else if (cCurUChar == _T('Q'))
00329                 lpFlags->bUser = ! bNegative;
00330             else if (cCurUChar == _T('S'))
00331                 lpFlags->bRecursive = ! bNegative;
00332             else if (cCurUChar == _T('X'))
00333                 lpFlags->bShortName = ! bNegative;
00334             else if (cCurChar == _T('4'))
00335                 lpFlags->b4Digit = ! bNegative;
00336             else if (cCurChar == _T('?'))
00337             {
00338                 DirHelp();
00339                 return FALSE;
00340             }
00341             else
00342             {
00343                 error_invalid_switch ((TCHAR)_totupper (*Line));
00344                 return FALSE;
00345             }
00346 
00347             /* Make sure there's no extra characters at the end of the switch */
00348             if (Line[1] && Line[1] != _T('/') && Line[1] != _T(' '))
00349             {
00350                 error_parameter_format(Line[1]);
00351                 return FALSE;
00352             }
00353 
00354             cCurSwitch = _T(' ');
00355         }
00356         else if (cCurSwitch == _T(' '))
00357         {
00358             /* 2nd section (see README_DIR.txt) */
00359             /* We are expecting parameter or the unknown */
00360 
00361             if (cCurChar == _T('/'))
00362                 cCurSwitch = _T('/');
00363             else if (cCurChar == _T(' '))
00364                 /* do nothing */;
00365             else
00366             {
00367                 /* This is a file/directory name parameter. Find its end */
00368                 ptrStart = Line;
00369                 bIntoQuotes = FALSE;
00370                 while (*Line)
00371                 {
00372                     if (!bIntoQuotes && (*Line == _T('/') || *Line == _T(' ')))
00373                         break;
00374                     bIntoQuotes ^= (*Line == _T('"'));
00375                     Line++;
00376                 }
00377                 ptrEnd = Line;
00378 
00379                 /* Copy it to the entries list */
00380                 temp = cmd_alloc((ptrEnd - ptrStart + 1) * sizeof (TCHAR));
00381                 if(!temp)
00382                     return FALSE;
00383                 memcpy(temp, ptrStart, (ptrEnd - ptrStart) * sizeof (TCHAR));
00384                 temp[ptrEnd - ptrStart] = _T('\0');
00385                 StripQuotes(temp);
00386                 if(!add_entry(entries, params, temp))
00387                 {
00388                     cmd_free(temp);
00389                     freep(*params);
00390                     return FALSE;
00391                 }
00392 
00393                 cmd_free(temp);
00394                 continue;
00395             }
00396         }
00397         else
00398         {
00399             /* 3rd section (see README_DIR.txt) */
00400             /* We are waiting for switch parameters */
00401 
00402             /* Check if there are no more switch parameters */
00403             if ((cCurChar == _T('/')) || ( cCurChar == _T(' ')))
00404             {
00405                 /* Wrong desicion path, reprocess current character */
00406                 cCurSwitch = _T(' ');
00407                 continue;
00408             }
00409             /* Process parameter switch */
00410             switch(cCurSwitch)
00411             {
00412             case _T('A'):   /* Switch parameters for /A (attributes filter) */
00413                 if(cCurChar == _T('-'))
00414                     bPNegative = TRUE;
00415                 else if(cCurUChar == _T('D'))
00416                 {
00417                     lpFlags->stAttribs.dwAttribMask |= FILE_ATTRIBUTE_DIRECTORY;
00418                     if (bPNegative)
00419                         lpFlags->stAttribs.dwAttribVal &= ~FILE_ATTRIBUTE_DIRECTORY;
00420                     else
00421                         lpFlags->stAttribs.dwAttribVal |= FILE_ATTRIBUTE_DIRECTORY;
00422                 }
00423                 else if(cCurUChar == _T('R'))
00424                 {
00425                     lpFlags->stAttribs.dwAttribMask |= FILE_ATTRIBUTE_READONLY;
00426                     if (bPNegative)
00427                         lpFlags->stAttribs.dwAttribVal &= ~FILE_ATTRIBUTE_READONLY;
00428                     else
00429                         lpFlags->stAttribs.dwAttribVal |= FILE_ATTRIBUTE_READONLY;
00430                 }
00431                 else if(cCurUChar == _T('H'))
00432                 {
00433                     lpFlags->stAttribs.dwAttribMask |= FILE_ATTRIBUTE_HIDDEN;
00434                     if (bPNegative)
00435                         lpFlags->stAttribs.dwAttribVal &= ~FILE_ATTRIBUTE_HIDDEN;
00436                     else
00437                         lpFlags->stAttribs.dwAttribVal |= FILE_ATTRIBUTE_HIDDEN;
00438                 }
00439                 else if(cCurUChar == _T('A'))
00440                 {
00441                     lpFlags->stAttribs.dwAttribMask |= FILE_ATTRIBUTE_ARCHIVE;
00442                     if (bPNegative)
00443                         lpFlags->stAttribs.dwAttribVal &= ~FILE_ATTRIBUTE_ARCHIVE;
00444                     else
00445                         lpFlags->stAttribs.dwAttribVal |= FILE_ATTRIBUTE_ARCHIVE;
00446                 }
00447                 else if(cCurUChar == _T('S'))
00448                 {
00449                     lpFlags->stAttribs.dwAttribMask |= FILE_ATTRIBUTE_SYSTEM;
00450                     if (bPNegative)
00451                         lpFlags->stAttribs.dwAttribVal &= ~FILE_ATTRIBUTE_SYSTEM;
00452                     else
00453                         lpFlags->stAttribs.dwAttribVal |= FILE_ATTRIBUTE_SYSTEM;
00454                 }
00455                 else
00456                 {
00457                     error_parameter_format((TCHAR)_totupper (*Line));
00458                     return FALSE;
00459                 }
00460                 break;
00461             case _T('T'):   /* Switch parameters for /T (time field) */
00462                 if(cCurUChar == _T('C'))
00463                     lpFlags->stTimeField.eTimeField= TF_CREATIONDATE ;
00464                 else if(cCurUChar == _T('A'))
00465                     lpFlags->stTimeField.eTimeField= TF_LASTACCESSEDDATE ;
00466                 else if(cCurUChar == _T('W'))
00467                     lpFlags->stTimeField.eTimeField= TF_MODIFIEDDATE  ;
00468                 else
00469                 {
00470                     error_parameter_format((TCHAR)_totupper (*Line));
00471                     return FALSE;
00472                 }
00473                 break;
00474             case _T('O'):   /* Switch parameters for /O (order) */
00475                 /* Ok a switch parameter was given */
00476                 bOrderByNoPar = FALSE;
00477 
00478                 if(cCurChar == _T('-'))
00479                     bPNegative = TRUE;
00480                 else if(cCurUChar == _T('N'))
00481                 {
00482                     if (lpFlags->stOrderBy.sCriteriaCount < 3) lpFlags->stOrderBy.sCriteriaCount++;
00483                     lpFlags->stOrderBy.bCriteriaRev[lpFlags->stOrderBy.sCriteriaCount - 1] = bPNegative;
00484                     lpFlags->stOrderBy.eCriteria[lpFlags->stOrderBy.sCriteriaCount - 1] = ORDER_NAME;
00485                 }
00486                 else if(cCurUChar == _T('S'))
00487                 {
00488                     if (lpFlags->stOrderBy.sCriteriaCount < 3) lpFlags->stOrderBy.sCriteriaCount++;
00489                     lpFlags->stOrderBy.bCriteriaRev[lpFlags->stOrderBy.sCriteriaCount - 1] = bPNegative;
00490                     lpFlags->stOrderBy.eCriteria[lpFlags->stOrderBy.sCriteriaCount - 1] = ORDER_SIZE;
00491                 }
00492                 else if(cCurUChar == _T('G'))
00493                 {
00494                     if (lpFlags->stOrderBy.sCriteriaCount < 3) lpFlags->stOrderBy.sCriteriaCount++;
00495                     lpFlags->stOrderBy.bCriteriaRev[lpFlags->stOrderBy.sCriteriaCount - 1] = bPNegative;
00496                     lpFlags->stOrderBy.eCriteria[lpFlags->stOrderBy.sCriteriaCount - 1] = ORDER_DIRECTORY;
00497                 }
00498                 else if(cCurUChar == _T('E'))
00499                 {
00500                     if (lpFlags->stOrderBy.sCriteriaCount < 3) lpFlags->stOrderBy.sCriteriaCount++;
00501                     lpFlags->stOrderBy.bCriteriaRev[lpFlags->stOrderBy.sCriteriaCount - 1] = bPNegative;
00502                     lpFlags->stOrderBy.eCriteria[lpFlags->stOrderBy.sCriteriaCount - 1] = ORDER_EXTENSION;
00503                 }
00504                 else if(cCurUChar == _T('D'))
00505                 {
00506                     if (lpFlags->stOrderBy.sCriteriaCount < 3) lpFlags->stOrderBy.sCriteriaCount++;
00507                     lpFlags->stOrderBy.bCriteriaRev[lpFlags->stOrderBy.sCriteriaCount - 1] = bPNegative;
00508                     lpFlags->stOrderBy.eCriteria[lpFlags->stOrderBy.sCriteriaCount - 1] = ORDER_TIME;
00509                 }
00510 
00511                 else
00512                 {
00513                     error_parameter_format((TCHAR)_totupper (*Line));
00514                     return FALSE;
00515                 }
00516 
00517 
00518             }
00519             /* We check if we calculated the negative value and realese the flag */
00520             if ((cCurChar != _T('-')) && bPNegative)
00521                 bPNegative = FALSE;
00522         }
00523 
00524         Line++;
00525     }
00526 
00527     /* /O with no switch parameters acts like /O:GN */
00528     if (bOrderByNoPar)
00529     {
00530         lpFlags->stOrderBy.sCriteriaCount = 2;
00531         lpFlags->stOrderBy.eCriteria[0] = ORDER_DIRECTORY;
00532         lpFlags->stOrderBy.bCriteriaRev[0] = FALSE;
00533         lpFlags->stOrderBy.eCriteria[1] = ORDER_NAME;
00534         lpFlags->stOrderBy.bCriteriaRev[1] = FALSE;
00535     }
00536 
00537     return TRUE;
00538 }
00539 
00540 /* Print either with or without paging, depending on /P switch */
00541 static INT
00542 DirPrintf(LPDIRSWITCHFLAGS lpFlags, LPTSTR szFormat, ...)
00543 {
00544     INT iReturn = 0;
00545     va_list arg_ptr;
00546     va_start(arg_ptr, szFormat);
00547     if (lpFlags->bPause)
00548         iReturn = ConPrintfPaging(FALSE, szFormat, arg_ptr, STD_OUTPUT_HANDLE);
00549     else
00550         ConPrintf(szFormat, arg_ptr, STD_OUTPUT_HANDLE);
00551     va_end(arg_ptr);
00552     return iReturn;
00553 }
00554 
00555 
00556 /*
00557  * PrintDirectoryHeader
00558  *
00559  * print the header for the dir command
00560  */
00561 static BOOL
00562 PrintDirectoryHeader(LPTSTR szPath, LPDIRSWITCHFLAGS lpFlags)
00563 {
00564   TCHAR szMsg[RC_STRING_MAX_SIZE];
00565   TCHAR szFullDir[MAX_PATH];
00566   TCHAR szRootName[MAX_PATH];
00567   TCHAR szVolName[80];
00568   LPTSTR pszFilePart;
00569   DWORD dwSerialNr;
00570 
00571   if (lpFlags->bBareFormat)
00572     return TRUE;
00573 
00574   if (GetFullPathName(szPath, sizeof(szFullDir) / sizeof(TCHAR), szFullDir, &pszFilePart) == 0)
00575     {
00576       ErrorMessage(GetLastError(), _T("Failed to build full directory path"));
00577       return FALSE;
00578     }
00579 
00580   if (pszFilePart != NULL)
00581       *pszFilePart = _T('\0');
00582 
00583   /* get the media ID of the drive */
00584   if (!GetVolumePathName(szFullDir, szRootName, sizeof(szRootName) / sizeof(TCHAR)) ||
00585       !GetVolumeInformation(szRootName, szVolName, 80, &dwSerialNr,
00586                 NULL, NULL, NULL, 0))
00587     {
00588       return(TRUE);
00589     }
00590 
00591   /* print drive info */
00592   if (szVolName[0] != _T('\0'))
00593     {
00594       LoadString(CMD_ModuleHandle, STRING_DIR_HELP2, szMsg, RC_STRING_MAX_SIZE);
00595       DirPrintf(lpFlags, szMsg, szRootName[0], szVolName);
00596     }
00597   else
00598     {
00599       LoadString(CMD_ModuleHandle, STRING_DIR_HELP3, szMsg, RC_STRING_MAX_SIZE);
00600       DirPrintf(lpFlags, szMsg, szRootName[0]);
00601     }
00602 
00603   /* print the volume serial number if the return was successful */
00604   LoadString(CMD_ModuleHandle, STRING_DIR_HELP4, (LPTSTR) szMsg, RC_STRING_MAX_SIZE);
00605   DirPrintf(lpFlags, szMsg, HIWORD(dwSerialNr), LOWORD(dwSerialNr));
00606 
00607   return TRUE;
00608 }
00609 
00610 
00611 static VOID
00612 DirPrintFileDateTime(TCHAR *lpDate,
00613                      TCHAR *lpTime,
00614                      LPWIN32_FIND_DATA lpFile,
00615                      LPDIRSWITCHFLAGS lpFlags)
00616 {
00617     FILETIME ft;
00618     SYSTEMTIME dt;
00619 
00620     /* Select the right time field */
00621     switch (lpFlags->stTimeField.eTimeField)
00622     {
00623         case TF_CREATIONDATE:
00624             if (!FileTimeToLocalFileTime(&lpFile->ftCreationTime, &ft))
00625                 return;
00626             FileTimeToSystemTime(&ft, &dt);
00627             break;
00628 
00629         case TF_LASTACCESSEDDATE :
00630             if (!FileTimeToLocalFileTime(&lpFile->ftLastAccessTime, &ft))
00631                 return;
00632             FileTimeToSystemTime(&ft, &dt);
00633             break;
00634 
00635         case TF_MODIFIEDDATE:
00636             if (!FileTimeToLocalFileTime(&lpFile->ftLastWriteTime, &ft))
00637                 return;
00638             FileTimeToSystemTime(&ft, &dt);
00639             break;
00640     }
00641 
00642     FormatDate(lpDate, &dt, lpFlags->b4Digit);
00643     FormatTime(lpTime, &dt);
00644 }
00645 
00646 INT
00647 FormatDate(TCHAR *lpDate, LPSYSTEMTIME dt, BOOL b4Digit)
00648 {
00649     /* Format date */
00650     WORD wYear = b4Digit ? dt->wYear : dt->wYear%100;
00651     switch (nDateFormat)
00652     {
00653         case 0: /* mmddyy */
00654         default:
00655             return _stprintf(lpDate, _T("%02d%c%02d%c%0*d"),
00656                     dt->wMonth, cDateSeparator,
00657                     dt->wDay, cDateSeparator,
00658                     b4Digit?4:2, wYear);
00659             break;
00660 
00661         case 1: /* ddmmyy */
00662             return _stprintf(lpDate, _T("%02d%c%02d%c%0*d"),
00663                     dt->wDay, cDateSeparator, dt->wMonth,
00664                     cDateSeparator, b4Digit?4:2, wYear);
00665             break;
00666 
00667         case 2: /* yymmdd */
00668             return _stprintf(lpDate, _T("%0*d%c%02d%c%02d"),
00669                     b4Digit?4:2, wYear, cDateSeparator,
00670                     dt->wMonth, cDateSeparator, dt->wDay);
00671             break;
00672     }
00673 }
00674 
00675 INT
00676 FormatTime(TCHAR *lpTime, LPSYSTEMTIME dt)
00677 {
00678     /* Format Time */
00679     switch (nTimeFormat)
00680     {
00681         case 0: /* 12 hour format */
00682         default:
00683             return _stprintf(lpTime,_T("%02d%c%02u %cM"),
00684                     (dt->wHour == 0 ? 12 : (dt->wHour <= 12 ? dt->wHour : dt->wHour - 12)),
00685                     cTimeSeparator,
00686                      dt->wMinute, (dt->wHour <= 11 ? _T('A') : _T('P')));
00687             break;
00688 
00689         case 1: /* 24 hour format */
00690             return _stprintf(lpTime, _T("%02d%c%02u"),
00691                     dt->wHour, cTimeSeparator, dt->wMinute);
00692             break;
00693     }
00694 }
00695 
00696 
00697 static VOID
00698 GetUserDiskFreeSpace(LPCTSTR lpRoot,
00699              PULARGE_INTEGER lpFreeSpace)
00700 {
00701   PGETFREEDISKSPACEEX pGetFreeDiskSpaceEx;
00702   HINSTANCE hInstance;
00703   DWORD dwSecPerCl;
00704   DWORD dwBytPerSec;
00705   DWORD dwFreeCl;
00706   DWORD dwTotCl;
00707   ULARGE_INTEGER TotalNumberOfBytes, TotalNumberOfFreeBytes;
00708 
00709   lpFreeSpace->QuadPart = 0;
00710 
00711   hInstance = GetModuleHandle(_T("KERNEL32"));
00712   if (hInstance != NULL)
00713     {
00714       pGetFreeDiskSpaceEx = (PGETFREEDISKSPACEEX)GetProcAddress(hInstance,
00715 #ifdef _UNICODE
00716                                             "GetDiskFreeSpaceExW");
00717 #else
00718                                                 "GetDiskFreeSpaceExA");
00719 #endif
00720       if (pGetFreeDiskSpaceEx != NULL)
00721     {
00722       if (pGetFreeDiskSpaceEx(lpRoot, lpFreeSpace, &TotalNumberOfBytes, &TotalNumberOfFreeBytes) == TRUE)
00723         return;
00724     }
00725     }
00726 
00727   GetDiskFreeSpace(lpRoot,
00728            &dwSecPerCl,
00729            &dwBytPerSec,
00730            &dwFreeCl,
00731            &dwTotCl);
00732 
00733   lpFreeSpace->QuadPart = dwSecPerCl * dwBytPerSec * dwFreeCl;
00734 }
00735 
00736 
00737 /*
00738  * print_summary: prints dir summary
00739  * Added by Rob Lake 06/17/98 to compact code
00740  * Just copied Tim's Code and patched it a bit
00741  *
00742  */
00743 static INT
00744 PrintSummary(LPTSTR szPath,
00745          ULONG ulFiles,
00746          ULONG ulDirs,
00747          ULONGLONG u64Bytes,
00748          LPDIRSWITCHFLAGS lpFlags,
00749          BOOL TotalSummary)
00750 {
00751     TCHAR szMsg[RC_STRING_MAX_SIZE];
00752     TCHAR szBuffer[64];
00753     ULARGE_INTEGER uliFree;
00754 
00755 
00756     /* Here we check if we didn't find anything */
00757     if (!(ulFiles + ulDirs))
00758     {
00759         if (!lpFlags->bRecursive || (TotalSummary && lpFlags->bRecursive))
00760             error_file_not_found();
00761         return 1;
00762     }
00763 
00764 
00765     /* In bare format we don't print results */
00766     if (lpFlags->bBareFormat)
00767         return 0;
00768 
00769     /* Print recursive specific results */
00770 
00771     /* Take this code offline to fix /S does not print duoble info */
00772    if (TotalSummary && lpFlags->bRecursive)
00773    {
00774       ConvertULargeInteger(u64Bytes, szBuffer, sizeof(szBuffer), lpFlags->bTSeperator);
00775       LoadString(CMD_ModuleHandle, STRING_DIR_HELP5, szMsg, RC_STRING_MAX_SIZE);
00776       DirPrintf(lpFlags, szMsg, ulFiles, szBuffer);
00777    }
00778    else
00779    {
00780       /* Print File Summary */
00781       /* Condition to print summary is:
00782       If we are not in bare format and if we have results! */
00783       ConvertULargeInteger(u64Bytes, szBuffer, 20, lpFlags->bTSeperator);
00784       LoadString(CMD_ModuleHandle, STRING_DIR_HELP8, szMsg, RC_STRING_MAX_SIZE);
00785       DirPrintf(lpFlags, szMsg, ulFiles, szBuffer);
00786    }
00787 
00788     /* Print total directories and freespace */
00789     if (!lpFlags->bRecursive || TotalSummary)
00790     {
00791         GetUserDiskFreeSpace(szPath, &uliFree);
00792         ConvertULargeInteger(uliFree.QuadPart, szBuffer, sizeof(szBuffer), lpFlags->bTSeperator);
00793         LoadString(CMD_ModuleHandle, STRING_DIR_HELP6, (LPTSTR) szMsg, RC_STRING_MAX_SIZE);
00794         DirPrintf(lpFlags, szMsg, ulDirs, szBuffer);
00795     }
00796 
00797     return 0;
00798 }
00799 
00800 /*
00801  * getExt
00802  *
00803  * Get the extension of a filename
00804  */
00805 TCHAR* getExt(const TCHAR* file)
00806 {
00807         static TCHAR *NoExt = _T("");
00808         TCHAR* lastdot = _tcsrchr(file, _T('.'));
00809     return (lastdot != NULL ? lastdot + 1 : NoExt);
00810 }
00811 
00812 /*
00813  * getName
00814  *
00815  * Get the name of the file without extension
00816  */
00817 static LPTSTR
00818 getName(const TCHAR* file, TCHAR * dest)
00819 {
00820     INT_PTR iLen;
00821     LPTSTR end;
00822 
00823     /* Check for "." and ".." folders */
00824     if ((_tcscmp(file, _T(".")) == 0) ||
00825         (_tcscmp(file, _T("..")) == 0))
00826     {
00827         _tcscpy(dest,file);
00828         return dest;
00829     }
00830 
00831     end = _tcsrchr(file, _T('.'));
00832     if (!end)
00833         iLen = _tcslen(file);
00834     else
00835         iLen = (end - file);
00836 
00837 
00838     _tcsncpy(dest, file, iLen);
00839     *(dest + iLen) = _T('\0');
00840 
00841     return dest;
00842 }
00843 
00844 
00845 /*
00846  *  DirPrintNewList
00847  *
00848  * The function that prints in new style
00849  */
00850 static VOID
00851 DirPrintNewList(LPWIN32_FIND_DATA ptrFiles[],   /* [IN]Files' Info */
00852         DWORD dwCount,          /* [IN] The quantity of files */
00853         TCHAR *szCurPath,       /* [IN] Full path of current directory */
00854         LPDIRSWITCHFLAGS lpFlags)   /* [IN] The flags used */
00855 {
00856   DWORD i;
00857   TCHAR szSize[30];
00858   TCHAR szShortName[15];
00859   TCHAR szDate[20];
00860   TCHAR szTime[20];
00861   INT iSizeFormat;
00862   ULARGE_INTEGER u64FileSize;
00863 
00864   for (i = 0; i < dwCount && !bCtrlBreak; i++)
00865   {
00866     /* Calculate size */
00867     if (ptrFiles[i]->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
00868     {
00869       /* Junction */
00870       iSizeFormat = -14;
00871       _tcscpy(szSize, _T("<JUNCTION>"));
00872     }
00873     else if (ptrFiles[i]->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
00874     {
00875       /* Directory */
00876       iSizeFormat = -14;
00877       _tcscpy(szSize, _T("<DIR>"));
00878     }
00879     else
00880     {
00881       /* File */
00882       iSizeFormat = 14;
00883       u64FileSize.HighPart = ptrFiles[i]->nFileSizeHigh;
00884       u64FileSize.LowPart = ptrFiles[i]->nFileSizeLow;
00885       ConvertULargeInteger(u64FileSize.QuadPart, szSize, 20, lpFlags->bTSeperator);
00886     }
00887 
00888     /* Calculate short name */
00889     szShortName[0] = _T('\0');
00890     if (lpFlags->bShortName)
00891       _stprintf(szShortName, _T(" %-12s"), ptrFiles[i]->cAlternateFileName);
00892 
00893     /* Format date and time */
00894     DirPrintFileDateTime(szDate, szTime, ptrFiles[i], lpFlags);
00895 
00896     /* Print the line */
00897     DirPrintf(lpFlags, _T("%10s  %-6s    %*s%s %s\n"),
00898                             szDate,
00899                             szTime,
00900                             iSizeFormat,
00901                             szSize,
00902                             szShortName,
00903                             ptrFiles[i]->cFileName);
00904   }
00905 }
00906 
00907 
00908 /*
00909  *  DirPrintWideList
00910  *
00911  * The function that prints in wide list
00912  */
00913 static VOID
00914 DirPrintWideList(LPWIN32_FIND_DATA ptrFiles[],  /* [IN] Files' Info */
00915                  DWORD dwCount,         /* [IN] The quantity of files */
00916                  TCHAR *szCurPath,      /* [IN] Full path of current directory */
00917                  LPDIRSWITCHFLAGS lpFlags)  /* [IN] The flags used */
00918 {
00919   SHORT iScreenWidth;
00920   USHORT iColumns;
00921   USHORT iLines;
00922   UINT_PTR iLongestName;
00923   TCHAR szTempFname[MAX_PATH];
00924   DWORD i;
00925   DWORD j;
00926   DWORD temp;
00927 
00928   /* Calculate longest name */
00929   iLongestName = 1;
00930   for (i = 0; i < dwCount; i++)
00931   {
00932     if (ptrFiles[i]->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
00933     {
00934       /* Directories need 2 additinal characters for brackets */
00935       if ((_tcslen(ptrFiles[i]->cFileName) + 2) > iLongestName)
00936         iLongestName = _tcslen(ptrFiles[i]->cFileName) + 2;
00937     }
00938     else
00939     {
00940       if (_tcslen(ptrFiles[i]->cFileName) > iLongestName)
00941         iLongestName = _tcslen(ptrFiles[i]->cFileName);
00942     }
00943   }
00944 
00945   /* Count the highest number of columns */
00946   GetScreenSize(&iScreenWidth, 0);
00947   iColumns = (USHORT)(iScreenWidth / iLongestName);
00948 
00949   /* Check if there is enough space for spaces between names */
00950   if (((iLongestName * iColumns) + iColumns) >= (UINT)iScreenWidth)
00951     iColumns --;
00952 
00953   /* A last check at iColumns to avoid division by zero */
00954   if (!(iColumns))
00955     iColumns = 1;
00956 
00957   /* Calculate the lines that will be printed */
00958   iLines = (USHORT)((dwCount + iColumns - 1) / iColumns);
00959 
00960   for (i = 0; i < iLines && !bCtrlBreak; i++)
00961   {
00962     for (j = 0; j < iColumns; j++)
00963     {
00964       if (lpFlags->bWideListColSort)
00965       {
00966         /* Print Column sorted */
00967         temp = (j * iLines) + i;
00968       }
00969       else
00970       {
00971         /* Print Line sorted */
00972         temp = (i * iColumns) + j;
00973       }
00974 
00975       if (temp >= dwCount)
00976          break;
00977 
00978       if (ptrFiles[temp]->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
00979         _stprintf(szTempFname, _T("[%s]"), ptrFiles[temp]->cFileName);
00980       else
00981         _stprintf(szTempFname, _T("%s"), ptrFiles[temp]->cFileName);
00982 
00983       DirPrintf(lpFlags, _T("%-*s"), iLongestName + 1, szTempFname);
00984     }
00985 
00986     /* Add a new line after the last item in the column */
00987     DirPrintf(lpFlags, _T("\n"));
00988   }
00989 }
00990 
00991 
00992 /*
00993  *  DirPrintOldList
00994  *
00995  * The function that prints in old style
00996  */
00997 static VOID
00998 DirPrintOldList(LPWIN32_FIND_DATA ptrFiles[],   /* [IN] Files' Info */
00999                 DWORD dwCount,                  /* [IN] The quantity of files */
01000                 TCHAR * szCurPath,              /* [IN] Full path of current directory */
01001                 LPDIRSWITCHFLAGS lpFlags)       /* [IN] The flags used */
01002 {
01003 DWORD i;                        /* An indexer for "for"s */
01004 TCHAR szName[10];               /* The name of file */
01005 TCHAR szExt[5];                 /* The extension of file */
01006 TCHAR szDate[30],szTime[30];    /* Used to format time and date */
01007 TCHAR szSize[30];               /* The size of file */
01008 int iSizeFormat;                /* The format of size field */
01009 ULARGE_INTEGER u64FileSize;     /* The file size */
01010 
01011     for (i = 0; i < dwCount && !bCtrlBreak; i++)
01012     {
01013         /* Broke 8.3 format */
01014         if (*ptrFiles[i]->cAlternateFileName )
01015         {
01016             /* If the file is long named then we read the alter name */
01017             getName( ptrFiles[i]->cAlternateFileName, szName);
01018             _tcscpy(szExt, getExt( ptrFiles[i]->cAlternateFileName));
01019         }
01020         else
01021         {
01022             /* If the file is not long name we read its original name */
01023             getName( ptrFiles[i]->cFileName, szName);
01024             _tcscpy(szExt, getExt( ptrFiles[i]->cFileName));
01025         }
01026 
01027         /* Calculate size */
01028         if (ptrFiles[i]->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
01029         {
01030             /* Directory, no size it's a directory*/
01031             iSizeFormat = -17;
01032             _tcscpy(szSize, _T("<DIR>"));
01033         }
01034         else
01035         {
01036             /* File */
01037             iSizeFormat = 17;
01038             u64FileSize.HighPart = ptrFiles[i]->nFileSizeHigh;
01039             u64FileSize.LowPart = ptrFiles[i]->nFileSizeLow;
01040             ConvertULargeInteger(u64FileSize.QuadPart, szSize, 20, lpFlags->bTSeperator);
01041         }
01042 
01043         /* Format date and time */
01044         DirPrintFileDateTime(szDate,szTime,ptrFiles[i],lpFlags);
01045 
01046         /* Print the line */
01047         DirPrintf(lpFlags, _T("%-8s %-3s  %*s %s  %s\n"),
01048                                 szName,         /* The file's 8.3 name */
01049                                 szExt,          /* The file's 8.3 extension */
01050                                 iSizeFormat,    /* print format for size column */
01051                                 szSize,         /* The size of file or "<DIR>" for dirs */
01052                                 szDate,         /* The date of file/dir */
01053                                 szTime);        /* The time of file/dir */
01054     }
01055 }
01056 
01057 /*
01058  *  DirPrintBareList
01059  *
01060  * The function that prints in bare format
01061  */
01062 static VOID
01063 DirPrintBareList(LPWIN32_FIND_DATA ptrFiles[],  /* [IN] Files' Info */
01064                  DWORD dwCount,         /* [IN] The number of files */
01065                  LPTSTR lpCurPath,      /* [IN] Full path of current directory */
01066                  LPDIRSWITCHFLAGS lpFlags)  /* [IN] The flags used */
01067 {
01068     DWORD i;
01069 
01070     for (i = 0; i < dwCount && !bCtrlBreak; i++)
01071     {
01072         if ((_tcscmp(ptrFiles[i]->cFileName, _T(".")) == 0) ||
01073             (_tcscmp(ptrFiles[i]->cFileName, _T("..")) == 0))
01074         {
01075             /* at bare format we don't print "." and ".." folder */
01076             continue;
01077         }
01078         if (lpFlags->bRecursive)
01079         {
01080             /* at recursive mode we print full path of file */
01081             DirPrintf(lpFlags, _T("%s\\%s\n"), lpCurPath, ptrFiles[i]->cFileName);
01082         }
01083         else
01084         {
01085             /* if we are not in recursive mode we print the file names */
01086             DirPrintf(lpFlags, _T("%s\n"), ptrFiles[i]->cFileName);
01087         }
01088     }
01089 }
01090 
01091 
01092 /*
01093  * DirPrintFiles
01094  *
01095  * The functions that prints the files list
01096  */
01097 static VOID
01098 DirPrintFiles(LPWIN32_FIND_DATA ptrFiles[], /* [IN] Files' Info */
01099               DWORD dwCount,            /* [IN] The quantity of files */
01100               TCHAR *szCurPath,         /* [IN] Full path of current directory */
01101               LPDIRSWITCHFLAGS lpFlags)     /* [IN] The flags used */
01102 {
01103     TCHAR szMsg[RC_STRING_MAX_SIZE];
01104     TCHAR szTemp[MAX_PATH];         /* A buffer to format the directory header */
01105 
01106     /* Print trailing backslash for root directory of drive */
01107     _tcscpy(szTemp, szCurPath);
01108     if (_tcslen(szTemp) == 2 && szTemp[1] == _T(':'))
01109         _tcscat(szTemp, _T("\\"));
01110 
01111     /* Condition to print header:
01112        We are not printing in bare format
01113        and if we are in recursive mode... we must have results */
01114     if (!(lpFlags->bBareFormat ) && !((lpFlags->bRecursive) && (dwCount <= 0)))
01115     {
01116         LoadString(CMD_ModuleHandle, STRING_DIR_HELP7, szMsg, RC_STRING_MAX_SIZE);
01117         if (DirPrintf(lpFlags, szMsg, szTemp))
01118             return;
01119     }
01120 
01121     if (lpFlags->bBareFormat)
01122     {
01123         /* Bare format */
01124         DirPrintBareList(ptrFiles, dwCount, szCurPath, lpFlags);
01125     }
01126     else if(lpFlags->bShortName)
01127     {
01128         /* New list style / Short names */
01129         DirPrintNewList(ptrFiles, dwCount, szCurPath, lpFlags);
01130     }
01131     else if(lpFlags->bWideListColSort || lpFlags->bWideList)
01132     {
01133         /* Wide list */
01134         DirPrintWideList(ptrFiles, dwCount, szCurPath, lpFlags);
01135     }
01136     else if (lpFlags->bNewLongList )
01137     {
01138         /* New list style*/
01139         DirPrintNewList(ptrFiles, dwCount, szCurPath, lpFlags);
01140     }
01141     else
01142     {
01143         /* If nothing is selected old list is the default */
01144         DirPrintOldList(ptrFiles, dwCount, szCurPath, lpFlags);
01145     }
01146 }
01147 
01148 
01149 
01150 /*
01151  * CompareFiles
01152  *
01153  * Compares 2 files based on the order criteria
01154  */
01155 static BOOL
01156 CompareFiles(LPWIN32_FIND_DATA lpFile1, /* [IN] A pointer to WIN32_FIND_DATA of file 1 */
01157              LPWIN32_FIND_DATA lpFile2, /* [IN] A pointer to WIN32_FIND_DATA of file 2 */
01158              LPDIRSWITCHFLAGS lpFlags)  /* [IN] The flags that we use to list */
01159 {
01160   ULARGE_INTEGER u64File1;
01161   ULARGE_INTEGER u64File2;
01162   int i;
01163   long iComp = 0;                   /* The comparison result */
01164 
01165     /* Calculate critiries by order given from user */
01166     for (i = 0;i < lpFlags->stOrderBy.sCriteriaCount;i++)
01167     {
01168 
01169         /* Calculate criteria */
01170         switch(lpFlags->stOrderBy.eCriteria[i])
01171         {
01172         case ORDER_SIZE:        /* Order by size /o:s */
01173             /* concat the 32bit integers to a 64bit */
01174             u64File1.LowPart = lpFile1->nFileSizeLow;
01175             u64File1.HighPart = lpFile1->nFileSizeHigh;
01176             u64File2.LowPart = lpFile2->nFileSizeLow;
01177             u64File2.HighPart = lpFile2->nFileSizeHigh;
01178 
01179             /* In case that differnce is too big for a long */
01180             if (u64File1.QuadPart < u64File2.QuadPart)
01181                 iComp = -1;
01182             else if (u64File1.QuadPart > u64File2.QuadPart)
01183                 iComp = 1;
01184             else
01185                 iComp = 0;
01186             break;
01187 
01188         case ORDER_DIRECTORY:   /* Order by directory attribute /o:g */
01189             iComp = ((lpFile2->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)-
01190                 (lpFile1->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY));
01191             break;
01192 
01193         case ORDER_EXTENSION:   /* Order by extension name /o:e */
01194             iComp = _tcsicmp(getExt(lpFile1->cFileName),getExt(lpFile2->cFileName));
01195             break;
01196 
01197         case ORDER_NAME:        /* Order by filename /o:n */
01198             iComp = _tcsicmp(lpFile1->cFileName, lpFile2->cFileName);
01199             break;
01200 
01201         case ORDER_TIME:        /* Order by file's time /o:t */
01202             /* We compare files based on the time field selected by /t */
01203             switch(lpFlags->stTimeField.eTimeField)
01204             {
01205             case TF_CREATIONDATE:
01206                 /* concat the 32bit integers to a 64bit */
01207                 u64File1.LowPart = lpFile1->ftCreationTime.dwLowDateTime;
01208                 u64File1.HighPart = lpFile1->ftCreationTime.dwHighDateTime ;
01209                 u64File2.LowPart = lpFile2->ftCreationTime.dwLowDateTime;
01210                 u64File2.HighPart = lpFile2->ftCreationTime.dwHighDateTime ;
01211                 break;
01212             case TF_LASTACCESSEDDATE :
01213                 /* concat the 32bit integers to a 64bit */
01214                 u64File1.LowPart = lpFile1->ftLastAccessTime.dwLowDateTime;
01215                 u64File1.HighPart = lpFile1->ftLastAccessTime.dwHighDateTime ;
01216                 u64File2.LowPart = lpFile2->ftLastAccessTime.dwLowDateTime;
01217                 u64File2.HighPart = lpFile2->ftLastAccessTime.dwHighDateTime ;
01218                 break;
01219             case TF_MODIFIEDDATE:
01220                 /* concat the 32bit integers to a 64bit */
01221                 u64File1.LowPart = lpFile1->ftLastWriteTime.dwLowDateTime;
01222                 u64File1.HighPart = lpFile1->ftLastWriteTime.dwHighDateTime ;
01223                 u64File2.LowPart = lpFile2->ftLastWriteTime.dwLowDateTime;
01224                 u64File2.HighPart = lpFile2->ftLastWriteTime.dwHighDateTime ;
01225                 break;
01226             }
01227 
01228             /* In case that differnce is too big for a long */
01229             if (u64File1.QuadPart < u64File2.QuadPart)
01230                 iComp = -1;
01231             else if (u64File1.QuadPart > u64File2.QuadPart)
01232                 iComp = 1;
01233             else
01234                 iComp = 0;
01235             break;
01236         }
01237 
01238         /* Reverse if desired */
01239         if (lpFlags->stOrderBy.bCriteriaRev[i])
01240             iComp *= -1;
01241 
01242         /* If that criteria was enough for distinguishing
01243            the files/dirs,there is no need to calculate the others*/
01244         if (iComp != 0) break;
01245     }
01246 
01247     /* Translate the value of iComp to boolean */
01248     return iComp > 0;
01249 }
01250 
01251 /*
01252  * QsortFiles
01253  *
01254  * Sort files by the order criterias using quicksort method
01255  */
01256 static VOID
01257 QsortFiles(LPWIN32_FIND_DATA ptrArray[],    /* [IN/OUT] The array with file info pointers */
01258        int i,               /* [IN]     The index of first item in array */
01259        int j,               /* [IN]     The index to last item in array */
01260        LPDIRSWITCHFLAGS lpFlags)        /* [IN]     The flags that we will use to sort */
01261 {
01262     LPWIN32_FIND_DATA lpTemp;   /* A temporary pointer */
01263     BOOL Way;
01264 
01265     if (i < j)
01266     {
01267         int First = i, Last = j, Temp;
01268         Way = TRUE;
01269         while (i != j)
01270         {
01271             if (Way == CompareFiles(ptrArray[i], ptrArray[j], lpFlags))
01272             {
01273                 /* Swap the pointers of the array */
01274                 lpTemp = ptrArray[i];
01275                 ptrArray[i]= ptrArray[j];
01276                 ptrArray[j] = lpTemp;
01277 
01278                 /* Swap the indexes for inverting sorting */
01279                 Temp = i;
01280                 i = j;
01281                 j =Temp;
01282 
01283                 Way = !Way;
01284             }
01285 
01286             j += (!Way - Way);
01287         }
01288 
01289         QsortFiles(ptrArray,First, i-1, lpFlags);
01290         QsortFiles(ptrArray,i+1,Last, lpFlags);
01291     }
01292 }
01293 
01294 
01295 
01296 /*
01297  * DirList
01298  *
01299  * The functions that does everything except for printing results
01300  */
01301 static INT
01302 DirList(LPTSTR szPath,          /* [IN] The path that dir starts */
01303         LPDIRSWITCHFLAGS lpFlags)   /* [IN] The flags of the listing */
01304 {
01305     BOOL fPoint;                            /* If szPath is a file with extension fPoint will be True*/
01306     HANDLE hSearch;                         /* The handle of the search */
01307     HANDLE hRecSearch;                      /* The handle for searching recursivly */
01308     WIN32_FIND_DATA wfdFileInfo;            /* The info of file that found */
01309     LPWIN32_FIND_DATA * ptrFileArray;       /* An array of pointers with all the files */
01310     PDIRFINDLISTNODE ptrStartNode;          /* The pointer to the first node */
01311     PDIRFINDLISTNODE ptrNextNode;           /* A pointer used for relatives refernces */
01312     TCHAR szFullPath[MAX_PATH];             /* The full path that we are listing with trailing \ */
01313     TCHAR szSubPath[MAX_PATH];
01314     LPTSTR pszFilePart;
01315     DWORD dwCount;                          /* A counter of files found in directory */
01316     DWORD dwCountFiles;                     /* Counter for files */
01317     DWORD dwCountDirs;                      /* Counter for directories */
01318     ULONGLONG u64CountBytes;                /* Counter for bytes */
01319     ULARGE_INTEGER u64Temp;                 /* A temporary counter */
01320 
01321     /* Initialize Variables */
01322     ptrStartNode = NULL;
01323     ptrNextNode = NULL;
01324     dwCount = 0;
01325     dwCountFiles = 0;
01326     dwCountDirs = 0;
01327     u64CountBytes = 0;
01328     fPoint= FALSE;
01329 
01330     /* Create szFullPath */
01331     if (GetFullPathName(szPath, sizeof(szFullPath) / sizeof(TCHAR), szFullPath, &pszFilePart) == 0)
01332     {
01333         _tcscpy (szFullPath, szPath);
01334         pszFilePart = NULL;
01335     }
01336 
01337     /* If no wildcard or file was specified and this is a directory, then
01338        display all files in it */
01339     if (pszFilePart == NULL || IsExistingDirectory(szFullPath))
01340     {
01341         pszFilePart = &szFullPath[_tcslen(szFullPath)];
01342         if (pszFilePart[-1] != _T('\\'))
01343             *pszFilePart++ = _T('\\');
01344         _tcscpy(pszFilePart, _T("*"));
01345     }
01346 
01347     /* Prepare the linked list, first node is allocated */
01348     ptrStartNode = cmd_alloc(sizeof(DIRFINDLISTNODE));
01349     if (ptrStartNode == NULL)
01350     {
01351         WARN("DEBUG: Cannot allocate memory for ptrStartNode!\n");
01352         return 1;   /* Error cannot allocate memory for 1st object */
01353     }
01354     ptrNextNode = ptrStartNode;
01355 
01356     /*Checking ir szPath is a File with/wout extension*/
01357     if (szPath[_tcslen(szPath) - 1] == _T('.'))
01358         fPoint= TRUE;
01359 
01360     /* Collect the results for the current folder */
01361     hSearch = FindFirstFile(szFullPath, &wfdFileInfo);
01362     if (hSearch != INVALID_HANDLE_VALUE)
01363     {
01364         do
01365         {
01366             /*If retrieved FileName has extension,and szPath doesnt have extension then JUMP the retrieved FileName*/
01367             if(_tcschr(wfdFileInfo.cFileName,_T('.'))&&(fPoint==TRUE))
01368             {
01369                 continue;
01370             /* Here we filter all the specified attributes */
01371             }else if ((wfdFileInfo.dwFileAttributes & lpFlags->stAttribs.dwAttribMask )
01372                     == (lpFlags->stAttribs.dwAttribMask & lpFlags->stAttribs.dwAttribVal ))
01373                 {
01374                     ptrNextNode->ptrNext = cmd_alloc(sizeof(DIRFINDLISTNODE));
01375                     if (ptrNextNode->ptrNext == NULL)
01376                     {
01377                         WARN("DEBUG: Cannot allocate memory for ptrNextNode->ptrNext!\n");
01378                         while (ptrStartNode)
01379                         {
01380                             ptrNextNode = ptrStartNode->ptrNext;
01381                             cmd_free(ptrStartNode);
01382                             ptrStartNode = ptrNextNode;
01383                             dwCount --;
01384                         }
01385                         FindClose(hSearch);
01386                         return 1;
01387                     }
01388 
01389                 /* If cmd_alloc fails we go to next file in hope it works,
01390                    without braking the linked list! */
01391                     if (ptrNextNode->ptrNext)
01392                     {
01393                     /* Copy the info of search at linked list */
01394                         memcpy(&ptrNextNode->ptrNext->stFindInfo,
01395                                 &wfdFileInfo,
01396                                 sizeof(WIN32_FIND_DATA));
01397 
01398                     /* If lower case is selected do it here */
01399                         if (lpFlags->bLowerCase)
01400                         {
01401                         _tcslwr(ptrNextNode->ptrNext->stFindInfo.cAlternateFileName);
01402                         _tcslwr(ptrNextNode->ptrNext->stFindInfo.cFileName);
01403                         }
01404 
01405                     /* Continue at next node at linked list */
01406                         ptrNextNode = ptrNextNode->ptrNext;
01407                         dwCount ++;
01408 
01409                     /* Grab statistics */
01410                         if (wfdFileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
01411                         {
01412                         /* Directory */
01413                             dwCountDirs++;
01414                         }
01415                         else
01416                             {
01417                         /* File */
01418                             dwCountFiles++;
01419                             u64Temp.HighPart = wfdFileInfo.nFileSizeHigh;
01420                             u64Temp.LowPart = wfdFileInfo.nFileSizeLow;
01421                             u64CountBytes += u64Temp.QuadPart;
01422                         }
01423                     }
01424                 }
01425         } while (FindNextFile(hSearch, &wfdFileInfo));
01426         FindClose(hSearch);
01427     }
01428 
01429     /* Terminate list */
01430     ptrNextNode->ptrNext = NULL;
01431 
01432     /* Calculate and allocate space need for making an array of pointers */
01433     ptrFileArray = cmd_alloc(sizeof(LPWIN32_FIND_DATA) * dwCount);
01434     if (ptrFileArray == NULL)
01435     {
01436         WARN("DEBUG: Cannot allocate memory for ptrFileArray!\n");
01437         while (ptrStartNode)
01438         {
01439             ptrNextNode = ptrStartNode->ptrNext;
01440             cmd_free(ptrStartNode);
01441             ptrStartNode = ptrNextNode;
01442             dwCount --;
01443         }
01444         return 1;
01445     }
01446 
01447     /*
01448      * Create an array of pointers from the linked list
01449      * this will be used to sort and print data, rather than the list
01450      */
01451     ptrNextNode = ptrStartNode;
01452     dwCount = 0;
01453     while (ptrNextNode->ptrNext)
01454     {
01455         *(ptrFileArray + dwCount) = &ptrNextNode->ptrNext->stFindInfo;
01456         ptrNextNode = ptrNextNode->ptrNext;
01457         dwCount++;
01458     }
01459 
01460     /* Sort Data if requested*/
01461     if (lpFlags->stOrderBy.sCriteriaCount > 0)
01462         QsortFiles(ptrFileArray, 0, dwCount-1, lpFlags);
01463 
01464     /* Print Data */
01465     pszFilePart[-1] = _T('\0'); /* truncate to directory name only */
01466     DirPrintFiles(ptrFileArray, dwCount, szFullPath, lpFlags);
01467     pszFilePart[-1] = _T('\\');
01468 
01469     if (lpFlags->bRecursive)
01470     {
01471         PrintSummary(szFullPath,
01472             dwCountFiles,
01473             dwCountDirs,
01474             u64CountBytes,
01475             lpFlags,
01476             FALSE);
01477     }
01478 
01479     /* Free array */
01480     cmd_free(ptrFileArray);
01481     /* Free linked list */
01482     while (ptrStartNode)
01483     {
01484         ptrNextNode = ptrStartNode->ptrNext;
01485         cmd_free(ptrStartNode);
01486         ptrStartNode = ptrNextNode;
01487         dwCount --;
01488     }
01489 
01490     if (CheckCtrlBreak(BREAK_INPUT))
01491         return 1;
01492 
01493 
01494     /* Add statistics to recursive statistics*/
01495     recurse_dir_cnt += dwCountDirs;
01496     recurse_file_cnt += dwCountFiles;
01497     recurse_bytes += u64CountBytes;
01498 
01499     /* Do the recursive job if requested
01500        the recursive is be done on ALL(indepent of their attribs)
01501        directoried of the current one.*/
01502     if (lpFlags->bRecursive)
01503     {
01504         /* The new search is involving any *.* file */
01505         memcpy(szSubPath, szFullPath, (pszFilePart - szFullPath) * sizeof(TCHAR));
01506         _tcscpy(&szSubPath[pszFilePart - szFullPath], _T("*.*"));
01507 
01508         hRecSearch = FindFirstFile (szSubPath, &wfdFileInfo);
01509         if (hRecSearch != INVALID_HANDLE_VALUE)
01510         {
01511             do
01512             {
01513                 /* We search for directories other than "." and ".." */
01514                 if ((_tcsicmp(wfdFileInfo.cFileName, _T(".")) != 0) &&
01515                     (_tcsicmp(wfdFileInfo.cFileName, _T("..")) != 0 ) &&
01516                     (wfdFileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
01517                 {
01518                     /* Concat the path and the directory to do recursive */
01519                     memcpy(szSubPath, szFullPath, (pszFilePart - szFullPath) * sizeof(TCHAR));
01520                     _tcscpy(&szSubPath[pszFilePart - szFullPath], wfdFileInfo.cFileName);
01521                     _tcscat(szSubPath, _T("\\"));
01522                     _tcscat(szSubPath, pszFilePart);
01523 
01524                     /* We do the same for the folder */
01525                     if (DirList(szSubPath, lpFlags) != 0)
01526                     {
01527                         FindClose(hRecSearch);
01528                         return 1;
01529                     }
01530                 }
01531             } while(FindNextFile(hRecSearch, &wfdFileInfo));
01532         }
01533         FindClose(hRecSearch);
01534     }
01535 
01536     return 0;
01537 }
01538 
01539 
01540 
01541 /*
01542  * dir
01543  *
01544  * internal dir command
01545  */
01546 INT
01547 CommandDir(LPTSTR rest)
01548 {
01549     TCHAR   dircmd[256];    /* A variable to store the DIRCMD enviroment variable */
01550     TCHAR   path[MAX_PATH];
01551     TCHAR   prev_volume[MAX_PATH];
01552     LPTSTR* params = NULL;
01553     LPTSTR  pszFilePart;
01554     INT     entries = 0;
01555     UINT    loop = 0;
01556     DIRSWITCHFLAGS stFlags;
01557     INT ret = 1;
01558     BOOL ChangedVolume;
01559 
01560     /* Initialize Switch Flags < Default switches are setted here!> */
01561     stFlags.b4Digit = TRUE;
01562     stFlags.bBareFormat = FALSE;
01563     stFlags.bLowerCase = FALSE;
01564     stFlags.bNewLongList = TRUE;
01565     stFlags.bPause = FALSE;
01566     stFlags.bRecursive = FALSE;
01567     stFlags.bShortName = FALSE;
01568     stFlags.bTSeperator = TRUE;
01569     stFlags.bUser = FALSE;
01570     stFlags.bWideList = FALSE;
01571     stFlags.bWideListColSort = FALSE;
01572     stFlags.stTimeField.eTimeField = TF_MODIFIEDDATE;
01573     stFlags.stAttribs.dwAttribMask = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
01574     stFlags.stAttribs.dwAttribVal = 0L;
01575     stFlags.stOrderBy.sCriteriaCount = 0;
01576 
01577     nErrorLevel = 0;
01578 
01579     /* read the parameters from the DIRCMD environment variable */
01580     if (GetEnvironmentVariable (_T("DIRCMD"), dircmd, 256))
01581         if (!DirReadParam(dircmd, &params, &entries, &stFlags))
01582         {
01583             nErrorLevel = 1;
01584             goto cleanup;
01585         }
01586 
01587     /* read the parameters */
01588     if (!DirReadParam(rest, &params, &entries, &stFlags) || CheckCtrlBreak(BREAK_INPUT))
01589     {
01590         nErrorLevel = 1;
01591         goto cleanup;
01592     }
01593 
01594     /* default to current directory */
01595     if(entries == 0) {
01596         if(!add_entry(&entries, &params, _T("*"))) {
01597             nErrorLevel = 1;
01598             goto cleanup;
01599         }
01600     }
01601 
01602     prev_volume[0] = _T('\0');
01603 
01604     /* Reset paging state */
01605     if (stFlags.bPause)
01606         ConOutPrintfPaging(TRUE, _T(""));
01607 
01608     for(loop = 0; loop < (UINT)entries; loop++)
01609     {
01610         if (CheckCtrlBreak(BREAK_INPUT))
01611         {
01612             nErrorLevel = 1;
01613             goto cleanup;
01614         }
01615 
01616         recurse_dir_cnt = 0L;
01617         recurse_file_cnt = 0L;
01618         recurse_bytes = 0;
01619 
01620     /* <Debug :>
01621        Uncomment this to show the final state of switch flags*/
01622     {
01623         int i;
01624         TRACE("Attributes mask/value %x/%x\n",stFlags.stAttribs.dwAttribMask,stFlags.stAttribs.dwAttribVal  );
01625         TRACE("(B) Bare format : %i\n", stFlags.bBareFormat );
01626         TRACE("(C) Thousand : %i\n", stFlags.bTSeperator );
01627         TRACE("(W) Wide list : %i\n", stFlags.bWideList );
01628         TRACE("(D) Wide list sort by column : %i\n", stFlags.bWideListColSort );
01629         TRACE("(L) Lowercase : %i\n", stFlags.bLowerCase );
01630         TRACE("(N) New : %i\n", stFlags.bNewLongList );
01631         TRACE("(O) Order : %i\n", stFlags.stOrderBy.sCriteriaCount );
01632         for (i =0;i<stFlags.stOrderBy.sCriteriaCount;i++)
01633             TRACE(" Order Criteria [%i]: %i (Reversed: %i)\n",i, stFlags.stOrderBy.eCriteria[i], stFlags.stOrderBy.bCriteriaRev[i] );
01634         TRACE("(P) Pause : %i\n", stFlags.bPause  );
01635         TRACE("(Q) Owner : %i\n", stFlags.bUser );
01636         TRACE("(S) Recursive : %i\n", stFlags.bRecursive );
01637         TRACE("(T) Time field : %i\n", stFlags.stTimeField.eTimeField );
01638         TRACE("(X) Short names : %i\n", stFlags.bShortName );
01639         TRACE("Parameter : %s\n", debugstr_aw(params[loop]) );
01640     }
01641 
01642         /* Print the drive header if the volume changed */
01643         ChangedVolume = TRUE;
01644 
01645         if (!stFlags.bBareFormat &&
01646             GetVolumePathName(params[loop], path, sizeof(path) / sizeof(TCHAR)))
01647         {
01648             if (!_tcscmp(path, prev_volume))
01649                 ChangedVolume = FALSE;
01650             else
01651                 _tcscpy(prev_volume, path);
01652         }
01653         else if (GetFullPathName(params[loop], sizeof(path) / sizeof(TCHAR), path, &pszFilePart) != 0)
01654         {
01655             if (pszFilePart != NULL)
01656                 *pszFilePart = _T('\0');
01657         }
01658         else
01659             _tcscpy(path, params[loop]);
01660 
01661         if (ChangedVolume && !stFlags.bBareFormat) {
01662             if (!PrintDirectoryHeader (params[loop], &stFlags)) {
01663                 nErrorLevel = 1;
01664                 goto cleanup;
01665             }
01666         }
01667 
01668         /* do the actual dir */
01669         if (DirList (params[loop], &stFlags))
01670         {
01671             nErrorLevel = 1;
01672             goto cleanup;
01673         }
01674 
01675         /* print the footer */
01676         PrintSummary(path,
01677             recurse_file_cnt,
01678             recurse_dir_cnt,
01679             recurse_bytes,
01680             &stFlags,
01681             TRUE);
01682     }
01683 
01684     ret = 0;
01685 
01686 cleanup:
01687     freep(params);
01688 
01689     return ret;
01690 }
01691 
01692 #endif
01693 
01694 /* EOF */

Generated on Sat May 26 2012 04:17:02 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.