fileio.c revision 546a1ff18cc912003883ff67ba3e87c69f700fc4
1885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/*
2885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org * fileio.c --- Simple file I/O routines
3885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org *
4885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org * Copyright (C) 1997 Theodore Ts'o.
5885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org *
6885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org * %Begin-Header%
7885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org * This file may be redistributed under the terms of the GNU Public
8885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org * License.
9885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org * %End-Header%
10885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org */
11e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
12885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include <stdio.h>
13885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include <string.h>
14885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#if HAVE_UNISTD_H
15e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#include <unistd.h>
16885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#endif
17885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
18885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "ext2_fs.h"
19885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "ext2fs.h"
20885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
21885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgstruct ext2_file {
22885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	errcode_t		magic;
23885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	ext2_filsys 		fs;
24885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	ext2_ino_t		ino;
25885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	struct ext2_inode	inode;
26885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	int 			flags;
27885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	ext2_off_t		pos;
28885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	blk_t			blockno;
29885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	blk_t			physblock;
30885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	char 			*buf;
31885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org};
32885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
33e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#define BMAP_BUFFER (file->buf + fs->blocksize)
34885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
35885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgerrcode_t ext2fs_file_open(ext2_filsys fs, ext2_ino_t ino,
363c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com			   int flags, ext2_file_t *ret)
37885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
38885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	ext2_file_t 	file;
39885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	errcode_t	retval;
40885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
41885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	/*
42885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	 * Don't let caller create or open a file for writing if the
43885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	 * filesystem is read-only.
44885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	 */
45885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	if ((flags & (EXT2_FILE_WRITE | EXT2_FILE_CREATE)) &&
46885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	    !(fs->flags & EXT2_FLAG_RW))
47885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		return EXT2_ET_RO_FILSYS;
48885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
49885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	retval = ext2fs_get_mem(sizeof(struct ext2_file), (void **) &file);
50885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	if (retval)
51885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		return retval;
52885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
53885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	memset(file, 0, sizeof(struct ext2_file));
54885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	file->magic = EXT2_ET_MAGIC_EXT2_FILE;
55885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	file->fs = fs;
56885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	file->ino = ino;
57885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	file->flags = flags & EXT2_FILE_MASK;
58885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
59885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	retval = ext2fs_read_inode(fs, ino, &file->inode);
60885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	if (retval)
61885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		goto fail;
62885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
63885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	retval = ext2fs_get_mem(fs->blocksize * 3, (void **) &file->buf);
64885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	if (retval)
65885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		goto fail;
66885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
67885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	*ret = file;
68885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	return 0;
69885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
70885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgfail:
71885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	if (file->buf)
72885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		ext2fs_free_mem((void **) &file->buf);
73885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	ext2fs_free_mem((void **) &file);
74885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	return retval;
75885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
76885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
77885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/*
78885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org * This function returns the filesystem handle of a file from the structure
79885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org */
80885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgext2_filsys ext2fs_file_get_fs(ext2_file_t file)
81885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
82885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	if (file->magic != EXT2_ET_MAGIC_EXT2_FILE)
83885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		return 0;
84885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	return file->fs;
85885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
86e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
87e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org/*
88e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org * This function flushes the dirty block buffer out to disk if
89885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org * necessary.
90885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org */
91e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.orgerrcode_t ext2fs_file_flush(ext2_file_t file)
92885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
93885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	errcode_t	retval;
94885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	ext2_filsys fs;
95e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
96885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
97885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	fs = file->fs;
98e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
99885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	if (!(file->flags & EXT2_FILE_BUF_VALID) ||
100885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	    !(file->flags & EXT2_FILE_BUF_DIRTY))
101885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		return 0;
102885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
103885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	/*
104885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	 * OK, the physical block hasn't been allocated yet.
105885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	 * Allocate it.
106885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	 */
107885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	if (!file->physblock) {
108885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		retval = ext2fs_bmap(fs, file->ino, &file->inode,
109e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org				     BMAP_BUFFER, BMAP_ALLOC,
110e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org				     file->blockno, &file->physblock);
111e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org		if (retval)
112e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org			return retval;
113e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org	}
114e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
115e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org	retval = io_channel_write_blk(fs->io, file->physblock,
116e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org				      1, file->buf);
117e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org	if (retval)
118e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org		return retval;
119e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
120e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org	file->flags &= ~EXT2_FILE_BUF_DIRTY;
121e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
122e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org	return retval;
123e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org}
124e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
125e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org/*
126e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org * This function synchronizes the file's block buffer and the current
127885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org * file position, possibly invalidating block buffer if necessary
128e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org */
129e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.orgstatic errcode_t sync_buffer_position(ext2_file_t file)
130885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
131885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	blk_t	b;
132e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org	errcode_t	retval;
133e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
134885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	b = file->pos / file->fs->blocksize;
135885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	if (b != file->blockno) {
136e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org		retval = ext2fs_file_flush(file);
137e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org		if (retval)
138885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org			return retval;
139885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		file->flags &= ~EXT2_FILE_BUF_VALID;
140885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	}
141885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	file->blockno = b;
142e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org	return 0;
143e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org}
144885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
145e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org/*
146e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org * This function loads the file's block buffer with valid data from
147885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org * the disk as necessary.
148e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org *
149885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org * If dontfill is true, then skip initializing the buffer since we're
150885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org * going to be replacing its entire contents anyway.  If set, then the
151885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org * function basically only sets file->physblock and EXT2_FILE_BUF_VALID
152885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org */
153885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#define DONTFILL 1
154885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgstatic errcode_t load_buffer(ext2_file_t file, int dontfill)
155885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
156885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	ext2_filsys	fs = file->fs;
157885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	errcode_t	retval;
158885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
159885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	if (!(file->flags & EXT2_FILE_BUF_VALID)) {
160885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		retval = ext2fs_bmap(fs, file->ino, &file->inode,
161885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org				     BMAP_BUFFER, 0, file->blockno,
162885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org				     &file->physblock);
163885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		if (retval)
164885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org			return retval;
165885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		if (!dontfill) {
166885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org			if (file->physblock) {
167885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org				retval = io_channel_read_blk(fs->io,
168885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org							     file->physblock,
169885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org							     1, file->buf);
170e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org				if (retval)
171e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org					return retval;
172885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org			} else
173885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org				memset(file->buf, 0, fs->blocksize);
174885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		}
175885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		file->flags |= EXT2_FILE_BUF_VALID;
176885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	}
177885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	return 0;
178885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
179885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
180885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
181885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgerrcode_t ext2fs_file_close(ext2_file_t file)
182885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
183885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	errcode_t	retval;
184885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
185885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
186885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
187885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	retval = ext2fs_file_flush(file);
188885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
189885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	if (file->buf)
190885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		ext2fs_free_mem((void **) &file->buf);
191885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	ext2fs_free_mem((void **) &file);
192885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
193885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	return retval;
194885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
195885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
196885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
197885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgerrcode_t ext2fs_file_read(ext2_file_t file, void *buf,
198885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org			   unsigned int wanted, unsigned int *got)
199885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
200885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	ext2_filsys	fs;
201885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	errcode_t	retval = 0;
202885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	unsigned int	start, left, c, count = 0;
203885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	char		*ptr = (char *) buf;
204885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
205885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
206885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	fs = file->fs;
207885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
208885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	while ((file->pos < file->inode.i_size) && (wanted > 0)) {
209885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		retval = sync_buffer_position(file);
210885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		if (retval)
211885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org			goto fail;
212885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		retval = load_buffer(file, 0);
213885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		if (retval)
214885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org			goto fail;
215885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
216885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		start = file->pos % fs->blocksize;
217885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		c = fs->blocksize - start;
218885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		if (c > wanted)
219885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org			c = wanted;
220885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		left = file->inode.i_size - file->pos ;
221885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		if (c > left)
222885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org			c = left;
223885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
224885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		memcpy(ptr, file->buf+start, c);
225885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		file->pos += c;
226885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		ptr += c;
227885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		count += c;
228885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		wanted -= c;
229885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	}
230885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
231885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgfail:
232885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	if (got)
233885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		*got = count;
234885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	return retval;
235885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
236885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
237885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
238885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgerrcode_t ext2fs_file_write(ext2_file_t file, const void *buf,
239885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org			    unsigned int nbytes, unsigned int *written)
240885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
241885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	ext2_filsys	fs;
242885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	errcode_t	retval = 0;
243885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	unsigned int	start, c, count = 0;
244885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	const char	*ptr = (const char *) buf;
245885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
246885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
247885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	fs = file->fs;
248885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
249885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	if (!(file->flags & EXT2_FILE_WRITE))
250885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		return EXT2_ET_FILE_RO;
251885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
252885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	while (nbytes > 0) {
253885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		retval = sync_buffer_position(file);
254885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		if (retval)
255885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org			goto fail;
256885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
257885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		start = file->pos % fs->blocksize;
258885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		c = fs->blocksize - start;
259885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		if (c > nbytes)
260885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org			c = nbytes;
261885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
262885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		/*
263885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		 * We only need to do a read-modify-update cycle if
264885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		 * we're doing a partial write.
265885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		 */
266885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		retval = load_buffer(file, (c == fs->blocksize));
267885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		if (retval)
268885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org			goto fail;
269885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
270885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		file->flags |= EXT2_FILE_BUF_DIRTY;
271885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		memcpy(file->buf+start, ptr, c);
272885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		file->pos += c;
273885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		ptr += c;
274885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		count += c;
275885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		nbytes -= c;
276885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	}
277885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
278885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgfail:
279885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	if (written)
280885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		*written = count;
281885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	return retval;
282885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
283885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
284885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgerrcode_t ext2fs_file_lseek(ext2_file_t file, ext2_off_t offset,
285885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org			    int whence, ext2_off_t *ret_pos)
286885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
287885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
288885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
289885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	if (whence == EXT2_SEEK_SET)
290885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		file->pos = offset;
291885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	else if (whence == EXT2_SEEK_CUR)
292e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org		file->pos += offset;
293885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	else if (whence == EXT2_SEEK_END)
294885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		file->pos = file->inode.i_size + offset;
295885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	else
296885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		return EXT2_ET_INVALID_ARGUMENT;
297885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
298885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	if (ret_pos)
2993c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com		*ret_pos = file->pos;
300885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
301885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	return 0;
302885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
303885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
304885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/*
305885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org * This function returns the size of the file, according to the inode
306885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org */
307885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgext2_off_t ext2fs_file_get_size(ext2_file_t file)
308885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
309885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	if (file->magic != EXT2_ET_MAGIC_EXT2_FILE)
310885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		return 0;
311885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	return file->inode.i_size;
312885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
313885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
314885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/*
315885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org * This function sets the size of the file, truncating it if necessary
316885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org *
317885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org * XXX still need to call truncate
318885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org */
319885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgerrcode_t ext2fs_file_set_size(ext2_file_t file, ext2_off_t size)
320885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
321885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	errcode_t	retval;
322885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
323885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
324885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	file->inode.i_size = size;
325885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	retval = ext2fs_write_inode(file->fs, file->ino, &file->inode);
326885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	if (retval)
327885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org		return retval;
328885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
329885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	/*
330885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	 * XXX truncate inode if necessary
331885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	 */
332885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
333885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org	return 0;
334885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
335885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org