1 /*
2 * virfilewrapper.c: Wrapper for universal file access
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19 #include <config.h>
20
21 #ifndef WIN32
22
23 # include <fcntl.h>
24
25 # include "viralloc.h"
26 # include "virfile.h"
27 # include "virfilewrapper.h"
28 # include "virmock.h"
29 # include "virstring.h"
30
31
32 /* Mapping for prefix overrides */
33 static size_t noverrides;
34 static const char **overrides;
35
36 /* nprefixes == noverrides, but two variables make it easier to use
37 * VIR_*_ELEMENT macros */
38 static size_t nprefixes;
39 static const char **prefixes;
40
41 /* TODO: callbacks */
42 static int (*real_open)(const char *path, int flags, ...);
43 static FILE *(*real_fopen)(const char *path, const char *mode);
44 static int (*real_access)(const char *path, int mode);
45 static int (*real_mkdir)(const char *path, mode_t mode);
46 static DIR *(*real_opendir)(const char *path);
47 static int (*real_execv)(const char *path, char *const argv[]);
48 static int (*real_execve)(const char *path, char *const argv[], char *const envp[]);
49
init_syms(void)50 static void init_syms(void)
51 {
52 if (real_fopen)
53 return;
54
55 VIR_MOCK_REAL_INIT(fopen);
56 VIR_MOCK_REAL_INIT(access);
57 VIR_MOCK_REAL_INIT(mkdir);
58 VIR_MOCK_REAL_INIT(open);
59 # if defined(__APPLE__) && defined(__x86_64__)
60 VIR_MOCK_REAL_INIT_ALIASED(opendir, "opendir$INODE64");
61 # else
62 VIR_MOCK_REAL_INIT(opendir);
63 # endif
64 VIR_MOCK_REAL_INIT(execv);
65 VIR_MOCK_REAL_INIT(execve);
66 }
67
68
69 void
virFileWrapperAddPrefix(const char * prefix,const char * override)70 virFileWrapperAddPrefix(const char *prefix,
71 const char *override)
72 {
73 /* Both parameters are mandatory */
74 if (!prefix || !override) {
75 fprintf(stderr, "Attempt to add invalid path override\n");
76 abort();
77 }
78
79 init_syms();
80
81 VIR_APPEND_ELEMENT(prefixes, nprefixes, prefix);
82 VIR_APPEND_ELEMENT(overrides, noverrides, override);
83 }
84
85
86 void
virFileWrapperRemovePrefix(const char * prefix)87 virFileWrapperRemovePrefix(const char *prefix)
88 {
89 size_t i = 0;
90
91 for (i = 0; i < noverrides; i++) {
92 if (STREQ(prefixes[i], prefix))
93 break;
94 }
95
96 if (i == noverrides)
97 return;
98
99 VIR_DELETE_ELEMENT(overrides, i, noverrides);
100 VIR_DELETE_ELEMENT(prefixes, i, nprefixes);
101 }
102
103 void
virFileWrapperClearPrefixes(void)104 virFileWrapperClearPrefixes(void)
105 {
106 nprefixes = 0;
107 noverrides = 0;
108
109 VIR_FREE(prefixes);
110 VIR_FREE(overrides);
111 }
112
113 # include "virmockstathelpers.c"
114
115 int
virMockStatRedirect(const char * path,char ** newpath)116 virMockStatRedirect(const char *path, char **newpath)
117 {
118 size_t i = 0;
119
120 for (i = 0; i < noverrides; i++) {
121 const char *tmp = STRSKIP(path, prefixes[i]);
122
123 if (!tmp)
124 continue;
125
126 *newpath = g_strdup_printf("%s%s", overrides[i], tmp);
127 break;
128 }
129
130 return 0;
131 }
132
133
134 # define PATH_OVERRIDE(newpath, path) \
135 do { \
136 init_syms(); \
137 \
138 if (virMockStatRedirect(path, &newpath) < 0) \
139 abort(); \
140 } while (0)
141
142
fopen(const char * path,const char * mode)143 FILE *fopen(const char *path, const char *mode)
144 {
145 g_autofree char *newpath = NULL;
146
147 PATH_OVERRIDE(newpath, path);
148
149 return real_fopen(newpath ? newpath : path, mode);
150 }
151
access(const char * path,int mode)152 int access(const char *path, int mode)
153 {
154 g_autofree char *newpath = NULL;
155
156 PATH_OVERRIDE(newpath, path);
157
158 return real_access(newpath ? newpath : path, mode);
159 }
160
open(const char * path,int flags,...)161 int open(const char *path, int flags, ...)
162 {
163 g_autofree char *newpath = NULL;
164 va_list ap;
165 mode_t mode = 0;
166
167 PATH_OVERRIDE(newpath, path);
168
169 /* The mode argument is mandatory when O_CREAT is set in flags,
170 * otherwise the argument is ignored.
171 */
172 if (flags & O_CREAT) {
173 va_start(ap, flags);
174 mode = (mode_t) va_arg(ap, int);
175 va_end(ap);
176 }
177
178 return real_open(newpath ? newpath : path, flags, mode);
179 }
180
opendir(const char * path)181 DIR *opendir(const char *path)
182 {
183 g_autofree char *newpath = NULL;
184
185 PATH_OVERRIDE(newpath, path);
186
187 return real_opendir(newpath ? newpath : path);
188 }
189
execv(const char * path,char * const argv[])190 int execv(const char *path, char *const argv[])
191 {
192 g_autofree char *newpath = NULL;
193
194 PATH_OVERRIDE(newpath, path);
195
196 return real_execv(newpath ? newpath : path, argv);
197 }
198
execve(const char * path,char * const argv[],char * const envp[])199 int execve(const char *path, char *const argv[], char *const envp[])
200 {
201 g_autofree char *newpath = NULL;
202
203 PATH_OVERRIDE(newpath, path);
204
205 return real_execve(newpath ? newpath : path, argv, envp);
206 }
207
208 #endif
209