1 | /* |
2 | * Copyright 2016-present Facebook, Inc. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | #include <folly/portability/Stdlib.h> |
18 | |
19 | #ifdef _WIN32 |
20 | |
21 | #include <cstring> |
22 | |
23 | #include <errno.h> |
24 | |
25 | #include <folly/portability/Fcntl.h> |
26 | #include <folly/portability/SysStat.h> |
27 | #include <folly/portability/Windows.h> |
28 | |
29 | extern "C" { |
30 | char* mktemp(char* tn) { |
31 | return _mktemp(tn); |
32 | } |
33 | |
34 | // While yes, this is for a directory, due to this being windows, |
35 | // a file and directory can't have the same name, resulting in this |
36 | // still working just fine. |
37 | char* mkdtemp(char* tn) { |
38 | char* ptr = nullptr; |
39 | auto len = strlen(tn); |
40 | int ret = 0; |
41 | do { |
42 | strcpy(tn + len - 6, "XXXXXX" ); |
43 | ptr = mktemp(tn); |
44 | if (ptr == nullptr || *ptr == '\0') { |
45 | return nullptr; |
46 | } |
47 | ret = mkdir(ptr, 0700); |
48 | if (ret != 0 && errno != EEXIST) { |
49 | return nullptr; |
50 | } |
51 | } while (ret != 0); |
52 | return tn; |
53 | } |
54 | |
55 | int mkstemp(char* tn) { |
56 | char* ptr = nullptr; |
57 | auto len = strlen(tn); |
58 | int ret = 0; |
59 | do { |
60 | strcpy(tn + len - 6, "XXXXXX" ); |
61 | ptr = mktemp(tn); |
62 | if (ptr == nullptr || *ptr == '\0') { |
63 | return -1; |
64 | } |
65 | ret = open(ptr, O_RDWR | O_EXCL | O_CREAT, S_IRUSR | S_IWUSR); |
66 | if (ret == -1 && errno != EEXIST) { |
67 | return -1; |
68 | } |
69 | } while (ret == -1); |
70 | return ret; |
71 | } |
72 | |
73 | char* realpath(const char* path, char* resolved_path) { |
74 | // I sure hope the caller gave us _MAX_PATH space in the buffer.... |
75 | return _fullpath(resolved_path, path, _MAX_PATH); |
76 | } |
77 | |
78 | int setenv(const char* name, const char* value, int overwrite) { |
79 | if (overwrite == 0 && getenv(name) != nullptr) { |
80 | return 0; |
81 | } |
82 | |
83 | if (*value != '\0') { |
84 | auto e = _putenv_s(name, value); |
85 | if (e != 0) { |
86 | errno = e; |
87 | return -1; |
88 | } |
89 | return 0; |
90 | } |
91 | |
92 | // We are trying to set the value to an empty string, but |
93 | // _putenv_s deletes entries if the value is an empty string, |
94 | // and just calling SetEnvironmentVariableA doesn't update |
95 | // _environ, so we have to do these terrible things. |
96 | if (_putenv_s(name, " " ) != 0) { |
97 | errno = EINVAL; |
98 | return -1; |
99 | } |
100 | |
101 | // Here lies the documentation we blatently ignore to make |
102 | // this work >_>... |
103 | *getenv(name) = '\0'; |
104 | // This would result in a double null termination, which |
105 | // normally signifies the end of the environment variable |
106 | // list, so we stick a completely empty environment variable |
107 | // into the list instead. |
108 | *(getenv(name) + 1) = '='; |
109 | |
110 | // If _wenviron is null, the wide environment has not been initialized |
111 | // yet, and we don't need to try to update it. |
112 | // We have to do this otherwise we'd be forcing the initialization and |
113 | // maintenance of the wide environment even though it's never actually |
114 | // used in most programs. |
115 | if (_wenviron != nullptr) { |
116 | wchar_t buf[_MAX_ENV + 1]; |
117 | size_t len; |
118 | if (mbstowcs_s(&len, buf, _MAX_ENV + 1, name, _MAX_ENV) != 0) { |
119 | errno = EINVAL; |
120 | return -1; |
121 | } |
122 | *_wgetenv(buf) = u'\0'; |
123 | *(_wgetenv(buf) + 1) = u'='; |
124 | } |
125 | |
126 | // And now, we have to update the outer environment to have |
127 | // a proper empty value. |
128 | if (!SetEnvironmentVariableA(name, value)) { |
129 | errno = EINVAL; |
130 | return -1; |
131 | } |
132 | return 0; |
133 | } |
134 | |
135 | int unsetenv(const char* name) { |
136 | if (_putenv_s(name, "" ) != 0) { |
137 | return -1; |
138 | } |
139 | return 0; |
140 | } |
141 | } |
142 | |
143 | #endif |
144 | |
145 | #if !__linux__ && !FOLLY_MOBILE |
146 | |
147 | #include <string> |
148 | #include <vector> |
149 | |
150 | extern "C" int clearenv() { |
151 | std::vector<std::string> data; |
152 | for (auto it = environ; it && *it; ++it) { |
153 | std::string entry(*it); |
154 | auto equalsPosition = entry.find('='); |
155 | if (equalsPosition == std::string::npos || equalsPosition == 0) { |
156 | // It's either a drive setting (if on Windows), or something clowny is |
157 | // going on in the environment. |
158 | continue; |
159 | } else { |
160 | data.emplace_back(entry.substr(0, equalsPosition)); |
161 | } |
162 | } |
163 | |
164 | for (auto s : data) { |
165 | if (unsetenv(s.c_str()) != 0) |
166 | return -1; |
167 | } |
168 | |
169 | return 0; |
170 | } |
171 | |
172 | #endif |
173 | |