Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F10615065
fs.cpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
7 KB
Subscribers
None
fs.cpp
View Options
// Copyright (c) 2017 The Bitcoin Core developers
// Copyright (c) 2019 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include
<fs.h>
#ifndef WIN32
#include
<cstring>
#include
<fcntl.h>
#include
<sys/file.h>
#include
<sys/utsname.h>
#include
<unistd.h>
#else
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include
<codecvt>
#include
<windows.h>
#endif
namespace
fsbridge
{
FILE
*
fopen
(
const
fs
::
path
&
p
,
const
char
*
mode
)
{
#ifndef WIN32
return
::
fopen
(
p
.
c_str
(),
mode
);
#else
std
::
wstring_convert
<
std
::
codecvt_utf8_utf16
<
wchar_t
>
,
wchar_t
>
utf8_cvt
;
return
::
_wfopen
(
p
.
wstring
().
c_str
(),
utf8_cvt
.
from_bytes
(
mode
).
c_str
());
#endif
}
#ifndef WIN32
static
std
::
string
GetErrorReason
()
{
return
std
::
strerror
(
errno
);
}
FileLock
::
FileLock
(
const
fs
::
path
&
file
)
{
fd
=
open
(
file
.
c_str
(),
O_RDWR
);
if
(
fd
==
-1
)
{
reason
=
GetErrorReason
();
}
}
FileLock
::~
FileLock
()
{
if
(
fd
!=
-1
)
{
close
(
fd
);
}
}
static
bool
IsWSL
()
{
struct
utsname
uname_data
;
return
uname
(
&
uname_data
)
==
0
&&
std
::
string
(
uname_data
.
version
).
find
(
"Microsoft"
)
!=
std
::
string
::
npos
;
}
bool
FileLock
::
TryLock
()
{
if
(
fd
==
-1
)
{
return
false
;
}
// Exclusive file locking is broken on WSL using fcntl (issue #18622)
// This workaround can be removed once the bug on WSL is fixed
static
const
bool
is_wsl
=
IsWSL
();
if
(
is_wsl
)
{
if
(
flock
(
fd
,
LOCK_EX
|
LOCK_NB
)
==
-1
)
{
reason
=
GetErrorReason
();
return
false
;
}
}
else
{
struct
flock
lock
;
lock
.
l_type
=
F_WRLCK
;
lock
.
l_whence
=
SEEK_SET
;
lock
.
l_start
=
0
;
lock
.
l_len
=
0
;
if
(
fcntl
(
fd
,
F_SETLK
,
&
lock
)
==
-1
)
{
reason
=
GetErrorReason
();
return
false
;
}
}
return
true
;
}
#else
static
std
::
string
GetErrorReason
()
{
wchar_t
*
err
;
FormatMessageW
(
FORMAT_MESSAGE_ALLOCATE_BUFFER
|
FORMAT_MESSAGE_FROM_SYSTEM
|
FORMAT_MESSAGE_IGNORE_INSERTS
,
nullptr
,
GetLastError
(),
MAKELANGID
(
LANG_NEUTRAL
,
SUBLANG_DEFAULT
),
reinterpret_cast
<
WCHAR
*>
(
&
err
),
0
,
nullptr
);
std
::
wstring
err_str
(
err
);
LocalFree
(
err
);
return
std
::
wstring_convert
<
std
::
codecvt_utf8_utf16
<
wchar_t
>>
().
to_bytes
(
err_str
);
}
FileLock
::
FileLock
(
const
fs
::
path
&
file
)
{
hFile
=
CreateFileW
(
file
.
wstring
().
c_str
(),
GENERIC_READ
|
GENERIC_WRITE
,
FILE_SHARE_READ
|
FILE_SHARE_WRITE
|
FILE_SHARE_DELETE
,
nullptr
,
OPEN_EXISTING
,
FILE_ATTRIBUTE_NORMAL
,
nullptr
);
if
(
hFile
==
INVALID_HANDLE_VALUE
)
{
reason
=
GetErrorReason
();
}
}
FileLock
::~
FileLock
()
{
if
(
hFile
!=
INVALID_HANDLE_VALUE
)
{
CloseHandle
(
hFile
);
}
}
bool
FileLock
::
TryLock
()
{
if
(
hFile
==
INVALID_HANDLE_VALUE
)
{
return
false
;
}
_OVERLAPPED
overlapped
=
{
0
};
if
(
!
LockFileEx
(
hFile
,
LOCKFILE_EXCLUSIVE_LOCK
|
LOCKFILE_FAIL_IMMEDIATELY
,
0
,
std
::
numeric_limits
<
DWORD
>::
max
(),
std
::
numeric_limits
<
DWORD
>::
max
(),
&
overlapped
))
{
reason
=
GetErrorReason
();
return
false
;
}
return
true
;
}
#endif
std
::
string
get_filesystem_error_message
(
const
fs
::
filesystem_error
&
e
)
{
#ifndef WIN32
return
e
.
what
();
#else
// Convert from Multi Byte to utf-16
std
::
string
mb_string
(
e
.
what
());
int
size
=
MultiByteToWideChar
(
CP_ACP
,
0
,
mb_string
.
data
(),
mb_string
.
size
(),
nullptr
,
0
);
std
::
wstring
utf16_string
(
size
,
L
'\0'
);
MultiByteToWideChar
(
CP_ACP
,
0
,
mb_string
.
data
(),
mb_string
.
size
(),
&*
utf16_string
.
begin
(),
size
);
// Convert from utf-16 to utf-8
return
std
::
wstring_convert
<
std
::
codecvt_utf8_utf16
<
wchar_t
>
,
wchar_t
>
()
.
to_bytes
(
utf16_string
);
#endif
}
#ifdef WIN32
#ifdef __GLIBCXX__
// reference:
// https://github.com/gcc-mirror/gcc/blob/gcc-7_3_0-release/libstdc%2B%2B-v3/include/std/fstream#L270
static
std
::
string
openmodeToStr
(
std
::
ios_base
::
openmode
mode
)
{
switch
(
mode
&
~
std
::
ios_base
::
ate
)
{
case
std
::
ios_base
::
out
:
case
std
::
ios_base
::
out
|
std
::
ios_base
::
trunc
:
return
"w"
;
case
std
::
ios_base
::
out
|
std
::
ios_base
::
app
:
case
std
::
ios_base
::
app
:
return
"a"
;
case
std
::
ios_base
::
in
:
return
"r"
;
case
std
::
ios_base
::
in
|
std
::
ios_base
::
out
:
return
"r+"
;
case
std
::
ios_base
::
in
|
std
::
ios_base
::
out
|
std
::
ios_base
::
trunc
:
return
"w+"
;
case
std
::
ios_base
::
in
|
std
::
ios_base
::
out
|
std
::
ios_base
::
app
:
case
std
::
ios_base
::
in
|
std
::
ios_base
::
app
:
return
"a+"
;
case
std
::
ios_base
::
out
|
std
::
ios_base
::
binary
:
case
std
::
ios_base
::
out
|
std
::
ios_base
::
trunc
|
std
::
ios_base
::
binary
:
return
"wb"
;
case
std
::
ios_base
::
out
|
std
::
ios_base
::
app
|
std
::
ios_base
::
binary
:
case
std
::
ios_base
::
app
|
std
::
ios_base
::
binary
:
return
"ab"
;
case
std
::
ios_base
::
in
|
std
::
ios_base
::
binary
:
return
"rb"
;
case
std
::
ios_base
::
in
|
std
::
ios_base
::
out
|
std
::
ios_base
::
binary
:
return
"r+b"
;
case
std
::
ios_base
::
in
|
std
::
ios_base
::
out
|
std
::
ios_base
::
trunc
|
std
::
ios_base
::
binary
:
return
"w+b"
;
case
std
::
ios_base
::
in
|
std
::
ios_base
::
out
|
std
::
ios_base
::
app
|
std
::
ios_base
::
binary
:
case
std
::
ios_base
::
in
|
std
::
ios_base
::
app
|
std
::
ios_base
::
binary
:
return
"a+b"
;
default
:
return
std
::
string
();
}
}
void
ifstream
::
open
(
const
fs
::
path
&
p
,
std
::
ios_base
::
openmode
mode
)
{
close
();
mode
|=
std
::
ios_base
::
in
;
m_file
=
fsbridge
::
fopen
(
p
,
openmodeToStr
(
mode
).
c_str
());
if
(
m_file
==
nullptr
)
{
return
;
}
m_filebuf
=
__gnu_cxx
::
stdio_filebuf
<
char
>
(
m_file
,
mode
);
rdbuf
(
&
m_filebuf
);
if
(
mode
&
std
::
ios_base
::
ate
)
{
seekg
(
0
,
std
::
ios_base
::
end
);
}
}
void
ifstream
::
close
()
{
if
(
m_file
!=
nullptr
)
{
m_filebuf
.
close
();
fclose
(
m_file
);
}
m_file
=
nullptr
;
}
void
ofstream
::
open
(
const
fs
::
path
&
p
,
std
::
ios_base
::
openmode
mode
)
{
close
();
mode
|=
std
::
ios_base
::
out
;
m_file
=
fsbridge
::
fopen
(
p
,
openmodeToStr
(
mode
).
c_str
());
if
(
m_file
==
nullptr
)
{
return
;
}
m_filebuf
=
__gnu_cxx
::
stdio_filebuf
<
char
>
(
m_file
,
mode
);
rdbuf
(
&
m_filebuf
);
if
(
mode
&
std
::
ios_base
::
ate
)
{
seekp
(
0
,
std
::
ios_base
::
end
);
}
}
void
ofstream
::
close
()
{
if
(
m_file
!=
nullptr
)
{
m_filebuf
.
close
();
fclose
(
m_file
);
}
m_file
=
nullptr
;
}
#else
// __GLIBCXX__
#if BOOST_VERSION >= 107700
static_assert
(
sizeof
(
*
BOOST_FILESYSTEM_C_STR
(
boost
::
filesystem
::
path
()))
==
sizeof
(
wchar_t
),
#else
static_assert
(
sizeof
(
*
boost
::
filesystem
::
path
().
BOOST_FILESYSTEM_C_STR
)
==
sizeof
(
wchar_t
),
#endif
// BOOST_VERSION >= 107700
"Warning: This build is using boost::filesystem ofstream and ifstream "
"implementations which will fail to open paths containing multibyte "
"characters. You should delete this static_assert to ignore this warning, "
"or switch to a different C++ standard library like the Microsoft C++ "
"Standard Library (where boost uses non-standard extensions to construct "
"stream objects with wide filenames), or the GNU libstdc++ library (where "
"a more complicated workaround has been implemented above)."
);
#endif
// __GLIBCXX__
#endif
// WIN32
}
// namespace fsbridge
File Metadata
Details
Attached
Mime Type
text/x-c++
Expires
Sat, Nov 23, 09:55 (1 d, 10 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4522755
Default Alt Text
fs.cpp (7 KB)
Attached To
rSTAGING Bitcoin ABC staging
Event Timeline
Log In to Comment