tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

util.h (3684B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=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 file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef util_h__
      8 #define util_h__
      9 
     10 #include <cassert>
     11 #include <cstdlib>
     12 #include <iomanip>
     13 #include <iostream>
     14 #include <sstream>
     15 #include <sys/stat.h>
     16 #include <vector>
     17 #if defined(_WIN32)
     18 #include <windows.h>
     19 #include <codecvt>
     20 #include <direct.h>
     21 #else
     22 #include <unistd.h>
     23 #endif
     24 
     25 #include "nspr.h"
     26 
     27 static inline std::vector<uint8_t> hex_string_to_bytes(std::string s) {
     28  std::vector<uint8_t> bytes;
     29  for (size_t i = 0; i < s.length(); i += 2) {
     30    bytes.push_back(std::stoul(s.substr(i, 2), nullptr, 16));
     31  }
     32  return bytes;
     33 }
     34 
     35 // Given a prefix, attempts to create a unique directory that the user can do
     36 // work in without impacting other tests. For example, if given the prefix
     37 // "scratch", a directory like "scratch05c17b25" will be created in the current
     38 // working directory (or the location specified by NSS_GTEST_WORKDIR, if
     39 // defined).
     40 // Upon destruction, the implementation will attempt to delete the directory.
     41 // However, no attempt is made to first remove files in the directory - the
     42 // user is responsible for this. If the directory is not empty, deleting it will
     43 // fail.
     44 // Statistically, it is technically possible to fail to create a unique
     45 // directory name, but this is extremely unlikely given the expected workload of
     46 // this implementation.
     47 class ScopedUniqueDirectory {
     48 public:
     49  explicit ScopedUniqueDirectory(const std::string &prefix) {
     50    std::string path;
     51    const char *workingDirectory = PR_GetEnvSecure("NSS_GTEST_WORKDIR");
     52    if (workingDirectory) {
     53      path.assign(workingDirectory);
     54    }
     55    path.append(prefix);
     56    for (int i = 0; i < RETRY_LIMIT; i++) {
     57      std::string pathCopy(path);
     58      // TryMakingDirectory will modify its input. If it fails, we want to throw
     59      // away the modified result.
     60      if (TryMakingDirectory(pathCopy)) {
     61        mPath.assign(pathCopy);
     62        break;
     63      }
     64    }
     65    assert(mPath.length() > 0);
     66 #if defined(_WIN32)
     67    // sqldb always uses UTF-8 regardless of the current system locale.
     68    DWORD len =
     69        MultiByteToWideChar(CP_ACP, 0, mPath.data(), mPath.size(), nullptr, 0);
     70    std::vector<wchar_t> buf(len, L'\0');
     71    MultiByteToWideChar(CP_ACP, 0, mPath.data(), mPath.size(), buf.data(),
     72                        buf.size());
     73    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
     74    mUTF8Path = converter.to_bytes(std::wstring(buf.begin(), buf.end()));
     75 #else
     76    mUTF8Path = mPath;
     77 #endif
     78  }
     79 
     80  // NB: the directory must be empty upon destruction
     81  ~ScopedUniqueDirectory() { assert(rmdir(mPath.c_str()) == 0); }
     82 
     83  const std::string &GetPath() { return mPath; }
     84  const std::string &GetUTF8Path() { return mUTF8Path; }
     85 
     86 private:
     87  static const int RETRY_LIMIT = 5;
     88 
     89  static void GenerateRandomName(/*in/out*/ std::string &prefix) {
     90    std::stringstream ss;
     91    ss << prefix;
     92    // RAND_MAX is at least 32767.
     93    ss << std::setfill('0') << std::setw(4) << std::hex << rand() << rand();
     94    // This will overwrite the value of prefix. This is a little inefficient,
     95    // but at least it makes the code simple.
     96    ss >> prefix;
     97  }
     98 
     99  static bool TryMakingDirectory(/*in/out*/ std::string &prefix) {
    100    GenerateRandomName(prefix);
    101 #if defined(_WIN32)
    102    return _mkdir(prefix.c_str()) == 0;
    103 #else
    104    return mkdir(prefix.c_str(), 0777) == 0;
    105 #endif
    106  }
    107 
    108  std::string mPath;
    109  std::string mUTF8Path;
    110 };
    111 
    112 #endif  // util_h__