Stdlib.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  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. #include <folly/portability/Stdlib.h>
  17. #ifdef _WIN32
  18. #include <cstring>
  19. #include <errno.h>
  20. #include <folly/portability/Fcntl.h>
  21. #include <folly/portability/SysStat.h>
  22. #include <folly/portability/Windows.h>
  23. extern "C" {
  24. char* mktemp(char* tn) {
  25. return _mktemp(tn);
  26. }
  27. // While yes, this is for a directory, due to this being windows,
  28. // a file and directory can't have the same name, resulting in this
  29. // still working just fine.
  30. char* mkdtemp(char* tn) {
  31. char* ptr = nullptr;
  32. auto len = strlen(tn);
  33. int ret = 0;
  34. do {
  35. strcpy(tn + len - 6, "XXXXXX");
  36. ptr = mktemp(tn);
  37. if (ptr == nullptr || *ptr == '\0') {
  38. return nullptr;
  39. }
  40. ret = mkdir(ptr, 0700);
  41. if (ret != 0 && errno != EEXIST) {
  42. return nullptr;
  43. }
  44. } while (ret != 0);
  45. return tn;
  46. }
  47. int mkstemp(char* tn) {
  48. char* ptr = nullptr;
  49. auto len = strlen(tn);
  50. int ret = 0;
  51. do {
  52. strcpy(tn + len - 6, "XXXXXX");
  53. ptr = mktemp(tn);
  54. if (ptr == nullptr || *ptr == '\0') {
  55. return -1;
  56. }
  57. ret = open(ptr, O_RDWR | O_EXCL | O_CREAT, S_IRUSR | S_IWUSR);
  58. if (ret == -1 && errno != EEXIST) {
  59. return -1;
  60. }
  61. } while (ret == -1);
  62. return ret;
  63. }
  64. char* realpath(const char* path, char* resolved_path) {
  65. // I sure hope the caller gave us _MAX_PATH space in the buffer....
  66. return _fullpath(resolved_path, path, _MAX_PATH);
  67. }
  68. int setenv(const char* name, const char* value, int overwrite) {
  69. if (overwrite == 0 && getenv(name) != nullptr) {
  70. return 0;
  71. }
  72. if (*value != '\0') {
  73. auto e = _putenv_s(name, value);
  74. if (e != 0) {
  75. errno = e;
  76. return -1;
  77. }
  78. return 0;
  79. }
  80. // We are trying to set the value to an empty string, but
  81. // _putenv_s deletes entries if the value is an empty string,
  82. // and just calling SetEnvironmentVariableA doesn't update
  83. // _environ, so we have to do these terrible things.
  84. if (_putenv_s(name, " ") != 0) {
  85. errno = EINVAL;
  86. return -1;
  87. }
  88. // Here lies the documentation we blatently ignore to make
  89. // this work >_>...
  90. *getenv(name) = '\0';
  91. // This would result in a double null termination, which
  92. // normally signifies the end of the environment variable
  93. // list, so we stick a completely empty environment variable
  94. // into the list instead.
  95. *(getenv(name) + 1) = '=';
  96. // If _wenviron is null, the wide environment has not been initialized
  97. // yet, and we don't need to try to update it.
  98. // We have to do this otherwise we'd be forcing the initialization and
  99. // maintenance of the wide environment even though it's never actually
  100. // used in most programs.
  101. if (_wenviron != nullptr) {
  102. wchar_t buf[_MAX_ENV + 1];
  103. size_t len;
  104. if (mbstowcs_s(&len, buf, _MAX_ENV + 1, name, _MAX_ENV) != 0) {
  105. errno = EINVAL;
  106. return -1;
  107. }
  108. *_wgetenv(buf) = u'\0';
  109. *(_wgetenv(buf) + 1) = u'=';
  110. }
  111. // And now, we have to update the outer environment to have
  112. // a proper empty value.
  113. if (!SetEnvironmentVariableA(name, value)) {
  114. errno = EINVAL;
  115. return -1;
  116. }
  117. return 0;
  118. }
  119. int unsetenv(const char* name) {
  120. if (_putenv_s(name, "") != 0) {
  121. return -1;
  122. }
  123. return 0;
  124. }
  125. }
  126. #endif
  127. #if !__linux__ && !FOLLY_MOBILE
  128. #include <string>
  129. #include <vector>
  130. extern "C" int clearenv() {
  131. std::vector<std::string> data;
  132. for (auto it = environ; it && *it; ++it) {
  133. std::string entry(*it);
  134. auto equalsPosition = entry.find('=');
  135. if (equalsPosition == std::string::npos || equalsPosition == 0) {
  136. // It's either a drive setting (if on Windows), or something clowny is
  137. // going on in the environment.
  138. continue;
  139. } else {
  140. data.emplace_back(entry.substr(0, equalsPosition));
  141. }
  142. }
  143. for (auto s : data) {
  144. if (unsetenv(s.c_str()) != 0)
  145. return -1;
  146. }
  147. return 0;
  148. }
  149. #endif