Many files:
Checkin of e2fsprogs 0.5b
diff --git a/lib/ext2fs/unix_io.c b/lib/ext2fs/unix_io.c
new file mode 100644
index 0000000..1137870
--- /dev/null
+++ b/lib/ext2fs/unix_io.c
@@ -0,0 +1,233 @@
+/*
+ * unix_io.c --- This is the Unix I/O interface to the I/O manager.
+ *
+ * Implements a one-block write-through cache.
+ *
+ * Copyright (C) 1993 Theodore Ts'o. This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "et/com_err.h"
+#include "ext2_err.h"
+#include "io.h"
+
+struct unix_private_data {
+ int dev;
+ int flags;
+ char *buf;
+ int buf_block_nr;
+};
+
+static errcode_t unix_open(const char *name, int flags, io_channel *channel);
+static errcode_t unix_close(io_channel channel);
+static errcode_t unix_set_blksize(io_channel channel, int blksize);
+static errcode_t unix_read_blk(io_channel channel, unsigned long block,
+ int count, void *data);
+static errcode_t unix_write_blk(io_channel channel, unsigned long block,
+ int count, const void *data);
+static errcode_t unix_flush(io_channel channel);
+
+struct struct_io_manager struct_unix_manager = {
+ "Unix I/O Manager",
+ unix_open,
+ unix_close,
+ unix_set_blksize,
+ unix_read_blk,
+ unix_write_blk,
+ unix_flush
+};
+
+io_manager unix_io_manager = &struct_unix_manager;
+
+static errcode_t unix_open(const char *name, int flags, io_channel *channel)
+{
+ io_channel io = NULL;
+ struct unix_private_data *data = NULL;
+ errcode_t retval;
+
+ io = (io_channel) malloc(sizeof(struct struct_io_channel));
+ if (!io)
+ return ENOMEM;
+ data = (struct unix_private_data *)
+ malloc(sizeof(struct unix_private_data));
+ if (!data) {
+ retval = ENOMEM;
+ goto cleanup;
+ }
+ io->manager = unix_io_manager;
+ io->name = malloc(strlen(name)+1);
+ if (!io->name) {
+ retval = ENOMEM;
+ goto cleanup;
+ }
+ strcpy(io->name, name);
+ io->private_data = data;
+
+ memset(data, 0, sizeof(struct unix_private_data));
+ io->block_size = 1024;
+ data->buf = malloc(io->block_size);
+ data->buf_block_nr = -1;
+ if (!data->buf) {
+ retval = ENOMEM;
+ goto cleanup;
+ }
+ data->dev = open(name, (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY);
+ if (data->dev < 0) {
+ retval = errno;
+ goto cleanup;
+ }
+ *channel = io;
+ return 0;
+
+cleanup:
+ if (io)
+ free(io);
+ if (data) {
+ if (data->buf)
+ free(data->buf);
+ free(data);
+ }
+ return retval;
+}
+
+static errcode_t unix_close(io_channel channel)
+{
+ struct unix_private_data *data;
+ errcode_t retval = 0;
+
+ data = (struct unix_private_data *) channel->private_data;
+ if (close(data->dev) < 0)
+ retval = errno;
+ if (data->buf)
+ free(data->buf);
+ if (channel->private_data)
+ free(channel->private_data);
+ if (channel->name)
+ free(channel->name);
+ free(channel);
+ return retval;
+}
+
+static errcode_t unix_set_blksize(io_channel channel, int blksize)
+{
+ struct unix_private_data *data;
+
+ data = (struct unix_private_data *) channel->private_data;
+ if (channel->block_size != blksize) {
+ channel->block_size = blksize;
+ free(data->buf);
+ data->buf = malloc(blksize);
+ if (!data->buf)
+ return ENOMEM;
+ data->buf_block_nr = -1;
+ }
+ return 0;
+}
+
+
+static errcode_t unix_read_blk(io_channel channel, unsigned long block,
+ int count, void *buf)
+{
+ struct unix_private_data *data;
+ errcode_t retval;
+ size_t size;
+ int actual = 0;
+
+ data = (struct unix_private_data *) channel->private_data;
+
+ /*
+ * If it's in the cache, use it!
+ */
+ if ((count == 1) && (block == data->buf_block_nr)) {
+ memcpy(buf, data->buf, channel->block_size);
+ return 0;
+ }
+ size = (count < 0) ? -count : count * channel->block_size;
+ if (lseek(data->dev, block * channel->block_size, SEEK_SET) !=
+ block * channel->block_size) {
+ retval = errno;
+ goto error_out;
+ }
+ actual = read(data->dev, buf, size);
+ if (actual != size) {
+ if (actual < 0)
+ actual = 0;
+ retval = EXT2_ET_SHORT_READ;
+ goto error_out;
+ }
+ if (count == 1) {
+ data->buf_block_nr = block;
+ memcpy(data->buf, buf, size); /* Update the cache */
+ }
+ return 0;
+
+error_out:
+ memset((char *) buf+actual, 0, size-actual);
+ if (channel->read_error)
+ retval = (channel->read_error)(channel, block, count, buf,
+ size, actual, retval);
+ return retval;
+}
+
+static errcode_t unix_write_blk(io_channel channel, unsigned long block,
+ int count, const void *buf)
+{
+ struct unix_private_data *data;
+ size_t size;
+ int actual = 0;
+ errcode_t retval;
+
+ data = (struct unix_private_data *) channel->private_data;
+
+ if (count == 1)
+ size = channel->block_size;
+ else {
+ data->buf_block_nr = -1; /* Invalidate the cache */
+ if (count < 0)
+ size = -count;
+ else
+ size = count * channel->block_size;
+ }
+
+ if (lseek(data->dev, block * channel->block_size, SEEK_SET) !=
+ block * channel->block_size) {
+ retval = errno;
+ goto error_out;
+ }
+
+ actual = write(data->dev, buf, size);
+ if (actual != size) {
+ retval = EXT2_ET_SHORT_WRITE;
+ goto error_out;
+ }
+
+ if ((count == 1) && (block == data->buf_block_nr))
+ memcpy(data->buf, buf, size); /* Update the cache */
+
+ return 0;
+
+error_out:
+ if (channel->write_error)
+ retval = (channel->write_error)(channel, block, count, buf,
+ size, actual, retval);
+ return retval;
+}
+
+/*
+ * Flush data buffers to disk. Since we are currently using a
+ * write-through cache, this is a no-op.
+ */
+static errcode_t unix_flush(io_channel channel)
+{
+ return 0;
+}
+