]> git.proxmox.com Git - ceph.git/blame - 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
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
92f5a8d4 10//--------------------------------------------------------------------------------------//
7c673cae 11
92f5a8d4 12#ifndef BOOST_SYSTEM_NO_DEPRECATED
7c673cae
FG
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>
b32b8144
FG
27# ifdef _MSC_VER
28# pragma comment(lib, "Advapi32.lib")
29# endif
7c673cae
FG
30# endif
31
32namespace {
33
34void 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
47int 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
72void 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 {
92f5a8d4 110 BOOL gen_ok = ::CryptGenRandom(handle, static_cast<DWORD>(len), static_cast<unsigned char*>(buf));
7c673cae
FG
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
124namespace boost { namespace filesystem { namespace detail {
125
126BOOST_FILESYSTEM_DECL
127path unique_path(const path& model, system::error_code* ec)
128{
92f5a8d4
TL
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
7c673cae 138 const wchar_t hex[] = L"0123456789abcdef";
92f5a8d4
TL
139 const wchar_t percent = L'%';
140#else
141 const char hex[] = "0123456789abcdef";
142 const char percent = '%';
143#endif
144
7c673cae
FG
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;
92f5a8d4 151 for(path::string_type::size_type i=0; i < s.size(); ++i)
7c673cae 152 {
92f5a8d4 153 if (s[i] == percent) // digit request
7c673cae
FG
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}}}