2 * fileio.c --- Simple file I/O routines
4 * Copyright (C) 1997 Theodore Ts'o.
7 * This file may be redistributed under the terms of the GNU Library
8 * General Public License, version 2.
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_array(3, fs
->blocksize
, &file
->buf
);
78 ext2fs_free_mem(&file
->buf
);
79 ext2fs_free_mem(&file
);
83 errcode_t
ext2fs_file_open(ext2_filsys fs
, ext2_ino_t ino
,
84 int flags
, ext2_file_t
*ret
)
86 return ext2fs_file_open2(fs
, ino
, NULL
, flags
, ret
);
90 * This function returns the filesystem handle of a file from the structure
92 ext2_filsys
ext2fs_file_get_fs(ext2_file_t file
)
94 if (file
->magic
!= EXT2_ET_MAGIC_EXT2_FILE
)
100 * This function returns the pointer to the inode of a file from the structure
102 struct ext2_inode
*ext2fs_file_get_inode(ext2_file_t file
)
104 if (file
->magic
!= EXT2_ET_MAGIC_EXT2_FILE
)
109 /* This function returns the inode number from the structure */
110 ext2_ino_t
ext2fs_file_get_inode_num(ext2_file_t file
)
112 if (file
->magic
!= EXT2_ET_MAGIC_EXT2_FILE
)
118 * This function flushes the dirty block buffer out to disk if
121 errcode_t
ext2fs_file_flush(ext2_file_t file
)
126 EXT2_CHECK_MAGIC(file
, EXT2_ET_MAGIC_EXT2_FILE
);
129 if (!(file
->flags
& EXT2_FILE_BUF_VALID
) ||
130 !(file
->flags
& EXT2_FILE_BUF_DIRTY
))
134 * OK, the physical block hasn't been allocated yet.
137 if (!file
->physblock
) {
138 retval
= ext2fs_bmap2(fs
, file
->ino
, &file
->inode
,
139 BMAP_BUFFER
, file
->ino
? BMAP_ALLOC
: 0,
140 file
->blockno
, 0, &file
->physblock
);
145 retval
= io_channel_write_blk(fs
->io
, file
->physblock
,
150 file
->flags
&= ~EXT2_FILE_BUF_DIRTY
;
156 * This function synchronizes the file's block buffer and the current
157 * file position, possibly invalidating block buffer if necessary
159 static errcode_t
sync_buffer_position(ext2_file_t file
)
164 b
= file
->pos
/ file
->fs
->blocksize
;
165 if (b
!= file
->blockno
) {
166 retval
= ext2fs_file_flush(file
);
169 file
->flags
&= ~EXT2_FILE_BUF_VALID
;
176 * This function loads the file's block buffer with valid data from
177 * the disk as necessary.
179 * If dontfill is true, then skip initializing the buffer since we're
180 * going to be replacing its entire contents anyway. If set, then the
181 * function basically only sets file->physblock and EXT2_FILE_BUF_VALID
184 static errcode_t
load_buffer(ext2_file_t file
, int dontfill
)
186 ext2_filsys fs
= file
->fs
;
189 if (!(file
->flags
& EXT2_FILE_BUF_VALID
)) {
190 retval
= ext2fs_bmap2(fs
, file
->ino
, &file
->inode
,
191 BMAP_BUFFER
, 0, file
->blockno
, 0,
196 if (file
->physblock
) {
197 retval
= io_channel_read_blk(fs
->io
,
203 memset(file
->buf
, 0, fs
->blocksize
);
205 file
->flags
|= EXT2_FILE_BUF_VALID
;
211 errcode_t
ext2fs_file_close(ext2_file_t file
)
215 EXT2_CHECK_MAGIC(file
, EXT2_ET_MAGIC_EXT2_FILE
);
217 retval
= ext2fs_file_flush(file
);
220 ext2fs_free_mem(&file
->buf
);
221 ext2fs_free_mem(&file
);
227 errcode_t
ext2fs_file_read(ext2_file_t file
, void *buf
,
228 unsigned int wanted
, unsigned int *got
)
231 errcode_t retval
= 0;
232 unsigned int start
, c
, count
= 0;
234 char *ptr
= (char *) buf
;
236 EXT2_CHECK_MAGIC(file
, EXT2_ET_MAGIC_EXT2_FILE
);
239 while ((file
->pos
< EXT2_I_SIZE(&file
->inode
)) && (wanted
> 0)) {
240 retval
= sync_buffer_position(file
);
243 retval
= load_buffer(file
, 0);
247 start
= file
->pos
% fs
->blocksize
;
248 c
= fs
->blocksize
- start
;
251 left
= EXT2_I_SIZE(&file
->inode
) - file
->pos
;
255 memcpy(ptr
, file
->buf
+start
, c
);
269 errcode_t
ext2fs_file_write(ext2_file_t file
, const void *buf
,
270 unsigned int nbytes
, unsigned int *written
)
273 errcode_t retval
= 0;
274 unsigned int start
, c
, count
= 0;
275 const char *ptr
= (const char *) buf
;
277 EXT2_CHECK_MAGIC(file
, EXT2_ET_MAGIC_EXT2_FILE
);
280 if (!(file
->flags
& EXT2_FILE_WRITE
))
281 return EXT2_ET_FILE_RO
;
284 retval
= sync_buffer_position(file
);
288 start
= file
->pos
% fs
->blocksize
;
289 c
= fs
->blocksize
- start
;
294 * We only need to do a read-modify-update cycle if
295 * we're doing a partial write.
297 retval
= load_buffer(file
, (c
== fs
->blocksize
));
301 file
->flags
|= EXT2_FILE_BUF_DIRTY
;
302 memcpy(file
->buf
+start
, ptr
, c
);
310 /* Update inode size */
311 if (count
!= 0 && EXT2_I_SIZE(&file
->inode
) < file
->pos
) {
314 rc
= ext2fs_file_set_size2(file
, file
->pos
);
324 errcode_t
ext2fs_file_llseek(ext2_file_t file
, __u64 offset
,
325 int whence
, __u64
*ret_pos
)
327 EXT2_CHECK_MAGIC(file
, EXT2_ET_MAGIC_EXT2_FILE
);
329 if (whence
== EXT2_SEEK_SET
)
331 else if (whence
== EXT2_SEEK_CUR
)
333 else if (whence
== EXT2_SEEK_END
)
334 file
->pos
= EXT2_I_SIZE(&file
->inode
) + offset
;
336 return EXT2_ET_INVALID_ARGUMENT
;
339 *ret_pos
= file
->pos
;
344 errcode_t
ext2fs_file_lseek(ext2_file_t file
, ext2_off_t offset
,
345 int whence
, ext2_off_t
*ret_pos
)
347 __u64 loffset
, ret_loffset
;
351 retval
= ext2fs_file_llseek(file
, loffset
, whence
, &ret_loffset
);
353 *ret_pos
= (ext2_off_t
) ret_loffset
;
359 * This function returns the size of the file, according to the inode
361 errcode_t
ext2fs_file_get_lsize(ext2_file_t file
, __u64
*ret_size
)
363 if (file
->magic
!= EXT2_ET_MAGIC_EXT2_FILE
)
364 return EXT2_ET_MAGIC_EXT2_FILE
;
365 *ret_size
= EXT2_I_SIZE(&file
->inode
);
370 * This function returns the size of the file, according to the inode
372 ext2_off_t
ext2fs_file_get_size(ext2_file_t file
)
376 if (ext2fs_file_get_lsize(file
, &size
))
378 if ((size
>> 32) != 0)
384 * This function sets the size of the file, truncating it if necessary
387 errcode_t
ext2fs_file_set_size2(ext2_file_t file
, ext2_off64_t size
)
389 ext2_off64_t old_size
;
391 blk64_t old_truncate
, truncate_block
;
393 EXT2_CHECK_MAGIC(file
, EXT2_ET_MAGIC_EXT2_FILE
);
395 truncate_block
= ((size
+ file
->fs
->blocksize
- 1) >>
396 EXT2_BLOCK_SIZE_BITS(file
->fs
->super
)) + 1;
397 old_size
= EXT2_I_SIZE(&file
->inode
);
398 old_truncate
= ((old_size
+ file
->fs
->blocksize
- 1) >>
399 EXT2_BLOCK_SIZE_BITS(file
->fs
->super
)) + 1;
401 /* If we're writing a large file, set the large_file flag */
402 if (LINUX_S_ISREG(file
->inode
.i_mode
) &&
403 EXT2_I_SIZE(&file
->inode
) > 0x7FFFFFFULL
&&
404 (!EXT2_HAS_RO_COMPAT_FEATURE(file
->fs
->super
,
405 EXT2_FEATURE_RO_COMPAT_LARGE_FILE
) ||
406 file
->fs
->super
->s_rev_level
== EXT2_GOOD_OLD_REV
)) {
407 file
->fs
->super
->s_feature_ro_compat
|=
408 EXT2_FEATURE_RO_COMPAT_LARGE_FILE
;
409 ext2fs_update_dynamic_rev(file
->fs
);
410 ext2fs_mark_super_dirty(file
->fs
);
413 file
->inode
.i_size
= size
& 0xffffffff;
414 file
->inode
.i_size_high
= (size
>> 32);
416 retval
= ext2fs_write_inode(file
->fs
, file
->ino
, &file
->inode
);
421 if (truncate_block
>= old_truncate
)
424 return ext2fs_punch(file
->fs
, file
->ino
, &file
->inode
, 0,
425 truncate_block
, ~0ULL);
428 errcode_t
ext2fs_file_set_size(ext2_file_t file
, ext2_off_t size
)
430 return ext2fs_file_set_size2(file
, size
);