Skip to content

Commit c3c6ed0

Browse files
committed
buffer: read and write
The buffer_pread and buffer_pwrite functions provide a POSIX pread and pwrite inspired API to get and set parts of a memory buffer. The buffer_read and buffer_write functions wrap the pread/pwrite variants and update the current buffer offset. Signed-off-by: Josef 'Jeff' Sipek <[email protected]>
1 parent 3da89fe commit c3c6ed0

File tree

8 files changed

+153
-2
lines changed

8 files changed

+153
-2
lines changed

buffer.c

+69
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,57 @@ int buffer_truncate(struct buffer *buffer, size_t size)
216216
return 0;
217217
}
218218

219+
ssize_t buffer_pread(struct buffer *buffer, void *buf, size_t len, size_t off)
220+
{
221+
ssize_t ret;
222+
223+
if (!buffer || !buf)
224+
return -EINVAL;
225+
226+
if (buffer->ops->check_read) {
227+
ret = buffer->ops->check_read(buffer, buf, len, off);
228+
if (ret)
229+
return ret;
230+
}
231+
232+
if (off >= buffer->used)
233+
ret = 0;
234+
else if ((off + len) > buffer->used)
235+
ret = buffer->used - off;
236+
else
237+
ret = len;
238+
239+
if (ret)
240+
buffer->ops->copyout(buffer, off, buf, ret);
241+
242+
return ret;
243+
}
244+
245+
ssize_t buffer_pwrite(struct buffer *buffer, const void *buf, size_t len,
246+
size_t off)
247+
{
248+
ssize_t ret;
249+
250+
if (!buffer || !buf)
251+
return -EINVAL;
252+
253+
if (buffer->ops->check_write) {
254+
ret = buffer->ops->check_write(buffer, buf, len, off);
255+
if (ret)
256+
return ret;
257+
}
258+
259+
ret = resize(buffer, off + len);
260+
if (ret)
261+
return ret;
262+
263+
buffer->ops->copyin(buffer, off, buf, len);
264+
265+
buffer->used = MAX(buffer->used, off + len);
266+
267+
return len;
268+
}
269+
219270
/*
220271
* Generic implementations
221272
*/
@@ -252,3 +303,21 @@ void generic_buffer_copyin_panic(struct buffer *buffer, size_t off,
252303
{
253304
panic("buffer copyin called");
254305
}
306+
307+
/* copyout implementations */
308+
void generic_buffer_copyout_memcpy(struct buffer *buffer, size_t off,
309+
void *data, size_t datalen)
310+
{
311+
memcpy(data, buffer->data + off, datalen);
312+
}
313+
314+
void generic_buffer_copyout_nop(struct buffer *buffer, size_t off, void *data,
315+
size_t datalen)
316+
{
317+
}
318+
319+
void generic_buffer_copyout_panic(struct buffer *buffer, size_t off, void *data,
320+
size_t datalen)
321+
{
322+
panic("buffer copyout called");
323+
}

buffer_heap.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017 Josef 'Jeff' Sipek <[email protected]>
2+
* Copyright (c) 2017-2018 Josef 'Jeff' Sipek <[email protected]>
33
*
44
* Permission is hereby granted, free of charge, to any person obtaining a copy
55
* of this software and associated documentation files (the "Software"), to deal
@@ -27,4 +27,5 @@ const struct buffer_ops heap_buffer = {
2727
.free = free,
2828
.clear = generic_buffer_clear_memset,
2929
.copyin = generic_buffer_copyin_memcpy,
30+
.copyout = generic_buffer_copyout_memcpy,
3031
};

buffer_impl.h

+8
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,12 @@ extern void generic_buffer_copyin_nop(struct buffer *buffer, size_t off,
4747
extern void generic_buffer_copyin_panic(struct buffer *buffer, size_t off,
4848
const void *newdata, size_t newdatalen);
4949

50+
/* copyout implementations */
51+
extern void generic_buffer_copyout_memcpy(struct buffer *buffer, size_t off,
52+
void *data, size_t datalen);
53+
extern void generic_buffer_copyout_nop(struct buffer *buffer, size_t off,
54+
void *data, size_t datalen);
55+
extern void generic_buffer_copyout_panic(struct buffer *buffer, size_t off,
56+
void *data, size_t datalen);
57+
5058
#endif

buffer_sink.c

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017 Josef 'Jeff' Sipek <[email protected]>
2+
* Copyright (c) 2017-2018 Josef 'Jeff' Sipek <[email protected]>
33
*
44
* Permission is hereby granted, free of charge, to any person obtaining a copy
55
* of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,15 @@
2222

2323
#include "buffer_impl.h"
2424

25+
static int sink_buffer_check_read(struct buffer *buffer, void *data, size_t len,
26+
size_t off)
27+
{
28+
return -ENOTSUP;
29+
}
30+
2531
const struct buffer_ops sink_buffer = {
32+
.check_read = sink_buffer_check_read,
33+
2634
/*
2735
* no need for:
2836
* - realloc since we use SIZE_MAX alloc size
@@ -31,4 +39,5 @@ const struct buffer_ops sink_buffer = {
3139

3240
.clear = generic_buffer_clear_nop,
3341
.copyin = generic_buffer_copyin_nop,
42+
.copyout = generic_buffer_copyout_panic,
3443
};

buffer_static.c

+19
Original file line numberDiff line numberDiff line change
@@ -69,20 +69,39 @@ static int static_buffer_check_truncate_rw(struct buffer *buffer, size_t size)
6969
return -ENOSPC;
7070
}
7171

72+
static int static_buffer_check_write_ro(struct buffer *buffer, const void *buf,
73+
size_t len, size_t off)
74+
{
75+
return -EROFS;
76+
}
77+
78+
static int static_buffer_check_write_rw(struct buffer *buffer, const void *buf,
79+
size_t len, size_t off)
80+
{
81+
if ((off + len) <= buffer->allocsize)
82+
return 0;
83+
84+
return -ENOSPC;
85+
}
86+
7287
/* a read-only static buffer */
7388
const struct buffer_ops static_buffer_ro = {
7489
.check_append = static_buffer_check_append_ro,
7590
.check_truncate = static_buffer_check_truncate_ro,
91+
.check_write = static_buffer_check_write_ro,
7692

7793
.clear = generic_buffer_clear_panic,
7894
.copyin = generic_buffer_copyin_panic,
95+
.copyout = generic_buffer_copyout_memcpy,
7996
};
8097

8198
/* a read-write static buffer */
8299
const struct buffer_ops static_buffer_rw = {
83100
.check_append = static_buffer_check_append_rw,
84101
.check_truncate = static_buffer_check_truncate_rw,
102+
.check_write = static_buffer_check_write_rw,
85103

86104
.clear = generic_buffer_clear_memset,
87105
.copyin = generic_buffer_copyin_memcpy,
106+
.copyout = generic_buffer_copyout_memcpy,
88107
};

buffer_stdio.c

+9
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ static void stdio_buffer_copyin(struct buffer *buffer, size_t off,
4545
strerror(errno));
4646
}
4747

48+
static void stdio_buffer_copyout(struct buffer *buffer, size_t off,
49+
void *data, size_t datalen)
50+
{
51+
if (fread(data, datalen, 1, buffer->private) != 1)
52+
panic("%s: failed to read data from buffer: %s", __func__,
53+
strerror(errno));
54+
}
55+
4856
const struct buffer_ops stdio_buffer = {
4957
.check_truncate = stdio_buffer_check_truncate,
5058
.check_seek = stdio_buffer_check_seek,
@@ -57,4 +65,5 @@ const struct buffer_ops stdio_buffer = {
5765

5866
.clear = generic_buffer_clear_panic,
5967
.copyin = stdio_buffer_copyin,
68+
.copyout = stdio_buffer_copyout,
6069
};

include/jeffpc/buffer.h

+34
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,17 @@ struct buffer;
3636
struct buffer_ops {
3737
/* op checking */
3838
int (*check_append)(struct buffer *, const void *, size_t);
39+
int (*check_read)(struct buffer *, void *, size_t, size_t);
3940
int (*check_truncate)(struct buffer *, size_t);
41+
int (*check_write)(struct buffer *, const void *, size_t, size_t);
4042
ssize_t (*check_seek)(struct buffer *, off_t, int, size_t);
4143

4244
/* data manipulation */
4345
void *(*realloc)(void *, size_t);
4446
void (*free)(void *);
4547
void (*clear)(struct buffer *, size_t, size_t);
4648
void (*copyin)(struct buffer *, size_t, const void *, size_t);
49+
void (*copyout)(struct buffer *, size_t, void *, size_t);
4750
};
4851

4952
struct buffer {
@@ -73,6 +76,10 @@ extern void buffer_init_stdio(struct buffer *buffer, FILE *f);
7376
extern int buffer_append(struct buffer *buffer, const void *data, size_t size);
7477
extern ssize_t buffer_seek(struct buffer *buffer, off_t offset, int whence);
7578
extern int buffer_truncate(struct buffer *buffer, size_t size);
79+
extern ssize_t buffer_pread(struct buffer *buffer, void *data, size_t len,
80+
size_t off);
81+
extern ssize_t buffer_pwrite(struct buffer *buffer, const void *data, size_t len,
82+
size_t off);
7683

7784
static inline size_t buffer_used(struct buffer *buffer)
7885
{
@@ -119,4 +126,31 @@ static inline int buffer_append_str(struct buffer *buffer, const struct str *s)
119126
return buffer_append_cstr(buffer, str);
120127
}
121128

129+
/* same as buffer_pread(), but it uses and updates current offset */
130+
static inline ssize_t buffer_read(struct buffer *buffer, void *buf, size_t len)
131+
{
132+
ssize_t ret;
133+
134+
ret = buffer_pread(buffer, buf, len, buffer->off);
135+
136+
if (ret >= 0)
137+
buffer->off += ret;
138+
139+
return ret;
140+
}
141+
142+
/* same as buffer_pwrite(), but it uses and updates current offset */
143+
static inline ssize_t buffer_write(struct buffer *buffer, const void *buf,
144+
size_t len)
145+
{
146+
ssize_t ret;
147+
148+
ret = buffer_pwrite(buffer, buf, len, buffer->off);
149+
150+
if (ret >= 0)
151+
buffer->off += ret;
152+
153+
return ret;
154+
}
155+
122156
#endif

mapfile-vers

+2
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ JEFFPC_0.10 {
4242
buffer_init_sink;
4343
buffer_init_static;
4444
buffer_init_stdio;
45+
buffer_pread;
46+
buffer_pwrite;
4547
buffer_seek;
4648
buffer_truncate;
4749

0 commit comments

Comments
 (0)