Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/atf/atf-c++/detail/fs.cpp
39562 views
1
// Copyright (c) 2007 The NetBSD Foundation, Inc.
2
// All rights reserved.
3
//
4
// Redistribution and use in source and binary forms, with or without
5
// modification, are permitted provided that the following conditions
6
// are met:
7
// 1. Redistributions of source code must retain the above copyright
8
// notice, this list of conditions and the following disclaimer.
9
// 2. Redistributions in binary form must reproduce the above copyright
10
// notice, this list of conditions and the following disclaimer in the
11
// documentation and/or other materials provided with the distribution.
12
//
13
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
14
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
15
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
18
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
22
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
26
#include "atf-c++/detail/fs.hpp"
27
28
#if defined(HAVE_CONFIG_H)
29
#include "config.h"
30
#endif
31
32
extern "C" {
33
#include <sys/param.h>
34
#include <sys/types.h>
35
#include <sys/mount.h>
36
#include <sys/stat.h>
37
#include <sys/wait.h>
38
#include <dirent.h>
39
#include <libgen.h>
40
#include <unistd.h>
41
}
42
43
#include <cerrno>
44
#include <cstdlib>
45
#include <cstring>
46
47
extern "C" {
48
#include "atf-c/error.h"
49
}
50
51
#include "atf-c++/detail/env.hpp"
52
#include "atf-c++/detail/exceptions.hpp"
53
#include "atf-c++/detail/process.hpp"
54
#include "atf-c++/detail/sanity.hpp"
55
#include "atf-c++/detail/text.hpp"
56
#include "atf-c++/utils.hpp"
57
58
namespace impl = atf::fs;
59
#define IMPL_NAME "atf::fs"
60
61
// ------------------------------------------------------------------------
62
// Auxiliary functions.
63
// ------------------------------------------------------------------------
64
65
static bool safe_access(const impl::path&, int, int);
66
67
//!
68
//! \brief A controlled version of access(2).
69
//!
70
//! This function reimplements the standard access(2) system call to
71
//! safely control its exit status and raise an exception in case of
72
//! failure.
73
//!
74
static
75
bool
76
safe_access(const impl::path& p, int mode, int experr)
77
{
78
bool ok;
79
80
atf_error_t err = atf_fs_eaccess(p.c_path(), mode);
81
if (atf_is_error(err)) {
82
if (atf_error_is(err, "libc")) {
83
if (atf_libc_error_code(err) == experr) {
84
atf_error_free(err);
85
ok = false;
86
} else {
87
atf::throw_atf_error(err);
88
// XXX Silence warning; maybe throw_atf_error should be
89
// an exception and not a function.
90
ok = false;
91
}
92
} else {
93
atf::throw_atf_error(err);
94
// XXX Silence warning; maybe throw_atf_error should be
95
// an exception and not a function.
96
ok = false;
97
}
98
} else
99
ok = true;
100
101
return ok;
102
}
103
104
// ------------------------------------------------------------------------
105
// The "path" class.
106
// ------------------------------------------------------------------------
107
108
impl::path::path(const std::string& s)
109
{
110
atf_error_t err = atf_fs_path_init_fmt(&m_path, "%s", s.c_str());
111
if (atf_is_error(err))
112
throw_atf_error(err);
113
}
114
115
impl::path::path(const path& p)
116
{
117
atf_error_t err = atf_fs_path_copy(&m_path, &p.m_path);
118
if (atf_is_error(err))
119
throw_atf_error(err);
120
}
121
122
impl::path::path(const atf_fs_path_t *p)
123
{
124
atf_error_t err = atf_fs_path_copy(&m_path, p);
125
if (atf_is_error(err))
126
throw_atf_error(err);
127
}
128
129
impl::path::~path(void)
130
{
131
atf_fs_path_fini(&m_path);
132
}
133
134
const char*
135
impl::path::c_str(void)
136
const
137
{
138
return atf_fs_path_cstring(&m_path);
139
}
140
141
const atf_fs_path_t*
142
impl::path::c_path(void)
143
const
144
{
145
return &m_path;
146
}
147
148
std::string
149
impl::path::str(void)
150
const
151
{
152
return c_str();
153
}
154
155
bool
156
impl::path::is_absolute(void)
157
const
158
{
159
return atf_fs_path_is_absolute(&m_path);
160
}
161
162
bool
163
impl::path::is_root(void)
164
const
165
{
166
return atf_fs_path_is_root(&m_path);
167
}
168
169
impl::path
170
impl::path::branch_path(void)
171
const
172
{
173
atf_fs_path_t bp;
174
atf_error_t err;
175
176
err = atf_fs_path_branch_path(&m_path, &bp);
177
if (atf_is_error(err))
178
throw_atf_error(err);
179
180
path p(atf_fs_path_cstring(&bp));
181
atf_fs_path_fini(&bp);
182
return p;
183
}
184
185
std::string
186
impl::path::leaf_name(void)
187
const
188
{
189
atf_dynstr_t ln;
190
atf_error_t err;
191
192
err = atf_fs_path_leaf_name(&m_path, &ln);
193
if (atf_is_error(err))
194
throw_atf_error(err);
195
196
std::string s(atf_dynstr_cstring(&ln));
197
atf_dynstr_fini(&ln);
198
return s;
199
}
200
201
impl::path
202
impl::path::to_absolute(void)
203
const
204
{
205
atf_fs_path_t pa;
206
207
atf_error_t err = atf_fs_path_to_absolute(&m_path, &pa);
208
if (atf_is_error(err))
209
throw_atf_error(err);
210
211
path p(atf_fs_path_cstring(&pa));
212
atf_fs_path_fini(&pa);
213
return p;
214
}
215
216
impl::path&
217
impl::path::operator=(const path& p)
218
{
219
atf_fs_path_t tmp;
220
221
atf_error_t err = atf_fs_path_init_fmt(&tmp, "%s", p.c_str());
222
if (atf_is_error(err))
223
throw_atf_error(err);
224
else {
225
atf_fs_path_fini(&m_path);
226
m_path = tmp;
227
}
228
229
return *this;
230
}
231
232
bool
233
impl::path::operator==(const path& p)
234
const
235
{
236
return atf_equal_fs_path_fs_path(&m_path, &p.m_path);
237
}
238
239
bool
240
impl::path::operator!=(const path& p)
241
const
242
{
243
return !atf_equal_fs_path_fs_path(&m_path, &p.m_path);
244
}
245
246
impl::path
247
impl::path::operator/(const std::string& p)
248
const
249
{
250
path p2 = *this;
251
252
atf_error_t err = atf_fs_path_append_fmt(&p2.m_path, "%s", p.c_str());
253
if (atf_is_error(err))
254
throw_atf_error(err);
255
256
return p2;
257
}
258
259
impl::path
260
impl::path::operator/(const path& p)
261
const
262
{
263
path p2 = *this;
264
265
atf_error_t err = atf_fs_path_append_fmt(&p2.m_path, "%s",
266
atf_fs_path_cstring(&p.m_path));
267
if (atf_is_error(err))
268
throw_atf_error(err);
269
270
return p2;
271
}
272
273
bool
274
impl::path::operator<(const path& p)
275
const
276
{
277
const char *s1 = atf_fs_path_cstring(&m_path);
278
const char *s2 = atf_fs_path_cstring(&p.m_path);
279
return std::strcmp(s1, s2) < 0;
280
}
281
282
// ------------------------------------------------------------------------
283
// The "file_info" class.
284
// ------------------------------------------------------------------------
285
286
const int impl::file_info::blk_type = atf_fs_stat_blk_type;
287
const int impl::file_info::chr_type = atf_fs_stat_chr_type;
288
const int impl::file_info::dir_type = atf_fs_stat_dir_type;
289
const int impl::file_info::fifo_type = atf_fs_stat_fifo_type;
290
const int impl::file_info::lnk_type = atf_fs_stat_lnk_type;
291
const int impl::file_info::reg_type = atf_fs_stat_reg_type;
292
const int impl::file_info::sock_type = atf_fs_stat_sock_type;
293
const int impl::file_info::wht_type = atf_fs_stat_wht_type;
294
295
impl::file_info::file_info(const path& p)
296
{
297
atf_error_t err;
298
299
err = atf_fs_stat_init(&m_stat, p.c_path());
300
if (atf_is_error(err))
301
throw_atf_error(err);
302
}
303
304
impl::file_info::file_info(const file_info& fi)
305
{
306
atf_fs_stat_copy(&m_stat, &fi.m_stat);
307
}
308
309
impl::file_info::~file_info(void)
310
{
311
atf_fs_stat_fini(&m_stat);
312
}
313
314
dev_t
315
impl::file_info::get_device(void)
316
const
317
{
318
return atf_fs_stat_get_device(&m_stat);
319
}
320
321
ino_t
322
impl::file_info::get_inode(void)
323
const
324
{
325
return atf_fs_stat_get_inode(&m_stat);
326
}
327
328
mode_t
329
impl::file_info::get_mode(void)
330
const
331
{
332
return atf_fs_stat_get_mode(&m_stat);
333
}
334
335
off_t
336
impl::file_info::get_size(void)
337
const
338
{
339
return atf_fs_stat_get_size(&m_stat);
340
}
341
342
int
343
impl::file_info::get_type(void)
344
const
345
{
346
return atf_fs_stat_get_type(&m_stat);
347
}
348
349
bool
350
impl::file_info::is_owner_readable(void)
351
const
352
{
353
return atf_fs_stat_is_owner_readable(&m_stat);
354
}
355
356
bool
357
impl::file_info::is_owner_writable(void)
358
const
359
{
360
return atf_fs_stat_is_owner_writable(&m_stat);
361
}
362
363
bool
364
impl::file_info::is_owner_executable(void)
365
const
366
{
367
return atf_fs_stat_is_owner_executable(&m_stat);
368
}
369
370
bool
371
impl::file_info::is_group_readable(void)
372
const
373
{
374
return atf_fs_stat_is_group_readable(&m_stat);
375
}
376
377
bool
378
impl::file_info::is_group_writable(void)
379
const
380
{
381
return atf_fs_stat_is_group_writable(&m_stat);
382
}
383
384
bool
385
impl::file_info::is_group_executable(void)
386
const
387
{
388
return atf_fs_stat_is_group_executable(&m_stat);
389
}
390
391
bool
392
impl::file_info::is_other_readable(void)
393
const
394
{
395
return atf_fs_stat_is_other_readable(&m_stat);
396
}
397
398
bool
399
impl::file_info::is_other_writable(void)
400
const
401
{
402
return atf_fs_stat_is_other_writable(&m_stat);
403
}
404
405
bool
406
impl::file_info::is_other_executable(void)
407
const
408
{
409
return atf_fs_stat_is_other_executable(&m_stat);
410
}
411
412
// ------------------------------------------------------------------------
413
// The "directory" class.
414
// ------------------------------------------------------------------------
415
416
impl::directory::directory(const path& p)
417
{
418
DIR* dp = ::opendir(p.c_str());
419
if (dp == NULL)
420
throw system_error(IMPL_NAME "::directory::directory(" +
421
p.str() + ")", "opendir(3) failed", errno);
422
423
struct dirent* dep;
424
while ((dep = ::readdir(dp)) != NULL) {
425
path entryp = p / dep->d_name;
426
insert(value_type(dep->d_name, file_info(entryp)));
427
}
428
429
if (::closedir(dp) == -1)
430
throw system_error(IMPL_NAME "::directory::directory(" +
431
p.str() + ")", "closedir(3) failed", errno);
432
}
433
434
std::set< std::string >
435
impl::directory::names(void)
436
const
437
{
438
std::set< std::string > ns;
439
440
for (const_iterator iter = begin(); iter != end(); iter++)
441
ns.insert((*iter).first);
442
443
return ns;
444
}
445
446
// ------------------------------------------------------------------------
447
// Free functions.
448
// ------------------------------------------------------------------------
449
450
bool
451
impl::exists(const path& p)
452
{
453
atf_error_t err;
454
bool b;
455
456
err = atf_fs_exists(p.c_path(), &b);
457
if (atf_is_error(err))
458
throw_atf_error(err);
459
460
return b;
461
}
462
463
bool
464
impl::have_prog_in_path(const std::string& prog)
465
{
466
PRE(prog.find('/') == std::string::npos);
467
468
// Do not bother to provide a default value for PATH. If it is not
469
// there something is broken in the user's environment.
470
if (!atf::env::has("PATH"))
471
throw std::runtime_error("PATH not defined in the environment");
472
std::vector< std::string > dirs =
473
atf::text::split(atf::env::get("PATH"), ":");
474
475
bool found = false;
476
for (std::vector< std::string >::const_iterator iter = dirs.begin();
477
!found && iter != dirs.end(); iter++) {
478
const path& dir = path(*iter);
479
480
if (is_executable(dir / prog))
481
found = true;
482
}
483
return found;
484
}
485
486
bool
487
impl::is_executable(const path& p)
488
{
489
if (!exists(p))
490
return false;
491
return safe_access(p, atf_fs_access_x, EACCES);
492
}
493
494
void
495
impl::remove(const path& p)
496
{
497
if (file_info(p).get_type() == file_info::dir_type)
498
throw atf::system_error(IMPL_NAME "::remove(" + p.str() + ")",
499
"Is a directory",
500
EPERM);
501
if (::unlink(p.c_str()) == -1)
502
throw atf::system_error(IMPL_NAME "::remove(" + p.str() + ")",
503
"unlink(" + p.str() + ") failed",
504
errno);
505
}
506
507
void
508
impl::rmdir(const path& p)
509
{
510
atf_error_t err = atf_fs_rmdir(p.c_path());
511
if (atf_is_error(err))
512
throw_atf_error(err);
513
}
514
515