fs_packed.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. #include "fs.h"
  2. #include "printf.h"
  3. #include "str.h"
  4. struct packed_file {
  5. const char *data;
  6. size_t size;
  7. size_t pos;
  8. };
  9. #if MG_ENABLE_PACKED_FS
  10. #else
  11. const char *mg_unpack(const char *path, size_t *size, time_t *mtime) {
  12. *size = 0, *mtime = 0;
  13. (void) path;
  14. return NULL;
  15. }
  16. const char *mg_unlist(size_t no) {
  17. (void) no;
  18. return NULL;
  19. }
  20. #endif
  21. struct mg_str mg_unpacked(const char *path) {
  22. size_t len = 0;
  23. const char *buf = mg_unpack(path, &len, NULL);
  24. return mg_str_n(buf, len);
  25. }
  26. static int is_dir_prefix(const char *prefix, size_t n, const char *path) {
  27. // MG_INFO(("[%.*s] [%s] %c", (int) n, prefix, path, path[n]));
  28. return n < strlen(path) && strncmp(prefix, path, n) == 0 &&
  29. (n == 0 || path[n] == '/' || path[n - 1] == '/');
  30. }
  31. static int packed_stat(const char *path, size_t *size, time_t *mtime) {
  32. const char *p;
  33. size_t i, n = strlen(path);
  34. if (mg_unpack(path, size, mtime)) return MG_FS_READ; // Regular file
  35. // Scan all files. If `path` is a dir prefix for any of them, it's a dir
  36. for (i = 0; (p = mg_unlist(i)) != NULL; i++) {
  37. if (is_dir_prefix(path, n, p)) return MG_FS_DIR;
  38. }
  39. return 0;
  40. }
  41. static void packed_list(const char *dir, void (*fn)(const char *, void *),
  42. void *userdata) {
  43. char buf[MG_PATH_MAX], tmp[sizeof(buf)];
  44. const char *path, *begin, *end;
  45. size_t i, n = strlen(dir);
  46. tmp[0] = '\0'; // Previously listed entry
  47. for (i = 0; (path = mg_unlist(i)) != NULL; i++) {
  48. if (!is_dir_prefix(dir, n, path)) continue;
  49. begin = &path[n + 1];
  50. end = strchr(begin, '/');
  51. if (end == NULL) end = begin + strlen(begin);
  52. mg_snprintf(buf, sizeof(buf), "%.*s", (int) (end - begin), begin);
  53. buf[sizeof(buf) - 1] = '\0';
  54. // If this entry has been already listed, skip
  55. // NOTE: we're assuming that file list is sorted alphabetically
  56. if (strcmp(buf, tmp) == 0) continue;
  57. fn(buf, userdata); // Not yet listed, call user function
  58. strcpy(tmp, buf); // And save this entry as listed
  59. }
  60. }
  61. static void *packed_open(const char *path, int flags) {
  62. size_t size = 0;
  63. const char *data = mg_unpack(path, &size, NULL);
  64. struct packed_file *fp = NULL;
  65. if (data == NULL) return NULL;
  66. if (flags & MG_FS_WRITE) return NULL;
  67. if ((fp = (struct packed_file *) calloc(1, sizeof(*fp))) != NULL) {
  68. fp->size = size;
  69. fp->data = data;
  70. }
  71. return (void *) fp;
  72. }
  73. static void packed_close(void *fp) {
  74. if (fp != NULL) free(fp);
  75. }
  76. static size_t packed_read(void *fd, void *buf, size_t len) {
  77. struct packed_file *fp = (struct packed_file *) fd;
  78. if (fp->pos + len > fp->size) len = fp->size - fp->pos;
  79. memcpy(buf, &fp->data[fp->pos], len);
  80. fp->pos += len;
  81. return len;
  82. }
  83. static size_t packed_write(void *fd, const void *buf, size_t len) {
  84. (void) fd, (void) buf, (void) len;
  85. return 0;
  86. }
  87. static size_t packed_seek(void *fd, size_t offset) {
  88. struct packed_file *fp = (struct packed_file *) fd;
  89. fp->pos = offset;
  90. if (fp->pos > fp->size) fp->pos = fp->size;
  91. return fp->pos;
  92. }
  93. static bool packed_rename(const char *from, const char *to) {
  94. (void) from, (void) to;
  95. return false;
  96. }
  97. static bool packed_remove(const char *path) {
  98. (void) path;
  99. return false;
  100. }
  101. static bool packed_mkdir(const char *path) {
  102. (void) path;
  103. return false;
  104. }
  105. struct mg_fs mg_fs_packed = {
  106. packed_stat, packed_list, packed_open, packed_close, packed_read,
  107. packed_write, packed_seek, packed_rename, packed_remove, packed_mkdir};