-
Notifications
You must be signed in to change notification settings - Fork 61
/
Copy pathlfs_fuse_bd.c
138 lines (113 loc) · 3.02 KB
/
lfs_fuse_bd.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/*
* Linux user-space block device wrapper
*
* Copyright (c) 2022, the littlefs authors.
* Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "lfs_fuse_bd.h"
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdint.h>
#include <assert.h>
#if !defined(__FreeBSD__)
#include <sys/ioctl.h>
#include <linux/fs.h>
#elif defined(__FreeBSD__)
#define BLKSSZGET DIOCGSECTORSIZE
#define BLKGETSIZE DIOCGMEDIASIZE
#include <sys/disk.h>
#endif
// Block device wrapper for user-space block devices
int lfs_fuse_bd_create(struct lfs_config *cfg, const char *path) {
int fd = open(path, O_RDWR);
if (fd < 0) {
return -errno;
}
cfg->context = (void*)(intptr_t)fd;
// get sector size
if (!cfg->block_size) {
long ssize;
int err = ioctl(fd, BLKSSZGET, &ssize);
if (err) {
return -errno;
}
cfg->block_size = ssize;
}
// get size in sectors
if (!cfg->block_count) {
uint64_t size;
int err = ioctl(fd, BLKGETSIZE64, &size);
if (err) {
return -errno;
}
cfg->block_count = size / cfg->block_size;
}
// setup function pointers
cfg->read = lfs_fuse_bd_read;
cfg->prog = lfs_fuse_bd_prog;
cfg->erase = lfs_fuse_bd_erase;
cfg->sync = lfs_fuse_bd_sync;
return 0;
}
void lfs_fuse_bd_destroy(const struct lfs_config *cfg) {
int fd = (intptr_t)cfg->context;
close(fd);
}
int lfs_fuse_bd_read(const struct lfs_config *cfg, lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size) {
int fd = (intptr_t)cfg->context;
uint8_t *buffer_ = buffer;
// check if read is valid
assert(block < cfg->block_count);
// go to block
off_t err = lseek(fd, (off_t)block*cfg->block_size + (off_t)off, SEEK_SET);
if (err < 0) {
return -errno;
}
// read block
while (size > 0) {
ssize_t res = read(fd, buffer_, (size_t)size);
if (res < 0) {
return -errno;
}
buffer_ += res;
size -= res;
}
return 0;
}
int lfs_fuse_bd_prog(const struct lfs_config *cfg, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size) {
int fd = (intptr_t)cfg->context;
const uint8_t *buffer_ = buffer;
// check if write is valid
assert(block < cfg->block_count);
// go to block
off_t err = lseek(fd, (off_t)block*cfg->block_size + (off_t)off, SEEK_SET);
if (err < 0) {
return -errno;
}
// write block
while (size > 0) {
ssize_t res = write(fd, buffer_, (size_t)size);
if (res < 0) {
return -errno;
}
buffer_ += res;
size -= res;
}
return 0;
}
int lfs_fuse_bd_erase(const struct lfs_config *cfg, lfs_block_t block) {
// do nothing
return 0;
}
int lfs_fuse_bd_sync(const struct lfs_config *cfg) {
int fd = (intptr_t)cfg->context;
int err = fsync(fd);
if (err) {
return -errno;
}
return 0;
}