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.

884 lines
22 KiB

  1. /*
  2. * copy.c - Copy routine for WinDosSetup
  3. * Todd Laney
  4. *
  5. * Modification History:
  6. *
  7. * 6/03/91 Vlads Change copy process to incorporate new Install API
  8. *
  9. * 3/24/89 Toddla Wrote it
  10. *
  11. *
  12. * notes:
  13. * we now use the LZCopy stuff for compression
  14. * we now set the crit error handler ourselves so CHECKFLOPPY is
  15. * NOT defined
  16. */
  17. #include <windows.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <ctype.h>
  21. #include <mmsystem.h>
  22. #include "drivers.h"
  23. #include "sulib.h"
  24. //#include <ver.h>
  25. #define MAX_COPY_ATTEMPTS 15
  26. /*
  27. * Maximum number of install disks we support
  28. */
  29. #define MAX_DISKS 100
  30. /*
  31. * Flags for VerInstallFile
  32. */
  33. #define FORCEABLE_FLAGS (VIF_MISMATCH + VIF_SRCOLD + VIF_DIFFLANG + VIF_DIFFTYPE + VIF_DIFFCODEPG )
  34. /**********************************************************************
  35. *
  36. * Local function prototypes.
  37. *
  38. **********************************************************************/
  39. // Retrieve disk path for logical disk
  40. BOOL GetDiskPath(LPSTR Disk, LPSTR szPath);
  41. // Convert VIF_... to ERROR... return codes
  42. UINT ConvertFlagToValue(DWORD dwFlags);
  43. // Do the work of trying to copy a file
  44. LONG TryCopy(LPSTR szSrc, // Full source file path
  45. LPSTR szLogSrc, // Logical source name
  46. LPSTR szDestPath,// Destination path
  47. FPFNCOPY fpfnCopy); // Callback routine
  48. #ifdef CHECK_FLOPPY
  49. BOOL NEAR IsDiskInDrive(int iDisk);
  50. #endif
  51. // GLOBAL VARIABLES
  52. // directory where windows will be setup to
  53. char szSetupPath[MAX_PATH];
  54. // directory where the root of the setup disks are!
  55. char szDiskPath[MAX_PATH];
  56. // Name of driver being copied (or oemsetup.inf)
  57. char szDrv[120];
  58. /*
  59. * global vars used by DosCopy
  60. */
  61. static LPSTR lpBuf = NULL; // copy buffer
  62. static int iBuf = 0; // usage count
  63. static UINT nBufSize;
  64. BOOL bRetry = FALSE;
  65. BOOL bQueryExist;
  66. BOOL DefCopyCallback(int msg, DWORD n, LPSTR szFile)
  67. {
  68. return FC_IGNORE;
  69. }
  70. /* UINT FileCopy (szSource, szDir, fpfnCopy, UINT fCopy)
  71. *
  72. * This function will copy a group of files to a single destination
  73. *
  74. * ENTRY:
  75. *
  76. * szSourc : pointer to a SETUP.INF section
  77. * szDir : pointer to a string containing the target DIR
  78. * fpfnCopy : callback function used to notify called of copy status
  79. * fCopy : flags
  80. *
  81. * FC_SECTION - szSource is a section name
  82. * FC_LIST - szSource is a pointer to a char **foo;
  83. * FC_LISTTYPE - szSource is a pointer to a char *foo[];
  84. * FC_FILE - szSource is a file name.
  85. * FC_QUALIFIED - szSource is a fully qualified file name.
  86. * FC_DEST_QUALIFIED - szDir is fully qualified. Don't expand this.
  87. * FC_CALLBACK_WITH_VER - call back if file exists and report version information.
  88. *
  89. * NOTES:
  90. * if szSource points to a string of the form '#name' the section
  91. * named by 'name' will be used as the source files
  92. *
  93. * the first field of each line in the secion is used as the name of the
  94. * source file. A file name has the following form:
  95. *
  96. * #:name
  97. *
  98. * # - Disk number containing file 1-9,A-Z
  99. * name - name of the file, may be a wild card expression
  100. *
  101. * Format for copy status function
  102. *
  103. * BOOL FAR PASCAL CopyStatus(int msg, int n, LPSTR szFile)
  104. *
  105. * msg:
  106. * COPY_ERROR error occured while copying file(s)
  107. * n is the DOS error number
  108. * szFile is the file that got the error
  109. * return: TRUE ok, FALSE abort copy
  110. *
  111. * COPY_STATUS Called each time a new file is copied
  112. * n is the percent done
  113. * szFile is the file being copied
  114. * return: TRUE ok, FALSE abort copy
  115. *
  116. * COPY_INSERTDISK Please tell the user to insert a disk
  117. * n is the disk needed ('1' - '9')
  118. * return: TRUE try again, FALSE abort copy
  119. *
  120. * COPY_QUERYCOPY Should this file be copied?
  121. * n line index in SETUP.INF section (0 based)
  122. * szFile is the line from section
  123. * return: TRUE copy it, FALSE dont copy
  124. *
  125. * COPY_START Sent before any files are copied
  126. *
  127. * COPY_END Sent after all files have been copied
  128. * n is dos error if copy failed
  129. *
  130. * COPY_EXISTS Sent if the FC_CALL_ON_EXIST bit was set
  131. * and the file exists at the destination
  132. * given for the filecopy.
  133. *
  134. *
  135. * EXIT: returns TRUE if successful, FALSE if failure.
  136. *
  137. */
  138. UINT FileCopy (LPSTR szSource, LPSTR szDir, FPFNCOPY fpfnCopy, UINT fCopy)
  139. {
  140. int err = ERROR_SUCCESS; // Return code from this routine
  141. char szPath[MAX_PATH];
  142. char szLogSrc[MAX_PATH];
  143. char szSrc[MAX_PATH];
  144. LPSTR pFileBegin; // First file
  145. LPSTR * List; // Handle lists of files
  146. LPSTR * ListHead;
  147. int nDisk; // The disk we're on
  148. int cntFiles = 0; // How many files we've got to do
  149. if (fpfnCopy == NULL) {
  150. fpfnCopy = DefCopyCallback;
  151. }
  152. if (!szSource || !*szSource || !szDir || !*szDir) {
  153. return ERROR_FILE_NOT_FOUND;
  154. }
  155. /*
  156. * fix up the drive in the destination
  157. */
  158. if ( fCopy & FC_DEST_QUALIFIED ) {
  159. lstrcpy(szPath, szDir);
  160. fCopy &= ~FC_DEST_QUALIFIED;
  161. } else {
  162. ExpandFileName(szDir, szPath);
  163. }
  164. if (szSource[0] == '#' && fCopy == FC_FILE) {
  165. fCopy = FC_SECTION;
  166. ++szSource;
  167. }
  168. switch (fCopy) {
  169. case FC_SECTION:
  170. {
  171. szSource = infFindSection(NULL,szSource);
  172. /*
  173. * We are called even when the section doesn't exist
  174. */
  175. if (szSource == NULL) {
  176. return ERROR_SUCCESS;
  177. }
  178. fCopy = FC_LIST;
  179. }
  180. // fall through to FC_LIST
  181. case FC_LIST:
  182. pFileBegin = szSource;
  183. cntFiles = infLineCount(szSource);
  184. break;
  185. case FC_LISTTYPE:
  186. ListHead = List = (LPSTR far *)szSource;
  187. pFileBegin = *ListHead;
  188. while ( *List++ ) // Count files to be copied.
  189. ++cntFiles;
  190. break;
  191. case FC_FILE:
  192. case FC_QUALIFIED:
  193. default:
  194. pFileBegin = szSource;
  195. cntFiles = 1;
  196. }
  197. /*
  198. * walk all files in the list and call TryCopy ....
  199. *
  200. * NOTES:
  201. * we must walk file list sorted by disk number.
  202. * we should use the disk that is currently inserted.
  203. * we should do a find first/find next on the files????
  204. * we need to check for errors.
  205. * we need to ask the user to insert disk in drive.
  206. *
  207. */
  208. (*fpfnCopy)(COPY_START,0,NULL);
  209. /*
  210. * Go through all possible disks: 1 to 100 and A to Z (26)
  211. */
  212. for (nDisk = 1;
  213. err == ERROR_SUCCESS && (cntFiles > 0) &&
  214. (nDisk <= MAX_DISKS + 'Z' - 'A' + 1);
  215. nDisk++)
  216. {
  217. char Disk[10]; // Maximum string is "100:"
  218. LPSTR pFile;
  219. int FileNumber; // Which file in the list we're on
  220. // (to pass to callback)
  221. pFile = pFileBegin; // Start at first file
  222. List = ListHead; // Handled chained lists
  223. FileNumber = 0; // Informational for callback - gives
  224. // which file in list we're on
  225. /*
  226. * Work out the string representing our disk letter
  227. */
  228. if (nDisk > MAX_DISKS) {
  229. Disk[0] = 'A' + nDisk - MAX_DISKS - 1;
  230. Disk[1] = '\0';
  231. } else {
  232. _itoa(nDisk, Disk, 10);
  233. }
  234. strcat(Disk, ":");
  235. for (;
  236. err == ERROR_SUCCESS && pFile;
  237. FileNumber++,
  238. pFile = fCopy == FC_LISTTYPE ? *(++List) :
  239. fCopy == FC_LIST ? infNextLine(pFile) :
  240. NULL)
  241. {
  242. /*
  243. * We have to reset high bit of first byte because it could be set
  244. * by translating service in OEM setup to show that file name was
  245. * mapped
  246. */
  247. *pFile = toascii(*pFile);
  248. /*
  249. * should we copy this file?
  250. * copy the files in disk order.
  251. */
  252. if (_strnicmp(pFile, Disk, strlen(Disk)) == 0 || // File has disk
  253. // number and we're
  254. // on that disk
  255. RemoveDiskId(pFile) == pFile &&
  256. nDisk == 1 && *pFile || // First disk and
  257. // no disk number
  258. fCopy == FC_QUALIFIED) { // Fully qualified
  259. /*
  260. * done with a file. decrement count.
  261. */
  262. cntFiles--;
  263. lstrcpy(szDrv, RemoveDiskId(pFile));
  264. switch ((*fpfnCopy)(COPY_QUERYCOPY, FileNumber, pFile))
  265. {
  266. case CopyCurrent: // Skip
  267. continue;
  268. case CopyNeither:
  269. err = ERROR_FILE_EXISTS; // File already exists
  270. case CopyNew:
  271. break;
  272. default:
  273. break;
  274. }
  275. /*
  276. * Pick up bad return code from switch
  277. */
  278. if (err != ERROR_SUCCESS) {
  279. break;
  280. }
  281. /*
  282. * now we convert logical dest into a physical
  283. * (unless FC_QUALIFIED)
  284. */
  285. infParseField(pFile, 1, szLogSrc); // logical source
  286. if ( fCopy != FC_QUALIFIED ) {
  287. ExpandFileName(szLogSrc, szSrc); // full physical source
  288. } else {
  289. lstrcpy(szSrc,szLogSrc);
  290. }
  291. /*
  292. * Attempt copy
  293. */
  294. err = TryCopy(szSrc, // Qualified Source file
  295. szLogSrc, // Logical source file name (with disk #)
  296. szPath, // Path for directory to install in
  297. fpfnCopy); // Copy callback function
  298. /*
  299. * If failed to find file try the windows directory
  300. */
  301. if (err != ERROR_SUCCESS) {
  302. break;
  303. }
  304. } /* End if dor if DoCopy */
  305. }
  306. }
  307. (*fpfnCopy)(COPY_END,err,NULL);
  308. return err;
  309. }
  310. /**********************************************************************
  311. *
  312. * TryCopy
  313. *
  314. * Copy a single file from source to destination using the VerInstallFile
  315. * API - interpreting the return code as :
  316. *
  317. * ERROR_SUCCESS - OK
  318. * Other - failure type
  319. *
  320. **********************************************************************/
  321. LONG TryCopy(LPSTR szSrc, // Full expanded source file path
  322. LPSTR szLogSrc, // Logical source name
  323. LPSTR szDestPath, // Destination path
  324. FPFNCOPY fpfnCopy) // Callback routine
  325. {
  326. DWORD wTmpLen;
  327. DWORD dwRetFlags;
  328. char szTempFile[MAX_PATH];
  329. char szErrFile[MAX_PATH];
  330. char DriversPath[MAX_PATH];
  331. BOOL bRetVal; // Return code from callback
  332. LPSTR szFile;
  333. char szSrcPath[MAX_PATH];
  334. int iAttemptCount;
  335. WORD wVerFlags;
  336. LONG err;
  337. /*
  338. * Fix up destination if file is a kernel driver
  339. */
  340. if (IsFileKernelDriver(szSrc)) {
  341. strcpy(DriversPath, szDestPath);
  342. strcat(DriversPath, "\\drivers");
  343. szDestPath = DriversPath;
  344. }
  345. /*
  346. * Create file name from current string
  347. */
  348. szFile = FileName(szSrc);
  349. lstrcpy(szSrcPath, szSrc);
  350. StripPathName(szSrcPath);
  351. for(iAttemptCount = 0, wVerFlags = 0 ;
  352. iAttemptCount <= MAX_COPY_ATTEMPTS;
  353. iAttemptCount++) {
  354. HCURSOR hcurPrev; // Saved cursor state
  355. // Central operation - attempt to install file szFile in directory
  356. // pointed by szPath from directory pointed by szSrc
  357. // If operation will fail but with possibility to force install
  358. // in last parameter buffer we will have temporary file name ==>
  359. // therefore we can avoid excessive copying.
  360. // NOTE: now szFile consists of only file name and other buffers
  361. // only path names.
  362. wTmpLen = MAX_PATH;
  363. hcurPrev = SetCursor(LoadCursor(NULL,IDC_WAIT));
  364. dwRetFlags = VerInstallFile(wVerFlags,
  365. (LPSTR) szFile,
  366. (LPSTR) szFile,
  367. (LPSTR) szSrcPath,
  368. (LPSTR) szDestPath,
  369. (LPSTR) szDestPath,
  370. (LPSTR) szTempFile,
  371. (LPDWORD) &wTmpLen);
  372. SetCursor(hcurPrev);
  373. /*
  374. * Operation failed if at least one bit of return flags is non-zero
  375. * That is unusual but defined so in Version API.
  376. */
  377. if ( !dwRetFlags )
  378. return ERROR_SUCCESS; // If no errors - goto next file
  379. /*
  380. * If flag MISMATCH is set - install can be forced and we have
  381. * temporary file in destination subdirectory
  382. */
  383. if ( dwRetFlags & VIF_MISMATCH ) {
  384. if ( dwRetFlags & VIF_SRCOLD ) {
  385. /*
  386. * If we need not call back with question - automatically
  387. * force install with same parameters.
  388. * michaele, *only* if src file is *newer* than dst file
  389. */
  390. DeleteFile(szTempFile);
  391. return ERROR_SUCCESS;
  392. }
  393. /*
  394. * If we need not call back with question - automatically
  395. * force install with same parameters.
  396. */
  397. wVerFlags |= VIFF_FORCEINSTALL;
  398. iAttemptCount--; // Make sure we get another go.
  399. continue;
  400. } /* End if MISMATCH */
  401. /*
  402. * If real error occured - call back with error file info
  403. * In all dialogs we use our error codes - so I will convert
  404. * flags returned from Ver API to ours.
  405. */
  406. err = ConvertFlagToValue(dwRetFlags);
  407. /*
  408. * If source path or file is nor readable - try to change disk
  409. */
  410. if ( dwRetFlags & VIF_CANNOTREADSRC )
  411. {
  412. /*
  413. * Now new path in szSrc so I deleted logic for creating it
  414. */
  415. if (RemoveDiskId(szLogSrc) == szLogSrc)
  416. /*
  417. * if disk # not provided, default to 1
  418. */
  419. bRetVal = (*fpfnCopy)(COPY_INSERTDISK, (DWORD)"1", szSrcPath);
  420. else
  421. bRetVal = (*fpfnCopy)(COPY_INSERTDISK, (DWORD)szLogSrc, szSrcPath);
  422. switch (bRetVal)
  423. {
  424. case FC_RETRY:
  425. continue; // and try again...
  426. case FC_ABORT:
  427. return ERROR_FILE_NOT_FOUND;
  428. case FC_IGNORE:
  429. break;
  430. }
  431. }
  432. ExpandFileName(szLogSrc, szErrFile);
  433. #if WINDOWSDIR
  434. if (!*bWindowsDir &&
  435. err != FC_ERROR_LOADED_DRIVER &&
  436. err != ERROR_DISK_FULL)
  437. {
  438. GetWindowsDirectory(szPath, MAX_PATH);
  439. *bWindowsDir = TRUE;
  440. continue;
  441. }
  442. #endif // WINDOWSDIR
  443. switch ((*fpfnCopy)(COPY_ERROR, err, szErrFile)) {
  444. case FC_IGNORE:
  445. return ERROR_SUCCESS;
  446. case FC_RETRY:
  447. break;
  448. case FC_ABORT:
  449. return ERROR_FILE_NOT_FOUND;
  450. }
  451. } // End of attempts
  452. return err;
  453. }
  454. /* BOOL GetDiskPath(Disk, szPath)
  455. *
  456. * This function will retrive the full path name for a logical disk
  457. *
  458. * The code reads the [disks] section of SETUP.INF and looks for
  459. * n = path where n is the disk char. NOTE the disk '0' defaults to
  460. * the root windows directory.
  461. *
  462. * ENTRY:
  463. *
  464. * cDisk : what disk to find 0-9,A-Z
  465. * szPath : buffer to hold disk path
  466. *
  467. * Returns :
  468. * TRUE if a disk path was found
  469. * FALSE if there was no disk specified (ie no ':'
  470. *
  471. */
  472. BOOL GetDiskPath(LPSTR Disk, LPSTR szPath)
  473. {
  474. char ach[MAX_PATH];
  475. char szBuf[MAX_PATH];
  476. int i;
  477. /*
  478. * Check to see if there is actually a disk id.
  479. * If not return FALSE
  480. */
  481. if (RemoveDiskId(Disk) == Disk) {
  482. return FALSE;
  483. }
  484. /*
  485. * Create our copy of the disk id
  486. */
  487. for (i = 0; Disk[i] != ':'; i++) {
  488. ach[i] = Disk[i];
  489. }
  490. ach[i] = '\0';
  491. /*
  492. * Zero disk letter means windows setup directory
  493. */
  494. if (_stricmp(ach, "0") == 0) {
  495. /*
  496. * return the windows setup directory
  497. */
  498. lstrcpy(szPath,szSetupPath);
  499. return TRUE;
  500. }
  501. /*
  502. * now look in the [disks] section for a full path name
  503. *
  504. * This is a pretty bogus concept and is not supported
  505. * in win 32 style disks section [Source Media Descriptions]
  506. */
  507. if ( !infGetProfileString(NULL,DISK_SECT,ach,szPath) &&
  508. !infGetProfileString(NULL,OEMDISK_SECT,ach,szPath)) {
  509. lstrcpy(szPath, szDiskPath);
  510. } else {
  511. infParseField(szPath,1,szPath);
  512. /*
  513. * is the path relative? is so prepend the szDiskPath
  514. */
  515. if (szPath[0] == '.' || szPath[0] == '\0') {
  516. lstrcpy(szBuf,szDiskPath);
  517. catpath(szBuf,szPath);
  518. lstrcpy(szPath,szBuf);
  519. }
  520. }
  521. return TRUE;
  522. }
  523. /* BOOL FAR PASCAL ExpandFileName(LPSTR szFile, LPSTR szPath)
  524. *
  525. * This function will retrive the full path name for a file
  526. * it will expand, logical disk letters to pyshical ones
  527. * will use current disk and directory if non specifed.
  528. *
  529. * if the drive specifed is 0-9, it will expand the drive into a
  530. * full pathname using GetDiskPath()
  531. *
  532. * IE 0:system ==> c:windows\system
  533. * 1:foo.txt a:\foo.txt
  534. *
  535. * ENTRY:
  536. *
  537. * szFile : File name to expand
  538. * szPath : buffer to hold full file name
  539. *
  540. */
  541. BOOL ExpandFileName(LPSTR szFile, LPSTR szPath)
  542. {
  543. char szBuf[MAX_PATH*2];
  544. if (GetDiskPath(szFile, szBuf)) {
  545. lstrcpy(szPath,szBuf);
  546. if (szFile[2])
  547. catpath(szPath,szFile + 2);
  548. } else {
  549. lstrcpy(szPath,szFile);
  550. }
  551. return TRUE;
  552. }
  553. void catpath(LPSTR path, LPSTR sz)
  554. {
  555. //
  556. // Remove any drive letters from the directory to append
  557. //
  558. sz = RemoveDiskId(sz);
  559. //
  560. // Remove any current directories ".\" from directory to append
  561. //
  562. while (sz[0] == '.' && SLASH(sz[1]))
  563. sz += 2;
  564. //
  565. // Dont append a NULL string or a single "."
  566. //
  567. if (*sz && ! (sz[0] == '.' && sz[1] == 0))
  568. {
  569. // Add a slash separator if necessary.
  570. if ((! SLASH(path[lstrlen(path) - 1])) && // slash at end of path
  571. ((path[lstrlen(path) - 1]) != ':') && // colon at end of path
  572. (! SLASH(sz[0]))) // slash at beginning of file
  573. lstrcat(path, CHSEPSTR);
  574. lstrcat(path, sz);
  575. }
  576. }
  577. /*
  578. * Return a pointer to the file name part of a string
  579. */
  580. LPSTR FileName(LPSTR szPath)
  581. {
  582. LPSTR sz;
  583. for (sz=szPath; *sz; sz++)
  584. ;
  585. for (; sz>=szPath && !SLASH(*sz) && *sz!=':'; sz--)
  586. ;
  587. return ++sz;
  588. }
  589. /*
  590. * Return the portion of a file name following the disk (ie anything
  591. * before the colon).
  592. * If there is no colon just return a pointer to the original string
  593. */
  594. LPSTR RemoveDiskId(LPSTR szPath)
  595. {
  596. LPSTR sz;
  597. for (sz = szPath; *sz; sz++) {
  598. if (*sz == ':') {
  599. return sz + 1;
  600. }
  601. }
  602. return szPath;
  603. }
  604. LPSTR StripPathName(LPSTR szPath)
  605. {
  606. LPSTR sz;
  607. sz = FileName(szPath);
  608. if (sz > szPath+1 && SLASH(sz[-1]) && sz[-2] != ':')
  609. sz--;
  610. *sz = 0;
  611. return szPath;
  612. }
  613. /*
  614. * See if a file is a kernel driver. Unfortunately the VersionInfo APIs
  615. * don't seem coded up to take care of this at the moment so we just check
  616. * to see if the file extension is ".SYS"
  617. */
  618. BOOL IsFileKernelDriver(LPSTR szPath)
  619. {
  620. char drive[MAX_PATH];
  621. char dir[MAX_PATH];
  622. char fname[MAX_PATH];
  623. char ext[MAX_PATH];
  624. _splitpath(szPath, drive, dir, fname, ext);
  625. return !_stricmp(ext, ".sys");
  626. }
  627. /**************************************************************************
  628. *
  629. * This function converts returned flags from Ver API to the numerical
  630. * error codes used in SETUP.
  631. *
  632. ***************************************************************************/
  633. UINT ConvertFlagToValue(DWORD dwFlags)
  634. {
  635. if ( ! dwFlags )
  636. return(NO_ERROR);
  637. if ( dwFlags & VIF_CANNOTREADSRC )
  638. return(ERROR_FILE_NOT_FOUND);
  639. if ( dwFlags & VIF_OUTOFMEMORY )
  640. return(ERROR_OUTOFMEMORY);
  641. if ( dwFlags & VIF_ACCESSVIOLATION )
  642. return(ERROR_ACCESS_DENIED);
  643. if ( dwFlags & VIF_SHARINGVIOLATION )
  644. return(ERROR_SHARING_VIOLATION);
  645. if ( dwFlags & VIF_FILEINUSE)
  646. return(FC_ERROR_LOADED_DRIVER);
  647. return(ERROR_CANNOT_COPY); // General error
  648. }
  649. #ifdef CHECK_FLOPPY
  650. /*--------------------------------------------------------------------------
  651. IsValidDiskette() -
  652. --------------------------------------------------------------------------*/
  653. #define CBSECTORSIZE 512
  654. #define INT13_READ 2
  655. BOOL IsValidDiskette(int iDrive)
  656. {
  657. char buf[CBSECTORSIZE];
  658. iDrive |= 0x0020; // make lower case
  659. iDrive -= 'a'; // A = 0, B = 1, etc. for BIOS stuff
  660. return MyReadWriteSector(buf, INT13_READ, iDrive, 0, 0, 1);
  661. }
  662. /* BOOL IsDiskInDrive(char cDisk)
  663. *
  664. * Is the specifed disk in the drive
  665. *
  666. * ENTRY:
  667. *
  668. * cDisk : what disk required to be in the drive (logical)
  669. *
  670. * return TRUE if the specifed disk is in the drive
  671. * FALSE if the wrong disk is in the drive or disk error
  672. *
  673. */
  674. BOOL IsDiskInDrive(int iDisk)
  675. {
  676. if ((iDisk >= 'A' && iDisk <= 'Z') ||
  677. (iDisk >= 'a' && iDisk <= 'z'))
  678. {
  679. if (DosRemoveable(iDisk))
  680. {
  681. if (!IsValidDiskette(iDisk))
  682. return FALSE;
  683. }
  684. return TRUE;
  685. }
  686. return TRUE; // for non drive letters assume a path
  687. // and thus always in.
  688. }
  689. #endif