Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "nsEnvironment.h"
8 : #include "prenv.h"
9 : #include "nsBaseHashtable.h"
10 : #include "nsHashKeys.h"
11 : #include "nsPromiseFlatString.h"
12 : #include "nsDependentString.h"
13 : #include "nsNativeCharsetUtils.h"
14 : #include "mozilla/Printf.h"
15 :
16 : using namespace mozilla;
17 :
18 62 : NS_IMPL_ISUPPORTS(nsEnvironment, nsIEnvironment)
19 :
20 : nsresult
21 1 : nsEnvironment::Create(nsISupports* aOuter, REFNSIID aIID, void** aResult)
22 : {
23 : nsresult rv;
24 1 : *aResult = nullptr;
25 :
26 1 : if (aOuter) {
27 0 : return NS_ERROR_NO_AGGREGATION;
28 : }
29 :
30 1 : nsEnvironment* obj = new nsEnvironment();
31 :
32 1 : rv = obj->QueryInterface(aIID, aResult);
33 1 : if (NS_FAILED(rv)) {
34 0 : delete obj;
35 : }
36 1 : return rv;
37 : }
38 :
39 0 : nsEnvironment::~nsEnvironment()
40 : {
41 0 : }
42 :
43 : NS_IMETHODIMP
44 3 : nsEnvironment::Exists(const nsAString& aName, bool* aOutValue)
45 : {
46 6 : nsAutoCString nativeName;
47 3 : nsresult rv = NS_CopyUnicodeToNative(aName, nativeName);
48 3 : if (NS_WARN_IF(NS_FAILED(rv))) {
49 0 : return rv;
50 : }
51 :
52 6 : nsAutoCString nativeVal;
53 : #if defined(XP_UNIX)
54 : /* For Unix/Linux platforms we follow the Unix definition:
55 : * An environment variable exists when |getenv()| returns a non-nullptr
56 : * value. An environment variable does not exist when |getenv()| returns
57 : * nullptr.
58 : */
59 3 : const char* value = PR_GetEnv(nativeName.get());
60 3 : *aOutValue = value && *value;
61 : #else
62 : /* For non-Unix/Linux platforms we have to fall back to a
63 : * "portable" definition (which is incorrect for Unix/Linux!!!!)
64 : * which simply checks whether the string returned by |Get()| is empty
65 : * or not.
66 : */
67 : nsAutoString value;
68 : Get(aName, value);
69 : *aOutValue = !value.IsEmpty();
70 : #endif /* XP_UNIX */
71 :
72 3 : return NS_OK;
73 : }
74 :
75 : NS_IMETHODIMP
76 0 : nsEnvironment::Get(const nsAString& aName, nsAString& aOutValue)
77 : {
78 0 : nsAutoCString nativeName;
79 0 : nsresult rv = NS_CopyUnicodeToNative(aName, nativeName);
80 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
81 0 : return rv;
82 : }
83 :
84 0 : nsAutoCString nativeVal;
85 0 : const char* value = PR_GetEnv(nativeName.get());
86 0 : if (value && *value) {
87 0 : rv = NS_CopyNativeToUnicode(nsDependentCString(value), aOutValue);
88 : } else {
89 0 : aOutValue.Truncate();
90 0 : rv = NS_OK;
91 : }
92 :
93 0 : return rv;
94 : }
95 :
96 : /* Environment strings must have static duration; We're gonna leak all of this
97 : * at shutdown: this is by design, caused how Unix/Linux implement environment
98 : * vars.
99 : */
100 :
101 : typedef nsBaseHashtableET<nsCharPtrHashKey, char*> EnvEntryType;
102 : typedef nsTHashtable<EnvEntryType> EnvHashType;
103 :
104 : static EnvHashType* gEnvHash = nullptr;
105 :
106 : static bool
107 0 : EnsureEnvHash()
108 : {
109 0 : if (gEnvHash) {
110 0 : return true;
111 : }
112 :
113 0 : gEnvHash = new EnvHashType;
114 0 : if (!gEnvHash) {
115 0 : return false;
116 : }
117 :
118 0 : return true;
119 : }
120 :
121 : NS_IMETHODIMP
122 0 : nsEnvironment::Set(const nsAString& aName, const nsAString& aValue)
123 : {
124 0 : nsAutoCString nativeName;
125 0 : nsAutoCString nativeVal;
126 :
127 0 : nsresult rv = NS_CopyUnicodeToNative(aName, nativeName);
128 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
129 0 : return rv;
130 : }
131 :
132 0 : rv = NS_CopyUnicodeToNative(aValue, nativeVal);
133 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
134 0 : return rv;
135 : }
136 :
137 0 : MutexAutoLock lock(mLock);
138 :
139 0 : if (!EnsureEnvHash()) {
140 0 : return NS_ERROR_UNEXPECTED;
141 : }
142 :
143 0 : EnvEntryType* entry = gEnvHash->PutEntry(nativeName.get());
144 0 : if (!entry) {
145 0 : return NS_ERROR_OUT_OF_MEMORY;
146 : }
147 :
148 : SmprintfPointer newData = mozilla::Smprintf("%s=%s",
149 : nativeName.get(),
150 0 : nativeVal.get());
151 0 : if (!newData) {
152 0 : return NS_ERROR_OUT_OF_MEMORY;
153 : }
154 :
155 0 : PR_SetEnv(newData.get());
156 0 : if (entry->mData) {
157 0 : mozilla::SmprintfFree(entry->mData);
158 : }
159 0 : entry->mData = newData.release();
160 0 : return NS_OK;
161 9 : }
162 :
163 :
|