Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygendir.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, ¶ms, &entries, &stFlags)) 01582 { 01583 nErrorLevel = 1; 01584 goto cleanup; 01585 } 01586 01587 /* read the parameters */ 01588 if (!DirReadParam(rest, ¶ms, &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, ¶ms, _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
1.7.6.1
|