untar.c 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. // This file is Copyright (C) 2024 Victor Suarez Rovere <suarezvictor@gmail.com>
  2. // SPDX-License-Identifier: AGPL-3.0-only
  3. #include <stdio.h>
  4. #define BLOCKSIZE 512
  5. // Parse an octal number, ignoring leading and trailing nonsense
  6. static unsigned long
  7. parseoct(const char *p, size_t n)
  8. {
  9. unsigned long i = 0;
  10. while ((*p < '0' || *p > '7') && n > 0) {
  11. ++p;
  12. --n;
  13. }
  14. while (*p >= '0' && *p <= '7' && n > 0) {
  15. i *= 8;
  16. i += *p - '0';
  17. ++p;
  18. --n;
  19. }
  20. return (i);
  21. }
  22. // Returns true if this is 512 zero bytes
  23. static int
  24. is_end_of_archive(const char *p)
  25. {
  26. int n;
  27. for (n = 0; n < BLOCKSIZE; ++n)
  28. if (p[n] != '\0')
  29. return (0);
  30. return (1);
  31. }
  32. // Verify the tar checksum
  33. static int
  34. verify_checksum(const char *p)
  35. {
  36. int n, u = 0;
  37. for (n = 0; n < BLOCKSIZE; ++n) {
  38. if (n < 148 || n > 155)
  39. /* Standard tar checksum adds unsigned bytes. */
  40. u += ((unsigned char *)p)[n];
  41. else
  42. u += 0x20;
  43. }
  44. return (u == (int)parseoct(p + 148, 8));
  45. }
  46. // Extract a tar archive
  47. typedef int (*process_archived_file_t)(FL_FILE *a, const char *fname, size_t flen);
  48. static int untar(FL_FILE *a, process_archived_file_t process_fn)
  49. {
  50. size_t bytes_read;
  51. unsigned long filesize;
  52. char buff[BLOCKSIZE];
  53. {
  54. bytes_read = fl_fread(buff, BLOCKSIZE, 1, a);
  55. if (bytes_read < BLOCKSIZE) {
  56. printf("UNTAR: short read: expected %d, got %d\n", BLOCKSIZE, (int)bytes_read);
  57. return -1;
  58. }
  59. if (is_end_of_archive(buff)) {
  60. return 0;
  61. }
  62. if (!verify_checksum(buff)) {
  63. printf("UNTAR: checksum failure\n");
  64. return -2;
  65. }
  66. filesize = parseoct(buff + 124, 12);
  67. switch (buff[156]) {
  68. case '1':
  69. printf("UNTAR: ignoring hardlink %s\n", buff);
  70. break;
  71. case '2':
  72. printf("UNTAR: ignoring symlink %s\n", buff);
  73. break;
  74. case '3':
  75. printf("UNTAR: ignoring character device %s\n", buff);
  76. break;
  77. case '4':
  78. printf("UNTAR: ignoring block device %s\n", buff);
  79. break;
  80. case '5':
  81. printf("UNTAR: directory %s\n", buff);
  82. //create_dir(buff, (int)parseoct(buff + 100, 8));
  83. filesize = 0;
  84. break;
  85. case '6':
  86. printf("UNTAR: ignoring FIFO %s\n", buff);
  87. break;
  88. default:
  89. process_fn(a, buff, filesize);
  90. filesize = 512-(filesize & 0x1FF); //skip unused bytes
  91. break;
  92. }
  93. if(filesize & 0x1FF)
  94. fl_fseek(a, filesize, SEEK_CUR);
  95. }
  96. return 1;
  97. }