]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/filesystem/src/unique_path.cpp
import new upstream nautilus stable release 14.2.8
[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 #ifndef BOOST_SYSTEM_NO_DEPRECATED
13 # define BOOST_SYSTEM_NO_DEPRECATED
14 #endif
15
16 #include <boost/filesystem/operations.hpp>
17 #include <cassert>
18
19 # ifdef BOOST_POSIX_API
20 # include <fcntl.h>
21 # ifdef BOOST_HAS_UNISTD_H
22 # include <unistd.h>
23 # endif
24 # else // BOOST_WINDOWS_API
25 # include <windows.h>
26 # include <wincrypt.h>
27 # ifdef _MSC_VER
28 # pragma comment(lib, "Advapi32.lib")
29 # endif
30 # endif
31
32 namespace {
33
34 void fail(int err, boost::system::error_code* ec)
35 {
36 if (ec == 0)
37 BOOST_FILESYSTEM_THROW( boost::system::system_error(err,
38 boost::system::system_category(),
39 "boost::filesystem::unique_path"));
40
41 ec->assign(err, boost::system::system_category());
42 return;
43 }
44
45 #ifdef BOOST_WINDOWS_API
46
47 int acquire_crypt_handle(HCRYPTPROV& handle)
48 {
49 if (::CryptAcquireContextW(&handle, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
50 return 0;
51
52 int errval = ::GetLastError();
53 if (errval != NTE_BAD_KEYSET)
54 return errval;
55
56 if (::CryptAcquireContextW(&handle, 0, 0, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
57 return 0;
58
59 errval = ::GetLastError();
60 // Another thread could have attempted to create the keyset at the same time.
61 if (errval != NTE_EXISTS)
62 return errval;
63
64 if (::CryptAcquireContextW(&handle, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
65 return 0;
66
67 return ::GetLastError();
68 }
69
70 #endif
71
72 void system_crypt_random(void* buf, std::size_t len, boost::system::error_code* ec)
73 {
74 # ifdef BOOST_POSIX_API
75
76 int file = open("/dev/urandom", O_RDONLY);
77 if (file == -1)
78 {
79 file = open("/dev/random", O_RDONLY);
80 if (file == -1)
81 {
82 fail(errno, ec);
83 return;
84 }
85 }
86
87 size_t bytes_read = 0;
88 while (bytes_read < len)
89 {
90 ssize_t n = read(file, buf, len - bytes_read);
91 if (n == -1)
92 {
93 close(file);
94 fail(errno, ec);
95 return;
96 }
97 bytes_read += n;
98 buf = static_cast<char*>(buf) + n;
99 }
100
101 close(file);
102
103 # else // BOOST_WINDOWS_API
104
105 HCRYPTPROV handle;
106 int errval = acquire_crypt_handle(handle);
107
108 if (!errval)
109 {
110 BOOL gen_ok = ::CryptGenRandom(handle, static_cast<DWORD>(len), static_cast<unsigned char*>(buf));
111 if (!gen_ok)
112 errval = ::GetLastError();
113 ::CryptReleaseContext(handle, 0);
114 }
115
116 if (!errval) return;
117
118 fail(errval, ec);
119 # endif
120 }
121
122 } // unnamed namespace
123
124 namespace boost { namespace filesystem { namespace detail {
125
126 BOOST_FILESYSTEM_DECL
127 path unique_path(const path& model, system::error_code* ec)
128 {
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.
134
135 path::string_type s( model.native() );
136
137 #ifdef BOOST_WINDOWS_API
138 const wchar_t hex[] = L"0123456789abcdef";
139 const wchar_t percent = L'%';
140 #else
141 const char hex[] = "0123456789abcdef";
142 const char percent = '%';
143 #endif
144
145 char ran[] = "123456789abcdef"; // init to avoid clang static analyzer message
146 // see ticket #8954
147 assert(sizeof(ran) == 16);
148 const int max_nibbles = 2 * sizeof(ran); // 4-bits per nibble
149
150 int nibbles_used = max_nibbles;
151 for(path::string_type::size_type i=0; i < s.size(); ++i)
152 {
153 if (s[i] == percent) // digit request
154 {
155 if (nibbles_used == max_nibbles)
156 {
157 system_crypt_random(ran, sizeof(ran), ec);
158 if (ec != 0 && *ec)
159 return "";
160 nibbles_used = 0;
161 }
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
165 }
166 }
167
168 if (ec != 0) ec->clear();
169
170 return s;
171 }
172
173 }}}