]>
git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/filesystem/src/unique_path.cpp
1 // filesystem unique_path.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 #ifndef BOOST_SYSTEM_NO_DEPRECATED
13 # define BOOST_SYSTEM_NO_DEPRECATED
16 #include <boost/filesystem/operations.hpp>
19 # ifdef BOOST_POSIX_API
21 # ifdef BOOST_HAS_UNISTD_H
24 # else // BOOST_WINDOWS_API
26 # include <wincrypt.h>
28 # pragma comment(lib, "Advapi32.lib")
34 void fail(int err
, boost::system::error_code
* ec
)
37 BOOST_FILESYSTEM_THROW( boost::system::system_error(err
,
38 boost::system::system_category(),
39 "boost::filesystem::unique_path"));
41 ec
->assign(err
, boost::system::system_category());
45 #ifdef BOOST_WINDOWS_API
47 int acquire_crypt_handle(HCRYPTPROV
& handle
)
49 if (::CryptAcquireContextW(&handle
, 0, 0, PROV_RSA_FULL
, CRYPT_VERIFYCONTEXT
| CRYPT_SILENT
))
52 int errval
= ::GetLastError();
53 if (errval
!= NTE_BAD_KEYSET
)
56 if (::CryptAcquireContextW(&handle
, 0, 0, PROV_RSA_FULL
, CRYPT_NEWKEYSET
| CRYPT_VERIFYCONTEXT
| CRYPT_SILENT
))
59 errval
= ::GetLastError();
60 // Another thread could have attempted to create the keyset at the same time.
61 if (errval
!= NTE_EXISTS
)
64 if (::CryptAcquireContextW(&handle
, 0, 0, PROV_RSA_FULL
, CRYPT_VERIFYCONTEXT
| CRYPT_SILENT
))
67 return ::GetLastError();
72 void system_crypt_random(void* buf
, std::size_t len
, boost::system::error_code
* ec
)
74 # ifdef BOOST_POSIX_API
76 int file
= open("/dev/urandom", O_RDONLY
);
79 file
= open("/dev/random", O_RDONLY
);
87 size_t bytes_read
= 0;
88 while (bytes_read
< len
)
90 ssize_t n
= read(file
, buf
, len
- bytes_read
);
98 buf
= static_cast<char*>(buf
) + n
;
103 # else // BOOST_WINDOWS_API
106 int errval
= acquire_crypt_handle(handle
);
110 BOOL gen_ok
= ::CryptGenRandom(handle
, static_cast<DWORD
>(len
), static_cast<unsigned char*>(buf
));
112 errval
= ::GetLastError();
113 ::CryptReleaseContext(handle
, 0);
122 } // unnamed namespace
124 namespace boost
{ namespace filesystem
{ namespace detail
{
126 BOOST_FILESYSTEM_DECL
127 path
unique_path(const path
& model
, system::error_code
* ec
)
129 // This function used wstring for fear of misidentifying
130 // a part of a multibyte character as a percent sign.
131 // However, double byte encodings only have 80-FF as lead
132 // bytes and 40-7F as trailing bytes, whereas % is 25.
133 // So, use string on POSIX and avoid conversions.
135 path::string_type
s( model
.native() );
137 #ifdef BOOST_WINDOWS_API
138 const wchar_t hex
[] = L
"0123456789abcdef";
139 const wchar_t percent
= L
'%';
141 const char hex
[] = "0123456789abcdef";
142 const char percent
= '%';
145 char ran
[] = "123456789abcdef"; // init to avoid clang static analyzer message
147 assert(sizeof(ran
) == 16);
148 const int max_nibbles
= 2 * sizeof(ran
); // 4-bits per nibble
150 int nibbles_used
= max_nibbles
;
151 for(path::string_type::size_type i
=0; i
< s
.size(); ++i
)
153 if (s
[i
] == percent
) // digit request
155 if (nibbles_used
== max_nibbles
)
157 system_crypt_random(ran
, sizeof(ran
), ec
);
162 int c
= ran
[nibbles_used
/2];
163 c
>>= 4 * (nibbles_used
++ & 1); // if odd, shift right 1 nibble
164 s
[i
] = hex
[c
& 0xf]; // convert to hex digit and replace
168 if (ec
!= 0) ec
->clear();