]> git.proxmox.com Git - ceph.git/blob - 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
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>
31 # ifdef _MSC_VER
32 # pragma comment(lib, "Advapi32.lib")
33 # endif
34 # endif
35
36 namespace {
37
38 void 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
51 int 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
76 void 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
128 namespace boost { namespace filesystem { namespace detail {
129
130 BOOST_FILESYSTEM_DECL
131 path 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 }}}