/
plugin.cc
172 lines (130 loc) · 3.55 KB
/
plugin.cc
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/*
* \brief Libc plugin that uses Genode's ROM session
* \author Norman Feske
* \date 2012-01-09
*/
/*
* Copyright (C) 2011-2012 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* libc plugin interface */
#include <libc-plugin/plugin.h>
#include <libc-plugin/fd_alloc.h>
/* libc includes */
#include <unistd.h>
#include <errno.h>
#include <string.h>
/* Genode includes */
#include <os/attached_rom_dataspace.h>
#include <util/misc_math.h>
#include <base/printf.h>
#include <base/env.h>
namespace {
/**
* An open file descriptor for this plugin corresponds to a ROM connection
*
* The connection is created along with the context.
*/
struct Plugin_context : Libc::Plugin_context, Genode::Attached_rom_dataspace
{
Genode::off_t read_offset;
Plugin_context(char const *filename)
: Genode::Attached_rom_dataspace(filename), read_offset(0) { }
};
static inline Plugin_context *context(Libc::File_descriptor *fd)
{
return static_cast<Plugin_context *>(fd->context);
}
class Plugin : public Libc::Plugin
{
private:
bool _probe_rom(char const *filename)
{
try {
/*
* Create ROM connection as local variable. The connection
* gets closed automatically when leaving the scope of this
* function.
*/
Genode::Rom_connection rom(filename);
return true;
} catch (...) {
return false;
}
}
public:
/**
* Constructor
*/
Plugin()
{ }
bool supports_open(const char *path, int flags)
{
return _probe_rom(path);
}
Libc::File_descriptor *open(const char *pathname, int flags)
{
Plugin_context *context = new (Genode::env()->heap())
Plugin_context(pathname);
return Libc::file_descriptor_allocator()->alloc(this, context);
}
int close(Libc::File_descriptor *fd)
{
Genode::destroy(Genode::env()->heap(), context(fd));
Libc::file_descriptor_allocator()->free(fd);
return 0;
}
ssize_t read(Libc::File_descriptor *fd, void *buf, ::size_t count)
{
Plugin_context *rom = context(fd);
/* file read limit is the size of data space */
Genode::size_t const max_size = rom->size();
/* shortcut to current read offset */
Genode::off_t &read_offset = rom->read_offset;
/* maximum read offset, clamped to dataspace size */
Genode::off_t const end_offset = Genode::min(count + read_offset, max_size);
/* source address within the dataspace */
char const *src = rom->local_addr<char>() + read_offset;
/* check if end of file is reached */
if (read_offset >= end_offset)
return 0;
/* copy-out bytes from ROM dataspace */
Genode::off_t num_bytes = end_offset - read_offset;
memcpy(buf, src, num_bytes);
/* advance read offset */
read_offset += num_bytes;
return num_bytes;
}
::off_t lseek(Libc::File_descriptor *fd, ::off_t offset, int whence)
{
Plugin_context *rom = context(fd);
switch (whence) {
case SEEK_CUR:
offset += rom->read_offset;
/*
* falling through...
*/
case SEEK_SET:
if (offset > rom->size()) {
errno = EINVAL;
return (::off_t)(-1);
}
rom->read_offset = offset;
break;
case SEEK_END:
rom->read_offset = rom->size();
break;
default:
errno = EINVAL;
return (::off_t)(-1);
}
return rom->read_offset;
}
};
} /* unnamed namespace */
void __attribute__((constructor)) init_libc_rom(void)
{
static Plugin plugin;
}