xref: /freebsd/contrib/atf/atf-c/detail/fs.c (revision 8f0ea33f2bbf3a6aa80235f0a02fa5f2780c2b17)
1*0677dfd1SJulio Merino /* Copyright (c) 2007 The NetBSD Foundation, Inc.
2c243e490SMarcel Moolenaar  * All rights reserved.
3c243e490SMarcel Moolenaar  *
4c243e490SMarcel Moolenaar  * Redistribution and use in source and binary forms, with or without
5c243e490SMarcel Moolenaar  * modification, are permitted provided that the following conditions
6c243e490SMarcel Moolenaar  * are met:
7c243e490SMarcel Moolenaar  * 1. Redistributions of source code must retain the above copyright
8c243e490SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer.
9c243e490SMarcel Moolenaar  * 2. Redistributions in binary form must reproduce the above copyright
10c243e490SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer in the
11c243e490SMarcel Moolenaar  *    documentation and/or other materials provided with the distribution.
12c243e490SMarcel Moolenaar  *
13c243e490SMarcel Moolenaar  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
14c243e490SMarcel Moolenaar  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
15c243e490SMarcel Moolenaar  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16c243e490SMarcel Moolenaar  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17c243e490SMarcel Moolenaar  * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
18c243e490SMarcel Moolenaar  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19c243e490SMarcel Moolenaar  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20c243e490SMarcel Moolenaar  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21c243e490SMarcel Moolenaar  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
22c243e490SMarcel Moolenaar  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23c243e490SMarcel Moolenaar  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24*0677dfd1SJulio Merino  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  */
25*0677dfd1SJulio Merino 
26*0677dfd1SJulio Merino #include "atf-c/detail/fs.h"
27c243e490SMarcel Moolenaar 
28c243e490SMarcel Moolenaar #if defined(HAVE_CONFIG_H)
29*0677dfd1SJulio Merino #include "config.h"
30c243e490SMarcel Moolenaar #endif
31c243e490SMarcel Moolenaar 
32c243e490SMarcel Moolenaar #include <sys/types.h>
33c243e490SMarcel Moolenaar #include <sys/param.h>
34c243e490SMarcel Moolenaar #include <sys/mount.h>
35c243e490SMarcel Moolenaar #include <sys/stat.h>
36c243e490SMarcel Moolenaar #include <sys/wait.h>
37c243e490SMarcel Moolenaar 
38c243e490SMarcel Moolenaar #include <dirent.h>
39c243e490SMarcel Moolenaar #include <errno.h>
40c243e490SMarcel Moolenaar #include <libgen.h>
41c243e490SMarcel Moolenaar #include <stdarg.h>
42c243e490SMarcel Moolenaar #include <stdio.h>
43c243e490SMarcel Moolenaar #include <stdlib.h>
44c243e490SMarcel Moolenaar #include <string.h>
45c243e490SMarcel Moolenaar #include <unistd.h>
46c243e490SMarcel Moolenaar 
47c243e490SMarcel Moolenaar #include "atf-c/defs.h"
48*0677dfd1SJulio Merino #include "atf-c/detail/sanity.h"
49*0677dfd1SJulio Merino #include "atf-c/detail/text.h"
50*0677dfd1SJulio Merino #include "atf-c/detail/user.h"
51c243e490SMarcel Moolenaar #include "atf-c/error.h"
52c243e490SMarcel Moolenaar 
53c243e490SMarcel Moolenaar /* ---------------------------------------------------------------------
54c243e490SMarcel Moolenaar  * Prototypes for auxiliary functions.
55c243e490SMarcel Moolenaar  * --------------------------------------------------------------------- */
56c243e490SMarcel Moolenaar 
57c243e490SMarcel Moolenaar static bool check_umask(const mode_t, const mode_t);
58c243e490SMarcel Moolenaar static atf_error_t copy_contents(const atf_fs_path_t *, char **);
59c243e490SMarcel Moolenaar static mode_t current_umask(void);
60c243e490SMarcel Moolenaar static atf_error_t do_mkdtemp(char *);
61c243e490SMarcel Moolenaar static atf_error_t normalize(atf_dynstr_t *, char *);
62c243e490SMarcel Moolenaar static atf_error_t normalize_ap(atf_dynstr_t *, const char *, va_list);
63c243e490SMarcel Moolenaar static void replace_contents(atf_fs_path_t *, const char *);
64c243e490SMarcel Moolenaar static const char *stat_type_to_string(const int);
65c243e490SMarcel Moolenaar 
66c243e490SMarcel Moolenaar /* ---------------------------------------------------------------------
67c243e490SMarcel Moolenaar  * The "invalid_umask" error type.
68c243e490SMarcel Moolenaar  * --------------------------------------------------------------------- */
69c243e490SMarcel Moolenaar 
70c243e490SMarcel Moolenaar struct invalid_umask_error_data {
71c243e490SMarcel Moolenaar     /* One of atf_fs_stat_*_type. */
72c243e490SMarcel Moolenaar     int m_type;
73c243e490SMarcel Moolenaar 
74c243e490SMarcel Moolenaar     /* The original path causing the error. */
75c243e490SMarcel Moolenaar     /* XXX: Ideally this would be an atf_fs_path_t, but if we create it
76c243e490SMarcel Moolenaar      * from the error constructor, we cannot delete the path later on.
77c243e490SMarcel Moolenaar      * Can't remember why atf_error_new does not take a hook for
78c243e490SMarcel Moolenaar      * deletion. */
79c243e490SMarcel Moolenaar     char m_path[1024];
80c243e490SMarcel Moolenaar 
81c243e490SMarcel Moolenaar     /* The umask that caused the error. */
82c243e490SMarcel Moolenaar     mode_t m_umask;
83c243e490SMarcel Moolenaar };
84c243e490SMarcel Moolenaar typedef struct invalid_umask_error_data invalid_umask_error_data_t;
85c243e490SMarcel Moolenaar 
86c243e490SMarcel Moolenaar static
87c243e490SMarcel Moolenaar void
invalid_umask_format(const atf_error_t err,char * buf,size_t buflen)88c243e490SMarcel Moolenaar invalid_umask_format(const atf_error_t err, char *buf, size_t buflen)
89c243e490SMarcel Moolenaar {
90c243e490SMarcel Moolenaar     const invalid_umask_error_data_t *data;
91c243e490SMarcel Moolenaar 
92c243e490SMarcel Moolenaar     PRE(atf_error_is(err, "invalid_umask"));
93c243e490SMarcel Moolenaar 
94c243e490SMarcel Moolenaar     data = atf_error_data(err);
95c243e490SMarcel Moolenaar     snprintf(buf, buflen, "Could not create the temporary %s %s because "
96c243e490SMarcel Moolenaar              "it will not have enough access rights due to the current "
97c243e490SMarcel Moolenaar              "umask %05o", stat_type_to_string(data->m_type),
98c243e490SMarcel Moolenaar              data->m_path, (unsigned int)data->m_umask);
99c243e490SMarcel Moolenaar }
100c243e490SMarcel Moolenaar 
101c243e490SMarcel Moolenaar static
102c243e490SMarcel Moolenaar atf_error_t
invalid_umask_error(const atf_fs_path_t * path,const int type,const mode_t failing_mask)103c243e490SMarcel Moolenaar invalid_umask_error(const atf_fs_path_t *path, const int type,
104c243e490SMarcel Moolenaar                     const mode_t failing_mask)
105c243e490SMarcel Moolenaar {
106c243e490SMarcel Moolenaar     atf_error_t err;
107c243e490SMarcel Moolenaar     invalid_umask_error_data_t data;
108c243e490SMarcel Moolenaar 
109c243e490SMarcel Moolenaar     data.m_type = type;
110c243e490SMarcel Moolenaar 
111c243e490SMarcel Moolenaar     strncpy(data.m_path, atf_fs_path_cstring(path), sizeof(data.m_path));
112c243e490SMarcel Moolenaar     data.m_path[sizeof(data.m_path) - 1] = '\0';
113c243e490SMarcel Moolenaar 
114c243e490SMarcel Moolenaar     data.m_umask = failing_mask;
115c243e490SMarcel Moolenaar 
116c243e490SMarcel Moolenaar     err = atf_error_new("invalid_umask", &data, sizeof(data),
117c243e490SMarcel Moolenaar                         invalid_umask_format);
118c243e490SMarcel Moolenaar 
119c243e490SMarcel Moolenaar     return err;
120c243e490SMarcel Moolenaar }
121c243e490SMarcel Moolenaar 
122c243e490SMarcel Moolenaar /* ---------------------------------------------------------------------
123c243e490SMarcel Moolenaar  * The "unknown_file_type" error type.
124c243e490SMarcel Moolenaar  * --------------------------------------------------------------------- */
125c243e490SMarcel Moolenaar 
126c243e490SMarcel Moolenaar struct unknown_type_error_data {
127c243e490SMarcel Moolenaar     const char *m_path;
128c243e490SMarcel Moolenaar     int m_type;
129c243e490SMarcel Moolenaar };
130c243e490SMarcel Moolenaar typedef struct unknown_type_error_data unknown_type_error_data_t;
131c243e490SMarcel Moolenaar 
132c243e490SMarcel Moolenaar static
133c243e490SMarcel Moolenaar void
unknown_type_format(const atf_error_t err,char * buf,size_t buflen)134c243e490SMarcel Moolenaar unknown_type_format(const atf_error_t err, char *buf, size_t buflen)
135c243e490SMarcel Moolenaar {
136c243e490SMarcel Moolenaar     const unknown_type_error_data_t *data;
137c243e490SMarcel Moolenaar 
138c243e490SMarcel Moolenaar     PRE(atf_error_is(err, "unknown_type"));
139c243e490SMarcel Moolenaar 
140c243e490SMarcel Moolenaar     data = atf_error_data(err);
141c243e490SMarcel Moolenaar     snprintf(buf, buflen, "Unknown file type %d of %s", data->m_type,
142c243e490SMarcel Moolenaar              data->m_path);
143c243e490SMarcel Moolenaar }
144c243e490SMarcel Moolenaar 
145c243e490SMarcel Moolenaar static
146c243e490SMarcel Moolenaar atf_error_t
unknown_type_error(const char * path,int type)147c243e490SMarcel Moolenaar unknown_type_error(const char *path, int type)
148c243e490SMarcel Moolenaar {
149c243e490SMarcel Moolenaar     atf_error_t err;
150c243e490SMarcel Moolenaar     unknown_type_error_data_t data;
151c243e490SMarcel Moolenaar 
152c243e490SMarcel Moolenaar     data.m_path = path;
153c243e490SMarcel Moolenaar     data.m_type = type;
154c243e490SMarcel Moolenaar 
155c243e490SMarcel Moolenaar     err = atf_error_new("unknown_type", &data, sizeof(data),
156c243e490SMarcel Moolenaar                         unknown_type_format);
157c243e490SMarcel Moolenaar 
158c243e490SMarcel Moolenaar     return err;
159c243e490SMarcel Moolenaar }
160c243e490SMarcel Moolenaar 
161c243e490SMarcel Moolenaar /* ---------------------------------------------------------------------
162c243e490SMarcel Moolenaar  * Auxiliary functions.
163c243e490SMarcel Moolenaar  * --------------------------------------------------------------------- */
164c243e490SMarcel Moolenaar 
165c243e490SMarcel Moolenaar static
166c243e490SMarcel Moolenaar bool
check_umask(const mode_t exp_mode,const mode_t min_mode)167c243e490SMarcel Moolenaar check_umask(const mode_t exp_mode, const mode_t min_mode)
168c243e490SMarcel Moolenaar {
169c243e490SMarcel Moolenaar     const mode_t actual_mode = (~current_umask() & exp_mode);
170c243e490SMarcel Moolenaar     return (actual_mode & min_mode) == min_mode;
171c243e490SMarcel Moolenaar }
172c243e490SMarcel Moolenaar 
173c243e490SMarcel Moolenaar static
174c243e490SMarcel Moolenaar atf_error_t
copy_contents(const atf_fs_path_t * p,char ** buf)175c243e490SMarcel Moolenaar copy_contents(const atf_fs_path_t *p, char **buf)
176c243e490SMarcel Moolenaar {
177c243e490SMarcel Moolenaar     atf_error_t err;
178c243e490SMarcel Moolenaar     char *str;
179c243e490SMarcel Moolenaar 
180c243e490SMarcel Moolenaar     str = (char *)malloc(atf_dynstr_length(&p->m_data) + 1);
181c243e490SMarcel Moolenaar     if (str == NULL)
182c243e490SMarcel Moolenaar         err = atf_no_memory_error();
183c243e490SMarcel Moolenaar     else {
184c243e490SMarcel Moolenaar         strcpy(str, atf_dynstr_cstring(&p->m_data));
185c243e490SMarcel Moolenaar         *buf = str;
186c243e490SMarcel Moolenaar         err = atf_no_error();
187c243e490SMarcel Moolenaar     }
188c243e490SMarcel Moolenaar 
189c243e490SMarcel Moolenaar     return err;
190c243e490SMarcel Moolenaar }
191c243e490SMarcel Moolenaar 
192c243e490SMarcel Moolenaar static
193c243e490SMarcel Moolenaar mode_t
current_umask(void)194c243e490SMarcel Moolenaar current_umask(void)
195c243e490SMarcel Moolenaar {
196c243e490SMarcel Moolenaar     const mode_t current = umask(0);
197c243e490SMarcel Moolenaar     (void)umask(current);
198c243e490SMarcel Moolenaar     return current;
199c243e490SMarcel Moolenaar }
200c243e490SMarcel Moolenaar 
201c243e490SMarcel Moolenaar static
202c243e490SMarcel Moolenaar atf_error_t
do_mkdtemp(char * tmpl)203c243e490SMarcel Moolenaar do_mkdtemp(char *tmpl)
204c243e490SMarcel Moolenaar {
205c243e490SMarcel Moolenaar     atf_error_t err;
206c243e490SMarcel Moolenaar 
207c243e490SMarcel Moolenaar     PRE(strstr(tmpl, "XXXXXX") != NULL);
208c243e490SMarcel Moolenaar 
209c243e490SMarcel Moolenaar     if (mkdtemp(tmpl) == NULL)
210c243e490SMarcel Moolenaar         err = atf_libc_error(errno, "Cannot create temporary directory "
211c243e490SMarcel Moolenaar                              "with template '%s'", tmpl);
212c243e490SMarcel Moolenaar     else
213c243e490SMarcel Moolenaar         err = atf_no_error();
214c243e490SMarcel Moolenaar 
215c243e490SMarcel Moolenaar     return err;
216c243e490SMarcel Moolenaar }
217c243e490SMarcel Moolenaar 
218c243e490SMarcel Moolenaar static
219c243e490SMarcel Moolenaar atf_error_t
do_mkstemp(char * tmpl,int * fdout)220c243e490SMarcel Moolenaar do_mkstemp(char *tmpl, int *fdout)
221c243e490SMarcel Moolenaar {
222c243e490SMarcel Moolenaar     atf_error_t err;
223c243e490SMarcel Moolenaar 
224c243e490SMarcel Moolenaar     PRE(strstr(tmpl, "XXXXXX") != NULL);
225c243e490SMarcel Moolenaar 
226c243e490SMarcel Moolenaar     *fdout = mkstemp(tmpl);
227c243e490SMarcel Moolenaar     if (*fdout == -1)
228c243e490SMarcel Moolenaar         err = atf_libc_error(errno, "Cannot create temporary file "
229c243e490SMarcel Moolenaar                              "with template '%s'", tmpl);
230c243e490SMarcel Moolenaar 
231c243e490SMarcel Moolenaar     else
232c243e490SMarcel Moolenaar         err = atf_no_error();
233c243e490SMarcel Moolenaar 
234c243e490SMarcel Moolenaar     return err;
235c243e490SMarcel Moolenaar }
236c243e490SMarcel Moolenaar 
237c243e490SMarcel Moolenaar static
238c243e490SMarcel Moolenaar atf_error_t
normalize(atf_dynstr_t * d,char * p)239c243e490SMarcel Moolenaar normalize(atf_dynstr_t *d, char *p)
240c243e490SMarcel Moolenaar {
241c243e490SMarcel Moolenaar     const char *ptr;
242c243e490SMarcel Moolenaar     char *last;
243c243e490SMarcel Moolenaar     atf_error_t err;
244c243e490SMarcel Moolenaar     bool first;
245c243e490SMarcel Moolenaar 
246c243e490SMarcel Moolenaar     PRE(strlen(p) > 0);
247c243e490SMarcel Moolenaar     PRE(atf_dynstr_length(d) == 0);
248c243e490SMarcel Moolenaar 
249c243e490SMarcel Moolenaar     if (p[0] == '/')
250c243e490SMarcel Moolenaar         err = atf_dynstr_append_fmt(d, "/");
251c243e490SMarcel Moolenaar     else
252c243e490SMarcel Moolenaar         err = atf_no_error();
253c243e490SMarcel Moolenaar 
254c243e490SMarcel Moolenaar     first = true;
255c243e490SMarcel Moolenaar     last = NULL; /* Silence GCC warning. */
256c243e490SMarcel Moolenaar     ptr = strtok_r(p, "/", &last);
257c243e490SMarcel Moolenaar     while (!atf_is_error(err) && ptr != NULL) {
258c243e490SMarcel Moolenaar         if (strlen(ptr) > 0) {
259c243e490SMarcel Moolenaar             err = atf_dynstr_append_fmt(d, "%s%s", first ? "" : "/", ptr);
260c243e490SMarcel Moolenaar             first = false;
261c243e490SMarcel Moolenaar         }
262c243e490SMarcel Moolenaar 
263c243e490SMarcel Moolenaar         ptr = strtok_r(NULL, "/", &last);
264c243e490SMarcel Moolenaar     }
265c243e490SMarcel Moolenaar 
266c243e490SMarcel Moolenaar     return err;
267c243e490SMarcel Moolenaar }
268c243e490SMarcel Moolenaar 
269c243e490SMarcel Moolenaar static
270c243e490SMarcel Moolenaar atf_error_t
normalize_ap(atf_dynstr_t * d,const char * p,va_list ap)271c243e490SMarcel Moolenaar normalize_ap(atf_dynstr_t *d, const char *p, va_list ap)
272c243e490SMarcel Moolenaar {
273c243e490SMarcel Moolenaar     char *str;
274c243e490SMarcel Moolenaar     atf_error_t err;
275c243e490SMarcel Moolenaar     va_list ap2;
276c243e490SMarcel Moolenaar 
277c243e490SMarcel Moolenaar     err = atf_dynstr_init(d);
278c243e490SMarcel Moolenaar     if (atf_is_error(err))
279c243e490SMarcel Moolenaar         goto out;
280c243e490SMarcel Moolenaar 
281c243e490SMarcel Moolenaar     va_copy(ap2, ap);
282c243e490SMarcel Moolenaar     err = atf_text_format_ap(&str, p, ap2);
283c243e490SMarcel Moolenaar     va_end(ap2);
284c243e490SMarcel Moolenaar     if (atf_is_error(err))
285c243e490SMarcel Moolenaar         atf_dynstr_fini(d);
286c243e490SMarcel Moolenaar     else {
287c243e490SMarcel Moolenaar         err = normalize(d, str);
288c243e490SMarcel Moolenaar         free(str);
289c243e490SMarcel Moolenaar     }
290c243e490SMarcel Moolenaar 
291c243e490SMarcel Moolenaar out:
292c243e490SMarcel Moolenaar     return err;
293c243e490SMarcel Moolenaar }
294c243e490SMarcel Moolenaar 
295c243e490SMarcel Moolenaar static
296c243e490SMarcel Moolenaar void
replace_contents(atf_fs_path_t * p,const char * buf)297c243e490SMarcel Moolenaar replace_contents(atf_fs_path_t *p, const char *buf)
298c243e490SMarcel Moolenaar {
299c243e490SMarcel Moolenaar     atf_error_t err;
300c243e490SMarcel Moolenaar 
301c243e490SMarcel Moolenaar     PRE(atf_dynstr_length(&p->m_data) == strlen(buf));
302c243e490SMarcel Moolenaar 
303c243e490SMarcel Moolenaar     atf_dynstr_clear(&p->m_data);
304c243e490SMarcel Moolenaar     err = atf_dynstr_append_fmt(&p->m_data, "%s", buf);
305c243e490SMarcel Moolenaar 
306c243e490SMarcel Moolenaar     INV(!atf_is_error(err));
307c243e490SMarcel Moolenaar }
308c243e490SMarcel Moolenaar 
309c243e490SMarcel Moolenaar static
310c243e490SMarcel Moolenaar const char *
stat_type_to_string(const int type)311c243e490SMarcel Moolenaar stat_type_to_string(const int type)
312c243e490SMarcel Moolenaar {
313c243e490SMarcel Moolenaar     const char *str;
314c243e490SMarcel Moolenaar 
315c243e490SMarcel Moolenaar     if (type == atf_fs_stat_blk_type)
316c243e490SMarcel Moolenaar         str = "block device";
317c243e490SMarcel Moolenaar     else if (type == atf_fs_stat_chr_type)
318c243e490SMarcel Moolenaar         str = "character device";
319c243e490SMarcel Moolenaar     else if (type == atf_fs_stat_dir_type)
320c243e490SMarcel Moolenaar         str = "directory";
321c243e490SMarcel Moolenaar     else if (type == atf_fs_stat_fifo_type)
322c243e490SMarcel Moolenaar         str = "named pipe";
323c243e490SMarcel Moolenaar     else if (type == atf_fs_stat_lnk_type)
324c243e490SMarcel Moolenaar         str = "symbolic link";
325c243e490SMarcel Moolenaar     else if (type == atf_fs_stat_reg_type)
326c243e490SMarcel Moolenaar         str = "regular file";
327c243e490SMarcel Moolenaar     else if (type == atf_fs_stat_sock_type)
328c243e490SMarcel Moolenaar         str = "socket";
329c243e490SMarcel Moolenaar     else if (type == atf_fs_stat_wht_type)
330c243e490SMarcel Moolenaar         str = "whiteout";
331c243e490SMarcel Moolenaar     else {
332c243e490SMarcel Moolenaar         UNREACHABLE;
333c243e490SMarcel Moolenaar         str = NULL;
334c243e490SMarcel Moolenaar     }
335c243e490SMarcel Moolenaar 
336c243e490SMarcel Moolenaar     return str;
337c243e490SMarcel Moolenaar }
338c243e490SMarcel Moolenaar 
339c243e490SMarcel Moolenaar /* ---------------------------------------------------------------------
340c243e490SMarcel Moolenaar  * The "atf_fs_path" type.
341c243e490SMarcel Moolenaar  * --------------------------------------------------------------------- */
342c243e490SMarcel Moolenaar 
343c243e490SMarcel Moolenaar /*
344c243e490SMarcel Moolenaar  * Constructors/destructors.
345c243e490SMarcel Moolenaar  */
346c243e490SMarcel Moolenaar 
347c243e490SMarcel Moolenaar atf_error_t
atf_fs_path_init_ap(atf_fs_path_t * p,const char * fmt,va_list ap)348c243e490SMarcel Moolenaar atf_fs_path_init_ap(atf_fs_path_t *p, const char *fmt, va_list ap)
349c243e490SMarcel Moolenaar {
350c243e490SMarcel Moolenaar     atf_error_t err;
351c243e490SMarcel Moolenaar     va_list ap2;
352c243e490SMarcel Moolenaar 
353c243e490SMarcel Moolenaar     va_copy(ap2, ap);
354c243e490SMarcel Moolenaar     err = normalize_ap(&p->m_data, fmt, ap2);
355c243e490SMarcel Moolenaar     va_end(ap2);
356c243e490SMarcel Moolenaar 
357c243e490SMarcel Moolenaar     return err;
358c243e490SMarcel Moolenaar }
359c243e490SMarcel Moolenaar 
360c243e490SMarcel Moolenaar atf_error_t
atf_fs_path_init_fmt(atf_fs_path_t * p,const char * fmt,...)361c243e490SMarcel Moolenaar atf_fs_path_init_fmt(atf_fs_path_t *p, const char *fmt, ...)
362c243e490SMarcel Moolenaar {
363c243e490SMarcel Moolenaar     va_list ap;
364c243e490SMarcel Moolenaar     atf_error_t err;
365c243e490SMarcel Moolenaar 
366c243e490SMarcel Moolenaar     va_start(ap, fmt);
367c243e490SMarcel Moolenaar     err = atf_fs_path_init_ap(p, fmt, ap);
368c243e490SMarcel Moolenaar     va_end(ap);
369c243e490SMarcel Moolenaar 
370c243e490SMarcel Moolenaar     return err;
371c243e490SMarcel Moolenaar }
372c243e490SMarcel Moolenaar 
373c243e490SMarcel Moolenaar atf_error_t
atf_fs_path_copy(atf_fs_path_t * dest,const atf_fs_path_t * src)374c243e490SMarcel Moolenaar atf_fs_path_copy(atf_fs_path_t *dest, const atf_fs_path_t *src)
375c243e490SMarcel Moolenaar {
376c243e490SMarcel Moolenaar     return atf_dynstr_copy(&dest->m_data, &src->m_data);
377c243e490SMarcel Moolenaar }
378c243e490SMarcel Moolenaar 
379c243e490SMarcel Moolenaar void
atf_fs_path_fini(atf_fs_path_t * p)380c243e490SMarcel Moolenaar atf_fs_path_fini(atf_fs_path_t *p)
381c243e490SMarcel Moolenaar {
382c243e490SMarcel Moolenaar     atf_dynstr_fini(&p->m_data);
383c243e490SMarcel Moolenaar }
384c243e490SMarcel Moolenaar 
385c243e490SMarcel Moolenaar /*
386c243e490SMarcel Moolenaar  * Getters.
387c243e490SMarcel Moolenaar  */
388c243e490SMarcel Moolenaar 
389c243e490SMarcel Moolenaar atf_error_t
atf_fs_path_branch_path(const atf_fs_path_t * p,atf_fs_path_t * bp)390c243e490SMarcel Moolenaar atf_fs_path_branch_path(const atf_fs_path_t *p, atf_fs_path_t *bp)
391c243e490SMarcel Moolenaar {
392c243e490SMarcel Moolenaar     const size_t endpos = atf_dynstr_rfind_ch(&p->m_data, '/');
393c243e490SMarcel Moolenaar     atf_error_t err;
394c243e490SMarcel Moolenaar 
395c243e490SMarcel Moolenaar     if (endpos == atf_dynstr_npos)
396c243e490SMarcel Moolenaar         err = atf_fs_path_init_fmt(bp, ".");
397c243e490SMarcel Moolenaar     else if (endpos == 0)
398c243e490SMarcel Moolenaar         err = atf_fs_path_init_fmt(bp, "/");
399c243e490SMarcel Moolenaar     else
400c243e490SMarcel Moolenaar         err = atf_dynstr_init_substr(&bp->m_data, &p->m_data, 0, endpos);
401c243e490SMarcel Moolenaar 
402c243e490SMarcel Moolenaar #if defined(HAVE_CONST_DIRNAME)
403c243e490SMarcel Moolenaar     INV(atf_equal_dynstr_cstring(&bp->m_data,
404c243e490SMarcel Moolenaar                                  dirname(atf_dynstr_cstring(&p->m_data))));
405c243e490SMarcel Moolenaar #endif /* defined(HAVE_CONST_DIRNAME) */
406c243e490SMarcel Moolenaar 
407c243e490SMarcel Moolenaar     return err;
408c243e490SMarcel Moolenaar }
409c243e490SMarcel Moolenaar 
410c243e490SMarcel Moolenaar const char *
atf_fs_path_cstring(const atf_fs_path_t * p)411c243e490SMarcel Moolenaar atf_fs_path_cstring(const atf_fs_path_t *p)
412c243e490SMarcel Moolenaar {
413c243e490SMarcel Moolenaar     return atf_dynstr_cstring(&p->m_data);
414c243e490SMarcel Moolenaar }
415c243e490SMarcel Moolenaar 
416c243e490SMarcel Moolenaar atf_error_t
atf_fs_path_leaf_name(const atf_fs_path_t * p,atf_dynstr_t * ln)417c243e490SMarcel Moolenaar atf_fs_path_leaf_name(const atf_fs_path_t *p, atf_dynstr_t *ln)
418c243e490SMarcel Moolenaar {
419c243e490SMarcel Moolenaar     size_t begpos = atf_dynstr_rfind_ch(&p->m_data, '/');
420c243e490SMarcel Moolenaar     atf_error_t err;
421c243e490SMarcel Moolenaar 
422c243e490SMarcel Moolenaar     if (begpos == atf_dynstr_npos)
423c243e490SMarcel Moolenaar         begpos = 0;
424c243e490SMarcel Moolenaar     else
425c243e490SMarcel Moolenaar         begpos++;
426c243e490SMarcel Moolenaar 
427c243e490SMarcel Moolenaar     err = atf_dynstr_init_substr(ln, &p->m_data, begpos, atf_dynstr_npos);
428c243e490SMarcel Moolenaar 
429c243e490SMarcel Moolenaar #if defined(HAVE_CONST_BASENAME)
430c243e490SMarcel Moolenaar     INV(atf_equal_dynstr_cstring(ln,
431c243e490SMarcel Moolenaar                                  basename(atf_dynstr_cstring(&p->m_data))));
432c243e490SMarcel Moolenaar #endif /* defined(HAVE_CONST_BASENAME) */
433c243e490SMarcel Moolenaar 
434c243e490SMarcel Moolenaar     return err;
435c243e490SMarcel Moolenaar }
436c243e490SMarcel Moolenaar 
437c243e490SMarcel Moolenaar bool
atf_fs_path_is_absolute(const atf_fs_path_t * p)438c243e490SMarcel Moolenaar atf_fs_path_is_absolute(const atf_fs_path_t *p)
439c243e490SMarcel Moolenaar {
440c243e490SMarcel Moolenaar     return atf_dynstr_cstring(&p->m_data)[0] == '/';
441c243e490SMarcel Moolenaar }
442c243e490SMarcel Moolenaar 
443c243e490SMarcel Moolenaar bool
atf_fs_path_is_root(const atf_fs_path_t * p)444c243e490SMarcel Moolenaar atf_fs_path_is_root(const atf_fs_path_t *p)
445c243e490SMarcel Moolenaar {
446c243e490SMarcel Moolenaar     return atf_equal_dynstr_cstring(&p->m_data, "/");
447c243e490SMarcel Moolenaar }
448c243e490SMarcel Moolenaar 
449c243e490SMarcel Moolenaar /*
450c243e490SMarcel Moolenaar  * Modifiers.
451c243e490SMarcel Moolenaar  */
452c243e490SMarcel Moolenaar 
453c243e490SMarcel Moolenaar atf_error_t
atf_fs_path_append_ap(atf_fs_path_t * p,const char * fmt,va_list ap)454c243e490SMarcel Moolenaar atf_fs_path_append_ap(atf_fs_path_t *p, const char *fmt, va_list ap)
455c243e490SMarcel Moolenaar {
456c243e490SMarcel Moolenaar     atf_dynstr_t aux;
457c243e490SMarcel Moolenaar     atf_error_t err;
458c243e490SMarcel Moolenaar     va_list ap2;
459c243e490SMarcel Moolenaar 
460c243e490SMarcel Moolenaar     va_copy(ap2, ap);
461c243e490SMarcel Moolenaar     err = normalize_ap(&aux, fmt, ap2);
462c243e490SMarcel Moolenaar     va_end(ap2);
463c243e490SMarcel Moolenaar     if (!atf_is_error(err)) {
464c243e490SMarcel Moolenaar         const char *auxstr = atf_dynstr_cstring(&aux);
465c243e490SMarcel Moolenaar         const bool needslash = auxstr[0] != '/';
466c243e490SMarcel Moolenaar 
467c243e490SMarcel Moolenaar         err = atf_dynstr_append_fmt(&p->m_data, "%s%s",
468c243e490SMarcel Moolenaar                                     needslash ? "/" : "", auxstr);
469c243e490SMarcel Moolenaar 
470c243e490SMarcel Moolenaar         atf_dynstr_fini(&aux);
471c243e490SMarcel Moolenaar     }
472c243e490SMarcel Moolenaar 
473c243e490SMarcel Moolenaar     return err;
474c243e490SMarcel Moolenaar }
475c243e490SMarcel Moolenaar 
476c243e490SMarcel Moolenaar atf_error_t
atf_fs_path_append_fmt(atf_fs_path_t * p,const char * fmt,...)477c243e490SMarcel Moolenaar atf_fs_path_append_fmt(atf_fs_path_t *p, const char *fmt, ...)
478c243e490SMarcel Moolenaar {
479c243e490SMarcel Moolenaar     va_list ap;
480c243e490SMarcel Moolenaar     atf_error_t err;
481c243e490SMarcel Moolenaar 
482c243e490SMarcel Moolenaar     va_start(ap, fmt);
483c243e490SMarcel Moolenaar     err = atf_fs_path_append_ap(p, fmt, ap);
484c243e490SMarcel Moolenaar     va_end(ap);
485c243e490SMarcel Moolenaar 
486c243e490SMarcel Moolenaar     return err;
487c243e490SMarcel Moolenaar }
488c243e490SMarcel Moolenaar 
489c243e490SMarcel Moolenaar atf_error_t
atf_fs_path_append_path(atf_fs_path_t * p,const atf_fs_path_t * p2)490c243e490SMarcel Moolenaar atf_fs_path_append_path(atf_fs_path_t *p, const atf_fs_path_t *p2)
491c243e490SMarcel Moolenaar {
492c243e490SMarcel Moolenaar     return atf_fs_path_append_fmt(p, "%s", atf_dynstr_cstring(&p2->m_data));
493c243e490SMarcel Moolenaar }
494c243e490SMarcel Moolenaar 
495c243e490SMarcel Moolenaar atf_error_t
atf_fs_path_to_absolute(const atf_fs_path_t * p,atf_fs_path_t * pa)496c243e490SMarcel Moolenaar atf_fs_path_to_absolute(const atf_fs_path_t *p, atf_fs_path_t *pa)
497c243e490SMarcel Moolenaar {
498c243e490SMarcel Moolenaar     atf_error_t err;
499c243e490SMarcel Moolenaar 
500c243e490SMarcel Moolenaar     PRE(!atf_fs_path_is_absolute(p));
501c243e490SMarcel Moolenaar 
502c243e490SMarcel Moolenaar     err = atf_fs_getcwd(pa);
503c243e490SMarcel Moolenaar     if (atf_is_error(err))
504c243e490SMarcel Moolenaar         goto out;
505c243e490SMarcel Moolenaar 
506c243e490SMarcel Moolenaar     err = atf_fs_path_append_path(pa, p);
507c243e490SMarcel Moolenaar     if (atf_is_error(err))
508c243e490SMarcel Moolenaar         atf_fs_path_fini(pa);
509c243e490SMarcel Moolenaar 
510c243e490SMarcel Moolenaar out:
511c243e490SMarcel Moolenaar     return err;
512c243e490SMarcel Moolenaar }
513c243e490SMarcel Moolenaar 
514c243e490SMarcel Moolenaar /*
515c243e490SMarcel Moolenaar  * Operators.
516c243e490SMarcel Moolenaar  */
517c243e490SMarcel Moolenaar 
atf_equal_fs_path_fs_path(const atf_fs_path_t * p1,const atf_fs_path_t * p2)518c243e490SMarcel Moolenaar bool atf_equal_fs_path_fs_path(const atf_fs_path_t *p1,
519c243e490SMarcel Moolenaar                                const atf_fs_path_t *p2)
520c243e490SMarcel Moolenaar {
521c243e490SMarcel Moolenaar     return atf_equal_dynstr_dynstr(&p1->m_data, &p2->m_data);
522c243e490SMarcel Moolenaar }
523c243e490SMarcel Moolenaar 
524c243e490SMarcel Moolenaar /* ---------------------------------------------------------------------
525c243e490SMarcel Moolenaar  * The "atf_fs_path" type.
526c243e490SMarcel Moolenaar  * --------------------------------------------------------------------- */
527c243e490SMarcel Moolenaar 
528c243e490SMarcel Moolenaar /*
529c243e490SMarcel Moolenaar  * Constants.
530c243e490SMarcel Moolenaar  */
531c243e490SMarcel Moolenaar 
532c243e490SMarcel Moolenaar const int atf_fs_stat_blk_type  = 1;
533c243e490SMarcel Moolenaar const int atf_fs_stat_chr_type  = 2;
534c243e490SMarcel Moolenaar const int atf_fs_stat_dir_type  = 3;
535c243e490SMarcel Moolenaar const int atf_fs_stat_fifo_type = 4;
536c243e490SMarcel Moolenaar const int atf_fs_stat_lnk_type  = 5;
537c243e490SMarcel Moolenaar const int atf_fs_stat_reg_type  = 6;
538c243e490SMarcel Moolenaar const int atf_fs_stat_sock_type = 7;
539c243e490SMarcel Moolenaar const int atf_fs_stat_wht_type  = 8;
540c243e490SMarcel Moolenaar 
541c243e490SMarcel Moolenaar /*
542c243e490SMarcel Moolenaar  * Constructors/destructors.
543c243e490SMarcel Moolenaar  */
544c243e490SMarcel Moolenaar 
545c243e490SMarcel Moolenaar atf_error_t
atf_fs_stat_init(atf_fs_stat_t * st,const atf_fs_path_t * p)546c243e490SMarcel Moolenaar atf_fs_stat_init(atf_fs_stat_t *st, const atf_fs_path_t *p)
547c243e490SMarcel Moolenaar {
548c243e490SMarcel Moolenaar     atf_error_t err;
549c243e490SMarcel Moolenaar     const char *pstr = atf_fs_path_cstring(p);
550c243e490SMarcel Moolenaar 
551c243e490SMarcel Moolenaar     if (lstat(pstr, &st->m_sb) == -1) {
552c243e490SMarcel Moolenaar         err = atf_libc_error(errno, "Cannot get information of %s; "
553c243e490SMarcel Moolenaar                              "lstat(2) failed", pstr);
554c243e490SMarcel Moolenaar     } else {
555c243e490SMarcel Moolenaar         int type = st->m_sb.st_mode & S_IFMT;
556c243e490SMarcel Moolenaar         err = atf_no_error();
557c243e490SMarcel Moolenaar         switch (type) {
558c243e490SMarcel Moolenaar             case S_IFBLK:  st->m_type = atf_fs_stat_blk_type;  break;
559c243e490SMarcel Moolenaar             case S_IFCHR:  st->m_type = atf_fs_stat_chr_type;  break;
560c243e490SMarcel Moolenaar             case S_IFDIR:  st->m_type = atf_fs_stat_dir_type;  break;
561c243e490SMarcel Moolenaar             case S_IFIFO:  st->m_type = atf_fs_stat_fifo_type; break;
562c243e490SMarcel Moolenaar             case S_IFLNK:  st->m_type = atf_fs_stat_lnk_type;  break;
563c243e490SMarcel Moolenaar             case S_IFREG:  st->m_type = atf_fs_stat_reg_type;  break;
564c243e490SMarcel Moolenaar             case S_IFSOCK: st->m_type = atf_fs_stat_sock_type; break;
565c243e490SMarcel Moolenaar #if defined(S_IFWHT)
566c243e490SMarcel Moolenaar             case S_IFWHT:  st->m_type = atf_fs_stat_wht_type;  break;
567c243e490SMarcel Moolenaar #endif
568c243e490SMarcel Moolenaar             default:
569c243e490SMarcel Moolenaar                 err = unknown_type_error(pstr, type);
570c243e490SMarcel Moolenaar         }
571c243e490SMarcel Moolenaar     }
572c243e490SMarcel Moolenaar 
573c243e490SMarcel Moolenaar     return err;
574c243e490SMarcel Moolenaar }
575c243e490SMarcel Moolenaar 
576c243e490SMarcel Moolenaar void
atf_fs_stat_copy(atf_fs_stat_t * dest,const atf_fs_stat_t * src)577c243e490SMarcel Moolenaar atf_fs_stat_copy(atf_fs_stat_t *dest, const atf_fs_stat_t *src)
578c243e490SMarcel Moolenaar {
579c243e490SMarcel Moolenaar     dest->m_type = src->m_type;
580c243e490SMarcel Moolenaar     dest->m_sb = src->m_sb;
581c243e490SMarcel Moolenaar }
582c243e490SMarcel Moolenaar 
583c243e490SMarcel Moolenaar void
atf_fs_stat_fini(atf_fs_stat_t * st ATF_DEFS_ATTRIBUTE_UNUSED)584c243e490SMarcel Moolenaar atf_fs_stat_fini(atf_fs_stat_t *st ATF_DEFS_ATTRIBUTE_UNUSED)
585c243e490SMarcel Moolenaar {
586c243e490SMarcel Moolenaar }
587c243e490SMarcel Moolenaar 
588c243e490SMarcel Moolenaar /*
589c243e490SMarcel Moolenaar  * Getters.
590c243e490SMarcel Moolenaar  */
591c243e490SMarcel Moolenaar 
592c243e490SMarcel Moolenaar dev_t
atf_fs_stat_get_device(const atf_fs_stat_t * st)593c243e490SMarcel Moolenaar atf_fs_stat_get_device(const atf_fs_stat_t *st)
594c243e490SMarcel Moolenaar {
595c243e490SMarcel Moolenaar     return st->m_sb.st_dev;
596c243e490SMarcel Moolenaar }
597c243e490SMarcel Moolenaar 
598c243e490SMarcel Moolenaar ino_t
atf_fs_stat_get_inode(const atf_fs_stat_t * st)599c243e490SMarcel Moolenaar atf_fs_stat_get_inode(const atf_fs_stat_t *st)
600c243e490SMarcel Moolenaar {
601c243e490SMarcel Moolenaar     return st->m_sb.st_ino;
602c243e490SMarcel Moolenaar }
603c243e490SMarcel Moolenaar 
604c243e490SMarcel Moolenaar mode_t
atf_fs_stat_get_mode(const atf_fs_stat_t * st)605c243e490SMarcel Moolenaar atf_fs_stat_get_mode(const atf_fs_stat_t *st)
606c243e490SMarcel Moolenaar {
607c243e490SMarcel Moolenaar     return st->m_sb.st_mode & ~S_IFMT;
608c243e490SMarcel Moolenaar }
609c243e490SMarcel Moolenaar 
610c243e490SMarcel Moolenaar off_t
atf_fs_stat_get_size(const atf_fs_stat_t * st)611c243e490SMarcel Moolenaar atf_fs_stat_get_size(const atf_fs_stat_t *st)
612c243e490SMarcel Moolenaar {
613c243e490SMarcel Moolenaar     return st->m_sb.st_size;
614c243e490SMarcel Moolenaar }
615c243e490SMarcel Moolenaar 
616c243e490SMarcel Moolenaar int
atf_fs_stat_get_type(const atf_fs_stat_t * st)617c243e490SMarcel Moolenaar atf_fs_stat_get_type(const atf_fs_stat_t *st)
618c243e490SMarcel Moolenaar {
619c243e490SMarcel Moolenaar     return st->m_type;
620c243e490SMarcel Moolenaar }
621c243e490SMarcel Moolenaar 
622c243e490SMarcel Moolenaar bool
atf_fs_stat_is_owner_readable(const atf_fs_stat_t * st)623c243e490SMarcel Moolenaar atf_fs_stat_is_owner_readable(const atf_fs_stat_t *st)
624c243e490SMarcel Moolenaar {
625c243e490SMarcel Moolenaar     return st->m_sb.st_mode & S_IRUSR;
626c243e490SMarcel Moolenaar }
627c243e490SMarcel Moolenaar 
628c243e490SMarcel Moolenaar bool
atf_fs_stat_is_owner_writable(const atf_fs_stat_t * st)629c243e490SMarcel Moolenaar atf_fs_stat_is_owner_writable(const atf_fs_stat_t *st)
630c243e490SMarcel Moolenaar {
631c243e490SMarcel Moolenaar     return st->m_sb.st_mode & S_IWUSR;
632c243e490SMarcel Moolenaar }
633c243e490SMarcel Moolenaar 
634c243e490SMarcel Moolenaar bool
atf_fs_stat_is_owner_executable(const atf_fs_stat_t * st)635c243e490SMarcel Moolenaar atf_fs_stat_is_owner_executable(const atf_fs_stat_t *st)
636c243e490SMarcel Moolenaar {
637c243e490SMarcel Moolenaar     return st->m_sb.st_mode & S_IXUSR;
638c243e490SMarcel Moolenaar }
639c243e490SMarcel Moolenaar 
640c243e490SMarcel Moolenaar bool
atf_fs_stat_is_group_readable(const atf_fs_stat_t * st)641c243e490SMarcel Moolenaar atf_fs_stat_is_group_readable(const atf_fs_stat_t *st)
642c243e490SMarcel Moolenaar {
643c243e490SMarcel Moolenaar     return st->m_sb.st_mode & S_IRGRP;
644c243e490SMarcel Moolenaar }
645c243e490SMarcel Moolenaar 
646c243e490SMarcel Moolenaar bool
atf_fs_stat_is_group_writable(const atf_fs_stat_t * st)647c243e490SMarcel Moolenaar atf_fs_stat_is_group_writable(const atf_fs_stat_t *st)
648c243e490SMarcel Moolenaar {
649c243e490SMarcel Moolenaar     return st->m_sb.st_mode & S_IWGRP;
650c243e490SMarcel Moolenaar }
651c243e490SMarcel Moolenaar 
652c243e490SMarcel Moolenaar bool
atf_fs_stat_is_group_executable(const atf_fs_stat_t * st)653c243e490SMarcel Moolenaar atf_fs_stat_is_group_executable(const atf_fs_stat_t *st)
654c243e490SMarcel Moolenaar {
655c243e490SMarcel Moolenaar     return st->m_sb.st_mode & S_IXGRP;
656c243e490SMarcel Moolenaar }
657c243e490SMarcel Moolenaar 
658c243e490SMarcel Moolenaar bool
atf_fs_stat_is_other_readable(const atf_fs_stat_t * st)659c243e490SMarcel Moolenaar atf_fs_stat_is_other_readable(const atf_fs_stat_t *st)
660c243e490SMarcel Moolenaar {
661c243e490SMarcel Moolenaar     return st->m_sb.st_mode & S_IROTH;
662c243e490SMarcel Moolenaar }
663c243e490SMarcel Moolenaar 
664c243e490SMarcel Moolenaar bool
atf_fs_stat_is_other_writable(const atf_fs_stat_t * st)665c243e490SMarcel Moolenaar atf_fs_stat_is_other_writable(const atf_fs_stat_t *st)
666c243e490SMarcel Moolenaar {
667c243e490SMarcel Moolenaar     return st->m_sb.st_mode & S_IWOTH;
668c243e490SMarcel Moolenaar }
669c243e490SMarcel Moolenaar 
670c243e490SMarcel Moolenaar bool
atf_fs_stat_is_other_executable(const atf_fs_stat_t * st)671c243e490SMarcel Moolenaar atf_fs_stat_is_other_executable(const atf_fs_stat_t *st)
672c243e490SMarcel Moolenaar {
673c243e490SMarcel Moolenaar     return st->m_sb.st_mode & S_IXOTH;
674c243e490SMarcel Moolenaar }
675c243e490SMarcel Moolenaar 
676c243e490SMarcel Moolenaar /* ---------------------------------------------------------------------
677c243e490SMarcel Moolenaar  * Free functions.
678c243e490SMarcel Moolenaar  * --------------------------------------------------------------------- */
679c243e490SMarcel Moolenaar 
680c243e490SMarcel Moolenaar const int atf_fs_access_f = 1 << 0;
681c243e490SMarcel Moolenaar const int atf_fs_access_r = 1 << 1;
682c243e490SMarcel Moolenaar const int atf_fs_access_w = 1 << 2;
683c243e490SMarcel Moolenaar const int atf_fs_access_x = 1 << 3;
684c243e490SMarcel Moolenaar 
685c243e490SMarcel Moolenaar /*
686c243e490SMarcel Moolenaar  * An implementation of access(2) but using the effective user value
687c243e490SMarcel Moolenaar  * instead of the real one.  Also avoids false positives for root when
688c243e490SMarcel Moolenaar  * asking for execute permissions, which appear in SunOS.
689c243e490SMarcel Moolenaar  */
690c243e490SMarcel Moolenaar atf_error_t
atf_fs_eaccess(const atf_fs_path_t * p,int mode)691c243e490SMarcel Moolenaar atf_fs_eaccess(const atf_fs_path_t *p, int mode)
692c243e490SMarcel Moolenaar {
693c243e490SMarcel Moolenaar     atf_error_t err;
694c243e490SMarcel Moolenaar     struct stat st;
695c243e490SMarcel Moolenaar     bool ok;
696c243e490SMarcel Moolenaar 
697c243e490SMarcel Moolenaar     PRE(mode & atf_fs_access_f || mode & atf_fs_access_r ||
698c243e490SMarcel Moolenaar         mode & atf_fs_access_w || mode & atf_fs_access_x);
699c243e490SMarcel Moolenaar 
700c243e490SMarcel Moolenaar     if (lstat(atf_fs_path_cstring(p), &st) == -1) {
701c243e490SMarcel Moolenaar         err = atf_libc_error(errno, "Cannot get information from file %s",
702c243e490SMarcel Moolenaar                              atf_fs_path_cstring(p));
703c243e490SMarcel Moolenaar         goto out;
704c243e490SMarcel Moolenaar     }
705c243e490SMarcel Moolenaar 
706c243e490SMarcel Moolenaar     err = atf_no_error();
707c243e490SMarcel Moolenaar 
708c243e490SMarcel Moolenaar     /* Early return if we are only checking for existence and the file
709c243e490SMarcel Moolenaar      * exists (stat call returned). */
710c243e490SMarcel Moolenaar     if (mode & atf_fs_access_f)
711c243e490SMarcel Moolenaar         goto out;
712c243e490SMarcel Moolenaar 
713c243e490SMarcel Moolenaar     ok = false;
714c243e490SMarcel Moolenaar     if (atf_user_is_root()) {
715c243e490SMarcel Moolenaar         if (!ok && !(mode & atf_fs_access_x)) {
716c243e490SMarcel Moolenaar             /* Allow root to read/write any file. */
717c243e490SMarcel Moolenaar             ok = true;
718c243e490SMarcel Moolenaar         }
719c243e490SMarcel Moolenaar 
720c243e490SMarcel Moolenaar         if (!ok && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) {
721c243e490SMarcel Moolenaar             /* Allow root to execute the file if any of its execution bits
722c243e490SMarcel Moolenaar              * are set. */
723c243e490SMarcel Moolenaar             ok = true;
724c243e490SMarcel Moolenaar         }
725c243e490SMarcel Moolenaar     } else {
726c243e490SMarcel Moolenaar         if (!ok && (atf_user_euid() == st.st_uid)) {
727c243e490SMarcel Moolenaar             ok = ((mode & atf_fs_access_r) && (st.st_mode & S_IRUSR)) ||
728c243e490SMarcel Moolenaar                  ((mode & atf_fs_access_w) && (st.st_mode & S_IWUSR)) ||
729c243e490SMarcel Moolenaar                  ((mode & atf_fs_access_x) && (st.st_mode & S_IXUSR));
730c243e490SMarcel Moolenaar         }
731c243e490SMarcel Moolenaar         if (!ok && atf_user_is_member_of_group(st.st_gid)) {
732c243e490SMarcel Moolenaar             ok = ((mode & atf_fs_access_r) && (st.st_mode & S_IRGRP)) ||
733c243e490SMarcel Moolenaar                  ((mode & atf_fs_access_w) && (st.st_mode & S_IWGRP)) ||
734c243e490SMarcel Moolenaar                  ((mode & atf_fs_access_x) && (st.st_mode & S_IXGRP));
735c243e490SMarcel Moolenaar         }
736c243e490SMarcel Moolenaar         if (!ok && ((atf_user_euid() != st.st_uid) &&
737c243e490SMarcel Moolenaar                     !atf_user_is_member_of_group(st.st_gid))) {
738c243e490SMarcel Moolenaar             ok = ((mode & atf_fs_access_r) && (st.st_mode & S_IROTH)) ||
739c243e490SMarcel Moolenaar                  ((mode & atf_fs_access_w) && (st.st_mode & S_IWOTH)) ||
740c243e490SMarcel Moolenaar                  ((mode & atf_fs_access_x) && (st.st_mode & S_IXOTH));
741c243e490SMarcel Moolenaar         }
742c243e490SMarcel Moolenaar     }
743c243e490SMarcel Moolenaar 
744c243e490SMarcel Moolenaar     if (!ok)
745c243e490SMarcel Moolenaar         err = atf_libc_error(EACCES, "Access check failed");
746c243e490SMarcel Moolenaar 
747c243e490SMarcel Moolenaar out:
748c243e490SMarcel Moolenaar     return err;
749c243e490SMarcel Moolenaar }
750c243e490SMarcel Moolenaar 
751c243e490SMarcel Moolenaar atf_error_t
atf_fs_exists(const atf_fs_path_t * p,bool * b)752c243e490SMarcel Moolenaar atf_fs_exists(const atf_fs_path_t *p, bool *b)
753c243e490SMarcel Moolenaar {
754c243e490SMarcel Moolenaar     atf_error_t err;
755c243e490SMarcel Moolenaar 
756c243e490SMarcel Moolenaar     err = atf_fs_eaccess(p, atf_fs_access_f);
757c243e490SMarcel Moolenaar     if (atf_is_error(err)) {
758c243e490SMarcel Moolenaar         if (atf_error_is(err, "libc") && atf_libc_error_code(err) == ENOENT) {
759c243e490SMarcel Moolenaar             atf_error_free(err);
760c243e490SMarcel Moolenaar             err = atf_no_error();
761c243e490SMarcel Moolenaar             *b = false;
762c243e490SMarcel Moolenaar         }
763c243e490SMarcel Moolenaar     } else
764c243e490SMarcel Moolenaar         *b = true;
765c243e490SMarcel Moolenaar 
766c243e490SMarcel Moolenaar     return err;
767c243e490SMarcel Moolenaar }
768c243e490SMarcel Moolenaar 
769c243e490SMarcel Moolenaar atf_error_t
atf_fs_getcwd(atf_fs_path_t * p)770c243e490SMarcel Moolenaar atf_fs_getcwd(atf_fs_path_t *p)
771c243e490SMarcel Moolenaar {
772c243e490SMarcel Moolenaar     atf_error_t err;
773c243e490SMarcel Moolenaar     char *cwd;
774c243e490SMarcel Moolenaar 
775c243e490SMarcel Moolenaar #if defined(HAVE_GETCWD_DYN)
776c243e490SMarcel Moolenaar     cwd = getcwd(NULL, 0);
777c243e490SMarcel Moolenaar #else
778c243e490SMarcel Moolenaar     cwd = getcwd(NULL, MAXPATHLEN);
779c243e490SMarcel Moolenaar #endif
780c243e490SMarcel Moolenaar     if (cwd == NULL) {
781c243e490SMarcel Moolenaar         err = atf_libc_error(errno, "Cannot determine current directory");
782c243e490SMarcel Moolenaar         goto out;
783c243e490SMarcel Moolenaar     }
784c243e490SMarcel Moolenaar 
785c243e490SMarcel Moolenaar     err = atf_fs_path_init_fmt(p, "%s", cwd);
786c243e490SMarcel Moolenaar     free(cwd);
787c243e490SMarcel Moolenaar 
788c243e490SMarcel Moolenaar out:
789c243e490SMarcel Moolenaar     return err;
790c243e490SMarcel Moolenaar }
791c243e490SMarcel Moolenaar 
792c243e490SMarcel Moolenaar atf_error_t
atf_fs_mkdtemp(atf_fs_path_t * p)793c243e490SMarcel Moolenaar atf_fs_mkdtemp(atf_fs_path_t *p)
794c243e490SMarcel Moolenaar {
795c243e490SMarcel Moolenaar     atf_error_t err;
796c243e490SMarcel Moolenaar     char *buf;
797c243e490SMarcel Moolenaar 
798c243e490SMarcel Moolenaar     if (!check_umask(S_IRWXU, S_IRWXU)) {
799c243e490SMarcel Moolenaar         err = invalid_umask_error(p, atf_fs_stat_dir_type, current_umask());
800c243e490SMarcel Moolenaar         goto out;
801c243e490SMarcel Moolenaar     }
802c243e490SMarcel Moolenaar 
803c243e490SMarcel Moolenaar     err = copy_contents(p, &buf);
804c243e490SMarcel Moolenaar     if (atf_is_error(err))
805c243e490SMarcel Moolenaar         goto out;
806c243e490SMarcel Moolenaar 
807c243e490SMarcel Moolenaar     err = do_mkdtemp(buf);
808c243e490SMarcel Moolenaar     if (atf_is_error(err))
809c243e490SMarcel Moolenaar         goto out_buf;
810c243e490SMarcel Moolenaar 
811c243e490SMarcel Moolenaar     replace_contents(p, buf);
812c243e490SMarcel Moolenaar 
813c243e490SMarcel Moolenaar     INV(!atf_is_error(err));
814c243e490SMarcel Moolenaar out_buf:
815c243e490SMarcel Moolenaar     free(buf);
816c243e490SMarcel Moolenaar out:
817c243e490SMarcel Moolenaar     return err;
818c243e490SMarcel Moolenaar }
819c243e490SMarcel Moolenaar 
820c243e490SMarcel Moolenaar atf_error_t
atf_fs_mkstemp(atf_fs_path_t * p,int * fdout)821c243e490SMarcel Moolenaar atf_fs_mkstemp(atf_fs_path_t *p, int *fdout)
822c243e490SMarcel Moolenaar {
823c243e490SMarcel Moolenaar     atf_error_t err;
824c243e490SMarcel Moolenaar     char *buf;
825c243e490SMarcel Moolenaar     int fd;
826c243e490SMarcel Moolenaar 
827c243e490SMarcel Moolenaar     if (!check_umask(S_IRWXU, S_IRWXU)) {
828c243e490SMarcel Moolenaar         err = invalid_umask_error(p, atf_fs_stat_reg_type, current_umask());
829c243e490SMarcel Moolenaar         goto out;
830c243e490SMarcel Moolenaar     }
831c243e490SMarcel Moolenaar 
832c243e490SMarcel Moolenaar     err = copy_contents(p, &buf);
833c243e490SMarcel Moolenaar     if (atf_is_error(err))
834c243e490SMarcel Moolenaar         goto out;
835c243e490SMarcel Moolenaar 
836c243e490SMarcel Moolenaar     err = do_mkstemp(buf, &fd);
837c243e490SMarcel Moolenaar     if (atf_is_error(err))
838c243e490SMarcel Moolenaar         goto out_buf;
839c243e490SMarcel Moolenaar 
840c243e490SMarcel Moolenaar     replace_contents(p, buf);
841c243e490SMarcel Moolenaar     *fdout = fd;
842c243e490SMarcel Moolenaar 
843c243e490SMarcel Moolenaar     INV(!atf_is_error(err));
844c243e490SMarcel Moolenaar out_buf:
845c243e490SMarcel Moolenaar     free(buf);
846c243e490SMarcel Moolenaar out:
847c243e490SMarcel Moolenaar     return err;
848c243e490SMarcel Moolenaar }
849c243e490SMarcel Moolenaar 
850c243e490SMarcel Moolenaar atf_error_t
atf_fs_rmdir(const atf_fs_path_t * p)851c243e490SMarcel Moolenaar atf_fs_rmdir(const atf_fs_path_t *p)
852c243e490SMarcel Moolenaar {
853c243e490SMarcel Moolenaar     atf_error_t err;
854c243e490SMarcel Moolenaar 
855c243e490SMarcel Moolenaar     if (rmdir(atf_fs_path_cstring(p))) {
856c243e490SMarcel Moolenaar         if (errno == EEXIST) {
857c243e490SMarcel Moolenaar             /* Some operating systems (e.g. OpenSolaris 200906) return
858c243e490SMarcel Moolenaar              * EEXIST instead of ENOTEMPTY for non-empty directories.
859c243e490SMarcel Moolenaar              * Homogenize the return value so that callers don't need
860c243e490SMarcel Moolenaar              * to bother about differences in operating systems. */
861c243e490SMarcel Moolenaar             errno = ENOTEMPTY;
862c243e490SMarcel Moolenaar         }
863c243e490SMarcel Moolenaar         err = atf_libc_error(errno, "Cannot remove directory");
864c243e490SMarcel Moolenaar     } else
865c243e490SMarcel Moolenaar         err = atf_no_error();
866c243e490SMarcel Moolenaar 
867c243e490SMarcel Moolenaar     return err;
868c243e490SMarcel Moolenaar }
869c243e490SMarcel Moolenaar 
870c243e490SMarcel Moolenaar atf_error_t
atf_fs_unlink(const atf_fs_path_t * p)871c243e490SMarcel Moolenaar atf_fs_unlink(const atf_fs_path_t *p)
872c243e490SMarcel Moolenaar {
873c243e490SMarcel Moolenaar     atf_error_t err;
874c243e490SMarcel Moolenaar     const char *path;
875c243e490SMarcel Moolenaar 
876c243e490SMarcel Moolenaar     path = atf_fs_path_cstring(p);
877c243e490SMarcel Moolenaar 
878c243e490SMarcel Moolenaar     if (unlink(path) != 0)
879c243e490SMarcel Moolenaar         err = atf_libc_error(errno, "Cannot unlink file: '%s'", path);
880c243e490SMarcel Moolenaar     else
881c243e490SMarcel Moolenaar         err = atf_no_error();
882c243e490SMarcel Moolenaar 
883c243e490SMarcel Moolenaar     return err;
884c243e490SMarcel Moolenaar }
885