]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/filesystem/src/unique_path.cpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / libs / filesystem / src / unique_path.cpp
CommitLineData
7c673cae
FG
1// filesystem unique_path.cpp --------------------------------------------------------//
2
3// Copyright Beman Dawes 2010
4
5// Distributed under the Boost Software License, Version 1.0.
6// See http://www.boost.org/LICENSE_1_0.txt
7
8// Library home page: http://www.boost.org/libs/filesystem
9
10//--------------------------------------------------------------------------------------//
11
12// define BOOST_FILESYSTEM_SOURCE so that <boost/filesystem/config.hpp> knows
13// the library is being built (possibly exporting rather than importing code)
14#define BOOST_FILESYSTEM_SOURCE
15
16#ifndef BOOST_SYSTEM_NO_DEPRECATED
17# define BOOST_SYSTEM_NO_DEPRECATED
18#endif
19
20#include <boost/filesystem/operations.hpp>
21#include <cassert>
22
23# ifdef BOOST_POSIX_API
24# include <fcntl.h>
25# ifdef BOOST_HAS_UNISTD_H
26# include <unistd.h>
27# endif
28# else // BOOST_WINDOWS_API
29# include <windows.h>
30# include <wincrypt.h>
b32b8144
FG
31# ifdef _MSC_VER
32# pragma comment(lib, "Advapi32.lib")
33# endif
7c673cae
FG
34# endif
35
36namespace {
37
38void fail(int err, boost::system::error_code* ec)
39{
40 if (ec == 0)
41 BOOST_FILESYSTEM_THROW( boost::system::system_error(err,
42 boost::system::system_category(),
43 "boost::filesystem::unique_path"));
44
45 ec->assign(err, boost::system::system_category());
46 return;
47}
48
49#ifdef BOOST_WINDOWS_API
50
51int acquire_crypt_handle(HCRYPTPROV& handle)
52{
53 if (::CryptAcquireContextW(&handle, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
54 return 0;
55
56 int errval = ::GetLastError();
57 if (errval != NTE_BAD_KEYSET)
58 return errval;
59
60 if (::CryptAcquireContextW(&handle, 0, 0, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
61 return 0;
62
63 errval = ::GetLastError();
64 // Another thread could have attempted to create the keyset at the same time.
65 if (errval != NTE_EXISTS)
66 return errval;
67
68 if (::CryptAcquireContextW(&handle, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
69 return 0;
70
71 return ::GetLastError();
72}
73
74#endif
75
76void system_crypt_random(void* buf, std::size_t len, boost::system::error_code* ec)
77{
78# ifdef BOOST_POSIX_API
79
80 int file = open("/dev/urandom", O_RDONLY);
81 if (file == -1)
82 {
83 file = open("/dev/random", O_RDONLY);
84 if (file == -1)
85 {
86 fail(errno, ec);
87 return;
88 }
89 }
90
91 size_t bytes_read = 0;
92 while (bytes_read < len)
93 {
94 ssize_t n = read(file, buf, len - bytes_read);
95 if (n == -1)
96 {
97 close(file);
98 fail(errno, ec);
99 return;
100 }
101 bytes_read += n;
102 buf = static_cast<char*>(buf) + n;
103 }
104
105 close(file);
106
107# else // BOOST_WINDOWS_API
108
109 HCRYPTPROV handle;
110 int errval = acquire_crypt_handle(handle);
111
112 if (!errval)
113 {
114 BOOL gen_ok = ::CryptGenRandom(handle, len, static_cast<unsigned char*>(buf));
115 if (!gen_ok)
116 errval = ::GetLastError();
117 ::CryptReleaseContext(handle, 0);
118 }
119
120 if (!errval) return;
121
122 fail(errval, ec);
123# endif
124}
125
126} // unnamed namespace
127
128namespace boost { namespace filesystem { namespace detail {
129
130BOOST_FILESYSTEM_DECL
131path unique_path(const path& model, system::error_code* ec)
132{
133 std::wstring s (model.wstring()); // std::string ng for MBCS encoded POSIX
134 const wchar_t hex[] = L"0123456789abcdef";
135 char ran[] = "123456789abcdef"; // init to avoid clang static analyzer message
136 // see ticket #8954
137 assert(sizeof(ran) == 16);
138 const int max_nibbles = 2 * sizeof(ran); // 4-bits per nibble
139
140 int nibbles_used = max_nibbles;
141 for(std::wstring::size_type i=0; i < s.size(); ++i)
142 {
143 if (s[i] == L'%') // digit request
144 {
145 if (nibbles_used == max_nibbles)
146 {
147 system_crypt_random(ran, sizeof(ran), ec);
148 if (ec != 0 && *ec)
149 return "";
150 nibbles_used = 0;
151 }
152 int c = ran[nibbles_used/2];
153 c >>= 4 * (nibbles_used++ & 1); // if odd, shift right 1 nibble
154 s[i] = hex[c & 0xf]; // convert to hex digit and replace
155 }
156 }
157
158 if (ec != 0) ec->clear();
159
160 return s;
161}
162
163}}}