xref: /aosp_15_r20/external/e2fsprogs/lib/ext2fs/fileio.c (revision 6a54128f25917bfc36a8a6e9d722c04a0b4641b6)
1*6a54128fSAndroid Build Coastguard Worker /*
2*6a54128fSAndroid Build Coastguard Worker  * fileio.c --- Simple file I/O routines
3*6a54128fSAndroid Build Coastguard Worker  *
4*6a54128fSAndroid Build Coastguard Worker  * Copyright (C) 1997 Theodore Ts'o.
5*6a54128fSAndroid Build Coastguard Worker  *
6*6a54128fSAndroid Build Coastguard Worker  * %Begin-Header%
7*6a54128fSAndroid Build Coastguard Worker  * This file may be redistributed under the terms of the GNU Library
8*6a54128fSAndroid Build Coastguard Worker  * General Public License, version 2.
9*6a54128fSAndroid Build Coastguard Worker  * %End-Header%
10*6a54128fSAndroid Build Coastguard Worker  */
11*6a54128fSAndroid Build Coastguard Worker 
12*6a54128fSAndroid Build Coastguard Worker #include "config.h"
13*6a54128fSAndroid Build Coastguard Worker #include <stdio.h>
14*6a54128fSAndroid Build Coastguard Worker #include <string.h>
15*6a54128fSAndroid Build Coastguard Worker #if HAVE_UNISTD_H
16*6a54128fSAndroid Build Coastguard Worker #include <unistd.h>
17*6a54128fSAndroid Build Coastguard Worker #endif
18*6a54128fSAndroid Build Coastguard Worker 
19*6a54128fSAndroid Build Coastguard Worker #include "ext2_fs.h"
20*6a54128fSAndroid Build Coastguard Worker #include "ext2fs.h"
21*6a54128fSAndroid Build Coastguard Worker #include "ext2fsP.h"
22*6a54128fSAndroid Build Coastguard Worker 
23*6a54128fSAndroid Build Coastguard Worker struct ext2_file {
24*6a54128fSAndroid Build Coastguard Worker 	errcode_t		magic;
25*6a54128fSAndroid Build Coastguard Worker 	ext2_filsys 		fs;
26*6a54128fSAndroid Build Coastguard Worker 	ext2_ino_t		ino;
27*6a54128fSAndroid Build Coastguard Worker 	struct ext2_inode	inode;
28*6a54128fSAndroid Build Coastguard Worker 	int 			flags;
29*6a54128fSAndroid Build Coastguard Worker 	__u64			pos;
30*6a54128fSAndroid Build Coastguard Worker 	blk64_t			blockno;
31*6a54128fSAndroid Build Coastguard Worker 	blk64_t			physblock;
32*6a54128fSAndroid Build Coastguard Worker 	char 			*buf;
33*6a54128fSAndroid Build Coastguard Worker };
34*6a54128fSAndroid Build Coastguard Worker 
35*6a54128fSAndroid Build Coastguard Worker struct block_entry {
36*6a54128fSAndroid Build Coastguard Worker 	blk64_t		physblock;
37*6a54128fSAndroid Build Coastguard Worker 	unsigned char 	sha[EXT2FS_SHA512_LENGTH];
38*6a54128fSAndroid Build Coastguard Worker };
39*6a54128fSAndroid Build Coastguard Worker typedef struct block_entry *block_entry_t;
40*6a54128fSAndroid Build Coastguard Worker 
41*6a54128fSAndroid Build Coastguard Worker #define BMAP_BUFFER (file->buf + fs->blocksize)
42*6a54128fSAndroid Build Coastguard Worker 
ext2fs_file_open2(ext2_filsys fs,ext2_ino_t ino,struct ext2_inode * inode,int flags,ext2_file_t * ret)43*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_file_open2(ext2_filsys fs, ext2_ino_t ino,
44*6a54128fSAndroid Build Coastguard Worker 			    struct ext2_inode *inode,
45*6a54128fSAndroid Build Coastguard Worker 			    int flags, ext2_file_t *ret)
46*6a54128fSAndroid Build Coastguard Worker {
47*6a54128fSAndroid Build Coastguard Worker 	ext2_file_t 	file;
48*6a54128fSAndroid Build Coastguard Worker 	errcode_t	retval;
49*6a54128fSAndroid Build Coastguard Worker 
50*6a54128fSAndroid Build Coastguard Worker 	/*
51*6a54128fSAndroid Build Coastguard Worker 	 * Don't let caller create or open a file for writing if the
52*6a54128fSAndroid Build Coastguard Worker 	 * filesystem is read-only.
53*6a54128fSAndroid Build Coastguard Worker 	 */
54*6a54128fSAndroid Build Coastguard Worker 	if ((flags & (EXT2_FILE_WRITE | EXT2_FILE_CREATE)) &&
55*6a54128fSAndroid Build Coastguard Worker 	    !(fs->flags & EXT2_FLAG_RW))
56*6a54128fSAndroid Build Coastguard Worker 		return EXT2_ET_RO_FILSYS;
57*6a54128fSAndroid Build Coastguard Worker 
58*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_get_mem(sizeof(struct ext2_file), &file);
59*6a54128fSAndroid Build Coastguard Worker 	if (retval)
60*6a54128fSAndroid Build Coastguard Worker 		return retval;
61*6a54128fSAndroid Build Coastguard Worker 
62*6a54128fSAndroid Build Coastguard Worker 	memset(file, 0, sizeof(struct ext2_file));
63*6a54128fSAndroid Build Coastguard Worker 	file->magic = EXT2_ET_MAGIC_EXT2_FILE;
64*6a54128fSAndroid Build Coastguard Worker 	file->fs = fs;
65*6a54128fSAndroid Build Coastguard Worker 	file->ino = ino;
66*6a54128fSAndroid Build Coastguard Worker 	file->flags = flags & EXT2_FILE_MASK;
67*6a54128fSAndroid Build Coastguard Worker 
68*6a54128fSAndroid Build Coastguard Worker 	if (inode) {
69*6a54128fSAndroid Build Coastguard Worker 		memcpy(&file->inode, inode, sizeof(struct ext2_inode));
70*6a54128fSAndroid Build Coastguard Worker 	} else {
71*6a54128fSAndroid Build Coastguard Worker 		retval = ext2fs_read_inode(fs, ino, &file->inode);
72*6a54128fSAndroid Build Coastguard Worker 		if (retval)
73*6a54128fSAndroid Build Coastguard Worker 			goto fail;
74*6a54128fSAndroid Build Coastguard Worker 	}
75*6a54128fSAndroid Build Coastguard Worker 
76*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_get_array(3, fs->blocksize, &file->buf);
77*6a54128fSAndroid Build Coastguard Worker 	if (retval)
78*6a54128fSAndroid Build Coastguard Worker 		goto fail;
79*6a54128fSAndroid Build Coastguard Worker 
80*6a54128fSAndroid Build Coastguard Worker 	*ret = file;
81*6a54128fSAndroid Build Coastguard Worker 	return 0;
82*6a54128fSAndroid Build Coastguard Worker 
83*6a54128fSAndroid Build Coastguard Worker fail:
84*6a54128fSAndroid Build Coastguard Worker 	if (file->buf)
85*6a54128fSAndroid Build Coastguard Worker 		ext2fs_free_mem(&file->buf);
86*6a54128fSAndroid Build Coastguard Worker 	ext2fs_free_mem(&file);
87*6a54128fSAndroid Build Coastguard Worker 	return retval;
88*6a54128fSAndroid Build Coastguard Worker }
89*6a54128fSAndroid Build Coastguard Worker 
ext2fs_file_open(ext2_filsys fs,ext2_ino_t ino,int flags,ext2_file_t * ret)90*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_file_open(ext2_filsys fs, ext2_ino_t ino,
91*6a54128fSAndroid Build Coastguard Worker 			   int flags, ext2_file_t *ret)
92*6a54128fSAndroid Build Coastguard Worker {
93*6a54128fSAndroid Build Coastguard Worker 	return ext2fs_file_open2(fs, ino, NULL, flags, ret);
94*6a54128fSAndroid Build Coastguard Worker }
95*6a54128fSAndroid Build Coastguard Worker 
96*6a54128fSAndroid Build Coastguard Worker /*
97*6a54128fSAndroid Build Coastguard Worker  * This function returns the filesystem handle of a file from the structure
98*6a54128fSAndroid Build Coastguard Worker  */
ext2fs_file_get_fs(ext2_file_t file)99*6a54128fSAndroid Build Coastguard Worker ext2_filsys ext2fs_file_get_fs(ext2_file_t file)
100*6a54128fSAndroid Build Coastguard Worker {
101*6a54128fSAndroid Build Coastguard Worker 	if (file->magic != EXT2_ET_MAGIC_EXT2_FILE)
102*6a54128fSAndroid Build Coastguard Worker 		return 0;
103*6a54128fSAndroid Build Coastguard Worker 	return file->fs;
104*6a54128fSAndroid Build Coastguard Worker }
105*6a54128fSAndroid Build Coastguard Worker 
106*6a54128fSAndroid Build Coastguard Worker /*
107*6a54128fSAndroid Build Coastguard Worker  * This function returns the pointer to the inode of a file from the structure
108*6a54128fSAndroid Build Coastguard Worker  */
ext2fs_file_get_inode(ext2_file_t file)109*6a54128fSAndroid Build Coastguard Worker struct ext2_inode *ext2fs_file_get_inode(ext2_file_t file)
110*6a54128fSAndroid Build Coastguard Worker {
111*6a54128fSAndroid Build Coastguard Worker 	if (file->magic != EXT2_ET_MAGIC_EXT2_FILE)
112*6a54128fSAndroid Build Coastguard Worker 		return NULL;
113*6a54128fSAndroid Build Coastguard Worker 	return &file->inode;
114*6a54128fSAndroid Build Coastguard Worker }
115*6a54128fSAndroid Build Coastguard Worker 
116*6a54128fSAndroid Build Coastguard Worker /* This function returns the inode number from the structure */
ext2fs_file_get_inode_num(ext2_file_t file)117*6a54128fSAndroid Build Coastguard Worker ext2_ino_t ext2fs_file_get_inode_num(ext2_file_t file)
118*6a54128fSAndroid Build Coastguard Worker {
119*6a54128fSAndroid Build Coastguard Worker 	if (file->magic != EXT2_ET_MAGIC_EXT2_FILE)
120*6a54128fSAndroid Build Coastguard Worker 		return 0;
121*6a54128fSAndroid Build Coastguard Worker 	return file->ino;
122*6a54128fSAndroid Build Coastguard Worker }
123*6a54128fSAndroid Build Coastguard Worker 
124*6a54128fSAndroid Build Coastguard Worker /*
125*6a54128fSAndroid Build Coastguard Worker  * This function flushes the dirty block buffer out to disk if
126*6a54128fSAndroid Build Coastguard Worker  * necessary.
127*6a54128fSAndroid Build Coastguard Worker  */
ext2fs_file_flush(ext2_file_t file)128*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_file_flush(ext2_file_t file)
129*6a54128fSAndroid Build Coastguard Worker {
130*6a54128fSAndroid Build Coastguard Worker 	errcode_t	retval;
131*6a54128fSAndroid Build Coastguard Worker 	ext2_filsys fs;
132*6a54128fSAndroid Build Coastguard Worker 	int		ret_flags;
133*6a54128fSAndroid Build Coastguard Worker 	blk64_t		dontcare;
134*6a54128fSAndroid Build Coastguard Worker 
135*6a54128fSAndroid Build Coastguard Worker 	EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
136*6a54128fSAndroid Build Coastguard Worker 	fs = file->fs;
137*6a54128fSAndroid Build Coastguard Worker 
138*6a54128fSAndroid Build Coastguard Worker 	if (!(file->flags & EXT2_FILE_BUF_VALID) ||
139*6a54128fSAndroid Build Coastguard Worker 	    !(file->flags & EXT2_FILE_BUF_DIRTY))
140*6a54128fSAndroid Build Coastguard Worker 		return 0;
141*6a54128fSAndroid Build Coastguard Worker 
142*6a54128fSAndroid Build Coastguard Worker 	/* Is this an uninit block? */
143*6a54128fSAndroid Build Coastguard Worker 	if (file->physblock && file->inode.i_flags & EXT4_EXTENTS_FL) {
144*6a54128fSAndroid Build Coastguard Worker 		retval = ext2fs_bmap2(fs, file->ino, &file->inode, BMAP_BUFFER,
145*6a54128fSAndroid Build Coastguard Worker 				      0, file->blockno, &ret_flags, &dontcare);
146*6a54128fSAndroid Build Coastguard Worker 		if (retval)
147*6a54128fSAndroid Build Coastguard Worker 			return retval;
148*6a54128fSAndroid Build Coastguard Worker 		if (ret_flags & BMAP_RET_UNINIT) {
149*6a54128fSAndroid Build Coastguard Worker 			retval = ext2fs_bmap2(fs, file->ino, &file->inode,
150*6a54128fSAndroid Build Coastguard Worker 					      BMAP_BUFFER, BMAP_SET,
151*6a54128fSAndroid Build Coastguard Worker 					      file->blockno, 0,
152*6a54128fSAndroid Build Coastguard Worker 					      &file->physblock);
153*6a54128fSAndroid Build Coastguard Worker 			if (retval)
154*6a54128fSAndroid Build Coastguard Worker 				return retval;
155*6a54128fSAndroid Build Coastguard Worker 		}
156*6a54128fSAndroid Build Coastguard Worker 	}
157*6a54128fSAndroid Build Coastguard Worker 
158*6a54128fSAndroid Build Coastguard Worker 	/*
159*6a54128fSAndroid Build Coastguard Worker 	 * OK, the physical block hasn't been allocated yet.
160*6a54128fSAndroid Build Coastguard Worker 	 * Allocate it.
161*6a54128fSAndroid Build Coastguard Worker 	 */
162*6a54128fSAndroid Build Coastguard Worker 	if (!file->physblock) {
163*6a54128fSAndroid Build Coastguard Worker 		retval = ext2fs_bmap2(fs, file->ino, &file->inode,
164*6a54128fSAndroid Build Coastguard Worker 				     BMAP_BUFFER, file->ino ? BMAP_ALLOC : 0,
165*6a54128fSAndroid Build Coastguard Worker 				     file->blockno, 0, &file->physblock);
166*6a54128fSAndroid Build Coastguard Worker 		if (retval)
167*6a54128fSAndroid Build Coastguard Worker 			return retval;
168*6a54128fSAndroid Build Coastguard Worker 	}
169*6a54128fSAndroid Build Coastguard Worker 
170*6a54128fSAndroid Build Coastguard Worker 	retval = io_channel_write_blk64(fs->io, file->physblock, 1, file->buf);
171*6a54128fSAndroid Build Coastguard Worker 	if (retval)
172*6a54128fSAndroid Build Coastguard Worker 		return retval;
173*6a54128fSAndroid Build Coastguard Worker 
174*6a54128fSAndroid Build Coastguard Worker 	file->flags &= ~EXT2_FILE_BUF_DIRTY;
175*6a54128fSAndroid Build Coastguard Worker 
176*6a54128fSAndroid Build Coastguard Worker 	return retval;
177*6a54128fSAndroid Build Coastguard Worker }
178*6a54128fSAndroid Build Coastguard Worker 
179*6a54128fSAndroid Build Coastguard Worker /*
180*6a54128fSAndroid Build Coastguard Worker  * This function synchronizes the file's block buffer and the current
181*6a54128fSAndroid Build Coastguard Worker  * file position, possibly invalidating block buffer if necessary
182*6a54128fSAndroid Build Coastguard Worker  */
sync_buffer_position(ext2_file_t file)183*6a54128fSAndroid Build Coastguard Worker static errcode_t sync_buffer_position(ext2_file_t file)
184*6a54128fSAndroid Build Coastguard Worker {
185*6a54128fSAndroid Build Coastguard Worker 	blk64_t	b;
186*6a54128fSAndroid Build Coastguard Worker 	errcode_t	retval;
187*6a54128fSAndroid Build Coastguard Worker 
188*6a54128fSAndroid Build Coastguard Worker 	b = file->pos / file->fs->blocksize;
189*6a54128fSAndroid Build Coastguard Worker 	if (b != file->blockno) {
190*6a54128fSAndroid Build Coastguard Worker 		retval = ext2fs_file_flush(file);
191*6a54128fSAndroid Build Coastguard Worker 		if (retval)
192*6a54128fSAndroid Build Coastguard Worker 			return retval;
193*6a54128fSAndroid Build Coastguard Worker 		file->flags &= ~EXT2_FILE_BUF_VALID;
194*6a54128fSAndroid Build Coastguard Worker 	}
195*6a54128fSAndroid Build Coastguard Worker 	file->blockno = b;
196*6a54128fSAndroid Build Coastguard Worker 	return 0;
197*6a54128fSAndroid Build Coastguard Worker }
198*6a54128fSAndroid Build Coastguard Worker 
199*6a54128fSAndroid Build Coastguard Worker /*
200*6a54128fSAndroid Build Coastguard Worker  * This function loads the file's block buffer with valid data from
201*6a54128fSAndroid Build Coastguard Worker  * the disk as necessary.
202*6a54128fSAndroid Build Coastguard Worker  *
203*6a54128fSAndroid Build Coastguard Worker  * If dontfill is true, then skip initializing the buffer since we're
204*6a54128fSAndroid Build Coastguard Worker  * going to be replacing its entire contents anyway.  If set, then the
205*6a54128fSAndroid Build Coastguard Worker  * function basically only sets file->physblock and EXT2_FILE_BUF_VALID
206*6a54128fSAndroid Build Coastguard Worker  */
207*6a54128fSAndroid Build Coastguard Worker #define DONTFILL 1
load_buffer(ext2_file_t file,int dontfill)208*6a54128fSAndroid Build Coastguard Worker static errcode_t load_buffer(ext2_file_t file, int dontfill)
209*6a54128fSAndroid Build Coastguard Worker {
210*6a54128fSAndroid Build Coastguard Worker 	ext2_filsys	fs = file->fs;
211*6a54128fSAndroid Build Coastguard Worker 	errcode_t	retval;
212*6a54128fSAndroid Build Coastguard Worker 	int		ret_flags;
213*6a54128fSAndroid Build Coastguard Worker 
214*6a54128fSAndroid Build Coastguard Worker 	if (!(file->flags & EXT2_FILE_BUF_VALID)) {
215*6a54128fSAndroid Build Coastguard Worker 		retval = ext2fs_bmap2(fs, file->ino, &file->inode,
216*6a54128fSAndroid Build Coastguard Worker 				     BMAP_BUFFER, 0, file->blockno, &ret_flags,
217*6a54128fSAndroid Build Coastguard Worker 				     &file->physblock);
218*6a54128fSAndroid Build Coastguard Worker 		if (retval)
219*6a54128fSAndroid Build Coastguard Worker 			return retval;
220*6a54128fSAndroid Build Coastguard Worker 		if (!dontfill) {
221*6a54128fSAndroid Build Coastguard Worker 			if (file->physblock &&
222*6a54128fSAndroid Build Coastguard Worker 			    !(ret_flags & BMAP_RET_UNINIT)) {
223*6a54128fSAndroid Build Coastguard Worker 				retval = io_channel_read_blk64(fs->io,
224*6a54128fSAndroid Build Coastguard Worker 							       file->physblock,
225*6a54128fSAndroid Build Coastguard Worker 							       1, file->buf);
226*6a54128fSAndroid Build Coastguard Worker 				if (retval)
227*6a54128fSAndroid Build Coastguard Worker 					return retval;
228*6a54128fSAndroid Build Coastguard Worker 			} else
229*6a54128fSAndroid Build Coastguard Worker 				memset(file->buf, 0, fs->blocksize);
230*6a54128fSAndroid Build Coastguard Worker 		}
231*6a54128fSAndroid Build Coastguard Worker 		file->flags |= EXT2_FILE_BUF_VALID;
232*6a54128fSAndroid Build Coastguard Worker 	}
233*6a54128fSAndroid Build Coastguard Worker 	return 0;
234*6a54128fSAndroid Build Coastguard Worker }
235*6a54128fSAndroid Build Coastguard Worker 
236*6a54128fSAndroid Build Coastguard Worker 
ext2fs_file_close(ext2_file_t file)237*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_file_close(ext2_file_t file)
238*6a54128fSAndroid Build Coastguard Worker {
239*6a54128fSAndroid Build Coastguard Worker 	errcode_t	retval;
240*6a54128fSAndroid Build Coastguard Worker 
241*6a54128fSAndroid Build Coastguard Worker 	EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
242*6a54128fSAndroid Build Coastguard Worker 
243*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_file_flush(file);
244*6a54128fSAndroid Build Coastguard Worker 
245*6a54128fSAndroid Build Coastguard Worker 	if (file->buf)
246*6a54128fSAndroid Build Coastguard Worker 		ext2fs_free_mem(&file->buf);
247*6a54128fSAndroid Build Coastguard Worker 	ext2fs_free_mem(&file);
248*6a54128fSAndroid Build Coastguard Worker 
249*6a54128fSAndroid Build Coastguard Worker 	return retval;
250*6a54128fSAndroid Build Coastguard Worker }
251*6a54128fSAndroid Build Coastguard Worker 
252*6a54128fSAndroid Build Coastguard Worker 
253*6a54128fSAndroid Build Coastguard Worker static errcode_t
ext2fs_file_read_inline_data(ext2_file_t file,void * buf,unsigned int wanted,unsigned int * got)254*6a54128fSAndroid Build Coastguard Worker ext2fs_file_read_inline_data(ext2_file_t file, void *buf,
255*6a54128fSAndroid Build Coastguard Worker 			     unsigned int wanted, unsigned int *got)
256*6a54128fSAndroid Build Coastguard Worker {
257*6a54128fSAndroid Build Coastguard Worker 	ext2_filsys fs;
258*6a54128fSAndroid Build Coastguard Worker 	errcode_t retval;
259*6a54128fSAndroid Build Coastguard Worker 	unsigned int count = 0;
260*6a54128fSAndroid Build Coastguard Worker 	size_t size;
261*6a54128fSAndroid Build Coastguard Worker 
262*6a54128fSAndroid Build Coastguard Worker 	fs = file->fs;
263*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_inline_data_get(fs, file->ino, &file->inode,
264*6a54128fSAndroid Build Coastguard Worker 					file->buf, &size);
265*6a54128fSAndroid Build Coastguard Worker 	if (retval)
266*6a54128fSAndroid Build Coastguard Worker 		return retval;
267*6a54128fSAndroid Build Coastguard Worker 
268*6a54128fSAndroid Build Coastguard Worker 	if (file->pos >= size)
269*6a54128fSAndroid Build Coastguard Worker 		goto out;
270*6a54128fSAndroid Build Coastguard Worker 
271*6a54128fSAndroid Build Coastguard Worker 	count = size - file->pos;
272*6a54128fSAndroid Build Coastguard Worker 	if (count > wanted)
273*6a54128fSAndroid Build Coastguard Worker 		count = wanted;
274*6a54128fSAndroid Build Coastguard Worker 	memcpy(buf, file->buf + file->pos, count);
275*6a54128fSAndroid Build Coastguard Worker 	file->pos += count;
276*6a54128fSAndroid Build Coastguard Worker 	buf = (char *) buf + count;
277*6a54128fSAndroid Build Coastguard Worker 
278*6a54128fSAndroid Build Coastguard Worker out:
279*6a54128fSAndroid Build Coastguard Worker 	if (got)
280*6a54128fSAndroid Build Coastguard Worker 		*got = count;
281*6a54128fSAndroid Build Coastguard Worker 	return retval;
282*6a54128fSAndroid Build Coastguard Worker }
283*6a54128fSAndroid Build Coastguard Worker 
284*6a54128fSAndroid Build Coastguard Worker 
ext2fs_file_read(ext2_file_t file,void * buf,unsigned int wanted,unsigned int * got)285*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_file_read(ext2_file_t file, void *buf,
286*6a54128fSAndroid Build Coastguard Worker 			   unsigned int wanted, unsigned int *got)
287*6a54128fSAndroid Build Coastguard Worker {
288*6a54128fSAndroid Build Coastguard Worker 	ext2_filsys	fs;
289*6a54128fSAndroid Build Coastguard Worker 	errcode_t	retval = 0;
290*6a54128fSAndroid Build Coastguard Worker 	unsigned int	start, c, count = 0;
291*6a54128fSAndroid Build Coastguard Worker 	__u64		left;
292*6a54128fSAndroid Build Coastguard Worker 	char		*ptr = (char *) buf;
293*6a54128fSAndroid Build Coastguard Worker 
294*6a54128fSAndroid Build Coastguard Worker 	EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
295*6a54128fSAndroid Build Coastguard Worker 	fs = file->fs;
296*6a54128fSAndroid Build Coastguard Worker 
297*6a54128fSAndroid Build Coastguard Worker 	/* If an inode has inline data, things get complicated. */
298*6a54128fSAndroid Build Coastguard Worker 	if (file->inode.i_flags & EXT4_INLINE_DATA_FL)
299*6a54128fSAndroid Build Coastguard Worker 		return ext2fs_file_read_inline_data(file, buf, wanted, got);
300*6a54128fSAndroid Build Coastguard Worker 
301*6a54128fSAndroid Build Coastguard Worker 	while ((file->pos < EXT2_I_SIZE(&file->inode)) && (wanted > 0)) {
302*6a54128fSAndroid Build Coastguard Worker 		retval = sync_buffer_position(file);
303*6a54128fSAndroid Build Coastguard Worker 		if (retval)
304*6a54128fSAndroid Build Coastguard Worker 			goto fail;
305*6a54128fSAndroid Build Coastguard Worker 		retval = load_buffer(file, 0);
306*6a54128fSAndroid Build Coastguard Worker 		if (retval)
307*6a54128fSAndroid Build Coastguard Worker 			goto fail;
308*6a54128fSAndroid Build Coastguard Worker 
309*6a54128fSAndroid Build Coastguard Worker 		start = file->pos % fs->blocksize;
310*6a54128fSAndroid Build Coastguard Worker 		c = fs->blocksize - start;
311*6a54128fSAndroid Build Coastguard Worker 		if (c > wanted)
312*6a54128fSAndroid Build Coastguard Worker 			c = wanted;
313*6a54128fSAndroid Build Coastguard Worker 		left = EXT2_I_SIZE(&file->inode) - file->pos ;
314*6a54128fSAndroid Build Coastguard Worker 		if (c > left)
315*6a54128fSAndroid Build Coastguard Worker 			c = left;
316*6a54128fSAndroid Build Coastguard Worker 
317*6a54128fSAndroid Build Coastguard Worker 		memcpy(ptr, file->buf+start, c);
318*6a54128fSAndroid Build Coastguard Worker 		file->pos += c;
319*6a54128fSAndroid Build Coastguard Worker 		ptr += c;
320*6a54128fSAndroid Build Coastguard Worker 		count += c;
321*6a54128fSAndroid Build Coastguard Worker 		wanted -= c;
322*6a54128fSAndroid Build Coastguard Worker 	}
323*6a54128fSAndroid Build Coastguard Worker 
324*6a54128fSAndroid Build Coastguard Worker fail:
325*6a54128fSAndroid Build Coastguard Worker 	if (got)
326*6a54128fSAndroid Build Coastguard Worker 		*got = count;
327*6a54128fSAndroid Build Coastguard Worker 	return retval;
328*6a54128fSAndroid Build Coastguard Worker }
329*6a54128fSAndroid Build Coastguard Worker 
330*6a54128fSAndroid Build Coastguard Worker 
331*6a54128fSAndroid Build Coastguard Worker static errcode_t
ext2fs_file_write_inline_data(ext2_file_t file,const void * buf,unsigned int nbytes,unsigned int * written)332*6a54128fSAndroid Build Coastguard Worker ext2fs_file_write_inline_data(ext2_file_t file, const void *buf,
333*6a54128fSAndroid Build Coastguard Worker 			      unsigned int nbytes, unsigned int *written)
334*6a54128fSAndroid Build Coastguard Worker {
335*6a54128fSAndroid Build Coastguard Worker 	ext2_filsys fs;
336*6a54128fSAndroid Build Coastguard Worker 	errcode_t retval;
337*6a54128fSAndroid Build Coastguard Worker 	unsigned int count = 0;
338*6a54128fSAndroid Build Coastguard Worker 	size_t size;
339*6a54128fSAndroid Build Coastguard Worker 
340*6a54128fSAndroid Build Coastguard Worker 	fs = file->fs;
341*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_inline_data_get(fs, file->ino, &file->inode,
342*6a54128fSAndroid Build Coastguard Worker 					file->buf, &size);
343*6a54128fSAndroid Build Coastguard Worker 	if (retval)
344*6a54128fSAndroid Build Coastguard Worker 		return retval;
345*6a54128fSAndroid Build Coastguard Worker 
346*6a54128fSAndroid Build Coastguard Worker 	if (file->pos < size) {
347*6a54128fSAndroid Build Coastguard Worker 		count = nbytes - file->pos;
348*6a54128fSAndroid Build Coastguard Worker 		memcpy(file->buf + file->pos, buf, count);
349*6a54128fSAndroid Build Coastguard Worker 
350*6a54128fSAndroid Build Coastguard Worker 		retval = ext2fs_inline_data_set(fs, file->ino, &file->inode,
351*6a54128fSAndroid Build Coastguard Worker 						file->buf, count);
352*6a54128fSAndroid Build Coastguard Worker 		if (retval == EXT2_ET_INLINE_DATA_NO_SPACE)
353*6a54128fSAndroid Build Coastguard Worker 			goto expand;
354*6a54128fSAndroid Build Coastguard Worker 		if (retval)
355*6a54128fSAndroid Build Coastguard Worker 			return retval;
356*6a54128fSAndroid Build Coastguard Worker 
357*6a54128fSAndroid Build Coastguard Worker 		file->pos += count;
358*6a54128fSAndroid Build Coastguard Worker 
359*6a54128fSAndroid Build Coastguard Worker 		/* Update inode size */
360*6a54128fSAndroid Build Coastguard Worker 		if (count != 0 && EXT2_I_SIZE(&file->inode) < file->pos) {
361*6a54128fSAndroid Build Coastguard Worker 			errcode_t	rc;
362*6a54128fSAndroid Build Coastguard Worker 
363*6a54128fSAndroid Build Coastguard Worker 			rc = ext2fs_file_set_size2(file, file->pos);
364*6a54128fSAndroid Build Coastguard Worker 			if (retval == 0)
365*6a54128fSAndroid Build Coastguard Worker 				retval = rc;
366*6a54128fSAndroid Build Coastguard Worker 		}
367*6a54128fSAndroid Build Coastguard Worker 
368*6a54128fSAndroid Build Coastguard Worker 		if (written)
369*6a54128fSAndroid Build Coastguard Worker 			*written = count;
370*6a54128fSAndroid Build Coastguard Worker 		return 0;
371*6a54128fSAndroid Build Coastguard Worker 	}
372*6a54128fSAndroid Build Coastguard Worker 
373*6a54128fSAndroid Build Coastguard Worker expand:
374*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_inline_data_expand(fs, file->ino);
375*6a54128fSAndroid Build Coastguard Worker 	if (retval)
376*6a54128fSAndroid Build Coastguard Worker 		return retval;
377*6a54128fSAndroid Build Coastguard Worker 	/*
378*6a54128fSAndroid Build Coastguard Worker 	 * reload inode and return no space error
379*6a54128fSAndroid Build Coastguard Worker 	 *
380*6a54128fSAndroid Build Coastguard Worker 	 * XXX: file->inode could be copied from the outside
381*6a54128fSAndroid Build Coastguard Worker 	 * in ext2fs_file_open2().  We have no way to modify
382*6a54128fSAndroid Build Coastguard Worker 	 * the outside inode.
383*6a54128fSAndroid Build Coastguard Worker 	 */
384*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_read_inode(fs, file->ino, &file->inode);
385*6a54128fSAndroid Build Coastguard Worker 	if (retval)
386*6a54128fSAndroid Build Coastguard Worker 		return retval;
387*6a54128fSAndroid Build Coastguard Worker 	return EXT2_ET_INLINE_DATA_NO_SPACE;
388*6a54128fSAndroid Build Coastguard Worker }
389*6a54128fSAndroid Build Coastguard Worker 
390*6a54128fSAndroid Build Coastguard Worker 
ext2fs_file_write(ext2_file_t file,const void * buf,unsigned int nbytes,unsigned int * written)391*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_file_write(ext2_file_t file, const void *buf,
392*6a54128fSAndroid Build Coastguard Worker 			    unsigned int nbytes, unsigned int *written)
393*6a54128fSAndroid Build Coastguard Worker {
394*6a54128fSAndroid Build Coastguard Worker 	ext2_filsys	fs;
395*6a54128fSAndroid Build Coastguard Worker 	errcode_t	retval = 0;
396*6a54128fSAndroid Build Coastguard Worker 	unsigned int	start, c, count = 0;
397*6a54128fSAndroid Build Coastguard Worker 	const char	*ptr = (const char *) buf;
398*6a54128fSAndroid Build Coastguard Worker 	block_entry_t	new_block = NULL, old_block = NULL;
399*6a54128fSAndroid Build Coastguard Worker 	int		bmap_flags = 0;
400*6a54128fSAndroid Build Coastguard Worker 
401*6a54128fSAndroid Build Coastguard Worker 	EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
402*6a54128fSAndroid Build Coastguard Worker 	fs = file->fs;
403*6a54128fSAndroid Build Coastguard Worker 
404*6a54128fSAndroid Build Coastguard Worker 	if (!(file->flags & EXT2_FILE_WRITE))
405*6a54128fSAndroid Build Coastguard Worker 		return EXT2_ET_FILE_RO;
406*6a54128fSAndroid Build Coastguard Worker 
407*6a54128fSAndroid Build Coastguard Worker 	/* If an inode has inline data, things get complicated. */
408*6a54128fSAndroid Build Coastguard Worker 	if (file->inode.i_flags & EXT4_INLINE_DATA_FL) {
409*6a54128fSAndroid Build Coastguard Worker 		retval = ext2fs_file_write_inline_data(file, buf, nbytes,
410*6a54128fSAndroid Build Coastguard Worker 						       written);
411*6a54128fSAndroid Build Coastguard Worker 		if (retval != EXT2_ET_INLINE_DATA_NO_SPACE)
412*6a54128fSAndroid Build Coastguard Worker 			return retval;
413*6a54128fSAndroid Build Coastguard Worker 		/* fall through to read data from the block */
414*6a54128fSAndroid Build Coastguard Worker 		retval = 0;
415*6a54128fSAndroid Build Coastguard Worker 	}
416*6a54128fSAndroid Build Coastguard Worker 
417*6a54128fSAndroid Build Coastguard Worker 	while (nbytes > 0) {
418*6a54128fSAndroid Build Coastguard Worker 		retval = sync_buffer_position(file);
419*6a54128fSAndroid Build Coastguard Worker 		if (retval)
420*6a54128fSAndroid Build Coastguard Worker 			goto fail;
421*6a54128fSAndroid Build Coastguard Worker 
422*6a54128fSAndroid Build Coastguard Worker 		start = file->pos % fs->blocksize;
423*6a54128fSAndroid Build Coastguard Worker 		c = fs->blocksize - start;
424*6a54128fSAndroid Build Coastguard Worker 		if (c > nbytes)
425*6a54128fSAndroid Build Coastguard Worker 			c = nbytes;
426*6a54128fSAndroid Build Coastguard Worker 
427*6a54128fSAndroid Build Coastguard Worker 		/*
428*6a54128fSAndroid Build Coastguard Worker 		 * We only need to do a read-modify-update cycle if
429*6a54128fSAndroid Build Coastguard Worker 		 * we're doing a partial write.
430*6a54128fSAndroid Build Coastguard Worker 		 */
431*6a54128fSAndroid Build Coastguard Worker 		retval = load_buffer(file, (c == fs->blocksize));
432*6a54128fSAndroid Build Coastguard Worker 		if (retval)
433*6a54128fSAndroid Build Coastguard Worker 			goto fail;
434*6a54128fSAndroid Build Coastguard Worker 
435*6a54128fSAndroid Build Coastguard Worker 		file->flags |= EXT2_FILE_BUF_DIRTY;
436*6a54128fSAndroid Build Coastguard Worker 		memcpy(file->buf+start, ptr, c);
437*6a54128fSAndroid Build Coastguard Worker 
438*6a54128fSAndroid Build Coastguard Worker 		/*
439*6a54128fSAndroid Build Coastguard Worker 		 * OK, the physical block hasn't been allocated yet.
440*6a54128fSAndroid Build Coastguard Worker 		 * Allocate it.
441*6a54128fSAndroid Build Coastguard Worker 		 */
442*6a54128fSAndroid Build Coastguard Worker 		if (!file->physblock) {
443*6a54128fSAndroid Build Coastguard Worker 			bmap_flags = (file->ino ? BMAP_ALLOC : 0);
444*6a54128fSAndroid Build Coastguard Worker 			if (fs->flags & EXT2_FLAG_SHARE_DUP) {
445*6a54128fSAndroid Build Coastguard Worker 				new_block = calloc(1, sizeof(*new_block));
446*6a54128fSAndroid Build Coastguard Worker 				if (!new_block) {
447*6a54128fSAndroid Build Coastguard Worker 					retval = EXT2_ET_NO_MEMORY;
448*6a54128fSAndroid Build Coastguard Worker 					goto fail;
449*6a54128fSAndroid Build Coastguard Worker 				}
450*6a54128fSAndroid Build Coastguard Worker 				ext2fs_sha512((const unsigned char*)file->buf,
451*6a54128fSAndroid Build Coastguard Worker 						fs->blocksize, new_block->sha);
452*6a54128fSAndroid Build Coastguard Worker 				old_block = ext2fs_hashmap_lookup(
453*6a54128fSAndroid Build Coastguard Worker 							fs->block_sha_map,
454*6a54128fSAndroid Build Coastguard Worker 							new_block->sha,
455*6a54128fSAndroid Build Coastguard Worker 							sizeof(new_block->sha));
456*6a54128fSAndroid Build Coastguard Worker 			}
457*6a54128fSAndroid Build Coastguard Worker 
458*6a54128fSAndroid Build Coastguard Worker 			if (old_block) {
459*6a54128fSAndroid Build Coastguard Worker 				file->physblock = old_block->physblock;
460*6a54128fSAndroid Build Coastguard Worker 				bmap_flags |= BMAP_SET;
461*6a54128fSAndroid Build Coastguard Worker 				free(new_block);
462*6a54128fSAndroid Build Coastguard Worker 				new_block = NULL;
463*6a54128fSAndroid Build Coastguard Worker 			}
464*6a54128fSAndroid Build Coastguard Worker 
465*6a54128fSAndroid Build Coastguard Worker 			retval = ext2fs_bmap2(fs, file->ino, &file->inode,
466*6a54128fSAndroid Build Coastguard Worker 					      BMAP_BUFFER,
467*6a54128fSAndroid Build Coastguard Worker 					      bmap_flags,
468*6a54128fSAndroid Build Coastguard Worker 					      file->blockno, 0,
469*6a54128fSAndroid Build Coastguard Worker 					      &file->physblock);
470*6a54128fSAndroid Build Coastguard Worker 			if (retval) {
471*6a54128fSAndroid Build Coastguard Worker 				free(new_block);
472*6a54128fSAndroid Build Coastguard Worker 				new_block = NULL;
473*6a54128fSAndroid Build Coastguard Worker 				goto fail;
474*6a54128fSAndroid Build Coastguard Worker 			}
475*6a54128fSAndroid Build Coastguard Worker 
476*6a54128fSAndroid Build Coastguard Worker 			if (new_block) {
477*6a54128fSAndroid Build Coastguard Worker 				new_block->physblock = file->physblock;
478*6a54128fSAndroid Build Coastguard Worker 				int ret = ext2fs_hashmap_add(fs->block_sha_map,
479*6a54128fSAndroid Build Coastguard Worker 						new_block, new_block->sha,
480*6a54128fSAndroid Build Coastguard Worker 						sizeof(new_block->sha));
481*6a54128fSAndroid Build Coastguard Worker 				if (ret) {
482*6a54128fSAndroid Build Coastguard Worker 					retval = EXT2_ET_NO_MEMORY;
483*6a54128fSAndroid Build Coastguard Worker 					free(new_block);
484*6a54128fSAndroid Build Coastguard Worker 					goto fail;
485*6a54128fSAndroid Build Coastguard Worker 				}
486*6a54128fSAndroid Build Coastguard Worker 			}
487*6a54128fSAndroid Build Coastguard Worker 
488*6a54128fSAndroid Build Coastguard Worker 			if (bmap_flags & BMAP_SET) {
489*6a54128fSAndroid Build Coastguard Worker 				ext2fs_iblk_add_blocks(fs, &file->inode, 1);
490*6a54128fSAndroid Build Coastguard Worker 				ext2fs_write_inode(fs, file->ino, &file->inode);
491*6a54128fSAndroid Build Coastguard Worker 			}
492*6a54128fSAndroid Build Coastguard Worker 		}
493*6a54128fSAndroid Build Coastguard Worker 
494*6a54128fSAndroid Build Coastguard Worker 		file->pos += c;
495*6a54128fSAndroid Build Coastguard Worker 		ptr += c;
496*6a54128fSAndroid Build Coastguard Worker 		count += c;
497*6a54128fSAndroid Build Coastguard Worker 		nbytes -= c;
498*6a54128fSAndroid Build Coastguard Worker 	}
499*6a54128fSAndroid Build Coastguard Worker 
500*6a54128fSAndroid Build Coastguard Worker fail:
501*6a54128fSAndroid Build Coastguard Worker 	/* Update inode size */
502*6a54128fSAndroid Build Coastguard Worker 	if (count != 0 && EXT2_I_SIZE(&file->inode) < file->pos) {
503*6a54128fSAndroid Build Coastguard Worker 		errcode_t	rc;
504*6a54128fSAndroid Build Coastguard Worker 
505*6a54128fSAndroid Build Coastguard Worker 		rc = ext2fs_file_set_size2(file, file->pos);
506*6a54128fSAndroid Build Coastguard Worker 		if (retval == 0)
507*6a54128fSAndroid Build Coastguard Worker 			retval = rc;
508*6a54128fSAndroid Build Coastguard Worker 	}
509*6a54128fSAndroid Build Coastguard Worker 
510*6a54128fSAndroid Build Coastguard Worker 	if (written)
511*6a54128fSAndroid Build Coastguard Worker 		*written = count;
512*6a54128fSAndroid Build Coastguard Worker 	return retval;
513*6a54128fSAndroid Build Coastguard Worker }
514*6a54128fSAndroid Build Coastguard Worker 
ext2fs_file_llseek(ext2_file_t file,__u64 offset,int whence,__u64 * ret_pos)515*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_file_llseek(ext2_file_t file, __u64 offset,
516*6a54128fSAndroid Build Coastguard Worker 			    int whence, __u64 *ret_pos)
517*6a54128fSAndroid Build Coastguard Worker {
518*6a54128fSAndroid Build Coastguard Worker 	EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
519*6a54128fSAndroid Build Coastguard Worker 
520*6a54128fSAndroid Build Coastguard Worker 	if (whence == EXT2_SEEK_SET)
521*6a54128fSAndroid Build Coastguard Worker 		file->pos = offset;
522*6a54128fSAndroid Build Coastguard Worker 	else if (whence == EXT2_SEEK_CUR)
523*6a54128fSAndroid Build Coastguard Worker 		file->pos += offset;
524*6a54128fSAndroid Build Coastguard Worker 	else if (whence == EXT2_SEEK_END)
525*6a54128fSAndroid Build Coastguard Worker 		file->pos = EXT2_I_SIZE(&file->inode) + offset;
526*6a54128fSAndroid Build Coastguard Worker 	else
527*6a54128fSAndroid Build Coastguard Worker 		return EXT2_ET_INVALID_ARGUMENT;
528*6a54128fSAndroid Build Coastguard Worker 
529*6a54128fSAndroid Build Coastguard Worker 	if (ret_pos)
530*6a54128fSAndroid Build Coastguard Worker 		*ret_pos = file->pos;
531*6a54128fSAndroid Build Coastguard Worker 
532*6a54128fSAndroid Build Coastguard Worker 	return 0;
533*6a54128fSAndroid Build Coastguard Worker }
534*6a54128fSAndroid Build Coastguard Worker 
ext2fs_file_lseek(ext2_file_t file,ext2_off_t offset,int whence,ext2_off_t * ret_pos)535*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_file_lseek(ext2_file_t file, ext2_off_t offset,
536*6a54128fSAndroid Build Coastguard Worker 			    int whence, ext2_off_t *ret_pos)
537*6a54128fSAndroid Build Coastguard Worker {
538*6a54128fSAndroid Build Coastguard Worker 	__u64		loffset, ret_loffset = 0;
539*6a54128fSAndroid Build Coastguard Worker 	errcode_t	retval;
540*6a54128fSAndroid Build Coastguard Worker 
541*6a54128fSAndroid Build Coastguard Worker 	loffset = offset;
542*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_file_llseek(file, loffset, whence, &ret_loffset);
543*6a54128fSAndroid Build Coastguard Worker 	if (ret_pos)
544*6a54128fSAndroid Build Coastguard Worker 		*ret_pos = (ext2_off_t) ret_loffset;
545*6a54128fSAndroid Build Coastguard Worker 	return retval;
546*6a54128fSAndroid Build Coastguard Worker }
547*6a54128fSAndroid Build Coastguard Worker 
548*6a54128fSAndroid Build Coastguard Worker 
549*6a54128fSAndroid Build Coastguard Worker /*
550*6a54128fSAndroid Build Coastguard Worker  * This function returns the size of the file, according to the inode
551*6a54128fSAndroid Build Coastguard Worker  */
ext2fs_file_get_lsize(ext2_file_t file,__u64 * ret_size)552*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_file_get_lsize(ext2_file_t file, __u64 *ret_size)
553*6a54128fSAndroid Build Coastguard Worker {
554*6a54128fSAndroid Build Coastguard Worker 	if (file->magic != EXT2_ET_MAGIC_EXT2_FILE)
555*6a54128fSAndroid Build Coastguard Worker 		return EXT2_ET_MAGIC_EXT2_FILE;
556*6a54128fSAndroid Build Coastguard Worker 	*ret_size = EXT2_I_SIZE(&file->inode);
557*6a54128fSAndroid Build Coastguard Worker 	return 0;
558*6a54128fSAndroid Build Coastguard Worker }
559*6a54128fSAndroid Build Coastguard Worker 
560*6a54128fSAndroid Build Coastguard Worker /*
561*6a54128fSAndroid Build Coastguard Worker  * This function returns the size of the file, according to the inode
562*6a54128fSAndroid Build Coastguard Worker  */
ext2fs_file_get_size(ext2_file_t file)563*6a54128fSAndroid Build Coastguard Worker ext2_off_t ext2fs_file_get_size(ext2_file_t file)
564*6a54128fSAndroid Build Coastguard Worker {
565*6a54128fSAndroid Build Coastguard Worker 	__u64	size;
566*6a54128fSAndroid Build Coastguard Worker 
567*6a54128fSAndroid Build Coastguard Worker 	if (ext2fs_file_get_lsize(file, &size))
568*6a54128fSAndroid Build Coastguard Worker 		return 0;
569*6a54128fSAndroid Build Coastguard Worker 	if ((size >> 32) != 0)
570*6a54128fSAndroid Build Coastguard Worker 		return 0;
571*6a54128fSAndroid Build Coastguard Worker 	return size;
572*6a54128fSAndroid Build Coastguard Worker }
573*6a54128fSAndroid Build Coastguard Worker 
574*6a54128fSAndroid Build Coastguard Worker /* Zero the parts of the last block that are past EOF. */
ext2fs_file_zero_past_offset(ext2_file_t file,ext2_off64_t offset)575*6a54128fSAndroid Build Coastguard Worker static errcode_t ext2fs_file_zero_past_offset(ext2_file_t file,
576*6a54128fSAndroid Build Coastguard Worker 					      ext2_off64_t offset)
577*6a54128fSAndroid Build Coastguard Worker {
578*6a54128fSAndroid Build Coastguard Worker 	ext2_filsys fs = file->fs;
579*6a54128fSAndroid Build Coastguard Worker 	char *b = NULL;
580*6a54128fSAndroid Build Coastguard Worker 	ext2_off64_t off = offset % fs->blocksize;
581*6a54128fSAndroid Build Coastguard Worker 	blk64_t blk;
582*6a54128fSAndroid Build Coastguard Worker 	int ret_flags;
583*6a54128fSAndroid Build Coastguard Worker 	errcode_t retval;
584*6a54128fSAndroid Build Coastguard Worker 
585*6a54128fSAndroid Build Coastguard Worker 	if (off == 0)
586*6a54128fSAndroid Build Coastguard Worker 		return 0;
587*6a54128fSAndroid Build Coastguard Worker 
588*6a54128fSAndroid Build Coastguard Worker 	retval = sync_buffer_position(file);
589*6a54128fSAndroid Build Coastguard Worker 	if (retval)
590*6a54128fSAndroid Build Coastguard Worker 		return retval;
591*6a54128fSAndroid Build Coastguard Worker 
592*6a54128fSAndroid Build Coastguard Worker 	/* Is there an initialized block at the end? */
593*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_bmap2(fs, file->ino, NULL, NULL, 0,
594*6a54128fSAndroid Build Coastguard Worker 			      offset / fs->blocksize, &ret_flags, &blk);
595*6a54128fSAndroid Build Coastguard Worker 	if (retval)
596*6a54128fSAndroid Build Coastguard Worker 		return retval;
597*6a54128fSAndroid Build Coastguard Worker 	if ((blk == 0) || (ret_flags & BMAP_RET_UNINIT))
598*6a54128fSAndroid Build Coastguard Worker 		return 0;
599*6a54128fSAndroid Build Coastguard Worker 
600*6a54128fSAndroid Build Coastguard Worker 	/* Zero to the end of the block */
601*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_get_mem(fs->blocksize, &b);
602*6a54128fSAndroid Build Coastguard Worker 	if (retval)
603*6a54128fSAndroid Build Coastguard Worker 		return retval;
604*6a54128fSAndroid Build Coastguard Worker 
605*6a54128fSAndroid Build Coastguard Worker 	/* Read/zero/write block */
606*6a54128fSAndroid Build Coastguard Worker 	retval = io_channel_read_blk64(fs->io, blk, 1, b);
607*6a54128fSAndroid Build Coastguard Worker 	if (retval)
608*6a54128fSAndroid Build Coastguard Worker 		goto out;
609*6a54128fSAndroid Build Coastguard Worker 
610*6a54128fSAndroid Build Coastguard Worker 	memset(b + off, 0, fs->blocksize - off);
611*6a54128fSAndroid Build Coastguard Worker 
612*6a54128fSAndroid Build Coastguard Worker 	retval = io_channel_write_blk64(fs->io, blk, 1, b);
613*6a54128fSAndroid Build Coastguard Worker 	if (retval)
614*6a54128fSAndroid Build Coastguard Worker 		goto out;
615*6a54128fSAndroid Build Coastguard Worker 
616*6a54128fSAndroid Build Coastguard Worker out:
617*6a54128fSAndroid Build Coastguard Worker 	ext2fs_free_mem(&b);
618*6a54128fSAndroid Build Coastguard Worker 	return retval;
619*6a54128fSAndroid Build Coastguard Worker }
620*6a54128fSAndroid Build Coastguard Worker 
621*6a54128fSAndroid Build Coastguard Worker /*
622*6a54128fSAndroid Build Coastguard Worker  * This function sets the size of the file, truncating it if necessary
623*6a54128fSAndroid Build Coastguard Worker  *
624*6a54128fSAndroid Build Coastguard Worker  */
ext2fs_file_set_size2(ext2_file_t file,ext2_off64_t size)625*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_file_set_size2(ext2_file_t file, ext2_off64_t size)
626*6a54128fSAndroid Build Coastguard Worker {
627*6a54128fSAndroid Build Coastguard Worker 	ext2_off64_t	old_size;
628*6a54128fSAndroid Build Coastguard Worker 	errcode_t	retval;
629*6a54128fSAndroid Build Coastguard Worker 	blk64_t		old_truncate, truncate_block;
630*6a54128fSAndroid Build Coastguard Worker 
631*6a54128fSAndroid Build Coastguard Worker 	EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
632*6a54128fSAndroid Build Coastguard Worker 
633*6a54128fSAndroid Build Coastguard Worker 	if (size && ext2fs_file_block_offset_too_big(file->fs, &file->inode,
634*6a54128fSAndroid Build Coastguard Worker 					(size - 1) / file->fs->blocksize))
635*6a54128fSAndroid Build Coastguard Worker 		return EXT2_ET_FILE_TOO_BIG;
636*6a54128fSAndroid Build Coastguard Worker 	truncate_block = ((size + file->fs->blocksize - 1) >>
637*6a54128fSAndroid Build Coastguard Worker 			  EXT2_BLOCK_SIZE_BITS(file->fs->super));
638*6a54128fSAndroid Build Coastguard Worker 	old_size = EXT2_I_SIZE(&file->inode);
639*6a54128fSAndroid Build Coastguard Worker 	old_truncate = ((old_size + file->fs->blocksize - 1) >>
640*6a54128fSAndroid Build Coastguard Worker 		      EXT2_BLOCK_SIZE_BITS(file->fs->super));
641*6a54128fSAndroid Build Coastguard Worker 
642*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_inode_size_set(file->fs, &file->inode, size);
643*6a54128fSAndroid Build Coastguard Worker 	if (retval)
644*6a54128fSAndroid Build Coastguard Worker 		return retval;
645*6a54128fSAndroid Build Coastguard Worker 
646*6a54128fSAndroid Build Coastguard Worker 	if (file->ino) {
647*6a54128fSAndroid Build Coastguard Worker 		retval = ext2fs_write_inode(file->fs, file->ino, &file->inode);
648*6a54128fSAndroid Build Coastguard Worker 		if (retval)
649*6a54128fSAndroid Build Coastguard Worker 			return retval;
650*6a54128fSAndroid Build Coastguard Worker 	}
651*6a54128fSAndroid Build Coastguard Worker 
652*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_file_zero_past_offset(file, size);
653*6a54128fSAndroid Build Coastguard Worker 	if (retval)
654*6a54128fSAndroid Build Coastguard Worker 		return retval;
655*6a54128fSAndroid Build Coastguard Worker 
656*6a54128fSAndroid Build Coastguard Worker 	if (truncate_block >= old_truncate)
657*6a54128fSAndroid Build Coastguard Worker 		return 0;
658*6a54128fSAndroid Build Coastguard Worker 
659*6a54128fSAndroid Build Coastguard Worker 	return ext2fs_punch(file->fs, file->ino, &file->inode, 0,
660*6a54128fSAndroid Build Coastguard Worker 			    truncate_block, ~0ULL);
661*6a54128fSAndroid Build Coastguard Worker }
662*6a54128fSAndroid Build Coastguard Worker 
ext2fs_file_set_size(ext2_file_t file,ext2_off_t size)663*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_file_set_size(ext2_file_t file, ext2_off_t size)
664*6a54128fSAndroid Build Coastguard Worker {
665*6a54128fSAndroid Build Coastguard Worker 	return ext2fs_file_set_size2(file, size);
666*6a54128fSAndroid Build Coastguard Worker }
667