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.

927 lines
31 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. environ.c
  5. Abstract:
  6. Environment Variable support
  7. Author:
  8. Steven R. Wood (stevewo) 30-Jan-1991
  9. Revision History:
  10. --*/
  11. #include "ntrtlp.h"
  12. #include "zwapi.h"
  13. #include "nturtl.h"
  14. #include "string.h"
  15. #include "ntrtlpath.h"
  16. #if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME)
  17. #pragma alloc_text(INIT,RtlCreateEnvironment )
  18. #pragma alloc_text(INIT,RtlDestroyEnvironment )
  19. #pragma alloc_text(INIT,RtlSetCurrentEnvironment )
  20. #pragma alloc_text(INIT,RtlQueryEnvironmentVariable_U )
  21. #pragma alloc_text(INIT,RtlSetEnvironmentVariable )
  22. #endif
  23. BOOLEAN RtlpEnvironCacheValid;
  24. NTSTATUS
  25. RtlCreateEnvironment(
  26. IN BOOLEAN CloneCurrentEnvironment OPTIONAL,
  27. OUT PVOID *Environment
  28. )
  29. {
  30. NTSTATUS Status;
  31. MEMORY_BASIC_INFORMATION MemoryInformation;
  32. PVOID pNew, pOld;
  33. //
  34. // If not cloning a copy of the current process's environment variable
  35. // block, just allocate a block of committed memory and return its
  36. // address.
  37. //
  38. pNew = NULL;
  39. if (!CloneCurrentEnvironment) {
  40. createEmptyEnvironment:
  41. MemoryInformation.RegionSize = 1;
  42. Status = ZwAllocateVirtualMemory( NtCurrentProcess(),
  43. &pNew,
  44. 0,
  45. &MemoryInformation.RegionSize,
  46. MEM_COMMIT,
  47. PAGE_READWRITE
  48. );
  49. if (NT_SUCCESS( Status )) {
  50. *Environment = pNew;
  51. }
  52. return( Status );
  53. }
  54. //
  55. // Acquire the Peb Lock for the duration while we munge the environment
  56. // variable storage block.
  57. //
  58. RtlAcquirePebLock();
  59. //
  60. // Capture the pointer to the current process's environment variable
  61. // block and initialize the new pointer to null for our finally clause.
  62. //
  63. pOld = NtCurrentPeb()->ProcessParameters->Environment;
  64. if (pOld == NULL) {
  65. RtlReleasePebLock();
  66. goto createEmptyEnvironment;
  67. }
  68. try {
  69. try {
  70. //
  71. // Query the current size of the current process's environment
  72. // variable block. Return status if failure.
  73. //
  74. Status = ZwQueryVirtualMemory( NtCurrentProcess(),
  75. pOld,
  76. MemoryBasicInformation,
  77. &MemoryInformation,
  78. sizeof( MemoryInformation ),
  79. NULL
  80. );
  81. if (!NT_SUCCESS( Status )) {
  82. leave;
  83. }
  84. //
  85. // Allocate memory to contain a copy of the current process's
  86. // environment variable block. Return status if failure.
  87. //
  88. Status = ZwAllocateVirtualMemory( NtCurrentProcess(),
  89. &pNew,
  90. 0,
  91. &MemoryInformation.RegionSize,
  92. MEM_COMMIT,
  93. PAGE_READWRITE
  94. );
  95. if (!NT_SUCCESS( Status )) {
  96. leave;
  97. }
  98. //
  99. // Copy the current process's environment to the allocated memory
  100. // and return a pointer to the copy.
  101. //
  102. RtlCopyMemory( pNew, pOld, MemoryInformation.RegionSize );
  103. *Environment = pNew;
  104. } except (EXCEPTION_EXECUTE_HANDLER) {
  105. Status = STATUS_ACCESS_VIOLATION;
  106. }
  107. } finally {
  108. if (Status == STATUS_ACCESS_VIOLATION) {
  109. if (pNew != NULL) {
  110. ZwFreeVirtualMemory( NtCurrentProcess(),
  111. &pNew,
  112. &MemoryInformation.RegionSize,
  113. MEM_RELEASE
  114. );
  115. }
  116. }
  117. RtlReleasePebLock();
  118. }
  119. return( Status );
  120. }
  121. NTSTATUS
  122. RtlDestroyEnvironment(
  123. IN PVOID Environment
  124. )
  125. {
  126. NTSTATUS Status;
  127. SIZE_T RegionSize;
  128. //
  129. // Free the specified environment variable block.
  130. //
  131. RtlpEnvironCacheValid = FALSE;
  132. RegionSize = 0;
  133. Status = ZwFreeVirtualMemory( NtCurrentProcess(),
  134. &Environment,
  135. &RegionSize,
  136. MEM_RELEASE
  137. );
  138. //
  139. // Return status.
  140. //
  141. return( Status );
  142. }
  143. NTSTATUS
  144. RtlSetCurrentEnvironment(
  145. IN PVOID Environment,
  146. OUT PVOID *PreviousEnvironment OPTIONAL
  147. )
  148. {
  149. NTSTATUS Status;
  150. PVOID pOld;
  151. //
  152. // Acquire the Peb Lock for the duration while we munge the environment
  153. // variable storage block.
  154. //
  155. RtlpEnvironCacheValid = FALSE;
  156. RtlAcquirePebLock();
  157. Status = STATUS_SUCCESS;
  158. try {
  159. //
  160. // Capture current process's environment variable block pointer to
  161. // return to caller or destroy.
  162. //
  163. pOld = NtCurrentPeb()->ProcessParameters->Environment;
  164. //
  165. // Change current process's environment variable block pointer to
  166. // point to the passed block.
  167. //
  168. NtCurrentPeb()->ProcessParameters->Environment = Environment;
  169. //
  170. // If caller requested it, return the pointer to the previous
  171. // process environment variable block and set the local variable
  172. // to NULL so we dont destroy it below.
  173. //
  174. if (ARGUMENT_PRESENT( PreviousEnvironment )) {
  175. *PreviousEnvironment = pOld;
  176. pOld = NULL;
  177. }
  178. } except (EXCEPTION_EXECUTE_HANDLER) {
  179. Status = STATUS_ACCESS_VIOLATION;
  180. pOld = NULL;
  181. }
  182. //
  183. // Release the Peb Lock
  184. //
  185. RtlReleasePebLock();
  186. //
  187. // If old environment not returned to caller, destroy it.
  188. //
  189. if (pOld != NULL) {
  190. RtlDestroyEnvironment( pOld );
  191. }
  192. //
  193. // Return status
  194. //
  195. return( Status );
  196. }
  197. UNICODE_STRING RtlpEnvironCacheName;
  198. UNICODE_STRING RtlpEnvironCacheValue;
  199. NTSTATUS
  200. RtlQueryEnvironmentVariable_U(
  201. IN PVOID Environment OPTIONAL,
  202. IN PUNICODE_STRING Name,
  203. IN OUT PUNICODE_STRING Value
  204. )
  205. {
  206. NTSTATUS Status;
  207. UNICODE_STRING CurrentName;
  208. UNICODE_STRING CurrentValue;
  209. PWSTR p;
  210. PPEB Peb;
  211. BOOLEAN PebLockLocked = FALSE;
  212. Status = STATUS_VARIABLE_NOT_FOUND;
  213. Peb = NtCurrentPeb();
  214. try {
  215. if (ARGUMENT_PRESENT( Environment )) {
  216. p = Environment;
  217. if (*p == UNICODE_NULL) {
  218. leave;
  219. }
  220. }
  221. else {
  222. //
  223. // Acquire the Peb Lock for the duration while we munge the
  224. // environment variable storage block.
  225. //
  226. RtlAcquirePebLock();
  227. PebLockLocked = TRUE;
  228. //
  229. // Capture the pointer to the current process's environment variable
  230. // block.
  231. //
  232. p = Peb->ProcessParameters->Environment;
  233. }
  234. if ( RtlpEnvironCacheValid && p == Peb->ProcessParameters->Environment ) {
  235. if (RtlEqualUnicodeString( Name, &RtlpEnvironCacheName, TRUE )) {
  236. //
  237. // Names are equal. Always return the length of the
  238. // value string, excluding the terminating null. If
  239. // there is room in the caller's buffer, return a copy
  240. // of the value string and success status. Otherwise
  241. // return an error status. In the latter case, the caller
  242. // can examine the length field of their value string
  243. // so they can determine much memory is needed.
  244. //
  245. Value->Length = RtlpEnvironCacheValue.Length;
  246. if (Value->MaximumLength >= RtlpEnvironCacheValue.Length) {
  247. RtlCopyMemory( Value->Buffer,
  248. RtlpEnvironCacheValue.Buffer,
  249. RtlpEnvironCacheValue.Length
  250. );
  251. //
  252. // Null terminate returned string if there is room.
  253. //
  254. if (Value->MaximumLength > RtlpEnvironCacheValue.Length) {
  255. Value->Buffer[ RtlpEnvironCacheValue.Length/sizeof(WCHAR) ] = L'\0';
  256. }
  257. Status = STATUS_SUCCESS;
  258. }
  259. else {
  260. Status = STATUS_BUFFER_TOO_SMALL;
  261. }
  262. leave;
  263. }
  264. }
  265. //
  266. // The environment variable block consists of zero or more null
  267. // terminated UNICODE strings. Each string is of the form:
  268. //
  269. // name=value
  270. //
  271. // where the null termination is after the value.
  272. //
  273. if (p != NULL) while (*p) {
  274. //
  275. // Determine the size of the name and value portions of
  276. // the current string of the environment variable block.
  277. //
  278. CurrentName.Buffer = p;
  279. CurrentName.Length = 0;
  280. CurrentName.MaximumLength = 0;
  281. while (*p) {
  282. //
  283. // If we see an equal sign, then compute the size of
  284. // the name portion and scan for the end of the value.
  285. //
  286. if (*p == L'=' && p != CurrentName.Buffer) {
  287. CurrentName.Length = (USHORT)(p - CurrentName.Buffer)*sizeof(WCHAR);
  288. CurrentName.MaximumLength = (USHORT)(CurrentName.Length+sizeof(WCHAR));
  289. CurrentValue.Buffer = ++p;
  290. while(*p) {
  291. p++;
  292. }
  293. CurrentValue.Length = (USHORT)(p - CurrentValue.Buffer)*sizeof(WCHAR);
  294. CurrentValue.MaximumLength = (USHORT)(CurrentValue.Length+sizeof(WCHAR));
  295. //
  296. // At this point we have the length of both the name
  297. // and value portions, so exit the loop so we can
  298. // do the compare.
  299. //
  300. break;
  301. }
  302. else {
  303. p++;
  304. }
  305. }
  306. //
  307. // Skip over the terminating null character for this name=value
  308. // pair in preparation for the next iteration of the loop.
  309. //
  310. p++;
  311. //
  312. // Compare the current name with the one requested, ignore
  313. // case.
  314. //
  315. if (RtlEqualUnicodeString( Name, &CurrentName, TRUE )) {
  316. //
  317. // Names are equal. Always return the length of the
  318. // value string, excluding the terminating null. If
  319. // there is room in the caller's buffer, return a copy
  320. // of the value string and success status. Otherwise
  321. // return an error status. In the latter case, the caller
  322. // can examine the length field of their value string
  323. // so they can determine much memory is needed.
  324. //
  325. Value->Length = CurrentValue.Length;
  326. if (Value->MaximumLength >= CurrentValue.Length) {
  327. RtlCopyMemory( Value->Buffer,
  328. CurrentValue.Buffer,
  329. CurrentValue.Length
  330. );
  331. //
  332. // Null terminate returned string if there is room.
  333. //
  334. if (Value->MaximumLength > CurrentValue.Length) {
  335. Value->Buffer[ CurrentValue.Length/sizeof(WCHAR) ] = L'\0';
  336. }
  337. if ( !Environment || Environment == Peb->ProcessParameters->Environment) {
  338. RtlpEnvironCacheValid = TRUE;
  339. RtlpEnvironCacheName = CurrentName;
  340. RtlpEnvironCacheValue = CurrentValue;
  341. }
  342. Status = STATUS_SUCCESS;
  343. }
  344. else {
  345. Status = STATUS_BUFFER_TOO_SMALL;
  346. }
  347. break;
  348. }
  349. }
  350. // If it's not in the real env block, let's see if it's a pseudo environment variable
  351. if (Status == STATUS_VARIABLE_NOT_FOUND) {
  352. static const UNICODE_STRING CurrentWorkingDirectoryPseudoVariable = RTL_CONSTANT_STRING(L"__CD__");
  353. static const UNICODE_STRING ApplicationDirectoryPseudoVariable = RTL_CONSTANT_STRING(L"__APPDIR__");
  354. if (RtlEqualUnicodeString(Name, &CurrentWorkingDirectoryPseudoVariable, TRUE)) {
  355. // Get the PEB lock if we don't already have it.
  356. if (!PebLockLocked) {
  357. RtlAcquirePebLock();
  358. PebLockLocked = TRUE;
  359. }
  360. // get cdw here...
  361. CurrentValue = NtCurrentPeb()->ProcessParameters->CurrentDirectory.DosPath;
  362. Status = STATUS_SUCCESS;
  363. } else if (RtlEqualUnicodeString(Name, &ApplicationDirectoryPseudoVariable, TRUE)) {
  364. USHORT PrefixLength = 0;
  365. if (!PebLockLocked) {
  366. RtlAcquirePebLock();
  367. PebLockLocked = TRUE;
  368. }
  369. // get appdir here
  370. CurrentValue = NtCurrentPeb()->ProcessParameters->ImagePathName;
  371. Status = RtlFindCharInUnicodeString(
  372. RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END,
  373. &CurrentValue,
  374. &RtlDosPathSeperatorsString,
  375. &PrefixLength);
  376. if (NT_SUCCESS(Status)) {
  377. CurrentValue.Length = PrefixLength + sizeof(WCHAR);
  378. } else if (Status == STATUS_NOT_FOUND) {
  379. // Use the whole thing; just translate the status to successs.
  380. Status = STATUS_SUCCESS;
  381. }
  382. }
  383. if (NT_SUCCESS(Status)) {
  384. Value->Length = CurrentValue.Length;
  385. if (Value->MaximumLength >= CurrentValue.Length) {
  386. RtlCopyMemory(Value->Buffer, CurrentValue.Buffer, CurrentValue.Length);
  387. //
  388. // Null terminate returned string if there is room.
  389. //
  390. if (Value->MaximumLength > CurrentValue.Length)
  391. Value->Buffer[ CurrentValue.Length/sizeof(WCHAR) ] = L'\0';
  392. }
  393. }
  394. }
  395. } except (EXCEPTION_EXECUTE_HANDLER) {
  396. Status = STATUS_ACCESS_VIOLATION;
  397. }
  398. //
  399. // Release the Peb lock.
  400. //
  401. if (PebLockLocked)
  402. RtlReleasePebLock();
  403. //
  404. // Return status.
  405. //
  406. return Status;
  407. }
  408. NTSTATUS
  409. RtlSetEnvironmentVariable(
  410. IN OUT PVOID *Environment OPTIONAL,
  411. IN PUNICODE_STRING Name,
  412. IN PUNICODE_STRING Value OPTIONAL
  413. )
  414. {
  415. NTSTATUS Status;
  416. MEMORY_BASIC_INFORMATION MemoryInformation;
  417. UNICODE_STRING CurrentName;
  418. UNICODE_STRING CurrentValue;
  419. PVOID pOld, pNew;
  420. ULONG n, Size;
  421. SIZE_T NewSize;
  422. LONG CompareResult;
  423. PWSTR p, pStart, pEnd;
  424. PWSTR InsertionPoint;
  425. //
  426. // Validate passed in name and reject if zero length or anything but the first
  427. // character is an equal sign.
  428. //
  429. n = Name->Length / sizeof( WCHAR );
  430. if (n == 0) {
  431. return STATUS_INVALID_PARAMETER;
  432. }
  433. try {
  434. p = Name->Buffer;
  435. while (--n) {
  436. if (*++p == L'=') {
  437. return STATUS_INVALID_PARAMETER;
  438. }
  439. }
  440. } except (EXCEPTION_EXECUTE_HANDLER) {
  441. return GetExceptionCode();
  442. }
  443. RtlpEnvironCacheValid = FALSE;
  444. Status = STATUS_VARIABLE_NOT_FOUND;
  445. if (ARGUMENT_PRESENT( Environment )) {
  446. pOld = *Environment;
  447. }
  448. else {
  449. //
  450. // Acquire the Peb Lock for the duration while we munge the
  451. // environment variable storage block.
  452. //
  453. RtlAcquirePebLock();
  454. //
  455. // Capture the pointer to the current process's environment variable
  456. // block.
  457. //
  458. pOld = NtCurrentPeb()->ProcessParameters->Environment;
  459. }
  460. pNew = NULL;
  461. InsertionPoint = NULL;
  462. try {
  463. try {
  464. //
  465. // The environment variable block consists of zero or more null
  466. // terminated UNICODE strings. Each string is of the form:
  467. //
  468. // name=value
  469. //
  470. // where the null termination is after the value.
  471. //
  472. p = pOld;
  473. pEnd = NULL;
  474. if (p != NULL) while (*p) {
  475. //
  476. // Determine the size of the name and value portions of
  477. // the current string of the environment variable block.
  478. //
  479. CurrentName.Buffer = p;
  480. CurrentName.Length = 0;
  481. CurrentName.MaximumLength = 0;
  482. while (*p) {
  483. //
  484. // If we see an equal sign, then compute the size of
  485. // the name portion and scan for the end of the value.
  486. //
  487. if (*p == L'=' && p != CurrentName.Buffer) {
  488. CurrentName.Length = (USHORT)(p - CurrentName.Buffer) * sizeof(WCHAR);
  489. CurrentName.MaximumLength = (USHORT)(CurrentName.Length+sizeof(WCHAR));
  490. CurrentValue.Buffer = ++p;
  491. while(*p) {
  492. p++;
  493. }
  494. CurrentValue.Length = (USHORT)(p - CurrentValue.Buffer) * sizeof(WCHAR);
  495. CurrentValue.MaximumLength = (USHORT)(CurrentValue.Length+sizeof(WCHAR));
  496. //
  497. // At this point we have the length of both the name
  498. // and value portions, so exit the loop so we can
  499. // do the compare.
  500. //
  501. break;
  502. }
  503. else {
  504. p++;
  505. }
  506. }
  507. //
  508. // Skip over the terminating null character for this name=value
  509. // pair in preparation for the next iteration of the loop.
  510. //
  511. p++;
  512. //
  513. // Compare the current name with the one requested, ignore
  514. // case.
  515. //
  516. if (!(CompareResult = RtlCompareUnicodeString( Name, &CurrentName, TRUE ))) {
  517. //
  518. // Names are equal. Now find the end of the current
  519. // environment variable block.
  520. //
  521. pEnd = p;
  522. while (*pEnd) {
  523. while (*pEnd++) {
  524. }
  525. }
  526. pEnd++;
  527. if (!ARGUMENT_PRESENT( Value )) {
  528. //
  529. // If the caller did not specify a new value, then delete
  530. // the entire name=value pair by copying up the remainder
  531. // of the environment variable block.
  532. //
  533. RtlMoveMemory( CurrentName.Buffer,
  534. p,
  535. (ULONG) ((pEnd - p)*sizeof(WCHAR))
  536. );
  537. Status = STATUS_SUCCESS;
  538. }
  539. else
  540. if (Value->Length <= CurrentValue.Length) {
  541. //
  542. // New value is smaller, so copy new value, then null
  543. // terminate it, and then move up the remainder of the
  544. // variable block so it is immediately after the new
  545. // null terminated value.
  546. //
  547. pStart = CurrentValue.Buffer;
  548. RtlMoveMemory( pStart, Value->Buffer, Value->Length );
  549. pStart += Value->Length/sizeof(WCHAR);
  550. *pStart++ = L'\0';
  551. RtlMoveMemory( pStart, p,(ULONG)((pEnd - p)*sizeof(WCHAR)) );
  552. Status = STATUS_SUCCESS;
  553. }
  554. else {
  555. //
  556. // New value is larger, so query the current size of the
  557. // environment variable block. Return status if failure.
  558. //
  559. Status = ZwQueryVirtualMemory( NtCurrentProcess(),
  560. pOld,
  561. MemoryBasicInformation,
  562. &MemoryInformation,
  563. sizeof( MemoryInformation ),
  564. NULL
  565. );
  566. if (!NT_SUCCESS( Status )) {
  567. leave;
  568. }
  569. //
  570. // See if there is room for new, larger value. If not
  571. // allocate a new copy of the environment variable
  572. // block.
  573. //
  574. NewSize = (pEnd - (PWSTR)pOld)*sizeof(WCHAR) +
  575. Value->Length - CurrentValue.Length;
  576. if (NewSize >= MemoryInformation.RegionSize) {
  577. //
  578. // Allocate memory to contain a copy of the current
  579. // process's environment variable block. Return
  580. // status if failure.
  581. //
  582. Status = ZwAllocateVirtualMemory( NtCurrentProcess(),
  583. &pNew,
  584. 0,
  585. &NewSize,
  586. MEM_COMMIT,
  587. PAGE_READWRITE
  588. );
  589. if (!NT_SUCCESS( Status )) {
  590. leave;
  591. }
  592. //
  593. // Copy the current process's environment to the allocated memory
  594. // inserting the new value as we do the copy.
  595. //
  596. Size = (ULONG) (CurrentValue.Buffer - (PWSTR)pOld);
  597. RtlMoveMemory( pNew, pOld, Size*sizeof(WCHAR) );
  598. pStart = (PWSTR)pNew + Size;
  599. RtlMoveMemory( pStart, Value->Buffer, Value->Length );
  600. pStart += Value->Length/sizeof(WCHAR);
  601. *pStart++ = L'\0';
  602. RtlMoveMemory( pStart, p,(ULONG)((pEnd - p)*sizeof(WCHAR)));
  603. if (ARGUMENT_PRESENT( Environment ))
  604. *Environment = pNew;
  605. else {
  606. NtCurrentPeb()->ProcessParameters->Environment = pNew;
  607. NtCurrentPeb()->EnvironmentUpdateCount += 1;
  608. }
  609. ZwFreeVirtualMemory( NtCurrentProcess(),
  610. &pOld,
  611. &MemoryInformation.RegionSize,
  612. MEM_RELEASE
  613. );
  614. pNew = pOld;
  615. }
  616. else {
  617. pStart = CurrentValue.Buffer + Value->Length/sizeof(WCHAR) + 1;
  618. RtlMoveMemory( pStart, p,(ULONG)((pEnd - p)*sizeof(WCHAR)));
  619. *--pStart = L'\0';
  620. RtlMoveMemory( pStart - Value->Length/sizeof(WCHAR),
  621. Value->Buffer,
  622. Value->Length
  623. );
  624. }
  625. }
  626. break;
  627. }
  628. else
  629. if (CompareResult < 0) {
  630. //
  631. // Requested name is less than the current name. Save this
  632. // spot in case the variable is not in a sorted position.
  633. // The insertion point for the new variable is before the
  634. // variable just examined.
  635. //
  636. if (InsertionPoint == NULL) {
  637. InsertionPoint = CurrentName.Buffer;
  638. }
  639. }
  640. }
  641. //
  642. // If we found an insertion point, reset the string
  643. // pointer back to it.
  644. //
  645. if (InsertionPoint != NULL) {
  646. p = InsertionPoint;
  647. }
  648. //
  649. // If variable name not found and a new value parameter was specified
  650. // then insert the new variable name and its value at the appropriate
  651. // place in the environment variable block (i.e. where p points to).
  652. //
  653. if (pEnd == NULL && ARGUMENT_PRESENT( Value )) {
  654. if (p != NULL) {
  655. //
  656. // Name not found. Now find the end of the current
  657. // environment variable block.
  658. //
  659. pEnd = p;
  660. while (*pEnd) {
  661. while (*pEnd++) {
  662. }
  663. }
  664. pEnd++;
  665. //
  666. // New value is present, so query the current size of the
  667. // environment variable block. Return status if failure.
  668. //
  669. Status = ZwQueryVirtualMemory( NtCurrentProcess(),
  670. pOld,
  671. MemoryBasicInformation,
  672. &MemoryInformation,
  673. sizeof( MemoryInformation ),
  674. NULL
  675. );
  676. if (!NT_SUCCESS( Status )) {
  677. leave;
  678. }
  679. //
  680. // See if there is room for new, larger value. If not
  681. // allocate a new copy of the environment variable
  682. // block.
  683. //
  684. NewSize = (pEnd - (PWSTR)pOld) * sizeof(WCHAR) +
  685. Name->Length +
  686. sizeof(WCHAR) +
  687. Value->Length +
  688. sizeof(WCHAR);
  689. }
  690. else {
  691. NewSize = Name->Length +
  692. sizeof(WCHAR) +
  693. Value->Length +
  694. sizeof(WCHAR);
  695. MemoryInformation.RegionSize = 0;
  696. }
  697. if (NewSize >= MemoryInformation.RegionSize) {
  698. //
  699. // Allocate memory to contain a copy of the current
  700. // process's environment variable block. Return
  701. // status if failure.
  702. //
  703. Status = ZwAllocateVirtualMemory( NtCurrentProcess(),
  704. &pNew,
  705. 0,
  706. &NewSize,
  707. MEM_COMMIT,
  708. PAGE_READWRITE
  709. );
  710. if (!NT_SUCCESS( Status )) {
  711. leave;
  712. }
  713. //
  714. // Copy the current process's environment to the allocated memory
  715. // inserting the new value as we do the copy.
  716. //
  717. if (p != NULL) {
  718. Size = (ULONG)(p - (PWSTR)pOld);
  719. RtlMoveMemory( pNew, pOld, Size*sizeof(WCHAR) );
  720. }
  721. else {
  722. Size = 0;
  723. }
  724. pStart = (PWSTR)pNew + Size;
  725. RtlMoveMemory( pStart, Name->Buffer, Name->Length );
  726. pStart += Name->Length/sizeof(WCHAR);
  727. *pStart++ = L'=';
  728. RtlMoveMemory( pStart, Value->Buffer, Value->Length );
  729. pStart += Value->Length/sizeof(WCHAR);
  730. *pStart++ = L'\0';
  731. if (p != NULL) {
  732. RtlMoveMemory( pStart, p,(ULONG)((pEnd - p)*sizeof(WCHAR)) );
  733. }
  734. if (ARGUMENT_PRESENT( Environment )) {
  735. *Environment = pNew;
  736. }
  737. else {
  738. NtCurrentPeb()->ProcessParameters->Environment = pNew;
  739. NtCurrentPeb()->EnvironmentUpdateCount += 1;
  740. }
  741. ZwFreeVirtualMemory( NtCurrentProcess(),
  742. &pOld,
  743. &MemoryInformation.RegionSize,
  744. MEM_RELEASE
  745. );
  746. }
  747. else {
  748. pStart = p + Name->Length/sizeof(WCHAR) + 1 + Value->Length/sizeof(WCHAR) + 1;
  749. RtlMoveMemory( pStart, p,(ULONG)((pEnd - p)*sizeof(WCHAR)) );
  750. RtlMoveMemory( p, Name->Buffer, Name->Length );
  751. p += Name->Length/sizeof(WCHAR);
  752. *p++ = L'=';
  753. RtlMoveMemory( p, Value->Buffer, Value->Length );
  754. p += Value->Length/sizeof(WCHAR);
  755. *p++ = L'\0';
  756. }
  757. }
  758. } except(EXCEPTION_EXECUTE_HANDLER) {
  759. //
  760. // If abnormally terminating, assume access violation.
  761. //
  762. Status = STATUS_ACCESS_VIOLATION;
  763. }
  764. } finally {
  765. //
  766. // Release the Peb lock.
  767. //
  768. if (!ARGUMENT_PRESENT( Environment )) {
  769. RtlReleasePebLock();
  770. }
  771. }
  772. //
  773. // Return status.
  774. //
  775. return( Status );
  776. }