source: branches/stable/mindi-busybox/e2fsprogs/ext2fs/fileio.c @ 821

Last change on this file since 821 was 821, checked in by Bruno Cornec, 14 years ago

Addition of busybox 1.2.1 as a mindi-busybox new package
This should avoid delivering binary files in mindi not built there (Fedora and Debian are quite serious about that)

File size: 7.7 KB
RevLine 
[821]1/*
2 * fileio.c --- Simple file I/O routines
3 *
4 * Copyright (C) 1997 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#include <string.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17
18#include "ext2_fs.h"
19#include "ext2fs.h"
20
21struct ext2_file {
22    errcode_t       magic;
23    ext2_filsys     fs;
24    ext2_ino_t      ino;
25    struct ext2_inode   inode;
26    int         flags;
27    __u64           pos;
28    blk_t           blockno;
29    blk_t           physblock;
30    char            *buf;
31};
32
33#define BMAP_BUFFER (file->buf + fs->blocksize)
34
35errcode_t ext2fs_file_open2(ext2_filsys fs, ext2_ino_t ino,
36                struct ext2_inode *inode,
37                int flags, ext2_file_t *ret)
38{
39    ext2_file_t file;
40    errcode_t   retval;
41
42    /*
43     * Don't let caller create or open a file for writing if the
44     * filesystem is read-only.
45     */
46    if ((flags & (EXT2_FILE_WRITE | EXT2_FILE_CREATE)) &&
47        !(fs->flags & EXT2_FLAG_RW))
48        return EXT2_ET_RO_FILSYS;
49
50    retval = ext2fs_get_mem(sizeof(struct ext2_file), &file);
51    if (retval)
52        return retval;
53
54    memset(file, 0, sizeof(struct ext2_file));
55    file->magic = EXT2_ET_MAGIC_EXT2_FILE;
56    file->fs = fs;
57    file->ino = ino;
58    file->flags = flags & EXT2_FILE_MASK;
59
60    if (inode) {
61        memcpy(&file->inode, inode, sizeof(struct ext2_inode));
62    } else {
63        retval = ext2fs_read_inode(fs, ino, &file->inode);
64        if (retval)
65            goto fail;
66    }
67
68    retval = ext2fs_get_mem(fs->blocksize * 3, &file->buf);
69    if (retval)
70        goto fail;
71
72    *ret = file;
73    return 0;
74
75fail:
76    ext2fs_free_mem(&file->buf);
77    ext2fs_free_mem(&file);
78    return retval;
79}
80
81errcode_t ext2fs_file_open(ext2_filsys fs, ext2_ino_t ino,
82               int flags, ext2_file_t *ret)
83{
84    return ext2fs_file_open2(fs, ino, NULL, flags, ret);
85}
86
87/*
88 * This function returns the filesystem handle of a file from the structure
89 */
90ext2_filsys ext2fs_file_get_fs(ext2_file_t file)
91{
92    if (file->magic != EXT2_ET_MAGIC_EXT2_FILE)
93        return 0;
94    return file->fs;
95}
96
97/*
98 * This function flushes the dirty block buffer out to disk if
99 * necessary.
100 */
101errcode_t ext2fs_file_flush(ext2_file_t file)
102{
103    errcode_t   retval;
104    ext2_filsys fs;
105
106    EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
107    fs = file->fs;
108
109    if (!(file->flags & EXT2_FILE_BUF_VALID) ||
110        !(file->flags & EXT2_FILE_BUF_DIRTY))
111        return 0;
112
113    /*
114     * OK, the physical block hasn't been allocated yet.
115     * Allocate it.
116     */
117    if (!file->physblock) {
118        retval = ext2fs_bmap(fs, file->ino, &file->inode,
119                     BMAP_BUFFER, file->ino ? BMAP_ALLOC : 0,
120                     file->blockno, &file->physblock);
121        if (retval)
122            return retval;
123    }
124
125    retval = io_channel_write_blk(fs->io, file->physblock,
126                      1, file->buf);
127    if (retval)
128        return retval;
129
130    file->flags &= ~EXT2_FILE_BUF_DIRTY;
131
132    return retval;
133}
134
135/*
136 * This function synchronizes the file's block buffer and the current
137 * file position, possibly invalidating block buffer if necessary
138 */
139static errcode_t sync_buffer_position(ext2_file_t file)
140{
141    blk_t   b;
142    errcode_t   retval;
143
144    b = file->pos / file->fs->blocksize;
145    if (b != file->blockno) {
146        retval = ext2fs_file_flush(file);
147        if (retval)
148            return retval;
149        file->flags &= ~EXT2_FILE_BUF_VALID;
150    }
151    file->blockno = b;
152    return 0;
153}
154
155/*
156 * This function loads the file's block buffer with valid data from
157 * the disk as necessary.
158 *
159 * If dontfill is true, then skip initializing the buffer since we're
160 * going to be replacing its entire contents anyway.  If set, then the
161 * function basically only sets file->physblock and EXT2_FILE_BUF_VALID
162 */
163#define DONTFILL 1
164static errcode_t load_buffer(ext2_file_t file, int dontfill)
165{
166    ext2_filsys fs = file->fs;
167    errcode_t   retval;
168
169    if (!(file->flags & EXT2_FILE_BUF_VALID)) {
170        retval = ext2fs_bmap(fs, file->ino, &file->inode,
171                     BMAP_BUFFER, 0, file->blockno,
172                     &file->physblock);
173        if (retval)
174            return retval;
175        if (!dontfill) {
176            if (file->physblock) {
177                retval = io_channel_read_blk(fs->io,
178                                 file->physblock,
179                                 1, file->buf);
180                if (retval)
181                    return retval;
182            } else
183                memset(file->buf, 0, fs->blocksize);
184        }
185        file->flags |= EXT2_FILE_BUF_VALID;
186    }
187    return 0;
188}
189
190
191errcode_t ext2fs_file_close(ext2_file_t file)
192{
193    errcode_t   retval;
194
195    EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
196
197    retval = ext2fs_file_flush(file);
198
199    ext2fs_free_mem(&file->buf);
200    ext2fs_free_mem(&file);
201
202    return retval;
203}
204
205
206errcode_t ext2fs_file_read(ext2_file_t file, void *buf,
207               unsigned int wanted, unsigned int *got)
208{
209    ext2_filsys fs;
210    errcode_t   retval = 0;
211    unsigned int    start, c, count = 0;
212    __u64       left;
213    char        *ptr = (char *) buf;
214
215    EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
216    fs = file->fs;
217
218    while ((file->pos < EXT2_I_SIZE(&file->inode)) && (wanted > 0)) {
219        retval = sync_buffer_position(file);
220        if (retval)
221            goto fail;
222        retval = load_buffer(file, 0);
223        if (retval)
224            goto fail;
225
226        start = file->pos % fs->blocksize;
227        c = fs->blocksize - start;
228        if (c > wanted)
229            c = wanted;
230        left = EXT2_I_SIZE(&file->inode) - file->pos ;
231        if (c > left)
232            c = left;
233
234        memcpy(ptr, file->buf+start, c);
235        file->pos += c;
236        ptr += c;
237        count += c;
238        wanted -= c;
239    }
240
241fail:
242    if (got)
243        *got = count;
244    return retval;
245}
246
247
248errcode_t ext2fs_file_write(ext2_file_t file, const void *buf,
249                unsigned int nbytes, unsigned int *written)
250{
251    ext2_filsys fs;
252    errcode_t   retval = 0;
253    unsigned int    start, c, count = 0;
254    const char  *ptr = (const char *) buf;
255
256    EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
257    fs = file->fs;
258
259    if (!(file->flags & EXT2_FILE_WRITE))
260        return EXT2_ET_FILE_RO;
261
262    while (nbytes > 0) {
263        retval = sync_buffer_position(file);
264        if (retval)
265            goto fail;
266
267        start = file->pos % fs->blocksize;
268        c = fs->blocksize - start;
269        if (c > nbytes)
270            c = nbytes;
271
272        /*
273         * We only need to do a read-modify-update cycle if
274         * we're doing a partial write.
275         */
276        retval = load_buffer(file, (c == fs->blocksize));
277        if (retval)
278            goto fail;
279
280        file->flags |= EXT2_FILE_BUF_DIRTY;
281        memcpy(file->buf+start, ptr, c);
282        file->pos += c;
283        ptr += c;
284        count += c;
285        nbytes -= c;
286    }
287
288fail:
289    if (written)
290        *written = count;
291    return retval;
292}
293
294errcode_t ext2fs_file_llseek(ext2_file_t file, __u64 offset,
295                int whence, __u64 *ret_pos)
296{
297    EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
298
299    if (whence == EXT2_SEEK_SET)
300        file->pos = offset;
301    else if (whence == EXT2_SEEK_CUR)
302        file->pos += offset;
303    else if (whence == EXT2_SEEK_END)
304        file->pos = EXT2_I_SIZE(&file->inode) + offset;
305    else
306        return EXT2_ET_INVALID_ARGUMENT;
307
308    if (ret_pos)
309        *ret_pos = file->pos;
310
311    return 0;
312}
313
314errcode_t ext2fs_file_lseek(ext2_file_t file, ext2_off_t offset,
315                int whence, ext2_off_t *ret_pos)
316{
317    __u64       loffset, ret_loffset;
318    errcode_t   retval;
319
320    loffset = offset;
321    retval = ext2fs_file_llseek(file, loffset, whence, &ret_loffset);
322    if (ret_pos)
323        *ret_pos = (ext2_off_t) ret_loffset;
324    return retval;
325}
326
327
328/*
329 * This function returns the size of the file, according to the inode
330 */
331errcode_t ext2fs_file_get_lsize(ext2_file_t file, __u64 *ret_size)
332{
333    if (file->magic != EXT2_ET_MAGIC_EXT2_FILE)
334        return EXT2_ET_MAGIC_EXT2_FILE;
335    *ret_size = EXT2_I_SIZE(&file->inode);
336    return 0;
337}
338
339/*
340 * This function returns the size of the file, according to the inode
341 */
342ext2_off_t ext2fs_file_get_size(ext2_file_t file)
343{
344    __u64   size;
345
346    if (ext2fs_file_get_lsize(file, &size))
347        return 0;
348    if ((size >> 32) != 0)
349        return 0;
350    return size;
351}
352
353/*
354 * This function sets the size of the file, truncating it if necessary
355 *
356 * XXX still need to call truncate
357 */
358errcode_t ext2fs_file_set_size(ext2_file_t file, ext2_off_t size)
359{
360    errcode_t   retval;
361    EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
362
363    file->inode.i_size = size;
364    file->inode.i_size_high = 0;
365    if (file->ino) {
366        retval = ext2fs_write_inode(file->fs, file->ino, &file->inode);
367        if (retval)
368            return retval;
369    }
370
371    /*
372     * XXX truncate inode if necessary
373     */
374
375    return 0;
376}
Note: See TracBrowser for help on using the repository browser.