Update Red Hat Copyright Notices
[nbdkit.git] / filters / ext2 / io.c
blob86c394409bdb0315c98913148f5e056c70396535
1 /* nbdkit
2 * Copyright Red Hat
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of Red Hat nor the names of its contributors may be
16 * used to endorse or promote products derived from this software without
17 * specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
33 /* Copies heavily from e2fsprogs lib/ext2fs/unix_io.c: */
36 * io.c --- This is an nbdkit filter implementation of the I/O manager.
38 * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
39 * 2002 by Theodore Ts'o.
41 * %Begin-Header%
42 * This file may be redistributed under the terms of the GNU Library
43 * General Public License, version 2.
44 * %End-Header%
47 #include <config.h>
49 #include <ext2_fs.h>
50 #include <ext2fs.h>
52 #include "io.h"
55 * For checking structure magic numbers...
58 #define EXT2_CHECK_MAGIC(struct, code) \
59 if ((struct)->magic != (code)) return (code)
61 struct io_private_data {
62 int magic;
63 nbdkit_next *next;
64 ext2_loff_t offset;
65 struct struct_io_stats io_stats;
68 static errcode_t
69 io_get_stats (io_channel channel, io_stats *stats)
71 errcode_t retval = 0;
73 struct io_private_data *data;
75 EXT2_CHECK_MAGIC (channel, EXT2_ET_MAGIC_IO_CHANNEL);
76 data = (struct io_private_data *) channel->private_data;
77 EXT2_CHECK_MAGIC (data, EXT2_ET_MAGIC_NBDKIT_IO_CHANNEL);
79 if (stats)
80 *stats = &data->io_stats;
82 return retval;
86 * Here are the raw I/O functions
88 static errcode_t
89 raw_read_blk (io_channel channel,
90 struct io_private_data *data,
91 unsigned long long block,
92 int count, void *bufv)
94 errcode_t retval;
95 ssize_t size;
96 ext2_loff_t location;
97 int actual = 0;
98 unsigned char *buf = bufv;
100 size = (count < 0) ? -count : (ext2_loff_t) count * channel->block_size;
101 data->io_stats.bytes_read += size;
102 location = ((ext2_loff_t) block * channel->block_size) + data->offset;
104 /* TODO is 32-bit overflow ever likely to be a problem? */
105 if (data->next->pread (data->next, buf, size, location, 0, &errno) == 0)
106 return 0;
108 retval = errno;
109 if (channel->read_error)
110 retval = (channel->read_error)(channel, block, count, buf,
111 size, actual, retval);
112 return retval;
115 static errcode_t
116 raw_write_blk (io_channel channel,
117 struct io_private_data *data,
118 unsigned long long block,
119 int count, const void *bufv)
121 ssize_t size;
122 ext2_loff_t location;
123 int actual = 0;
124 errcode_t retval;
125 const unsigned char *buf = bufv;
127 if (count == 1)
128 size = channel->block_size;
129 else {
130 if (count < 0)
131 size = -count;
132 else
133 size = (ext2_loff_t) count * channel->block_size;
135 data->io_stats.bytes_written += size;
137 location = ((ext2_loff_t) block * channel->block_size) + data->offset;
139 /* TODO is 32-bit overflow ever likely to be a problem? */
140 if (data->next->pwrite (data->next, buf, size, location, 0,
141 &errno) == 0)
142 return 0;
144 retval = errno;
145 if (channel->write_error)
146 retval = (channel->write_error)(channel, block, count, buf,
147 size, actual, retval);
148 return retval;
151 char *
152 nbdkit_io_encode (const nbdkit_next *next)
154 char *ret;
156 if (asprintf (&ret, "nbdkit:%p", next) < 0)
157 return NULL;
158 return ret;
162 nbdkit_io_decode (const char *name, nbdkit_next **next)
164 int n;
166 if (sscanf (name, "nbdkit:%p%n", next, &n) != 1 || n != strlen (name))
167 return -1;
168 return 0;
171 static errcode_t
172 io_open (const char *name, int flags,
173 io_channel *channel)
175 nbdkit_next *next;
176 io_channel io = NULL;
177 struct io_private_data *data = NULL;
178 errcode_t retval;
180 if (nbdkit_io_decode (name, &next) == -1)
181 return EXT2_ET_BAD_DEVICE_NAME;
183 retval = ext2fs_get_mem (sizeof (struct struct_io_channel), &io);
184 if (retval)
185 goto cleanup;
186 memset (io, 0, sizeof (struct struct_io_channel));
187 io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
188 retval = ext2fs_get_mem (sizeof (struct io_private_data), &data);
189 if (retval)
190 goto cleanup;
192 io->manager = nbdkit_io_manager;
193 retval = ext2fs_get_mem (strlen (name)+1, &io->name);
194 if (retval)
195 goto cleanup;
197 strcpy (io->name, name);
198 io->private_data = data;
199 io->block_size = 1024;
200 io->read_error = 0;
201 io->write_error = 0;
202 io->refcount = 1;
204 memset (data, 0, sizeof (struct io_private_data));
205 data->magic = EXT2_ET_MAGIC_NBDKIT_IO_CHANNEL;
206 data->io_stats.num_fields = 2;
207 data->next = next;
209 /* Too bad NBD doesn't tell us if next->trim guarantees read as zero. */
210 /* if (next-> XXX (...)
211 io->flags |= CHANNEL_FLAGS_DISCARD_ZEROES; */
213 if (flags & IO_FLAG_RW && next->can_write (next) != 1) {
214 retval = EPERM;
215 goto cleanup;
217 *channel = io;
218 return 0;
220 cleanup:
221 if (data)
222 ext2fs_free_mem (&data);
223 if (io) {
224 if (io->name) {
225 ext2fs_free_mem (&io->name);
227 ext2fs_free_mem (&io);
229 return retval;
232 static errcode_t
233 io_close (io_channel channel)
235 struct io_private_data *data;
236 errcode_t retval = 0;
238 EXT2_CHECK_MAGIC (channel, EXT2_ET_MAGIC_IO_CHANNEL);
239 data = (struct io_private_data *) channel->private_data;
240 EXT2_CHECK_MAGIC (data, EXT2_ET_MAGIC_NBDKIT_IO_CHANNEL);
242 if (--channel->refcount > 0)
243 return 0;
245 ext2fs_free_mem (&channel->private_data);
246 if (channel->name)
247 ext2fs_free_mem (&channel->name);
248 ext2fs_free_mem (&channel);
249 return retval;
252 static errcode_t
253 io_set_blksize (io_channel channel, int blksize)
255 struct io_private_data *data;
257 EXT2_CHECK_MAGIC (channel, EXT2_ET_MAGIC_IO_CHANNEL);
258 data = (struct io_private_data *) channel->private_data;
259 EXT2_CHECK_MAGIC (data, EXT2_ET_MAGIC_NBDKIT_IO_CHANNEL);
261 channel->block_size = blksize;
262 return 0;
265 static errcode_t
266 io_read_blk64 (io_channel channel, unsigned long long block,
267 int count, void *buf)
269 struct io_private_data *data;
271 EXT2_CHECK_MAGIC (channel, EXT2_ET_MAGIC_IO_CHANNEL);
272 data = (struct io_private_data *) channel->private_data;
273 EXT2_CHECK_MAGIC (data, EXT2_ET_MAGIC_NBDKIT_IO_CHANNEL);
275 return raw_read_blk (channel, data, block, count, buf);
278 static errcode_t
279 io_read_blk (io_channel channel, unsigned long block,
280 int count, void *buf)
282 return io_read_blk64 (channel, block, count, buf);
285 static errcode_t
286 io_write_blk64 (io_channel channel, unsigned long long block,
287 int count, const void *buf)
289 struct io_private_data *data;
291 EXT2_CHECK_MAGIC (channel, EXT2_ET_MAGIC_IO_CHANNEL);
292 data = (struct io_private_data *) channel->private_data;
293 EXT2_CHECK_MAGIC (data, EXT2_ET_MAGIC_NBDKIT_IO_CHANNEL);
295 return raw_write_blk (channel, data, block, count, buf);
298 #ifdef HAVE_STRUCT_STRUCT_IO_MANAGER_CACHE_READAHEAD
299 static errcode_t
300 io_cache_readahead (io_channel channel,
301 unsigned long long block,
302 unsigned long long count)
304 struct io_private_data *data;
306 EXT2_CHECK_MAGIC (channel, EXT2_ET_MAGIC_IO_CHANNEL);
307 data = (struct io_private_data *)channel->private_data;
308 EXT2_CHECK_MAGIC (data, EXT2_ET_MAGIC_NBDKIT_IO_CHANNEL);
310 if (data->next->can_cache (data->next) == NBDKIT_CACHE_NATIVE) {
311 /* TODO is 32-bit overflow ever likely to be a problem? */
312 if (data->next->cache (data->next,
313 (ext2_loff_t)count * channel->block_size,
314 ((ext2_loff_t)block * channel->block_size +
315 data->offset),
316 0, &errno) == -1)
317 return errno;
318 return 0;
321 return EXT2_ET_OP_NOT_SUPPORTED;
323 #endif
325 static errcode_t
326 io_write_blk (io_channel channel, unsigned long block,
327 int count, const void *buf)
329 return io_write_blk64 (channel, block, count, buf);
332 static errcode_t
333 io_write_byte (io_channel channel, unsigned long offset,
334 int size, const void *buf)
336 struct io_private_data *data;
338 EXT2_CHECK_MAGIC (channel, EXT2_ET_MAGIC_IO_CHANNEL);
339 data = (struct io_private_data *) channel->private_data;
340 EXT2_CHECK_MAGIC (data, EXT2_ET_MAGIC_NBDKIT_IO_CHANNEL);
342 if (data->next->pwrite (data->next, buf, size,
343 offset + data->offset, 0, &errno) == -1)
344 return errno;
346 return 0;
350 * Flush data buffers to disk.
352 static errcode_t
353 io_flush (io_channel channel)
355 struct io_private_data *data;
356 errcode_t retval = 0;
358 EXT2_CHECK_MAGIC (channel, EXT2_ET_MAGIC_IO_CHANNEL);
359 data = (struct io_private_data *) channel->private_data;
360 EXT2_CHECK_MAGIC (data, EXT2_ET_MAGIC_NBDKIT_IO_CHANNEL);
362 if (data->next->can_flush (data->next) == 1)
363 if (data->next->flush (data->next, 0, &errno) == -1)
364 return errno;
365 return retval;
368 static errcode_t
369 io_set_option (io_channel channel, const char *option,
370 const char *arg)
372 struct io_private_data *data;
373 unsigned long long tmp;
374 char *end;
376 EXT2_CHECK_MAGIC (channel, EXT2_ET_MAGIC_IO_CHANNEL);
377 data = (struct io_private_data *) channel->private_data;
378 EXT2_CHECK_MAGIC (data, EXT2_ET_MAGIC_NBDKIT_IO_CHANNEL);
380 if (!strcmp (option, "offset")) {
381 if (!arg)
382 return EXT2_ET_INVALID_ARGUMENT;
384 tmp = strtoull (arg, &end, 0);
385 if (*end)
386 return EXT2_ET_INVALID_ARGUMENT;
387 data->offset = tmp;
388 if (data->offset < 0)
389 return EXT2_ET_INVALID_ARGUMENT;
390 return 0;
392 return EXT2_ET_INVALID_ARGUMENT;
395 static errcode_t
396 io_discard (io_channel channel, unsigned long long block,
397 unsigned long long count)
399 struct io_private_data *data;
401 EXT2_CHECK_MAGIC (channel, EXT2_ET_MAGIC_IO_CHANNEL);
402 data = (struct io_private_data *) channel->private_data;
403 EXT2_CHECK_MAGIC (data, EXT2_ET_MAGIC_NBDKIT_IO_CHANNEL);
405 if (data->next->can_trim (data->next) == 1) {
406 /* TODO is 32-bit overflow ever likely to be a problem? */
407 if (data->next->trim (data->next,
408 (off_t)(count) * channel->block_size,
409 ((off_t)(block) * channel->block_size +
410 data->offset),
411 0, &errno) == 0)
412 return 0;
413 if (errno == EOPNOTSUPP)
414 goto unimplemented;
415 return errno;
418 unimplemented:
419 return EXT2_ET_UNIMPLEMENTED;
422 #ifdef HAVE_STRUCT_STRUCT_IO_MANAGER_ZEROOUT
423 static errcode_t
424 io_zeroout (io_channel channel, unsigned long long block,
425 unsigned long long count)
427 struct io_private_data *data;
429 EXT2_CHECK_MAGIC (channel, EXT2_ET_MAGIC_IO_CHANNEL);
430 data = (struct io_private_data *) channel->private_data;
431 EXT2_CHECK_MAGIC (data, EXT2_ET_MAGIC_NBDKIT_IO_CHANNEL);
433 if (data->next->can_zero (data->next) > NBDKIT_ZERO_NONE) {
434 /* TODO is 32-bit overflow ever likely to be a problem? */
435 if (data->next->zero (data->next,
436 (off_t)(count) * channel->block_size,
437 ((off_t)(block) * channel->block_size +
438 data->offset),
439 NBDKIT_FLAG_MAY_TRIM, &errno) == 0)
440 return 0;
441 if (errno == EOPNOTSUPP)
442 goto unimplemented;
443 return errno;
446 unimplemented:
447 return EXT2_ET_UNIMPLEMENTED;
449 #endif
451 static struct struct_io_manager struct_nbdkit_manager = {
452 .magic = EXT2_ET_MAGIC_IO_MANAGER,
453 .name = "nbdkit I/O Manager",
454 .open = io_open,
455 .close = io_close,
456 .set_blksize = io_set_blksize,
457 .read_blk = io_read_blk,
458 .write_blk = io_write_blk,
459 .flush = io_flush,
460 .write_byte = io_write_byte,
461 .set_option = io_set_option,
462 .get_stats = io_get_stats,
463 .read_blk64 = io_read_blk64,
464 .write_blk64 = io_write_blk64,
465 .discard = io_discard,
466 #ifdef HAVE_STRUCT_STRUCT_IO_MANAGER_CACHE_READAHEAD
467 .cache_readahead = io_cache_readahead,
468 #endif
469 #ifdef HAVE_STRUCT_STRUCT_IO_MANAGER_ZEROOUT
470 .zeroout = io_zeroout,
471 #endif
474 io_manager nbdkit_io_manager = &struct_nbdkit_manager;