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.

402 lines
11 KiB

  1. /* demerror.c - Error handling routines of DEM
  2. *
  3. * demSetHardErrorInfo
  4. * demClientError
  5. * demRetry
  6. *
  7. * Modification History:
  8. *
  9. * Sudeepb 27-Nov-1991 Created
  10. */
  11. #include "dem.h"
  12. #include "demmsg.h"
  13. #include <softpc.h>
  14. PVHE pHardErrPacket;
  15. PSYSDEV pDeviceChain;
  16. SAVEDEMWORLD RetryInfo;
  17. CHAR GetDriveLetterByHandle(HANDLE hFile);
  18. VOID SubstituteDeviceName( PUNICODE_STRING InputDeviceName,
  19. LPSTR OutputDriveLetter);
  20. /* demSetHardErrorInfo - Store away harderr related address of DOSKRNL
  21. *
  22. * Entry
  23. * Client (DS:DX) - VHE structure
  24. *
  25. * Exit
  26. * None
  27. */
  28. VOID demSetHardErrorInfo (VOID)
  29. {
  30. pHardErrPacket = (PVHE) GetVDMAddr (getDS(),getDX());
  31. pDeviceChain = (PSYSDEV) GetVDMAddr(getDS(),getBX());
  32. return;
  33. }
  34. /* demRetry - Retry the operation which last resulted in hard error
  35. *
  36. * Entry
  37. * None
  38. *
  39. * Exit
  40. * None
  41. */
  42. VOID demRetry (VOID)
  43. {
  44. ULONG iSvc;
  45. demRestoreHardErrInfo ();
  46. iSvc = CurrentISVC;
  47. #if DBG
  48. if(iSvc < SVC_DEMLASTSVC && (fShowSVCMsg & DEMSVCTRACE) &&
  49. apfnSVC[iSvc] != demNotYetImplemented){
  50. sprintf(demDebugBuffer,"demRetry:Retrying %s\n\tAX=%.4x BX=%.4x CX=%.4x DX=%.4x DI=%.4x SI=%.4x\n",
  51. aSVCNames[iSvc],getAX(),getBX(),getCX(),getDX(),getDI(),getSI());
  52. OutputDebugStringOem(demDebugBuffer);
  53. sprintf(demDebugBuffer,"\tCS=%.4x IP=%.4x DS=%.4x ES=%.4x SS=%.4x SP=%.4x BP=%.4x\n",
  54. getCS(),getIP(), getDS(),getES(),getSS(),getSP(),getBP());
  55. OutputDebugStringOem(demDebugBuffer);
  56. }
  57. if (iSvc >= SVC_DEMLASTSVC || apfnSVC[iSvc] == demNotYetImplemented ){
  58. ASSERT(FALSE);
  59. setCF(1);
  60. setAX(0xff);
  61. return;
  62. }
  63. #endif // DBG
  64. (apfnSVC [iSvc])();
  65. #if DBG
  66. if((fShowSVCMsg & DEMSVCTRACE)){
  67. sprintf(demDebugBuffer,"demRetry:After %s\n\tAX=%.4x BX=%.4x CX=%.4x DX=%.4x DI=%.4x SI=%.4x\n",
  68. aSVCNames[iSvc],getAX(),getBX(),getCX(),getDX(),getDI(),getSI());
  69. OutputDebugStringOem(demDebugBuffer);
  70. sprintf(demDebugBuffer,"\tCS=%.4x IP=%.4x DS=%.4x ES=%.4x SS=%.4x SP=%.4x BP=%.4x CF=%x\n",
  71. getCS(),getIP(), getDS(),getES(),getSS(),getSP(),getBP(),getCF());
  72. OutputDebugStringOem(demDebugBuffer);
  73. }
  74. #endif
  75. return;
  76. }
  77. /* demClientError - Update client registers to signal error
  78. *
  79. * Entry
  80. * HANDLE hFile; file handle , if none == -1
  81. * char chDrive; drive letter , if none == -1
  82. *
  83. * Exit
  84. * Client (CF) = 1
  85. * Client (AX) = Error Code
  86. *
  87. * Notes
  88. * the following errors cause hard errors
  89. * errors above ERROR_GEN_FAILURE are mapped to general fail by the DOS
  90. *
  91. *
  92. * ERROR_WRITE_PROTECT 19L
  93. * ERROR_BAD_UNIT 20L
  94. * ERROR_NOT_READY 21L
  95. * ERROR_BAD_COMMAND 22L
  96. * ERROR_CRC 23L
  97. * ERROR_BAD_LENGTH 24L
  98. * ERROR_SEEK 25L
  99. * ERROR_NOT_DOS_DISK 26L
  100. * ERROR_SECTOR_NOT_FOUND 27L
  101. * ERROR_OUT_OF_PAPER 28L
  102. * ERROR_WRITE_FAULT 29L
  103. * ERROR_READ_FAULT 30L
  104. * ERROR_GEN_FAILURE 31L
  105. * ERROR_WRONG_DISK 34l
  106. * ERROR_NO_MEDIA_IN_DRIVE 1112l
  107. * #ifdef JAPAN
  108. * ERROR_UNRECOGNIZED_MEDIA 1785L
  109. * #ifdef JAPAN
  110. *
  111. */
  112. VOID demClientError (HANDLE hFile, CHAR chDrive)
  113. {
  114. demClientErrorEx (hFile, chDrive, TRUE);
  115. }
  116. ULONG demClientErrorEx (HANDLE hFile, CHAR chDrive, BOOL bSetRegs)
  117. {
  118. ULONG ulErrCode;
  119. if(!(ulErrCode = GetLastError()))
  120. ulErrCode = ERROR_ACCESS_DENIED;
  121. #ifdef JAPAN
  122. if ((ulErrCode < ERROR_WRITE_PROTECT || ulErrCode > ERROR_GEN_FAILURE)
  123. && ulErrCode != ERROR_WRONG_DISK && ulErrCode != ERROR_UNRECOGNIZED_MEDIA)
  124. #else // !JAPAN
  125. if ((ulErrCode < ERROR_WRITE_PROTECT || ulErrCode > ERROR_GEN_FAILURE)
  126. && ulErrCode != ERROR_WRONG_DISK )
  127. #endif // !JAPAN
  128. {
  129. #if DBG
  130. if (fShowSVCMsg & DEMERROR) {
  131. sprintf(demDebugBuffer,"demClientErr: ErrCode=%ld\n", ulErrCode);
  132. OutputDebugStringOem(demDebugBuffer);
  133. }
  134. #endif
  135. if (bSetRegs) {
  136. setAX((USHORT)ulErrCode);
  137. }
  138. }
  139. else { // handle hard error case
  140. if (ulErrCode > ERROR_GEN_FAILURE)
  141. ulErrCode = ERROR_GEN_FAILURE;
  142. // Set the hard error flag
  143. pHardErrPacket->vhe_fbInt24 = 1;
  144. // Get the drive letter
  145. if (hFile != INVALID_HANDLE_VALUE)
  146. chDrive = GetDriveLetterByHandle(hFile);
  147. pHardErrPacket->vhe_bDriveNum = chDrive == -1
  148. ? -1 : toupper(chDrive) - 'A';
  149. // convert error code to i24 based error.
  150. ulErrCode -= ERROR_WRITE_PROTECT;
  151. pHardErrPacket->vhe_HrdErrCode = (UCHAR)ulErrCode;
  152. #if DBG
  153. if (fShowSVCMsg & DEMERROR) {
  154. sprintf(demDebugBuffer,
  155. "demClientErr HRDERR: DriveNum=%ld ErrCode=%ld\n",
  156. (DWORD)pHardErrPacket->vhe_bDriveNum,
  157. (DWORD)pHardErrPacket->vhe_HrdErrCode);
  158. OutputDebugStringOem(demDebugBuffer);
  159. }
  160. #endif
  161. // Save Away Information for possible retry operation
  162. demSaveHardErrInfo ();
  163. }
  164. if (bSetRegs)
  165. setCF(1);
  166. return (ulErrCode);
  167. }
  168. /*
  169. * GetDriveLetterByHandle
  170. *
  171. * retrieves the drive letter for the file handle
  172. * if its a remote drive or fails returns -1
  173. */
  174. CHAR GetDriveLetterByHandle(HANDLE hFile)
  175. {
  176. NTSTATUS Status;
  177. ULONG ul;
  178. ANSI_STRING AnsiString;
  179. FILE_FS_DEVICE_INFORMATION DeviceInfo;
  180. IO_STATUS_BLOCK IoStatusBlock;
  181. POBJECT_NAME_INFORMATION pObNameInfo;
  182. CHAR Buffer[MAX_PATH+sizeof(OBJECT_NAME_INFORMATION)];
  183. CHAR ch;
  184. // if a remote drive return -1 for drive letter
  185. Status = NtQueryVolumeInformationFile(
  186. hFile,
  187. &IoStatusBlock,
  188. &DeviceInfo,
  189. sizeof(DeviceInfo),
  190. FileFsDeviceInformation );
  191. if (NT_SUCCESS(Status) &&
  192. DeviceInfo.Characteristics & FILE_REMOTE_DEVICE )
  193. return (CHAR) -1;
  194. // get the name
  195. pObNameInfo = (POBJECT_NAME_INFORMATION)Buffer;
  196. Status = NtQueryObject( // get len of name
  197. hFile,
  198. ObjectNameInformation,
  199. pObNameInfo,
  200. sizeof(Buffer),
  201. &ul);
  202. if (!NT_SUCCESS(Status))
  203. return -1;
  204. RtlUnicodeStringToAnsiString(&AnsiString, &(pObNameInfo->Name), TRUE);
  205. if (strstr(AnsiString.Buffer,"\\Device") == AnsiString.Buffer)
  206. SubstituteDeviceName(&(pObNameInfo->Name), AnsiString.Buffer);
  207. ch = AnsiString.Buffer[0];
  208. RtlFreeAnsiString(&AnsiString);
  209. return ch;
  210. }
  211. static WCHAR wszDosDevices[] = L"\\DosDevices\\?:";
  212. /*
  213. * SubstituteDeviceName
  214. *
  215. * lifted this code from the user\harderror hard error thread
  216. */
  217. VOID SubstituteDeviceName( PUNICODE_STRING InputDeviceName,
  218. LPSTR OutputDriveLetter )
  219. {
  220. UNICODE_STRING LinkName;
  221. UNICODE_STRING DeviceName;
  222. OBJECT_ATTRIBUTES Obja;
  223. HANDLE LinkHandle;
  224. NTSTATUS Status;
  225. ULONG i;
  226. PWCHAR p;
  227. PWCHAR pSlash = L"\\";
  228. WCHAR DeviceNameBuffer[MAXIMUM_FILENAME_LENGTH];
  229. /*
  230. * Ensure have trailing backslash
  231. */
  232. if (InputDeviceName->Buffer[(InputDeviceName->Length >>1) - 1] != *pSlash)
  233. RtlAppendUnicodeToString(InputDeviceName, pSlash);
  234. RtlInitUnicodeString(&LinkName,wszDosDevices);
  235. p = (PWCHAR)LinkName.Buffer;
  236. p = p+12;
  237. for(i=0;i<26;i++){
  238. *p = (WCHAR)'A' + (WCHAR)i;
  239. InitializeObjectAttributes(
  240. &Obja,
  241. &LinkName,
  242. OBJ_CASE_INSENSITIVE,
  243. NULL,
  244. NULL
  245. );
  246. Status = NtOpenSymbolicLinkObject(
  247. &LinkHandle,
  248. SYMBOLIC_LINK_QUERY,
  249. &Obja
  250. );
  251. if (NT_SUCCESS( Status )) {
  252. //
  253. // Open succeeded, Now get the link value
  254. //
  255. DeviceName.Length = 0;
  256. DeviceName.MaximumLength = sizeof(DeviceNameBuffer);
  257. DeviceName.Buffer = DeviceNameBuffer;
  258. Status = NtQuerySymbolicLinkObject(
  259. LinkHandle,
  260. &DeviceName,
  261. NULL
  262. );
  263. NtClose(LinkHandle);
  264. if ( NT_SUCCESS(Status) ) {
  265. if (DeviceName.Buffer[(DeviceName.Length >>1) - 1] != *pSlash)
  266. RtlAppendUnicodeToString(&DeviceName, pSlash);
  267. #ifdef JAPAN
  268. // #6197 compare only device name
  269. if (InputDeviceName->Length > DeviceName.Length)
  270. InputDeviceName->Length = DeviceName.Length;
  271. #endif // JAPAN
  272. if ( RtlEqualUnicodeString(InputDeviceName,&DeviceName,TRUE) )
  273. {
  274. OutputDriveLetter[0]='A'+(WCHAR)i;
  275. OutputDriveLetter[1]='\0';
  276. return;
  277. }
  278. }
  279. }
  280. }
  281. // just in case we don't find it
  282. OutputDriveLetter[0]=(char)-1;
  283. OutputDriveLetter[1]='\0';
  284. return;
  285. }
  286. /* demSaveHardErrInfo
  287. * demRestoreHardErrInfo
  288. *
  289. * These two routines are used to preserve all the DOSKRNL registers
  290. * which will be needed to retry an SVC handler, in case user opts for
  291. * retry in harderr popup. This is a preferred way to handle retry
  292. * as it gives the DOSKRNL code the freedom to trash any register
  293. * even though it might have to retry the operation. It saves lots
  294. * of code bytes in heavily used DOS macro "HrdSVC".
  295. *
  296. * Entry
  297. * None
  298. *
  299. * Exit
  300. * None
  301. *
  302. * Notes
  303. *
  304. * 1. Doing things this way means, DOSKRNL cannot change the
  305. * registers for retry. Under any circumstances, i can't think
  306. * why it would need to do that anyway.
  307. *
  308. * 2. This mechanism also assumes that DOSKRNL never uses CS,IP,SS,SP
  309. * for passing SVC parameters.
  310. *
  311. * 3. DOS does'nt allow int24 hookers to make any call which comes
  312. * to DEM, so using CurrentISVC is safe.
  313. *
  314. * 4. If an SVC handler can pssibly return a hard error it should never
  315. * modify the client registers.
  316. */
  317. VOID demSaveHardErrInfo (VOID)
  318. {
  319. RetryInfo.ax = getAX();
  320. RetryInfo.bx = getBX();
  321. RetryInfo.cx = getCX();
  322. RetryInfo.dx = getDX();
  323. RetryInfo.ds = getDS();
  324. RetryInfo.es = getES();
  325. RetryInfo.si = getSI();
  326. RetryInfo.di = getDI();
  327. RetryInfo.bp = getBP();
  328. RetryInfo.iSVC = CurrentISVC;
  329. return;
  330. }
  331. VOID demRestoreHardErrInfo (VOID)
  332. {
  333. setAX(RetryInfo.ax);
  334. setBX(RetryInfo.bx);
  335. setCX(RetryInfo.cx);
  336. setDX(RetryInfo.dx);
  337. setDS(RetryInfo.ds);
  338. setES(RetryInfo.es);
  339. setSI(RetryInfo.si);
  340. setDI(RetryInfo.di);
  341. setBP(RetryInfo.bp);
  342. CurrentISVC = RetryInfo.iSVC;
  343. return;
  344. }
  345.