Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1407 lines
33 KiB

  1. /*++
  2. Copyright (c) 1988-1999 Microsoft Corporation
  3. Module Name:
  4. display.c
  5. Abstract:
  6. Output routines for DIR
  7. --*/
  8. #include "cmd.h"
  9. extern TCHAR ThousandSeparator[];
  10. // Entry is displayed.
  11. // If not /b,
  12. // Cursor is left at end of entry on screen.
  13. // FileCnt, FileCntTotal, FileSiz, FileSizTotal are updated.
  14. // If /b,
  15. // Cursor is left at beginning of next line.
  16. // Cnt's and Siz's aren't updated.
  17. //
  18. // Create a manager for these totals
  19. //
  20. // New format:
  21. // 0123456789012345678901234567890123456789012345678901234567890123456789
  22. // 02/23/2001 05:12p 14,611 build.log
  23. // 02/23/2001 05:12p 14,611 ... build.log
  24. // 02/26/2001 04:58p 13 VERYLO~1 verylongfilename
  25. // 02/26/2001 04:58p 13 VERYLO~1 ... verylongfilename
  26. //
  27. // <date><space><space><time><space><space><18-char-size><space><15-char-short-name><space><22-char-ownername><space><longfilename>
  28. // Old format:
  29. // build log 14,611 02/23/2001 05:12p
  30. // <8.3-name><space><18-char-size><space><date><space><space><time>
  31. //
  32. // Since the size of dates and times is *VARIABLE*, we presize these on each DIR call
  33. //
  34. ULONG WidthOfTimeDate = 19;
  35. ULONG WidthOfFileSize = 17;
  36. ULONG WidthOfShortName = 12;
  37. ULONG WidthOfOwnerName = 22;
  38. #define SPACES_AFTER_SIZE 1
  39. #define SPACES_AFTERDATETIME 1
  40. #define DIR_NEW_PAST_DATETIME (WidthOfTimeDate + SPACES_AFTERDATETIME)
  41. #define DIR_NEW_PAST_DATETIME_SPECIAL (WidthOfTimeDate + SPACES_AFTERDATETIME + 3)
  42. #define DIR_NEW_PAST_SIZE (WidthOfTimeDate + SPACES_AFTERDATETIME + WidthOfFileSize + SPACES_AFTER_SIZE)
  43. #define DIR_NEW_PAST_OWNER (WidthOfTimeDate + SPACES_AFTERDATETIME + WidthOfFileSize + SPACES_AFTER_SIZE + WidthOfOwnerName + 1)
  44. #define DIR_NEW_PAST_SHORTNAME (WidthOfTimeDate + SPACES_AFTERDATETIME + WidthOfFileSize + SPACES_AFTER_SIZE + WidthOfShortName + 1)
  45. #define DIR_NEW_PAST_SHORTNAME_OWNER (WidthOfTimeDate + SPACES_AFTERDATETIME + WidthOfFileSize + SPACES_AFTER_SIZE + WidthOfShortName + 1 + WidthOfOwnerName + 1)
  46. #define DIR_OLD_PAST_SHORTNAME (WidthOfShortName + 2)
  47. #define DIR_OLD_PAST_SIZE (WidthOfShortName + 2 + WidthOfFileSize + SPACES_AFTER_SIZE)
  48. extern TCHAR Fmt09[], Fmt26[] ;
  49. extern BOOL CtrlCSeen;
  50. extern ULONG YearWidth;
  51. BOOLEAN GetDrive( PTCHAR , PTCHAR );
  52. VOID SortFileList( PFS, PSORTDESC, ULONG);
  53. STATUS
  54. NewDisplayFileListHeader(
  55. IN PFS FileSpec,
  56. IN PSCREEN pscr,
  57. IN PVOID Data
  58. )
  59. /*++
  60. Routine Description:
  61. Display the header for a complete file list. This will include
  62. the current directory.
  63. Arguments:
  64. FileSpec - PFS for directory being enumerated
  65. pscr - screen handle
  66. data - PVOID to pdpr
  67. Return Value:
  68. SUCCESS if everything was correctly displayed
  69. --*/
  70. {
  71. PDRP pdrp = (PDRP) Data;
  72. pdrp->rgfSwitches &= ~HEADERDISPLAYED;
  73. //
  74. // We suppress the header:
  75. //
  76. // For bare format
  77. // Recursing (we display the header after we've actually found something)
  78. //
  79. if ((pdrp->rgfSwitches & (BAREFORMATSWITCH | RECURSESWITCH)) != 0) {
  80. return( SUCCESS );
  81. }
  82. CHECKSTATUS ( WriteEol( pscr ));
  83. return( WriteMsgString(pscr, MSG_DIR_OF, ONEARG, FileSpec->pszDir) );
  84. }
  85. STATUS
  86. NewDisplayFile(
  87. IN PFS FileSpec,
  88. IN PFF CurrentFF,
  89. IN PSCREEN pscr,
  90. IN PVOID Data
  91. )
  92. /*++
  93. Routine Description:
  94. Displays a single file in 1 of several formats.
  95. Arguments:
  96. FileSpec - PFS of directory being enumerated
  97. CurrentFF - PFF to current file
  98. pscr - screen handle for output
  99. Data - PVOID to pdpr with switches
  100. Return Value:
  101. return SUCCESS
  102. FAILURE
  103. --*/
  104. {
  105. PDRP pdrp = (PDRP) Data;
  106. STATUS rc = SUCCESS;
  107. PWIN32_FIND_DATA pdata;
  108. LARGE_INTEGER cbFile;
  109. pdata = &(CurrentFF->data);
  110. cbFile.LowPart = pdata->nFileSizeLow;
  111. cbFile.HighPart = pdata->nFileSizeHigh;
  112. FileSpec->cbFileTotal.QuadPart += cbFile.QuadPart;
  113. //
  114. // If we're in a recursive display, there might not be a header
  115. // displayed. Check the state and print out one if needed.
  116. //
  117. if ((pdrp->rgfSwitches & RECURSESWITCH) != 0) {
  118. if ((pdrp->rgfSwitches & HEADERDISPLAYED) == 0) {
  119. pdrp->rgfSwitches &= ~RECURSESWITCH;
  120. rc = NewDisplayFileListHeader( FileSpec, pscr, Data );
  121. pdrp->rgfSwitches |= RECURSESWITCH;
  122. if (rc != SUCCESS) {
  123. return rc;
  124. }
  125. pdrp->rgfSwitches |= HEADERDISPLAYED;
  126. }
  127. }
  128. if ((pdrp->rgfSwitches & BAREFORMATSWITCH) != 0) {
  129. rc = DisplayBare( pscr, pdrp->rgfSwitches, FileSpec->pszDir, pdata);
  130. } else if ((pdrp->rgfSwitches & WIDEFORMATSWITCH) != 0) {
  131. rc = DisplayWide( pscr, pdrp->rgfSwitches, pdata );
  132. } else if ((pdrp->rgfSwitches & (NEWFORMATSWITCH | SHORTFORMATSWITCH)) != 0) {
  133. rc = DisplayNewRest(pscr, pdrp->dwTimeType, pdrp->rgfSwitches, pdata);
  134. if (rc == SUCCESS) {
  135. if ((pdrp->rgfSwitches & SHORTFORMATSWITCH) != 0) {
  136. if (CurrentFF->obAlternate != 0) {
  137. FillToCol( pscr, DIR_NEW_PAST_SIZE );
  138. rc = DisplayDotForm( pscr,
  139. pdrp->rgfSwitches,
  140. &(pdata->cFileName[CurrentFF->obAlternate]),
  141. pdata
  142. );
  143. }
  144. FillToCol( pscr, DIR_NEW_PAST_SHORTNAME );
  145. } else {
  146. FillToCol( pscr, DIR_NEW_PAST_SIZE );
  147. }
  148. #ifndef WIN95_CMD
  149. if ((pdrp->rgfSwitches & DISPLAYOWNER) != 0) {
  150. TCHAR FullPath[MAX_PATH];
  151. BYTE SecurityDescriptor[ 65536 ];
  152. TCHAR Name[MAX_PATH];
  153. ULONG NameSize = sizeof( Name );
  154. TCHAR Domain[MAX_PATH];
  155. ULONG DomainSize = sizeof( Name );
  156. DWORD dwNeeded;
  157. PSID SID = NULL;
  158. BOOL OwnerDefaulted;
  159. SID_NAME_USE snu;
  160. if (AppendPath( FullPath, MAX_PATH, FileSpec->pszDir, pdata->cFileName ) != SUCCESS) {
  161. WriteString( pscr, TEXT( "..." ));
  162. } else if (!GetFileSecurity( FullPath,
  163. OWNER_SECURITY_INFORMATION,
  164. SecurityDescriptor,
  165. sizeof( SecurityDescriptor ),
  166. &dwNeeded )) {
  167. WriteString( pscr, TEXT( "..." ));
  168. } else if (!GetSecurityDescriptorOwner( SecurityDescriptor,
  169. &SID,
  170. &OwnerDefaulted)) {
  171. WriteString( pscr, TEXT( "..." ));
  172. } else if (!LookupAccountSid( NULL,
  173. SID,
  174. Name,
  175. &NameSize,
  176. Domain,
  177. &DomainSize,
  178. &snu)) {
  179. WriteString( pscr, TEXT( "..." ));
  180. SID = FreeSid( SID );
  181. } else {
  182. WriteString( pscr, Domain );
  183. WriteString( pscr, TEXT( "\\" ));
  184. WriteString( pscr, Name );
  185. SID = FreeSid( SID );
  186. }
  187. FillToCol( pscr,
  188. (pdrp->rgfSwitches & SHORTFORMATSWITCH) != 0
  189. ? DIR_NEW_PAST_SHORTNAME_OWNER
  190. : DIR_NEW_PAST_OWNER );
  191. }
  192. #endif
  193. rc = DisplayDotForm( pscr, pdrp->rgfSwitches, pdata->cFileName, pdata );
  194. }
  195. CHECKSTATUS( WriteFlushAndEol( pscr ) );
  196. } else {
  197. rc = DisplaySpacedForm( pscr,
  198. pdrp->rgfSwitches,
  199. CurrentFF->obAlternate ?
  200. &(pdata->cFileName[CurrentFF->obAlternate]) :
  201. pdata->cFileName,
  202. pdata
  203. );
  204. if (rc == SUCCESS) {
  205. FillToCol( pscr, DIR_OLD_PAST_SHORTNAME );
  206. rc = DisplayOldRest( pscr, pdrp->dwTimeType, pdrp->rgfSwitches, pdata );
  207. }
  208. CHECKSTATUS( WriteFlushAndEol( pscr ) );
  209. }
  210. return( rc );
  211. }
  212. STATUS
  213. NewDisplayFileList(
  214. IN PFS FileSpec,
  215. IN PSCREEN pscr,
  216. IN PVOID Data
  217. )
  218. /*++
  219. Routine Description:
  220. Displays a list of files and directories in the specified format. The files
  221. have been buffered in the PFS structure.
  222. Arguments:
  223. FileSpec - PFS containing set of files to display
  224. pscr - PSCREEN for display
  225. Data - PVOID pointer to DRP
  226. Return Value:
  227. return SUCCESS
  228. FAILURE
  229. --*/
  230. {
  231. ULONG irgpff;
  232. ULONG cffColMax;
  233. ULONG crowMax;
  234. ULONG crow, cffCol;
  235. STATUS rc = SUCCESS;
  236. PDRP pdrp = (PDRP) Data;
  237. BOOL PrintedEarly = (pdrp->rgfSwitches & (WIDEFORMATSWITCH | SORTSWITCH)) == 0;
  238. ULONG cff = FileSpec->cff;
  239. LARGE_INTEGER cbFile;
  240. pdrp->FileCount += FileSpec->FileCount;
  241. pdrp->DirectoryCount += FileSpec->DirectoryCount;
  242. pdrp->TotalBytes.QuadPart += FileSpec->cbFileTotal.QuadPart;
  243. if (!PrintedEarly && cff != 0) {
  244. //
  245. // Sort the data if needed
  246. //
  247. if ((pdrp->rgfSwitches & SORTSWITCH) != 0) {
  248. SortFileList( FileSpec, pdrp->rgsrtdsc, pdrp->dwTimeType );
  249. }
  250. //
  251. // Compute the tab spacing on the line from the size of the file names.
  252. // add 3 spaces to seperate each field
  253. //
  254. // If multiple files per line then base tabs on the max file/dir size
  255. //
  256. if ((pdrp->rgfSwitches & WIDEFORMATSWITCH) != 0) {
  257. SetTab( pscr, (USHORT)(GetMaxCbFileSize( FileSpec ) + 3) );
  258. } else {
  259. SetTab( pscr, 0 );
  260. }
  261. DEBUG((ICGRP, DISLVL, "\t count of files %d",cff));
  262. if ((pdrp->rgfSwitches & SORTDOWNFORMATSWITCH) != 0) {
  263. //
  264. // no. of files on a line.
  265. //
  266. cffColMax = (pscr->ccolMax / pscr->ccolTab);
  267. //
  268. // number of row required for entire list
  269. //
  270. if (cffColMax == 0) // wider than a line
  271. goto abort_wide; // abort wide format for this list
  272. else
  273. crowMax = (cff + cffColMax) / cffColMax;
  274. //
  275. // move down each rown picking the elements cffCols aport down the list.
  276. //
  277. for (crow = 0; crow < crowMax; crow++) {
  278. for (cffCol = 0, irgpff = crow;
  279. cffCol < cffColMax;
  280. cffCol++, irgpff += crowMax) {
  281. if (CtrlCSeen) {
  282. return FAILURE;
  283. }
  284. if (irgpff < cff) {
  285. cbFile.LowPart = FileSpec->prgpff[irgpff]->data.nFileSizeLow;
  286. cbFile.HighPart = FileSpec->prgpff[irgpff]->data.nFileSizeHigh;
  287. pdrp->TotalBytes.QuadPart += cbFile.QuadPart;
  288. rc = NewDisplayFile( FileSpec,
  289. FileSpec->prgpff[irgpff],
  290. pscr,
  291. Data );
  292. if (rc != SUCCESS) {
  293. return rc;
  294. }
  295. } else {
  296. //
  297. // If we have run past the end of the file list terminate
  298. // line and start over back inside the line
  299. //
  300. CHECKSTATUS( WriteEol(pscr) );
  301. break;
  302. }
  303. }
  304. }
  305. } else if (!PrintedEarly) {
  306. abort_wide:
  307. if (CtrlCSeen) {
  308. return FAILURE;
  309. }
  310. for (irgpff = 0; irgpff < cff; irgpff++) {
  311. if (CtrlCSeen) {
  312. return FAILURE;
  313. }
  314. cbFile.LowPart = FileSpec->prgpff[irgpff]->data.nFileSizeLow;
  315. cbFile.HighPart = FileSpec->prgpff[irgpff]->data.nFileSizeHigh;
  316. pdrp->TotalBytes.QuadPart += cbFile.QuadPart;
  317. rc = NewDisplayFile( FileSpec,
  318. FileSpec->prgpff[irgpff],
  319. pscr,
  320. Data );
  321. if (rc != SUCCESS) {
  322. return rc;
  323. }
  324. }
  325. }
  326. //
  327. // Before writing the tailer make sure buffer is
  328. // empty. (Could have something from doing WIDEFORMATSWITCH
  329. //
  330. CHECKSTATUS( WriteFlushAndEol( pscr ) );
  331. }
  332. if ((pdrp->rgfSwitches & BAREFORMATSWITCH) == 0) {
  333. if (FileSpec->FileCount + FileSpec->DirectoryCount != 0) {
  334. CHECKSTATUS( DisplayFileSizes( pscr, &FileSpec->cbFileTotal, FileSpec->FileCount, pdrp->rgfSwitches ));
  335. }
  336. }
  337. return SUCCESS;
  338. }
  339. STATUS
  340. DisplayBare (
  341. IN PSCREEN pscr,
  342. IN ULONG rgfSwitches,
  343. IN PTCHAR pszDir,
  344. IN PWIN32_FIND_DATA pdata
  345. )
  346. /*++
  347. Routine Description:
  348. Displays a single file in bare format. This is with no header, tail and
  349. no file information other then it's name. If it is a recursive catalog
  350. then the full file path is displayed. This mode is used to feed other
  351. utitilies such as grep.
  352. Arguments:
  353. pscr - screen handle
  354. rgfSwitches - command line switch (controls formating)
  355. pszDir - current directory (used for full path information)
  356. pdata - data gotten back from FindNext API
  357. Return Value:
  358. return SUCCESS
  359. FAILURE
  360. --*/
  361. {
  362. TCHAR szDirString[MAX_PATH + 2];
  363. STATUS rc;
  364. DEBUG((ICGRP, DISLVL, "DisplayBare `%ws'", pdata->cFileName));
  365. //
  366. // Do not display '.' and '..' in a bare listing
  367. //
  368. if ((_tcscmp(pdata->cFileName, TEXT(".")) == 0) || (_tcscmp(pdata->cFileName, TEXT("..")) == 0)) {
  369. return( SUCCESS );
  370. }
  371. //
  372. // If we are recursing down then display full name else just the
  373. // name in the find buffer
  374. //
  375. if (rgfSwitches & RECURSESWITCH) {
  376. mystrcpy(szDirString, pszDir);
  377. if (rgfSwitches & LOWERCASEFORMATSWITCH) {
  378. _tcslwr(szDirString);
  379. }
  380. CHECKSTATUS( WriteString(pscr, szDirString) );
  381. if (*lastc(szDirString) != BSLASH) {
  382. CHECKSTATUS( WriteString(pscr, TEXT("\\")));
  383. }
  384. }
  385. if ((rc = DisplayDotForm(pscr, rgfSwitches, pdata->cFileName, pdata)) == SUCCESS) {
  386. return( WriteEol(pscr));
  387. } else {
  388. return( rc );
  389. }
  390. }
  391. VOID
  392. SetDotForm (
  393. IN PTCHAR pszFileName,
  394. IN ULONG rgfSwitches
  395. )
  396. /*++
  397. Routine Description:
  398. If FATFORMAT and there is a '.' with a blank extension, the '.' is
  399. removed so it does not get displayed. This is by convension and is very
  400. strange but that's life. Also a lower case mapping is done.
  401. Arguments:
  402. pszFileName - file to remove '.' from.
  403. rgfSwitches - command line switches (tell wither in FATFORMAT or not)
  404. Return Value:
  405. return SUCCESS
  406. FAILURE
  407. --*/
  408. {
  409. PTCHAR pszT;
  410. if (rgfSwitches & FATFORMAT) {
  411. //
  412. // Under DOS if there is a . with a blank extension
  413. // then do not display '.'.
  414. //
  415. if (pszT = mystrrchr(pszFileName, DOT)) {
  416. //
  417. // FAT will not allow foo. ba as a valid name so
  418. // see of any blanks in extensions and if so then assume
  419. // the entire extension is blank
  420. //
  421. if (mystrchr(pszT, SPACE)) {
  422. *pszT = NULLC;
  423. }
  424. }
  425. }
  426. }
  427. STATUS
  428. DisplayDotForm (
  429. IN PSCREEN pscr,
  430. IN ULONG rgfSwitches,
  431. IN PTCHAR pszFileName,
  432. IN PWIN32_FIND_DATA pdata
  433. )
  434. /*++
  435. Routine Description:
  436. Displays a single file in DOT form (see SetDotForm).
  437. Arguments:
  438. pscr - screen handle
  439. rgfSwitches - command line switch (tell wither to lowercase or not)
  440. pdata - data gotten back from FindNext API
  441. Return Value:
  442. return SUCCESS
  443. FAILURE
  444. --*/
  445. {
  446. TCHAR szFileName[MAX_PATH + 2];
  447. mystrcpy(szFileName, pszFileName);
  448. SetDotForm(szFileName, rgfSwitches);
  449. if (rgfSwitches & LOWERCASEFORMATSWITCH) {
  450. _tcslwr(szFileName);
  451. }
  452. if (WriteString( pscr, szFileName ) )
  453. return FAILURE;
  454. return SUCCESS;
  455. }
  456. STATUS
  457. DisplaySpacedForm(
  458. IN PSCREEN pscr,
  459. IN ULONG rgfSwitches,
  460. IN PTCHAR pszName,
  461. IN PWIN32_FIND_DATA pdata
  462. )
  463. /*++
  464. Routine Description:
  465. Display name in expanded format. name <spaces> ext.
  466. This is ONLY called for a FAT partition. This is controled by the
  467. NEWFORMATSWITCH. This is set for any file system other then FAT. There
  468. is no OLDFORMATSWITCH so we can never be called on an HPFS or NTFS
  469. volume. If this is changed then the entire spacing of the display will
  470. be blown due to non-fixed max file names. (i.e. 8.3).
  471. Arguments:
  472. pscr - screen handle
  473. rgfSwitches - command line switch (tell wither to lowercase or not)
  474. pszname - name string to use (short name format only)
  475. pdata - data gotten back from FindNext API
  476. Return Value:
  477. return SUCCESS
  478. FAILURE
  479. --*/
  480. {
  481. TCHAR szFileName[MAX_PATH + 2];
  482. PTCHAR pszExt;
  483. USHORT cbName;
  484. STATUS rc;
  485. #ifdef FE_SB
  486. int i;
  487. int l;
  488. #endif
  489. mytcsnset(szFileName, SPACE, MAX_PATH + 2);
  490. cbName = 0;
  491. if ((_tcscmp(pszName, TEXT(".")) == 0) || (_tcscmp(pszName, TEXT("..")) == 0)) {
  492. //
  493. // If it is either of these then do not get it
  494. // confused with extensions
  495. //
  496. pszExt = NULL;
  497. } else {
  498. pszExt = mystrrchr(pszName, (int)DOT);
  499. cbName = (USHORT)(pszExt - pszName)*sizeof(WCHAR);
  500. }
  501. //
  502. // if no extension or name is extension only
  503. //
  504. if ((pszExt == NULL) || (cbName == 0)) {
  505. cbName = (USHORT)_tcslen(pszName)*sizeof(TCHAR);
  506. }
  507. memcpy(szFileName, pszName, cbName );
  508. #if defined(FE_SB)
  509. //
  510. // If we had an extension then print it after
  511. // all the spaces
  512. //
  513. i = 9;
  514. if (IsDBCSCodePage())
  515. {
  516. for (l=0 ; l<8 ; l++) {
  517. if (IsFullWidth(szFileName[l]))
  518. i--;
  519. }
  520. }
  521. if (pszExt) {
  522. mystrcpy(szFileName + i, pszExt + 1);
  523. }
  524. //
  525. // terminate at max end for a FAT name
  526. //
  527. szFileName[i+3] = NULLC;
  528. if (pszExt &&
  529. IsDBCSCodePage()) {
  530. //
  531. // Only 1 of three can be full width, since 3/2=1.
  532. // If the first isn't, only the second could be.
  533. //
  534. if (IsFullWidth(*(pszExt+1)) || IsFullWidth(*(pszExt+2)))
  535. szFileName[i+2] = NULLC;
  536. }
  537. #else
  538. if (pszExt) {
  539. //
  540. // move pszExt past dot. use 9 not 8 to pass
  541. // over 1 space between name and extension
  542. //
  543. mystrcpy(szFileName + 9, pszExt + 1);
  544. }
  545. //
  546. // terminate at max end for a FAT name
  547. //
  548. szFileName[12] = NULLC;
  549. #endif
  550. if (rgfSwitches & LOWERCASEFORMATSWITCH) {
  551. _tcslwr(szFileName);
  552. }
  553. rc = WriteString( pscr, szFileName );
  554. return rc;
  555. }
  556. STATUS
  557. DisplayOldRest(
  558. IN PSCREEN pscr,
  559. IN ULONG dwTimeType,
  560. IN ULONG rgfSwitches,
  561. IN PWIN32_FIND_DATA pdata
  562. )
  563. /*++
  564. Routine Description:
  565. Used with DisplaySpacedForm to write out file information such as size
  566. and last write time.
  567. Arguments:
  568. pscr - screen handle
  569. pdata - data gotten back from FindNext API
  570. Return Value:
  571. return SUCCESS
  572. FAILURE
  573. --*/
  574. {
  575. TCHAR szSize [ MAX_PATH ];
  576. DWORD Length;
  577. LARGE_INTEGER FileSize;
  578. //
  579. // If directory put <DIR> after name instead of file size
  580. //
  581. if (pdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  582. CHECKSTATUS( WriteMsgString(pscr, MSG_DIR,0) );
  583. } else {
  584. FileSize.LowPart = pdata->nFileSizeLow;
  585. FileSize.HighPart = pdata->nFileSizeHigh;
  586. Length = FormatFileSize( rgfSwitches, &FileSize, 0, szSize );
  587. FillToCol(pscr, DIR_OLD_PAST_SIZE - SPACES_AFTER_SIZE - Length);
  588. WriteFmtString(pscr, TEXT( "%s" ), (PVOID)szSize);
  589. }
  590. FillToCol(pscr, DIR_OLD_PAST_SIZE);
  591. return( DisplayTimeDate( pscr, dwTimeType, rgfSwitches, pdata) );
  592. }
  593. STATUS
  594. DisplayTimeDate (
  595. IN PSCREEN pscr,
  596. IN ULONG dwTimeType,
  597. IN ULONG rgfSwitches,
  598. IN PWIN32_FIND_DATA pdata
  599. )
  600. /*++
  601. Routine Description:
  602. Display time/data information for a file
  603. Arguments:
  604. pscr - screen handle
  605. pdata - data gotten back from FindNext API
  606. Return Value:
  607. return SUCCESS
  608. FAILURE
  609. --*/
  610. {
  611. struct tm FileTime;
  612. TCHAR szT[ MAX_PATH + 1];
  613. TCHAR szD[ MAX_PATH + 1];
  614. FILETIME ft;
  615. switch (dwTimeType) {
  616. case LAST_ACCESS_TIME:
  617. ft = pdata->ftLastAccessTime;
  618. break;
  619. case LAST_WRITE_TIME:
  620. ft = pdata->ftLastWriteTime;
  621. break;
  622. case CREATE_TIME:
  623. ft = pdata->ftCreationTime;
  624. break;
  625. }
  626. ConvertFILETIMETotm( &ft, &FileTime );
  627. //
  628. // Display four digit year iff the year width is specified
  629. // in the locale or if it was requested on the command line
  630. //
  631. PrintDate( &FileTime,
  632. (YearWidth == 4 || (rgfSwitches & YEAR2000) != 0)
  633. ? PD_DIR2000
  634. : PD_DIR,
  635. szD, MAX_PATH );
  636. CHECKSTATUS( WriteFmtString( pscr, TEXT("%s "), szD ));
  637. PrintTime( &FileTime, PT_DIR, szT, MAX_PATH ) ;
  638. CHECKSTATUS( WriteFmtString(pscr, TEXT("%s"), szT) );
  639. WidthOfTimeDate = SizeOfHalfWidthString( szD ) + 2 + SizeOfHalfWidthString( szT );
  640. return( SUCCESS );
  641. }
  642. STATUS
  643. DisplayNewRest(
  644. IN PSCREEN pscr,
  645. IN ULONG dwTimeType,
  646. IN ULONG rgfSwitches,
  647. IN PWIN32_FIND_DATA pdata
  648. )
  649. /*++
  650. Routine Description:
  651. Display file information for new format (comes before file name).
  652. This is used with NEWFORMATSWITCH which is active on any non-FAT
  653. partition.
  654. Arguments:
  655. pscr - screen handle
  656. pdata - data gotten back from FindNext API
  657. Return Value:
  658. return SUCCESS
  659. FAILURE
  660. --*/
  661. {
  662. STATUS rc;
  663. DWORD MsgNo;
  664. LARGE_INTEGER FileSize;
  665. rc = DisplayTimeDate( pscr, dwTimeType, rgfSwitches, pdata);
  666. if (rc == SUCCESS) {
  667. //
  668. // If reparse point, special formatting.
  669. //
  670. // If it's an NSS reparse tag, we want to end up in the
  671. // normal file path below.
  672. if ((pdata->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
  673. (pdata->dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) == 0 &&
  674. IsReparseTagNameSurrogate( pdata->dwReserved0 )) {
  675. FillToCol( pscr, DIR_NEW_PAST_DATETIME_SPECIAL );
  676. MsgNo = MSG_DIR_MOUNT_POINT;
  677. rc = WriteMsgString(pscr, MsgNo, 0);
  678. } else
  679. //
  680. // If directory put <DIR> after name instead of file size
  681. //
  682. if (pdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  683. FillToCol( pscr, DIR_NEW_PAST_DATETIME_SPECIAL );
  684. rc = WriteMsgString(pscr, MSG_DIR, 0);
  685. } else {
  686. TCHAR szSize [ MAX_PATH ];
  687. DWORD Length;
  688. FillToCol(pscr, DIR_NEW_PAST_DATETIME);
  689. FileSize.LowPart = pdata->nFileSizeLow;
  690. FileSize.HighPart = pdata->nFileSizeHigh;
  691. Length = FormatFileSize( rgfSwitches, &FileSize, 0, szSize );
  692. //
  693. // Show file sizes of high latency reparse points in parens to
  694. // tell user it will be slow to retreive.
  695. //
  696. if ((pdata->dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) != 0) {
  697. Length += 2;
  698. FillToCol(pscr, DIR_NEW_PAST_SIZE - SPACES_AFTER_SIZE - Length);
  699. rc = WriteFmtString(pscr, TEXT("(%s)"), (PVOID)szSize);
  700. } else {
  701. FillToCol(pscr, DIR_NEW_PAST_SIZE - SPACES_AFTER_SIZE - Length);
  702. rc = WriteFmtString(pscr, TEXT( "%s" ), (PVOID)szSize);
  703. }
  704. }
  705. }
  706. return( rc );
  707. }
  708. STATUS
  709. DisplayWide (
  710. IN PSCREEN pscr,
  711. IN ULONG rgfSwitches,
  712. IN PWIN32_FIND_DATA pdata
  713. )
  714. /*++
  715. Routine Description:
  716. Displays a single file used in the /w or /d Switches. That is with a
  717. multiple file column display.
  718. Arguments:
  719. pscr - screen handle
  720. rgfSwitches - command line Switches (controls formating)
  721. pdata - data gotten back from FindNext API
  722. Return Value:
  723. return SUCCESS
  724. FAILURE
  725. --*/
  726. {
  727. TCHAR szFileName[MAX_PATH + 2];
  728. PTCHAR pszFmt;
  729. STATUS rc;
  730. pszFmt = TEXT( "%s" ); // assume non-dir format
  731. //
  732. // Provides [] around directories
  733. //
  734. if (pdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  735. pszFmt = Fmt09;
  736. }
  737. mystrcpy(szFileName, pdata->cFileName);
  738. SetDotForm(szFileName, rgfSwitches);
  739. if (rgfSwitches & LOWERCASEFORMATSWITCH) {
  740. _tcslwr(szFileName);
  741. }
  742. rc = WriteFmtString(pscr, pszFmt, szFileName);
  743. if (rc == SUCCESS) {
  744. rc = WriteTab(pscr);
  745. }
  746. return( rc );
  747. }
  748. USHORT
  749. GetMaxCbFileSize(
  750. IN PFS pfsFiles
  751. )
  752. /*++
  753. Routine Description:
  754. Determines the longest string size in a file list. Used in computing
  755. the number of possible columns in a catalog listing.
  756. Arguments:
  757. pfsFiles - file list.
  758. Return Value:
  759. return # of characters in largest file name
  760. --*/
  761. {
  762. ULONG cff;
  763. ULONG irgff;
  764. USHORT cb;
  765. PFF pffCur;
  766. cb = 0;
  767. for(irgff = 0, cff = pfsFiles->cff, pffCur = pfsFiles->prgpff[irgff];
  768. irgff < cff;
  769. irgff++) {
  770. #if defined(FE_SB)
  771. if (IsDBCSCodePage())
  772. cb = max(cb, (USHORT)SizeOfHalfWidthString(((pfsFiles->prgpff[irgff])->data).cFileName));
  773. else
  774. cb = max(cb, (USHORT)mystrlen( ((pfsFiles->prgpff[irgff])->data).cFileName ));
  775. #else
  776. cb = max(cb, (USHORT)mystrlen( ((pfsFiles->prgpff[irgff])->data).cFileName ));
  777. #endif
  778. }
  779. return( cb );
  780. }
  781. STATUS
  782. DisplayFileSizes(
  783. IN PSCREEN pscr,
  784. IN PLARGE_INTEGER cbFileTotal,
  785. IN ULONG cffTotal,
  786. IN ULONG rgfSwitches
  787. )
  788. /*++
  789. Routine Description:
  790. Does tailer display of # of files displayed and # of bytes
  791. in all files displayed.
  792. Arguments:
  793. pscr - screen handle
  794. cbFileTotal - bytes in all files displayed
  795. cffTotal - number of files displayed.
  796. Return Value:
  797. return SUCCESS
  798. FAILURE
  799. --*/
  800. {
  801. TCHAR szSize [ MAX_PATH];
  802. FillToCol(pscr, 6);
  803. FormatFileSize( rgfSwitches, cbFileTotal, 14, szSize );
  804. return( WriteMsgString(pscr, MSG_FILES_COUNT_FREE, TWOARGS,
  805. (UINT_PTR)argstr1(TEXT("%5lu"), cffTotal ),
  806. szSize ) );
  807. }
  808. STATUS
  809. DisplayTotals(
  810. IN PSCREEN pscr,
  811. IN ULONG cffTotal,
  812. IN PLARGE_INTEGER cbFileTotal,
  813. IN ULONG rgfSwitches
  814. )
  815. /*++
  816. Routine Description:
  817. Does tailer display of # of files displayed and # of bytes
  818. in all files displayed.
  819. Arguments:
  820. pscr - screen handle
  821. cbFileTotal - bytes in all files displayed
  822. cffTotal - number of files displayed.
  823. Return Value:
  824. return SUCCESS
  825. FAILURE
  826. --*/
  827. {
  828. STATUS rc;
  829. if ((rc = WriteMsgString(pscr, MSG_FILE_TOTAL, 0) ) == SUCCESS ) {
  830. if ((rc = DisplayFileSizes( pscr, cbFileTotal, cffTotal, rgfSwitches )) == SUCCESS) {
  831. rc = WriteFlush(pscr) ;
  832. }
  833. }
  834. return ( rc );
  835. }
  836. STATUS
  837. DisplayDiskFreeSpace(
  838. IN PSCREEN pscr,
  839. IN PTCHAR pszDrive,
  840. IN ULONG rgfSwitches,
  841. IN ULONG DirectoryCount
  842. )
  843. /*++
  844. Routine Description:
  845. Displays total free space on volume.
  846. Arguments:
  847. pscr - screen handle
  848. pszDrive - volume drive letter
  849. Return Value:
  850. return SUCCESS
  851. FAILURE
  852. --*/
  853. {
  854. TCHAR szPath [ MAX_PATH + 2];
  855. ULARGE_INTEGER cbFree;
  856. CheckPause( pscr );
  857. #ifdef WIN95_CMD
  858. if (!GetDrive( pszDrive, szPath )) {
  859. return SUCCESS;
  860. }
  861. mystrcat( szPath, TEXT( "\\" ));
  862. #else
  863. mystrcpy( szPath, pszDrive );
  864. if (IsDrive( szPath )) {
  865. mystrcat( szPath, TEXT("\\") );
  866. }
  867. #endif
  868. cbFree.LowPart = cbFree.HighPart = 0;
  869. #ifdef WIN95_CMD
  870. {
  871. DWORD dwSectorsPerCluster;
  872. DWORD dwBytesPerSector;
  873. DWORD dwNumberOfFreeClusters;
  874. DWORD dwTotalNumberOfClusters;
  875. if (GetDiskFreeSpace( szPath,&dwSectorsPerCluster, &dwBytesPerSector,
  876. &dwNumberOfFreeClusters, &dwTotalNumberOfClusters)) {
  877. cbFree.QuadPart = UInt32x32To64(dwSectorsPerCluster, dwNumberOfFreeClusters);
  878. cbFree.QuadPart = cbFree.QuadPart * dwBytesPerSector;
  879. }
  880. }
  881. #else
  882. {
  883. ULARGE_INTEGER lpTotalNumberOfBytes;
  884. ULARGE_INTEGER lpTotalNumberOfFreeBytes;
  885. GetDiskFreeSpaceEx( szPath, &cbFree,
  886. &lpTotalNumberOfBytes,
  887. &lpTotalNumberOfFreeBytes);
  888. }
  889. #endif
  890. FillToCol(pscr, 6);
  891. FormatFileSize( rgfSwitches, (PLARGE_INTEGER) &cbFree, 14, szPath );
  892. return( WriteMsgString(pscr,
  893. MSG_FILES_TOTAL_FREE,
  894. TWOARGS,
  895. (UINT_PTR)argstr1(TEXT("%5lu"), DirectoryCount ),
  896. szPath ));
  897. }
  898. STATUS
  899. DisplayVolInfo(
  900. IN PSCREEN pscr,
  901. IN PTCHAR pszDrive
  902. )
  903. /*++
  904. Routine Description:
  905. Displays the volume trailer information. Used before switching to
  906. a catalog of another drive (dir a:* b:*)
  907. Arguments:
  908. pscr - screen handle
  909. pszDrive - volume drive letter
  910. Return Value:
  911. return SUCCESS
  912. FAILURE
  913. --*/
  914. {
  915. DWORD Vsn[2];
  916. TCHAR szVolName[MAX_PATH + 2];
  917. TCHAR szVolRoot[MAX_PATH + 2];
  918. TCHAR szT[256];
  919. STATUS rc = SUCCESS;
  920. if (!GetDrive(pszDrive, szVolRoot)) {
  921. return SUCCESS;
  922. }
  923. mystrcat(szVolRoot, TEXT("\\"));
  924. if (!GetVolumeInformation(szVolRoot,szVolName,MAX_PATH,Vsn,NULL,NULL,NULL,0)) {
  925. DEBUG((ICGRP, DISLVL, "DisplayVolInfo: GetVolumeInformation ret'd %d", GetLastError())) ;
  926. // don't fail if we're a substed drive
  927. if (GetLastError() == ERROR_DIR_NOT_ROOT) {
  928. return SUCCESS;
  929. }
  930. PutStdErr(GetLastError(), NOARGS);
  931. return( FAILURE ) ;
  932. } else {
  933. if (szVolRoot[0] == BSLASH) {
  934. *lastc(szVolRoot) = NULLC;
  935. } else {
  936. szVolRoot[1] = NULLC;
  937. }
  938. if (szVolName[0]) {
  939. rc = WriteMsgString(pscr,
  940. MSG_DR_VOL_LABEL,
  941. TWOARGS,
  942. szVolRoot,
  943. szVolName ) ;
  944. } else {
  945. rc = WriteMsgString(pscr,
  946. MSG_HAS_NO_LABEL,
  947. ONEARG,
  948. szVolRoot ) ;
  949. }
  950. if ((rc == SUCCESS) && (Vsn)) {
  951. _sntprintf(szT,256,Fmt26,(Vsn[0] & 0xffff0000)>>16, (Vsn[0] & 0xffff) );
  952. rc = WriteMsgString(pscr, MSG_DR_VOL_SERIAL, ONEARG, szT);
  953. }
  954. }
  955. return( rc );
  956. }
  957. ULONG
  958. FormatFileSize(
  959. IN DWORD rgfSwitches,
  960. IN PLARGE_INTEGER FileSize,
  961. IN DWORD Width,
  962. OUT PTCHAR FormattedSize
  963. )
  964. {
  965. TCHAR Buffer[ 100 ];
  966. PTCHAR s, s1;
  967. ULONG DigitIndex;
  968. ULONGLONG Digit;
  969. ULONG nThousandSeparator;
  970. ULONGLONG Size;
  971. nThousandSeparator = _tcslen(ThousandSeparator);
  972. s = &Buffer[ 99 ];
  973. *s = TEXT('\0');
  974. DigitIndex = 0;
  975. Size = FileSize->QuadPart;
  976. while (Size != 0) {
  977. Digit = (Size % 10);
  978. Size = Size / 10;
  979. *--s = (TCHAR)(TEXT('0') + Digit);
  980. if ((++DigitIndex % 3) == 0 && (rgfSwitches & THOUSANDSEPSWITCH)) {
  981. // If non-null Thousand separator, insert it.
  982. if (nThousandSeparator) {
  983. s -= nThousandSeparator;
  984. _tcsncpy(s, ThousandSeparator, nThousandSeparator);
  985. }
  986. }
  987. }
  988. if (DigitIndex == 0) {
  989. *--s = TEXT('0');
  990. }
  991. else
  992. if ((rgfSwitches & THOUSANDSEPSWITCH) && !_tcsncmp(s, ThousandSeparator, nThousandSeparator)) {
  993. s += nThousandSeparator;
  994. }
  995. Size = _tcslen( s );
  996. if (Width != 0 && Size < Width) {
  997. s1 = FormattedSize;
  998. while (Width > Size) {
  999. Width -= 1;
  1000. *s1++ = SPACE;
  1001. }
  1002. _tcscpy( s1, s );
  1003. } else {
  1004. _tcscpy( FormattedSize, s );
  1005. }
  1006. return _tcslen( FormattedSize );
  1007. }