~ubuntu-branches/ubuntu/edgy/e2fsprogs/edgy

« back to all changes in this revision

Viewing changes to lib/ext2fs/inode.c

  • Committer: Bazaar Package Importer
  • Author(s): Yann Dirson
  • Date: 2002-03-21 23:58:48 UTC
  • Revision ID: james.westby@ubuntu.com-20020321235848-cmmy98hy0nihp922
Tags: upstream-1.27
ImportĀ upstreamĀ versionĀ 1.27

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * inode.c --- utility routines to read and write inodes
 
3
 * 
 
4
 * Copyright (C) 1993, 1994, 1995, 1996, 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
#if HAVE_SYS_STAT_H
 
18
#include <sys/stat.h>
 
19
#endif
 
20
#if HAVE_SYS_TYPES_H
 
21
#include <sys/types.h>
 
22
#endif
 
23
 
 
24
#include "ext2_fs.h"
 
25
#include "ext2fsP.h"
 
26
#include "e2image.h"
 
27
 
 
28
struct ext2_struct_inode_scan {
 
29
        errcode_t               magic;
 
30
        ext2_filsys             fs;
 
31
        ext2_ino_t              current_inode;
 
32
        blk_t                   current_block;
 
33
        dgrp_t                  current_group;
 
34
        ext2_ino_t              inodes_left;
 
35
        blk_t                   blocks_left;
 
36
        dgrp_t                  groups_left;
 
37
        blk_t                   inode_buffer_blocks;
 
38
        char *                  inode_buffer;
 
39
        int                     inode_size;
 
40
        char *                  ptr;
 
41
        int                     bytes_left;
 
42
        char                    *temp_buffer;
 
43
        errcode_t               (*done_group)(ext2_filsys fs,
 
44
                                              ext2_inode_scan scan,
 
45
                                              dgrp_t group,
 
46
                                              void * priv_data);
 
47
        void *                  done_group_data;
 
48
        int                     bad_block_ptr;
 
49
        int                     scan_flags;
 
50
        int                     reserved[6];
 
51
};
 
52
 
 
53
/*
 
54
 * This routine flushes the icache, if it exists.
 
55
 */
 
56
errcode_t ext2fs_flush_icache(ext2_filsys fs)
 
57
{
 
58
        int     i;
 
59
        
 
60
        if (!fs->icache)
 
61
                return 0;
 
62
 
 
63
        for (i=0; i < fs->icache->cache_size; i++)
 
64
                fs->icache->cache[i].ino = 0;
 
65
 
 
66
        return 0;
 
67
}
 
68
 
 
69
static errcode_t create_icache(ext2_filsys fs)
 
70
{
 
71
        errcode_t       retval;
 
72
        
 
73
        if (fs->icache)
 
74
                return 0;
 
75
        retval = ext2fs_get_mem(sizeof(struct ext2_inode_cache), 
 
76
                                (void **) &fs->icache);
 
77
        if (retval)
 
78
                return retval;
 
79
 
 
80
        memset(fs->icache, 0, sizeof(struct ext2_inode_cache));
 
81
        retval = ext2fs_get_mem(fs->blocksize, (void **) &fs->icache->buffer);
 
82
        if (retval) {
 
83
                ext2fs_free_mem((void **) &fs->icache);
 
84
                return retval;
 
85
        }
 
86
        fs->icache->buffer_blk = 0;
 
87
        fs->icache->cache_last = -1;
 
88
        fs->icache->cache_size = 4;
 
89
        fs->icache->refcount = 1;
 
90
        retval = ext2fs_get_mem(sizeof(struct ext2_inode_cache_ent)
 
91
                                * fs->icache->cache_size,
 
92
                                (void **) &fs->icache->cache);
 
93
        if (retval) {
 
94
                ext2fs_free_mem((void **) &fs->icache->buffer);
 
95
                ext2fs_free_mem((void **) &fs->icache);
 
96
                return retval;
 
97
        }
 
98
        ext2fs_flush_icache(fs);
 
99
        return 0;
 
100
}
 
101
 
 
102
errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
 
103
                                 ext2_inode_scan *ret_scan)
 
104
{
 
105
        ext2_inode_scan scan;
 
106
        errcode_t       retval;
 
107
        errcode_t (*save_get_blocks)(ext2_filsys f, ext2_ino_t ino, blk_t *blocks);
 
108
 
 
109
        EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
110
 
 
111
        /*
 
112
         * If fs->badblocks isn't set, then set it --- since the inode
 
113
         * scanning functions require it.
 
114
         */
 
115
        if (fs->badblocks == 0) {
 
116
                /*
 
117
                 * Temporarly save fs->get_blocks and set it to zero,
 
118
                 * for compatibility with old e2fsck's.
 
119
                 */
 
120
                save_get_blocks = fs->get_blocks;
 
121
                fs->get_blocks = 0;
 
122
                retval = ext2fs_read_bb_inode(fs, &fs->badblocks);
 
123
                if (retval && fs->badblocks) {
 
124
                        ext2fs_badblocks_list_free(fs->badblocks);
 
125
                        fs->badblocks = 0;
 
126
                }
 
127
                fs->get_blocks = save_get_blocks;
 
128
        }
 
129
 
 
130
        retval = ext2fs_get_mem(sizeof(struct ext2_struct_inode_scan),
 
131
                                (void **) &scan);
 
132
        if (retval)
 
133
                return retval;
 
134
        memset(scan, 0, sizeof(struct ext2_struct_inode_scan));
 
135
 
 
136
        scan->magic = EXT2_ET_MAGIC_INODE_SCAN;
 
137
        scan->fs = fs;
 
138
        scan->inode_size = EXT2_INODE_SIZE(fs->super);
 
139
        scan->bytes_left = 0;
 
140
        scan->current_group = 0;
 
141
        scan->groups_left = fs->group_desc_count - 1;
 
142
        scan->inode_buffer_blocks = buffer_blocks ? buffer_blocks : 8;
 
143
        scan->current_block = scan->fs->
 
144
                group_desc[scan->current_group].bg_inode_table;
 
145
        scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super);
 
146
        scan->blocks_left = scan->fs->inode_blocks_per_group;
 
147
        retval = ext2fs_get_mem((size_t) (scan->inode_buffer_blocks * 
 
148
                                          fs->blocksize),
 
149
                                (void **) &scan->inode_buffer);
 
150
        scan->done_group = 0;
 
151
        scan->done_group_data = 0;
 
152
        scan->bad_block_ptr = 0;
 
153
        if (retval) {
 
154
                ext2fs_free_mem((void **) &scan);
 
155
                return retval;
 
156
        }
 
157
        retval = ext2fs_get_mem(scan->inode_size,
 
158
                                (void **) &scan->temp_buffer);
 
159
        if (retval) {
 
160
                ext2fs_free_mem((void **) &scan->inode_buffer);
 
161
                ext2fs_free_mem((void **) &scan);
 
162
                return retval;
 
163
        }
 
164
        if (scan->fs->badblocks && scan->fs->badblocks->num)
 
165
                scan->scan_flags |= EXT2_SF_CHK_BADBLOCKS;
 
166
        *ret_scan = scan;
 
167
        return 0;
 
168
}
 
169
 
 
170
void ext2fs_close_inode_scan(ext2_inode_scan scan)
 
171
{
 
172
        if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
 
173
                return;
 
174
        
 
175
        ext2fs_free_mem((void **) &scan->inode_buffer);
 
176
        scan->inode_buffer = NULL;
 
177
        ext2fs_free_mem((void **) &scan->temp_buffer);
 
178
        scan->temp_buffer = NULL;
 
179
        ext2fs_free_mem((void **) &scan);
 
180
        return;
 
181
}
 
182
 
 
183
void ext2fs_set_inode_callback(ext2_inode_scan scan,
 
184
                               errcode_t (*done_group)(ext2_filsys fs,
 
185
                                                       ext2_inode_scan scan,
 
186
                                                       dgrp_t group,
 
187
                                                       void * priv_data),
 
188
                               void *done_group_data)
 
189
{
 
190
        if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
 
191
                return;
 
192
        
 
193
        scan->done_group = done_group;
 
194
        scan->done_group_data = done_group_data;
 
195
}
 
196
 
 
197
int ext2fs_inode_scan_flags(ext2_inode_scan scan, int set_flags,
 
198
                            int clear_flags)
 
199
{
 
200
        int     old_flags;
 
201
 
 
202
        if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
 
203
                return 0;
 
204
 
 
205
        old_flags = scan->scan_flags;
 
206
        scan->scan_flags &= ~clear_flags;
 
207
        scan->scan_flags |= set_flags;
 
208
        return old_flags;
 
209
}
 
210
 
 
211
/*
 
212
 * This function is called by ext2fs_get_next_inode when it needs to
 
213
 * get ready to read in a new blockgroup.
 
214
 */
 
215
static errcode_t get_next_blockgroup(ext2_inode_scan scan)
 
216
{
 
217
        scan->current_group++;
 
218
        scan->groups_left--;
 
219
                        
 
220
        scan->current_block = scan->fs->
 
221
                group_desc[scan->current_group].bg_inode_table;
 
222
 
 
223
        scan->current_inode = scan->current_group *
 
224
                EXT2_INODES_PER_GROUP(scan->fs->super);
 
225
 
 
226
        scan->bytes_left = 0;
 
227
        scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super);
 
228
        scan->blocks_left = scan->fs->inode_blocks_per_group;
 
229
        return 0;
 
230
}
 
231
 
 
232
errcode_t ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan,
 
233
                                            int group)
 
234
{
 
235
        scan->current_group = group - 1;
 
236
        scan->groups_left = scan->fs->group_desc_count - group;
 
237
        return get_next_blockgroup(scan);
 
238
}
 
239
 
 
240
/*
 
241
 * This function is called by get_next_blocks() to check for bad
 
242
 * blocks in the inode table.
 
243
 *
 
244
 * This function assumes that badblocks_list->list is sorted in
 
245
 * increasing order.
 
246
 */
 
247
static errcode_t check_for_inode_bad_blocks(ext2_inode_scan scan,
 
248
                                            blk_t *num_blocks)
 
249
{
 
250
        blk_t   blk = scan->current_block;
 
251
        badblocks_list  bb = scan->fs->badblocks;
 
252
 
 
253
        /*
 
254
         * If the inode table is missing, then obviously there are no
 
255
         * bad blocks.  :-)
 
256
         */
 
257
        if (blk == 0)
 
258
                return 0;
 
259
 
 
260
        /*
 
261
         * If the current block is greater than the bad block listed
 
262
         * in the bad block list, then advance the pointer until this
 
263
         * is no longer the case.  If we run out of bad blocks, then
 
264
         * we don't need to do any more checking!
 
265
         */
 
266
        while (blk > bb->list[scan->bad_block_ptr]) {
 
267
                if (++scan->bad_block_ptr >= bb->num) {
 
268
                        scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS;
 
269
                        return 0;
 
270
                }
 
271
        }
 
272
 
 
273
        /*
 
274
         * If the current block is equal to the bad block listed in
 
275
         * the bad block list, then handle that one block specially.
 
276
         * (We could try to handle runs of bad blocks, but that
 
277
         * only increases CPU efficiency by a small amount, at the
 
278
         * expense of a huge expense of code complexity, and for an
 
279
         * uncommon case at that.)
 
280
         */
 
281
        if (blk == bb->list[scan->bad_block_ptr]) {
 
282
                scan->scan_flags |= EXT2_SF_BAD_INODE_BLK;
 
283
                *num_blocks = 1;
 
284
                if (++scan->bad_block_ptr >= bb->num)
 
285
                        scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS;
 
286
                return 0;
 
287
        }
 
288
 
 
289
        /*
 
290
         * If there is a bad block in the range that we're about to
 
291
         * read in, adjust the number of blocks to read so that we we
 
292
         * don't read in the bad block.  (Then the next block to read
 
293
         * will be the bad block, which is handled in the above case.)
 
294
         */
 
295
        if ((blk + *num_blocks) > bb->list[scan->bad_block_ptr])
 
296
                *num_blocks = (int) (bb->list[scan->bad_block_ptr] - blk);
 
297
 
 
298
        return 0;
 
299
}
 
300
 
 
301
/*
 
302
 * This function is called by ext2fs_get_next_inode when it needs to
 
303
 * read in more blocks from the current blockgroup's inode table.
 
304
 */
 
305
static errcode_t get_next_blocks(ext2_inode_scan scan)
 
306
{
 
307
        blk_t           num_blocks;
 
308
        errcode_t       retval;
 
309
 
 
310
        /*
 
311
         * Figure out how many blocks to read; we read at most
 
312
         * inode_buffer_blocks, and perhaps less if there aren't that
 
313
         * many blocks left to read.
 
314
         */
 
315
        num_blocks = scan->inode_buffer_blocks;
 
316
        if (num_blocks > scan->blocks_left)
 
317
                num_blocks = scan->blocks_left;
 
318
 
 
319
        /*
 
320
         * If the past block "read" was a bad block, then mark the
 
321
         * left-over extra bytes as also being bad.
 
322
         */
 
323
        if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK) {
 
324
                if (scan->bytes_left)
 
325
                        scan->scan_flags |= EXT2_SF_BAD_EXTRA_BYTES;
 
326
                scan->scan_flags &= ~EXT2_SF_BAD_INODE_BLK;
 
327
        }
 
328
 
 
329
        /*
 
330
         * Do inode bad block processing, if necessary.
 
331
         */
 
332
        if (scan->scan_flags & EXT2_SF_CHK_BADBLOCKS) {
 
333
                retval = check_for_inode_bad_blocks(scan, &num_blocks);
 
334
                if (retval)
 
335
                        return retval;
 
336
        }
 
337
                
 
338
        if ((scan->scan_flags & EXT2_SF_BAD_INODE_BLK) ||
 
339
            (scan->current_block == 0)) {
 
340
                memset(scan->inode_buffer, 0,
 
341
                       (size_t) num_blocks * scan->fs->blocksize);
 
342
        } else {
 
343
                retval = io_channel_read_blk(scan->fs->io,
 
344
                                             scan->current_block,
 
345
                                             (int) num_blocks,
 
346
                                             scan->inode_buffer);
 
347
                if (retval)
 
348
                        return EXT2_ET_NEXT_INODE_READ;
 
349
        }
 
350
        scan->ptr = scan->inode_buffer;
 
351
        scan->bytes_left = num_blocks * scan->fs->blocksize;
 
352
 
 
353
        scan->blocks_left -= num_blocks;
 
354
        if (scan->current_block)
 
355
                scan->current_block += num_blocks;
 
356
        return 0;
 
357
}
 
358
 
 
359
#if 0
 
360
/*
 
361
 * Returns 1 if the entire inode_buffer has a non-zero size and
 
362
 * contains all zeros.  (Not just deleted inodes, since that means
 
363
 * that part of the inode table was used at one point; we want all
 
364
 * zeros, which means that the inode table is pristine.)
 
365
 */
 
366
static inline int is_empty_scan(ext2_inode_scan scan)
 
367
{
 
368
        int     i;
 
369
        
 
370
        if (scan->bytes_left == 0)
 
371
                return 0;
 
372
 
 
373
        for (i=0; i < scan->bytes_left; i++)
 
374
                if (scan->ptr[i])
 
375
                        return 0;
 
376
        return 1;
 
377
}
 
378
#endif
 
379
 
 
380
errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino,
 
381
                                struct ext2_inode *inode)
 
382
{
 
383
        errcode_t       retval;
 
384
        int             extra_bytes = 0;
 
385
        
 
386
        EXT2_CHECK_MAGIC(scan, EXT2_ET_MAGIC_INODE_SCAN);
 
387
 
 
388
        /*
 
389
         * Do we need to start reading a new block group?
 
390
         */
 
391
        if (scan->inodes_left <= 0) {
 
392
        force_new_group:
 
393
                if (scan->done_group) {
 
394
                        retval = (scan->done_group)
 
395
                                (scan->fs, scan, scan->current_group,
 
396
                                 scan->done_group_data);
 
397
                        if (retval)
 
398
                                return retval;
 
399
                }
 
400
                if (scan->groups_left <= 0) {
 
401
                        *ino = 0;
 
402
                        return 0;
 
403
                }
 
404
                retval = get_next_blockgroup(scan);
 
405
                if (retval)
 
406
                        return retval;
 
407
        }
 
408
        /*
 
409
         * This is done outside the above if statement so that the
 
410
         * check can be done for block group #0.
 
411
         */
 
412
        if (scan->current_block == 0) {
 
413
                if (scan->scan_flags & EXT2_SF_SKIP_MISSING_ITABLE) {
 
414
                        goto force_new_group;
 
415
                } else
 
416
                        return EXT2_ET_MISSING_INODE_TABLE;
 
417
        }
 
418
        
 
419
 
 
420
        /*
 
421
         * Have we run out of space in the inode buffer?  If so, we
 
422
         * need to read in more blocks.
 
423
         */
 
424
        if (scan->bytes_left < scan->inode_size) {
 
425
                memcpy(scan->temp_buffer, scan->ptr, scan->bytes_left);
 
426
                extra_bytes = scan->bytes_left;
 
427
 
 
428
                retval = get_next_blocks(scan);
 
429
                if (retval)
 
430
                        return retval;
 
431
#if 0
 
432
                /*
 
433
                 * XXX test  Need check for used inode somehow.
 
434
                 * (Note: this is hard.)
 
435
                 */
 
436
                if (is_empty_scan(scan))
 
437
                        goto force_new_group;
 
438
#endif
 
439
        }
 
440
 
 
441
        retval = 0;
 
442
        if (extra_bytes) {
 
443
                memcpy(scan->temp_buffer+extra_bytes, scan->ptr,
 
444
                       scan->inode_size - extra_bytes);
 
445
                scan->ptr += scan->inode_size - extra_bytes;
 
446
                scan->bytes_left -= scan->inode_size - extra_bytes;
 
447
 
 
448
#ifdef EXT2FS_ENABLE_SWAPFS
 
449
                if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
 
450
                    (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
 
451
                        ext2fs_swap_inode(scan->fs, inode,
 
452
                                 (struct ext2_inode *) scan->temp_buffer, 0);
 
453
                else
 
454
#endif
 
455
                        *inode = *((struct ext2_inode *) scan->temp_buffer);
 
456
                if (scan->scan_flags & EXT2_SF_BAD_EXTRA_BYTES)
 
457
                        retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
 
458
                scan->scan_flags &= ~EXT2_SF_BAD_EXTRA_BYTES;
 
459
        } else {
 
460
#ifdef EXT2FS_ENABLE_SWAPFS
 
461
                if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
 
462
                    (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
 
463
                        ext2fs_swap_inode(scan->fs, inode,
 
464
                                 (struct ext2_inode *) scan->ptr, 0);
 
465
                else
 
466
#endif
 
467
                        *inode = *((struct ext2_inode *) scan->ptr);
 
468
                scan->ptr += scan->inode_size;
 
469
                scan->bytes_left -= scan->inode_size;
 
470
                if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK)
 
471
                        retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
 
472
        }
 
473
 
 
474
        scan->inodes_left--;
 
475
        scan->current_inode++;
 
476
        *ino = scan->current_inode;
 
477
        return retval;
 
478
}
 
479
 
 
480
/*
 
481
 * Functions to read and write a single inode.
 
482
 */
 
483
errcode_t ext2fs_read_inode (ext2_filsys fs, ext2_ino_t ino,
 
484
                             struct ext2_inode * inode)
 
485
{
 
486
        unsigned long   group, block, block_nr, offset;
 
487
        char            *ptr;
 
488
        errcode_t       retval;
 
489
        int             clen, length, i, inodes_per_block;
 
490
 
 
491
        EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
492
 
 
493
        /* Check to see if user has an override function */
 
494
        if (fs->read_inode) {
 
495
                retval = (fs->read_inode)(fs, ino, inode);
 
496
                if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
 
497
                        return retval;
 
498
        }
 
499
        /* Create inode cache if not present */
 
500
        if (!fs->icache) {
 
501
                retval = create_icache(fs);
 
502
                if (retval)
 
503
                        return retval;
 
504
        }
 
505
        /* Check to see if it's in the inode cache */
 
506
        for (i=0; i < fs->icache->cache_size; i++) {
 
507
                if (fs->icache->cache[i].ino == ino) {
 
508
                        *inode = fs->icache->cache[i].inode;
 
509
                        return 0;
 
510
                }
 
511
        }
 
512
        if ((ino == 0) || (ino > fs->super->s_inodes_count))
 
513
                return EXT2_ET_BAD_INODE_NUM;
 
514
        if (fs->flags & EXT2_FLAG_IMAGE_FILE) {
 
515
                inodes_per_block = fs->blocksize / EXT2_INODE_SIZE(fs->super);
 
516
                block_nr = fs->image_header->offset_inode / fs->blocksize;
 
517
                block_nr += (ino - 1) / inodes_per_block;
 
518
                offset = ((ino - 1) % inodes_per_block) *
 
519
                        EXT2_INODE_SIZE(fs->super);
 
520
        } else {
 
521
                group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
 
522
                offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
 
523
                        EXT2_INODE_SIZE(fs->super);
 
524
                block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super);
 
525
                if (!fs->group_desc[(unsigned)group].bg_inode_table)
 
526
                        return EXT2_ET_MISSING_INODE_TABLE;
 
527
                block_nr = fs->group_desc[(unsigned)group].bg_inode_table + 
 
528
                        block;
 
529
        }
 
530
        if (block_nr != fs->icache->buffer_blk) {
 
531
                retval = io_channel_read_blk(fs->io, block_nr, 1,
 
532
                                             fs->icache->buffer);
 
533
                if (retval)
 
534
                        return retval;
 
535
                fs->icache->buffer_blk = block_nr;
 
536
        }
 
537
        offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
 
538
        ptr = ((char *) fs->icache->buffer) + (unsigned) offset;
 
539
 
 
540
        memset(inode, 0, sizeof(struct ext2_inode));
 
541
        length = EXT2_INODE_SIZE(fs->super);
 
542
        if (length > sizeof(struct ext2_inode))
 
543
                length = sizeof(struct ext2_inode);
 
544
        
 
545
        if ((offset + length) > EXT2_BLOCK_SIZE(fs->super)) {
 
546
                clen = (int) (EXT2_BLOCK_SIZE(fs->super) - offset);
 
547
                memcpy((char *) inode, ptr, clen);
 
548
                length -= clen;
 
549
                
 
550
                retval = io_channel_read_blk(fs->io, block_nr+1, 1,
 
551
                                             fs->icache->buffer);
 
552
                if (retval) {
 
553
                        fs->icache->buffer_blk = 0;
 
554
                        return retval;
 
555
                }
 
556
                fs->icache->buffer_blk = block_nr+1;
 
557
                
 
558
                memcpy(((char *) inode) + clen,
 
559
                       fs->icache->buffer, length);
 
560
        } else
 
561
                memcpy((char *) inode, ptr, length);
 
562
        
 
563
#ifdef EXT2FS_ENABLE_SWAPFS
 
564
        if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
 
565
            (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
 
566
                ext2fs_swap_inode(fs, inode, inode, 0);
 
567
#endif
 
568
 
 
569
        /* Update the inode cache */
 
570
        fs->icache->cache_last = (fs->icache->cache_last + 1) %
 
571
                fs->icache->cache_size;
 
572
        fs->icache->cache[fs->icache->cache_last].ino = ino;
 
573
        fs->icache->cache[fs->icache->cache_last].inode = *inode;
 
574
        
 
575
        return 0;
 
576
}
 
577
 
 
578
errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino,
 
579
                             struct ext2_inode * inode)
 
580
{
 
581
        unsigned long group, block, block_nr, offset;
 
582
        errcode_t       retval;
 
583
        struct ext2_inode temp_inode;
 
584
        char *ptr;
 
585
        int clen, length, i;
 
586
 
 
587
        EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
588
 
 
589
        /* Check to see if user provided an override function */
 
590
        if (fs->write_inode) {
 
591
                retval = (fs->write_inode)(fs, ino, inode);
 
592
                if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
 
593
                        return retval;
 
594
        }
 
595
 
 
596
        /* Check to see if the inode cache needs to be updated */
 
597
        if (fs->icache) {
 
598
                for (i=0; i < fs->icache->cache_size; i++) {
 
599
                        if (fs->icache->cache[i].ino == ino) {
 
600
                                fs->icache->cache[i].inode = *inode;
 
601
                                break;
 
602
                        }
 
603
                }
 
604
        } else {
 
605
                retval = create_icache(fs);
 
606
                if (retval)
 
607
                        return retval;
 
608
        }
 
609
                
 
610
        if (!(fs->flags & EXT2_FLAG_RW))
 
611
                return EXT2_ET_RO_FILSYS;
 
612
 
 
613
        if ((ino == 0) || (ino > fs->super->s_inodes_count))
 
614
                return EXT2_ET_BAD_INODE_NUM;
 
615
 
 
616
#ifdef EXT2FS_ENABLE_SWAPFS
 
617
        if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
 
618
            (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
 
619
                ext2fs_swap_inode(fs, &temp_inode, inode, 1);
 
620
        else
 
621
#endif
 
622
                memcpy(&temp_inode, inode, sizeof(struct ext2_inode));
 
623
        
 
624
        group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
 
625
        offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
 
626
                EXT2_INODE_SIZE(fs->super);
 
627
        block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super);
 
628
        if (!fs->group_desc[(unsigned) group].bg_inode_table)
 
629
                return EXT2_ET_MISSING_INODE_TABLE;
 
630
        block_nr = fs->group_desc[(unsigned) group].bg_inode_table + block;
 
631
        offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
 
632
        ptr = (char *) fs->icache->buffer + (unsigned) offset;
 
633
 
 
634
        length = EXT2_INODE_SIZE(fs->super);
 
635
        clen = length;
 
636
        if (length > sizeof(struct ext2_inode))
 
637
                length = sizeof(struct ext2_inode);
 
638
        
 
639
        if (fs->icache->buffer_blk != block_nr) {
 
640
                retval = io_channel_read_blk(fs->io, block_nr, 1,
 
641
                                             fs->icache->buffer);
 
642
                if (retval)
 
643
                        return retval;
 
644
                fs->icache->buffer_blk = block_nr;
 
645
        }
 
646
        
 
647
        if ((offset + length) > EXT2_BLOCK_SIZE(fs->super)) {
 
648
                clen = (int) (EXT2_BLOCK_SIZE(fs->super) - offset);
 
649
                length -= clen;
 
650
        } else {
 
651
                length = 0;
 
652
        }
 
653
        memcpy(ptr, &temp_inode, clen);
 
654
        retval = io_channel_write_blk(fs->io, block_nr, 1, fs->icache->buffer);
 
655
        if (retval)
 
656
                return retval;
 
657
 
 
658
        if (length) {
 
659
                retval = io_channel_read_blk(fs->io, ++block_nr, 1,
 
660
                                             fs->icache->buffer);
 
661
                if (retval) {
 
662
                        fs->icache->buffer_blk = 0;
 
663
                        return retval;
 
664
                }
 
665
                fs->icache->buffer_blk = block_nr;
 
666
                memcpy(fs->icache->buffer, ((char *) &temp_inode) + clen,
 
667
                       length);
 
668
 
 
669
                retval = io_channel_write_blk(fs->io, block_nr, 1,
 
670
                                              fs->icache->buffer);
 
671
                if (retval)
 
672
                        return retval;
 
673
        }
 
674
        
 
675
        fs->flags |= EXT2_FLAG_CHANGED;
 
676
        return 0;
 
677
}
 
678
 
 
679
errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks)
 
680
{
 
681
        struct ext2_inode       inode;
 
682
        int                     i;
 
683
        errcode_t               retval;
 
684
        
 
685
        EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
686
 
 
687
        if (ino > fs->super->s_inodes_count)
 
688
                return EXT2_ET_BAD_INODE_NUM;
 
689
 
 
690
        if (fs->get_blocks) {
 
691
                if (!(*fs->get_blocks)(fs, ino, blocks))
 
692
                        return 0;
 
693
        }
 
694
        retval = ext2fs_read_inode(fs, ino, &inode);
 
695
        if (retval)
 
696
                return retval;
 
697
        for (i=0; i < EXT2_N_BLOCKS; i++)
 
698
                blocks[i] = inode.i_block[i];
 
699
        return 0;
 
700
}
 
701
 
 
702
errcode_t ext2fs_check_directory(ext2_filsys fs, ext2_ino_t ino)
 
703
{
 
704
        struct  ext2_inode      inode;
 
705
        errcode_t               retval;
 
706
        
 
707
        EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
708
 
 
709
        if (ino > fs->super->s_inodes_count)
 
710
                return EXT2_ET_BAD_INODE_NUM;
 
711
 
 
712
        if (fs->check_directory) {
 
713
                retval = (fs->check_directory)(fs, ino);
 
714
                if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
 
715
                        return retval;
 
716
        }
 
717
        retval = ext2fs_read_inode(fs, ino, &inode);
 
718
        if (retval)
 
719
                return retval;
 
720
        if (!LINUX_S_ISDIR(inode.i_mode))
 
721
                return EXT2_ET_NO_DIRECTORY;
 
722
        return 0;
 
723
}
 
724