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