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