Leaked source code of windows server 2003
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.

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