file_util.c cleanups. Remove redundant str_chomp from str_util.c.
[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
70         buf[0] = '\0';
71
72         while (fgets(buf, BUFSIZ, fp)) {
73                 buf_len = strlen(buf);
74                 if (line) {
75                         line_size += buf_len;
76                         line = xrealloc(line, line_size+1);
77                         strncat(line, buf, line_size);
78                 } else {
79                         line_size = buf_len + 1;
80                         line = xstrdup(buf);
81                 }
82                 if (buf[buf_len - 1] == '\n') {
83                         buf[buf_len -1] = '\0';
84                         break;
85                 }
86         }
87
88         return line;
89 }
90
91 int
92 file_move(const char *src, const char *dest)
93 {
94         int err;
95
96         err = rename(src, dest);
97         if (err == -1) {
98                 if (errno == EXDEV) {
99                         /* src & dest live on different file systems */
100                         err = file_copy(src, dest);
101                         if (err == 0)
102                                 unlink(src);
103                 } else {
104                         fprintf(stderr, "%s: rename(%s, %s): %s\n",
105                                 __FUNCTION__, src, dest, strerror(errno));
106                 }
107         }
108
109         return err;
110 }
111
112 int
113 file_copy(const char *src, const char *dest)
114 {
115         int err;
116
117         err = copy_file(src, dest, FILEUTILS_FORCE | FILEUTILS_PRESERVE_STATUS);
118         if (err)
119                 fprintf(stderr, "%s: copy_file(%s, %s)\n",
120                                 __FUNCTION__, src, dest);
121
122         return err;
123 }
124
125 int
126 file_mkdir_hier(const char *path, long mode)
127 {
128         return make_directory(path, mode, FILEUTILS_RECUR);
129 }
130
131 char *file_md5sum_alloc(const char *file_name)
132 {
133     static const int md5sum_bin_len = 16;
134     static const int md5sum_hex_len = 32;
135
136     static const unsigned char bin2hex[16] = {
137         '0', '1', '2', '3',
138         '4', '5', '6', '7',
139         '8', '9', 'a', 'b',
140         'c', 'd', 'e', 'f'
141     };
142
143     int i, err;
144     FILE *file;
145     char *md5sum_hex;
146     unsigned char md5sum_bin[md5sum_bin_len];
147
148     md5sum_hex = xcalloc(1, md5sum_hex_len + 1);
149
150     file = fopen(file_name, "r");
151     if (file == NULL) {
152         fprintf(stderr, "%s: Failed to open file %s: %s\n",
153                 __FUNCTION__, file_name, strerror(errno));
154         free(md5sum_hex);
155         return NULL;
156     }
157
158     err = md5_stream(file, md5sum_bin);
159     if (err) {
160         fprintf(stderr, "%s: ERROR computing md5sum for %s: %s\n",
161                 __FUNCTION__, file_name, strerror(err));
162         fclose(file);
163         free(md5sum_hex);
164         return NULL;
165     }
166
167     fclose(file);
168
169     for (i=0; i < md5sum_bin_len; i++) {
170         md5sum_hex[i*2] = bin2hex[md5sum_bin[i] >> 4];
171         md5sum_hex[i*2+1] = bin2hex[md5sum_bin[i] & 0xf];
172     }
173     
174     md5sum_hex[md5sum_hex_len] = '\0';
175     
176     return md5sum_hex;
177 }
178
179 #ifdef HAVE_SHA256
180 char *file_sha256sum_alloc(const char *file_name)
181 {
182     static const int sha256sum_bin_len = 32;
183     static const int sha256sum_hex_len = 64;
184
185     static const unsigned char bin2hex[16] = {
186         '0', '1', '2', '3',
187         '4', '5', '6', '7',
188         '8', '9', 'a', 'b',
189         'c', 'd', 'e', 'f'
190     };
191
192     int i, err;
193     FILE *file;
194     char *sha256sum_hex;
195     unsigned char sha256sum_bin[sha256sum_bin_len];
196
197     sha256sum_hex = xcalloc(1, sha256sum_hex_len + 1);
198
199     file = fopen(file_name, "r");
200     if (file == NULL) {
201         fprintf(stderr, "%s: Failed to open file %s: %s\n",
202                 __FUNCTION__, file_name, strerror(errno));
203         free(sha256sum_hex);
204         return NULL;
205     }
206
207     err = sha256_stream(file, sha256sum_bin);
208     if (err) {
209         fprintf(stderr, "%s: ERROR computing sha256sum for %s: %s\n",
210                 __FUNCTION__, file_name, strerror(err));
211         fclose(file);
212         free(sha256sum_hex);
213         return NULL;
214     }
215
216     fclose(file);
217
218     for (i=0; i < sha256sum_bin_len; i++) {
219         sha256sum_hex[i*2] = bin2hex[sha256sum_bin[i] >> 4];
220         sha256sum_hex[i*2+1] = bin2hex[sha256sum_bin[i] & 0xf];
221     }
222     
223     sha256sum_hex[sha256sum_hex_len] = '\0';
224     
225     return sha256sum_hex;
226 }
227
228 #endif
229
230
231 int
232 rm_r(const char *path)
233 {
234         int ret = 0;
235         DIR *dir;
236         struct dirent *dent;
237
238         dir = opendir(path);
239         if (dir == NULL) {
240                 perror_msg("%s: opendir(%s)", __FUNCTION__, path);
241                 return -1;
242         }
243
244         if (fchdir(dirfd(dir)) == -1) {
245                 perror_msg("%s: fchdir(%s)", __FUNCTION__, path);
246                 closedir(dir);
247                 return -1;
248         }
249
250         while (1) {
251                 errno = 0;
252                 if ((dent = readdir(dir)) == NULL) {
253                         if (errno) {
254                                 perror_msg("%s: readdir(%s)",
255                                                 __FUNCTION__, path);
256                                 ret = -1;
257                         }
258                         break;
259                 }
260
261                 if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
262                         continue;
263
264 #ifdef _BSD_SOURCE
265                 if (dent->d_type == DT_DIR) {
266                         if ((ret = rm_r(dent->d_name)) == -1)
267                                 break;
268                         continue;
269                 } else if (dent->d_type == DT_UNKNOWN)
270 #endif
271                 {
272                         struct stat st;
273                         if ((ret = lstat(dent->d_name, &st)) == -1) {
274                                 perror_msg("%s: lstat(%s)",
275                                                 __FUNCTION__, dent->d_name);
276                                 break;
277                         }
278                         if (S_ISDIR(st.st_mode)) {
279                                 if ((ret = rm_r(dent->d_name)) == -1)
280                                         break;
281                                 continue;
282                         }
283                 }
284
285                 if ((ret = unlink(dent->d_name)) == -1) {
286                         perror_msg("%s: unlink(%s)",
287                                         __FUNCTION__, dent->d_name);
288                         break;
289                 }
290         }
291
292         if (chdir("..") == -1) {
293                 ret = -1;
294                 perror_msg("%s: chdir(%s/..)", __FUNCTION__, path);
295         }
296
297         if (rmdir(path) == -1 ) {
298                 ret = -1;
299                 perror_msg("%s: rmdir(%s)", __FUNCTION__, path);
300         }
301
302         if (closedir(dir) == -1) {
303                 ret = -1;
304                 perror_msg("%s: closedir(%s)", __FUNCTION__, path);
305         }
306
307         return ret;
308 }