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