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