file_util.c 7.8 KB

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