Mirror of CollapseOS
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.

143 lines
3.7KB

  1. #include <stdio.h>
  2. #include <dirent.h>
  3. #include <string.h>
  4. #include <fnmatch.h>
  5. #include <libgen.h>
  6. #include <sys/stat.h>
  7. #define BLKSIZE 0x100
  8. #define HEADERSIZE 0x20
  9. #define MAX_FN_LEN 25 // 26 - null char
  10. #define MAX_FILE_SIZE (BLKSIZE * 0x100) - HEADERSIZE
  11. int is_regular_file(char *path)
  12. {
  13. struct stat path_stat;
  14. stat(path, &path_stat);
  15. return S_ISREG(path_stat.st_mode);
  16. }
  17. int spitblock(char *fullpath, char *fn)
  18. {
  19. FILE *fp = fopen(fullpath, "r");
  20. fseek(fp, 0, SEEK_END);
  21. long fsize = ftell(fp);
  22. if (fsize > MAX_FILE_SIZE) {
  23. fclose(fp);
  24. fprintf(stderr, "File too big: %s %ld\n", fullpath, fsize);
  25. return 1;
  26. }
  27. /* Compute block count.
  28. * We always have at least one, which contains 0x100 bytes - 0x20, which is
  29. * metadata. The rest of the blocks have a steady 0x100.
  30. */
  31. unsigned char blockcount = 1;
  32. int fsize2 = fsize - (BLKSIZE - HEADERSIZE);
  33. if (fsize2 > 0) {
  34. blockcount += (fsize2 / BLKSIZE);
  35. }
  36. if (blockcount * BLKSIZE < fsize + HEADERSIZE) {
  37. blockcount++;
  38. }
  39. putchar('C');
  40. putchar('F');
  41. putchar('S');
  42. putchar(blockcount);
  43. // file size is little endian
  44. putchar(fsize & 0xff);
  45. putchar((fsize >> 8) & 0xff);
  46. int fnlen = strlen(fn);
  47. for (int i=0; i<MAX_FN_LEN; i++) {
  48. if (i < fnlen) {
  49. putchar(fn[i]);
  50. } else {
  51. putchar(0);
  52. }
  53. }
  54. // And the last FN char which is always null
  55. putchar(0);
  56. char buf[MAX_FILE_SIZE] = {0};
  57. rewind(fp);
  58. fread(buf, fsize, 1, fp);
  59. fclose(fp);
  60. fwrite(buf, (blockcount * BLKSIZE) - HEADERSIZE, 1, stdout);
  61. fflush(stdout);
  62. return 0;
  63. }
  64. int spitdir(char *path, char *prefix, char *pattern)
  65. {
  66. DIR *dp;
  67. struct dirent *ep;
  68. int prefixlen = strlen(prefix);
  69. dp = opendir(path);
  70. if (dp == NULL) {
  71. fprintf(stderr, "Couldn't open directory.\n");
  72. return 1;
  73. }
  74. while (ep = readdir(dp)) {
  75. if ((strcmp(ep->d_name, ".") == 0) || strcmp(ep->d_name, "..") == 0) {
  76. continue;
  77. }
  78. if (ep->d_type != DT_DIR && ep->d_type != DT_REG) {
  79. fprintf(stderr, "Only regular file or directories are supported\n");
  80. return 1;
  81. }
  82. int slen = strlen(ep->d_name);
  83. if (prefixlen + slen> MAX_FN_LEN) {
  84. fprintf(stderr, "Filename too long: %s/%s\n", prefix, ep->d_name);
  85. return 1;
  86. }
  87. char fullpath[0x1000];
  88. strcpy(fullpath, path);
  89. strcat(fullpath, "/");
  90. strcat(fullpath, ep->d_name);
  91. char newprefix[MAX_FN_LEN];
  92. strcpy(newprefix, prefix);
  93. if (prefixlen > 0) {
  94. strcat(newprefix, "/");
  95. }
  96. strcat(newprefix, ep->d_name);
  97. if (ep->d_type == DT_DIR) {
  98. int r = spitdir(fullpath, newprefix, pattern);
  99. if (r != 0) {
  100. return r;
  101. }
  102. } else {
  103. if (pattern) {
  104. if (fnmatch(pattern, ep->d_name, 0) != 0) {
  105. continue;
  106. }
  107. }
  108. int r = spitblock(fullpath, newprefix);
  109. if (r != 0) {
  110. return r;
  111. }
  112. }
  113. }
  114. closedir(dp);
  115. return 0;
  116. }
  117. int main(int argc, char *argv[])
  118. {
  119. if ((argc > 3) || (argc < 2)) {
  120. fprintf(stderr, "Usage: cfspack /path/to/dir [pattern] \n");
  121. return 1;
  122. }
  123. char *srcpath = argv[1];
  124. char *pattern = NULL;
  125. if (argc == 3) {
  126. pattern = argv[2];
  127. }
  128. if (is_regular_file(srcpath)) {
  129. // special case: just one file
  130. return spitblock(srcpath, basename(srcpath));
  131. } else {
  132. return spitdir(srcpath, "", pattern);
  133. }
  134. }