blob: 51375b7878d06a08af2bac07bc1604d6cd16cacb [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;
29 ino_t ino;
30 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
38/*
39 * XXX Doesn't handle writing yet
40 */
41errcode_t ext2fs_file_open(ext2_filsys fs, ino_t ino,
42 int flags, ext2_file_t *ret)
43{
44 ext2_file_t file;
45 errcode_t retval;
46
47 /*
48 * Don't let caller create or open a file for writing if the
49 * filesystem is read-only.
50 */
51 if ((flags & (EXT2_FILE_WRITE | EXT2_FILE_CREATE)) &&
52 !(fs->flags & EXT2_FLAG_RW))
53 return EXT2_ET_RO_FILSYS;
54
Theodore Ts'o7b4e4531997-10-26 03:41:24 +000055 retval = ext2fs_get_mem(sizeof(struct ext2_file), (void **) &file);
56 if (retval)
57 return retval;
Theodore Ts'o30fab291997-10-25 22:37:42 +000058
59 memset(file, 0, sizeof(struct ext2_file));
60 file->magic = EXT2_ET_MAGIC_EXT2_FILE;
61 file->fs = fs;
62 file->ino = ino;
63 file->flags = flags & EXT2_FILE_MASK;
64
65 retval = ext2fs_read_inode(fs, ino, &file->inode);
66 if (retval)
67 goto fail;
68
Theodore Ts'o7b4e4531997-10-26 03:41:24 +000069 retval = ext2fs_get_mem(fs->blocksize, (void **) &file->buf);
70 if (retval)
Theodore Ts'o30fab291997-10-25 22:37:42 +000071 goto fail;
Theodore Ts'o30fab291997-10-25 22:37:42 +000072
73 *ret = file;
74 return 0;
75
76fail:
77 if (file->buf)
Theodore Ts'o7b4e4531997-10-26 03:41:24 +000078 ext2fs_free_mem((void **) &file->buf);
79 ext2fs_free_mem((void **) &file);
Theodore Ts'o30fab291997-10-25 22:37:42 +000080 return retval;
81}
82
83/*
Theodore Ts'o79a90bd1997-11-03 19:16:55 +000084 * This function returns the filesystem handle of a file from the structure
85 */
86ext2_filsys ext2fs_file_get_fs(ext2_file_t file)
87{
88 if (file->magic != EXT2_ET_MAGIC_EXT2_FILE)
89 return 0;
90 return file->fs;
91}
92
93/*
Theodore Ts'o30fab291997-10-25 22:37:42 +000094 * This function flushes the dirty block buffer out to disk if
95 * necessary.
96 */
97static errcode_t ext2fs_file_flush(ext2_file_t file)
98{
99 errcode_t retval;
100
101 EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
102
103 if (!(file->flags & EXT2_FILE_BUF_VALID) ||
104 !(file->flags & EXT2_FILE_BUF_DIRTY))
105 return 0;
106
107 /*
108 * OK, the physical block hasn't been allocated yet.
109 * Allocate it.
110 */
111 if (!file->physblock) {
112 retval = ext2fs_bmap(file->fs, file->ino, &file->inode,
113 file->buf, BMAP_ALLOC,
114 file->blockno, &file->physblock);
115 if (retval)
116 return retval;
117 }
118
119 retval = io_channel_write_blk(file->fs->io, file->physblock,
120 1, file->buf);
121 if (retval)
122 return retval;
123
124 file->flags &= ~EXT2_FILE_BUF_DIRTY;
125
126 return retval;
127}
128
129errcode_t ext2fs_file_close(ext2_file_t file)
130{
131 errcode_t retval;
132
133 EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
134
135 retval = ext2fs_file_flush(file);
136
137 if (file->buf)
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000138 ext2fs_free_mem((void **) &file->buf);
139 ext2fs_free_mem((void **) &file);
Theodore Ts'o30fab291997-10-25 22:37:42 +0000140
141 return retval;
142}
143
144
145errcode_t ext2fs_file_read(ext2_file_t file, void *buf,
Theodore Ts'o79a90bd1997-11-03 19:16:55 +0000146 unsigned int wanted, unsigned int *got)
Theodore Ts'o30fab291997-10-25 22:37:42 +0000147{
148 ext2_filsys fs;
149 errcode_t retval;
150 blk_t b, pb;
Theodore Ts'o79a90bd1997-11-03 19:16:55 +0000151 unsigned int start, left, c, count = 0;
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000152 char *ptr = (char *) buf;
Theodore Ts'o30fab291997-10-25 22:37:42 +0000153
154 EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
155 fs = file->fs;
156
157again:
158 if (file->pos >= file->inode.i_size)
159 goto done;
160
161 b = file->pos / fs->blocksize;
162 if (b != file->blockno) {
163 retval = ext2fs_file_flush(file);
164 if (retval)
165 goto fail;
166 file->flags &= ~EXT2_FILE_BUF_VALID;
167 }
168 file->blockno = b;
169 if (!(file->flags & EXT2_FILE_BUF_VALID)) {
170 retval = ext2fs_bmap(fs, file->ino, &file->inode,
171 file->buf, 0, b, &pb);
172 if (retval)
173 goto fail;
174 if (pb) {
175 file->physblock = pb;
176 retval = io_channel_read_blk(fs->io, pb, 1, file->buf);
177 if (retval)
178 goto fail;
179 } else {
180 file->physblock = 0;
181 memset(file->buf, 0, fs->blocksize);
182 }
183
184 file->flags |= EXT2_FILE_BUF_VALID;
185 }
186 start = file->pos % fs->blocksize;
187 c = fs->blocksize - start;
188 if (c > wanted)
189 c = wanted;
190 left = file->inode.i_size - file->pos ;
191 if (c > left)
192 c = left;
193
194 memcpy(ptr, file->buf+start, c);
195 file->pos += c;
196 ptr += c;
197 count += c;
198 wanted -= c;
199
200 if (wanted > 0)
201 goto again;
202
203done:
204 if (got)
205 *got = count;
206 return 0;
207
208fail:
209 if (count)
210 goto done;
211 return retval;
212}
213
214
215errcode_t ext2fs_file_write(ext2_file_t file, void *buf,
Theodore Ts'o79a90bd1997-11-03 19:16:55 +0000216 unsigned int nbytes, unsigned int *written)
Theodore Ts'o30fab291997-10-25 22:37:42 +0000217{
218 ext2_filsys fs;
219 errcode_t retval;
220 blk_t b, pb;
Theodore Ts'o79a90bd1997-11-03 19:16:55 +0000221 unsigned int start, c, count = 0;
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000222 char *ptr = (char *) buf;
Theodore Ts'o30fab291997-10-25 22:37:42 +0000223
224 EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
225 fs = file->fs;
226
227 if (!(file->flags & EXT2_FILE_WRITE))
Theodore Ts'o1f0b6c11997-10-31 06:07:47 +0000228 return EXT2_ET_FILE_RO;
Theodore Ts'o30fab291997-10-25 22:37:42 +0000229
230again:
231 b = file->pos / fs->blocksize;
232 if (b != file->blockno) {
233 retval = ext2fs_file_flush(file);
234 if (retval)
235 goto fail;
236 file->flags &= ~EXT2_FILE_BUF_VALID;
237 }
238 file->blockno = b;
239 if (!(file->flags & EXT2_FILE_BUF_VALID)) {
240 retval = ext2fs_bmap(fs, file->ino, &file->inode,
241 file->buf, BMAP_ALLOC, b, &pb);
242 if (retval)
243 goto fail;
244 file->physblock = pb;
245
246 retval = io_channel_read_blk(fs->io, pb, 1, file->buf);
247 if (retval)
248 goto fail;
249 file->flags |= EXT2_FILE_BUF_VALID;
250 }
251 start = file->pos % fs->blocksize;
252 c = fs->blocksize - start;
253 if (c > nbytes)
254 c = nbytes;
255
256 file->flags |= EXT2_FILE_BUF_DIRTY;
257 memcpy(file->buf+start, ptr, c);
258 file->pos += c;
259 ptr += c;
260 count += c;
261 nbytes -= c;
262
263 if (nbytes > 0)
264 goto again;
265
266done:
267 if (written)
268 *written = count;
269 return 0;
270
271fail:
272 if (count)
273 goto done;
274 return retval;
275}
276
277
Theodore Ts'o674a4ee1998-03-23 02:06:52 +0000278errcode_t ext2fs_file_lseek(ext2_file_t file, ext2_off_t offset,
279 int whence, ext2_off_t *ret_pos)
Theodore Ts'o30fab291997-10-25 22:37:42 +0000280{
281 EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
282
283 if (whence == EXT2_SEEK_SET)
284 file->pos = offset;
285 else if (whence == EXT2_SEEK_CUR)
286 file->pos += offset;
287 else if (whence == EXT2_SEEK_END)
288 file->pos = file->inode.i_size + offset;
289 else
Theodore Ts'o1f0b6c11997-10-31 06:07:47 +0000290 return EXT2_ET_INVALID_ARGUMENT;
Theodore Ts'o30fab291997-10-25 22:37:42 +0000291
292 if (ret_pos)
293 *ret_pos = file->pos;
294
295 return 0;
296}
297
Theodore Ts'o79a90bd1997-11-03 19:16:55 +0000298/*
299 * This function returns the size of the file, according to the inode
300 */
301ext2_off_t ext2fs_file_get_size(ext2_file_t file)
302{
303 if (file->magic != EXT2_ET_MAGIC_EXT2_FILE)
304 return 0;
305 return file->inode.i_size;
306}
Theodore Ts'o30fab291997-10-25 22:37:42 +0000307
Theodore Ts'o79a90bd1997-11-03 19:16:55 +0000308/*
309 * This function sets the size of the file, truncating it if necessary
310 *
311 * XXX still need to call truncate
312 */
313extern errcode_t ext2fs_file_set_size(ext2_file_t file, ext2_off_t size)
314{
315 errcode_t retval;
316 EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
317
318 file->inode.i_size = size;
319 retval = ext2fs_write_inode(file->fs, file->ino, &file->inode);
320 if (retval)
321 return retval;
322
323 /*
324 * XXX truncate inode if necessary
325 */
326
327 return 0;
328}