blob: fa7acb0d1878a45e7ff5c0c575ada3e0a38aa20c [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
17#include <stdlib.h>
18
19#include <linux/ext2_fs.h>
20
21#include "ext2fs.h"
22
23struct ext2_file {
24 errcode_t magic;
25 ext2_filsys fs;
26 ino_t ino;
27 struct ext2_inode inode;
28 int flags;
29 ext2_off_t pos;
30 blk_t blockno;
31 blk_t physblock;
32 char *buf;
33};
34
35/*
36 * XXX Doesn't handle writing yet
37 */
38errcode_t ext2fs_file_open(ext2_filsys fs, ino_t ino,
39 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
52 file = (ext2_file_t) malloc(sizeof(struct ext2_file));
53 if (!file)
54 return EXT2_NO_MEMORY;
55
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
66 file->buf = malloc(fs->blocksize);
67 if (!file->buf) {
68 retval = EXT2_NO_MEMORY;
69 goto fail;
70 }
71
72 *ret = file;
73 return 0;
74
75fail:
76 if (file->buf)
77 free(file->buf);
78 free(file);
79 return retval;
80}
81
82/*
83 * This function flushes the dirty block buffer out to disk if
84 * necessary.
85 */
86static errcode_t ext2fs_file_flush(ext2_file_t file)
87{
88 errcode_t retval;
89
90 EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
91
92 if (!(file->flags & EXT2_FILE_BUF_VALID) ||
93 !(file->flags & EXT2_FILE_BUF_DIRTY))
94 return 0;
95
96 /*
97 * OK, the physical block hasn't been allocated yet.
98 * Allocate it.
99 */
100 if (!file->physblock) {
101 retval = ext2fs_bmap(file->fs, file->ino, &file->inode,
102 file->buf, BMAP_ALLOC,
103 file->blockno, &file->physblock);
104 if (retval)
105 return retval;
106 }
107
108 retval = io_channel_write_blk(file->fs->io, file->physblock,
109 1, file->buf);
110 if (retval)
111 return retval;
112
113 file->flags &= ~EXT2_FILE_BUF_DIRTY;
114
115 return retval;
116}
117
118errcode_t ext2fs_file_close(ext2_file_t file)
119{
120 errcode_t retval;
121
122 EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
123
124 retval = ext2fs_file_flush(file);
125
126 if (file->buf)
127 free(file->buf);
128 free(file);
129
130 return retval;
131}
132
133
134errcode_t ext2fs_file_read(ext2_file_t file, void *buf,
135 int wanted, int *got)
136{
137 ext2_filsys fs;
138 errcode_t retval;
139 blk_t b, pb;
140 int start, left, c, count = 0;
141 char *ptr = buf;
142
143 EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
144 fs = file->fs;
145
146again:
147 if (file->pos >= file->inode.i_size)
148 goto done;
149
150 b = file->pos / fs->blocksize;
151 if (b != file->blockno) {
152 retval = ext2fs_file_flush(file);
153 if (retval)
154 goto fail;
155 file->flags &= ~EXT2_FILE_BUF_VALID;
156 }
157 file->blockno = b;
158 if (!(file->flags & EXT2_FILE_BUF_VALID)) {
159 retval = ext2fs_bmap(fs, file->ino, &file->inode,
160 file->buf, 0, b, &pb);
161 if (retval)
162 goto fail;
163 if (pb) {
164 file->physblock = pb;
165 retval = io_channel_read_blk(fs->io, pb, 1, file->buf);
166 if (retval)
167 goto fail;
168 } else {
169 file->physblock = 0;
170 memset(file->buf, 0, fs->blocksize);
171 }
172
173 file->flags |= EXT2_FILE_BUF_VALID;
174 }
175 start = file->pos % fs->blocksize;
176 c = fs->blocksize - start;
177 if (c > wanted)
178 c = wanted;
179 left = file->inode.i_size - file->pos ;
180 if (c > left)
181 c = left;
182
183 memcpy(ptr, file->buf+start, c);
184 file->pos += c;
185 ptr += c;
186 count += c;
187 wanted -= c;
188
189 if (wanted > 0)
190 goto again;
191
192done:
193 if (got)
194 *got = count;
195 return 0;
196
197fail:
198 if (count)
199 goto done;
200 return retval;
201}
202
203
204errcode_t ext2fs_file_write(ext2_file_t file, void *buf,
205 int nbytes, int *written)
206{
207 ext2_filsys fs;
208 errcode_t retval;
209 blk_t b, pb;
210 int start, c, count = 0;
211 char *ptr = buf;
212
213 EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
214 fs = file->fs;
215
216 if (!(file->flags & EXT2_FILE_WRITE))
217 return EXT2_FILE_RO;
218
219again:
220 b = file->pos / fs->blocksize;
221 if (b != file->blockno) {
222 retval = ext2fs_file_flush(file);
223 if (retval)
224 goto fail;
225 file->flags &= ~EXT2_FILE_BUF_VALID;
226 }
227 file->blockno = b;
228 if (!(file->flags & EXT2_FILE_BUF_VALID)) {
229 retval = ext2fs_bmap(fs, file->ino, &file->inode,
230 file->buf, BMAP_ALLOC, b, &pb);
231 if (retval)
232 goto fail;
233 file->physblock = pb;
234
235 retval = io_channel_read_blk(fs->io, pb, 1, file->buf);
236 if (retval)
237 goto fail;
238 file->flags |= EXT2_FILE_BUF_VALID;
239 }
240 start = file->pos % fs->blocksize;
241 c = fs->blocksize - start;
242 if (c > nbytes)
243 c = nbytes;
244
245 file->flags |= EXT2_FILE_BUF_DIRTY;
246 memcpy(file->buf+start, ptr, c);
247 file->pos += c;
248 ptr += c;
249 count += c;
250 nbytes -= c;
251
252 if (nbytes > 0)
253 goto again;
254
255done:
256 if (written)
257 *written = count;
258 return 0;
259
260fail:
261 if (count)
262 goto done;
263 return retval;
264}
265
266
267errcode_t ext2fs_file_llseek(ext2_file_t file, ext2_off_t offset,
268 int whence, ext2_off_t *ret_pos)
269{
270 EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
271
272 if (whence == EXT2_SEEK_SET)
273 file->pos = offset;
274 else if (whence == EXT2_SEEK_CUR)
275 file->pos += offset;
276 else if (whence == EXT2_SEEK_END)
277 file->pos = file->inode.i_size + offset;
278 else
279 return EXT2_INVALID_ARGUMENT;
280
281 if (ret_pos)
282 *ret_pos = file->pos;
283
284 return 0;
285}
286
287