unix_io.c revision 544349270e4c74a6feb971123884a8cf5052a7ee
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;
58adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		dirty:1;
59adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		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;
71adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache cache[CACHE_SIZE];
723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o};
733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_open(const char *name, int flags, io_channel *channel);
753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel);
763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize);
773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_read_blk(io_channel channel, unsigned long block,
783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			       int count, void *data);
793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_write_blk(io_channel channel, unsigned long block,
803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				int count, const void *data);
813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel);
82c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'ostatic errcode_t unix_write_byte(io_channel channel, unsigned long offset,
83c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o				int size, const void *data);
843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
8523b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'ostatic void reuse_cache(io_channel channel, struct unix_private_data *data,
8623b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'o		 struct unix_cache *cache, unsigned long block);
8723b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'o
88f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'ostatic struct struct_io_manager struct_unix_manager = {
89f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_ET_MAGIC_IO_MANAGER,
903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	"Unix I/O Manager",
913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_open,
923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_close,
933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_set_blksize,
943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_read_blk,
953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_write_blk,
96c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	unix_flush,
97a85e81a2ff4fb1afc05ff74d5da573031c3495e0Theodore Ts'o#ifdef __CYGWIN__
98fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	0
99fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#else
100c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	unix_write_byte
101fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#endif
1023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o};
1033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oio_manager unix_io_manager = &struct_unix_manager;
1053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
106adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
107adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Here are the raw I/O functions
108adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
109a85e81a2ff4fb1afc05ff74d5da573031c3495e0Theodore Ts'o#ifndef __CYGWIN__
110adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t raw_read_blk(io_channel channel,
111adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			      struct unix_private_data *data,
112adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			      unsigned long block,
113adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			      int count, void *buf)
114adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
115adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t	retval;
116544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	ssize_t		size;
117adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	ext2_loff_t	location;
118adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		actual = 0;
119adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
120adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	size = (count < 0) ? -count : count * channel->block_size;
121adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	location = (ext2_loff_t) block * channel->block_size;
122adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
123adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
124adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
125adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
126adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	actual = read(data->dev, buf, size);
127adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (actual != size) {
128adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (actual < 0)
129adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			actual = 0;
130adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = EXT2_ET_SHORT_READ;
131adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
132adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
133adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return 0;
134adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
135adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'oerror_out:
136adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	memset((char *) buf+actual, 0, size-actual);
137adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (channel->read_error)
138adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = (channel->read_error)(channel, block, count, buf,
139adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o					       size, actual, retval);
140adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval;
141adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
142a85e81a2ff4fb1afc05ff74d5da573031c3495e0Theodore Ts'o#else /* __CYGWIN__ */
143fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o/*
144fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o * Windows block devices only allow sector alignment IO in offset and size
145fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o */
146fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'ostatic errcode_t raw_read_blk(io_channel channel,
147fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o			      struct unix_private_data *data,
148fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o			      unsigned long block,
149fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o			      int count, void *buf)
150fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o{
151fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	errcode_t	retval;
152fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	size_t		size, alignsize, fragment;
153fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	ext2_loff_t	location;
154fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	int		total = 0, actual;
155fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#define BLOCKALIGN 512
156fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	char		sector[BLOCKALIGN];
157fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o
158fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	size = (count < 0) ? -count : count * channel->block_size;
159fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	location = (ext2_loff_t) block * channel->block_size;
160fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#ifdef DEBUG
161fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	printf("count=%d, size=%d, block=%d, blk_size=%d, location=%lx\n",
162fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	 		count, size, block, channel->block_size, location);
163fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#endif
164fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
165fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
166fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		goto error_out;
167fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	}
168fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	fragment = size % BLOCKALIGN;
169fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	alignsize = size - fragment;
170fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	if (alignsize) {
171fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		actual = read(data->dev, buf, alignsize);
172fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		if (actual != alignsize)
173fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o			goto short_read;
174fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	}
175fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	if (fragment) {
176fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		actual = read(data->dev, sector, BLOCKALIGN);
177fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		if (actual != BLOCKALIGN)
178fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o			goto short_read;
179fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		memcpy(buf+alignsize, sector, fragment);
180fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	}
181fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	return 0;
182fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o
183fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'oshort_read:
184fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	if (actual>0)
185fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		total += actual;
186fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	retval = EXT2_ET_SHORT_READ;
187fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o
188fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'oerror_out:
189fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	memset((char *) buf+total, 0, size-actual);
190fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	if (channel->read_error)
191fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		retval = (channel->read_error)(channel, block, count, buf,
192fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o					       size, actual, retval);
193fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	return retval;
194fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o}
195fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#endif
196adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
197adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t raw_write_blk(io_channel channel,
198adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			       struct unix_private_data *data,
199adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			       unsigned long block,
200adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			       int count, const void *buf)
201adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
202544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	ssize_t		size;
203adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	ext2_loff_t	location;
204adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		actual = 0;
205adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t	retval;
206adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
207adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (count == 1)
208adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		size = channel->block_size;
209adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	else {
210adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (count < 0)
211adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			size = -count;
212adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		else
213adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			size = count * channel->block_size;
214adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
215adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
216adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	location = (ext2_loff_t) block * channel->block_size;
217adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
218adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
219adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
220adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
221adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
222adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	actual = write(data->dev, buf, size);
223adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (actual != size) {
224adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = EXT2_ET_SHORT_WRITE;
225adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
226adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
227adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return 0;
228adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
229adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'oerror_out:
230adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (channel->write_error)
231adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = (channel->write_error)(channel, block, count, buf,
232adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o						size, actual, retval);
233adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval;
234adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
235adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
236adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
237adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
238adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Here we implement the cache functions
239adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
240adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
241adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* Allocate the cache buffers */
242adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t alloc_cache(io_channel channel,
243adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			     struct unix_private_data *data)
244adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
245adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t		retval;
246adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache	*cache;
247adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
248adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
249adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	data->access_time = 0;
250adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
251adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->block = 0;
252adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->access_time = 0;
253adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->dirty = 0;
254adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->in_use = 0;
255adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = ext2fs_get_mem(channel->block_size,
256c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o					     &cache->buf)))
257adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
258adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
259adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return 0;
260adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
261adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
262adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* Free the cache buffers */
263544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'ostatic void free_cache(struct unix_private_data *data)
264adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
265adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache	*cache;
266adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
267adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
268adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	data->access_time = 0;
269adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
270adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->block = 0;
271adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->access_time = 0;
272adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->dirty = 0;
273adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->in_use = 0;
274adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (cache->buf)
275c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o			ext2fs_free_mem(&cache->buf);
276adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->buf = 0;
277adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
278adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
279adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
280b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
281adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
28282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * Try to find a block in the cache.  If the block is not found, and
28382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * eldest is a non-zero pointer, then fill in eldest with the cache
28482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * entry to that should be reused.
285adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
286544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'ostatic struct unix_cache *find_cached_block(struct unix_private_data *data,
28731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o					    unsigned long block,
28882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o					    struct unix_cache **eldest)
289adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
29031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	struct unix_cache	*cache, *unused_cache, *oldest_cache;
291adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
292adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
29331dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	unused_cache = oldest_cache = 0;
294adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
295adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache->in_use) {
29682c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			if (!unused_cache)
29782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o				unused_cache = cache;
298adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
299adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
300adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (cache->block == block) {
301adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			cache->access_time = ++data->access_time;
302adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return cache;
303adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
304adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!oldest_cache ||
305adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		    (cache->access_time < oldest_cache->access_time))
306adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			oldest_cache = cache;
307adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
30882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (eldest)
30982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		*eldest = (unused_cache) ? unused_cache : oldest_cache;
31082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	return 0;
31182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o}
31282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o
31382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o/*
31482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * Reuse a particular cache entry for another block.
31582c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o */
31623b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'ostatic void reuse_cache(io_channel channel, struct unix_private_data *data,
31782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		 struct unix_cache *cache, unsigned long block)
31882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o{
31982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (cache->dirty && cache->in_use)
32082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		raw_write_blk(channel, data, cache->block, 1, cache->buf);
32182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o
322adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	cache->in_use = 1;
3231d47dfb91ef010c506e9354dec102385d8494d8fTheodore Ts'o	cache->dirty = 0;
324adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	cache->block = block;
325adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	cache->access_time = ++data->access_time;
326adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
327adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
328adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
329adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Flush all of the blocks in the cache
330adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
331adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t flush_cached_blocks(io_channel channel,
332adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				     struct unix_private_data *data,
333adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				     int invalidate)
334adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
335adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
336adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache	*cache;
337adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t		retval, retval2;
338adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
339adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
340adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	retval2 = 0;
341adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
342adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache->in_use)
343adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
344adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
345adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (invalidate)
346adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			cache->in_use = 0;
347adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
348adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache->dirty)
349adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
350adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
351adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = raw_write_blk(channel, data,
352adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				       cache->block, 1, cache->buf);
353adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (retval)
354adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			retval2 = retval;
355adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		else
356adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			cache->dirty = 0;
357adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
358adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval2;
359adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
360b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif /* NO_IO_CACHE */
361adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
3623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_open(const char *name, int flags, io_channel *channel)
3633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
3643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io_channel	io = NULL;
3653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data = NULL;
3663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
367dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o	int		open_flags;
3688880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	struct stat	st;
369f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#ifdef __linux__
370f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	struct 		utsname ut;
371f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#endif
3723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
37350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	if (name == 0)
37450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		return EXT2_ET_BAD_DEVICE_NAME;
375c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
3767b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
3777b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		return retval;
378f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	memset(io, 0, sizeof(struct struct_io_channel));
379f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
380c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	retval = ext2fs_get_mem(sizeof(struct unix_private_data), &data);
3817b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
3823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
3837b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
3843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io->manager = unix_io_manager;
385c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	retval = ext2fs_get_mem(strlen(name)+1, &io->name);
3867b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
3873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
3887b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
3893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	strcpy(io->name, name);
3903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io->private_data = data;
391f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->block_size = 1024;
392f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->read_error = 0;
393f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->write_error = 0;
394a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o	io->refcount = 1;
3953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	memset(data, 0, sizeof(struct unix_private_data));
397f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
3987b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
399adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if ((retval = alloc_cache(io, data)))
400adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto cleanup;
401adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
402dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o	open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY;
403dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#ifdef HAVE_OPEN64
404dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o	data->dev = open64(name, open_flags);
405dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#else
406dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o	data->dev = open(name, open_flags);
407dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#endif
4083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (data->dev < 0) {
4093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = errno;
4103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
4113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
41264e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o
41364e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#ifdef __linux__
41464e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#undef RLIM_INFINITY
41564e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#if (defined(__alpha__) || ((defined(__sparc__) || defined(__mips__)) && (SIZEOF_LONG == 4)))
41664e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#define RLIM_INFINITY	((unsigned long)(~0UL>>1))
41764e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#else
41864e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#define RLIM_INFINITY  (~0UL)
41964e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#endif
4208880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	/*
421f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * Work around a bug in 2.4.10-2.4.18 kernels where writes to
422f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * block devices are wrongly getting hit by the filesize
423f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * limit.  This workaround isn't perfect, since it won't work
424f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * if glibc wasn't built against 2.2 header files.  (Sigh.)
425f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 *
4268880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	 */
427f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	if ((flags & IO_FLAG_RW) &&
428f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	    (uname(&ut) == 0) &&
429f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	    ((ut.release[0] == '2') && (ut.release[1] == '.') &&
430f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	     (ut.release[2] == '4') && (ut.release[3] == '.') &&
431f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	     (ut.release[4] == '1') && (ut.release[5] >= '0') &&
432f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	     (ut.release[5] < '8')) &&
4338880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	    (fstat(data->dev, &st) == 0) &&
4348880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	    (S_ISBLK(st.st_mode))) {
4358880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		struct rlimit	rlim;
4368880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o
43764e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o		rlim.rlim_cur = rlim.rlim_max = (unsigned long) RLIM_INFINITY;
4388880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		setrlimit(RLIMIT_FSIZE, &rlim);
4398880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		getrlimit(RLIMIT_FSIZE, &rlim);
440bd27880b4ba42544f30a08ac3b6ba86190da021bTheodore Ts'o		if (((unsigned long) rlim.rlim_cur) <
441bd27880b4ba42544f30a08ac3b6ba86190da021bTheodore Ts'o		    ((unsigned long) rlim.rlim_max)) {
4428880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o			rlim.rlim_cur = rlim.rlim_max;
4438880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o			setrlimit(RLIMIT_FSIZE, &rlim);
4448880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		}
4458880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	}
44664e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#endif
4473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	*channel = io;
4483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
4493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ocleanup:
4513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (data) {
452544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		free_cache(data);
453c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		ext2fs_free_mem(&data);
4543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
455adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (io)
456c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		ext2fs_free_mem(&io);
4573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
4583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
4593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel)
4613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
4623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
4633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval = 0;
4643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
465f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
4663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
467f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
468a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o
469a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o	if (--channel->refcount > 0)
470a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o		return 0;
471adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
472b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
473adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	retval = flush_cached_blocks(channel, data, 0);
474b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif
475adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
4763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (close(data->dev) < 0)
4773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = errno;
478544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	free_cache(data);
479f12e285ffd9ff0b37c4f91d5ab2b021ed1eb43beTheodore Ts'o
480c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	ext2fs_free_mem(&channel->private_data);
4813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (channel->name)
482c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		ext2fs_free_mem(&channel->name);
483c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	ext2fs_free_mem(&channel);
4843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
4853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
4863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize)
4883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
4893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
4907b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	errcode_t		retval;
4913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
492f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
4933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
494f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
495f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
4963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (channel->block_size != blksize) {
497b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
498adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = flush_cached_blocks(channel, data, 0)))
499adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
500b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif
501adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
5023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		channel->block_size = blksize;
503544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		free_cache(data);
504adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = alloc_cache(channel, data)))
5057b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o			return retval;
5063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
5073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
5083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
5093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_read_blk(io_channel channel, unsigned long block,
5123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			       int count, void *buf)
5133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
5143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
51582c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	struct unix_cache *cache, *reuse[READ_DIRECT_SIZE];
5163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
51731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	char		*cp;
518adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		i, j;
5193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
520f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
5213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
522f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
5233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
524b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifdef NO_IO_CACHE
525b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o	return raw_read_blk(channel, data, block, count, buf);
526b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#else
5273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
52882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	 * If we're doing an odd-sized read or a very large read,
52982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	 * flush out the cache and then do a direct read.
5303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
53182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (count < 0 || count > WRITE_DIRECT_SIZE) {
532adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = flush_cached_blocks(channel, data, 0)))
533adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
534adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		return raw_read_blk(channel, data, block, count, buf);
5353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
536adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
53731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	cp = buf;
538adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	while (count > 0) {
539adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		/* If it's in the cache, use it! */
540544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		if ((cache = find_cached_block(data, block, &reuse[0]))) {
541adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG
542adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			printf("Using cached block %d\n", block);
543f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#endif
54431dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			memcpy(cp, cache->buf, channel->block_size);
545adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			count--;
546adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			block++;
54731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			cp += channel->block_size;
548adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
549adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
550adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		/*
551adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		 * Find the number of uncached blocks so we can do a
552adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		 * single read request
553adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		 */
554adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		for (i=1; i < count; i++)
555544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			if (find_cached_block(data, block+i, &reuse[i]))
556adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				break;
557adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG
558adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		printf("Reading %d blocks starting at %d\n", i, block);
559adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#endif
56031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o		if ((retval = raw_read_blk(channel, data, block, i, cp)))
561adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
562adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
563adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		/* Save the results in the cache */
564adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		for (j=0; j < i; j++) {
565adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			count--;
56682c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			cache = reuse[j];
56782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			reuse_cache(channel, data, cache, block++);
56882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			memcpy(cache->buf, cp, channel->block_size);
56931dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			cp += channel->block_size;
570adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
5713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
5723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
573b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif /* NO_IO_CACHE */
5743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
5753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_write_blk(io_channel channel, unsigned long block,
5773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				int count, const void *buf)
5783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
5793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
58082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	struct unix_cache *cache, *reuse;
58123b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'o	errcode_t	retval = 0;
58231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	const char	*cp;
58331dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	int		writethrough;
5843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
585f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
5863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
587f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
5883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
589b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifdef NO_IO_CACHE
590b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o	return raw_write_blk(channel, data, block, count, buf);
591b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#else
592adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	/*
593adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * If we're doing an odd-sized write or a very large write,
594adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * flush out the cache completely and then do a direct write.
595adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 */
59682c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (count < 0 || count > WRITE_DIRECT_SIZE) {
597adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = flush_cached_blocks(channel, data, 1)))
598adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
599adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		return raw_write_blk(channel, data, block, count, buf);
6003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
6013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
602adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	/*
603adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * For a moderate-sized multi-block write, first force a write
604adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * if we're in write-through cache mode, and then fill the
605adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * cache with the blocks.
606adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 */
607adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	writethrough = channel->flags & CHANNEL_FLAGS_WRITETHROUGH;
608adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (writethrough)
609adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = raw_write_blk(channel, data, block, count, buf);
6103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
61131dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	cp = buf;
612adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	while (count > 0) {
613544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		cache = find_cached_block(data, block, &reuse);
614adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache) {
61582c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			cache = reuse;
61682c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			reuse_cache(channel, data, cache, block);
617adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
61882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		memcpy(cache->buf, cp, channel->block_size);
61982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		cache->dirty = !writethrough;
620adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		count--;
621adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		block++;
62231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o		cp += channel->block_size;
623adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
6243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
625b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif /* NO_IO_CACHE */
6263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
6273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
628c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'ostatic errcode_t unix_write_byte(io_channel channel, unsigned long offset,
629c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o				 int size, const void *buf)
630c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o{
631c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	struct unix_private_data *data;
63231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	errcode_t	retval = 0;
633544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	ssize_t		actual;
634c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
635c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
636c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	data = (struct unix_private_data *) channel->private_data;
637c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
638c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
639b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
640c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	/*
641c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	 * Flush out the cache completely
642c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	 */
643c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	if ((retval = flush_cached_blocks(channel, data, 1)))
644c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o		return retval;
645b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif
646c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
647c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	if (lseek(data->dev, offset, SEEK_SET) < 0)
648c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o		return errno;
649c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
650c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	actual = write(data->dev, buf, size);
651c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	if (actual != size)
652c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o		return EXT2_ET_SHORT_WRITE;
653c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
654c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	return 0;
655c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o}
656c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
6573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
65836f21439f5d8b2233d13e042833d4d921a5c2c40Theodore Ts'o * Flush data buffers to disk.
6593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
6603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel)
6613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
662f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	struct unix_private_data *data;
663adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t retval = 0;
664f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
665f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
666f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	data = (struct unix_private_data *) channel->private_data;
667f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
668adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
669b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
670adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	retval = flush_cached_blocks(channel, data, 0);
671b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif
67236f21439f5d8b2233d13e042833d4d921a5c2c40Theodore Ts'o	fsync(data->dev);
673adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval;
6743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
6753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
676