Raw
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
16 void 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
27 void 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
37 ssize_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
46 uint64_t block_source_size(struct reftable_block_source *source)
47 {
48 return source->ops->size(source->arg);
49 }
50
51 static 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
58 static void reftable_buf_close(void *b REFTABLE_UNUSED)
59 {
60 }
61
62 static 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
75 static uint64_t reftable_buf_size(void *b)
76 {
77 return ((struct reftable_buf *)b)->len;
78 }
79
80 static 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
87 void 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
95 struct file_block_source {
96 struct reftable_mmap mmap;
97 };
98
99 static uint64_t file_size(void *b)
100 {
101 return ((struct file_block_source *)b)->mmap.size;
102 }
103
104 static void file_release_data(void *b REFTABLE_UNUSED, struct reftable_block_data *dest REFTABLE_UNUSED)
105 {
106 }
107
108 static void file_close(void *v)
109 {
110 struct file_block_source *b = v;
111 reftable_munmap(&b->mmap);
112 reftable_free(b);
113 }
114
115 static ssize_t file_read_data(void *v, struct reftable_block_data *dest, uint64_t off,
116 uint32_t size)
117 {
118 struct file_block_source *b = v;
119 assert(off + size <= b->mmap.size);
120 dest->data = (unsigned char *) b->mmap.data + off;
121 dest->len = size;
122 return size;
123 }
124
125 static struct reftable_block_source_vtable file_vtable = {
126 .size = &file_size,
127 .read_data = &file_read_data,
128 .release_data = &file_release_data,
129 .close = &file_close,
130 };
131
132 int reftable_block_source_from_file(struct reftable_block_source *bs,
133 const char *name)
134 {
135 struct file_block_source *p = NULL;
136 struct stat st;
137 int fd, err;
138
139 fd = open(name, O_RDONLY);
140 if (fd < 0) {
141 if (errno == ENOENT)
142 return REFTABLE_NOT_EXIST_ERROR;
143 err = -1;
144 goto out;
145 }
146
147 if (fstat(fd, &st) < 0) {
148 err = REFTABLE_IO_ERROR;
149 goto out;
150 }
151
152 REFTABLE_CALLOC_ARRAY(p, 1);
153 if (!p) {
154 err = REFTABLE_OUT_OF_MEMORY_ERROR;
155 goto out;
156 }
157
158 err = reftable_mmap(&p->mmap, fd, st.st_size);
159 if (err < 0)
160 goto out;
161
162 assert(!bs->ops);
163 bs->ops = &file_vtable;
164 bs->arg = p;
165
166 err = 0;
167
168 out:
169 if (fd >= 0)
170 close(fd);
171 if (err < 0)
172 reftable_free(p);
173 return err;
174 }