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.

996 lines
24 KiB

  1. /* demgset.c - Drive related SVC hanlers.
  2. *
  3. * demSetDefaultDrive
  4. * demGetBootDrive
  5. * demGetDriveFreeSpace
  6. * demGetDrives
  7. * demGSetMediaID
  8. * demQueryDate
  9. * demQueryTime
  10. * demSetDate
  11. * demSetTime
  12. * demSetDTALocation
  13. * demGSetMediaID
  14. * demGetDPB
  15. * Modification History:
  16. *
  17. * Sudeepb 02-Apr-1991 Created
  18. *
  19. */
  20. #include "dem.h"
  21. #include "demmsg.h"
  22. #include <softpc.h>
  23. #include <mvdm.h>
  24. #include <winbase.h>
  25. #include "demdasd.h"
  26. #include "dpmtbls.h"
  27. #define BOOTDRIVE_PATH "Software\\Microsoft\\Windows\\CurrentVersion\\Setup"
  28. #define BOOTDRIVE_VALUE "BootDir"
  29. #define SUCCESS 0
  30. #define NODISK 1
  31. #define FAILURE 2
  32. BYTE demGetDpbI(BYTE Drive, DPB UNALIGNED *pDpb);
  33. UCHAR PhysicalDriveTypes[26]={0};
  34. extern PDOSSF pSFTHead;
  35. USHORT nDrives = 0;
  36. CHAR IsAPresent = TRUE;
  37. CHAR IsBPresent = TRUE;
  38. /* demSetDefaultDrive - Set the default drive
  39. *
  40. *
  41. * Entry -
  42. * Client (DS:SI) Current Directory on that drive
  43. * Client (dl) Zero based DriveNum
  44. *
  45. * Exit - SUCCESS
  46. * Client (CY) = 0
  47. * Current Drive Set
  48. *
  49. * FAILURE
  50. * Client (CY) = 1
  51. * Current Drive Not Set
  52. *
  53. * Notes:
  54. * The DOS keeps a current directory for each of the drives,
  55. * However winnt keeps only one current Drive, Directory per
  56. * process, and it is cmd.exe which associates a current
  57. * directory for each of the drive.
  58. */
  59. VOID demSetDefaultDrive (VOID)
  60. {
  61. LPSTR lpPath;
  62. lpPath = (LPSTR)GetVDMAddr (getDS(),getSI());
  63. // only in sp4
  64. #ifdef NOVELL_NETWARE_SETERRORMODE
  65. //
  66. // For removable drives check for media\volume info to avoid triggering
  67. // hard errors when no media is present. There exists win32 code
  68. // (e.g novell netware redir vdd) which is known to clobber our error
  69. // mode setting.
  70. //
  71. // 16-Jul-1997 Jonle
  72. //
  73. {
  74. UCHAR DriveType;
  75. CHAR DriveNum;
  76. DriveNum = (CHAR)getDL();
  77. DriveType = demGetPhysicalDriveType(DriveNum);
  78. if (DriveType == DRIVE_REMOVABLE || DriveType == DRIVE_CDROM) {
  79. VOLINFO VolInfo;
  80. //
  81. // if No Media in drive, the drive is still valid,
  82. // but the win32 curdir is still the old one.
  83. //
  84. if (!GetMediaId(DriveNum, &VolInfo)) {
  85. if (GetLastError() == ERROR_INVALID_DRIVE) {
  86. setCF(1);
  87. }
  88. else {
  89. setCF(0);
  90. }
  91. return;
  92. }
  93. }
  94. }
  95. #endif
  96. if (!SetCurrentDirectoryOem(lpPath) && GetLastError() == ERROR_INVALID_DRIVE) {
  97. //
  98. // Only return error if drive was invalid, the DOS doesn't check
  99. // for curdir when changing drives. Note that a number of old dos
  100. // apps will walk all of the drives, and do setdefaultdrive,
  101. // to determine the valid drives letters. The SetCurrentDirectoryOem
  102. // causes ntio to touch the drive and verify that the dir exists.
  103. // This is a significant performance problem for removable media
  104. // and network drives, but we have no choice since locking the
  105. // current dir for this drive is mandatory for winnt.
  106. //
  107. setCF(1);
  108. }
  109. else {
  110. setCF(0);
  111. }
  112. return;
  113. }
  114. /* demGetBootDrive - Get the boot drive
  115. *
  116. *
  117. * Entry - None
  118. *
  119. * Exit - CLIENT (AL) has 1 base boot drive (i.e. C=3)
  120. *
  121. * We try to read the registry value that indicates the real boot drive. This
  122. * should be the location of autoexec.bat, etc. If we can't find the key,
  123. * or if the value indicates some drive letter that is not a fixed drive,
  124. * then we use a fallback plan of just saying drive C.
  125. *
  126. */
  127. VOID demGetBootDrive (VOID)
  128. {
  129. HKEY hKey;
  130. DWORD retCode;
  131. DWORD dwType, cbData = MAX_PATH;
  132. CHAR szBootDir[MAX_PATH];
  133. BYTE Drive = 3; // default it to 'C:'
  134. retCode = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
  135. BOOTDRIVE_PATH,
  136. 0,
  137. KEY_EXECUTE, // Requesting read access.
  138. &hKey);
  139. if (retCode) {
  140. // error: can't find section
  141. goto DefaultBootDrive;
  142. }
  143. retCode = RegQueryValueEx(hKey,
  144. BOOTDRIVE_VALUE,
  145. NULL,
  146. &dwType,
  147. szBootDir,
  148. &cbData);
  149. RegCloseKey(hKey);
  150. if (retCode) {
  151. // error: can't find key
  152. goto DefaultBootDrive;
  153. }
  154. if (DPM_GetDriveType(szBootDir) != DRIVE_FIXED) {
  155. // error: drive is not a valid boot drive
  156. goto DefaultBootDrive;
  157. }
  158. Drive = (BYTE)(tolower(szBootDir[0])-'a')+1;
  159. DefaultBootDrive:
  160. setAL(Drive);
  161. return;
  162. }
  163. /* demGetDriveFreeSpace - Get free Space on the drive
  164. *
  165. *
  166. * Entry - Client (AL) Drive in question
  167. * 0 - A: etc.
  168. *
  169. * Exit -
  170. * SUCCESS
  171. * Client (CY) = 0
  172. * Client (AL) = FAT ID byte
  173. * Client (BX) = Number of free allocation units
  174. * Client (CX) = Sector size
  175. * Client (DX) = Total Number of allocation units on disk
  176. * Client (SI) = Sectors per allocation unit
  177. *
  178. * FAILURE
  179. * Client (CY) = 1
  180. * Client (AX) = Error code
  181. */
  182. VOID demGetDriveFreeSpace (VOID)
  183. {
  184. WORD SectorsPerCluster;
  185. WORD BytesPerSector;
  186. WORD FreeClusters;
  187. WORD TotalClusters;
  188. BYTE Drive;
  189. PBDS pbds;
  190. Drive = getAL();
  191. if (demGetDiskFreeSpace(Drive,
  192. &BytesPerSector,
  193. &SectorsPerCluster,
  194. &TotalClusters,
  195. &FreeClusters) == FALSE)
  196. {
  197. demClientError(INVALID_HANDLE_VALUE, (CHAR)(getAL() + 'A'));
  198. return;
  199. }
  200. if (pbds = demGetBDS(Drive)) {
  201. // if the device is a floppy, reload its bpb
  202. if (!(pbds->Flags & NON_REMOVABLE) && !demGetBPB(pbds))
  203. pbds->bpb.MediaID = 0xF8;
  204. setAL(pbds->bpb.MediaID);
  205. }
  206. else
  207. setAL(0);
  208. setBX(FreeClusters);
  209. setCX(BytesPerSector);
  210. setDX(TotalClusters);
  211. setSI(SectorsPerCluster);
  212. setCF(0);
  213. return;
  214. }
  215. //
  216. // retrieves drive type for physical drives
  217. // substd, redir drives are returned as unknown
  218. // uses same DriveType definitions as win32 GetDriveTypeW
  219. //
  220. UCHAR
  221. demGetPhysicalDriveType(
  222. UCHAR DriveNum)
  223. {
  224. return DriveNum < 26 ? PhysicalDriveTypes[DriveNum] : DRIVE_UNKNOWN;
  225. }
  226. //
  227. // worker function for DemGetDrives
  228. //
  229. UCHAR
  230. DosDeviceDriveTypeToPhysicalDriveType(
  231. UCHAR DeviceDriveType
  232. )
  233. {
  234. switch (DeviceDriveType) {
  235. case DOSDEVICE_DRIVE_REMOVABLE:
  236. return DRIVE_REMOVABLE;
  237. case DOSDEVICE_DRIVE_FIXED:
  238. return DRIVE_FIXED;
  239. case DOSDEVICE_DRIVE_CDROM:
  240. return DRIVE_CDROM;
  241. case DOSDEVICE_DRIVE_RAMDISK:
  242. return DRIVE_RAMDISK;
  243. }
  244. //case DOSDEVICE_DRIVE_REMOTE:
  245. //case DOSDEVICE_DRIVE_UNKNOWN:
  246. //default:
  247. return DRIVE_UNKNOWN;
  248. }
  249. /* demGetDrives - Get number of logical drives in the system
  250. * called by ntdos from msinit to get numio
  251. * initializes the physical drive list, which consists
  252. * of drive types for true physical drives. subst
  253. * and redir drives are classed as DRIVE_UNKNOWN.
  254. *
  255. * Entry - None
  256. *
  257. * Exit -
  258. * SUCCESS
  259. * Client (CY) = 0
  260. * Client (AL) = number of drives
  261. *
  262. * FAILURE
  263. * None
  264. */
  265. VOID demGetDrives (VOID)
  266. {
  267. NTSTATUS Status;
  268. UCHAR DriveNum;
  269. UCHAR DriveType;
  270. BOOL bCounting;
  271. PROCESS_DEVICEMAP_INFORMATION ProcessDeviceMapInfo;
  272. Status = NtQueryInformationProcess( NtCurrentProcess(),
  273. ProcessDeviceMap,
  274. &ProcessDeviceMapInfo.Query,
  275. sizeof(ProcessDeviceMapInfo.Query),
  276. NULL
  277. );
  278. if (!NT_SUCCESS(Status)) {
  279. RtlZeroMemory( &ProcessDeviceMapInfo, sizeof(ProcessDeviceMapInfo));
  280. }
  281. //
  282. // A and B are special cases.
  283. // if A doesn't exist means b also doesn't exist
  284. //
  285. PhysicalDriveTypes[0] = DosDeviceDriveTypeToPhysicalDriveType(
  286. ProcessDeviceMapInfo.Query.DriveType[0]
  287. );
  288. if (PhysicalDriveTypes[0] == DRIVE_UNKNOWN) {
  289. IsAPresent = FALSE;
  290. IsBPresent = FALSE;
  291. }
  292. PhysicalDriveTypes[1] = DosDeviceDriveTypeToPhysicalDriveType(
  293. ProcessDeviceMapInfo.Query.DriveType[1]
  294. );
  295. if (PhysicalDriveTypes[1] == DRIVE_UNKNOWN) {
  296. IsBPresent = FALSE;
  297. }
  298. DriveNum = 2;
  299. nDrives = 2;
  300. bCounting = TRUE;
  301. do {
  302. PhysicalDriveTypes[DriveNum] = DosDeviceDriveTypeToPhysicalDriveType(
  303. ProcessDeviceMapInfo.Query.DriveType[DriveNum]
  304. );
  305. if (bCounting) {
  306. if (PhysicalDriveTypes[DriveNum] == DRIVE_REMOVABLE ||
  307. PhysicalDriveTypes[DriveNum] == DRIVE_FIXED ||
  308. PhysicalDriveTypes[DriveNum] == DRIVE_CDROM ||
  309. PhysicalDriveTypes[DriveNum] == DRIVE_RAMDISK )
  310. {
  311. nDrives++;
  312. }
  313. else {
  314. bCounting = FALSE;
  315. }
  316. }
  317. } while (++DriveNum < 26);
  318. setAX(nDrives);
  319. setCF(0);
  320. return;
  321. }
  322. /* demQueryDate - Get The Date
  323. *
  324. *
  325. * Entry - None
  326. *
  327. * Exit -
  328. * SUCCESS
  329. * Client (DH) - month
  330. * Client (DL) - Day
  331. * Client (CX) - Year
  332. * Client (AL) - WeekDay
  333. *
  334. * FAILURE
  335. * Never
  336. */
  337. VOID demQueryDate (VOID)
  338. {
  339. SYSTEMTIME TimeDate;
  340. GetLocalTime(&TimeDate);
  341. setDH((UCHAR)TimeDate.wMonth);
  342. setDL((UCHAR)TimeDate.wDay);
  343. setCX(TimeDate.wYear);
  344. setAL((UCHAR)TimeDate.wDayOfWeek);
  345. return;
  346. }
  347. /* demQueryTime - Get The Time
  348. *
  349. *
  350. * Entry - None
  351. *
  352. * Exit -
  353. * SUCCESS
  354. * Client (CH) - hour
  355. * Client (CL) - minutes
  356. * Client (DH) - seconds
  357. * Client (DL) - hundredth of seconds
  358. *
  359. * FAILURE
  360. * Never
  361. */
  362. VOID demQueryTime (VOID)
  363. {
  364. SYSTEMTIME TimeDate;
  365. GetLocalTime(&TimeDate);
  366. setCH((UCHAR)TimeDate.wHour);
  367. setCL((UCHAR)TimeDate.wMinute);
  368. setDH((UCHAR)TimeDate.wSecond);
  369. setDL((UCHAR)(TimeDate.wMilliseconds/10));
  370. return;
  371. }
  372. /* demSetDate - Set The Date
  373. *
  374. *
  375. * Entry - Client (CX) - Year
  376. * Client (DH) - month
  377. * Client (DL) - Day
  378. *
  379. * Exit - SUCCESS
  380. * Client (AL) - 00
  381. *
  382. *
  383. * FAILURE
  384. * Client (AL) - ff
  385. */
  386. VOID demSetDate (VOID)
  387. {
  388. SYSTEMTIME TimeDate;
  389. GetLocalTime(&TimeDate);
  390. TimeDate.wYear = (WORD)getCX();
  391. TimeDate.wMonth = (WORD)getDH();
  392. TimeDate.wDay = (WORD)getDL();
  393. if(SetLocalTime(&TimeDate) || GetLastError() == ERROR_PRIVILEGE_NOT_HELD)
  394. setAL(0);
  395. else
  396. setAL(0xff);
  397. }
  398. /* demSetTime - Set The Time
  399. *
  400. *
  401. * Entry - Client (CH) - hour
  402. * Client (CL) - minutes
  403. * Client (DH) - seconds
  404. * Client (DL) - hundredth of seconds
  405. *
  406. * Exit - None
  407. *
  408. */
  409. VOID demSetTime (VOID)
  410. {
  411. SYSTEMTIME TimeDate;
  412. GetLocalTime(&TimeDate);
  413. TimeDate.wHour = (WORD)getCH();
  414. TimeDate.wMinute = (WORD)getCL();
  415. TimeDate.wSecond = (WORD)getDH();
  416. TimeDate.wMilliseconds = (WORD)getDL()*10;
  417. if (SetLocalTime(&TimeDate) || GetLastError() == ERROR_PRIVILEGE_NOT_HELD)
  418. setAL(0);
  419. else
  420. setAL(0xff);
  421. }
  422. /* demSetDTALocation - Set The address of variable where Disk Transfer Address
  423. * is stored in NTDOS.
  424. *
  425. *
  426. * Entry - Client (DS:AX) - DTA variable Address
  427. * Client (DS:DX) - CurrentPDB address
  428. *
  429. * Exit - None
  430. *
  431. */
  432. VOID demSetDTALocation (VOID)
  433. {
  434. PDOSWOWDATA pDosWowData;
  435. pulDTALocation = (PULONG) GetVDMAddr(getDS(),getAX());
  436. pusCurrentPDB = (PUSHORT) GetVDMAddr(getDS(),getDX());
  437. pExtendedError = (PDEMEXTERR) GetVDMAddr(getDS(),getCX());
  438. pDosWowData = (PDOSWOWDATA) GetVDMAddr(getDS(),getSI());
  439. pSFTHead = (PDOSSF) GetVDMAddr(getDS(),(WORD)pDosWowData->lpSftAddr);
  440. return;
  441. }
  442. /* demGSetMediaID - Get or set volume serial and volume label
  443. *
  444. * Entry - Client (BL) - Drive Number (0=A;1=B..etc)
  445. * Client (AL) - Get or Set (0=Get;1=Set)
  446. * Client (DS:DX) - Buffer to return information
  447. * (see VOLINFO in dosdef.h)
  448. *
  449. * Exit - SUCCESS
  450. * Client (CF) - 0
  451. *
  452. * FAILURE
  453. * Client (CF) - 1
  454. * Client (AX) - Error code
  455. *
  456. * NOTES:
  457. * Currently There is no way for us to set Volume info.
  458. */
  459. VOID demGSetMediaID (VOID)
  460. {
  461. CHAR Drive;
  462. PVOLINFO pVolInfo;
  463. // Set Volume info is not currently supported
  464. if(getAL() != 0){
  465. setCF(1);
  466. return;
  467. }
  468. pVolInfo = (PVOLINFO) GetVDMAddr (getDS(),getDX());
  469. Drive = (CHAR)getBL();
  470. if (!GetMediaId(Drive, pVolInfo)) {
  471. demClientError(INVALID_HANDLE_VALUE, (CHAR)(Drive + 'A'));
  472. return;
  473. }
  474. setCF(0);
  475. return;
  476. }
  477. //
  478. // GetMediaId
  479. //
  480. //
  481. BOOL
  482. GetMediaId(
  483. CHAR DriveNum,
  484. PVOLINFO pVolInfo
  485. )
  486. {
  487. CHAR RootPathName[] = "?:\\";
  488. CHAR achVolumeName[NT_VOLUME_NAME_SIZE];
  489. CHAR achFileSystemType[MAX_PATH];
  490. DWORD adwVolumeSerial[2],i;
  491. // Form Root path
  492. RootPathName[0] = DriveNum + 'A';
  493. // Call the supreme source of information
  494. if(!GetVolumeInformationOem( RootPathName,
  495. achVolumeName,
  496. NT_VOLUME_NAME_SIZE,
  497. adwVolumeSerial,
  498. NULL,
  499. NULL,
  500. achFileSystemType,
  501. MAX_PATH) )
  502. {
  503. return FALSE;
  504. }
  505. // Fill in user buffer. Remember to convert the null characters
  506. // to spaces in different strings.
  507. STOREDWORD(pVolInfo->ulSerialNumber,adwVolumeSerial[0]);
  508. strncpy(pVolInfo->VolumeID,achVolumeName,DOS_VOLUME_NAME_SIZE);
  509. for(i=0;i<DOS_VOLUME_NAME_SIZE;i++) {
  510. if (pVolInfo->VolumeID[i] == '\0')
  511. pVolInfo->VolumeID[i] = '\x020';
  512. }
  513. strncpy(pVolInfo->FileSystemType,achFileSystemType,FILESYS_NAME_SIZE);
  514. for(i=0;i<FILESYS_NAME_SIZE;i++) {
  515. if (pVolInfo->FileSystemType[i] == '\0')
  516. pVolInfo->VolumeID[i] = '\x020';
  517. }
  518. return TRUE;
  519. }
  520. /* demGetDPB - Get Devicr Parameter Block
  521. *
  522. * Entry - Client (AL) - Drive Number (0=A;1=B..etc)
  523. * Client (DS:DI) - Buffer to return information
  524. *
  525. * Exit - SUCCESS
  526. * Client (CF) - 0
  527. *
  528. * FAILURE
  529. * Client (CF) - 1
  530. * Client (AX) - Error code
  531. *
  532. */
  533. VOID demGetDPB(VOID)
  534. {
  535. BYTE Drive;
  536. DPB UNALIGNED *pDPB;
  537. BYTE Result;
  538. Drive = getAL();
  539. pDPB = (PDPB) GetVDMAddr(getDS(), getDI());
  540. Result = demGetDpbI(Drive, pDPB);
  541. if (Result == FAILURE) {
  542. demClientError(INVALID_HANDLE_VALUE,(CHAR)(Drive + 'A'));
  543. return;
  544. }
  545. else if (Result == NODISK){
  546. setCF(1);
  547. return;
  548. }
  549. setAX(0);
  550. setCF(0);
  551. }
  552. /* demGetDPBI - Worker for GetDPB and GetDPBList
  553. *
  554. * Entry -
  555. * Drive -- Drive Number (0=A;1=B..etc)
  556. * pDPB -- pointer to the location to store the dpb
  557. *
  558. * Exit - SUCCESS
  559. * returns success, fills in DPB
  560. * FAILURE
  561. * returns FAILURE or NODISK
  562. */
  563. BYTE demGetDpbI(BYTE Drive, DPB UNALIGNED *pDPB)
  564. {
  565. WORD SectorSize, ClusterSize, FreeClusters, TotalClusters;
  566. PBDS pbds;
  567. WORD DirsPerSector;
  568. if (demGetDiskFreeSpace(Drive,
  569. &SectorSize,
  570. &ClusterSize,
  571. &TotalClusters,
  572. &FreeClusters
  573. ))
  574. {
  575. pDPB->Next = (PDPB) 0xFFFFFFFF;
  576. pDPB->SectorSize = SectorSize;
  577. pDPB->FreeClusters = FreeClusters;
  578. pDPB->MaxCluster = TotalClusters + 1;
  579. pDPB->ClusterMask = ClusterSize - 1;
  580. pDPB->ClusterShift = 0;
  581. pDPB->DriveNum = pDPB->Unit = Drive;
  582. while ((ClusterSize & 1) == 0) {
  583. ClusterSize >>= 1;
  584. pDPB->ClusterShift++;
  585. }
  586. if (pbds = demGetBDS(Drive)) {
  587. // if the device is a floppy, reload its bpb
  588. if (!(pbds->Flags & NON_REMOVABLE) && !demGetBPB(pbds)) {
  589. return NODISK;
  590. }
  591. pDPB->MediaID = pbds->bpb.MediaID;
  592. pDPB->FATSector = pbds->bpb.ReservedSectors;
  593. pDPB->FATs = pbds->bpb.FATs;
  594. pDPB->RootDirs = pbds->bpb.RootDirs;
  595. pDPB->FATSize = pbds->bpb.FATSize;
  596. pDPB->DirSector = pbds->bpb.FATs * pbds->bpb.FATSize +
  597. pDPB->FATSector;
  598. DirsPerSector = pDPB->SectorSize >> DOS_DIR_ENTRY_LENGTH_SHIFT_COUNT;
  599. pDPB->FirstDataSector = pDPB->DirSector +
  600. ((pDPB->RootDirs + DirsPerSector - 1) /
  601. DirsPerSector);
  602. pDPB->DriveAddr = 0x123456;
  603. pDPB->FirstAccess = 10;
  604. }
  605. // if we don't know the drive, fake a DPB for it
  606. else {
  607. pDPB->MediaID = 0xF8;
  608. pDPB->FATSector = 1;
  609. pDPB->FATs = 2;
  610. pDPB->RootDirs = 63;
  611. pDPB->FATSize = 512;
  612. pDPB->DirSector = 1;
  613. pDPB->DriveAddr = 1212L * 64L * 1024L + 1212L;
  614. pDPB->FirstAccess = 10;
  615. }
  616. return SUCCESS;
  617. }
  618. else {
  619. return FAILURE;
  620. }
  621. }
  622. /* demGetComputerName - Get computer name
  623. *
  624. * Entry -
  625. * Client (DS:DX) - 16 byte buffer
  626. *
  627. * Exit - Always Succeeds
  628. * DS:DX is filled with the computer name (NULL terminated).
  629. */
  630. VOID demGetComputerName (VOID)
  631. {
  632. PCHAR pDOSBuffer;
  633. CHAR ComputerName[MAX_COMPUTERNAME_LENGTH+1];
  634. DWORD BufferSize = MAX_COMPUTERNAME_LENGTH+1;
  635. ULONG i;
  636. pDOSBuffer = (PCHAR) GetVDMAddr(getDS(), getDX());
  637. if (GetComputerNameOem(ComputerName, &BufferSize)){
  638. if (BufferSize <= 15){
  639. for (i = BufferSize ; i < 15 ; i++)
  640. ComputerName [i] = ' ';
  641. ComputerName[15] = '\0';
  642. strcpy (pDOSBuffer, ComputerName);
  643. }
  644. else{
  645. strncpy (pDOSBuffer, ComputerName, 15);
  646. pDOSBuffer [15] = '\0';
  647. }
  648. setCX(0x1ff);
  649. }
  650. else {
  651. *pDOSBuffer = '\0';
  652. setCH(0);
  653. }
  654. }
  655. #define APPS_SPACE_LIMIT 999990*1024 //999990kb to be on the safe side
  656. BOOL demGetDiskFreeSpace(
  657. BYTE Drive,
  658. WORD * BytesPerSector,
  659. WORD * SectorsPerCluster,
  660. WORD * TotalClusters,
  661. WORD * FreeClusters
  662. )
  663. {
  664. CHAR chRoot[]="?:\\";
  665. DWORD dwBytesPerSector;
  666. DWORD dwSectorsPerCluster;
  667. DWORD dwTotalClusters;
  668. DWORD dwFreeClusters;
  669. DWORD dwLostFreeSectors;
  670. DWORD dwLostTotalSectors;
  671. DWORD dwNewSectorPerCluster;
  672. ULONG ulTotal,ulTemp;
  673. // sudeepb 22-Jun-1993;
  674. // Please read this routine with an empty stomach.
  675. // The most common mistake all the apps do when calculating total
  676. // disk space or free space is to neglect overflow. Excel/Winword/Ppnt
  677. // and lots of other apps use "mul cx mul bx" never taking care
  678. // of first multiplication which can overflow. Hence this routine makes
  679. // sure that first multiplication will never overflow by fixing
  680. // appropriate values. Secondly, all these above apps use signed long
  681. // to deal with these free spaces. This puts a limit of 2Gb-1 on
  682. // the final outcome of the multiplication. If its above this the setup
  683. // fails. So here we have to make sure that total should never exceed
  684. // 0x7fffffff. Another bug in above setup program's that if you return
  685. // anything more than 999,999KB then they try to put "999,999KB+\0", but
  686. // unfortunately the buffer is only 10 bytes. Hence it corrupts something
  687. // with the last byte. In our case that is low byte of a segment which
  688. // it later tries to pop and GPF. This shrinks the maximum size that
  689. // we can return is 999,999KB.
  690. chRoot[0]=(CHAR)('A'+ Drive);
  691. if (GetDiskFreeSpaceOem(chRoot,
  692. &dwSectorsPerCluster,
  693. &dwBytesPerSector,
  694. &dwFreeClusters,
  695. &dwTotalClusters) == FALSE)
  696. return FALSE;
  697. /*
  698. * HPFS and NTFS can give num clusters over dos limit
  699. * For these cases increase SectorPerCluster and lower
  700. * cluster number accordingly. If the disk is very large
  701. * even this isn't enuf, so pass max sizes that dos can
  702. * handle.
  703. *
  704. * The following algorithm is accurate within 1 cluster
  705. * (final figure)
  706. *
  707. */
  708. dwLostFreeSectors = dwLostTotalSectors = 0;
  709. while (dwTotalClusters + dwLostTotalSectors/dwSectorsPerCluster > 0xFFFF)
  710. {
  711. if (dwSectorsPerCluster > 0x7FFF)
  712. {
  713. dwTotalClusters = 0xFFFF;
  714. if (dwFreeClusters > 0xFFFF)
  715. dwFreeClusters = 0xFFFF;
  716. break;
  717. }
  718. if (dwFreeClusters & 1) {
  719. dwLostFreeSectors += dwSectorsPerCluster;
  720. }
  721. if (dwTotalClusters & 1) {
  722. dwLostTotalSectors += dwSectorsPerCluster;
  723. }
  724. dwSectorsPerCluster <<= 1;
  725. dwFreeClusters >>= 1;
  726. dwTotalClusters >>= 1;
  727. }
  728. if (dwTotalClusters < 0xFFFF) {
  729. dwFreeClusters += dwLostFreeSectors/dwSectorsPerCluster;
  730. dwTotalClusters += dwLostTotalSectors/dwSectorsPerCluster;
  731. }
  732. if ((dwNewSectorPerCluster = (0xffff / dwBytesPerSector)) < dwSectorsPerCluster)
  733. dwSectorsPerCluster = dwNewSectorPerCluster;
  734. // finally check for 999,999kb
  735. ulTemp = (ULONG)((USHORT)dwSectorsPerCluster * (USHORT)dwBytesPerSector);
  736. // check that total space does'nt exceed 999,999kb
  737. ulTotal = ulTemp * (USHORT)dwTotalClusters;
  738. if (ulTotal > APPS_SPACE_LIMIT){
  739. if (ulTemp <= APPS_SPACE_LIMIT)
  740. dwTotalClusters = APPS_SPACE_LIMIT / ulTemp;
  741. else
  742. dwTotalClusters = 1;
  743. }
  744. ulTotal = ulTemp * (USHORT)dwFreeClusters;
  745. if (ulTotal > APPS_SPACE_LIMIT) {
  746. if (ulTemp <= APPS_SPACE_LIMIT)
  747. dwFreeClusters = APPS_SPACE_LIMIT / ulTemp;
  748. else
  749. dwFreeClusters = 1;
  750. }
  751. *BytesPerSector = (WORD) dwBytesPerSector;
  752. *SectorsPerCluster = (WORD) dwSectorsPerCluster;
  753. *TotalClusters = (WORD) dwTotalClusters;
  754. *FreeClusters = (WORD) dwFreeClusters;
  755. return TRUE;
  756. }
  757. /* demGetDPBList - Create the list of dpbs
  758. *
  759. * Entry -
  760. * Client(ES:BP) - points to destination for the dpb list
  761. * Exit - SUCCESS
  762. * Client (BP) - points to first byte past dpb list
  763. * FAILURE
  764. * Client (BP) unchanged
  765. *
  766. * Notes:
  767. * For performance reasons, only the drive and unit fields are
  768. * filled in. The only application I know of that depends on the
  769. * dpb list is go.exe (a shareware app installer). Even if we filled
  770. * in the other fields they would likely be incorrect when the app
  771. * looked at them, since ntdos.sys never updates the pdbs in the pdb
  772. * list
  773. */
  774. VOID demGetDPBList (VOID)
  775. {
  776. UCHAR DriveType;
  777. UCHAR DriveNum;
  778. DPB UNALIGNED *pDpb;
  779. USHORT usDpbOffset, usDpbSeg;
  780. usDpbOffset = getBP();
  781. usDpbSeg = getES();
  782. pDpb = (PDPB)GetVDMAddr(usDpbSeg, usDpbOffset);
  783. //
  784. // Iterate over all of the drive letters.
  785. //
  786. DriveNum = 0;
  787. do {
  788. DriveType = demGetPhysicalDriveType(DriveNum);
  789. //
  790. // Only include the local non cd rom drives ?? ramdisk ???
  791. //
  792. if ((DriveType == DRIVE_REMOVABLE) || (DriveType == DRIVE_FIXED)) {
  793. //
  794. // Fake the Dpb for the drive
  795. //
  796. pDpb->DriveNum = pDpb->Unit = DriveNum;
  797. //
  798. // Link it to the next dpb
  799. //
  800. usDpbOffset += sizeof(DPB);
  801. pDpb->Next = (PDPB)(((ULONG)usDpbSeg) << 16 | usDpbOffset);
  802. //
  803. // Advance to the next dpb
  804. //
  805. pDpb += 1;
  806. ASSERT(usDpbOffset < 0xFFFF);
  807. }
  808. } while (++DriveNum < 26);
  809. //
  810. // Terminate the list if necessary
  811. //
  812. if (usDpbOffset != getBP()) {
  813. pDpb -= 1;
  814. pDpb->Next = (PDPB)-1;
  815. }
  816. //
  817. // Return the new free space pointer
  818. //
  819. setBP(usDpbOffset);
  820. }