blob: ffb11ef88a908d30883ba954af2e9d256a4640a4 [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
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'o7b4e4531997-10-26 03:41:24 +000066 retval = ext2fs_get_mem(fs->blocksize, (void **) &file->buf);
67 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/*
81 * This function flushes the dirty block buffer out to disk if
82 * necessary.
83 */
84static errcode_t ext2fs_file_flush(ext2_file_t file)
85{
86 errcode_t retval;
87
88 EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
89
90 if (!(file->flags & EXT2_FILE_BUF_VALID) ||
91 !(file->flags & EXT2_FILE_BUF_DIRTY))
92 return 0;
93
94 /*
95 * OK, the physical block hasn't been allocated yet.
96 * Allocate it.
97 */
98 if (!file->physblock) {
99 retval = ext2fs_bmap(file->fs, file->ino, &file->inode,
100 file->buf, BMAP_ALLOC,
101 file->blockno, &file->physblock);
102 if (retval)
103 return retval;
104 }
105
106 retval = io_channel_write_blk(file->fs->io, file->physblock,
107 1, file->buf);
108 if (retval)
109 return retval;
110
111 file->flags &= ~EXT2_FILE_BUF_DIRTY;
112
113 return retval;
114}
115
116errcode_t ext2fs_file_close(ext2_file_t file)
117{
118 errcode_t retval;
119
120 EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
121
122 retval = ext2fs_file_flush(file);
123
124 if (file->buf)
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000125 ext2fs_free_mem((void **) &file->buf);
126 ext2fs_free_mem((void **) &file);
Theodore Ts'o30fab291997-10-25 22:37:42 +0000127
128 return retval;
129}
130
131
132errcode_t ext2fs_file_read(ext2_file_t file, void *buf,
133 int wanted, int *got)
134{
135 ext2_filsys fs;
136 errcode_t retval;
137 blk_t b, pb;
138 int start, left, c, count = 0;
139 char *ptr = buf;
140
141 EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
142 fs = file->fs;
143
144again:
145 if (file->pos >= file->inode.i_size)
146 goto done;
147
148 b = file->pos / fs->blocksize;
149 if (b != file->blockno) {
150 retval = ext2fs_file_flush(file);
151 if (retval)
152 goto fail;
153 file->flags &= ~EXT2_FILE_BUF_VALID;
154 }
155 file->blockno = b;
156 if (!(file->flags & EXT2_FILE_BUF_VALID)) {
157 retval = ext2fs_bmap(fs, file->ino, &file->inode,
158 file->buf, 0, b, &pb);
159 if (retval)
160 goto fail;
161 if (pb) {
162 file->physblock = pb;
163 retval = io_channel_read_blk(fs->io, pb, 1, file->buf);
164 if (retval)
165 goto fail;
166 } else {
167 file->physblock = 0;
168 memset(file->buf, 0, fs->blocksize);
169 }
170
171 file->flags |= EXT2_FILE_BUF_VALID;
172 }
173 start = file->pos % fs->blocksize;
174 c = fs->blocksize - start;
175 if (c > wanted)
176 c = wanted;
177 left = file->inode.i_size - file->pos ;
178 if (c > left)
179 c = left;
180
181 memcpy(ptr, file->buf+start, c);
182 file->pos += c;
183 ptr += c;
184 count += c;
185 wanted -= c;
186
187 if (wanted > 0)
188 goto again;
189
190done:
191 if (got)
192 *got = count;
193 return 0;
194
195fail:
196 if (count)
197 goto done;
198 return retval;
199}
200
201
202errcode_t ext2fs_file_write(ext2_file_t file, void *buf,
203 int nbytes, int *written)
204{
205 ext2_filsys fs;
206 errcode_t retval;
207 blk_t b, pb;
208 int start, c, count = 0;
209 char *ptr = buf;
210
211 EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
212 fs = file->fs;
213
214 if (!(file->flags & EXT2_FILE_WRITE))
Theodore Ts'o1f0b6c11997-10-31 06:07:47 +0000215 return EXT2_ET_FILE_RO;
Theodore Ts'o30fab291997-10-25 22:37:42 +0000216
217again:
218 b = file->pos / fs->blocksize;
219 if (b != file->blockno) {
220 retval = ext2fs_file_flush(file);
221 if (retval)
222 goto fail;
223 file->flags &= ~EXT2_FILE_BUF_VALID;
224 }
225 file->blockno = b;
226 if (!(file->flags & EXT2_FILE_BUF_VALID)) {
227 retval = ext2fs_bmap(fs, file->ino, &file->inode,
228 file->buf, BMAP_ALLOC, b, &pb);
229 if (retval)
230 goto fail;
231 file->physblock = pb;
232
233 retval = io_channel_read_blk(fs->io, pb, 1, file->buf);
234 if (retval)
235 goto fail;
236 file->flags |= EXT2_FILE_BUF_VALID;
237 }
238 start = file->pos % fs->blocksize;
239 c = fs->blocksize - start;
240 if (c > nbytes)
241 c = nbytes;
242
243 file->flags |= EXT2_FILE_BUF_DIRTY;
244 memcpy(file->buf+start, ptr, c);
245 file->pos += c;
246 ptr += c;
247 count += c;
248 nbytes -= c;
249
250 if (nbytes > 0)
251 goto again;
252
253done:
254 if (written)
255 *written = count;
256 return 0;
257
258fail:
259 if (count)
260 goto done;
261 return retval;
262}
263
264
265errcode_t ext2fs_file_llseek(ext2_file_t file, ext2_off_t offset,
266 int whence, ext2_off_t *ret_pos)
267{
268 EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
269
270 if (whence == EXT2_SEEK_SET)
271 file->pos = offset;
272 else if (whence == EXT2_SEEK_CUR)
273 file->pos += offset;
274 else if (whence == EXT2_SEEK_END)
275 file->pos = file->inode.i_size + offset;
276 else
Theodore Ts'o1f0b6c11997-10-31 06:07:47 +0000277 return EXT2_ET_INVALID_ARGUMENT;
Theodore Ts'o30fab291997-10-25 22:37:42 +0000278
279 if (ret_pos)
280 *ret_pos = file->pos;
281
282 return 0;
283}
284
285