1 /* vi: set sw=4 ts=4: */
3 * fileio.c --- Simple file I/O routines
5 * Copyright (C) 1997 Theodore Ts'o.
8 * This file may be redistributed under the terms of the GNU Public
26 struct ext2_inode inode
;
34 #define BMAP_BUFFER (file->buf + fs->blocksize)
36 errcode_t
ext2fs_file_open2(ext2_filsys fs
, ext2_ino_t ino
,
37 struct ext2_inode
*inode
,
38 int flags
, ext2_file_t
*ret
)
44 * Don't let caller create or open a file for writing if the
45 * filesystem is read-only.
47 if ((flags
& (EXT2_FILE_WRITE
| EXT2_FILE_CREATE
)) &&
48 !(fs
->flags
& EXT2_FLAG_RW
))
49 return EXT2_ET_RO_FILSYS
;
51 retval
= ext2fs_get_mem(sizeof(struct ext2_file
), &file
);
55 memset(file
, 0, sizeof(struct ext2_file
));
56 file
->magic
= EXT2_ET_MAGIC_EXT2_FILE
;
59 file
->flags
= flags
& EXT2_FILE_MASK
;
62 memcpy(&file
->inode
, inode
, sizeof(struct ext2_inode
));
64 retval
= ext2fs_read_inode(fs
, ino
, &file
->inode
);
69 retval
= ext2fs_get_mem(fs
->blocksize
* 3, &file
->buf
);
77 ext2fs_free_mem(&file
->buf
);
78 ext2fs_free_mem(&file
);
82 errcode_t
ext2fs_file_open(ext2_filsys fs
, ext2_ino_t ino
,
83 int flags
, ext2_file_t
*ret
)
85 return ext2fs_file_open2(fs
, ino
, NULL
, flags
, ret
);
89 * This function returns the filesystem handle of a file from the structure
91 ext2_filsys
ext2fs_file_get_fs(ext2_file_t file
)
93 if (file
->magic
!= EXT2_ET_MAGIC_EXT2_FILE
)
99 * This function flushes the dirty block buffer out to disk if
102 errcode_t
ext2fs_file_flush(ext2_file_t file
)
107 EXT2_CHECK_MAGIC(file
, EXT2_ET_MAGIC_EXT2_FILE
);
110 if (!(file
->flags
& EXT2_FILE_BUF_VALID
) ||
111 !(file
->flags
& EXT2_FILE_BUF_DIRTY
))
115 * OK, the physical block hasn't been allocated yet.
118 if (!file
->physblock
) {
119 retval
= ext2fs_bmap(fs
, file
->ino
, &file
->inode
,
120 BMAP_BUFFER
, file
->ino
? BMAP_ALLOC
: 0,
121 file
->blockno
, &file
->physblock
);
126 retval
= io_channel_write_blk(fs
->io
, file
->physblock
,
131 file
->flags
&= ~EXT2_FILE_BUF_DIRTY
;
137 * This function synchronizes the file's block buffer and the current
138 * file position, possibly invalidating block buffer if necessary
140 static errcode_t
sync_buffer_position(ext2_file_t file
)
145 b
= file
->pos
/ file
->fs
->blocksize
;
146 if (b
!= file
->blockno
) {
147 retval
= ext2fs_file_flush(file
);
150 file
->flags
&= ~EXT2_FILE_BUF_VALID
;
157 * This function loads the file's block buffer with valid data from
158 * the disk as necessary.
160 * If dontfill is true, then skip initializing the buffer since we're
161 * going to be replacing its entire contents anyway. If set, then the
162 * function basically only sets file->physblock and EXT2_FILE_BUF_VALID
165 static errcode_t
load_buffer(ext2_file_t file
, int dontfill
)
167 ext2_filsys fs
= file
->fs
;
170 if (!(file
->flags
& EXT2_FILE_BUF_VALID
)) {
171 retval
= ext2fs_bmap(fs
, file
->ino
, &file
->inode
,
172 BMAP_BUFFER
, 0, file
->blockno
,
177 if (file
->physblock
) {
178 retval
= io_channel_read_blk(fs
->io
,
184 memset(file
->buf
, 0, fs
->blocksize
);
186 file
->flags
|= EXT2_FILE_BUF_VALID
;
192 errcode_t
ext2fs_file_close(ext2_file_t file
)
196 EXT2_CHECK_MAGIC(file
, EXT2_ET_MAGIC_EXT2_FILE
);
198 retval
= ext2fs_file_flush(file
);
200 ext2fs_free_mem(&file
->buf
);
201 ext2fs_free_mem(&file
);
207 errcode_t
ext2fs_file_read(ext2_file_t file
, void *buf
,
208 unsigned int wanted
, unsigned int *got
)
211 errcode_t retval
= 0;
212 unsigned int start
, c
, count
= 0;
214 char *ptr
= (char *) buf
;
216 EXT2_CHECK_MAGIC(file
, EXT2_ET_MAGIC_EXT2_FILE
);
219 while ((file
->pos
< EXT2_I_SIZE(&file
->inode
)) && (wanted
> 0)) {
220 retval
= sync_buffer_position(file
);
223 retval
= load_buffer(file
, 0);
227 start
= file
->pos
% fs
->blocksize
;
228 c
= fs
->blocksize
- start
;
231 left
= EXT2_I_SIZE(&file
->inode
) - file
->pos
;
235 memcpy(ptr
, file
->buf
+start
, c
);
249 errcode_t
ext2fs_file_write(ext2_file_t file
, const void *buf
,
250 unsigned int nbytes
, unsigned int *written
)
253 errcode_t retval
= 0;
254 unsigned int start
, c
, count
= 0;
255 const char *ptr
= (const char *) buf
;
257 EXT2_CHECK_MAGIC(file
, EXT2_ET_MAGIC_EXT2_FILE
);
260 if (!(file
->flags
& EXT2_FILE_WRITE
))
261 return EXT2_ET_FILE_RO
;
264 retval
= sync_buffer_position(file
);
268 start
= file
->pos
% fs
->blocksize
;
269 c
= fs
->blocksize
- start
;
274 * We only need to do a read-modify-update cycle if
275 * we're doing a partial write.
277 retval
= load_buffer(file
, (c
== fs
->blocksize
));
281 file
->flags
|= EXT2_FILE_BUF_DIRTY
;
282 memcpy(file
->buf
+start
, ptr
, c
);
295 errcode_t
ext2fs_file_llseek(ext2_file_t file
, __u64 offset
,
296 int whence
, __u64
*ret_pos
)
298 EXT2_CHECK_MAGIC(file
, EXT2_ET_MAGIC_EXT2_FILE
);
300 if (whence
== EXT2_SEEK_SET
)
302 else if (whence
== EXT2_SEEK_CUR
)
304 else if (whence
== EXT2_SEEK_END
)
305 file
->pos
= EXT2_I_SIZE(&file
->inode
) + offset
;
307 return EXT2_ET_INVALID_ARGUMENT
;
310 *ret_pos
= file
->pos
;
315 errcode_t
ext2fs_file_lseek(ext2_file_t file
, ext2_off_t offset
,
316 int whence
, ext2_off_t
*ret_pos
)
318 __u64 loffset
, ret_loffset
;
322 retval
= ext2fs_file_llseek(file
, loffset
, whence
, &ret_loffset
);
324 *ret_pos
= (ext2_off_t
) ret_loffset
;
330 * This function returns the size of the file, according to the inode
332 errcode_t
ext2fs_file_get_lsize(ext2_file_t file
, __u64
*ret_size
)
334 if (file
->magic
!= EXT2_ET_MAGIC_EXT2_FILE
)
335 return EXT2_ET_MAGIC_EXT2_FILE
;
336 *ret_size
= EXT2_I_SIZE(&file
->inode
);
341 * This function returns the size of the file, according to the inode
343 ext2_off_t
ext2fs_file_get_size(ext2_file_t file
)
347 if (ext2fs_file_get_lsize(file
, &size
))
349 if ((size
>> 32) != 0)
355 * This function sets the size of the file, truncating it if necessary
357 * XXX still need to call truncate
359 errcode_t
ext2fs_file_set_size(ext2_file_t file
, ext2_off_t size
)
362 EXT2_CHECK_MAGIC(file
, EXT2_ET_MAGIC_EXT2_FILE
);
364 file
->inode
.i_size
= size
;
365 file
->inode
.i_size_high
= 0;
367 retval
= ext2fs_write_inode(file
->fs
, file
->ino
, &file
->inode
);
373 * XXX truncate inode if necessary