merged plib
[ppastats.git] / src / pio.c
1 /*
2     Copyright (C) 2010-2014 wpitchoune@gmail.com
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program 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
12     GNU 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
20 #include <dirent.h>
21 #include <fts.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27
28 #include <plog.h>
29 #include <pio.h>
30
31 /* Directory separator is \ when cross-compiling for MS Windows
32    systems */
33 #if defined(__MINGW32__)
34 #define DIRSEP ('\\')
35 #else
36 #define DIRSEP '/'
37 #endif
38
39 #define FCOPY_BUF_SZ 4096
40
41 int is_dir(const char *path)
42 {
43         struct stat st;
44
45         int ret = lstat(path, &st);
46
47         if (ret == 0 && S_ISDIR(st.st_mode))
48                 return 1;
49
50         return 0;
51 }
52
53 int is_file(const char *path)
54 {
55         struct stat st;
56
57         int ret = lstat(path, &st);
58
59         if (ret == 0 && S_ISREG(st.st_mode))
60                 return 1;
61
62         return 0;
63 }
64
65 char *dir_normalize(const char *dpath)
66 {
67         char *npath;
68         int n;
69
70         if (!dpath || !strlen(dpath))
71                 return NULL;
72
73         npath = strdup(dpath);
74
75         n = strlen(npath);
76
77         if (n > 1 && npath[n - 1] == '/')
78                 npath[n - 1] = '\0';
79
80         return npath;
81 }
82
83 char **dir_list(const char *dpath, int (*filter) (const char *path))
84 {
85         struct dirent *ent;
86         DIR *dir;
87         char **paths;
88         int n;
89
90         dir = opendir(dpath);
91
92         if (!dir)
93                 return NULL;
94
95         n = 1;
96         paths = malloc(sizeof(void *));
97         *paths = NULL;
98
99         while ((ent = readdir(dir)) != NULL) {
100                 char *fpath;
101                 char *name = ent->d_name;
102
103                 if (!strcmp(name, ".") || !strcmp(name, ".."))
104                         continue;
105
106                 fpath = malloc(strlen(dpath) + 1 + strlen(name) + 1);
107
108                 strcpy(fpath, dpath);
109                 strcat(fpath, "/");
110                 strcat(fpath, name);
111
112                 if (!filter || filter(fpath)) {
113                         char **npaths;
114
115                         n++;
116                         npaths = malloc(n * sizeof(void *));
117                         memcpy(npaths + 1, paths, (n - 1) * sizeof(void *));
118                         free(paths);
119                         paths = npaths;
120                         *npaths = fpath;
121
122                 } else {
123                         free(fpath);
124                 }
125         }
126
127         closedir(dir);
128
129         return paths;
130 }
131
132 void paths_free(char **paths)
133 {
134         char **paths_cur;
135
136         paths_cur = paths;
137         while (*paths_cur) {
138                 free(*paths_cur);
139
140                 paths_cur++;
141         }
142
143         free(paths);
144 }
145
146 char *file_get_content(const char *fpath)
147 {
148         long size;
149
150         char *page;
151
152         size = file_get_size(fpath);
153         if (size == -1) {
154                 page = NULL;
155
156         } else if (size == 0) {
157                 page = malloc(1);
158                 *page = '\0';
159
160         } else {
161                 FILE *fp = fopen(fpath, "rb");
162                 if (fp) {
163                         page = malloc(size + 1);
164                         if (!page || size != fread(page, 1, size, fp)) {
165                                 free(page);
166                                 return NULL;
167                         }
168
169                         *(page + size) = '\0';
170
171                         fclose(fp);
172                 } else {
173                         page = NULL;
174                 }
175         }
176
177         return page;
178 }
179
180 long file_get_size(const char *path)
181 {
182         FILE *fp;
183
184         if (!is_file(path))
185                 return -1;
186
187         fp = fopen(path, "rb");
188         if (fp) {
189                 long size;
190
191                 if (fseek(fp, 0, SEEK_END) == -1)
192                         return -1;
193
194                 size = ftell(fp);
195
196                 fclose(fp);
197
198                 return size;
199         }
200
201         return -1;
202 }
203
204 #define FCOPY_BUF_SZ 4096
205 static int FILE_copy(FILE *src, FILE *dst)
206 {
207         int ret = 0;
208         char *buf = malloc(FCOPY_BUF_SZ);
209         int n;
210
211         if (!buf)
212                 return FILE_COPY_ERROR_ALLOC_BUFFER;
213
214         while (!ret) {
215                 n = fread(buf, 1, FCOPY_BUF_SZ, src);
216                 if (n) {
217                         if (fwrite(buf, 1, n, dst) != n)
218                                 ret = FILE_COPY_ERROR_WRITE;
219                 } else {
220                         if (!feof(src))
221                                 ret = FILE_COPY_ERROR_READ;
222                         else
223                                 break;
224                 }
225         }
226
227         free(buf);
228
229         return ret;
230 }
231
232 int
233 file_copy(const char *src, const char *dst)
234 {
235         FILE *fsrc, *fdst;
236         int ret = 0;
237
238         log_fct("copy %s to %s", src, dst);
239
240         fsrc = fopen(src, "r");
241
242         if (fsrc) {
243                 fdst = fopen(dst, "w+");
244
245                 if (fdst) {
246                         ret = FILE_copy(fsrc, fdst);
247                         fclose(fdst);
248                 } else {
249                         ret = FILE_COPY_ERROR_OPEN_DST;
250                 }
251
252                 fclose(fsrc);
253         } else {
254                 ret = FILE_COPY_ERROR_OPEN_SRC;
255         }
256
257         return ret;
258 }
259
260 char *path_append(const char *dir, const char *path)
261 {
262         char *ret, *ndir;
263
264         ndir = dir_normalize(dir);
265
266         if (!ndir && (!path || !strlen(path)))
267                 ret = NULL;
268
269         else if (!ndir) {
270                 ret = strdup(path);
271
272         } else if (!path || !strlen(path)) {
273                 return ndir;
274
275         } else {
276                 ret = malloc(strlen(ndir) + 1 + strlen(path) + 1);
277                 strcpy(ret, ndir);
278                 strcat(ret, "/");
279                 strcat(ret, path);
280         }
281
282         free(ndir);
283
284         return ret;
285 }
286
287 void mkdirs(const char *dirs, mode_t mode)
288 {
289         char *c, *dir;
290         int i;
291
292         log_fct("mkdirs %s", dirs);
293
294         c = (char *)dirs;
295         dir = malloc(strlen(dirs) + 1);
296
297         i = 0;
298         while (*c) {
299                 if ((*c == DIRSEP || *c == '\0') && c != dirs) {
300                         strncpy(dir, dirs, i);
301                         dir[i] = '\0';
302                         mkdir(dir, mode);
303                 }
304
305                 c++;
306                 i++;
307         }
308
309         mkdir(dirs, mode);
310
311         free(dir);
312 }
313
314 void
315 file_copy_print_error(int code, const char *src, const char *dst)
316 {
317         switch (code) {
318         case 0:
319                 break;
320         case FILE_COPY_ERROR_OPEN_SRC:
321                 printf("File copy error: failed to open %s.\n", src);
322                 break;
323         case FILE_COPY_ERROR_OPEN_DST:
324                 printf("File copy error: failed to open %s.\n", dst);
325                 break;
326         case FILE_COPY_ERROR_READ:
327                 printf("File copy error: failed to read %s.\n", src);
328                 break;
329         case FILE_COPY_ERROR_WRITE:
330                 printf("File copy error: failed to write %s.\n", src);
331                 break;
332         case FILE_COPY_ERROR_ALLOC_BUFFER:
333                 printf("File copy error: failed to allocate buffer.\n");
334                 break;
335         default:
336                 printf("File copy error: unknown error %d.\n", code);
337         }
338 }
339
340 int dir_rcopy(const char *src, const char *dst)
341 {
342         int ret;
343         char **paths;
344         FTS *ftsp;
345         FTSENT *p, *chp;
346         int fts_options = FTS_COMFOLLOW | FTS_LOGICAL | FTS_NOCHDIR;
347         char *p_dst, *n_dst;
348
349         log_fct_enter();
350
351         log_fct("copy dir %s to %s", src, dst);
352
353         paths = malloc(2 * sizeof(char *));
354         paths[0] = strdup(src);
355         paths[1] = NULL;
356
357         ftsp = fts_open(paths, fts_options, NULL);
358         if (!ftsp)
359                 return 1;
360
361         chp = fts_children(ftsp, 0);
362         if (!chp)
363                 return 0;
364
365         n_dst = dir_normalize(dst);
366
367         while ((p = fts_read(ftsp)) != NULL) {
368                 switch (p->fts_info) {
369                 case FTS_D:
370                         p_dst = path_append(n_dst,
371                                             p->fts_path + strlen(src) + 1);
372                         mkdirs(p_dst, 0777);
373                         free(p_dst);
374                         break;
375                 case FTS_F:
376                         p_dst = path_append(n_dst,
377                                             p->fts_path + strlen(src) + 1);
378                         file_copy(p->fts_path, p_dst);
379                         free(p_dst);
380                         break;
381                 default:
382                         break;
383                 }
384         }
385         fts_close(ftsp);
386
387         free(n_dst);
388         free(paths);
389
390         ret = 0;
391
392         log_fct_exit();
393
394         return ret;
395 }