unix_io.c revision b5abe6fac9c9e7caf4710501d1657d30e4857ef6
13839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
23839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * unix_io.c --- This is the Unix I/O interface to the I/O manager.
33839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *
43839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Implements a one-block write-through cache.
53839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *
619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * Copyright (C) 1993, 1994, 1995 Theodore Ts'o.
719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o *
819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %Begin-Header%
919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * This file may be redistributed under the terms of the GNU Public
1019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * License.
1119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %End-Header%
123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <stdio.h>
153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <string.h>
164cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#if HAVE_UNISTD_H
173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <unistd.h>
184cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#endif
193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <fcntl.h>
203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <time.h>
211d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#if HAVE_SYS_STAT_H
223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/stat.h>
231d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#endif
241d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#if HAVE_SYS_TYPES_H
253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/types.h>
261d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#endif
273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
28b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#if EXT2_FLAT_INCLUDES
29b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#include "ext2_fs.h"
30b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#else
317b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o#include <linux/ext2_fs.h>
32b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#endif
337b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
347b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o#include "ext2fs.h"
353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
36f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o/*
37f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o * For checking structure magic numbers...
38f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o */
39f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
40f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#define EXT2_CHECK_MAGIC(struct, code) \
41f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	  if ((struct)->magic != (code)) return (code)
42f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostruct unix_private_data {
44f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	int	magic;
453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int	dev;
463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int	flags;
473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	char	*buf;
483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int	buf_block_nr;
493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o};
503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_open(const char *name, int flags, io_channel *channel);
523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel);
533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize);
543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_read_blk(io_channel channel, unsigned long block,
553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			       int count, void *data);
563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_write_blk(io_channel channel, unsigned long block,
573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				int count, const void *data);
583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel);
593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
60f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'ostatic struct struct_io_manager struct_unix_manager = {
61f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_ET_MAGIC_IO_MANAGER,
623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	"Unix I/O Manager",
633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_open,
643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_close,
653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_set_blksize,
663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_read_blk,
673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_write_blk,
683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_flush
693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o};
703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oio_manager unix_io_manager = &struct_unix_manager;
723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_open(const char *name, int flags, io_channel *channel)
743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io_channel	io = NULL;
763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data = NULL;
773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
7950e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	if (name == 0)
8050e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		return EXT2_ET_BAD_DEVICE_NAME;
817b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	retval = ext2fs_get_mem(sizeof(struct struct_io_channel),
827b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o				(void **) &io);
837b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
847b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		return retval;
85f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	memset(io, 0, sizeof(struct struct_io_channel));
86f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
877b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	retval = ext2fs_get_mem(sizeof(struct unix_private_data),
887b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o				(void **) &data);
897b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
917b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io->manager = unix_io_manager;
937b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	retval = ext2fs_get_mem(strlen(name)+1, (void **) &io->name);
947b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
967b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	strcpy(io->name, name);
983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io->private_data = data;
99f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->block_size = 1024;
100f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->read_error = 0;
101f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->write_error = 0;
102a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o	io->refcount = 1;
1033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	memset(data, 0, sizeof(struct unix_private_data));
105f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
1067b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	retval = ext2fs_get_mem(io->block_size, (void **) &data->buf);
1073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data->buf_block_nr = -1;
1087b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
1093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
1107b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
1113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data->dev = open(name, (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY);
1123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (data->dev < 0) {
1133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = errno;
1143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
1153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
1163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	*channel = io;
1173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
1183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ocleanup:
1203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (io)
1217b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		ext2fs_free_mem((void **) &io);
1223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (data) {
1233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (data->buf)
1247b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o			ext2fs_free_mem((void **) &data->buf);
1257b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		ext2fs_free_mem((void **) &data);
1263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
1273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
1283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
1293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel)
1313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
1323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
1333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval = 0;
1343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
135f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
1363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
137f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
138a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o
139a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o	if (--channel->refcount > 0)
140a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o		return 0;
141f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
1423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (close(data->dev) < 0)
1433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = errno;
1443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (data->buf)
1457b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		ext2fs_free_mem((void **) &data->buf);
1463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (channel->private_data)
1477b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		ext2fs_free_mem((void **) &channel->private_data);
1483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (channel->name)
1497b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		ext2fs_free_mem((void **) &channel->name);
1507b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	ext2fs_free_mem((void **) &channel);
1513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
1523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
1533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize)
1553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
1563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
1577b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	errcode_t		retval;
1583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
159f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
1603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
161f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
162f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
1633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (channel->block_size != blksize) {
1643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		channel->block_size = blksize;
1657b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		ext2fs_free_mem((void **) &data->buf);
1667b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		retval = ext2fs_get_mem(blksize, (void **) &data->buf);
1677b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		if (retval)
1687b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o			return retval;
1693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		data->buf_block_nr = -1;
1703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
1713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
1723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
1733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_read_blk(io_channel channel, unsigned long block,
1763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			       int count, void *buf)
1773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
1783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
1793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
1803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	size_t		size;
181f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	ext2_loff_t	location;
1823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int		actual = 0;
1833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
184f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
1853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
186f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
1873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
1893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 * If it's in the cache, use it!
1903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
1913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if ((count == 1) && (block == data->buf_block_nr)) {
1923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		memcpy(buf, data->buf, channel->block_size);
1933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 0;
1943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
195f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#if 0
196f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	printf("read_block %lu (%d)\n", block, count);
197f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#endif
1983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	size = (count < 0) ? -count : count * channel->block_size;
199f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	location = (ext2_loff_t) block * channel->block_size;
20019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
2015be8dc2143c7b3b21a9b8fb56797dd855ee87560Theodore Ts'o		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
2023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto error_out;
2033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
2043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	actual = read(data->dev, buf, size);
2053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (actual != size) {
2063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (actual < 0)
2073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			actual = 0;
2083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = EXT2_ET_SHORT_READ;
2093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto error_out;
2103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
2113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (count == 1) {
2123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		data->buf_block_nr = block;
2133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		memcpy(data->buf, buf, size);	/* Update the cache */
2143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
2153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
2163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
2173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oerror_out:
2183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	memset((char *) buf+actual, 0, size-actual);
2193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (channel->read_error)
2203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = (channel->read_error)(channel, block, count, buf,
2213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o					       size, actual, retval);
2223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
2233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
2243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
2253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_write_blk(io_channel channel, unsigned long block,
2263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				int count, const void *buf)
2273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
2283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
2293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	size_t		size;
230f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	ext2_loff_t	location;
2313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int		actual = 0;
2323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
2333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
234f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
2353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
236f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
2373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
2383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (count == 1)
2393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		size = channel->block_size;
2403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	else {
2413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		data->buf_block_nr = -1; 	/* Invalidate the cache */
2423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		if (count < 0)
2433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			size = -count;
2443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		else
2453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			size = count * channel->block_size;
2463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
247f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
248f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	location = (ext2_loff_t) block * channel->block_size;
24919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
2505be8dc2143c7b3b21a9b8fb56797dd855ee87560Theodore Ts'o		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
2513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto error_out;
2523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
2533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
2543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	actual = write(data->dev, buf, size);
2553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (actual != size) {
2563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = EXT2_ET_SHORT_WRITE;
2573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto error_out;
2583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
2593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
2603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if ((count == 1) && (block == data->buf_block_nr))
2613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		memcpy(data->buf, buf, size); /* Update the cache */
2623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
2633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
2643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
2653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oerror_out:
2663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (channel->write_error)
2673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = (channel->write_error)(channel, block, count, buf,
2683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o						size, actual, retval);
2693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
2703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
2713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
2723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
27336f21439f5d8b2233d13e042833d4d921a5c2c40Theodore Ts'o * Flush data buffers to disk.
2743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
2753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel)
2763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
277f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	struct unix_private_data *data;
278f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
279f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
280f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	data = (struct unix_private_data *) channel->private_data;
281f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
282f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
28336f21439f5d8b2233d13e042833d4d921a5c2c40Theodore Ts'o	fsync(data->dev);
2843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
2853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
2863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
287