1 // filesystem system_crypt_random.cpp ------------------------------------------------//
3 // Copyright Beman Dawes 2010
5 // Distributed under the Boost Software License, Version 1.0.
6 // See http://www.boost.org/LICENSE_1_0.txt
8 // Library home page: http://www.boost.org/libs/filesystem
10 //--------------------------------------------------------------------------------------//
12 #include <boost/config.hpp>
13 #if !defined( BOOST_NO_STD_WSTRING )
14 // Boost.Filesystem V3 and later requires std::wstring support.
15 // During the transition to V3, libraries are compiled with both V2 and V3 sources.
16 // On old compilers that don't support V3 anyhow, we just skip everything so the compile
17 // will succeed and the library can be built.
19 // define BOOST_FILESYSTEM_SOURCE so that <boost/filesystem/config.hpp> knows
20 // the library is being built (possibly exporting rather than importing code)
21 #define BOOST_FILESYSTEM_SOURCE
23 #ifndef BOOST_SYSTEM_NO_DEPRECATED
24 # define BOOST_SYSTEM_NO_DEPRECATED
27 #include <boost/filesystem/v3/operations.hpp>
29 # ifdef BOOST_POSIX_API
31 # else // BOOST_WINDOWS_API
33 # include <wincrypt.h>
34 # pragma comment(lib, "Advapi32.lib")
39 void fail(int err
, boost::system::error_code
* ec
)
42 BOOST_FILESYSTEM_THROW( boost::system::system_error(err
,
43 boost::system::system_category(),
44 "boost::filesystem::unique_path"));
46 ec
->assign(err
, boost::system::system_category());
50 void system_crypt_random(void* buf
, std::size_t len
, boost::system::error_code
* ec
)
52 # ifdef BOOST_POSIX_API
54 int file
= open("/dev/urandom", O_RDONLY
);
57 file
= open("/dev/random", O_RDONLY
);
65 size_t bytes_read
= 0;
66 while (bytes_read
< len
)
68 ssize_t n
= read(file
, buf
, len
- bytes_read
);
76 buf
= static_cast<char*>(buf
) + n
;
81 # else // BOOST_WINDOWS_API
86 if (!::CryptAcquireContextW(&handle
, 0, 0, PROV_RSA_FULL
, 0))
88 errval
= ::GetLastError();
89 if (errval
== NTE_BAD_KEYSET
)
91 if (!::CryptAcquireContextW(&handle
, 0, 0, PROV_RSA_FULL
, CRYPT_NEWKEYSET
))
93 errval
= ::GetLastError();
101 BOOL gen_ok
= ::CryptGenRandom(handle
, len
, static_cast<unsigned char*>(buf
));
103 errval
= ::GetLastError();
104 ::CryptReleaseContext(handle
, 0);
113 } // unnamed namespace
115 namespace boost
{ namespace filesystem3
{ namespace detail
{
117 BOOST_FILESYSTEM_DECL
118 path
unique_path(const path
& model
, system::error_code
* ec
)
120 std::wstring
s (model
.wstring()); // std::string ng for MBCS encoded POSIX
121 const wchar_t hex
[] = L
"0123456789abcdef";
122 const int n_ran
= 16;
123 const int max_nibbles
= 2 * n_ran
; // 4-bits per nibble
126 int nibbles_used
= max_nibbles
;
127 for(std::wstring::size_type i
=0; i
< s
.size(); ++i
)
129 if (s
[i
] == L
'%') // digit request
131 if (nibbles_used
== max_nibbles
)
133 system_crypt_random(ran
, sizeof(ran
), ec
);
138 int c
= ran
[nibbles_used
/2];
139 c
>>= 4 * (nibbles_used
++ & 1); // if odd, shift right 1 nibble
140 s
[i
] = hex
[c
& 0xf]; // convert to hex digit and replace
144 if (ec
!= 0) ec
->clear();
151 #endif // no wide character support