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.

992 lines
25 KiB

  1. /*++
  2. Copyright (c) 1988-1999 Microsoft Corporation
  3. Module Name:
  4. ctools3.c
  5. Abstract:
  6. Low level utilities
  7. --*/
  8. #include "cmd.h"
  9. extern unsigned tywild; /* type is wild flag @@5@J1 */
  10. extern TCHAR CurDrvDir[], PathChar, Delimiters[] ;
  11. extern TCHAR VolSrch[] ; /* M009 */
  12. extern TCHAR BSlash ;
  13. extern unsigned DosErr ;
  14. /*** FullPath - build a full path name
  15. *
  16. * Purpose:
  17. * See below.
  18. *
  19. * int FullPath(TCHAR * buf, TCHAR *fname)
  20. *
  21. * Args:
  22. * buf - buffer to write full pathname into. (M017)
  23. * fname - a file name and/or partial path
  24. *
  25. * Returns: (M017)
  26. * FAILURE if malformed pathname (erroneous '.' or '..')
  27. * SUCCESS otherwise
  28. *
  29. * Notes:
  30. * - '.' and '..' are removed from the translated string (M017)
  31. * - VERY BIG GOTCHA! Note that the 509 change can cause
  32. * this rountine to modify the input filename (fname), because
  33. * it strips quotes and copies it over the input filename.
  34. *
  35. */
  36. int FullPath(
  37. TCHAR *buf,
  38. TCHAR *fname,
  39. ULONG sizpath
  40. )
  41. {
  42. unsigned rc = SUCCESS; /* prime with good rc */
  43. unsigned buflen; /* buffer length */
  44. TCHAR *filepart;
  45. DWORD rv;
  46. mystrcpy(fname, StripQuotes(fname) );
  47. if (*fname == NULLC) {
  48. GetDir(buf,GD_DEFAULT);
  49. buf += 2; /* Inc past drivespec */
  50. buflen = mystrlen(buf); /* Is curdir root only? */
  51. if (buflen >= MAX_PATH-3) { /* If too big then stop */
  52. DosErr = ERROR_PATH_NOT_FOUND;
  53. rc = FAILURE;
  54. } else if (buflen != 1) { /* if not root then append */
  55. *(buf+buflen++) = PathChar; /* ...a pathchar and... */
  56. *(buf+buflen) = NULLC ; /* ...a null byte... */
  57. } /* */
  58. } else {
  59. if ((mystrlen(fname) == 2) && (*(fname + 1) == COLON)) {
  60. GetDir(buf,*fname); /* Get curdrvdir */
  61. if ((buflen = mystrlen(buf)) > 3) {
  62. *(buf+buflen++) = PathChar; /* ...a pathchar and... */
  63. *(buf+buflen) = NULLC ; /* ...a null byte... */
  64. }
  65. } else {
  66. DWORD dwOldMode;
  67. dwOldMode = SetErrorMode(0);
  68. SetErrorMode(SEM_FAILCRITICALERRORS);
  69. rv = GetFullPathName( fname, sizpath, buf, &filepart );
  70. SetErrorMode(dwOldMode);
  71. if (!rv || rv > sizpath ) {
  72. DosErr = ERROR_FILENAME_EXCED_RANGE;
  73. rc = FAILURE;
  74. }
  75. }
  76. }
  77. return(rc);
  78. }
  79. /*** FileIsDevice - check a handle to see if it references a device
  80. *
  81. * Purpose:
  82. * Return a nonzero value if fh is the file handle for a device.
  83. * Otherwise, return 0.
  84. *
  85. * int FileIsDevice(int fh)
  86. *
  87. * Args:
  88. * fh - the file handle to check
  89. *
  90. * Returns:
  91. * See above.
  92. *
  93. */
  94. unsigned int flgwd;
  95. int FileIsDevice( CRTHANDLE fh )
  96. {
  97. HANDLE hFile;
  98. DWORD dwMode;
  99. unsigned htype ;
  100. hFile = CRTTONT(fh);
  101. htype = GetFileType( hFile );
  102. htype &= ~FILE_TYPE_REMOTE;
  103. if (htype == FILE_TYPE_CHAR) {
  104. //
  105. // Simulate old behavior of this routine of setting the flgwd
  106. // global variable with either 0, 1 or 2 to indicate if the
  107. // passed handle is NOT a CON handle or is a CON input handle or
  108. // is a CON output handle.
  109. //
  110. switch ( fh ) {
  111. case STDIN:
  112. hFile = GetStdHandle(STD_INPUT_HANDLE);
  113. break;
  114. case STDOUT:
  115. hFile = GetStdHandle(STD_OUTPUT_HANDLE);
  116. break;
  117. case STDERR:
  118. hFile = GetStdHandle(STD_ERROR_HANDLE);
  119. break;
  120. }
  121. if (GetConsoleMode(hFile,&dwMode)) {
  122. if (dwMode & (ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT)) {
  123. flgwd = 1;
  124. } else if (dwMode & (ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT)) {
  125. flgwd = 2;
  126. }
  127. } else {
  128. flgwd = 0;
  129. }
  130. return TRUE;
  131. } else {
  132. flgwd = 0;
  133. return FALSE;
  134. }
  135. }
  136. int FileIsPipe( CRTHANDLE fh )
  137. {
  138. unsigned htype ;
  139. htype = GetFileType( CRTTONT(fh) );
  140. htype &= ~FILE_TYPE_REMOTE;
  141. flgwd = 0;
  142. return( htype == FILE_TYPE_PIPE ) ; /* @@4 */
  143. }
  144. int FileIsRemote( LPTSTR FileName )
  145. {
  146. LPTSTR p;
  147. TCHAR Drive[MAX_PATH*2];
  148. DWORD Length;
  149. Length = GetFullPathName( FileName, sizeof(Drive)/sizeof(TCHAR), Drive, &p );
  150. if (Length != 0 && Length < MAX_PATH * 2) {
  151. Drive[3] = 0;
  152. if (GetDriveType( Drive ) == DRIVE_REMOTE) {
  153. return TRUE;
  154. }
  155. }
  156. return FALSE;
  157. }
  158. int FileIsConsole(CRTHANDLE fh)
  159. {
  160. unsigned htype ;
  161. DWORD dwMode;
  162. HANDLE hFile;
  163. hFile = CRTTONT(fh);
  164. if (hFile == INVALID_HANDLE_VALUE) {
  165. return FALSE;
  166. }
  167. htype = GetFileType( hFile );
  168. htype &= ~FILE_TYPE_REMOTE;
  169. if ( htype == FILE_TYPE_CHAR ) {
  170. switch ( fh ) {
  171. case STDIN:
  172. hFile = GetStdHandle(STD_INPUT_HANDLE);
  173. break;
  174. case STDOUT:
  175. hFile = GetStdHandle(STD_OUTPUT_HANDLE);
  176. break;
  177. case STDERR:
  178. hFile = GetStdHandle(STD_ERROR_HANDLE);
  179. break;
  180. }
  181. if (GetConsoleMode(hFile,&dwMode)) {
  182. return TRUE;
  183. }
  184. }
  185. return FALSE;
  186. }
  187. /*** GetDir - get a current directory string
  188. *
  189. * Purpose:
  190. * Get the current directory of the specified drive and put it in str.
  191. *
  192. * int GetDir(TCHAR *str, TCHAR dlet)
  193. *
  194. * Args:
  195. * str - place to store the directory string
  196. * dlet - the drive letter or 0 for the default drive
  197. *
  198. * Returns:
  199. * 0 or 1 depending on the value of the carry flag after the CURRENTDIR
  200. * system call/
  201. *
  202. * Notes:
  203. * - M024 - If dlet is invalid, we leave the buffer as simply the
  204. * null terminated root directory string.
  205. *
  206. */
  207. int GetDir(TCHAR *str, TCHAR dlet)
  208. {
  209. TCHAR denvname[ 4 ];
  210. TCHAR *denvvalue;
  211. if (dlet == GD_DEFAULT) {
  212. GetCurrentDirectory(MAX_PATH, str);
  213. return( SUCCESS );
  214. }
  215. denvname[ 0 ] = EQ;
  216. denvname[ 1 ] = (TCHAR)_totupper(dlet);
  217. denvname[ 2 ] = COLON;
  218. denvname[ 3 ] = NULLC;
  219. denvvalue = GetEnvVar( denvname );
  220. if (!denvvalue) {
  221. *str++ = (TCHAR)_totupper(dlet);
  222. *str++ = COLON;
  223. *str++ = BSLASH;
  224. *str = NULLC;
  225. return(FAILURE);
  226. } else {
  227. mystrcpy( str, denvvalue );
  228. return(SUCCESS);
  229. }
  230. }
  231. BOOL
  232. FixupPath(
  233. TCHAR *path,
  234. BOOL fShortNames
  235. )
  236. {
  237. TCHAR c, *src, *dst, *s;
  238. int n, n1, length;
  239. WIN32_FIND_DATA FindFileData;
  240. HANDLE hFind;
  241. length = _tcslen( path );
  242. if (length > MAX_PATH) {
  243. return FALSE;
  244. }
  245. src = path + 3; // Skip root directory.
  246. dst = path + 3;
  247. do {
  248. c = *src;
  249. if (!c || c == PathChar) {
  250. *src = NULLC;
  251. hFind = FindFirstFile( path, &FindFileData );
  252. *src = c;
  253. if (hFind != INVALID_HANDLE_VALUE) {
  254. FindClose( hFind );
  255. if (FindFileData.cAlternateFileName[0] &&
  256. (fShortNames ||
  257. (!_tcsnicmp( FindFileData.cAlternateFileName, dst, (UINT)(src - dst)) &&
  258. _tcsicmp( FindFileData.cFileName, FindFileData.cAlternateFileName)
  259. )
  260. )
  261. )
  262. //
  263. // Use short name if requested or
  264. // if input is explicitly using it and short name differs from long name
  265. //
  266. s = FindFileData.cAlternateFileName;
  267. else
  268. s = FindFileData.cFileName;
  269. n = _tcslen( s );
  270. n1 = n - (int)(src - dst);
  271. //
  272. // Make sure we don't overflow name
  273. //
  274. if (length + n1 > MAX_PATH) {
  275. return FALSE;
  276. } else {
  277. length += n1;
  278. }
  279. if (n1 > 0) {
  280. memmove( src+n1, src, _tcslen(src)*sizeof(TCHAR) );
  281. src += n1;
  282. }
  283. _tcsncpy( dst, s, n );
  284. dst += n;
  285. _tcscpy( dst, src );
  286. dst += 1;
  287. src = dst;
  288. } else {
  289. src += 1;
  290. dst = src;
  291. }
  292. }
  293. src += 1;
  294. }
  295. while (c != NULLC);
  296. return TRUE;
  297. }
  298. /*** ChangeDirectory - change a current directory
  299. *
  300. * Purpose:
  301. * Change the current directory on a drive. We do this either
  302. * via changing the associated environment variable, or
  303. * by changing the Win32 drive and directory.
  304. *
  305. * Args:
  306. * newdir - directory (optionally w/drive)
  307. * op - what operation should be performed
  308. * CD_SET_DRIVE_DIRECTORY - set the Win32 current directory and drive
  309. * CD_SET_DIRECTORY - set the Win32 current directory if the same drive
  310. * CD_SET_ENV - set the environment variables for the current directory
  311. * on a drive that's not the default drive.
  312. *
  313. * Returns:
  314. * SUCCESS if the directory was changed.
  315. * FAILURE otherwise.
  316. */
  317. int ChangeDirectory(
  318. TCHAR *newdir,
  319. CHANGE_OP op
  320. )
  321. {
  322. TCHAR denvname[ 4 ];
  323. TCHAR newpath[ MAX_PATH + MAX_PATH ];
  324. TCHAR denvvalue[ MAX_PATH ];
  325. TCHAR c, *s;
  326. DWORD attr;
  327. DWORD newdirlength,length;
  328. //
  329. // UNC paths are not allowed
  330. //
  331. if (newdir[0] == PathChar && newdir[1] == PathChar)
  332. return MSG_NO_UNC_CURDIR;
  333. //
  334. // truncate trailing spaces on ..
  335. //
  336. if (newdir[0] == DOT && newdir[1] == DOT) {
  337. DWORD i, fNonBlank;
  338. fNonBlank = 0;
  339. newdirlength = mystrlen(newdir);
  340. for (i=2; i<newdirlength; i++) {
  341. if (newdir[i] != SPACE) {
  342. fNonBlank = 1;
  343. break;
  344. }
  345. }
  346. if ( ! fNonBlank) {
  347. newdir[2] = NULLC;
  348. }
  349. }
  350. //
  351. // Get current drive and directory in order to
  352. // set up for forming the environment variable
  353. //
  354. GetCurrentDirectory( MAX_PATH, denvvalue );
  355. c = (TCHAR)_totupper( denvvalue[ 0 ] );
  356. //
  357. // Convention for environment form is:
  358. // Name of variable =d:
  359. // value is full path including drive
  360. //
  361. denvname[ 0 ] = EQ;
  362. if (_istalpha(*newdir) && newdir[1] == COLON) {
  363. denvname[ 1 ] = (TCHAR)_totupper(*newdir);
  364. newdir += 2;
  365. } else {
  366. denvname[ 1 ] = c;
  367. }
  368. denvname[ 2 ] = COLON;
  369. denvname[ 3 ] = NULLC;
  370. newdirlength = mystrlen(newdir);
  371. if (*newdir == PathChar) {
  372. if ((newdirlength+2) > sizeof(newpath)/sizeof( TCHAR )) {
  373. return ERROR_FILENAME_EXCED_RANGE;
  374. }
  375. newpath[ 0 ] = denvname[ 1 ]; // drive
  376. newpath[ 1 ] = denvname[ 2 ]; // colon
  377. mystrcpy( &newpath[ 2 ], newdir );
  378. } else {
  379. if (s = GetEnvVar( denvname )) {
  380. mystrcpy( newpath, s );
  381. } else {
  382. newpath[ 0 ] = denvname[ 1 ]; // drive
  383. newpath[ 1 ] = denvname[ 2 ]; // colon
  384. newpath[ 2 ] = NULLC;
  385. }
  386. //
  387. // Make sure there's exactly one backslash between newpath and newdir
  388. //
  389. s = lastc( newpath );
  390. //
  391. // s points to the last character or point to NUL (if newpath was
  392. // zero length to begin with). A NULL means we drop in a path char
  393. // over the NUL. A non-path char means we append a path char.
  394. //
  395. if (*s == NULLC) {
  396. *s++ = PathChar;
  397. } else if (*s != PathChar) {
  398. s[1] = PathChar;
  399. s += 2;
  400. }
  401. if (newdirlength + (s - newpath) > sizeof( newpath ) / sizeof( TCHAR )) {
  402. return ERROR_FILENAME_EXCED_RANGE;
  403. }
  404. mystrcpy( s, newdir );
  405. }
  406. denvvalue[(sizeof( denvvalue )-1)/sizeof( TCHAR )] = NULLC;
  407. //
  408. // form the full path name
  409. //
  410. if ((length = GetFullPathName( newpath, (sizeof( denvvalue )-1)/sizeof( TCHAR ), denvvalue, &s ))==0) {
  411. return( ERROR_ACCESS_DENIED );
  412. }
  413. //
  414. // Remove any trailing backslash
  415. //
  416. if (s == NULL) {
  417. s = denvvalue + _tcslen( denvvalue );
  418. }
  419. if (*s == NULLC && s > &denvvalue[ 3 ] && s[ -1 ] == PathChar) {
  420. *--s = NULLC;
  421. }
  422. //
  423. // Verify that there won't be (initially) disk errors when we touch
  424. // the directory
  425. //
  426. attr = GetFileAttributes( denvvalue );
  427. if (attr == -1) {
  428. attr = GetLastError( );
  429. if (attr != ERROR_FILE_NOT_FOUND &&
  430. attr != ERROR_PATH_NOT_FOUND &&
  431. attr != ERROR_INVALID_NAME) {
  432. return attr;
  433. }
  434. }
  435. //
  436. // If extensions are enabled, fixup the path to have the same case as
  437. // on disk
  438. //
  439. if (fEnableExtensions) {
  440. if (!FixupPath( denvvalue, FALSE )) {
  441. return ERROR_FILENAME_EXCED_RANGE;
  442. }
  443. }
  444. if (op != CD_SET_ENV) {
  445. attr = GetFileAttributes( denvvalue );
  446. if (attr == (DWORD)-1 ||
  447. !(attr & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_REPARSE_POINT))
  448. ) {
  449. if ( attr == -1 ) {
  450. attr = GetLastError();
  451. if ( attr == ERROR_FILE_NOT_FOUND ) {
  452. attr = ERROR_PATH_NOT_FOUND;
  453. }
  454. return attr;
  455. }
  456. return( ERROR_DIRECTORY );
  457. }
  458. }
  459. //
  460. // If we're always setting the directory or
  461. // if we're setting the directory if the drives are the same and
  462. // the drives ARE the same
  463. //
  464. if (op == CD_SET_DRIVE_DIRECTORY
  465. || (op == CD_SET_DIRECTORY
  466. && c == denvname[ 1 ])) {
  467. if (!SetCurrentDirectory( denvvalue )) {
  468. return GetLastError();
  469. }
  470. }
  471. if (SetEnvVar(denvname,denvvalue )) {
  472. return( ERROR_NOT_ENOUGH_MEMORY );
  473. }
  474. GetDir(CurDrvDir, GD_DEFAULT) ;
  475. return SUCCESS;
  476. }
  477. /*** ChangeDir2 - change a current directory
  478. *
  479. * Purpose:
  480. * To change to the directory specified in newdir on the drive specified
  481. * in newdir. If no drive is given, the default drive is used. If the
  482. * directory of the current drive is changed, the global variable
  483. * CurDrvDir is updated.
  484. *
  485. * This routine is used by RestoreCurrentDirectories
  486. *
  487. * int ChangeDir2(BYTE *newdir, BOOL )
  488. *
  489. * Args:
  490. * newdir - directory to change to
  491. * BOOL - current drive
  492. *
  493. * Returns:
  494. * SUCCESS if the directory was changed.
  495. * FAILURE otherwise.
  496. *
  497. */
  498. int ChangeDir2(
  499. TCHAR *newdir,
  500. BOOL CurrentDrive
  501. )
  502. {
  503. return ChangeDirectory( newdir, CurrentDrive ? CD_SET_DRIVE_DIRECTORY : CD_SET_ENV );
  504. }
  505. /*** ChangeDir - change a current directory
  506. *
  507. * Purpose:
  508. * To change to the directory specified in newdir on the drive specified
  509. * in newdir. If no drive is given, the default drive is used. If the
  510. * directory of the current drive is changed, the global variable
  511. * CurDrvDir is updated.
  512. *
  513. * int ChangeDir(TCHAR *newdir)
  514. *
  515. * Args:
  516. * newdir - directory to change to
  517. *
  518. * Returns:
  519. * SUCCESS if the directory was changed.
  520. * FAILURE otherwise.
  521. *
  522. */
  523. int ChangeDir(
  524. TCHAR *newdir
  525. )
  526. {
  527. return ChangeDirectory( newdir, CD_SET_DIRECTORY );
  528. }
  529. /*** exists - Determine if a given file exists
  530. *
  531. * Purpose:
  532. * To test the existence of a named file.
  533. *
  534. * int exists(TCHAR *filename)
  535. *
  536. * Args:
  537. * filename - the filespec to test
  538. *
  539. * Returns:
  540. * TRUE if file exists
  541. * FALSE if it does not.
  542. *
  543. * Notes:
  544. * M020 - Now uses ffirst to catch devices, directories and wildcards.
  545. */
  546. exists(filename)
  547. TCHAR *filename;
  548. {
  549. WIN32_FIND_DATA buf ; /* Use for ffirst/fnext */
  550. HANDLE hn ;
  551. int i ; /* tmp */
  552. TCHAR FullPath[ 2 * MAX_PATH ];
  553. TCHAR *p, *p1, SaveChar;
  554. p = StripQuotes(filename);
  555. i = GetFullPathName( p, 2 * MAX_PATH, FullPath, &p1 );
  556. if (i) {
  557. p = FullPath;
  558. if (!_tcsncmp( p, TEXT("\\\\.\\"), 4 )) {
  559. //
  560. // If they gave us a device name, then see if they put something
  561. // in front of it.
  562. //
  563. p += 4;
  564. p1 = p;
  565. if ((p1 = _tcsstr( filename, p )) && p1 > filename) {
  566. //
  567. // Something in front of the device name, so truncate the input
  568. // path at the device name and see if that exists.
  569. //
  570. SaveChar = *p1;
  571. *p1 = NULLC;
  572. i = (int)GetFileAttributes( filename );
  573. *p1 = SaveChar;
  574. if (i != 0xFFFFFFFF) {
  575. return i;
  576. } else {
  577. return 0;
  578. }
  579. } else {
  580. //
  581. // Just a device name given. See if it is valid.
  582. //
  583. i = (int)GetFileAttributes( filename );
  584. if (i != 0xFFFFFFFF) {
  585. return i;
  586. } else {
  587. return 0;
  588. }
  589. }
  590. }
  591. if (p1 == NULL || *p1 == NULLC) {
  592. i = (int)(GetFileAttributes( p ) != 0xFFFFFFFF);
  593. } else {
  594. i = ffirst( p, A_ALL, &buf, &hn );
  595. findclose(hn);
  596. if ( i == 0 ) {
  597. //
  598. // ffirst handles files & directories, but not
  599. // root drives, so do special check for them.
  600. //
  601. if ( *(p+1) == (TCHAR)'\\' ||
  602. (*(p+1) == (TCHAR)':' &&
  603. *(p+2) == (TCHAR)'\\' &&
  604. *(p+3) == (TCHAR)0
  605. )
  606. ) {
  607. UINT t;
  608. t = GetDriveType( p );
  609. if ( t > 1 ) {
  610. i = 1;
  611. }
  612. }
  613. }
  614. }
  615. }
  616. return i;
  617. }
  618. /*** exists_ex - Determine if a given executable file exists @@4
  619. *
  620. * Purpose:
  621. * To test the existence of a named executable file.
  622. *
  623. * int exists_ex(TCHAR *filename)
  624. *
  625. * Args:
  626. * filename - the filespec to test
  627. * checkformeta - if TRUE, check for wildcard char
  628. *
  629. * Returns:
  630. * TRUE if file exists
  631. * FALSE if it does not.
  632. *
  633. * Notes:
  634. * @@4 - Now uses ffirst to catch only files .
  635. */
  636. exists_ex(filename,checkformeta) /*@@4*/
  637. TCHAR *filename; /*@@4*/
  638. BOOL checkformeta;
  639. { /*@@4*/
  640. WIN32_FIND_DATA buf; /* use for ffirst/fnext */
  641. HANDLE hn;
  642. int i;
  643. TCHAR *ptr;
  644. /* can not execute wild card files, so check for those first */
  645. if (checkformeta && (mystrchr( filename, STAR ) || mystrchr( filename, QMARK ))) {
  646. DosErr = 3;
  647. i = 0;
  648. } else {
  649. /* see if the file exists, do not include Directory, volume, or */
  650. /* hidden files */
  651. i = ((ffirst( filename , A_AEDV, &buf, &hn))) ;
  652. if ( i ) {
  653. findclose(hn) ;
  654. /* if the file exists then copy the file name, to get the case */
  655. ptr = mystrrchr( filename, BSLASH );
  656. if ( ptr == NULL ) {
  657. ptr = filename;
  658. if ( mystrlen( ptr ) > 2 && ptr[1] == COLON ) {
  659. ptr = &filename[2];
  660. }
  661. } else {
  662. ptr++;
  663. }
  664. //
  665. // Append the found, expanded name. Since this name may be longer
  666. // (due to seeing a short name or expanding metacharacters), we make
  667. // sure that the destination is no more than MAXPATH long
  668. //
  669. if ((ptr - filename) + _tcslen( buf.cFileName ) + 1 > MAX_PATH) {
  670. DosErr= ERROR_BUFFER_OVERFLOW;
  671. } else {
  672. mystrcpy( ptr, buf.cFileName);
  673. }
  674. } else if ( DosErr == 18 ) {
  675. DosErr = 2;
  676. }
  677. }
  678. return(i) ; /*@@4*/
  679. } /*@@4*/
  680. /*** FixPChar - Fix up any leading path in a string
  681. *
  682. * Purpose:
  683. * To insure that paths match the current Swit/Pathchar setting
  684. *
  685. * void FixPChar(TCHAR *str, TCHAR PChar)
  686. *
  687. * Args:
  688. * str - the string to fixup
  689. * Pchar - character to replace
  690. *
  691. * Returns:
  692. * Nothing
  693. *
  694. */
  695. void FixPChar(TCHAR *str, TCHAR PChar)
  696. {
  697. TCHAR *sptr1, /* Index for string */
  698. *sptr2 ; /* Change marker */
  699. sptr1 = str ; /* Init to start of string */
  700. while (sptr2 = mystrchr(sptr1,PChar)) {
  701. *sptr2++ = PathChar ;
  702. sptr1 = sptr2 ;
  703. } ;
  704. }
  705. /*** FlushKB - Remove extra unwanted input from Keyboard
  706. *
  707. * Purpose:
  708. * To perform a keyboard flush up to the next CR/LF.
  709. *
  710. * FlushKB()
  711. *
  712. * Args:
  713. * None
  714. *
  715. * Returns:
  716. * Nothing
  717. *
  718. */
  719. void FlushKB()
  720. {
  721. DWORD cnt;
  722. TCHAR IgnoreBuffer[128];
  723. while (ReadBufFromInput( GetStdHandle(STD_INPUT_HANDLE), IgnoreBuffer, 128, &cnt )) {
  724. if (mystrchr( IgnoreBuffer, CR ))
  725. return ;
  726. }
  727. }
  728. /*** DriveIsFixed - Determine if drive is removeable media
  729. *
  730. * Purpose: @@4
  731. * To determine if the input drive is a removeable media.
  732. *
  733. * DriveIsFixed(TCHAR *drive_ptr )
  734. *
  735. * Args:
  736. * drive_ptr - pointer to a file name that contains a drive
  737. * specification.
  738. *
  739. * Returns:
  740. * 1 - if error or non removeable media
  741. * 0 - if no error and removeable media
  742. */
  743. int
  744. DriveIsFixed( TCHAR *drive_ptr )
  745. {
  746. unsigned rc = 0;
  747. TCHAR drive_spec[3];
  748. drive_spec[0] = *drive_ptr;
  749. drive_spec[1] = COLON;
  750. drive_spec[2] = NULLC;
  751. // FIX, FIX - use GetVolumeInfo, disabling hard errors?
  752. if ((*drive_ptr == TEXT('A')) || (*drive_ptr == TEXT('B'))) {
  753. rc = 0;
  754. } else {
  755. rc = 1;
  756. }
  757. return( rc );
  758. }
  759. int
  760. CmdPutChars(
  761. PTCHAR String,
  762. int Length
  763. )
  764. {
  765. int rc = SUCCESS; /* return code */
  766. int bytesread; /* bytes to write count */
  767. int byteswrit; /* bytes written count */
  768. BOOL flag;
  769. if (Length > 0) {
  770. if (FileIsConsole(STDOUT)) {
  771. if (!(flag=WriteConsole(CRTTONT(STDOUT), String, Length, &byteswrit, NULL)))
  772. rc = GetLastError();
  773. } else {
  774. Length *= sizeof(TCHAR);
  775. flag = MyWriteFile( STDOUT, (CHAR *)String, Length, &byteswrit);
  776. }
  777. //
  778. // If the write failed or unable to output all the data
  779. //
  780. if (flag == 0 || byteswrit != Length) {
  781. rc = GetLastError();
  782. //
  783. // No error => DiskFull
  784. //
  785. if (rc == 0) {
  786. rc = ERROR_DISK_FULL;
  787. }
  788. if (FileIsDevice(STDOUT)) {
  789. //
  790. // If the we were writing to a device then the error is a device
  791. // write fault.
  792. //
  793. PutStdErr( ERROR_WRITE_FAULT, NOARGS );
  794. } else if (FileIsPipe(STDOUT)) {
  795. //
  796. // If the we were writing to a pipe, then the error is an invalid
  797. // pipe error.
  798. //
  799. PutStdErr(MSG_CMD_INVAL_PIPE, NOARGS);
  800. return(FAILURE);
  801. } else {
  802. //
  803. // Just output the error we found
  804. //
  805. PrtErr(rc);
  806. return(FAILURE);
  807. }
  808. }
  809. }
  810. return(rc);
  811. }
  812. int
  813. CmdPutString(
  814. PTCHAR String
  815. )
  816. {
  817. return CmdPutChars( String, _tcslen( String ));
  818. }
  819. int
  820. cmd_printf(
  821. TCHAR *fmt,
  822. ...
  823. )
  824. {
  825. int Length;
  826. va_list arg_ptr;
  827. va_start(arg_ptr,fmt);
  828. Length = _vsntprintf( MsgBuf, MAXCBMSGBUFFER, fmt, arg_ptr );
  829. MsgBuf[MAXCBMSGBUFFER - 1] = TEXT( '\0' );
  830. va_end(arg_ptr);
  831. return CmdPutChars( MsgBuf, Length );
  832. }