lfs_filebd.c 6.2 KB

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