lfs_filebd.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. /*
  2. * Block device emulated in a file
  3. *
  4. * Copyright (c) 2022, The littlefs authors.
  5. * Copyright (c) 2017, Arm Limited. All rights reserved.
  6. * SPDX-License-Identifier: BSD-3-Clause
  7. */
  8. #include "bd/lfs_filebd.h"
  9. #include <fcntl.h>
  10. #include <unistd.h>
  11. #include <errno.h>
  12. int lfs_filebd_createcfg(const struct lfs_config *cfg, const char *path,
  13. const struct lfs_filebd_config *bdcfg) {
  14. LFS_FILEBD_TRACE("lfs_filebd_createcfg(%p {.context=%p, "
  15. ".read=%p, .prog=%p, .erase=%p, .sync=%p, "
  16. ".read_size=%"PRIu32", .prog_size=%"PRIu32", "
  17. ".block_size=%"PRIu32", .block_count=%"PRIu32"}, "
  18. "\"%s\", "
  19. "%p {.erase_value=%"PRId32"})",
  20. (void*)cfg, cfg->context,
  21. (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog,
  22. (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync,
  23. cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count,
  24. path, (void*)bdcfg, bdcfg->erase_value);
  25. lfs_filebd_t *bd = cfg->context;
  26. bd->cfg = bdcfg;
  27. // open file
  28. bd->fd = open(path, O_RDWR | O_CREAT, 0666);
  29. if (bd->fd < 0) {
  30. int err = -errno;
  31. LFS_FILEBD_TRACE("lfs_filebd_createcfg -> %d", err);
  32. return err;
  33. }
  34. LFS_FILEBD_TRACE("lfs_filebd_createcfg -> %d", 0);
  35. return 0;
  36. }
  37. int lfs_filebd_create(const struct lfs_config *cfg, const char *path) {
  38. LFS_FILEBD_TRACE("lfs_filebd_create(%p {.context=%p, "
  39. ".read=%p, .prog=%p, .erase=%p, .sync=%p, "
  40. ".read_size=%"PRIu32", .prog_size=%"PRIu32", "
  41. ".block_size=%"PRIu32", .block_count=%"PRIu32"}, "
  42. "\"%s\")",
  43. (void*)cfg, cfg->context,
  44. (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog,
  45. (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync,
  46. cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count,
  47. path);
  48. static const struct lfs_filebd_config defaults = {.erase_value=-1};
  49. int err = lfs_filebd_createcfg(cfg, path, &defaults);
  50. LFS_FILEBD_TRACE("lfs_filebd_create -> %d", err);
  51. return err;
  52. }
  53. int lfs_filebd_destroy(const struct lfs_config *cfg) {
  54. LFS_FILEBD_TRACE("lfs_filebd_destroy(%p)", (void*)cfg);
  55. lfs_filebd_t *bd = cfg->context;
  56. int err = close(bd->fd);
  57. if (err < 0) {
  58. err = -errno;
  59. LFS_FILEBD_TRACE("lfs_filebd_destroy -> %d", err);
  60. return err;
  61. }
  62. LFS_FILEBD_TRACE("lfs_filebd_destroy -> %d", 0);
  63. return 0;
  64. }
  65. int lfs_filebd_read(const struct lfs_config *cfg, lfs_block_t block,
  66. lfs_off_t off, void *buffer, lfs_size_t size) {
  67. LFS_FILEBD_TRACE("lfs_filebd_read(%p, "
  68. "0x%"PRIx32", %"PRIu32", %p, %"PRIu32")",
  69. (void*)cfg, block, off, buffer, size);
  70. lfs_filebd_t *bd = cfg->context;
  71. // check if read is valid
  72. LFS_ASSERT(off % cfg->read_size == 0);
  73. LFS_ASSERT(size % cfg->read_size == 0);
  74. LFS_ASSERT(block < cfg->block_count);
  75. // zero for reproducability (in case file is truncated)
  76. if (bd->cfg->erase_value != -1) {
  77. memset(buffer, bd->cfg->erase_value, size);
  78. }
  79. // read
  80. off_t res1 = lseek(bd->fd,
  81. (off_t)block*cfg->block_size + (off_t)off, SEEK_SET);
  82. if (res1 < 0) {
  83. int err = -errno;
  84. LFS_FILEBD_TRACE("lfs_filebd_read -> %d", err);
  85. return err;
  86. }
  87. ssize_t res2 = read(bd->fd, buffer, size);
  88. if (res2 < 0) {
  89. int err = -errno;
  90. LFS_FILEBD_TRACE("lfs_filebd_read -> %d", err);
  91. return err;
  92. }
  93. LFS_FILEBD_TRACE("lfs_filebd_read -> %d", 0);
  94. return 0;
  95. }
  96. int lfs_filebd_prog(const struct lfs_config *cfg, lfs_block_t block,
  97. lfs_off_t off, const void *buffer, lfs_size_t size) {
  98. LFS_FILEBD_TRACE("lfs_filebd_prog(%p, 0x%"PRIx32", %"PRIu32", %p, %"PRIu32")",
  99. (void*)cfg, block, off, buffer, size);
  100. lfs_filebd_t *bd = cfg->context;
  101. // check if write is valid
  102. LFS_ASSERT(off % cfg->prog_size == 0);
  103. LFS_ASSERT(size % cfg->prog_size == 0);
  104. LFS_ASSERT(block < cfg->block_count);
  105. // check that data was erased? only needed for testing
  106. if (bd->cfg->erase_value != -1) {
  107. off_t res1 = lseek(bd->fd,
  108. (off_t)block*cfg->block_size + (off_t)off, SEEK_SET);
  109. if (res1 < 0) {
  110. int err = -errno;
  111. LFS_FILEBD_TRACE("lfs_filebd_prog -> %d", err);
  112. return err;
  113. }
  114. for (lfs_off_t i = 0; i < size; i++) {
  115. uint8_t c;
  116. ssize_t res2 = read(bd->fd, &c, 1);
  117. if (res2 < 0) {
  118. int err = -errno;
  119. LFS_FILEBD_TRACE("lfs_filebd_prog -> %d", err);
  120. return err;
  121. }
  122. LFS_ASSERT(c == bd->cfg->erase_value);
  123. }
  124. }
  125. // program data
  126. off_t res1 = lseek(bd->fd,
  127. (off_t)block*cfg->block_size + (off_t)off, SEEK_SET);
  128. if (res1 < 0) {
  129. int err = -errno;
  130. LFS_FILEBD_TRACE("lfs_filebd_prog -> %d", err);
  131. return err;
  132. }
  133. ssize_t res2 = write(bd->fd, buffer, size);
  134. if (res2 < 0) {
  135. int err = -errno;
  136. LFS_FILEBD_TRACE("lfs_filebd_prog -> %d", err);
  137. return err;
  138. }
  139. LFS_FILEBD_TRACE("lfs_filebd_prog -> %d", 0);
  140. return 0;
  141. }
  142. int lfs_filebd_erase(const struct lfs_config *cfg, lfs_block_t block) {
  143. LFS_FILEBD_TRACE("lfs_filebd_erase(%p, 0x%"PRIx32")", (void*)cfg, block);
  144. lfs_filebd_t *bd = cfg->context;
  145. // check if erase is valid
  146. LFS_ASSERT(block < cfg->block_count);
  147. // erase, only needed for testing
  148. if (bd->cfg->erase_value != -1) {
  149. off_t res1 = lseek(bd->fd, (off_t)block*cfg->block_size, SEEK_SET);
  150. if (res1 < 0) {
  151. int err = -errno;
  152. LFS_FILEBD_TRACE("lfs_filebd_erase -> %d", err);
  153. return err;
  154. }
  155. for (lfs_off_t i = 0; i < cfg->block_size; i++) {
  156. ssize_t res2 = write(bd->fd, &(uint8_t){bd->cfg->erase_value}, 1);
  157. if (res2 < 0) {
  158. int err = -errno;
  159. LFS_FILEBD_TRACE("lfs_filebd_erase -> %d", err);
  160. return err;
  161. }
  162. }
  163. }
  164. LFS_FILEBD_TRACE("lfs_filebd_erase -> %d", 0);
  165. return 0;
  166. }
  167. int lfs_filebd_sync(const struct lfs_config *cfg) {
  168. LFS_FILEBD_TRACE("lfs_filebd_sync(%p)", (void*)cfg);
  169. // file sync
  170. lfs_filebd_t *bd = cfg->context;
  171. int err = fsync(bd->fd);
  172. if (err) {
  173. err = -errno;
  174. LFS_FILEBD_TRACE("lfs_filebd_sync -> %d", 0);
  175. return err;
  176. }
  177. LFS_FILEBD_TRACE("lfs_filebd_sync -> %d", 0);
  178. return 0;
  179. }