e6259848edf7b98c7a1551d21ec5fa869de8c2b6
[oweals/opkg-lede.git] / libopkg / file_util.c
1 /* file_util.c - convenience routines for common stat operations
2
3    Carl D. Worth
4
5    Copyright (C) 2001 University of Southern California
6
7    This program is free software; you can redistribute it and/or
8    modify it under the terms of the GNU General Public License as
9    published by the Free Software Foundation; either version 2, or (at
10    your option) any later version.
11
12    This program is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    General Public License for more details.
16 */
17
18 #include "includes.h"
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <dirent.h>
22
23 #include "sprintf_alloc.h"
24 #include "file_util.h"
25 #include "md5.h"
26 #include "libbb/libbb.h"
27 #undef strlen
28
29 #if defined HAVE_SHA256
30 #include "sha256.h"
31 #endif
32
33 int
34 file_exists(const char *file_name)
35 {
36         struct stat st;
37
38         if (stat(file_name, &st) == -1)
39                 return 0;
40
41         return 1;
42 }
43
44 int
45 file_is_dir(const char *file_name)
46 {
47         struct stat st;
48
49         if (stat(file_name, &st) == -1)
50                 return 0;
51
52         return S_ISDIR(st.st_mode);
53 }
54
55 /* read a single line from a file, stopping at a newline or EOF.
56    If a newline is read, it will appear in the resulting string.
57    Return value is a malloc'ed char * which should be freed at
58    some point by the caller.
59
60    Return value is NULL if the file is at EOF when called.
61 */
62 char *
63 file_read_line_alloc(FILE *fp)
64 {
65         char buf[BUFSIZ];
66         int buf_len;
67         char *line = NULL;
68         int line_size = 0;
69         int got_nl = 0;
70
71         buf[0] = '\0';
72
73         while (fgets(buf, BUFSIZ, fp)) {
74                 buf_len = strlen(buf);
75                 if (buf[buf_len - 1] == '\n') {
76                         buf_len--;
77                         buf[buf_len] = '\0';
78                         got_nl = 1;
79                 }
80                 if (line) {
81                         line_size += buf_len;
82                         line = xrealloc(line, line_size+1);
83                         strncat(line, buf, line_size);
84                 } else {
85                         line_size = buf_len + 1;
86                         line = xstrdup(buf);
87                 }
88                 if (got_nl)
89                         break;
90         }
91
92         return line;
93 }
94
95 int
96 file_move(const char *src, const char *dest)
97 {
98         int err;
99
100         err = rename(src, dest);
101         if (err == -1) {
102                 if (errno == EXDEV) {
103                         /* src & dest live on different file systems */
104                         err = file_copy(src, dest);
105                         if (err == 0)
106                                 unlink(src);
107                 } else {
108                         fprintf(stderr, "%s: rename(%s, %s): %s\n",
109                                 __FUNCTION__, src, dest, strerror(errno));
110                 }
111         }
112
113         return err;
114 }
115
116 int
117 file_copy(const char *src, const char *dest)
118 {
119         int err;
120
121         err = copy_file(src, dest, FILEUTILS_FORCE | FILEUTILS_PRESERVE_STATUS);
122         if (err)
123                 fprintf(stderr, "%s: copy_file(%s, %s)\n",
124                                 __FUNCTION__, src, dest);
125
126         return err;
127 }
128
129 int
130 file_mkdir_hier(const char *path, long mode)
131 {
132         return make_directory(path, mode, FILEUTILS_RECUR);
133 }
134
135 char *file_md5sum_alloc(const char *file_name)
136 {
137     static const int md5sum_bin_len = 16;
138     static const int md5sum_hex_len = 32;
139
140     static const unsigned char bin2hex[16] = {
141         '0', '1', '2', '3',
142         '4', '5', '6', '7',
143         '8', '9', 'a', 'b',
144         'c', 'd', 'e', 'f'
145     };
146
147     int i, err;
148     FILE *file;
149     char *md5sum_hex;
150     unsigned char md5sum_bin[md5sum_bin_len];
151
152     md5sum_hex = xcalloc(1, md5sum_hex_len + 1);
153
154     file = fopen(file_name, "r");
155     if (file == NULL) {
156         fprintf(stderr, "%s: Failed to open file %s: %s\n",
157                 __FUNCTION__, file_name, strerror(errno));
158         free(md5sum_hex);
159         return NULL;
160     }
161
162     err = md5_stream(file, md5sum_bin);
163     if (err) {
164         fprintf(stderr, "%s: ERROR computing md5sum for %s: %s\n",
165                 __FUNCTION__, file_name, strerror(err));
166         fclose(file);
167         free(md5sum_hex);
168         return NULL;
169     }
170
171     fclose(file);
172
173     for (i=0; i < md5sum_bin_len; i++) {
174         md5sum_hex[i*2] = bin2hex[md5sum_bin[i] >> 4];
175         md5sum_hex[i*2+1] = bin2hex[md5sum_bin[i] & 0xf];
176     }
177     
178     md5sum_hex[md5sum_hex_len] = '\0';
179     
180     return md5sum_hex;
181 }
182
183 #ifdef HAVE_SHA256
184 char *file_sha256sum_alloc(const char *file_name)
185 {
186     static const int sha256sum_bin_len = 32;
187     static const int sha256sum_hex_len = 64;
188
189     static const unsigned char bin2hex[16] = {
190         '0', '1', '2', '3',
191         '4', '5', '6', '7',
192         '8', '9', 'a', 'b',
193         'c', 'd', 'e', 'f'
194     };
195
196     int i, err;
197     FILE *file;
198     char *sha256sum_hex;
199     unsigned char sha256sum_bin[sha256sum_bin_len];
200
201     sha256sum_hex = xcalloc(1, sha256sum_hex_len + 1);
202
203     file = fopen(file_name, "r");
204     if (file == NULL) {
205         fprintf(stderr, "%s: Failed to open file %s: %s\n",
206                 __FUNCTION__, file_name, strerror(errno));
207         free(sha256sum_hex);
208         return NULL;
209     }
210
211     err = sha256_stream(file, sha256sum_bin);
212     if (err) {
213         fprintf(stderr, "%s: ERROR computing sha256sum for %s: %s\n",
214                 __FUNCTION__, file_name, strerror(err));
215         fclose(file);
216         free(sha256sum_hex);
217         return NULL;
218     }
219
220     fclose(file);
221
222     for (i=0; i < sha256sum_bin_len; i++) {
223         sha256sum_hex[i*2] = bin2hex[sha256sum_bin[i] >> 4];
224         sha256sum_hex[i*2+1] = bin2hex[sha256sum_bin[i] & 0xf];
225     }
226     
227     sha256sum_hex[sha256sum_hex_len] = '\0';
228     
229     return sha256sum_hex;
230 }
231
232 #endif
233
234
235 int
236 rm_r(const char *path)
237 {
238         int ret = 0;
239         DIR *dir;
240         struct dirent *dent;
241
242         dir = opendir(path);
243         if (dir == NULL) {
244                 perror_msg("%s: opendir(%s)", __FUNCTION__, path);
245                 return -1;
246         }
247
248         if (fchdir(dirfd(dir)) == -1) {
249                 perror_msg("%s: fchdir(%s)", __FUNCTION__, path);
250                 closedir(dir);
251                 return -1;
252         }
253
254         while (1) {
255                 errno = 0;
256                 if ((dent = readdir(dir)) == NULL) {
257                         if (errno) {
258                                 perror_msg("%s: readdir(%s)",
259                                                 __FUNCTION__, path);
260                                 ret = -1;
261                         }
262                         break;
263                 }
264
265                 if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
266                         continue;
267
268 #ifdef _BSD_SOURCE
269                 if (dent->d_type == DT_DIR) {
270                         if ((ret = rm_r(dent->d_name)) == -1)
271                                 break;
272                         continue;
273                 } else if (dent->d_type == DT_UNKNOWN)
274 #endif
275                 {
276                         struct stat st;
277                         if ((ret = lstat(dent->d_name, &st)) == -1) {
278                                 perror_msg("%s: lstat(%s)",
279                                                 __FUNCTION__, dent->d_name);
280                                 break;
281                         }
282                         if (S_ISDIR(st.st_mode)) {
283                                 if ((ret = rm_r(dent->d_name)) == -1)
284                                         break;
285                                 continue;
286                         }
287                 }
288
289                 if ((ret = unlink(dent->d_name)) == -1) {
290                         perror_msg("%s: unlink(%s)",
291                                         __FUNCTION__, dent->d_name);
292                         break;
293                 }
294         }
295
296         if (chdir("..") == -1) {
297                 ret = -1;
298                 perror_msg("%s: chdir(%s/..)", __FUNCTION__, path);
299         }
300
301         if (rmdir(path) == -1 ) {
302                 ret = -1;
303                 perror_msg("%s: rmdir(%s)", __FUNCTION__, path);
304         }
305
306         if (closedir(dir) == -1) {
307                 ret = -1;
308                 perror_msg("%s: closedir(%s)", __FUNCTION__, path);
309         }
310
311         return ret;
312 }