| // filesystem system_crypt_random.cpp ------------------------------------------------// |
| |
| // Copyright Beman Dawes 2010 |
| |
| // Distributed under the Boost Software License, Version 1.0. |
| // See http://www.boost.org/LICENSE_1_0.txt |
| |
| // Library home page: http://www.boost.org/libs/filesystem |
| |
| //--------------------------------------------------------------------------------------// |
| |
| #include <boost/config.hpp> |
| #if !defined( BOOST_NO_STD_WSTRING ) |
| // Boost.Filesystem V3 and later requires std::wstring support. |
| // During the transition to V3, libraries are compiled with both V2 and V3 sources. |
| // On old compilers that don't support V3 anyhow, we just skip everything so the compile |
| // will succeed and the library can be built. |
| |
| // define BOOST_FILESYSTEM_SOURCE so that <boost/filesystem/config.hpp> knows |
| // the library is being built (possibly exporting rather than importing code) |
| #define BOOST_FILESYSTEM_SOURCE |
| |
| #ifndef BOOST_SYSTEM_NO_DEPRECATED |
| # define BOOST_SYSTEM_NO_DEPRECATED |
| #endif |
| |
| #include <boost/filesystem/v3/operations.hpp> |
| |
| # ifdef BOOST_POSIX_API |
| # include <fcntl.h> |
| # else // BOOST_WINDOWS_API |
| # include <windows.h> |
| # include <wincrypt.h> |
| # pragma comment(lib, "Advapi32.lib") |
| # endif |
| |
| namespace { |
| |
| void fail(int err, boost::system::error_code* ec) |
| { |
| if (ec == 0) |
| BOOST_FILESYSTEM_THROW( boost::system::system_error(err, |
| boost::system::system_category(), |
| "boost::filesystem::unique_path")); |
| |
| ec->assign(err, boost::system::system_category()); |
| return; |
| } |
| |
| void system_crypt_random(void* buf, std::size_t len, boost::system::error_code* ec) |
| { |
| # ifdef BOOST_POSIX_API |
| |
| int file = open("/dev/urandom", O_RDONLY); |
| if (file == -1) |
| { |
| file = open("/dev/random", O_RDONLY); |
| if (file == -1) |
| { |
| fail(errno, ec); |
| return; |
| } |
| } |
| |
| size_t bytes_read = 0; |
| while (bytes_read < len) |
| { |
| ssize_t n = read(file, buf, len - bytes_read); |
| if (n == -1) |
| { |
| close(file); |
| fail(errno, ec); |
| return; |
| } |
| bytes_read += n; |
| buf = static_cast<char*>(buf) + n; |
| } |
| |
| close(file); |
| |
| # else // BOOST_WINDOWS_API |
| |
| HCRYPTPROV handle; |
| int errval = 0; |
| |
| if (!::CryptAcquireContextW(&handle, 0, 0, PROV_RSA_FULL, 0)) |
| { |
| errval = ::GetLastError(); |
| if (errval == NTE_BAD_KEYSET) |
| { |
| if (!::CryptAcquireContextW(&handle, 0, 0, PROV_RSA_FULL, CRYPT_NEWKEYSET)) |
| { |
| errval = ::GetLastError(); |
| } |
| else errval = 0; |
| } |
| } |
| |
| if (!errval) |
| { |
| BOOL gen_ok = ::CryptGenRandom(handle, len, static_cast<unsigned char*>(buf)); |
| if (!gen_ok) |
| errval = ::GetLastError(); |
| ::CryptReleaseContext(handle, 0); |
| } |
| |
| if (!errval) return; |
| |
| fail(errval, ec); |
| # endif |
| } |
| |
| } // unnamed namespace |
| |
| namespace boost { namespace filesystem3 { namespace detail { |
| |
| BOOST_FILESYSTEM_DECL |
| path unique_path(const path& model, system::error_code* ec) |
| { |
| std::wstring s (model.wstring()); // std::string ng for MBCS encoded POSIX |
| const wchar_t hex[] = L"0123456789abcdef"; |
| const int n_ran = 16; |
| const int max_nibbles = 2 * n_ran; // 4-bits per nibble |
| char ran[n_ran]; |
| |
| int nibbles_used = max_nibbles; |
| for(std::wstring::size_type i=0; i < s.size(); ++i) |
| { |
| if (s[i] == L'%') // digit request |
| { |
| if (nibbles_used == max_nibbles) |
| { |
| system_crypt_random(ran, sizeof(ran), ec); |
| if (ec != 0 && *ec) |
| return ""; |
| nibbles_used = 0; |
| } |
| int c = ran[nibbles_used/2]; |
| c >>= 4 * (nibbles_used++ & 1); // if odd, shift right 1 nibble |
| s[i] = hex[c & 0xf]; // convert to hex digit and replace |
| } |
| } |
| |
| if (ec != 0) ec->clear(); |
| |
| return s; |
| } |
| |
| }}} |
| |
| #endif // no wide character support |