blob: d876cd19ccf3598a39304cbf3e60e057ac2f048a [file] [log] [blame]
Theodore Ts'o30fab291997-10-25 22:37:42 +00001/*
2 * fileio.c --- Simple file I/O routines
3 *
4 * Copyright (C) 1997 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#include <string.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
Theodore Ts'o30fab291997-10-25 22:37:42 +000017
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000018#if EXT2_FLAT_INCLUDES
19#include "ext2_fs.h"
20#else
Theodore Ts'o30fab291997-10-25 22:37:42 +000021#include <linux/ext2_fs.h>
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000022#endif
Theodore Ts'o30fab291997-10-25 22:37:42 +000023
24#include "ext2fs.h"
25
26struct ext2_file {
27 errcode_t magic;
28 ext2_filsys fs;
Theodore Ts'o31dbecd2001-01-11 04:54:39 +000029 ext2_ino_t ino;
Theodore Ts'o30fab291997-10-25 22:37:42 +000030 struct ext2_inode inode;
31 int flags;
32 ext2_off_t pos;
33 blk_t blockno;
34 blk_t physblock;
35 char *buf;
36};
37
Theodore Ts'o31dbecd2001-01-11 04:54:39 +000038errcode_t ext2fs_file_open(ext2_filsys fs, ext2_ino_t ino,
Theodore Ts'o30fab291997-10-25 22:37:42 +000039 int flags, ext2_file_t *ret)
40{
41 ext2_file_t file;
42 errcode_t retval;
43
44 /*
45 * Don't let caller create or open a file for writing if the
46 * filesystem is read-only.
47 */
48 if ((flags & (EXT2_FILE_WRITE | EXT2_FILE_CREATE)) &&
49 !(fs->flags & EXT2_FLAG_RW))
50 return EXT2_ET_RO_FILSYS;
51
Theodore Ts'o7b4e4531997-10-26 03:41:24 +000052 retval = ext2fs_get_mem(sizeof(struct ext2_file), (void **) &file);
53 if (retval)
54 return retval;
Theodore Ts'o30fab291997-10-25 22:37:42 +000055
56 memset(file, 0, sizeof(struct ext2_file));
57 file->magic = EXT2_ET_MAGIC_EXT2_FILE;
58 file->fs = fs;
59 file->ino = ino;
60 file->flags = flags & EXT2_FILE_MASK;
61
62 retval = ext2fs_read_inode(fs, ino, &file->inode);
63 if (retval)
64 goto fail;
65
Theodore Ts'oa4bf69d1999-05-29 21:53:30 +000066 retval = ext2fs_get_mem(fs->blocksize * 2, (void **) &file->buf);
Theodore Ts'o7b4e4531997-10-26 03:41:24 +000067 if (retval)
Theodore Ts'o30fab291997-10-25 22:37:42 +000068 goto fail;
Theodore Ts'o30fab291997-10-25 22:37:42 +000069
70 *ret = file;
71 return 0;
72
73fail:
74 if (file->buf)
Theodore Ts'o7b4e4531997-10-26 03:41:24 +000075 ext2fs_free_mem((void **) &file->buf);
76 ext2fs_free_mem((void **) &file);
Theodore Ts'o30fab291997-10-25 22:37:42 +000077 return retval;
78}
79
80/*
Theodore Ts'o79a90bd1997-11-03 19:16:55 +000081 * This function returns the filesystem handle of a file from the structure
82 */
83ext2_filsys ext2fs_file_get_fs(ext2_file_t file)
84{
85 if (file->magic != EXT2_ET_MAGIC_EXT2_FILE)
86 return 0;
87 return file->fs;
88}
89
90/*
Theodore Ts'o30fab291997-10-25 22:37:42 +000091 * This function flushes the dirty block buffer out to disk if
92 * necessary.
93 */
94static errcode_t ext2fs_file_flush(ext2_file_t file)
95{
96 errcode_t retval;
97
98 EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
99
100 if (!(file->flags & EXT2_FILE_BUF_VALID) ||
101 !(file->flags & EXT2_FILE_BUF_DIRTY))
102 return 0;
103
104 /*
105 * OK, the physical block hasn't been allocated yet.
106 * Allocate it.
107 */
108 if (!file->physblock) {
109 retval = ext2fs_bmap(file->fs, file->ino, &file->inode,
110 file->buf, BMAP_ALLOC,
111 file->blockno, &file->physblock);
112 if (retval)
113 return retval;
114 }
115
116 retval = io_channel_write_blk(file->fs->io, file->physblock,
117 1, file->buf);
118 if (retval)
119 return retval;
120
121 file->flags &= ~EXT2_FILE_BUF_DIRTY;
122
123 return retval;
124}
125
126errcode_t ext2fs_file_close(ext2_file_t file)
127{
128 errcode_t retval;
129
130 EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
131
132 retval = ext2fs_file_flush(file);
133
134 if (file->buf)
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000135 ext2fs_free_mem((void **) &file->buf);
136 ext2fs_free_mem((void **) &file);
Theodore Ts'o30fab291997-10-25 22:37:42 +0000137
138 return retval;
139}
140
141
142errcode_t ext2fs_file_read(ext2_file_t file, void *buf,
Theodore Ts'o79a90bd1997-11-03 19:16:55 +0000143 unsigned int wanted, unsigned int *got)
Theodore Ts'o30fab291997-10-25 22:37:42 +0000144{
145 ext2_filsys fs;
146 errcode_t retval;
147 blk_t b, pb;
Theodore Ts'o79a90bd1997-11-03 19:16:55 +0000148 unsigned int start, left, c, count = 0;
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000149 char *ptr = (char *) buf;
Theodore Ts'o30fab291997-10-25 22:37:42 +0000150
151 EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
152 fs = file->fs;
153
154again:
155 if (file->pos >= file->inode.i_size)
156 goto done;
157
158 b = file->pos / fs->blocksize;
159 if (b != file->blockno) {
160 retval = ext2fs_file_flush(file);
161 if (retval)
162 goto fail;
163 file->flags &= ~EXT2_FILE_BUF_VALID;
164 }
165 file->blockno = b;
166 if (!(file->flags & EXT2_FILE_BUF_VALID)) {
167 retval = ext2fs_bmap(fs, file->ino, &file->inode,
168 file->buf, 0, b, &pb);
169 if (retval)
170 goto fail;
171 if (pb) {
172 file->physblock = pb;
173 retval = io_channel_read_blk(fs->io, pb, 1, file->buf);
174 if (retval)
175 goto fail;
176 } else {
177 file->physblock = 0;
178 memset(file->buf, 0, fs->blocksize);
179 }
180
181 file->flags |= EXT2_FILE_BUF_VALID;
182 }
183 start = file->pos % fs->blocksize;
184 c = fs->blocksize - start;
185 if (c > wanted)
186 c = wanted;
187 left = file->inode.i_size - file->pos ;
188 if (c > left)
189 c = left;
190
191 memcpy(ptr, file->buf+start, c);
192 file->pos += c;
193 ptr += c;
194 count += c;
195 wanted -= c;
196
197 if (wanted > 0)
198 goto again;
199
200done:
201 if (got)
202 *got = count;
203 return 0;
204
205fail:
206 if (count)
207 goto done;
208 return retval;
209}
210
211
212errcode_t ext2fs_file_write(ext2_file_t file, void *buf,
Theodore Ts'o79a90bd1997-11-03 19:16:55 +0000213 unsigned int nbytes, unsigned int *written)
Theodore Ts'o30fab291997-10-25 22:37:42 +0000214{
215 ext2_filsys fs;
216 errcode_t retval;
217 blk_t b, pb;
Theodore Ts'o79a90bd1997-11-03 19:16:55 +0000218 unsigned int start, c, count = 0;
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000219 char *ptr = (char *) buf;
Theodore Ts'o30fab291997-10-25 22:37:42 +0000220
221 EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
222 fs = file->fs;
223
224 if (!(file->flags & EXT2_FILE_WRITE))
Theodore Ts'o1f0b6c11997-10-31 06:07:47 +0000225 return EXT2_ET_FILE_RO;
Theodore Ts'o30fab291997-10-25 22:37:42 +0000226
227again:
228 b = file->pos / fs->blocksize;
229 if (b != file->blockno) {
230 retval = ext2fs_file_flush(file);
231 if (retval)
232 goto fail;
233 file->flags &= ~EXT2_FILE_BUF_VALID;
234 }
235 file->blockno = b;
236 if (!(file->flags & EXT2_FILE_BUF_VALID)) {
237 retval = ext2fs_bmap(fs, file->ino, &file->inode,
238 file->buf, BMAP_ALLOC, b, &pb);
239 if (retval)
240 goto fail;
241 file->physblock = pb;
242
243 retval = io_channel_read_blk(fs->io, pb, 1, file->buf);
244 if (retval)
245 goto fail;
246 file->flags |= EXT2_FILE_BUF_VALID;
247 }
248 start = file->pos % fs->blocksize;
249 c = fs->blocksize - start;
250 if (c > nbytes)
251 c = nbytes;
252
253 file->flags |= EXT2_FILE_BUF_DIRTY;
254 memcpy(file->buf+start, ptr, c);
255 file->pos += c;
256 ptr += c;
257 count += c;
258 nbytes -= c;
259
260 if (nbytes > 0)
261 goto again;
262
263done:
264 if (written)
265 *written = count;
266 return 0;
267
268fail:
269 if (count)
270 goto done;
271 return retval;
272}
273
274
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000275errcode_t ext2fs_file_lseek(ext2_file_t file, ext2_off_t offset,
276 int whence, ext2_off_t *ret_pos)
Theodore Ts'o30fab291997-10-25 22:37:42 +0000277{
278 EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
279
280 if (whence == EXT2_SEEK_SET)
281 file->pos = offset;
282 else if (whence == EXT2_SEEK_CUR)
283 file->pos += offset;
284 else if (whence == EXT2_SEEK_END)
285 file->pos = file->inode.i_size + offset;
286 else
Theodore Ts'o1f0b6c11997-10-31 06:07:47 +0000287 return EXT2_ET_INVALID_ARGUMENT;
Theodore Ts'o30fab291997-10-25 22:37:42 +0000288
289 if (ret_pos)
290 *ret_pos = file->pos;
291
292 return 0;
293}
294
Theodore Ts'o79a90bd1997-11-03 19:16:55 +0000295/*
296 * This function returns the size of the file, according to the inode
297 */
298ext2_off_t ext2fs_file_get_size(ext2_file_t file)
299{
300 if (file->magic != EXT2_ET_MAGIC_EXT2_FILE)
301 return 0;
302 return file->inode.i_size;
303}
Theodore Ts'o30fab291997-10-25 22:37:42 +0000304
Theodore Ts'o79a90bd1997-11-03 19:16:55 +0000305/*
306 * This function sets the size of the file, truncating it if necessary
307 *
308 * XXX still need to call truncate
309 */
Theodore Ts'o2eb374c1998-09-03 01:22:57 +0000310errcode_t ext2fs_file_set_size(ext2_file_t file, ext2_off_t size)
Theodore Ts'o79a90bd1997-11-03 19:16:55 +0000311{
312 errcode_t retval;
313 EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
314
315 file->inode.i_size = size;
316 retval = ext2fs_write_inode(file->fs, file->ino, &file->inode);
317 if (retval)
318 return retval;
319
320 /*
321 * XXX truncate inode if necessary
322 */
323
324 return 0;
325}