35202a53500525105ac8757dae6e4e947f528a84
[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 <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26
27 #include <pio.h>
28
29
30 /* Directory separator is \ when cross-compiling for MS Windows
31    systems */
32 #if defined(__MINGW32__)
33 #define DIRSEP ('\\')
34 #else
35 #define DIRSEP '/'
36 #endif
37
38 #define FCOPY_BUF_SZ 4096
39
40 int is_dir(const char *path)
41 {
42         struct stat st;
43
44         int ret = lstat(path, &st);
45
46         if (ret == 0 && S_ISDIR(st.st_mode))
47                 return 1;
48
49         return 0;
50 }
51
52 int is_file(const char *path)
53 {
54         struct stat st;
55
56         int ret = lstat(path, &st);
57
58         if (ret == 0 && S_ISREG(st.st_mode))
59                 return 1;
60
61         return 0;
62 }
63
64 char *dir_normalize(const char *dpath)
65 {
66         char *npath;
67         int n;
68
69         if (!dpath || !strlen(dpath))
70                 return NULL;
71
72         npath = strdup(dpath);
73
74         n = strlen(npath);
75
76         if (n > 1 && npath[n - 1] == '/')
77                 npath[n - 1] = '\0';
78
79         return npath;
80 }
81
82 char **dir_list(const char *dpath, int (*filter) (const char *path))
83 {
84         struct dirent *ent;
85         DIR *dir;
86         char **paths;
87         int n;
88
89         dir = opendir(dpath);
90
91         if (!dir)
92                 return NULL;
93
94         n = 1;
95         paths = malloc(sizeof(void *));
96         *paths = NULL;
97
98         while ((ent = readdir(dir)) != NULL) {
99                 char *fpath;
100                 char *name = ent->d_name;
101
102                 if (!strcmp(name, ".") || !strcmp(name, ".."))
103                         continue;
104
105                 fpath = malloc(strlen(dpath) + 1 + strlen(name) + 1);
106
107                 strcpy(fpath, dpath);
108                 strcat(fpath, "/");
109                 strcat(fpath, name);
110
111                 if (!filter || filter(fpath)) {
112                         char **npaths;
113
114                         n++;
115                         npaths = malloc(n * sizeof(void *));
116                         memcpy(npaths + 1, paths, (n - 1) * sizeof(void *));
117                         free(paths);
118                         paths = npaths;
119                         *npaths = fpath;
120
121                 } else {
122                         free(fpath);
123                 }
124         }
125
126         closedir(dir);
127
128         return paths;
129 }
130
131 void paths_free(char **paths)
132 {
133         char **paths_cur;
134
135         paths_cur = paths;
136         while (*paths_cur) {
137                 free(*paths_cur);
138
139                 paths_cur++;
140         }
141
142         free(paths);
143 }
144
145 char *file_get_content(const char *fpath)
146 {
147         long size;
148
149         char *page;
150
151         size = file_get_size(fpath);
152         if (size == -1) {
153                 page = NULL;
154
155         } else if (size == 0) {
156                 page = malloc(1);
157                 *page = '\0';
158
159         } else {
160                 FILE *fp = fopen(fpath, "rb");
161                 if (fp) {
162                         page = malloc(size + 1);
163                         if (!page || size != fread(page, 1, size, fp)) {
164                                 free(page);
165                                 return NULL;
166                         }
167
168                         *(page + size) = '\0';
169
170                         fclose(fp);
171                 } else {
172                         page = NULL;
173                 }
174         }
175
176         return page;
177 }
178
179 long file_get_size(const char *path)
180 {
181         FILE *fp;
182
183         if (!is_file(path))
184                 return -1;
185
186         fp = fopen(path, "rb");
187         if (fp) {
188                 long size;
189
190                 if (fseek(fp, 0, SEEK_END) == -1)
191                         return -1;
192
193                 size = ftell(fp);
194
195                 fclose(fp);
196
197                 return size;
198         }
199
200         return -1;
201 }
202
203 #define FCOPY_BUF_SZ 4096
204 static int FILE_copy(FILE *src, FILE *dst)
205 {
206         int ret = 0;
207         char *buf = malloc(FCOPY_BUF_SZ);
208         int n;
209
210         if (!buf)
211                 return FILE_COPY_ERROR_ALLOC_BUFFER;
212
213         while (!ret) {
214                 n = fread(buf, 1, FCOPY_BUF_SZ, src);
215                 if (n) {
216                         if (fwrite(buf, 1, n, dst) != n)
217                                 ret = FILE_COPY_ERROR_WRITE;
218                 } else {
219                         if (!feof(src))
220                                 ret = FILE_COPY_ERROR_READ;
221                         else
222                                 break;
223                 }
224         }
225
226         free(buf);
227
228         return ret;
229 }
230
231 int
232 file_copy(const char *src, const char *dst)
233 {
234         FILE *fsrc, *fdst;
235         int ret = 0;
236
237         fsrc = fopen(src, "r");
238
239         if (fsrc) {
240                 fdst = fopen(dst, "w+");
241
242                 if (fdst) {
243                         ret = FILE_copy(fsrc, fdst);
244                         fclose(fdst);
245                 } else {
246                         ret = FILE_COPY_ERROR_OPEN_DST;
247                 }
248
249                 fclose(fsrc);
250         } else {
251                 ret = FILE_COPY_ERROR_OPEN_SRC;
252         }
253
254         return ret;
255 }
256
257 char *path_append(const char *dir, const char *path)
258 {
259         char *ret, *ndir;
260
261         ndir = dir_normalize(dir);
262
263         if (!ndir && (!path || !strlen(path)))
264                 ret = NULL;
265
266         else if (!ndir) {
267                 ret = strdup(path);
268
269         } else if (!path || !strlen(path)) {
270                 return ndir;
271
272         } else {
273                 ret = malloc(strlen(ndir) + 1 + strlen(path) + 1);
274                 strcpy(ret, ndir);
275                 strcat(ret, "/");
276                 strcat(ret, path);
277         }
278
279         free(ndir);
280
281         return ret;
282 }
283
284 void mkdirs(const char *dirs, mode_t mode)
285 {
286         char *c = (char *)dirs;
287         char *dir = malloc(strlen(dirs) + 1);
288
289         int i = 0;
290         while (*c) {
291                 if ((*c == DIRSEP || *c == '\0') && c != dirs) {
292                         strncpy(dir, dirs, i);
293                         dir[i] = '\0';
294                         mkdir(dir, mode);
295                 }
296
297                 c++;
298                 i++;
299         }
300
301         mkdir(dirs, mode);
302
303         free(dir);
304 }
305
306 void
307 file_copy_print_error(int code, const char *src, const char *dst)
308 {
309         switch (code) {
310         case 0:
311                 break;
312         case FILE_COPY_ERROR_OPEN_SRC:
313                 printf("File copy error: failed to open %s.\n", src);
314                 break;
315         case FILE_COPY_ERROR_OPEN_DST:
316                 printf("File copy error: failed to open %s.\n", dst);
317                 break;
318         case FILE_COPY_ERROR_READ:
319                 printf("File copy error: failed to read %s.\n", src);
320                 break;
321         case FILE_COPY_ERROR_WRITE:
322                 printf("File copy error: failed to write %s.\n", src);
323                 break;
324         case FILE_COPY_ERROR_ALLOC_BUFFER:
325                 printf("File copy error: failed to allocate buffer.\n");
326                 break;
327         default:
328                 printf("File copy error: unknown error %d.\n", code);
329         }
330 }