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.

813 lines
21 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. srvstat.c
  5. Abstract:
  6. Contains data and modules for error handling.
  7. Author:
  8. David Treadwell (davidtr) 10-May-1990
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #include "srvstat.tmh"
  13. #pragma hdrstop
  14. #define DISK_HARD_ERROR 0x38
  15. VOID
  16. MapErrorForDosClient (
  17. IN PWORK_CONTEXT WorkContext,
  18. IN ULONG Error,
  19. OUT PUSHORT DosError,
  20. OUT PUCHAR DosErrorClass
  21. );
  22. #ifdef ALLOC_PRAGMA
  23. #pragma alloc_text( PAGE, _SrvSetSmbError2 )
  24. #pragma alloc_text( PAGE, MapErrorForDosClient )
  25. #pragma alloc_text( PAGE8FIL, SrvSetBufferOverflowError )
  26. #if DBG
  27. #pragma alloc_text( PAGE, SrvLogBuffer )
  28. #endif
  29. #endif
  30. VOID
  31. _SrvSetSmbError2 (
  32. IN PWORK_CONTEXT WorkContext,
  33. IN NTSTATUS Status,
  34. IN BOOLEAN HeaderOnly,
  35. IN ULONG Line,
  36. IN PCHAR File
  37. )
  38. /*++
  39. Routine Description:
  40. Loads error information into a response SMB. If the client is
  41. NT, the status is placed directly into the outgoing SMB. If
  42. the client is DOS or OS/2 and this is a special status code that
  43. has the DOS/OS|2/SMB error code embedded, put the code and class
  44. from the status code into the outgoing SMB. If that doesn't work,
  45. use RtlNtStatusToDosError to try to map the status to an OS/2
  46. error code, then map to DOS if necessary. If we still haven't
  47. mapped it, use our own array to try to find a mapping. And,
  48. finally, if that doesn't work, return the generic error code.
  49. Arguments:
  50. WorkContext - Supplies a pointer to the work context block for the
  51. current SMB. In particular, the Connection block pointer is
  52. used to find the negotiated dialect for the connection, and
  53. the ResponseHeader and ResponseParameter pointers are used
  54. to determine where to write the error information.
  55. Status - Supplies an NT status code.
  56. Return Value:
  57. None.
  58. --*/
  59. {
  60. PSMB_HEADER header = WorkContext->ResponseHeader;
  61. PSMB_PARAMS params = WorkContext->ResponseParameters;
  62. SMB_DIALECT smbDialect;
  63. ULONG error;
  64. CCHAR errorClass;
  65. USHORT errorCode;
  66. USHORT flags;
  67. PAGED_CODE( );
  68. IF_DEBUG( ERRORS ) { \
  69. KdPrint(( "SrvSetSmbError %X (%s,%d)\n",Status,File,Line )); \
  70. }
  71. smbDialect = WorkContext->Connection->SmbDialect;
  72. //
  73. // Update the SMB body, if necessary.
  74. //
  75. if ( !HeaderOnly ) {
  76. params->WordCount = 0;
  77. SmbPutUshort( &params->ByteCount, 0 );
  78. WorkContext->ResponseParameters = (PVOID)(params + 1);
  79. }
  80. //
  81. // If the status code is a real NT status, then either return it
  82. // directly to the client or map it to a Win32 error code.
  83. //
  84. if ( !SrvIsSrvStatus( Status ) ) {
  85. //
  86. // Map STATUS_INSUFFICIENT_RESOURCES to the server form. If we
  87. // get an insufficient resources error from the system, we
  88. // report it as a server shortage. This helps keep things
  89. // clearer for the client.
  90. //
  91. if ( Status == STATUS_INSUFFICIENT_RESOURCES ) {
  92. Status = STATUS_INSUFF_SERVER_RESOURCES;
  93. }
  94. if ( CLIENT_CAPABLE_OF(NT_STATUS, WorkContext->Connection) ) {
  95. //
  96. // The client understands NT status codes. Load the status
  97. // directly into the SMB header.
  98. //
  99. SmbPutUlong( (PULONG)&header->ErrorClass, Status );
  100. flags = SmbGetAlignedUshort( &header->Flags2 ) | SMB_FLAGS2_NT_STATUS;
  101. SmbPutAlignedUshort( &header->Flags2, flags );
  102. return;
  103. }
  104. //
  105. // This is an NT status, but the client doesn't understand them.
  106. // Indicate that we're not returning an NT status code. Then
  107. // map the NT status to a Win32 status. Some NT status codes
  108. // require special mapping.
  109. //
  110. flags = SmbGetAlignedUshort( &header->Flags2 ) & ~SMB_FLAGS2_NT_STATUS;
  111. SmbPutAlignedUshort( &header->Flags2, flags );
  112. switch ( Status ) {
  113. case STATUS_TIMEOUT:
  114. header->ErrorClass = SMB_ERR_CLASS_SERVER;
  115. SmbPutUshort( &header->Error, SMB_ERR_TIMEOUT );
  116. return;
  117. case STATUS_INVALID_SYSTEM_SERVICE:
  118. //
  119. // This status code is returned by XACTSRV when an invalid API
  120. // number is specified.
  121. //
  122. header->ErrorClass = SMB_ERR_CLASS_DOS;
  123. SmbPutUshort( &header->Error, NERR_InvalidAPI );
  124. return;
  125. case STATUS_PATH_NOT_COVERED:
  126. //
  127. // This code indicates that the server does not cover this part
  128. // of the DFS namespace.
  129. //
  130. header->ErrorClass = SMB_ERR_CLASS_SERVER;
  131. SmbPutUshort( &header->Error, SMB_ERR_BAD_PATH );
  132. return;
  133. default:
  134. //
  135. // This is not a special status code. Map the NT status
  136. // code to a Win32 error code. If there is no mapping,
  137. // return the generic SMB error.
  138. //
  139. error = RtlNtStatusToDosErrorNoTeb( Status );
  140. if ( error == ERROR_MR_MID_NOT_FOUND || error == (ULONG)Status ) {
  141. header->ErrorClass = SMB_ERR_CLASS_HARDWARE;
  142. SmbPutUshort( &header->Error, SMB_ERR_GENERAL );
  143. return;
  144. }
  145. //
  146. // We now have a Win32 error. Drop through to the code
  147. // that maps Win32 errors for downlevel clients.
  148. //
  149. break;
  150. }
  151. } else {
  152. //
  153. // The status code is not an NT status. Deal with it based on
  154. // the error class.
  155. //
  156. errorClass = SrvErrorClass( Status );
  157. //
  158. // Clear the FLAGS2_NT_STATUS bit to indicate that this is *not* an
  159. // NT_STATUS
  160. //
  161. flags = SmbGetAlignedUshort( &header->Flags2 ) & ~SMB_FLAGS2_NT_STATUS;
  162. SmbPutAlignedUshort( &header->Flags2, flags );
  163. switch ( errorClass ) {
  164. case SMB_ERR_CLASS_DOS:
  165. case SMB_ERR_CLASS_SERVER:
  166. case SMB_ERR_CLASS_HARDWARE:
  167. //
  168. // The status code has the SMB error class and code
  169. // embedded.
  170. //
  171. header->ErrorClass = errorClass;
  172. //
  173. // Because SMB_ERR_NO_SUPPORT in the SERVER class is 0xFFFF
  174. // (16 bits), we must special-case for it. The code
  175. // SMB_ERR_NO_SUPPORT_INTERNAL in the error code field of
  176. // the status, along with class = 2 (SERVER), indicates that
  177. // we should use SMB_ERR_NO_SUPPORT.
  178. //
  179. if ( errorClass == SMB_ERR_CLASS_SERVER &&
  180. SrvErrorCode( Status ) == SMB_ERR_NO_SUPPORT_INTERNAL ) {
  181. SmbPutUshort( &header->Error, SMB_ERR_NO_SUPPORT );
  182. } else {
  183. SmbPutUshort( &header->Error, SrvErrorCode( Status ) );
  184. }
  185. return;
  186. case 0xF:
  187. //
  188. // The error code is defined in OS/2 but not in the SMB
  189. // protocol. If the client is speaking a dialect after
  190. // LanMan 1.0 and is not a DOS client, send the OS/2 error
  191. // code. Otherwise, send the generic SMB error code.
  192. //
  193. if ( smbDialect <= SmbDialectLanMan10 &&
  194. !IS_DOS_DIALECT(smbDialect) ) {
  195. header->ErrorClass = SMB_ERR_CLASS_DOS;
  196. SmbPutUshort( &header->Error, SrvErrorCode( Status ) );
  197. } else {
  198. header->ErrorClass = SMB_ERR_CLASS_HARDWARE;
  199. SmbPutUshort( &header->Error, SMB_ERR_GENERAL );
  200. }
  201. return;
  202. case 0xE:
  203. //
  204. // This is a Win32 error. Drop through to the code that
  205. // maps Win32 errors for downlevel clients.
  206. //
  207. error = SrvErrorCode( Status );
  208. break;
  209. case 0x0:
  210. default:
  211. //
  212. // This is an internal server error (class 0) or some other
  213. // undefined class. We should never get here. But since we
  214. // did, return the generic error.
  215. //
  216. KdPrint(( "SRV: Unmapped error: %lx\n", Status ));
  217. header->ErrorClass = SMB_ERR_CLASS_HARDWARE;
  218. SmbPutUshort( &header->Error, SMB_ERR_GENERAL );
  219. return;
  220. }
  221. }
  222. //
  223. // At this point we have a Win32 error code and need to map it for
  224. // the downlevel client. Some errors need to be specially mapped.
  225. //
  226. errorClass = SMB_ERR_CLASS_DOS;
  227. switch ( error ) {
  228. case ERROR_NOT_ENOUGH_SERVER_MEMORY:
  229. error = ERROR_NOT_ENOUGH_MEMORY;
  230. break;
  231. case ERROR_INSUFFICIENT_BUFFER:
  232. error = ERROR_BUFFER_OVERFLOW;
  233. break;
  234. case ERROR_ACCOUNT_LOCKED_OUT:
  235. case ERROR_PRIVILEGE_NOT_HELD:
  236. case ERROR_NO_SUCH_USER:
  237. case ERROR_LOGON_FAILURE:
  238. case ERROR_LOGON_TYPE_NOT_GRANTED:
  239. case ERROR_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT:
  240. case ERROR_NOLOGON_WORKSTATION_TRUST_ACCOUNT:
  241. case ERROR_NOLOGON_SERVER_TRUST_ACCOUNT:
  242. case ERROR_TRUSTED_RELATIONSHIP_FAILURE:
  243. case ERROR_TRUSTED_DOMAIN_FAILURE:
  244. case ERROR_TRUST_FAILURE:
  245. case ERROR_NO_TRUST_SAM_ACCOUNT:
  246. case ERROR_NO_TRUST_LSA_SECRET:
  247. error = ERROR_ACCESS_DENIED;
  248. break;
  249. //
  250. // For the following four errors, we return an ERROR_ACCESS_DENIED
  251. // for clients older than doslm20. The error class for these
  252. // must be SMB_ERR_CLASS_SERVER.
  253. //
  254. case ERROR_INVALID_LOGON_HOURS:
  255. if ( IS_DOS_DIALECT(smbDialect) && (smbDialect > SmbDialectDosLanMan20) ) {
  256. error = ERROR_ACCESS_DENIED;
  257. } else {
  258. errorClass = SMB_ERR_CLASS_SERVER;
  259. error = NERR_InvalidLogonHours;
  260. }
  261. break;
  262. case ERROR_INVALID_WORKSTATION:
  263. if ( IS_DOS_DIALECT(smbDialect) && (smbDialect > SmbDialectDosLanMan20) ) {
  264. error = ERROR_ACCESS_DENIED;
  265. } else {
  266. errorClass = SMB_ERR_CLASS_SERVER;
  267. error = NERR_InvalidWorkstation;
  268. }
  269. break;
  270. case ERROR_ACCOUNT_DISABLED:
  271. case ERROR_ACCOUNT_EXPIRED:
  272. if ( IS_DOS_DIALECT(smbDialect) && (smbDialect > SmbDialectDosLanMan20) ) {
  273. error = ERROR_ACCESS_DENIED;
  274. } else {
  275. errorClass = SMB_ERR_CLASS_SERVER;
  276. error = NERR_AccountExpired;
  277. }
  278. break;
  279. case ERROR_PASSWORD_MUST_CHANGE:
  280. case ERROR_PASSWORD_EXPIRED:
  281. if ( IS_DOS_DIALECT(smbDialect) && (smbDialect > SmbDialectDosLanMan20) ) {
  282. error = ERROR_ACCESS_DENIED;
  283. } else {
  284. errorClass = SMB_ERR_CLASS_SERVER;
  285. error = NERR_PasswordExpired;
  286. }
  287. break;
  288. //
  289. // The only NERR codes that DOSLM20 understands are the 4 above.
  290. // According to larryo, the rest of the NERR codes have to be
  291. // mapped to ERROR_ACCESS_DENIED.
  292. //
  293. case ERROR_NETLOGON_NOT_STARTED:
  294. if ( IS_DOS_DIALECT(smbDialect) && (smbDialect > SmbDialectDosLanMan21) ) {
  295. error = ERROR_ACCESS_DENIED;
  296. } else {
  297. error = NERR_NetlogonNotStarted;
  298. }
  299. break;
  300. case ERROR_NO_LOGON_SERVERS:
  301. if ( IS_DOS_DIALECT(smbDialect) ) {
  302. error = ERROR_ACCESS_DENIED;
  303. } else {
  304. error = NERR_LogonServerNotFound;
  305. }
  306. break;
  307. case ERROR_DIR_NOT_EMPTY:
  308. if ( IS_DOS_DIALECT(smbDialect) ) {
  309. error = ERROR_ACCESS_DENIED;
  310. }
  311. break;
  312. default:
  313. break;
  314. }
  315. //
  316. // Now map the error to a DOS or OS/2 error code.
  317. //
  318. if ( error == ERROR_ACCESS_DENIED &&
  319. smbDialect == SmbDialectDosLanMan21 &&
  320. WorkContext->ShareAclFailure ) {
  321. //
  322. // WfW & DOS LM2.1 want SMB_ERR_ACCESS to be in the server
  323. // error class when it's due to ACL restrictions, but in the
  324. // DOS class otherwise.
  325. //
  326. errorClass = SMB_ERR_CLASS_SERVER;
  327. errorCode = SMB_ERR_ACCESS;
  328. } else if ( smbDialect > SmbDialectLanMan10 ) {
  329. MapErrorForDosClient(
  330. WorkContext,
  331. error,
  332. &errorCode,
  333. &errorClass
  334. );
  335. } else if ( (error > ERROR_ARITHMETIC_OVERFLOW) &&
  336. ((error < NERR_BASE) || (error > MAX_NERR)) ) {
  337. //
  338. // Win32 errors above ERROR_ARITHMETIC_OVERFLOW (but not in the
  339. // NERR_xxx range) do not map to DOS or OS/2 errors, so we
  340. // return the generic error for those.
  341. //
  342. errorClass = SMB_ERR_CLASS_HARDWARE;
  343. errorCode = SMB_ERR_GENERAL;
  344. } else {
  345. errorCode = (USHORT)error;
  346. }
  347. header->ErrorClass = errorClass;
  348. SmbPutUshort( &header->Error, errorCode );
  349. return;
  350. } // _SrvSetSmbError2
  351. VOID
  352. MapErrorForDosClient (
  353. IN PWORK_CONTEXT WorkContext,
  354. IN ULONG Error,
  355. OUT PUSHORT DosError,
  356. OUT PUCHAR DosErrorClass
  357. )
  358. /*++
  359. Routine Description:
  360. Maps an Win32 error to a DOS error.
  361. Arguments:
  362. WorkContext - Supplies a pointer to the work context block for the
  363. current SMB.
  364. Error - the Win32 error code to map.
  365. DosError - the corresponding DOS error.
  366. DosErrorClass - the error class to put in the outgoing SMB.
  367. Return Value:
  368. None.
  369. --*/
  370. {
  371. PSMB_HEADER header = WorkContext->ResponseHeader;
  372. PAGED_CODE( );
  373. //
  374. // Default to using the initial error code and the win32 error.
  375. //
  376. *DosError = (USHORT)Error;
  377. *DosErrorClass = SMB_ERR_CLASS_DOS;
  378. //
  379. // If the error is more recent and not part of the set of DOS errors
  380. // (value greater than ERROR_NET_WRITE_FAULT) and the SMB command is
  381. // not a newer SMB (errors for these get mapped by the newer DOS
  382. // redir that sent them), then map the OS/2 error to the DOS range.
  383. // This code was lifted from the ring 3 OS/2 server.
  384. //
  385. if ( Error > ERROR_NET_WRITE_FAULT &&
  386. !( header->Command == SMB_COM_COPY ||
  387. header->Command == SMB_COM_MOVE ||
  388. header->Command == SMB_COM_TRANSACTION ||
  389. header->Command == SMB_COM_TRANSACTION_SECONDARY ) ) {
  390. switch( Error ) {
  391. case ERROR_OPEN_FAILED:
  392. *DosError = ERROR_FILE_NOT_FOUND;
  393. break;
  394. case ERROR_BUFFER_OVERFLOW:
  395. case ERROR_INSUFFICIENT_BUFFER:
  396. case ERROR_INVALID_NAME:
  397. case ERROR_INVALID_LEVEL:
  398. case ERROR_SEEK_ON_DEVICE:
  399. //
  400. // These don't get mapped to anything. No explanation was
  401. // given in the ring 3 code.
  402. //
  403. break;
  404. case ERROR_BAD_EXE_FORMAT:
  405. case ERROR_INVALID_STARTING_CODESEG:
  406. case ERROR_INVALID_STACKSEG:
  407. case ERROR_INVALID_MODULETYPE:
  408. case ERROR_INVALID_EXE_SIGNATURE:
  409. case ERROR_EXE_MARKED_INVALID:
  410. case ERROR_ITERATED_DATA_EXCEEDS_64k:
  411. case ERROR_INVALID_MINALLOCSIZE:
  412. case ERROR_DYNLINK_FROM_INVALID_RING:
  413. case ERROR_IOPL_NOT_ENABLED:
  414. case ERROR_INVALID_SEGDPL:
  415. case ERROR_AUTODATASEG_EXCEEDS_64k:
  416. case ERROR_RING2SEG_MUST_BE_MOVABLE:
  417. case ERROR_RELOC_CHAIN_XEEDS_SEGLIM:
  418. case ERROR_INFLOOP_IN_RELOC_CHAIN:
  419. //case ERROR_BAD_DYNALINK:
  420. case ERROR_TOO_MANY_MODULES:
  421. //
  422. // About these, the ring 3 server code says "map to bad
  423. // format errors." Whatever that means. It doesn't do
  424. // anything with them, so we don't either.
  425. //
  426. break;
  427. case ERROR_DISK_CHANGE:
  428. *DosErrorClass = SMB_ERR_CLASS_HARDWARE;
  429. *DosError = ERROR_WRONG_DISK;
  430. break;
  431. case ERROR_DRIVE_LOCKED:
  432. *DosErrorClass = SMB_ERR_CLASS_HARDWARE;
  433. *DosError = ERROR_NOT_READY;
  434. break;
  435. case ERROR_ALREADY_EXISTS:
  436. *DosError = ERROR_FILE_EXISTS;
  437. break;
  438. case ERROR_DISK_FULL:
  439. //
  440. // Per LarryO, map to the "old" disk full error code.
  441. //
  442. *DosErrorClass = SMB_ERR_CLASS_HARDWARE;
  443. *DosError = ERROR_HANDLE_DISK_FULL;
  444. break;
  445. case ERROR_NO_MORE_SEARCH_HANDLES:
  446. *DosError = ERROR_OUT_OF_STRUCTURES;
  447. break;
  448. case ERROR_INVALID_TARGET_HANDLE:
  449. *DosError = ERROR_INVALID_HANDLE;
  450. break;
  451. case ERROR_BROKEN_PIPE:
  452. case ERROR_BAD_PIPE:
  453. case ERROR_PIPE_BUSY:
  454. case ERROR_NO_DATA:
  455. case ERROR_PIPE_NOT_CONNECTED:
  456. case ERROR_MORE_DATA:
  457. //
  458. // If this is a pipe share, return these unmolested. If
  459. // it's not a pipe share, so map to the generic error.
  460. //
  461. if ( (WorkContext->Rfcb != NULL &&
  462. WorkContext->Rfcb->ShareType == ShareTypePipe)
  463. ||
  464. (WorkContext->TreeConnect != NULL &&
  465. WorkContext->TreeConnect->Share->ShareType == ShareTypePipe) ) {
  466. break;
  467. } else {
  468. *DosErrorClass = SMB_ERR_CLASS_HARDWARE;
  469. *DosError = SMB_ERR_GENERAL;
  470. }
  471. break;
  472. case ERROR_BAD_PATHNAME:
  473. break;
  474. //
  475. // The following error mappings (not including default) were not
  476. // copied from the OS/2 server mapping.
  477. //
  478. case ERROR_LOCK_FAILED:
  479. case ERROR_NOT_LOCKED:
  480. *DosError = ERROR_LOCK_VIOLATION;
  481. break;
  482. case NERR_InvalidLogonHours:
  483. case NERR_InvalidWorkstation:
  484. case NERR_PasswordExpired:
  485. case NERR_AccountUndefined:
  486. case ERROR_ACCESS_DENIED:
  487. *DosError = ERROR_ACCESS_DENIED;
  488. break;
  489. default:
  490. *DosErrorClass = SMB_ERR_CLASS_HARDWARE;
  491. *DosError = SMB_ERR_GENERAL;
  492. }
  493. }
  494. //
  495. // The DOS redirector uses the reserved field for the hard error action.
  496. // Set it now.
  497. //
  498. if ( *DosErrorClass == SMB_ERR_CLASS_HARDWARE ) {
  499. WorkContext->ResponseHeader->Reserved = DISK_HARD_ERROR;
  500. }
  501. } // MapErrorForDosClient
  502. VOID
  503. SrvSetBufferOverflowError (
  504. IN PWORK_CONTEXT WorkContext
  505. )
  506. {
  507. PSMB_HEADER header = WorkContext->ResponseHeader;
  508. USHORT flags = SmbGetAlignedUshort( &header->Flags2 );
  509. UNLOCKABLE_CODE( 8FIL );
  510. if ( CLIENT_CAPABLE_OF(NT_STATUS, WorkContext->Connection) ) {
  511. SmbPutUlong(
  512. (PULONG)&header->ErrorClass,
  513. (ULONG)STATUS_BUFFER_OVERFLOW
  514. );
  515. flags |= SMB_FLAGS2_NT_STATUS;
  516. } else {
  517. header->ErrorClass = SMB_ERR_CLASS_DOS;
  518. SmbPutUshort( &header->Error, ERROR_MORE_DATA );
  519. flags &= ~SMB_FLAGS2_NT_STATUS;
  520. }
  521. SmbPutAlignedUshort( &header->Flags2, flags );
  522. return;
  523. } // SrvSetBufferOverflowError
  524. #if DBG
  525. VOID
  526. SrvLogBuffer( PCHAR msg, PVOID buf, ULONG len )
  527. {
  528. NTSTATUS status;
  529. HANDLE handle;
  530. IO_STATUS_BLOCK iosb;
  531. OBJECT_ATTRIBUTES objectAttributes;
  532. PUCHAR buffer;
  533. ULONG n = 0;
  534. ULONG i;
  535. UNICODE_STRING name;
  536. PAGED_CODE();
  537. if( msg ) {
  538. n = strlen( msg );
  539. }
  540. buffer = ALLOCATE_HEAP( 4*len + n, BlockTypeDataBuffer );
  541. if( buffer == NULL ) {
  542. return;
  543. }
  544. buffer[ 0 ] = '\n';
  545. if( msg ) {
  546. RtlCopyMemory( &buffer[1], msg, n );
  547. n++;
  548. buffer[ n++ ] = '\n';
  549. }
  550. for( i=0; i < len && n < 4*len; ) {
  551. UCHAR c = ((PUCHAR)buf)[ i ];
  552. /*
  553. if( (c >= 'A' && c <= 'Z') ||
  554. (c >= 'a' && c <= 'z') ||
  555. ( c == ' ' || c == ';' || c == ':' || c == ',' || c == '.' ) ||
  556. ( c >= '0' && c <= '9' ) ) {
  557. buffer[ n++ ] = c;
  558. buffer[ n++ ] = ' ';
  559. }
  560. else
  561. */
  562. {
  563. buffer[n++] = "0123456789abcdef"[ (c>>4) & 0xf ];
  564. buffer[n++] = "0123456789abcdef"[ c & 0xf ];
  565. }
  566. buffer[n++] = ' ';
  567. ++i;
  568. if( (i%16) == 0 ) {
  569. buffer[ n++ ] = '\n';
  570. }
  571. }
  572. if( n < 4*len ) {
  573. buffer[ n++ ] = '\n';
  574. buffer[ n++ ] = '\n';
  575. }
  576. name.Length = 44;
  577. name.MaximumLength = name.Length;
  578. name.Buffer = L"\\DosDevices\\C:\\Srv.Log";
  579. SrvInitializeObjectAttributes_U(
  580. &objectAttributes,
  581. &name,
  582. OBJ_CASE_INSENSITIVE,
  583. NULL,
  584. NULL
  585. );
  586. status = NtCreateFile(
  587. &handle,
  588. FILE_APPEND_DATA, // desired access
  589. &objectAttributes,
  590. &iosb,
  591. NULL, // AllocationSize OPTIONAL
  592. FILE_ATTRIBUTE_NORMAL, // FileAttributes
  593. FILE_SHARE_WRITE | FILE_SHARE_READ, // ShareAccess
  594. FILE_OPEN_IF, // Create dispisition
  595. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, // Create options
  596. NULL, // EaBuffer
  597. 0 // EaLength
  598. );
  599. if( NT_SUCCESS( status ) ) {
  600. NtWriteFile( handle,
  601. NULL,
  602. NULL,
  603. NULL,
  604. &iosb,
  605. buffer,
  606. n,
  607. NULL,
  608. NULL
  609. );
  610. NtClose( handle );
  611. }
  612. FREE_HEAP( buffer );
  613. }
  614. #endif