4
4
#include " filesystem_include.h"
5
5
6
6
#include < sys/stat.h> // for stat, mkdir, mkfifo
7
+ #ifndef _WIN32
7
8
#include < unistd.h> // for ftruncate, link, symlink, getcwd, chdir
9
+ #else
10
+ #include < io.h>
11
+ #include < direct.h>
12
+ #include < windows.h> // for CreateSymbolicLink, CreateHardLink
13
+ #endif
8
14
9
15
#include < cassert>
10
16
#include < cstdio> // for printf
24
30
#endif
25
31
26
32
namespace utils {
33
+ #ifdef _WIN32
34
+ inline int mkdir (const char * path, int mode) { (void )mode; return ::_mkdir (path); }
35
+ inline int ftruncate (int fd, off_t length) { return ::_chsize (fd, length); }
36
+ inline int symlink (const char * oldname, const char * newname, bool is_dir) {
37
+ DWORD flags = is_dir ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0 ;
38
+ if (CreateSymbolicLinkA (newname, oldname,
39
+ flags | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE))
40
+ return 0 ;
41
+ if (GetLastError () != ERROR_INVALID_PARAMETER)
42
+ return 1 ;
43
+ return !CreateSymbolicLinkA (newname, oldname, flags);
44
+ }
45
+ inline int link (const char *oldname, const char * newname) {
46
+ return !CreateHardLinkA (newname, oldname, NULL );
47
+ }
48
+ #else
49
+ using ::mkdir;
50
+ using ::ftruncate;
51
+ inline int symlink (const char * oldname, const char * newname, bool is_dir) { (void )is_dir; return ::symlink (oldname, newname); }
52
+ using ::link;
53
+ #endif
54
+
27
55
inline std::string getcwd () {
28
56
// Assume that path lengths are not greater than this.
29
57
// This should be fine for testing purposes.
@@ -42,7 +70,13 @@ namespace utils {
42
70
struct scoped_test_env
43
71
{
44
72
scoped_test_env () : test_root(available_cwd_path()) {
45
- std::string cmd = " mkdir -p " + test_root.native ();
73
+ #ifdef _WIN32
74
+ // Windows mkdir can create multiple recursive directories
75
+ // if needed.
76
+ std::string cmd = " mkdir " + test_root.string ();
77
+ #else
78
+ std::string cmd = " mkdir -p " + test_root.string ();
79
+ #endif
46
80
int ret = std::system (cmd.c_str ());
47
81
assert (ret == 0 );
48
82
@@ -54,11 +88,16 @@ struct scoped_test_env
54
88
}
55
89
56
90
~scoped_test_env () {
57
- std::string cmd = " chmod -R 777 " + test_root.native ();
91
+ #ifdef _WIN32
92
+ std::string cmd = " rmdir /s /q " + test_root.string ();
93
+ int ret;
94
+ #else
95
+ std::string cmd = " chmod -R 777 " + test_root.string ();
58
96
int ret = std::system (cmd.c_str ());
59
97
assert (ret == 0 );
60
98
61
- cmd = " rm -r " + test_root.native ();
99
+ cmd = " rm -r " + test_root.string ();
100
+ #endif
62
101
ret = std::system (cmd.c_str ());
63
102
assert (ret == 0 );
64
103
}
@@ -70,12 +109,12 @@ struct scoped_test_env
70
109
71
110
std::string sanitize_path (std::string raw) {
72
111
assert (raw.find (" .." ) == std::string::npos);
73
- std::string const & root = test_root.native ();
112
+ std::string root = test_root.string ();
74
113
if (root.compare (0 , root.size (), raw, 0 , root.size ()) != 0 ) {
75
114
assert (raw.front () != ' \\ ' );
76
115
fs::path tmp (test_root);
77
116
tmp /= raw;
78
- return std::move ( const_cast <std::string&>( tmp.native ()) );
117
+ return tmp.string ( );
79
118
}
80
119
return raw;
81
120
}
@@ -85,10 +124,11 @@ struct scoped_test_env
85
124
// but the caller is not (std::filesystem also uses uintmax_t rather than
86
125
// off_t). On a 32-bit system this allows us to create a file larger than
87
126
// 2GB.
88
- std::string create_file (std::string filename, uintmax_t size = 0 ) {
89
- #if defined(__LP64__)
127
+ std::string create_file (fs::path filename_path, uintmax_t size = 0 ) {
128
+ std::string filename = filename_path.string ();
129
+ #if defined(__LP64__) || defined(_WIN32)
90
130
auto large_file_fopen = fopen;
91
- auto large_file_ftruncate = ftruncate;
131
+ auto large_file_ftruncate = utils:: ftruncate;
92
132
using large_file_offset_t = off_t ;
93
133
#else
94
134
auto large_file_fopen = fopen64;
@@ -104,7 +144,12 @@ struct scoped_test_env
104
144
abort ();
105
145
}
106
146
107
- FILE* file = large_file_fopen (filename.c_str (), " we" );
147
+ #ifndef _WIN32
148
+ #define FOPEN_CLOEXEC_FLAG " e"
149
+ #else
150
+ #define FOPEN_CLOEXEC_FLAG " "
151
+ #endif
152
+ FILE* file = large_file_fopen (filename.c_str (), " w" FOPEN_CLOEXEC_FLAG);
108
153
if (file == nullptr ) {
109
154
fprintf (stderr, " fopen %s failed: %s\n " , filename.c_str (),
110
155
strerror (errno));
@@ -123,38 +168,46 @@ struct scoped_test_env
123
168
return filename;
124
169
}
125
170
126
- std::string create_dir (std::string filename) {
171
+ std::string create_dir (fs::path filename_path) {
172
+ std::string filename = filename_path.string ();
127
173
filename = sanitize_path (std::move (filename));
128
- int ret = ::mkdir (filename.c_str (), 0777 ); // rwxrwxrwx mode
174
+ int ret = utils ::mkdir (filename.c_str (), 0777 ); // rwxrwxrwx mode
129
175
assert (ret == 0 );
130
176
return filename;
131
177
}
132
178
133
- std::string create_symlink (std::string source,
134
- std::string to,
135
- bool sanitize_source = true ) {
179
+ std::string create_symlink (fs::path source_path,
180
+ fs::path to_path,
181
+ bool sanitize_source = true ,
182
+ bool is_dir = false ) {
183
+ std::string source = source_path.string ();
184
+ std::string to = to_path.string ();
136
185
if (sanitize_source)
137
186
source = sanitize_path (std::move (source));
138
187
to = sanitize_path (std::move (to));
139
- int ret = ::symlink (source.c_str (), to.c_str ());
188
+ int ret = utils ::symlink (source.c_str (), to.c_str (), is_dir );
140
189
assert (ret == 0 );
141
190
return to;
142
191
}
143
192
144
- std::string create_hardlink (std::string source, std::string to) {
193
+ std::string create_hardlink (fs::path source_path, fs::path to_path) {
194
+ std::string source = source_path.string ();
195
+ std::string to = to_path.string ();
145
196
source = sanitize_path (std::move (source));
146
197
to = sanitize_path (std::move (to));
147
- int ret = ::link (source.c_str (), to.c_str ());
198
+ int ret = utils ::link (source.c_str (), to.c_str ());
148
199
assert (ret == 0 );
149
200
return to;
150
201
}
151
202
203
+ #ifndef _WIN32
152
204
std::string create_fifo (std::string file) {
153
205
file = sanitize_path (std::move (file));
154
206
int ret = ::mkfifo (file.c_str (), 0666 ); // rw-rw-rw- mode
155
207
assert (ret == 0 );
156
208
return file;
157
209
}
210
+ #endif
158
211
159
212
// Some platforms doesn't support socket files so we shouldn't even
160
213
// allow tests to call this unguarded.
@@ -186,7 +239,7 @@ struct scoped_test_env
186
239
fs::path const base = tmp / cwd.filename ();
187
240
int i = 0 ;
188
241
fs::path p = base / (" static_env." + std::to_string (i));
189
- while (utils::exists (p)) {
242
+ while (utils::exists (p. string () )) {
190
243
p = fs::path (base) / (" static_env." + std::to_string (++i));
191
244
}
192
245
return p;
@@ -222,7 +275,7 @@ class static_test_env {
222
275
env_.create_dir (" dir1/dir2/dir3" );
223
276
env_.create_file (" dir1/dir2/dir3/file5" );
224
277
env_.create_file (" dir1/dir2/file4" );
225
- env_.create_symlink (" dir3" , " dir1/dir2/symlink_to_dir3" , false );
278
+ env_.create_symlink (" dir3" , " dir1/dir2/symlink_to_dir3" , false , true );
226
279
env_.create_file (" dir1/file1" );
227
280
env_.create_file (" dir1/file2" , 42 );
228
281
env_.create_file (" empty_file" );
@@ -398,7 +451,7 @@ std::size_t StrLen(CharT const* P) {
398
451
// This hack forces path to allocate enough memory.
399
452
inline void PathReserve (fs::path& p, std::size_t N) {
400
453
auto const & native_ref = p.native ();
401
- const_cast <std::string &>(native_ref).reserve (N);
454
+ const_cast <fs::path::string_type &>(native_ref).reserve (N);
402
455
}
403
456
404
457
template <class Iter1 , class Iter2 >
@@ -526,8 +579,8 @@ struct ExceptionChecker {
526
579
}
527
580
auto transform_path = [](const fs::path& p) {
528
581
if (p.native ().empty ())
529
- return " \"\" " ;
530
- return p.c_str ();
582
+ return std::string ( " \"\" " ) ;
583
+ return p.string ();
531
584
};
532
585
std::string format = [&]() -> std::string {
533
586
switch (num_paths) {
@@ -537,12 +590,12 @@ struct ExceptionChecker {
537
590
case 1 :
538
591
return format_string (" filesystem error: in %s: %s%s [%s]" , func_name,
539
592
additional_msg, message,
540
- transform_path (expected_path1));
593
+ transform_path (expected_path1). c_str () );
541
594
case 2 :
542
595
return format_string (" filesystem error: in %s: %s%s [%s] [%s]" ,
543
596
func_name, additional_msg, message,
544
- transform_path (expected_path1),
545
- transform_path (expected_path2));
597
+ transform_path (expected_path1). c_str () ,
598
+ transform_path (expected_path2). c_str () );
546
599
default :
547
600
TEST_CHECK (false && " unexpected case" );
548
601
return " " ;
0 commit comments