summaryrefslogtreecommitdiffstats
path: root/lib/ext2fs/inode_io.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 15:49:25 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 15:49:25 +0000
commit464df1d5e5ab1322e2dd0a7796939fff1aeefa9a (patch)
tree6a403684e0978f0287d7f0ec0e5aab1fd31a59e1 /lib/ext2fs/inode_io.c
parentInitial commit. (diff)
downloade2fsprogs-464df1d5e5ab1322e2dd0a7796939fff1aeefa9a.tar.xz
e2fsprogs-464df1d5e5ab1322e2dd0a7796939fff1aeefa9a.zip
Adding upstream version 1.47.0.upstream/1.47.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'lib/ext2fs/inode_io.c')
-rw-r--r--lib/ext2fs/inode_io.c290
1 files changed, 290 insertions, 0 deletions
diff --git a/lib/ext2fs/inode_io.c b/lib/ext2fs/inode_io.c
new file mode 100644
index 0000000..d7474a6
--- /dev/null
+++ b/lib/ext2fs/inode_io.c
@@ -0,0 +1,290 @@
+/*
+ * inode_io.c --- This is allows an inode in an ext2 filesystem image
+ * to be accessed via the I/O manager interface.
+ *
+ * Copyright (C) 2002 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Library
+ * General Public License, version 2.
+ * %End-Header%
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <time.h>
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+/*
+ * For checking structure magic numbers...
+ */
+
+#define EXT2_CHECK_MAGIC(struct, code) \
+ if ((struct)->magic != (code)) return (code)
+
+struct inode_private_data {
+ int magic;
+ char name[32];
+ ext2_file_t file;
+ ext2_filsys fs;
+ ext2_ino_t ino;
+ struct ext2_inode inode;
+ int flags;
+ struct inode_private_data *next;
+};
+
+#define CHANNEL_HAS_INODE 0x8000
+
+static struct inode_private_data *top_intern;
+static int ino_unique = 0;
+
+static errcode_t inode_open(const char *name, int flags, io_channel *channel);
+static errcode_t inode_close(io_channel channel);
+static errcode_t inode_set_blksize(io_channel channel, int blksize);
+static errcode_t inode_read_blk(io_channel channel, unsigned long block,
+ int count, void *data);
+static errcode_t inode_write_blk(io_channel channel, unsigned long block,
+ int count, const void *data);
+static errcode_t inode_flush(io_channel channel);
+static errcode_t inode_write_byte(io_channel channel, unsigned long offset,
+ int size, const void *data);
+static errcode_t inode_read_blk64(io_channel channel,
+ unsigned long long block, int count, void *data);
+static errcode_t inode_write_blk64(io_channel channel,
+ unsigned long long block, int count, const void *data);
+
+static struct struct_io_manager struct_inode_manager = {
+ .magic = EXT2_ET_MAGIC_IO_MANAGER,
+ .name = "Inode I/O Manager",
+ .open = inode_open,
+ .close = inode_close,
+ .set_blksize = inode_set_blksize,
+ .read_blk = inode_read_blk,
+ .write_blk = inode_write_blk,
+ .flush = inode_flush,
+ .write_byte = inode_write_byte,
+ .read_blk64 = inode_read_blk64,
+ .write_blk64 = inode_write_blk64
+};
+
+io_manager inode_io_manager = &struct_inode_manager;
+
+errcode_t ext2fs_inode_io_intern2(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode *inode,
+ char **name)
+{
+ struct inode_private_data *data;
+ errcode_t retval;
+
+ if ((retval = ext2fs_get_mem(sizeof(struct inode_private_data),
+ &data)))
+ return retval;
+ data->magic = EXT2_ET_MAGIC_INODE_IO_CHANNEL;
+ sprintf(data->name, "%u:%d", ino, ino_unique++);
+ data->file = 0;
+ data->fs = fs;
+ data->ino = ino;
+ data->flags = 0;
+ if (inode) {
+ memcpy(&data->inode, inode, sizeof(struct ext2_inode));
+ data->flags |= CHANNEL_HAS_INODE;
+ }
+ data->next = top_intern;
+ top_intern = data;
+ *name = data->name;
+ return 0;
+}
+
+errcode_t ext2fs_inode_io_intern(ext2_filsys fs, ext2_ino_t ino,
+ char **name)
+{
+ return ext2fs_inode_io_intern2(fs, ino, NULL, name);
+}
+
+
+static errcode_t inode_open(const char *name, int flags, io_channel *channel)
+{
+ io_channel io = NULL;
+ struct inode_private_data *prev, *data = NULL;
+ errcode_t retval;
+ int open_flags;
+
+ if (name == 0)
+ return EXT2_ET_BAD_DEVICE_NAME;
+
+ for (data = top_intern, prev = NULL; data;
+ prev = data, data = data->next)
+ if (strcmp(name, data->name) == 0)
+ break;
+ if (!data)
+ return ENOENT;
+ if (prev)
+ prev->next = data->next;
+ else
+ top_intern = data->next;
+
+ retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
+ if (retval)
+ goto cleanup;
+ memset(io, 0, sizeof(struct struct_io_channel));
+
+ io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
+ io->manager = inode_io_manager;
+ retval = ext2fs_get_mem(strlen(name)+1, &io->name);
+ if (retval)
+ goto cleanup;
+
+ strcpy(io->name, name);
+ io->private_data = data;
+ io->block_size = 1024;
+ io->read_error = 0;
+ io->write_error = 0;
+ io->refcount = 1;
+
+ open_flags = (flags & IO_FLAG_RW) ? EXT2_FILE_WRITE : 0;
+ retval = ext2fs_file_open2(data->fs, data->ino,
+ (data->flags & CHANNEL_HAS_INODE) ?
+ &data->inode : 0, open_flags,
+ &data->file);
+ if (retval)
+ goto cleanup;
+
+ *channel = io;
+ return 0;
+
+cleanup:
+ if (io && io->name)
+ ext2fs_free_mem(&io->name);
+ if (data)
+ ext2fs_free_mem(&data);
+ if (io)
+ ext2fs_free_mem(&io);
+ return retval;
+}
+
+static errcode_t inode_close(io_channel channel)
+{
+ struct inode_private_data *data;
+ errcode_t retval = 0;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct inode_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
+
+ if (--channel->refcount > 0)
+ return 0;
+
+ retval = ext2fs_file_close(data->file);
+
+ ext2fs_free_mem(&channel->private_data);
+ if (channel->name)
+ ext2fs_free_mem(&channel->name);
+ ext2fs_free_mem(&channel);
+ return retval;
+}
+
+static errcode_t inode_set_blksize(io_channel channel, int blksize)
+{
+ struct inode_private_data *data;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct inode_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
+
+ channel->block_size = blksize;
+ return 0;
+}
+
+
+static errcode_t inode_read_blk64(io_channel channel,
+ unsigned long long block, int count, void *buf)
+{
+ struct inode_private_data *data;
+ errcode_t retval;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct inode_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
+
+ if ((retval = ext2fs_file_llseek(data->file,
+ (ext2_off64_t)(block * channel->block_size),
+ EXT2_SEEK_SET, 0)))
+ return retval;
+
+ count = (count < 0) ? -count : (count * channel->block_size);
+
+ return ext2fs_file_read(data->file, buf, count, 0);
+}
+
+static errcode_t inode_read_blk(io_channel channel, unsigned long block,
+ int count, void *buf)
+{
+ return inode_read_blk64(channel, block, count, buf);
+}
+
+static errcode_t inode_write_blk64(io_channel channel,
+ unsigned long long block, int count, const void *buf)
+{
+ struct inode_private_data *data;
+ errcode_t retval;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct inode_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
+
+ if ((retval = ext2fs_file_llseek(data->file,
+ (ext2_off64_t) (block * channel->block_size),
+ EXT2_SEEK_SET, 0)))
+ return retval;
+
+ count = (count < 0) ? -count : (count * channel->block_size);
+
+ return ext2fs_file_write(data->file, buf, count, 0);
+}
+
+static errcode_t inode_write_blk(io_channel channel, unsigned long block,
+ int count, const void *buf)
+{
+ return inode_write_blk64(channel, block, count, buf);
+}
+
+static errcode_t inode_write_byte(io_channel channel, unsigned long offset,
+ int size, const void *buf)
+{
+ struct inode_private_data *data;
+ errcode_t retval = 0;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct inode_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
+
+ if ((retval = ext2fs_file_lseek(data->file, offset,
+ EXT2_SEEK_SET, 0)))
+ return retval;
+
+ return ext2fs_file_write(data->file, buf, size, 0);
+}
+
+/*
+ * Flush data buffers to disk.
+ */
+static errcode_t inode_flush(io_channel channel)
+{
+ struct inode_private_data *data;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct inode_private_data *) channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
+
+ return ext2fs_file_flush(data->file);
+}
+