Git fork
1/*
2 * Copyright 2020 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style
5 * license that can be found in the LICENSE file or at
6 * https://developers.google.com/open-source/licenses/bsd
7 */
8
9#include "system.h"
10
11#include "basics.h"
12#include "blocksource.h"
13#include "reftable-blocksource.h"
14#include "reftable-error.h"
15
16void block_source_release_data(struct reftable_block_data *data)
17{
18 struct reftable_block_source source = data->source;
19 if (data && source.ops)
20 source.ops->release_data(source.arg, data);
21 data->data = NULL;
22 data->len = 0;
23 data->source.ops = NULL;
24 data->source.arg = NULL;
25}
26
27void block_source_close(struct reftable_block_source *source)
28{
29 if (!source->ops) {
30 return;
31 }
32
33 source->ops->close(source->arg);
34 source->ops = NULL;
35}
36
37ssize_t block_source_read_data(struct reftable_block_source *source,
38 struct reftable_block_data *dest, uint64_t off,
39 uint32_t size)
40{
41 ssize_t result = source->ops->read_data(source->arg, dest, off, size);
42 dest->source = *source;
43 return result;
44}
45
46uint64_t block_source_size(struct reftable_block_source *source)
47{
48 return source->ops->size(source->arg);
49}
50
51static void reftable_buf_release_data(void *b REFTABLE_UNUSED, struct reftable_block_data *dest)
52{
53 if (dest->len)
54 memset(dest->data, 0xff, dest->len);
55 reftable_free(dest->data);
56}
57
58static void reftable_buf_close(void *b REFTABLE_UNUSED)
59{
60}
61
62static ssize_t reftable_buf_read_data(void *v, struct reftable_block_data *dest,
63 uint64_t off, uint32_t size)
64{
65 struct reftable_buf *b = v;
66 assert(off + size <= b->len);
67 REFTABLE_CALLOC_ARRAY(dest->data, size);
68 if (!dest->data)
69 return -1;
70 memcpy(dest->data, b->buf + off, size);
71 dest->len = size;
72 return size;
73}
74
75static uint64_t reftable_buf_size(void *b)
76{
77 return ((struct reftable_buf *)b)->len;
78}
79
80static struct reftable_block_source_vtable reftable_buf_vtable = {
81 .size = &reftable_buf_size,
82 .read_data = &reftable_buf_read_data,
83 .release_data = &reftable_buf_release_data,
84 .close = &reftable_buf_close,
85};
86
87void block_source_from_buf(struct reftable_block_source *bs,
88 struct reftable_buf *buf)
89{
90 assert(!bs->ops);
91 bs->ops = &reftable_buf_vtable;
92 bs->arg = buf;
93}
94
95struct file_block_source {
96 uint64_t size;
97 unsigned char *data;
98};
99
100static uint64_t file_size(void *b)
101{
102 return ((struct file_block_source *)b)->size;
103}
104
105static void file_release_data(void *b REFTABLE_UNUSED, struct reftable_block_data *dest REFTABLE_UNUSED)
106{
107}
108
109static void file_close(void *v)
110{
111 struct file_block_source *b = v;
112 munmap(b->data, b->size);
113 reftable_free(b);
114}
115
116static ssize_t file_read_data(void *v, struct reftable_block_data *dest, uint64_t off,
117 uint32_t size)
118{
119 struct file_block_source *b = v;
120 assert(off + size <= b->size);
121 dest->data = b->data + off;
122 dest->len = size;
123 return size;
124}
125
126static struct reftable_block_source_vtable file_vtable = {
127 .size = &file_size,
128 .read_data = &file_read_data,
129 .release_data = &file_release_data,
130 .close = &file_close,
131};
132
133int reftable_block_source_from_file(struct reftable_block_source *bs,
134 const char *name)
135{
136 struct file_block_source *p = NULL;
137 struct stat st;
138 int fd, err;
139
140 fd = open(name, O_RDONLY);
141 if (fd < 0) {
142 if (errno == ENOENT)
143 return REFTABLE_NOT_EXIST_ERROR;
144 err = -1;
145 goto out;
146 }
147
148 if (fstat(fd, &st) < 0) {
149 err = REFTABLE_IO_ERROR;
150 goto out;
151 }
152
153 REFTABLE_CALLOC_ARRAY(p, 1);
154 if (!p) {
155 err = REFTABLE_OUT_OF_MEMORY_ERROR;
156 goto out;
157 }
158
159 p->size = st.st_size;
160 p->data = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
161 if (p->data == MAP_FAILED) {
162 err = REFTABLE_IO_ERROR;
163 p->data = NULL;
164 goto out;
165 }
166
167 assert(!bs->ops);
168 bs->ops = &file_vtable;
169 bs->arg = p;
170
171 err = 0;
172
173out:
174 if (fd >= 0)
175 close(fd);
176 if (err < 0)
177 reftable_free(p);
178 return err;
179}