1942348b6af01e709a335fdce4c81cb62b70eba2
[psensor.git] / src / lib / pio.c
1 /*
2  * Copyright (C) 2010-2017 jeanfi@gmail.com
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301 USA
18  */
19 #define _LARGEFILE_SOURCE 1
20 #include "config.h"
21
22 #include <dirent.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/stat.h>
27
28 #include <plog.h>
29 #include <pio.h>
30
31 /* Directory separator is \ when cross-compiling for MS Windows
32  * systems
33  */
34 #if defined(__MINGW32__)
35 #define DIRSEP ('\\')
36 #else
37 #define DIRSEP '/'
38 #endif
39
40 #define FCOPY_BUF_SZ 4096
41
42 int is_dir(const char *path)
43 {
44         struct stat st;
45
46         int ret = lstat(path, &st);
47
48         if (ret == 0 && S_ISDIR(st.st_mode))
49                 return 1;
50
51         return 0;
52 }
53
54 int is_file(const char *path)
55 {
56         struct stat st;
57
58         int ret = lstat(path, &st);
59
60         if (ret == 0 && S_ISREG(st.st_mode))
61                 return 1;
62
63         return 0;
64 }
65
66 static char *dir_normalize(const char *dpath)
67 {
68         char *npath;
69         int n;
70
71         if (!dpath || !strlen(dpath))
72                 return NULL;
73
74         npath = strdup(dpath);
75
76         n = strlen(npath);
77
78         if (n > 1 && npath[n - 1] == '/')
79                 npath[n - 1] = '\0';
80
81         return npath;
82 }
83
84 static char **paths_add(char **paths, int n, char *path)
85 {
86         char **result;
87
88         result = malloc((n+1) * sizeof(void *));
89
90         memcpy(result + 1, paths, n * sizeof(void *));
91
92         *result = path;
93
94         return result;
95 }
96
97 char **dir_list(const char *dpath, int (*filter) (const char *))
98 {
99         struct dirent *ent;
100         DIR *dir;
101         char **paths, *path, *name, **tmp;
102         int n;
103
104         dir = opendir(dpath);
105
106         if (!dir)
107                 return NULL;
108
109         n = 1;
110         paths = malloc(sizeof(void *));
111         *paths = NULL;
112
113         while ((ent = readdir(dir)) != NULL) {
114                 name = ent->d_name;
115
116                 if (!strcmp(name, ".") || !strcmp(name, ".."))
117                         continue;
118
119                 path = path_append(dpath, name);
120
121                 if (!filter || filter(path)) {
122                         tmp = paths_add(paths, n, path);
123                         free(paths);
124                         paths = tmp;
125
126                         n++;
127                 } else {
128                         free(path);
129                 }
130         }
131
132         closedir(dir);
133
134         return paths;
135 }
136
137 void paths_free(char **paths)
138 {
139         char **paths_cur;
140
141         paths_cur = paths;
142         while (*paths_cur) {
143                 free(*paths_cur);
144
145                 paths_cur++;
146         }
147
148         free(paths);
149 }
150
151 char *file_get_content(const char *fpath)
152 {
153         long size, n;
154         char *page;
155
156         log_fct_enter();
157
158         size = file_get_size(fpath);
159
160         if (size == -1) {
161                 page = NULL;
162
163         } else if (size == 0) {
164                 page = malloc(1);
165                 *page = '\0';
166
167         } else {
168                 FILE *fp = fopen(fpath, "rb");
169
170                 if (fp) {
171                         page = malloc(size + 1);
172
173                         if (page) {
174                                 clearerr(fp);
175                                 n = fread(page, 1, size, fp);
176                                 if (n != size && ferror(fp)) {
177                                         free(page);
178                                         page = NULL;
179                                 } else {
180                                         *(page + n) = '\0';
181                                 }
182                         }
183
184                         fclose(fp);
185                 } else {
186                         log_debug("failed to open %s", fpath);
187                         page = NULL;
188                 }
189         }
190
191         log_fct_exit();
192
193         return page;
194 }
195
196 long file_get_size(const char *path)
197 {
198         FILE *fp;
199         long size;
200
201         if (!is_file(path))
202                 return -1;
203
204         fp = fopen(path, "rb");
205         if (fp) {
206                 if (fseek(fp, 0, SEEK_END) == -1)
207                         size = -1;
208                 else
209                         size = ftell(fp);
210
211                 fclose(fp);
212         } else {
213                 size = -1;
214         }
215
216         return size;
217 }
218
219 #define FCOPY_BUF_SZ 4096
220 static int FILE_copy(FILE *src, FILE *dst)
221 {
222         int ret = 0;
223         char *buf = malloc(FCOPY_BUF_SZ);
224         int n;
225
226         if (!buf)
227                 return FILE_COPY_ERROR_ALLOC_BUFFER;
228
229         while (!ret) {
230                 n = fread(buf, 1, FCOPY_BUF_SZ, src);
231                 if (n) {
232                         if (fwrite(buf, 1, n, dst) != n)
233                                 ret = FILE_COPY_ERROR_WRITE;
234                 } else {
235                         if (!feof(src))
236                                 ret = FILE_COPY_ERROR_READ;
237                         else
238                                 break;
239                 }
240         }
241
242         free(buf);
243
244         return ret;
245 }
246
247 int
248 file_copy(const char *src, const char *dst)
249 {
250         FILE *fsrc, *fdst;
251         int ret = 0;
252
253         log_fct("copy %s to %s", src, dst);
254
255         fsrc = fopen(src, "r");
256
257         if (fsrc) {
258                 fdst = fopen(dst, "w+");
259
260                 if (fdst) {
261                         ret = FILE_copy(fsrc, fdst);
262                         fclose(fdst);
263                 } else {
264                         ret = FILE_COPY_ERROR_OPEN_DST;
265                 }
266
267                 fclose(fsrc);
268         } else {
269                 ret = FILE_COPY_ERROR_OPEN_SRC;
270         }
271
272         return ret;
273 }
274
275 char *path_append(const char *dir, const char *path)
276 {
277         char *ret, *ndir;
278
279         ndir = dir_normalize(dir);
280
281         if (!ndir && (!path || !strlen(path)))
282                 ret = NULL;
283
284         else if (!ndir) {
285                 ret = strdup(path);
286
287         } else if (!path || !strlen(path)) {
288                 return ndir;
289
290         } else {
291                 ret = malloc(strlen(ndir) + 1 + strlen(path) + 1);
292                 strcpy(ret, ndir);
293                 strcat(ret, "/");
294                 strcat(ret, path);
295         }
296
297         free(ndir);
298
299         return ret;
300 }
301
302 void mkdirs(const char *dirs, mode_t mode)
303 {
304         char *c, *dir;
305         int i;
306
307         log_fct("mkdirs %s", dirs);
308
309         c = (char *)dirs;
310         dir = malloc(strlen(dirs) + 1);
311
312         i = 0;
313         while (*c) {
314                 if ((*c == DIRSEP || *c == '\0') && c != dirs) {
315                         strncpy(dir, dirs, i);
316                         dir[i] = '\0';
317                         mkdir(dir, mode);
318                 }
319
320                 c++;
321                 i++;
322         }
323
324         mkdir(dirs, mode);
325
326         free(dir);
327 }
328
329 void
330 file_copy_print_error(int code, const char *src, const char *dst)
331 {
332         switch (code) {
333         case 0:
334                 break;
335         case FILE_COPY_ERROR_OPEN_SRC:
336                 printf("File copy error: failed to open %s.\n", src);
337                 break;
338         case FILE_COPY_ERROR_OPEN_DST:
339                 printf("File copy error: failed to open %s.\n", dst);
340                 break;
341         case FILE_COPY_ERROR_READ:
342                 printf("File copy error: failed to read %s.\n", src);
343                 break;
344         case FILE_COPY_ERROR_WRITE:
345                 printf("File copy error: failed to write %s.\n", src);
346                 break;
347         case FILE_COPY_ERROR_ALLOC_BUFFER:
348                 printf("File copy error: failed to allocate buffer.\n");
349                 break;
350         default:
351                 printf("File copy error: unknown error %d.\n", code);
352         }
353 }