unix_io.c revision fa6c653ec3117dd689c8adb4ea2ebfc10f8cdd4a
13839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
2fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o * unix_io.c --- This is the Unix (well, really POSIX) implementation
3fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o * 	of the I/O manager.
43839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *
53839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Implements a one-block write-through cache.
63839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *
7fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o * Includes support for Windows NT support under Cygwin.
8fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o *
964e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
1064e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o * 	2002 by Theodore Ts'o.
1119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o *
1219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %Begin-Header%
1319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * This file may be redistributed under the terms of the GNU Public
1419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * License.
1519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %End-Header%
163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
18dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#define _LARGEFILE_SOURCE
19dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#define _LARGEFILE64_SOURCE
20dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o
213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <stdio.h>
223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <string.h>
234cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#if HAVE_UNISTD_H
243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <unistd.h>
254cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#endif
26c4e749abd8451f02418fe552b2af14f226f7bd1eTheodore Ts'o#if HAVE_ERRNO_H
27c4e749abd8451f02418fe552b2af14f226f7bd1eTheodore Ts'o#include <errno.h>
28c4e749abd8451f02418fe552b2af14f226f7bd1eTheodore Ts'o#endif
293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <fcntl.h>
303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <time.h>
31f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#ifdef __linux__
32f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#include <sys/utsname.h>
33f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#endif
341d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#if HAVE_SYS_STAT_H
353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/stat.h>
361d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#endif
371d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#if HAVE_SYS_TYPES_H
383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/types.h>
391d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#endif
40fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#if HAVE_SYS_RESOURCE_H
418880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o#include <sys/resource.h>
42fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#endif
433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
44b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#include "ext2_fs.h"
457b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o#include "ext2fs.h"
463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
47f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o/*
48f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o * For checking structure magic numbers...
49f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o */
50f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
51f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#define EXT2_CHECK_MAGIC(struct, code) \
52f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	  if ((struct)->magic != (code)) return (code)
53adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
54adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostruct unix_cache {
55adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	char		*buf;
56adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	unsigned long	block;
57adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		access_time;
5883e692e88bf2d01edb089010bdfc07b7dcc78642Matthias Andree	unsigned	dirty:1;
5983e692e88bf2d01edb089010bdfc07b7dcc78642Matthias Andree	unsigned	in_use:1;
60adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o};
61adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
62adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#define CACHE_SIZE 8
6382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o#define WRITE_DIRECT_SIZE 4	/* Must be smaller than CACHE_SIZE */
6482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o#define READ_DIRECT_SIZE 4	/* Should be smaller than CACHE_SIZE */
65adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostruct unix_private_data {
67f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	int	magic;
683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int	dev;
693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int	flags;
70adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int	access_time;
712e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	ext2_loff_t offset;
72adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache cache[CACHE_SIZE];
733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o};
743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_open(const char *name, int flags, io_channel *channel);
763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel);
773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize);
783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_read_blk(io_channel channel, unsigned long block,
793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			       int count, void *data);
803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_write_blk(io_channel channel, unsigned long block,
813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				int count, const void *data);
823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel);
83c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'ostatic errcode_t unix_write_byte(io_channel channel, unsigned long offset,
84c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o				int size, const void *data);
852e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'ostatic errcode_t unix_set_option(io_channel channel, const char *option,
862e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o				 const char *arg);
873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
8823b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'ostatic void reuse_cache(io_channel channel, struct unix_private_data *data,
8923b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'o		 struct unix_cache *cache, unsigned long block);
9023b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'o
91289e0557c24c68290b6d9b73b09674447801fdacMatthias Andree/* __FreeBSD_kernel__ is defined by GNU/kFreeBSD - the FreeBSD kernel
92289e0557c24c68290b6d9b73b09674447801fdacMatthias Andree * does not know buffered block devices - everything is raw. */
93289e0557c24c68290b6d9b73b09674447801fdacMatthias Andree#if defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
94b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#define NEED_BOUNCE_BUFFER
95b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#else
96b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#undef NEED_BOUNCE_BUFFER
97b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#endif
98b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree
99f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'ostatic struct struct_io_manager struct_unix_manager = {
100f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_ET_MAGIC_IO_MANAGER,
1013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	"Unix I/O Manager",
1023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_open,
1033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_close,
1043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_set_blksize,
1053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_read_blk,
1063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_write_blk,
107c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	unix_flush,
108b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#ifdef NEED_BOUNCE_BUFFER
1092e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	0,
110fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#else
1112e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	unix_write_byte,
112fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#endif
1132e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	unix_set_option
1143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o};
1153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oio_manager unix_io_manager = &struct_unix_manager;
1173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
118adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
119adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Here are the raw I/O functions
120adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
121b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#ifndef NEED_BOUNCE_BUFFER
122adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t raw_read_blk(io_channel channel,
123adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			      struct unix_private_data *data,
124adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			      unsigned long block,
125adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			      int count, void *buf)
126adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
127adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t	retval;
128544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	ssize_t		size;
129adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	ext2_loff_t	location;
130adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		actual = 0;
131adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
132adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	size = (count < 0) ? -count : count * channel->block_size;
1332e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	location = ((ext2_loff_t) block * channel->block_size) + data->offset;
134adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
135adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
136adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
137adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
138adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	actual = read(data->dev, buf, size);
139adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (actual != size) {
140adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (actual < 0)
141adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			actual = 0;
142adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = EXT2_ET_SHORT_READ;
143adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
144adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
145adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return 0;
146adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
147adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'oerror_out:
148adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	memset((char *) buf+actual, 0, size-actual);
149adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (channel->read_error)
150adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = (channel->read_error)(channel, block, count, buf,
151adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o					       size, actual, retval);
152adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval;
153adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
154b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#else /* NEED_BOUNCE_BUFFER */
155fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o/*
156b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree * Windows and FreeBSD block devices only allow sector alignment IO in offset and size
157fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o */
158fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'ostatic errcode_t raw_read_blk(io_channel channel,
159fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o			      struct unix_private_data *data,
160fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o			      unsigned long block,
161fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o			      int count, void *buf)
162fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o{
163fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	errcode_t	retval;
164fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	size_t		size, alignsize, fragment;
165fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	ext2_loff_t	location;
166fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	int		total = 0, actual;
167fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#define BLOCKALIGN 512
168fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	char		sector[BLOCKALIGN];
169fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o
170fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	size = (count < 0) ? -count : count * channel->block_size;
1712e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	location = ((ext2_loff_t) block * channel->block_size) + data->offset;
172fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#ifdef DEBUG
173fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	printf("count=%d, size=%d, block=%d, blk_size=%d, location=%lx\n",
174fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	 		count, size, block, channel->block_size, location);
175fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#endif
176fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
177fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
178fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		goto error_out;
179fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	}
180fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	fragment = size % BLOCKALIGN;
181fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	alignsize = size - fragment;
182fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	if (alignsize) {
183fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		actual = read(data->dev, buf, alignsize);
184fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		if (actual != alignsize)
185fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o			goto short_read;
186fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	}
187fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	if (fragment) {
188fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		actual = read(data->dev, sector, BLOCKALIGN);
189fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		if (actual != BLOCKALIGN)
190fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o			goto short_read;
191fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		memcpy(buf+alignsize, sector, fragment);
192fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	}
193fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	return 0;
194fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o
195fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'oshort_read:
196fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	if (actual>0)
197fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		total += actual;
198fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	retval = EXT2_ET_SHORT_READ;
199fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o
200fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'oerror_out:
201fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	memset((char *) buf+total, 0, size-actual);
202fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	if (channel->read_error)
203fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		retval = (channel->read_error)(channel, block, count, buf,
204fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o					       size, actual, retval);
205fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	return retval;
206fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o}
207fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#endif
208adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
209adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t raw_write_blk(io_channel channel,
210adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			       struct unix_private_data *data,
211adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			       unsigned long block,
212adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			       int count, const void *buf)
213adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
214544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	ssize_t		size;
215adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	ext2_loff_t	location;
216adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		actual = 0;
217adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t	retval;
218adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
219adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (count == 1)
220adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		size = channel->block_size;
221adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	else {
222adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (count < 0)
223adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			size = -count;
224adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		else
225adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			size = count * channel->block_size;
226adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
227adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
2282e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	location = ((ext2_loff_t) block * channel->block_size) + data->offset;
229adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
230adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
231adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
232adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
233adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
234adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	actual = write(data->dev, buf, size);
235adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (actual != size) {
236adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = EXT2_ET_SHORT_WRITE;
237adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
238adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
239adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return 0;
240adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
241adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'oerror_out:
242adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (channel->write_error)
243adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = (channel->write_error)(channel, block, count, buf,
244adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o						size, actual, retval);
245adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval;
246adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
247adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
248adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
249adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
250adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Here we implement the cache functions
251adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
252adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
253adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* Allocate the cache buffers */
254adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t alloc_cache(io_channel channel,
255adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			     struct unix_private_data *data)
256adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
257adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t		retval;
258adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache	*cache;
259adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
260adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
261adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	data->access_time = 0;
262adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
263adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->block = 0;
264adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->access_time = 0;
265adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->dirty = 0;
266adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->in_use = 0;
267adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = ext2fs_get_mem(channel->block_size,
268c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o					     &cache->buf)))
269adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
270adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
271adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return 0;
272adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
273adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
274adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* Free the cache buffers */
275544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'ostatic void free_cache(struct unix_private_data *data)
276adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
277adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache	*cache;
278adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
279adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
280adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	data->access_time = 0;
281adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
282adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->block = 0;
283adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->access_time = 0;
284adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->dirty = 0;
285adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->in_use = 0;
286adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (cache->buf)
287c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o			ext2fs_free_mem(&cache->buf);
288adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->buf = 0;
289adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
290adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
291adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
292b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
293adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
29482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * Try to find a block in the cache.  If the block is not found, and
29582c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * eldest is a non-zero pointer, then fill in eldest with the cache
29682c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * entry to that should be reused.
297adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
298544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'ostatic struct unix_cache *find_cached_block(struct unix_private_data *data,
29931dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o					    unsigned long block,
30082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o					    struct unix_cache **eldest)
301adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
30231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	struct unix_cache	*cache, *unused_cache, *oldest_cache;
303adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
304adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
30531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	unused_cache = oldest_cache = 0;
306adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
307adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache->in_use) {
30882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			if (!unused_cache)
30982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o				unused_cache = cache;
310adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
311adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
312adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (cache->block == block) {
313adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			cache->access_time = ++data->access_time;
314adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return cache;
315adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
316adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!oldest_cache ||
317adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		    (cache->access_time < oldest_cache->access_time))
318adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			oldest_cache = cache;
319adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
32082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (eldest)
32182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		*eldest = (unused_cache) ? unused_cache : oldest_cache;
32282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	return 0;
32382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o}
32482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o
32582c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o/*
32682c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * Reuse a particular cache entry for another block.
32782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o */
32823b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'ostatic void reuse_cache(io_channel channel, struct unix_private_data *data,
32982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		 struct unix_cache *cache, unsigned long block)
33082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o{
33182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (cache->dirty && cache->in_use)
33282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		raw_write_blk(channel, data, cache->block, 1, cache->buf);
33382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o
334adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	cache->in_use = 1;
3351d47dfb91ef010c506e9354dec102385d8494d8fTheodore Ts'o	cache->dirty = 0;
336adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	cache->block = block;
337adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	cache->access_time = ++data->access_time;
338adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
339adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
340adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
341adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Flush all of the blocks in the cache
342adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
343adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t flush_cached_blocks(io_channel channel,
344adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				     struct unix_private_data *data,
345adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				     int invalidate)
346adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
347adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
348adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache	*cache;
349adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t		retval, retval2;
350adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
351adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
352adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	retval2 = 0;
353adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
354adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache->in_use)
355adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
356adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
357adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (invalidate)
358adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			cache->in_use = 0;
359adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
360adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache->dirty)
361adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
362adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
363adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = raw_write_blk(channel, data,
364adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				       cache->block, 1, cache->buf);
365adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (retval)
366adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			retval2 = retval;
367adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		else
368adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			cache->dirty = 0;
369adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
370adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval2;
371adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
372b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif /* NO_IO_CACHE */
373adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
3743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_open(const char *name, int flags, io_channel *channel)
3753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
3763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io_channel	io = NULL;
3773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data = NULL;
3783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
379dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o	int		open_flags;
3808880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	struct stat	st;
381f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#ifdef __linux__
382f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	struct 		utsname ut;
383f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#endif
3843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
38550e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	if (name == 0)
38650e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		return EXT2_ET_BAD_DEVICE_NAME;
387c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
3887b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
3897b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		return retval;
390f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	memset(io, 0, sizeof(struct struct_io_channel));
391f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
392c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	retval = ext2fs_get_mem(sizeof(struct unix_private_data), &data);
3937b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
3943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
3957b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
3963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io->manager = unix_io_manager;
397c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	retval = ext2fs_get_mem(strlen(name)+1, &io->name);
3987b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
3993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
4007b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
4013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	strcpy(io->name, name);
4023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io->private_data = data;
403f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->block_size = 1024;
404f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->read_error = 0;
405f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->write_error = 0;
406a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o	io->refcount = 1;
4073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	memset(data, 0, sizeof(struct unix_private_data));
409f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
4107b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
411adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if ((retval = alloc_cache(io, data)))
412adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto cleanup;
4132e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o
414dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o	open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY;
415fa6c653ec3117dd689c8adb4ea2ebfc10f8cdd4aTheodore Ts'o	if (flags & IO_FLAG_EXCLUSIVE)
416fa6c653ec3117dd689c8adb4ea2ebfc10f8cdd4aTheodore Ts'o		open_flags |= O_EXCL;
417dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#ifdef HAVE_OPEN64
4182e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	data->dev = open64(io->name, open_flags);
419dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#else
4202e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	data->dev = open(io->name, open_flags);
421dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#endif
4223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (data->dev < 0) {
4233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = errno;
4243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
4253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
42664e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o
42764e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#ifdef __linux__
42864e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#undef RLIM_INFINITY
42964e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#if (defined(__alpha__) || ((defined(__sparc__) || defined(__mips__)) && (SIZEOF_LONG == 4)))
43064e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#define RLIM_INFINITY	((unsigned long)(~0UL>>1))
43164e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#else
43264e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#define RLIM_INFINITY  (~0UL)
43364e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#endif
4348880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	/*
435f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * Work around a bug in 2.4.10-2.4.18 kernels where writes to
436f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * block devices are wrongly getting hit by the filesize
437f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * limit.  This workaround isn't perfect, since it won't work
438f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * if glibc wasn't built against 2.2 header files.  (Sigh.)
439f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 *
4408880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	 */
441f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	if ((flags & IO_FLAG_RW) &&
442f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	    (uname(&ut) == 0) &&
443f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	    ((ut.release[0] == '2') && (ut.release[1] == '.') &&
444f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	     (ut.release[2] == '4') && (ut.release[3] == '.') &&
445f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	     (ut.release[4] == '1') && (ut.release[5] >= '0') &&
446f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	     (ut.release[5] < '8')) &&
4478880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	    (fstat(data->dev, &st) == 0) &&
4488880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	    (S_ISBLK(st.st_mode))) {
4498880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		struct rlimit	rlim;
4508880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o
45164e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o		rlim.rlim_cur = rlim.rlim_max = (unsigned long) RLIM_INFINITY;
4528880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		setrlimit(RLIMIT_FSIZE, &rlim);
4538880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		getrlimit(RLIMIT_FSIZE, &rlim);
454bd27880b4ba42544f30a08ac3b6ba86190da021bTheodore Ts'o		if (((unsigned long) rlim.rlim_cur) <
455bd27880b4ba42544f30a08ac3b6ba86190da021bTheodore Ts'o		    ((unsigned long) rlim.rlim_max)) {
4568880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o			rlim.rlim_cur = rlim.rlim_max;
4578880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o			setrlimit(RLIMIT_FSIZE, &rlim);
4588880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		}
4598880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	}
46064e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#endif
4613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	*channel = io;
4623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
4633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ocleanup:
4653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (data) {
466544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		free_cache(data);
467c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		ext2fs_free_mem(&data);
4683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
469adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (io)
470c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		ext2fs_free_mem(&io);
4713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
4723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
4733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel)
4753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
4763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
4773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval = 0;
4783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
479f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
4803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
481f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
482a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o
483a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o	if (--channel->refcount > 0)
484a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o		return 0;
485adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
486b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
487adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	retval = flush_cached_blocks(channel, data, 0);
488b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif
489adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
4903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (close(data->dev) < 0)
4913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = errno;
492544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	free_cache(data);
493f12e285ffd9ff0b37c4f91d5ab2b021ed1eb43beTheodore Ts'o
494c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	ext2fs_free_mem(&channel->private_data);
4953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (channel->name)
496c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		ext2fs_free_mem(&channel->name);
497c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	ext2fs_free_mem(&channel);
4983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
4993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
5003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize)
5023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
5033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
5047b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	errcode_t		retval;
5053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
506f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
5073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
508f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
509f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
5103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (channel->block_size != blksize) {
511b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
512adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = flush_cached_blocks(channel, data, 0)))
513adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
514b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif
515adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
5163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		channel->block_size = blksize;
517544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		free_cache(data);
518adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = alloc_cache(channel, data)))
5197b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o			return retval;
5203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
5213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
5223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
5233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_read_blk(io_channel channel, unsigned long block,
5263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			       int count, void *buf)
5273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
5283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
52982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	struct unix_cache *cache, *reuse[READ_DIRECT_SIZE];
5303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
53131dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	char		*cp;
532adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		i, j;
5333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
534f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
5353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
536f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
5373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
538b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifdef NO_IO_CACHE
539b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o	return raw_read_blk(channel, data, block, count, buf);
540b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#else
5413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
54282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	 * If we're doing an odd-sized read or a very large read,
54382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	 * flush out the cache and then do a direct read.
5443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
54582c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (count < 0 || count > WRITE_DIRECT_SIZE) {
546adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = flush_cached_blocks(channel, data, 0)))
547adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
548adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		return raw_read_blk(channel, data, block, count, buf);
5493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
550adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
55131dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	cp = buf;
552adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	while (count > 0) {
553adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		/* If it's in the cache, use it! */
554544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		if ((cache = find_cached_block(data, block, &reuse[0]))) {
555adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG
556adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			printf("Using cached block %d\n", block);
557f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#endif
55831dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			memcpy(cp, cache->buf, channel->block_size);
559adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			count--;
560adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			block++;
56131dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			cp += channel->block_size;
562adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
563adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
564adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		/*
565adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		 * Find the number of uncached blocks so we can do a
566adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		 * single read request
567adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		 */
568adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		for (i=1; i < count; i++)
569544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			if (find_cached_block(data, block+i, &reuse[i]))
570adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				break;
571adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG
572adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		printf("Reading %d blocks starting at %d\n", i, block);
573adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#endif
57431dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o		if ((retval = raw_read_blk(channel, data, block, i, cp)))
575adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
576adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
577adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		/* Save the results in the cache */
578adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		for (j=0; j < i; j++) {
579adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			count--;
58082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			cache = reuse[j];
58182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			reuse_cache(channel, data, cache, block++);
58282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			memcpy(cache->buf, cp, channel->block_size);
58331dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			cp += channel->block_size;
584adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
5853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
5863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
587b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif /* NO_IO_CACHE */
5883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
5893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_write_blk(io_channel channel, unsigned long block,
5913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				int count, const void *buf)
5923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
5933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
59482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	struct unix_cache *cache, *reuse;
59523b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'o	errcode_t	retval = 0;
59631dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	const char	*cp;
59731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	int		writethrough;
5983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
599f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
6003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
601f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
6023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
603b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifdef NO_IO_CACHE
604b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o	return raw_write_blk(channel, data, block, count, buf);
605b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#else
606adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	/*
607adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * If we're doing an odd-sized write or a very large write,
608adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * flush out the cache completely and then do a direct write.
609adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 */
61082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (count < 0 || count > WRITE_DIRECT_SIZE) {
611adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = flush_cached_blocks(channel, data, 1)))
612adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
613adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		return raw_write_blk(channel, data, block, count, buf);
6143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
6153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
616adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	/*
617adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * For a moderate-sized multi-block write, first force a write
618adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * if we're in write-through cache mode, and then fill the
619adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * cache with the blocks.
620adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 */
621adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	writethrough = channel->flags & CHANNEL_FLAGS_WRITETHROUGH;
622adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (writethrough)
623adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = raw_write_blk(channel, data, block, count, buf);
6243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
62531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	cp = buf;
626adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	while (count > 0) {
627544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		cache = find_cached_block(data, block, &reuse);
628adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache) {
62982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			cache = reuse;
63082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			reuse_cache(channel, data, cache, block);
631adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
63282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		memcpy(cache->buf, cp, channel->block_size);
63382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		cache->dirty = !writethrough;
634adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		count--;
635adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		block++;
63631dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o		cp += channel->block_size;
637adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
6383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
639b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif /* NO_IO_CACHE */
6403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
6413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
642c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'ostatic errcode_t unix_write_byte(io_channel channel, unsigned long offset,
643c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o				 int size, const void *buf)
644c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o{
645c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	struct unix_private_data *data;
64631dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	errcode_t	retval = 0;
647544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	ssize_t		actual;
648c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
649c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
650c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	data = (struct unix_private_data *) channel->private_data;
651c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
652c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
653b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
654c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	/*
655c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	 * Flush out the cache completely
656c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	 */
657c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	if ((retval = flush_cached_blocks(channel, data, 1)))
658c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o		return retval;
659b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif
660c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
6612e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	if (lseek(data->dev, offset + data->offset, SEEK_SET) < 0)
662c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o		return errno;
663c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
664c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	actual = write(data->dev, buf, size);
665c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	if (actual != size)
666c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o		return EXT2_ET_SHORT_WRITE;
667c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
668c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	return 0;
669c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o}
670c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
6713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
67236f21439f5d8b2233d13e042833d4d921a5c2c40Theodore Ts'o * Flush data buffers to disk.
6733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
6743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel)
6753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
676f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	struct unix_private_data *data;
677adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t retval = 0;
678f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
679f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
680f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	data = (struct unix_private_data *) channel->private_data;
681f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
682adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
683b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
684adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	retval = flush_cached_blocks(channel, data, 0);
685b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif
68636f21439f5d8b2233d13e042833d4d921a5c2c40Theodore Ts'o	fsync(data->dev);
687adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval;
6883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
6893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6902e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'ostatic errcode_t unix_set_option(io_channel channel, const char *option,
6912e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o				 const char *arg)
6922e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o{
6932e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	struct unix_private_data *data;
6942e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	unsigned long tmp;
6952e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	char *end;
6962e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o
6972e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
6982e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
6992e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
7002e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o
7012e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	if (!strcmp(option, "offset")) {
7022e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o		if (!arg)
7032e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o			return EXT2_ET_INVALID_ARGUMENT;
7042e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o
7052e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o		tmp = strtoul(arg, &end, 0);
7062e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o		if (*end)
7072e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o			return EXT2_ET_INVALID_ARGUMENT;
7082e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o		data->offset = tmp;
7092e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o		return 0;
7102e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	}
7112e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	return EXT2_ET_INVALID_ARGUMENT;
7122e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o}
713