1 // Copyright (c) 2007 The NetBSD Foundation, Inc.
2 // All rights reserved.
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
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.
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.
26 #include "atf-c++/detail/fs.hpp"
28 #if defined(HAVE_CONFIG_H)
33 #include <sys/param.h>
34 #include <sys/types.h>
35 #include <sys/mount.h>
48 #include "atf-c/error.h"
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"
58 namespace impl = atf::fs;
59 #define IMPL_NAME "atf::fs"
61 // ------------------------------------------------------------------------
62 // Auxiliary functions.
63 // ------------------------------------------------------------------------
65 static bool safe_access(const impl::path&, int, int);
68 //! \brief A controlled version of access(2).
70 //! This function reimplements the standard access(2) system call to
71 //! safely control its exit status and raise an exception in case of
76 safe_access(const impl::path& p, int mode, int experr)
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) {
87 atf::throw_atf_error(err);
88 // XXX Silence warning; maybe throw_atf_error should be
89 // an exception and not a function.
93 atf::throw_atf_error(err);
94 // XXX Silence warning; maybe throw_atf_error should be
95 // an exception and not a function.
104 // ------------------------------------------------------------------------
106 // ------------------------------------------------------------------------
108 impl::path::path(const std::string& s)
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);
115 impl::path::path(const path& p)
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);
122 impl::path::path(const atf_fs_path_t *p)
124 atf_error_t err = atf_fs_path_copy(&m_path, p);
125 if (atf_is_error(err))
126 throw_atf_error(err);
129 impl::path::~path(void)
131 atf_fs_path_fini(&m_path);
135 impl::path::c_str(void)
138 return atf_fs_path_cstring(&m_path);
142 impl::path::c_path(void)
149 impl::path::str(void)
156 impl::path::is_absolute(void)
159 return atf_fs_path_is_absolute(&m_path);
163 impl::path::is_root(void)
166 return atf_fs_path_is_root(&m_path);
170 impl::path::branch_path(void)
176 err = atf_fs_path_branch_path(&m_path, &bp);
177 if (atf_is_error(err))
178 throw_atf_error(err);
180 path p(atf_fs_path_cstring(&bp));
181 atf_fs_path_fini(&bp);
186 impl::path::leaf_name(void)
192 err = atf_fs_path_leaf_name(&m_path, &ln);
193 if (atf_is_error(err))
194 throw_atf_error(err);
196 std::string s(atf_dynstr_cstring(&ln));
197 atf_dynstr_fini(&ln);
202 impl::path::to_absolute(void)
207 atf_error_t err = atf_fs_path_to_absolute(&m_path, &pa);
208 if (atf_is_error(err))
209 throw_atf_error(err);
211 path p(atf_fs_path_cstring(&pa));
212 atf_fs_path_fini(&pa);
217 impl::path::operator=(const path& p)
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);
225 atf_fs_path_fini(&m_path);
233 impl::path::operator==(const path& p)
236 return atf_equal_fs_path_fs_path(&m_path, &p.m_path);
240 impl::path::operator!=(const path& p)
243 return !atf_equal_fs_path_fs_path(&m_path, &p.m_path);
247 impl::path::operator/(const std::string& p)
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);
260 impl::path::operator/(const path& p)
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);
274 impl::path::operator<(const path& p)
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;
282 // ------------------------------------------------------------------------
283 // The "file_info" class.
284 // ------------------------------------------------------------------------
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;
295 impl::file_info::file_info(const path& p)
299 err = atf_fs_stat_init(&m_stat, p.c_path());
300 if (atf_is_error(err))
301 throw_atf_error(err);
304 impl::file_info::file_info(const file_info& fi)
306 atf_fs_stat_copy(&m_stat, &fi.m_stat);
309 impl::file_info::~file_info(void)
311 atf_fs_stat_fini(&m_stat);
315 impl::file_info::get_device(void)
318 return atf_fs_stat_get_device(&m_stat);
322 impl::file_info::get_inode(void)
325 return atf_fs_stat_get_inode(&m_stat);
329 impl::file_info::get_mode(void)
332 return atf_fs_stat_get_mode(&m_stat);
336 impl::file_info::get_size(void)
339 return atf_fs_stat_get_size(&m_stat);
343 impl::file_info::get_type(void)
346 return atf_fs_stat_get_type(&m_stat);
350 impl::file_info::is_owner_readable(void)
353 return atf_fs_stat_is_owner_readable(&m_stat);
357 impl::file_info::is_owner_writable(void)
360 return atf_fs_stat_is_owner_writable(&m_stat);
364 impl::file_info::is_owner_executable(void)
367 return atf_fs_stat_is_owner_executable(&m_stat);
371 impl::file_info::is_group_readable(void)
374 return atf_fs_stat_is_group_readable(&m_stat);
378 impl::file_info::is_group_writable(void)
381 return atf_fs_stat_is_group_writable(&m_stat);
385 impl::file_info::is_group_executable(void)
388 return atf_fs_stat_is_group_executable(&m_stat);
392 impl::file_info::is_other_readable(void)
395 return atf_fs_stat_is_other_readable(&m_stat);
399 impl::file_info::is_other_writable(void)
402 return atf_fs_stat_is_other_writable(&m_stat);
406 impl::file_info::is_other_executable(void)
409 return atf_fs_stat_is_other_executable(&m_stat);
412 // ------------------------------------------------------------------------
413 // The "directory" class.
414 // ------------------------------------------------------------------------
416 impl::directory::directory(const path& p)
418 DIR* dp = ::opendir(p.c_str());
420 throw system_error(IMPL_NAME "::directory::directory(" +
421 p.str() + ")", "opendir(3) failed", errno);
424 while ((dep = ::readdir(dp)) != NULL) {
425 path entryp = p / dep->d_name;
426 insert(value_type(dep->d_name, file_info(entryp)));
429 if (::closedir(dp) == -1)
430 throw system_error(IMPL_NAME "::directory::directory(" +
431 p.str() + ")", "closedir(3) failed", errno);
434 std::set< std::string >
435 impl::directory::names(void)
438 std::set< std::string > ns;
440 for (const_iterator iter = begin(); iter != end(); iter++)
441 ns.insert((*iter).first);
446 // ------------------------------------------------------------------------
448 // ------------------------------------------------------------------------
451 impl::exists(const path& p)
456 err = atf_fs_exists(p.c_path(), &b);
457 if (atf_is_error(err))
458 throw_atf_error(err);
464 impl::have_prog_in_path(const std::string& prog)
466 PRE(prog.find('/') == std::string::npos);
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"), ":");
476 for (std::vector< std::string >::const_iterator iter = dirs.begin();
477 !found && iter != dirs.end(); iter++) {
478 const path& dir = path(*iter);
480 if (is_executable(dir / prog))
487 impl::is_executable(const path& p)
491 return safe_access(p, atf_fs_access_x, EACCES);
495 impl::remove(const path& p)
497 if (file_info(p).get_type() == file_info::dir_type)
498 throw atf::system_error(IMPL_NAME "::remove(" + p.str() + ")",
501 if (::unlink(p.c_str()) == -1)
502 throw atf::system_error(IMPL_NAME "::remove(" + p.str() + ")",
503 "unlink(" + p.str() + ") failed",
508 impl::rmdir(const path& p)
510 atf_error_t err = atf_fs_rmdir(p.c_path());
511 if (atf_is_error(err))
512 throw_atf_error(err);