BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /**
2 * @file file.c
3 * @author Ambroz Bizjak <ambrop7@gmail.com>
4 *
5 * @section LICENSE
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the author nor the
15 * names of its contributors may be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * @section DESCRIPTION
30 *
31 * File I/O module.
32 *
33 * Synopsis:
34 * file_read(string filename)
35 *
36 * Variables:
37 * string (empty) - file contents
38 *
39 * Description:
40 * Reads the contents of a file. Reports an error if something goes wrong.
41 * WARNING: this uses fopen/fread/fclose, blocking the entire interpreter while
42 * the file is being read. For this reason, you should only use this
43 * to read small local files which will be read quickly, and especially
44 * not files on network mounts.
45 *
46 * Synopsis:
47 * file_write(string filename, string contents)
48 *
49 * Description:
50 * Writes a file, possibly overwriting an existing one. Reports an error if something
51 * goes wrong.
52 * WARNING: this is not an atomic operation; other programs may see the file in an
53 * inconsistent state while it is being written. Similarly, if writing
54 * fails, the file may remain in an inconsistent state indefinitely.
55 * If this is a problem, you should write the new contents to a temporary
56 * file and rename this temporary file to the live file.
57 * WARNING: this uses fopen/fwrite/fclose, blocking the entire interpreter while
58 * the file is being written. For this reason, you should only use this
59 * to write small local files which will be written quickly, and especially
60 * not files on network mounts.
61 *
62 * Synopsis:
63 * file_stat(string filename)
64 * file_lstat(string filename)
65 *
66 * Description:
67 * Retrieves information about a file.
68 * file_stat() follows symlinks; file_lstat() does not and allows retrieving information
69 * about a symlink.
70 * WARNING: this blocks the interpreter
71 *
72 * Variables:
73 * succeeded - whether the stat operation succeeded (true/false). If false, all other
74 * variables obtain the value "failed".
75 * type - file, dir, chr, blk, fifo, link, socket, other, failed
76 * size - size of the file, or failed
77 */
78  
79 #include <stdlib.h>
80 #include <string.h>
81 #include <stdint.h>
82 #include <sys/types.h>
83 #include <sys/stat.h>
84 #include <unistd.h>
85  
86 #include <misc/read_file.h>
87 #include <misc/write_file.h>
88 #include <misc/parse_number.h>
89  
90 #include <ncd/module_common.h>
91  
92 #include <generated/blog_channel_ncd_file.h>
93  
94 struct read_instance {
95 NCDModuleInst *i;
96 uint8_t *file_data;
97 size_t file_len;
98 };
99  
100 struct stat_instance {
101 NCDModuleInst *i;
102 int succeeded;
103 struct stat result;
104 };
105  
106 static void read_func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
107 {
108 struct read_instance *o = vo;
109 o->i = i;
110  
111 // read arguments
112 NCDValRef filename_arg;
113 if (!NCDVal_ListRead(params->args, 1, &filename_arg)) {
114 ModuleLog(i, BLOG_ERROR, "wrong arity");
115 goto fail0;
116 }
117 if (!NCDVal_IsStringNoNulls(filename_arg)) {
118 ModuleLog(i, BLOG_ERROR, "wrong type");
119 goto fail0;
120 }
121  
122 // get null terminated name
123 NCDValNullTermString filename_nts;
124 if (!NCDVal_StringNullTerminate(filename_arg, &filename_nts)) {
125 ModuleLog(i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
126 goto fail0;
127 }
128  
129 // read file
130 int res = read_file(filename_nts.data, &o->file_data, &o->file_len);
131 NCDValNullTermString_Free(&filename_nts);
132 if (!res) {
133 ModuleLog(i, BLOG_ERROR, "failed to read file");
134 goto fail0;
135 }
136  
137 // signal up
138 NCDModuleInst_Backend_Up(i);
139 return;
140  
141 fail0:
142 NCDModuleInst_Backend_DeadError(i);
143 }
144  
145 static void read_func_die (void *vo)
146 {
147 struct read_instance *o = vo;
148  
149 // free data
150 free(o->file_data);
151  
152 NCDModuleInst_Backend_Dead(o->i);
153 }
154  
155 static int read_func_getvar2 (void *vo, NCD_string_id_t name, NCDValMem *mem, NCDValRef *out)
156 {
157 struct read_instance *o = vo;
158  
159 if (name == NCD_STRING_EMPTY) {
160 *out = NCDVal_NewStringBin(mem, o->file_data, o->file_len);
161 return 1;
162 }
163  
164 return 0;
165 }
166  
167 static void write_func_new (void *unused, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
168 {
169 // read arguments
170 NCDValRef filename_arg;
171 NCDValRef contents_arg;
172 if (!NCDVal_ListRead(params->args, 2, &filename_arg, &contents_arg)) {
173 ModuleLog(i, BLOG_ERROR, "wrong arity");
174 goto fail0;
175 }
176 if (!NCDVal_IsStringNoNulls(filename_arg) || !NCDVal_IsString(contents_arg)) {
177 ModuleLog(i, BLOG_ERROR, "wrong type");
178 goto fail0;
179 }
180  
181 // get null terminated name
182 NCDValNullTermString filename_nts;
183 if (!NCDVal_StringNullTerminate(filename_arg, &filename_nts)) {
184 ModuleLog(i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
185 goto fail0;
186 }
187  
188 // write file
189 int res = write_file(filename_nts.data, NCDVal_StringMemRef(contents_arg));
190 NCDValNullTermString_Free(&filename_nts);
191 if (!res) {
192 ModuleLog(i, BLOG_ERROR, "failed to write file");
193 goto fail0;
194 }
195  
196 // signal up
197 NCDModuleInst_Backend_Up(i);
198 return;
199  
200 fail0:
201 NCDModuleInst_Backend_DeadError(i);
202 }
203  
204 static void stat_func_new_common (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params, int is_lstat)
205 {
206 struct stat_instance *o = vo;
207 o->i = i;
208  
209 NCDValRef filename_arg;
210 if (!NCDVal_ListRead(params->args, 1, &filename_arg)) {
211 ModuleLog(i, BLOG_ERROR, "wrong arity");
212 goto fail0;
213 }
214 if (!NCDVal_IsString(filename_arg)) {
215 ModuleLog(i, BLOG_ERROR, "wrong type");
216 goto fail0;
217 }
218  
219 o->succeeded = 0;
220  
221 if (!NCDVal_IsStringNoNulls(filename_arg)) {
222 goto out;
223 }
224  
225 // null terminate filename
226 NCDValNullTermString filename_nts;
227 if (!NCDVal_StringNullTerminate(filename_arg, &filename_nts)) {
228 ModuleLog(i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
229 goto fail0;
230 }
231  
232 int res;
233 if (is_lstat) {
234 res = lstat(filename_nts.data, &o->result);
235 } else {
236 res = stat(filename_nts.data, &o->result);
237 }
238 NCDValNullTermString_Free(&filename_nts);
239  
240 if (res < 0) {
241 goto out;
242 }
243  
244 o->succeeded = 1;
245  
246 out:
247 NCDModuleInst_Backend_Up(i);
248 return;
249  
250 fail0:
251 NCDModuleInst_Backend_DeadError(i);
252 }
253  
254 static void stat_func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
255 {
256 stat_func_new_common(vo, i, params, 0);
257 }
258  
259 static void lstat_func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
260 {
261 stat_func_new_common(vo, i, params, 1);
262 }
263  
264 static int stat_func_getvar2 (void *vo, NCD_string_id_t name, NCDValMem *mem, NCDValRef *out)
265 {
266 struct stat_instance *o = vo;
267  
268 if (name == NCD_STRING_SUCCEEDED) {
269 *out = ncd_make_boolean(mem, o->succeeded);
270 return 1;
271 }
272  
273 if (name == NCD_STRING_TYPE) {
274 const char *str;
275  
276 if (!o->succeeded) {
277 str = "failed";
278 } else if (S_ISREG(o->result.st_mode)) {
279 str = "file";
280 } else if (S_ISDIR(o->result.st_mode)) {
281 str = "dir";
282 } else if (S_ISCHR(o->result.st_mode)) {
283 str = "chr";
284 } else if (S_ISBLK(o->result.st_mode)) {
285 str = "blk";
286 } else if (S_ISFIFO(o->result.st_mode)) {
287 str = "fifo";
288 } else if (S_ISLNK(o->result.st_mode)) {
289 str = "link";
290 } else if (S_ISSOCK(o->result.st_mode)) {
291 str = "socket";
292 } else {
293 str = "other";
294 }
295  
296 *out = NCDVal_NewString(mem, str);
297 return 1;
298 }
299  
300 if (name == NCD_STRING_SIZE) {
301 char str[50];
302 if (!o->succeeded) {
303 strcpy(str, "failed");
304 } else {
305 generate_decimal_repr_string((uintmax_t)o->result.st_size, str);
306 }
307  
308 *out = NCDVal_NewString(mem, str);
309 return 1;
310 }
311  
312 return 0;
313 }
314  
315 static struct NCDModule modules[] = {
316 {
317 .type = "file_read",
318 .func_new2 = read_func_new,
319 .func_die = read_func_die,
320 .func_getvar2 = read_func_getvar2,
321 .alloc_size = sizeof(struct read_instance)
322 }, {
323 .type = "file_write",
324 .func_new2 = write_func_new
325 }, {
326 .type = "file_stat",
327 .func_new2 = stat_func_new,
328 .func_getvar2 = stat_func_getvar2,
329 .alloc_size = sizeof(struct stat_instance)
330 }, {
331 .type = "file_lstat",
332 .func_new2 = lstat_func_new,
333 .func_getvar2 = stat_func_getvar2,
334 .alloc_size = sizeof(struct stat_instance)
335 }, {
336 .type = NULL
337 }
338 };
339  
340 const struct NCDModuleGroup ncdmodule_file = {
341 .modules = modules
342 };