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.

626 lines
19 KiB

  1. /*++
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. Module Name:
  4. globalog.c
  5. Abstract:
  6. The global logger, which is started only by registry settings.
  7. Will start at boot.
  8. Author:
  9. Jee Fung Pang (jeepang) 03-Nov-1998
  10. Revision History:
  11. --*/
  12. #ifndef MEMPHIS
  13. #include "ntos.h"
  14. #include <evntrace.h>
  15. #include "wmikmp.h"
  16. #include "tracep.h"
  17. #define MAX_REGKEYS 10
  18. #define MAX_ENABLE_FLAGS 10
  19. #define TRACE_VERSION_MAJOR 1
  20. #define TRACE_VERSION_MINOR 0
  21. #define DOSDEVICES L"\\DosDevices\\"
  22. #define UNCDEVICES L"\\??\\UNC"
  23. #define DEFAULT_GLOBAL_LOGFILE_ROOT L"%SystemRoot%"
  24. #define DEFAULT_GLOBAL_DIRECTORY L"\\System32\\LogFiles\\WMI"
  25. #define DEFAULT_GLOBAL_LOGFILE L"trace.log"
  26. //
  27. // NOTE: Need a trailing NULL entry so that RtlQueryRegistryValues()
  28. // knows when to stop
  29. //
  30. #ifdef ALLOC_PRAGMA
  31. #pragma alloc_text(INIT, WmipStartGlobalLogger)
  32. #pragma alloc_text(PAGE, WmipQueryGLRegistryRoutine)
  33. #pragma alloc_text(PAGE, WmipAddLogHeader)
  34. #pragma alloc_text(PAGE, WmipDelayCreate)
  35. #pragma alloc_text(PAGE, WmipCreateDirectoryFile)
  36. #pragma alloc_text(PAGE, WmipCreateNtFileName)
  37. #endif
  38. extern HANDLE WmipPageLockHandle;
  39. //
  40. // NOTE: If we are going to function earlier in boot, we need to see
  41. // if the creation routines and logger routines can run at all while in
  42. // boot path and being pagable
  43. //
  44. VOID
  45. WmipStartGlobalLogger(
  46. )
  47. /*++
  48. Routine Description:
  49. This routine will check for registry entries to see if the global
  50. needs to be started at boot time.
  51. Arguments:
  52. None
  53. Return Value:
  54. --*/
  55. {
  56. struct _LOGGER_INFO {
  57. WMI_LOGGER_INFORMATION LoggerInfo;
  58. ULONG EnableFlags[MAX_ENABLE_FLAGS];
  59. } GLog;
  60. RTL_QUERY_REGISTRY_TABLE QueryRegistryTable[MAX_REGKEYS];
  61. NTSTATUS status;
  62. ULONG StartRequested = 0;
  63. WCHAR NullString = UNICODE_NULL;
  64. WmipPageLockHandle
  65. = MmLockPagableCodeSection((PVOID)WmipReserveTraceBuffer);
  66. MmUnlockPagableImageSection(WmipPageLockHandle);
  67. ExInitializeFastMutex(&WmipTraceFastMutex);
  68. RtlZeroMemory(&GLog, sizeof(GLog));
  69. GLog.LoggerInfo.Wnode.Flags = WNODE_FLAG_TRACED_GUID;
  70. GLog.LoggerInfo.MinimumBuffers = (ULONG) KeNumberProcessors + 1;
  71. GLog.LoggerInfo.MaximumBuffers = GLog.LoggerInfo.MinimumBuffers + 25;
  72. GLog.LoggerInfo.BufferSize = PAGE_SIZE / 1024;
  73. GLog.LoggerInfo.Wnode.BufferSize = sizeof(WMI_LOGGER_INFORMATION);
  74. GLog.LoggerInfo.Wnode.Guid = GlobalLoggerGuid;
  75. GLog.LoggerInfo.LogFileMode = EVENT_TRACE_DELAY_OPEN_FILE_MODE;
  76. RtlInitUnicodeString(&GLog.LoggerInfo.LoggerName, L"GlobalLogger");
  77. RtlZeroMemory(QueryRegistryTable,
  78. sizeof(RTL_QUERY_REGISTRY_TABLE) * MAX_REGKEYS);
  79. QueryRegistryTable[0].QueryRoutine = WmipQueryGLRegistryRoutine;
  80. QueryRegistryTable[0].EntryContext = (PVOID) &StartRequested;
  81. QueryRegistryTable[0].Name = L"Start";
  82. QueryRegistryTable[0].DefaultType = REG_DWORD;
  83. QueryRegistryTable[1].QueryRoutine = WmipQueryGLRegistryRoutine;
  84. QueryRegistryTable[1].EntryContext = (PVOID) &GLog.LoggerInfo.BufferSize;
  85. QueryRegistryTable[1].Name = L"BufferSize";
  86. QueryRegistryTable[1].DefaultType = REG_DWORD;
  87. QueryRegistryTable[2].QueryRoutine = WmipQueryGLRegistryRoutine;
  88. QueryRegistryTable[2].EntryContext = (PVOID)&GLog.LoggerInfo.MinimumBuffers;
  89. QueryRegistryTable[2].Name = L"MinimumBuffers";
  90. QueryRegistryTable[2].DefaultType = REG_DWORD;
  91. QueryRegistryTable[3].QueryRoutine = WmipQueryGLRegistryRoutine;
  92. QueryRegistryTable[3].EntryContext = (PVOID) &GLog.LoggerInfo.FlushTimer;
  93. QueryRegistryTable[3].Name = L"FlushTimer";
  94. QueryRegistryTable[3].DefaultType = REG_DWORD;
  95. QueryRegistryTable[4].QueryRoutine = WmipQueryGLRegistryRoutine;
  96. QueryRegistryTable[4].EntryContext = (PVOID)&GLog.LoggerInfo.MaximumBuffers;
  97. QueryRegistryTable[4].Name = L"MaximumBuffers";
  98. QueryRegistryTable[4].DefaultType = REG_DWORD;
  99. QueryRegistryTable[5].QueryRoutine = WmipQueryGLRegistryRoutine;
  100. QueryRegistryTable[5].EntryContext = (PVOID) &GLog.LoggerInfo.LogFileName;
  101. QueryRegistryTable[5].Name = L"FileName";
  102. QueryRegistryTable[5].DefaultType = REG_SZ;
  103. QueryRegistryTable[5].DefaultData = &NullString;
  104. QueryRegistryTable[6].QueryRoutine = WmipQueryGLRegistryRoutine;
  105. QueryRegistryTable[6].EntryContext = (PVOID) &GLog.EnableFlags[0];
  106. QueryRegistryTable[6].Name = L"EnableKernelFlags";
  107. QueryRegistryTable[6].DefaultType = REG_BINARY;
  108. QueryRegistryTable[7].QueryRoutine = WmipQueryGLRegistryRoutine;
  109. QueryRegistryTable[7].EntryContext = (PVOID)&GLog.LoggerInfo.Wnode.ClientContext;
  110. QueryRegistryTable[7].Name = L"ClockType";
  111. QueryRegistryTable[7].DefaultType = REG_DWORD;
  112. status = RtlQueryRegistryValues(
  113. RTL_REGISTRY_CONTROL,
  114. L"WMI\\GlobalLogger",
  115. QueryRegistryTable,
  116. NULL,
  117. NULL);
  118. if (NT_SUCCESS(status) && (StartRequested != 0)) {
  119. if (GLog.EnableFlags[0] != 0) {
  120. SHORT Length;
  121. for (Length=MAX_ENABLE_FLAGS-1; Length>=0; Length--) {
  122. if (GLog.EnableFlags[Length] != 0)
  123. break;
  124. }
  125. if (Length >= 0) {
  126. PTRACE_ENABLE_FLAG_EXTENSION FlagExt;
  127. Length++; // Index is 1 less!
  128. FlagExt = (PTRACE_ENABLE_FLAG_EXTENSION)
  129. &GLog.LoggerInfo.EnableFlags;
  130. GLog.LoggerInfo.EnableFlags = EVENT_TRACE_FLAG_EXTENSION;
  131. FlagExt->Length = (UCHAR) Length;
  132. FlagExt->Offset = (UCHAR) GLog.LoggerInfo.Wnode.BufferSize;
  133. GLog.LoggerInfo.Wnode.BufferSize
  134. += (ULONG) (Length * sizeof(ULONG));
  135. }
  136. }
  137. if (GLog.LoggerInfo.LogFileName.Buffer == NULL) {
  138. RtlCreateUnicodeString(
  139. &GLog.LoggerInfo.LogFileName,
  140. DEFAULT_GLOBAL_LOGFILE_ROOT); // Use ROOT as indicator
  141. if (GLog.LoggerInfo.LogFileName.Buffer == NULL)
  142. status = STATUS_NO_MEMORY;
  143. else
  144. status = STATUS_SUCCESS;
  145. }
  146. if (NT_SUCCESS(status)) {
  147. status = WmipStartLogger(&GLog.LoggerInfo);
  148. }
  149. }
  150. if (GLog.LoggerInfo.LogFileName.Buffer) {
  151. RtlFreeUnicodeString(&GLog.LoggerInfo.LogFileName);
  152. }
  153. }
  154. NTSTATUS
  155. WmipQueryGLRegistryRoutine(
  156. IN PWSTR ValueName,
  157. IN ULONG ValueType,
  158. IN PVOID ValueData,
  159. IN ULONG ValueLength,
  160. IN PVOID Context,
  161. IN PVOID EntryContext
  162. )
  163. /*++
  164. Routine Description:
  165. Registry query values callback routine for reading SDs for guids
  166. Arguments:
  167. ValueName - the name of the value
  168. ValueType - the type of the value
  169. ValueData - the data in the value (unicode string data)
  170. ValueLength - the number of bytes in the value data
  171. Context - Not used
  172. EntryContext - Pointer to PSECURITY_DESCRIPTOR to store a pointer to
  173. store the security descriptor read from the registry value
  174. Return Value:
  175. NT Status code
  176. --*/
  177. {
  178. NTSTATUS status = STATUS_SUCCESS;
  179. PAGED_CODE();
  180. UNREFERENCED_PARAMETER(ValueName);
  181. UNREFERENCED_PARAMETER(Context);
  182. if ( (ValueData != NULL) && (ValueLength > 0) && (EntryContext != NULL) ){
  183. if (ValueType == REG_DWORD) {
  184. if ((ValueLength >= sizeof(ULONG)) && (ValueData != NULL)) {
  185. *((PULONG)EntryContext) = *((PULONG)ValueData);
  186. }
  187. }
  188. else if (ValueType == REG_SZ) {
  189. if (ValueLength > sizeof(UNICODE_NULL)) {
  190. status = RtlCreateUnicodeString(
  191. (PUNICODE_STRING) EntryContext,
  192. (PCWSTR) ValueData);
  193. }
  194. }
  195. else if (ValueType == REG_BINARY) {
  196. if ((ValueLength >= sizeof(ULONG)) && (ValueData != NULL)) {
  197. RtlMoveMemory(EntryContext, ValueData, ValueLength);
  198. }
  199. }
  200. }
  201. return status;
  202. }
  203. NTSTATUS
  204. WmipAddLogHeader(
  205. IN PWMI_LOGGER_CONTEXT LoggerContext,
  206. IN OUT PWMI_BUFFER_HEADER Buffer
  207. )
  208. /*++
  209. Routine Description:
  210. Add a standard logfile header in kernel moder.
  211. To make sure the first buffer of the log file contains the file header,
  212. we pop a buffer from the free list, write the header, and flush the buffer
  213. right away.
  214. Arguments:
  215. LoggerContext - The logger context
  216. Return Value:
  217. NT Status code
  218. --*/
  219. {
  220. PTRACE_LOGFILE_HEADER LogfileHeader;
  221. USHORT HeaderSize;
  222. PSYSTEM_TRACE_HEADER EventTrace;
  223. PSINGLE_LIST_ENTRY SingleListEntry;
  224. PETHREAD Thread;
  225. NTSTATUS Status = STATUS_SUCCESS;
  226. ULONG BufferProvided = (Buffer != NULL);
  227. ULONG LocalBuffer = FALSE;
  228. if (LoggerContext == NULL) {
  229. return STATUS_INVALID_PARAMETER;
  230. }
  231. HeaderSize = sizeof(TRACE_LOGFILE_HEADER)
  232. + LoggerContext->LoggerName.Length + sizeof(UNICODE_NULL)
  233. + LoggerContext->LogFileName.Length + sizeof(UNICODE_NULL);
  234. if (LoggerContext->BufferSize < (HeaderSize - sizeof(WMI_BUFFER_HEADER))) {
  235. return STATUS_NO_MEMORY;
  236. }
  237. //
  238. // Pop a buffer from Free List
  239. //
  240. if (!BufferProvided) {
  241. Buffer = WmipGetFreeBuffer(LoggerContext);
  242. if (Buffer == NULL) {
  243. Buffer = ExAllocatePoolWithTag(PagedPool,
  244. LoggerContext->BufferSize, TRACEPOOLTAG);
  245. if (Buffer == NULL) {
  246. //
  247. // No buffer available.
  248. //
  249. return STATUS_NO_MEMORY;
  250. }
  251. LocalBuffer = TRUE;
  252. Buffer->Flags = 1;
  253. Buffer->SavedOffset = 0;
  254. Buffer->CurrentOffset = sizeof(WMI_BUFFER_HEADER);
  255. Buffer->Wnode.ClientContext = 0;
  256. Buffer->LoggerContext = LoggerContext;
  257. Buffer->State.Free = 0;
  258. Buffer->State.InUse = 1;
  259. KeQuerySystemTime(&Buffer->TimeStamp);
  260. }
  261. }
  262. //
  263. // Fill in the Header Info.
  264. //
  265. Thread = PsGetCurrentThread();
  266. EventTrace = (PSYSTEM_TRACE_HEADER) (Buffer+1);
  267. EventTrace->Packet.Group = (UCHAR) EVENT_TRACE_GROUP_HEADER >> 8;
  268. EventTrace->Packet.Type = EVENT_TRACE_TYPE_INFO;
  269. EventTrace->Packet.Size = HeaderSize + sizeof(SYSTEM_TRACE_HEADER);
  270. EventTrace->Marker = SYSTEM_TRACE_MARKER;
  271. EventTrace->ThreadId = HandleToUlong(Thread->Cid.UniqueThread);
  272. EventTrace->KernelTime = Thread->Tcb.KernelTime;
  273. EventTrace->UserTime = Thread->Tcb.UserTime;
  274. EventTrace->SystemTime = LoggerContext->ReferenceTimeStamp;
  275. LogfileHeader = (PTRACE_LOGFILE_HEADER) (EventTrace+1);
  276. RtlZeroMemory(LogfileHeader, HeaderSize);
  277. LogfileHeader->StartTime = LoggerContext->ReferenceSystemTime;
  278. LogfileHeader->BufferSize = LoggerContext->BufferSize;
  279. LogfileHeader->VersionDetail.MajorVersion = (UCHAR) NtMajorVersion;
  280. LogfileHeader->VersionDetail.MinorVersion = (UCHAR) NtMinorVersion;
  281. LogfileHeader->VersionDetail.SubVersion = TRACE_VERSION_MAJOR;
  282. LogfileHeader->VersionDetail.SubMinorVersion = TRACE_VERSION_MINOR;
  283. LogfileHeader->ProviderVersion = NtBuildNumber;
  284. LogfileHeader->StartBuffers = 1;
  285. LogfileHeader->BootTime = KeBootTime;
  286. LogfileHeader->LogFileMode =
  287. LoggerContext->LoggerMode & (~(EVENT_TRACE_REAL_TIME_MODE));
  288. LogfileHeader->NumberOfProcessors = KeNumberProcessors;
  289. LogfileHeader->MaximumFileSize = LoggerContext->MaximumFileSize;
  290. KeQueryPerformanceCounter(&LogfileHeader->PerfFreq);
  291. //
  292. // ReservedFlags to indicate using Perf Clock
  293. //
  294. LogfileHeader->ReservedFlags = LoggerContext->UsePerfClock;
  295. LogfileHeader->TimerResolution = KeMaximumIncrement;
  296. LogfileHeader->LoggerName = (PWCHAR) ( (PUCHAR) LogfileHeader
  297. + sizeof(TRACE_LOGFILE_HEADER) );
  298. LogfileHeader->LogFileName = (PWCHAR) ( (PUCHAR)LogfileHeader->LoggerName
  299. + LoggerContext->LoggerName.Length
  300. + sizeof(UNICODE_NULL));
  301. RtlCopyMemory(LogfileHeader->LoggerName,
  302. LoggerContext->LoggerName.Buffer,
  303. LoggerContext->LoggerName.Length + sizeof(UNICODE_NULL));
  304. RtlCopyMemory(LogfileHeader->LogFileName,
  305. LoggerContext->LogFileName.Buffer,
  306. LoggerContext->LogFileName.Length + sizeof(UNICODE_NULL));
  307. RtlQueryTimeZoneInformation(&LogfileHeader->TimeZone);
  308. LogfileHeader->PointerSize = sizeof(PVOID);
  309. //
  310. // Adjust the Offset;
  311. //
  312. Buffer->CurrentOffset += ALIGN_TO_POWER2(sizeof(SYSTEM_TRACE_HEADER) + HeaderSize,
  313. WmiTraceAlignment);
  314. if (BufferProvided)
  315. return Status;
  316. //
  317. // The buffer is prepared properly. Flush it so it can be written out to disk.
  318. //
  319. Status = WmipFlushBuffer(LoggerContext, Buffer);
  320. if (LocalBuffer && (Buffer != NULL)) {
  321. ExFreePool(Buffer);
  322. return Status;
  323. }
  324. InterlockedPushEntrySList(&LoggerContext->FreeList,
  325. (PSINGLE_LIST_ENTRY) &Buffer->SlistEntry);
  326. InterlockedIncrement(&LoggerContext->BuffersAvailable);
  327. InterlockedDecrement(&LoggerContext->BuffersInUse);
  328. TraceDebug((2,
  329. "WmipAddLogHeader: Boot %I64u Current %I64u Difference %I64u\n",
  330. KeBootTime, EventTrace->SystemTime,
  331. EventTrace->SystemTime.QuadPart - KeBootTime.QuadPart));
  332. return Status;
  333. }
  334. NTSTATUS
  335. WmipDelayCreate(
  336. OUT PHANDLE FileHandle,
  337. IN OUT PUNICODE_STRING FileName,
  338. IN ULONG Append
  339. )
  340. /*++
  341. Routine Description:
  342. This is called by the global logger to actually open the logfile
  343. when the first buffer needs to flush (instead of when the logger started)
  344. Arguments:
  345. LoggerHandle The handle to the logfile to be returned
  346. FileName The logfile name. If the default was chosen, we will
  347. returned the actual pathname in %systemroot%
  348. Return Value:
  349. NT Status code
  350. --*/
  351. {
  352. PWCHAR Buffer;
  353. PWCHAR strBuffer = NULL;
  354. ULONG DefaultFile, Length;
  355. UNICODE_STRING LogFileName;
  356. NTSTATUS Status;
  357. if (FileName == NULL)
  358. return STATUS_INVALID_PARAMETER;
  359. RtlInitUnicodeString(&LogFileName, DEFAULT_GLOBAL_LOGFILE_ROOT);
  360. DefaultFile = (RtlCompareUnicodeString(FileName, &LogFileName, TRUE) == 0);
  361. if (DefaultFile) {
  362. //
  363. // Try creating the file first
  364. //
  365. Length = (ULONG) ( NtSystemRoot.Length
  366. + sizeof(WCHAR) * (wcslen(DEFAULT_GLOBAL_DIRECTORY) +
  367. wcslen(DEFAULT_GLOBAL_LOGFILE) + 1)
  368. + sizeof(UNICODE_NULL));
  369. strBuffer = (PWCHAR) ExAllocatePoolWithTag(
  370. PagedPool, Length, TRACEPOOLTAG);
  371. if (strBuffer == NULL)
  372. return STATUS_NO_MEMORY;
  373. swprintf(strBuffer,
  374. L"%ws%ws\\%ws",
  375. NtSystemRoot.Buffer,
  376. DEFAULT_GLOBAL_DIRECTORY,
  377. DEFAULT_GLOBAL_LOGFILE);
  378. Status = WmipCreateNtFileName(strBuffer, & Buffer);
  379. if (!NT_SUCCESS(Status)) {
  380. ExFreePool(strBuffer);
  381. return Status;
  382. }
  383. Status = WmipCreateDirectoryFile(Buffer, FALSE, FileHandle, Append);
  384. if (!NT_SUCCESS(Status)) {
  385. ULONG DirLen;
  386. //
  387. // Probably directory does not exist, so try and create it
  388. //
  389. DirLen = (ULONG)
  390. (wcslen(Buffer)-wcslen(DEFAULT_GLOBAL_LOGFILE)) - 5;
  391. Buffer[DirLen] = UNICODE_NULL;
  392. Status = WmipCreateDirectoryFile(Buffer, TRUE, NULL, Append);
  393. if (NT_SUCCESS(Status)) {
  394. Buffer[DirLen] = L'\\';
  395. DirLen += 4;
  396. Buffer[DirLen] = UNICODE_NULL;
  397. Status = WmipCreateDirectoryFile(Buffer, TRUE, NULL, Append);
  398. Buffer[DirLen] = L'\\';
  399. }
  400. if (NT_SUCCESS(Status)) {
  401. Status = WmipCreateDirectoryFile(Buffer, FALSE, FileHandle, Append);
  402. }
  403. }
  404. // Make sure that directory is there first
  405. if (NT_SUCCESS(Status)) {
  406. if (FileName->Buffer != NULL) {
  407. RtlFreeUnicodeString(FileName);
  408. }
  409. RtlInitUnicodeString(FileName, strBuffer);
  410. if (FileName->MaximumLength < Length)
  411. FileName->MaximumLength = (USHORT) Length;
  412. }
  413. }
  414. else {
  415. Status = WmipCreateNtFileName(FileName->Buffer, & Buffer);
  416. if (NT_SUCCESS(Status)) {
  417. Status = WmipCreateDirectoryFile(Buffer, FALSE, FileHandle, Append);
  418. }
  419. }
  420. if (Buffer != NULL) {
  421. ExFreePool(Buffer);
  422. }
  423. return Status;
  424. }
  425. NTSTATUS
  426. WmipCreateDirectoryFile(
  427. IN PWCHAR DirFileName,
  428. IN ULONG IsDirectory,
  429. OUT PHANDLE FileHandle,
  430. IN ULONG Append
  431. )
  432. {
  433. OBJECT_ATTRIBUTES ObjectAttributes;
  434. IO_STATUS_BLOCK IoStatus;
  435. UNICODE_STRING LogDirName;
  436. HANDLE DirHandle = NULL;
  437. NTSTATUS Status;
  438. ULONG CreateDisposition;
  439. RtlInitUnicodeString(&LogDirName, DirFileName);
  440. InitializeObjectAttributes(
  441. &ObjectAttributes,
  442. &LogDirName,
  443. OBJ_CASE_INSENSITIVE,
  444. NULL,
  445. NULL);
  446. if (IsDirectory) {
  447. CreateDisposition = FILE_OPEN_IF;
  448. } else if (Append) {
  449. CreateDisposition = FILE_OPEN_IF;
  450. } else {
  451. CreateDisposition = FILE_OVERWRITE_IF;
  452. }
  453. Status = ZwCreateFile(
  454. &DirHandle,
  455. FILE_GENERIC_READ | SYNCHRONIZE
  456. | (IsDirectory ? FILE_GENERIC_WRITE : FILE_WRITE_DATA),
  457. &ObjectAttributes,
  458. &IoStatus,
  459. NULL,
  460. FILE_ATTRIBUTE_NORMAL,
  461. FILE_SHARE_READ,
  462. CreateDisposition,
  463. FILE_SYNCHRONOUS_IO_NONALERT
  464. | (IsDirectory ? FILE_DIRECTORY_FILE
  465. : FILE_NO_INTERMEDIATE_BUFFERING),
  466. NULL,
  467. 0);
  468. TraceDebug((2, "WmipCreateDirectoryFile: Create %ws Mode: %x status: %x\n",
  469. DirFileName, Append, Status));
  470. if (NT_SUCCESS(Status) && IsDirectory && (DirHandle != NULL)) {
  471. ZwClose(DirHandle);
  472. if (FileHandle)
  473. *FileHandle = NULL;
  474. }
  475. else {
  476. if (FileHandle)
  477. *FileHandle = DirHandle;
  478. }
  479. return Status;
  480. }
  481. NTSTATUS
  482. WmipCreateNtFileName(
  483. IN PWCHAR strFileName,
  484. OUT PWCHAR * strNtFileName
  485. )
  486. {
  487. PWCHAR NtFileName;
  488. ULONG lenFileName;
  489. if (strFileName == NULL) {
  490. * strNtFileName = NULL;
  491. return STATUS_INVALID_PARAMETER;
  492. }
  493. lenFileName = sizeof(UNICODE_NULL)
  494. + (ULONG) (sizeof(WCHAR) * wcslen(strFileName));
  495. if ((strFileName[0] == L'\\') && (strFileName[1] == L'\\')) {
  496. lenFileName += (ULONG) (wcslen(UNCDEVICES) * sizeof(WCHAR));
  497. }
  498. else {
  499. lenFileName += (ULONG) (wcslen(DOSDEVICES) * sizeof(WCHAR));
  500. }
  501. NtFileName = (PWCHAR) ExAllocatePoolWithTag(
  502. PagedPool, lenFileName, TRACEPOOLTAG);
  503. if (NtFileName == NULL) {
  504. * strNtFileName = NULL;
  505. return STATUS_NO_MEMORY;
  506. }
  507. if ((strFileName[0] == L'\\') && (strFileName[1] == L'\\')) {
  508. swprintf(NtFileName, L"%ws%ws", UNCDEVICES, & (strFileName[1]));
  509. }
  510. else {
  511. swprintf(NtFileName, L"%ws%ws", DOSDEVICES, strFileName);
  512. }
  513. * strNtFileName = NtFileName;
  514. return STATUS_SUCCESS;
  515. }
  516. #endif // !MEMPHIS