A tool for adding anime to your anidb list.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

126 lines
3.1KB

  1. #define _XOPEN_SOURCE 500
  2. #include <sys/stat.h>
  3. #include <string.h>
  4. #include <errno.h>
  5. #include <ftw.h>
  6. #include <assert.h>
  7. #include "ed2k.h"
  8. #include "ed2k_util.h"
  9. #include "uio.h"
  10. #include "globals.h"
  11. static struct ed2k_util_opts l_opts;
  12. static enum error ed2k_util_hash(const char *file_path, blksize_t blksize,
  13. const struct stat *st)
  14. {
  15. unsigned char buf[blksize], hash[ED2K_HASH_SIZE];
  16. struct ed2k_ctx ed2k;
  17. enum error err;
  18. FILE *f;
  19. size_t read_len;
  20. int en;
  21. if (l_opts.pre_hash_fn) {
  22. err = l_opts.pre_hash_fn(file_path, st, l_opts.data);
  23. if (err == ED2KUTIL_DONTHASH)
  24. return NOERR;
  25. else if (err != NOERR)
  26. return err;
  27. }
  28. f = fopen(file_path, "rb");
  29. if (!f) {
  30. en = errno;
  31. uio_error("Failed to open file: %s (%s)", file_path, strerror(en));
  32. if (en == EINTR && should_exit)
  33. return ERR_SHOULD_EXIT;
  34. else
  35. return ERR_ED2KUTIL_FS;
  36. }
  37. ed2k_init(&ed2k);
  38. read_len = fread(buf, 1, sizeof(buf), f);
  39. /* From my test, fread wont return anything special on signal interrupt */
  40. while (read_len > 0 && !should_exit) {
  41. ed2k_update(&ed2k, buf, read_len);
  42. read_len = fread(buf, 1, sizeof(buf), f);
  43. }
  44. if (should_exit) {
  45. err = ERR_SHOULD_EXIT;
  46. goto fail;
  47. }
  48. if (ferror(f)) { /* Loop stopped bcuz of error, not EOF */
  49. uio_error("Failure while reading file");
  50. err = ERR_ED2KUTIL_FS;
  51. goto fail;
  52. }
  53. assert(feof(f));
  54. ed2k_final(&ed2k, hash);
  55. if (fclose(f) != 0) {
  56. en = errno;
  57. uio_debug("Fclose failed: %s", strerror(en));
  58. if (en == EINTR && should_exit)
  59. return ERR_SHOULD_EXIT;
  60. else
  61. return ERR_ED2KUTIL_FS;
  62. }
  63. if (l_opts.post_hash_fn)
  64. return l_opts.post_hash_fn(file_path, hash, st, l_opts.data);
  65. return NOERR;
  66. fail:
  67. if (f) /* We can't get a 2nd interrupt now */
  68. fclose(f);
  69. return err;
  70. }
  71. static int ed2k_util_walk(const char *fpath, const struct stat *sb,
  72. int typeflag, struct FTW *ftwbuf)
  73. {
  74. if (typeflag == FTW_DNR) {
  75. uio_error("Cannot read directory '%s'. Skipping", fpath);
  76. return NOERR;
  77. }
  78. if (typeflag == FTW_D)
  79. return NOERR;
  80. if (typeflag != FTW_F) {
  81. uio_error("Unhandled error '%d'", typeflag);
  82. return ERR_ED2KUTIL_UNSUP;
  83. }
  84. return ed2k_util_hash(fpath, sb->st_blksize, sb);
  85. }
  86. enum error ed2k_util_iterpath(const char *path, const struct ed2k_util_opts *opts)
  87. {
  88. struct stat ts;
  89. if (stat(path, &ts) != 0) {
  90. uio_error("Stat failed for path: '%s' (%s)",
  91. path, strerror(errno));
  92. return ERR_ED2KUTIL_FS;
  93. }
  94. l_opts = *opts;
  95. if (S_ISREG(ts.st_mode)) {
  96. return ed2k_util_hash(path, ts.st_blksize, &ts);
  97. } else if (S_ISDIR(ts.st_mode)) {
  98. int ftwret = nftw(path, ed2k_util_walk, 20, 0);
  99. if (ftwret == -1) {
  100. uio_error("nftw failure");
  101. return ERR_ED2KUTIL_FS;
  102. }
  103. return ftwret;
  104. }
  105. uio_error("Unsupported file type: %d", ts.st_mode & S_IFMT);
  106. return ERR_ED2KUTIL_UNSUP;
  107. }