Coverage Report

Created: 2022-11-24 06:30

/src/e2fsprogs/lib/ext2fs/inode.c
Line
Count
Source (jump to first uncovered line)
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 Library
8
 * General Public License, version 2.
9
 * %End-Header%
10
 */
11
12
#include "config.h"
13
#include <stdio.h>
14
#include <string.h>
15
#if HAVE_UNISTD_H
16
#include <unistd.h>
17
#endif
18
#if HAVE_ERRNO_H
19
#include <errno.h>
20
#endif
21
#include <time.h>
22
#if HAVE_SYS_STAT_H
23
#include <sys/stat.h>
24
#endif
25
#if HAVE_SYS_TYPES_H
26
#include <sys/types.h>
27
#endif
28
29
#include "ext2_fs.h"
30
#include "ext2fsP.h"
31
#include "e2image.h"
32
33
0
#define IBLOCK_STATUS_CSUMS_OK  1
34
0
#define IBLOCK_STATUS_INSANE  2
35
0
#define SCAN_BLOCK_STATUS(scan) ((scan)->temp_buffer + (scan)->inode_size)
36
37
struct ext2_struct_inode_scan {
38
  errcode_t   magic;
39
  ext2_filsys   fs;
40
  ext2_ino_t    current_inode;
41
  blk64_t     current_block;
42
  dgrp_t      current_group;
43
  ext2_ino_t    inodes_left;
44
  blk_t     blocks_left;
45
  dgrp_t      groups_left;
46
  blk_t     inode_buffer_blocks;
47
  char *      inode_buffer;
48
  int     inode_size;
49
  char *      ptr;
50
  int     bytes_left;
51
  char      *temp_buffer;
52
  errcode_t   (*done_group)(ext2_filsys fs,
53
                ext2_inode_scan scan,
54
                dgrp_t group,
55
                void * priv_data);
56
  void *      done_group_data;
57
  int     bad_block_ptr;
58
  int     scan_flags;
59
  int     reserved[6];
60
};
61
62
/*
63
 * This routine flushes the icache, if it exists.
64
 */
65
errcode_t ext2fs_flush_icache(ext2_filsys fs)
66
0
{
67
0
  unsigned  i;
68
69
0
  if (!fs->icache)
70
0
    return 0;
71
72
0
  for (i=0; i < fs->icache->cache_size; i++)
73
0
    fs->icache->cache[i].ino = 0;
74
75
0
  fs->icache->buffer_blk = 0;
76
0
  return 0;
77
0
}
78
79
/*
80
 * Free the inode cache structure
81
 */
82
void ext2fs_free_inode_cache(struct ext2_inode_cache *icache)
83
0
{
84
0
  unsigned i;
85
86
0
  if (--icache->refcount)
87
0
    return;
88
0
  if (icache->buffer)
89
0
    ext2fs_free_mem(&icache->buffer);
90
0
  for (i = 0; i < icache->cache_size; i++)
91
0
    ext2fs_free_mem(&icache->cache[i].inode);
92
0
  if (icache->cache)
93
0
    ext2fs_free_mem(&icache->cache);
94
0
  icache->buffer_blk = 0;
95
0
  ext2fs_free_mem(&icache);
96
0
}
97
98
errcode_t ext2fs_create_inode_cache(ext2_filsys fs, unsigned int cache_size)
99
0
{
100
0
  unsigned  i;
101
0
  errcode_t retval;
102
103
0
  if (fs->icache)
104
0
    return 0;
105
0
  retval = ext2fs_get_mem(sizeof(struct ext2_inode_cache), &fs->icache);
106
0
  if (retval)
107
0
    return retval;
108
109
0
  memset(fs->icache, 0, sizeof(struct ext2_inode_cache));
110
0
  retval = ext2fs_get_mem(fs->blocksize, &fs->icache->buffer);
111
0
  if (retval)
112
0
    goto errout;
113
114
0
  fs->icache->buffer_blk = 0;
115
0
  fs->icache->cache_last = -1;
116
0
  fs->icache->cache_size = cache_size;
117
0
  fs->icache->refcount = 1;
118
0
  retval = ext2fs_get_array(fs->icache->cache_size,
119
0
          sizeof(struct ext2_inode_cache_ent),
120
0
          &fs->icache->cache);
121
0
  if (retval)
122
0
    goto errout;
123
124
0
  for (i = 0; i < fs->icache->cache_size; i++) {
125
0
    retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super),
126
0
          &fs->icache->cache[i].inode);
127
0
    if (retval)
128
0
      goto errout;
129
0
  }
130
131
0
  ext2fs_flush_icache(fs);
132
0
  return 0;
133
0
errout:
134
0
  ext2fs_free_inode_cache(fs->icache);
135
0
  fs->icache = 0;
136
0
  return retval;
137
0
}
138
139
errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
140
         ext2_inode_scan *ret_scan)
141
0
{
142
0
  ext2_inode_scan scan;
143
0
  errcode_t retval;
144
0
  errcode_t (*save_get_blocks)(ext2_filsys f, ext2_ino_t ino, blk_t *blocks);
145
146
0
  EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
147
148
0
  if (ext2fs_has_feature_journal_dev(fs->super))
149
0
    return EXT2_ET_EXTERNAL_JOURNAL_NOSUPP;
150
151
0
  if (fs->blocksize < 1024)
152
0
    return EXT2_FILSYS_CORRUPTED; /* Should never happen */
153
154
  /*
155
   * If fs->badblocks isn't set, then set it --- since the inode
156
   * scanning functions require it.
157
   */
158
0
  if (fs->badblocks == 0) {
159
    /*
160
     * Temporarily save fs->get_blocks and set it to zero,
161
     * for compatibility with old e2fsck's.
162
     */
163
0
    save_get_blocks = fs->get_blocks;
164
0
    fs->get_blocks = 0;
165
0
    retval = ext2fs_read_bb_inode(fs, &fs->badblocks);
166
0
    if (retval && fs->badblocks) {
167
0
      ext2fs_badblocks_list_free(fs->badblocks);
168
0
      fs->badblocks = 0;
169
0
    }
170
0
    fs->get_blocks = save_get_blocks;
171
0
  }
172
173
0
  retval = ext2fs_get_mem(sizeof(struct ext2_struct_inode_scan), &scan);
174
0
  if (retval)
175
0
    return retval;
176
0
  memset(scan, 0, sizeof(struct ext2_struct_inode_scan));
177
178
0
  scan->magic = EXT2_ET_MAGIC_INODE_SCAN;
179
0
  scan->fs = fs;
180
0
  scan->inode_size = EXT2_INODE_SIZE(fs->super);
181
0
  scan->bytes_left = 0;
182
0
  scan->current_group = 0;
183
0
  scan->groups_left = fs->group_desc_count - 1;
184
0
  scan->inode_buffer_blocks = buffer_blocks ? buffer_blocks :
185
0
            EXT2_INODE_SCAN_DEFAULT_BUFFER_BLOCKS;
186
0
  scan->current_block = ext2fs_inode_table_loc(scan->fs,
187
0
                 scan->current_group);
188
0
  if (scan->current_block &&
189
0
      ((scan->current_block < fs->super->s_first_data_block) ||
190
0
       (scan->current_block + fs->inode_blocks_per_group - 1 >=
191
0
        ext2fs_blocks_count(fs->super)))) {
192
0
    ext2fs_free_mem(&scan);
193
0
    return EXT2_ET_GDESC_BAD_INODE_TABLE;
194
0
  }
195
196
0
  scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super);
197
0
  scan->blocks_left = scan->fs->inode_blocks_per_group;
198
0
  if (ext2fs_has_group_desc_csum(fs)) {
199
0
    __u32 unused = ext2fs_bg_itable_unused(fs, scan->current_group);
200
0
    if (scan->inodes_left > unused)
201
0
      scan->inodes_left -= unused;
202
0
    else
203
0
      scan->inodes_left = 0;
204
0
    scan->blocks_left =
205
0
      (scan->inodes_left +
206
0
       (fs->blocksize / scan->inode_size - 1)) *
207
0
      scan->inode_size / fs->blocksize;
208
0
  }
209
0
  retval = io_channel_alloc_buf(fs->io, scan->inode_buffer_blocks,
210
0
              &scan->inode_buffer);
211
0
  scan->done_group = 0;
212
0
  scan->done_group_data = 0;
213
0
  scan->bad_block_ptr = 0;
214
0
  if (retval) {
215
0
    ext2fs_free_mem(&scan);
216
0
    return retval;
217
0
  }
218
0
  retval = ext2fs_get_mem(scan->inode_size + scan->inode_buffer_blocks,
219
0
        &scan->temp_buffer);
220
0
  if (retval) {
221
0
    ext2fs_free_mem(&scan->inode_buffer);
222
0
    ext2fs_free_mem(&scan);
223
0
    return retval;
224
0
  }
225
0
  memset(SCAN_BLOCK_STATUS(scan), 0, scan->inode_buffer_blocks);
226
0
  if (scan->fs->badblocks && scan->fs->badblocks->num)
227
0
    scan->scan_flags |= EXT2_SF_CHK_BADBLOCKS;
228
0
  if (ext2fs_has_group_desc_csum(fs))
229
0
    scan->scan_flags |= EXT2_SF_DO_LAZY;
230
0
  *ret_scan = scan;
231
0
  return 0;
232
0
}
233
234
void ext2fs_close_inode_scan(ext2_inode_scan scan)
235
0
{
236
0
  if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
237
0
    return;
238
239
0
  ext2fs_free_mem(&scan->inode_buffer);
240
0
  scan->inode_buffer = NULL;
241
0
  ext2fs_free_mem(&scan->temp_buffer);
242
0
  scan->temp_buffer = NULL;
243
0
  ext2fs_free_mem(&scan);
244
0
  return;
245
0
}
246
247
void ext2fs_set_inode_callback(ext2_inode_scan scan,
248
             errcode_t (*done_group)(ext2_filsys fs,
249
                   ext2_inode_scan scan,
250
                   dgrp_t group,
251
                   void * priv_data),
252
             void *done_group_data)
253
0
{
254
0
  if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
255
0
    return;
256
257
0
  scan->done_group = done_group;
258
0
  scan->done_group_data = done_group_data;
259
0
}
260
261
int ext2fs_inode_scan_flags(ext2_inode_scan scan, int set_flags,
262
          int clear_flags)
263
0
{
264
0
  int old_flags;
265
266
0
  if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
267
0
    return 0;
268
269
0
  old_flags = scan->scan_flags;
270
0
  scan->scan_flags &= ~clear_flags;
271
0
  scan->scan_flags |= set_flags;
272
0
  return old_flags;
273
0
}
274
275
/*
276
 * This function is called by ext2fs_get_next_inode when it needs to
277
 * get ready to read in a new blockgroup.
278
 */
279
static errcode_t get_next_blockgroup(ext2_inode_scan scan)
280
0
{
281
0
  ext2_filsys fs = scan->fs;
282
283
0
  scan->current_group++;
284
0
  scan->groups_left--;
285
286
0
  scan->current_block = ext2fs_inode_table_loc(scan->fs,
287
0
                 scan->current_group);
288
0
  scan->current_inode = scan->current_group *
289
0
    EXT2_INODES_PER_GROUP(fs->super);
290
291
0
  scan->bytes_left = 0;
292
0
  scan->inodes_left = EXT2_INODES_PER_GROUP(fs->super);
293
0
  scan->blocks_left = fs->inode_blocks_per_group;
294
0
  if (ext2fs_has_group_desc_csum(fs)) {
295
0
    __u32 unused = ext2fs_bg_itable_unused(fs, scan->current_group);
296
0
    if (scan->inodes_left > unused)
297
0
      scan->inodes_left -= unused;
298
0
    else
299
0
      scan->inodes_left = 0;
300
0
    scan->blocks_left =
301
0
      (scan->inodes_left +
302
0
       (fs->blocksize / scan->inode_size - 1)) *
303
0
      scan->inode_size / fs->blocksize;
304
0
  }
305
0
  if (scan->current_block &&
306
0
      ((scan->current_block < fs->super->s_first_data_block) ||
307
0
       (scan->current_block + fs->inode_blocks_per_group - 1 >=
308
0
        ext2fs_blocks_count(fs->super))))
309
0
    return EXT2_ET_GDESC_BAD_INODE_TABLE;
310
0
  return 0;
311
0
}
312
313
errcode_t ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan,
314
              int group)
315
0
{
316
0
  scan->current_group = group - 1;
317
0
  scan->groups_left = scan->fs->group_desc_count - group;
318
0
  scan->bad_block_ptr = 0;
319
0
  return get_next_blockgroup(scan);
320
0
}
321
322
/*
323
 * This function is called by get_next_blocks() to check for bad
324
 * blocks in the inode table.
325
 *
326
 * This function assumes that badblocks_list->list is sorted in
327
 * increasing order.
328
 */
329
static errcode_t check_for_inode_bad_blocks(ext2_inode_scan scan,
330
              blk64_t *num_blocks)
331
0
{
332
0
  blk64_t blk = scan->current_block;
333
0
  badblocks_list  bb = scan->fs->badblocks;
334
335
  /*
336
   * If the inode table is missing, then obviously there are no
337
   * bad blocks.  :-)
338
   */
339
0
  if (blk == 0)
340
0
    return 0;
341
342
  /* Make sure bad_block_ptr is still valid */
343
0
  if (scan->bad_block_ptr >= bb->num) {
344
0
    scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS;
345
0
    return 0;
346
0
  }
347
348
  /*
349
   * If the current block is greater than the bad block listed
350
   * in the bad block list, then advance the pointer until this
351
   * is no longer the case.  If we run out of bad blocks, then
352
   * we don't need to do any more checking!
353
   */
354
0
  while (blk > bb->list[scan->bad_block_ptr]) {
355
0
    if (++scan->bad_block_ptr >= bb->num) {
356
0
      scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS;
357
0
      return 0;
358
0
    }
359
0
  }
360
361
  /*
362
   * If the current block is equal to the bad block listed in
363
   * the bad block list, then handle that one block specially.
364
   * (We could try to handle runs of bad blocks, but that
365
   * only increases CPU efficiency by a small amount, at the
366
   * expense of a huge expense of code complexity, and for an
367
   * uncommon case at that.)
368
   */
369
0
  if (blk == bb->list[scan->bad_block_ptr]) {
370
0
    scan->scan_flags |= EXT2_SF_BAD_INODE_BLK;
371
0
    *num_blocks = 1;
372
0
    if (++scan->bad_block_ptr >= bb->num)
373
0
      scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS;
374
0
    return 0;
375
0
  }
376
377
  /*
378
   * If there is a bad block in the range that we're about to
379
   * read in, adjust the number of blocks to read so that we we
380
   * don't read in the bad block.  (Then the next block to read
381
   * will be the bad block, which is handled in the above case.)
382
   */
383
0
  if ((blk + *num_blocks) > bb->list[scan->bad_block_ptr])
384
0
    *num_blocks = (int) (bb->list[scan->bad_block_ptr] - blk);
385
386
0
  return 0;
387
0
}
388
389
static int block_map_looks_insane(ext2_filsys fs,
390
          struct ext2_inode_large *inode)
391
0
{
392
0
  unsigned int i, bad;
393
394
  /* We're only interested in block mapped files, dirs, and symlinks */
395
0
  if ((inode->i_flags & EXT4_INLINE_DATA_FL) ||
396
0
      (inode->i_flags & EXT4_EXTENTS_FL))
397
0
    return 0;
398
0
  if (!LINUX_S_ISREG(inode->i_mode) &&
399
0
      !LINUX_S_ISLNK(inode->i_mode) &&
400
0
      !LINUX_S_ISDIR(inode->i_mode))
401
0
    return 0;
402
0
  if (LINUX_S_ISLNK(inode->i_mode) &&
403
0
      EXT2_I_SIZE(inode) <= sizeof(inode->i_block))
404
0
    return 0;
405
406
  /* Unused inodes probably aren't insane */
407
0
  if (inode->i_links_count == 0)
408
0
    return 0;
409
410
  /* See if more than half the block maps are insane */
411
0
  for (i = 0, bad = 0; i < EXT2_N_BLOCKS; i++)
412
0
    if (inode->i_block[i] != 0 &&
413
0
        (inode->i_block[i] < fs->super->s_first_data_block ||
414
0
         inode->i_block[i] >= ext2fs_blocks_count(fs->super)))
415
0
      bad++;
416
0
  return bad > EXT2_N_BLOCKS / 2;
417
0
}
418
419
static int extent_head_looks_insane(struct ext2_inode_large *inode)
420
0
{
421
0
  if (!(inode->i_flags & EXT4_EXTENTS_FL) ||
422
0
      ext2fs_extent_header_verify(inode->i_block,
423
0
          sizeof(inode->i_block)) == 0)
424
0
    return 0;
425
0
  return 1;
426
0
}
427
428
/*
429
 * Check all the inodes that we just read into the buffer.  Record what we
430
 * find here -- currently, we can observe that all checksums are ok; more
431
 * than half the inodes are insane; or no conclusions at all.
432
 */
433
static void check_inode_block_sanity(ext2_inode_scan scan, blk64_t num_blocks)
434
0
{
435
0
  ext2_ino_t  ino, inodes_to_scan;
436
0
  unsigned int  badness, checksum_failures;
437
0
  unsigned int  inodes_in_buf, inodes_per_block;
438
0
  char    *p;
439
0
  struct ext2_inode_large *inode;
440
0
  char    *block_status;
441
0
  unsigned int  blk, bad_csum;
442
443
0
  if (!(scan->scan_flags & EXT2_SF_WARN_GARBAGE_INODES))
444
0
    return;
445
446
0
  inodes_to_scan = scan->inodes_left;
447
0
  inodes_in_buf = num_blocks * scan->fs->blocksize / scan->inode_size;
448
0
  if (inodes_to_scan > inodes_in_buf)
449
0
    inodes_to_scan = inodes_in_buf;
450
451
0
  p = (char *) scan->inode_buffer;
452
0
  ino = scan->current_inode + 1;
453
0
  checksum_failures = badness = 0;
454
0
  block_status = SCAN_BLOCK_STATUS(scan);
455
0
  memset(block_status, 0, scan->inode_buffer_blocks);
456
0
  inodes_per_block = EXT2_INODES_PER_BLOCK(scan->fs->super);
457
458
0
  if (inodes_per_block < 2)
459
0
    return;
460
461
#ifdef WORDS_BIGENDIAN
462
  if (ext2fs_get_mem(EXT2_INODE_SIZE(scan->fs->super), &inode))
463
    return;
464
#endif
465
466
0
  while (inodes_to_scan > 0) {
467
0
    blk = (p - (char *)scan->inode_buffer) / scan->fs->blocksize;
468
0
    bad_csum = ext2fs_inode_csum_verify(scan->fs, ino,
469
0
        (struct ext2_inode_large *) p) == 0;
470
471
#ifdef WORDS_BIGENDIAN
472
    ext2fs_swap_inode_full(scan->fs,
473
             (struct ext2_inode_large *) inode,
474
             (struct ext2_inode_large *) p,
475
             0, EXT2_INODE_SIZE(scan->fs->super));
476
#else
477
0
    inode = (struct ext2_inode_large *) p;
478
0
#endif
479
480
    /* Is this inode insane? */
481
0
    if (bad_csum) {
482
0
      checksum_failures++;
483
0
      badness++;
484
0
    } else if (extent_head_looks_insane(inode) ||
485
0
         block_map_looks_insane(scan->fs, inode))
486
0
      badness++;
487
488
    /* If more than half are insane, declare the whole block bad */
489
0
    if (badness > inodes_per_block / 2) {
490
0
      unsigned int ino_adj;
491
492
0
      block_status[blk] |= IBLOCK_STATUS_INSANE;
493
0
      ino_adj = inodes_per_block -
494
0
            ((ino - 1) % inodes_per_block);
495
0
      if (ino_adj > inodes_to_scan)
496
0
        ino_adj = inodes_to_scan;
497
0
      inodes_to_scan -= ino_adj;
498
0
      p += scan->inode_size * ino_adj;
499
0
      ino += ino_adj;
500
0
      checksum_failures = badness = 0;
501
0
      continue;
502
0
    }
503
504
0
    if ((ino % inodes_per_block) == 0) {
505
0
      if (checksum_failures == 0)
506
0
        block_status[blk] |= IBLOCK_STATUS_CSUMS_OK;
507
0
      checksum_failures = badness = 0;
508
0
    }
509
0
    inodes_to_scan--;
510
0
    p += scan->inode_size;
511
0
    ino++;
512
0
  };
513
514
#ifdef WORDS_BIGENDIAN
515
  ext2fs_free_mem(&inode);
516
#endif
517
0
}
518
519
/*
520
 * This function is called by ext2fs_get_next_inode when it needs to
521
 * read in more blocks from the current blockgroup's inode table.
522
 */
523
static errcode_t get_next_blocks(ext2_inode_scan scan)
524
0
{
525
0
  blk64_t   num_blocks;
526
0
  errcode_t retval;
527
528
  /*
529
   * Figure out how many blocks to read; we read at most
530
   * inode_buffer_blocks, and perhaps less if there aren't that
531
   * many blocks left to read.
532
   */
533
0
  num_blocks = scan->inode_buffer_blocks;
534
0
  if (num_blocks > scan->blocks_left)
535
0
    num_blocks = scan->blocks_left;
536
537
  /*
538
   * If the past block "read" was a bad block, then mark the
539
   * left-over extra bytes as also being bad.
540
   */
541
0
  if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK) {
542
0
    if (scan->bytes_left)
543
0
      scan->scan_flags |= EXT2_SF_BAD_EXTRA_BYTES;
544
0
    scan->scan_flags &= ~EXT2_SF_BAD_INODE_BLK;
545
0
  }
546
547
  /*
548
   * Do inode bad block processing, if necessary.
549
   */
550
0
  if (scan->scan_flags & EXT2_SF_CHK_BADBLOCKS) {
551
0
    retval = check_for_inode_bad_blocks(scan, &num_blocks);
552
0
    if (retval)
553
0
      return retval;
554
0
  }
555
556
0
  if ((scan->scan_flags & EXT2_SF_BAD_INODE_BLK) ||
557
0
      (scan->current_block == 0)) {
558
0
    memset(scan->inode_buffer, 0,
559
0
           (size_t) num_blocks * scan->fs->blocksize);
560
0
  } else {
561
0
    retval = io_channel_read_blk64(scan->fs->io,
562
0
               scan->current_block,
563
0
               (int) num_blocks,
564
0
               scan->inode_buffer);
565
0
    if (retval)
566
0
      return EXT2_ET_NEXT_INODE_READ;
567
0
  }
568
0
  check_inode_block_sanity(scan, num_blocks);
569
570
0
  scan->ptr = scan->inode_buffer;
571
0
  scan->bytes_left = num_blocks * scan->fs->blocksize;
572
573
0
  scan->blocks_left -= num_blocks;
574
0
  if (scan->current_block)
575
0
    scan->current_block += num_blocks;
576
577
0
  return 0;
578
0
}
579
580
#if 0
581
/*
582
 * Returns 1 if the entire inode_buffer has a non-zero size and
583
 * contains all zeros.  (Not just deleted inodes, since that means
584
 * that part of the inode table was used at one point; we want all
585
 * zeros, which means that the inode table is pristine.)
586
 */
587
static inline int is_empty_scan(ext2_inode_scan scan)
588
{
589
  int i;
590
591
  if (scan->bytes_left == 0)
592
    return 0;
593
594
  for (i=0; i < scan->bytes_left; i++)
595
    if (scan->ptr[i])
596
      return 0;
597
  return 1;
598
}
599
#endif
600
601
errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino,
602
             struct ext2_inode *inode, int bufsize)
603
0
{
604
0
  errcode_t retval;
605
0
  int   extra_bytes = 0;
606
0
  int   length;
607
0
  struct ext2_inode_large *iptr = (struct ext2_inode_large *)inode;
608
0
  char    *iblock_status;
609
0
  unsigned int  iblk;
610
611
0
  EXT2_CHECK_MAGIC(scan, EXT2_ET_MAGIC_INODE_SCAN);
612
0
  length = EXT2_INODE_SIZE(scan->fs->super);
613
0
  iblock_status = SCAN_BLOCK_STATUS(scan);
614
615
  /*
616
   * Do we need to start reading a new block group?
617
   */
618
0
  if (scan->inodes_left <= 0) {
619
0
  force_new_group:
620
0
    if (scan->done_group) {
621
0
      retval = (scan->done_group)
622
0
        (scan->fs, scan, scan->current_group,
623
0
         scan->done_group_data);
624
0
      if (retval)
625
0
        return retval;
626
0
    }
627
0
    if (scan->groups_left <= 0) {
628
0
      *ino = 0;
629
0
      return 0;
630
0
    }
631
0
    retval = get_next_blockgroup(scan);
632
0
    if (retval)
633
0
      return retval;
634
0
  }
635
  /*
636
   * These checks are done outside the above if statement so
637
   * they can be done for block group #0.
638
   */
639
0
  if ((scan->scan_flags & EXT2_SF_DO_LAZY) &&
640
0
      (ext2fs_bg_flags_test(scan->fs, scan->current_group, EXT2_BG_INODE_UNINIT)
641
0
       ))
642
0
    goto force_new_group;
643
0
  if (scan->inodes_left == 0)
644
0
    goto force_new_group;
645
0
  if (scan->current_block == 0) {
646
0
    if (scan->scan_flags & EXT2_SF_SKIP_MISSING_ITABLE) {
647
0
      goto force_new_group;
648
0
    } else
649
0
      return EXT2_ET_MISSING_INODE_TABLE;
650
0
  }
651
652
653
  /*
654
   * Have we run out of space in the inode buffer?  If so, we
655
   * need to read in more blocks.
656
   */
657
0
  if (scan->bytes_left < scan->inode_size) {
658
0
    if (scan->bytes_left)
659
0
      memcpy(scan->temp_buffer, scan->ptr, scan->bytes_left);
660
0
    extra_bytes = scan->bytes_left;
661
662
0
    retval = get_next_blocks(scan);
663
0
    if (retval)
664
0
      return retval;
665
#if 0
666
    /*
667
     * XXX test  Need check for used inode somehow.
668
     * (Note: this is hard.)
669
     */
670
    if (is_empty_scan(scan))
671
      goto force_new_group;
672
#endif
673
0
  }
674
675
0
  if (bufsize < length) {
676
0
    retval = ext2fs_get_mem(length, &iptr);
677
0
    if (retval)
678
0
      return retval;
679
0
  }
680
681
0
  retval = 0;
682
0
  iblk = scan->current_inode % EXT2_INODES_PER_GROUP(scan->fs->super) /
683
0
        EXT2_INODES_PER_BLOCK(scan->fs->super) %
684
0
        scan->inode_buffer_blocks;
685
0
  if (extra_bytes) {
686
0
    memcpy(scan->temp_buffer+extra_bytes, scan->ptr,
687
0
           scan->inode_size - extra_bytes);
688
0
    scan->ptr += scan->inode_size - extra_bytes;
689
0
    scan->bytes_left -= scan->inode_size - extra_bytes;
690
691
    /* Verify the inode checksum. */
692
0
    if (!(iblock_status[iblk] & IBLOCK_STATUS_CSUMS_OK) &&
693
0
        !(scan->fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
694
0
        !ext2fs_inode_csum_verify(scan->fs, scan->current_inode + 1,
695
0
        (struct ext2_inode_large *)scan->temp_buffer))
696
0
      retval = EXT2_ET_INODE_CSUM_INVALID;
697
698
#ifdef WORDS_BIGENDIAN
699
    memset(iptr, 0, length);
700
    ext2fs_swap_inode_full(scan->fs,
701
             (struct ext2_inode_large *) iptr,
702
             (struct ext2_inode_large *) scan->temp_buffer,
703
             0, length);
704
#else
705
0
    memcpy(iptr, scan->temp_buffer, length);
706
0
#endif
707
0
    if (scan->scan_flags & EXT2_SF_BAD_EXTRA_BYTES)
708
0
      retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
709
0
    scan->scan_flags &= ~EXT2_SF_BAD_EXTRA_BYTES;
710
0
  } else {
711
    /* Verify the inode checksum. */
712
0
    if (!(iblock_status[iblk] & IBLOCK_STATUS_CSUMS_OK) &&
713
0
        !(scan->fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
714
0
        !ext2fs_inode_csum_verify(scan->fs, scan->current_inode + 1,
715
0
        (struct ext2_inode_large *)scan->ptr))
716
0
      retval = EXT2_ET_INODE_CSUM_INVALID;
717
718
#ifdef WORDS_BIGENDIAN
719
    memset(iptr, 0, length);
720
    ext2fs_swap_inode_full(scan->fs,
721
        (struct ext2_inode_large *) iptr,
722
        (struct ext2_inode_large *) scan->ptr,
723
        0, length);
724
#else
725
0
    memcpy(iptr, scan->ptr, length);
726
0
#endif
727
0
    scan->ptr += scan->inode_size;
728
0
    scan->bytes_left -= scan->inode_size;
729
0
    if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK)
730
0
      retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
731
0
  }
732
0
  if ((iblock_status[iblk] & IBLOCK_STATUS_INSANE) &&
733
0
      (retval == 0 || retval == EXT2_ET_INODE_CSUM_INVALID))
734
0
    retval = EXT2_ET_INODE_IS_GARBAGE;
735
736
0
  scan->inodes_left--;
737
0
  scan->current_inode++;
738
0
  *ino = scan->current_inode;
739
0
  if (iptr != (struct ext2_inode_large *)inode) {
740
0
    memcpy(inode, iptr, bufsize);
741
0
    ext2fs_free_mem(&iptr);
742
0
  }
743
0
  return retval;
744
0
}
745
746
errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino,
747
        struct ext2_inode *inode)
748
0
{
749
0
  return ext2fs_get_next_inode_full(scan, ino, inode,
750
0
            sizeof(struct ext2_inode));
751
0
}
752
753
/*
754
 * Functions to read and write a single inode.
755
 */
756
errcode_t ext2fs_read_inode2(ext2_filsys fs, ext2_ino_t ino,
757
           struct ext2_inode * inode, int bufsize,
758
           int flags)
759
0
{
760
0
  blk64_t   block_nr;
761
0
  dgrp_t    group;
762
0
  unsigned long   block, offset;
763
0
  char    *ptr;
764
0
  errcode_t retval;
765
0
  unsigned  i;
766
0
  int   clen, inodes_per_block;
767
0
  io_channel  io;
768
0
  int   length = EXT2_INODE_SIZE(fs->super);
769
0
  struct ext2_inode_large *iptr;
770
0
  int   cache_slot, fail_csum;
771
772
0
  EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
773
774
0
  if (ext2fs_has_feature_journal_dev(fs->super))
775
0
    return EXT2_ET_EXTERNAL_JOURNAL_NOSUPP;
776
777
0
  if (fs->blocksize < 1024)
778
0
    return EXT2_FILSYS_CORRUPTED; /* Should never happen */
779
780
  /* Check to see if user has an override function */
781
0
  if (fs->read_inode &&
782
0
      ((bufsize == sizeof(struct ext2_inode)) ||
783
0
       (EXT2_INODE_SIZE(fs->super) == sizeof(struct ext2_inode)))) {
784
0
    retval = (fs->read_inode)(fs, ino, inode);
785
0
    if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
786
0
      return retval;
787
0
  }
788
0
  if ((ino == 0) || (ino > fs->super->s_inodes_count))
789
0
    return EXT2_ET_BAD_INODE_NUM;
790
  /* Create inode cache if not present */
791
0
  if (!fs->icache) {
792
0
    retval = ext2fs_create_inode_cache(fs, 4);
793
0
    if (retval)
794
0
      return retval;
795
0
  }
796
  /* Check to see if it's in the inode cache */
797
0
  for (i = 0; i < fs->icache->cache_size; i++) {
798
0
    if (fs->icache->cache[i].ino == ino) {
799
0
      memcpy(inode, fs->icache->cache[i].inode,
800
0
             (bufsize > length) ? length : bufsize);
801
0
      return 0;
802
0
    }
803
0
  }
804
0
  if (fs->flags & EXT2_FLAG_IMAGE_FILE) {
805
0
    inodes_per_block = fs->blocksize / EXT2_INODE_SIZE(fs->super);
806
0
    block_nr = ext2fs_le32_to_cpu(fs->image_header->offset_inode) / fs->blocksize;
807
0
    block_nr += (ino - 1) / inodes_per_block;
808
0
    offset = ((ino - 1) % inodes_per_block) *
809
0
      EXT2_INODE_SIZE(fs->super);
810
0
    io = fs->image_io;
811
0
  } else {
812
0
    group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
813
0
    if (group > fs->group_desc_count)
814
0
      return EXT2_ET_BAD_INODE_NUM;
815
0
    offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
816
0
      EXT2_INODE_SIZE(fs->super);
817
0
    block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super);
818
0
    block_nr = ext2fs_inode_table_loc(fs, group);
819
0
    if (!block_nr)
820
0
      return EXT2_ET_MISSING_INODE_TABLE;
821
0
    if ((block_nr < fs->super->s_first_data_block) ||
822
0
        (block_nr + fs->inode_blocks_per_group - 1 >=
823
0
         ext2fs_blocks_count(fs->super)))
824
0
      return EXT2_ET_GDESC_BAD_INODE_TABLE;
825
0
    block_nr += block;
826
0
    io = fs->io;
827
0
  }
828
0
  offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
829
830
0
  cache_slot = (fs->icache->cache_last + 1) % fs->icache->cache_size;
831
0
  iptr = (struct ext2_inode_large *)fs->icache->cache[cache_slot].inode;
832
833
0
  ptr = (char *) iptr;
834
0
  while (length) {
835
0
    clen = length;
836
0
    if ((offset + length) > fs->blocksize)
837
0
      clen = fs->blocksize - offset;
838
839
0
    if (block_nr != fs->icache->buffer_blk) {
840
0
      retval = io_channel_read_blk64(io, block_nr, 1,
841
0
                 fs->icache->buffer);
842
0
      if (retval)
843
0
        return retval;
844
0
      fs->icache->buffer_blk = block_nr;
845
0
    }
846
847
0
    memcpy(ptr, ((char *) fs->icache->buffer) + (unsigned) offset,
848
0
           clen);
849
850
0
    offset = 0;
851
0
    length -= clen;
852
0
    ptr += clen;
853
0
    block_nr++;
854
0
  }
855
0
  length = EXT2_INODE_SIZE(fs->super);
856
857
  /* Verify the inode checksum. */
858
0
  fail_csum = !ext2fs_inode_csum_verify(fs, ino, iptr);
859
860
#ifdef WORDS_BIGENDIAN
861
  ext2fs_swap_inode_full(fs, (struct ext2_inode_large *) iptr,
862
             (struct ext2_inode_large *) iptr,
863
             0, length);
864
#endif
865
866
  /* Update the inode cache bookkeeping */
867
0
  if (!fail_csum) {
868
0
    fs->icache->cache_last = cache_slot;
869
0
    fs->icache->cache[cache_slot].ino = ino;
870
0
  }
871
0
  memcpy(inode, iptr, (bufsize > length) ? length : bufsize);
872
873
0
  if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
874
0
      !(flags & READ_INODE_NOCSUM) && fail_csum)
875
0
    return EXT2_ET_INODE_CSUM_INVALID;
876
877
0
  return 0;
878
0
}
879
880
errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
881
         struct ext2_inode * inode, int bufsize)
882
0
{
883
0
  return ext2fs_read_inode2(fs, ino, inode, bufsize, 0);
884
0
}
885
886
errcode_t ext2fs_read_inode(ext2_filsys fs, ext2_ino_t ino,
887
          struct ext2_inode * inode)
888
0
{
889
0
  return ext2fs_read_inode2(fs, ino, inode,
890
0
          sizeof(struct ext2_inode), 0);
891
0
}
892
893
errcode_t ext2fs_write_inode2(ext2_filsys fs, ext2_ino_t ino,
894
            struct ext2_inode * inode, int bufsize,
895
            int flags)
896
0
{
897
0
  blk64_t block_nr;
898
0
  dgrp_t group;
899
0
  unsigned long block, offset;
900
0
  errcode_t retval = 0;
901
0
  struct ext2_inode_large *w_inode;
902
0
  char *ptr;
903
0
  unsigned i;
904
0
  int clen;
905
0
  int length = EXT2_INODE_SIZE(fs->super);
906
907
0
  EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
908
909
0
  if (ext2fs_has_feature_journal_dev(fs->super))
910
0
    return EXT2_ET_EXTERNAL_JOURNAL_NOSUPP;
911
912
  /* Check to see if user provided an override function */
913
0
  if (fs->write_inode) {
914
0
    retval = (fs->write_inode)(fs, ino, inode);
915
0
    if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
916
0
      return retval;
917
0
  }
918
919
0
  if ((ino == 0) || (ino > fs->super->s_inodes_count))
920
0
    return EXT2_ET_BAD_INODE_NUM;
921
922
  /* Prepare our shadow buffer for read/modify/byteswap/write */
923
0
  retval = ext2fs_get_mem(length, &w_inode);
924
0
  if (retval)
925
0
    return retval;
926
927
0
  if (bufsize < length) {
928
0
    retval = ext2fs_read_inode2(fs, ino,
929
0
              (struct ext2_inode *)w_inode,
930
0
              length, READ_INODE_NOCSUM);
931
0
    if (retval)
932
0
      goto errout;
933
0
  }
934
935
  /* Check to see if the inode cache needs to be updated */
936
0
  if (fs->icache) {
937
0
    for (i=0; i < fs->icache->cache_size; i++) {
938
0
      if (fs->icache->cache[i].ino == ino) {
939
0
        memcpy(fs->icache->cache[i].inode, inode,
940
0
               (bufsize > length) ? length : bufsize);
941
0
        break;
942
0
      }
943
0
    }
944
0
  } else {
945
0
    retval = ext2fs_create_inode_cache(fs, 4);
946
0
    if (retval)
947
0
      goto errout;
948
0
  }
949
0
  memcpy(w_inode, inode, (bufsize > length) ? length : bufsize);
950
951
0
  if (!(fs->flags & EXT2_FLAG_RW)) {
952
0
    retval = EXT2_ET_RO_FILSYS;
953
0
    goto errout;
954
0
  }
955
956
#ifdef WORDS_BIGENDIAN
957
  ext2fs_swap_inode_full(fs, w_inode, w_inode, 1, length);
958
#endif
959
960
0
  if ((flags & WRITE_INODE_NOCSUM) == 0) {
961
0
    retval = ext2fs_inode_csum_set(fs, ino, w_inode);
962
0
    if (retval)
963
0
      goto errout;
964
0
  }
965
966
0
  group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
967
0
  offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
968
0
    EXT2_INODE_SIZE(fs->super);
969
0
  block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super);
970
0
  block_nr = ext2fs_inode_table_loc(fs, (unsigned) group);
971
0
  if (!block_nr) {
972
0
    retval = EXT2_ET_MISSING_INODE_TABLE;
973
0
    goto errout;
974
0
  }
975
0
  if ((block_nr < fs->super->s_first_data_block) ||
976
0
      (block_nr + fs->inode_blocks_per_group - 1 >=
977
0
       ext2fs_blocks_count(fs->super))) {
978
0
    retval = EXT2_ET_GDESC_BAD_INODE_TABLE;
979
0
    goto errout;
980
0
  }
981
0
  block_nr += block;
982
983
0
  offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
984
985
0
  ptr = (char *) w_inode;
986
987
0
  while (length) {
988
0
    clen = length;
989
0
    if ((offset + length) > fs->blocksize)
990
0
      clen = fs->blocksize - offset;
991
992
0
    if (fs->icache->buffer_blk != block_nr) {
993
0
      retval = io_channel_read_blk64(fs->io, block_nr, 1,
994
0
                 fs->icache->buffer);
995
0
      if (retval)
996
0
        goto errout;
997
0
      fs->icache->buffer_blk = block_nr;
998
0
    }
999
1000
1001
0
    memcpy((char *) fs->icache->buffer + (unsigned) offset,
1002
0
           ptr, clen);
1003
1004
0
    retval = io_channel_write_blk64(fs->io, block_nr, 1,
1005
0
                fs->icache->buffer);
1006
0
    if (retval)
1007
0
      goto errout;
1008
1009
0
    offset = 0;
1010
0
    ptr += clen;
1011
0
    length -= clen;
1012
0
    block_nr++;
1013
0
  }
1014
1015
0
  fs->flags |= EXT2_FLAG_CHANGED;
1016
0
errout:
1017
0
  ext2fs_free_mem(&w_inode);
1018
0
  return retval;
1019
0
}
1020
1021
errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
1022
          struct ext2_inode * inode, int bufsize)
1023
0
{
1024
0
  return ext2fs_write_inode2(fs, ino, inode, bufsize, 0);
1025
0
}
1026
1027
errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino,
1028
           struct ext2_inode *inode)
1029
0
{
1030
0
  return ext2fs_write_inode2(fs, ino, inode,
1031
0
           sizeof(struct ext2_inode), 0);
1032
0
}
1033
1034
/*
1035
 * This function should be called when writing a new inode.  It makes
1036
 * sure that extra part of large inodes is initialized properly.
1037
 */
1038
errcode_t ext2fs_write_new_inode(ext2_filsys fs, ext2_ino_t ino,
1039
         struct ext2_inode *inode)
1040
0
{
1041
0
  struct ext2_inode *buf;
1042
0
  int       size = EXT2_INODE_SIZE(fs->super);
1043
0
  struct ext2_inode_large *large_inode;
1044
0
  errcode_t   retval;
1045
0
  __u32       t = fs->now ? fs->now : time(NULL);
1046
1047
0
  if (!inode->i_ctime)
1048
0
    inode->i_ctime = t;
1049
0
  if (!inode->i_mtime)
1050
0
    inode->i_mtime = t;
1051
0
  if (!inode->i_atime)
1052
0
    inode->i_atime = t;
1053
1054
0
  if (size == sizeof(struct ext2_inode))
1055
0
    return ext2fs_write_inode_full(fs, ino, inode,
1056
0
                 sizeof(struct ext2_inode));
1057
1058
0
  buf = malloc(size);
1059
0
  if (!buf)
1060
0
    return ENOMEM;
1061
1062
0
  memset(buf, 0, size);
1063
0
  *buf = *inode;
1064
1065
0
  large_inode = (struct ext2_inode_large *) buf;
1066
0
  large_inode->i_extra_isize = sizeof(struct ext2_inode_large) -
1067
0
    EXT2_GOOD_OLD_INODE_SIZE;
1068
0
  if (!large_inode->i_crtime)
1069
0
    large_inode->i_crtime = t;
1070
1071
0
  retval = ext2fs_write_inode_full(fs, ino, buf, size);
1072
0
  free(buf);
1073
0
  return retval;
1074
0
}
1075
1076
1077
errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks)
1078
0
{
1079
0
  struct ext2_inode inode;
1080
0
  int     i;
1081
0
  errcode_t   retval;
1082
1083
0
  EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
1084
1085
0
  if (ino > fs->super->s_inodes_count)
1086
0
    return EXT2_ET_BAD_INODE_NUM;
1087
1088
0
  if (fs->get_blocks) {
1089
0
    if (!(*fs->get_blocks)(fs, ino, blocks))
1090
0
      return 0;
1091
0
  }
1092
0
  retval = ext2fs_read_inode(fs, ino, &inode);
1093
0
  if (retval)
1094
0
    return retval;
1095
0
  for (i=0; i < EXT2_N_BLOCKS; i++)
1096
0
    blocks[i] = inode.i_block[i];
1097
0
  return 0;
1098
0
}
1099
1100
errcode_t ext2fs_check_directory(ext2_filsys fs, ext2_ino_t ino)
1101
0
{
1102
0
  struct  ext2_inode  inode;
1103
0
  errcode_t   retval;
1104
1105
0
  EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
1106
1107
0
  if (ino > fs->super->s_inodes_count)
1108
0
    return EXT2_ET_BAD_INODE_NUM;
1109
1110
0
  if (fs->check_directory) {
1111
0
    retval = (fs->check_directory)(fs, ino);
1112
0
    if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
1113
0
      return retval;
1114
0
  }
1115
0
  retval = ext2fs_read_inode(fs, ino, &inode);
1116
0
  if (retval)
1117
0
    return retval;
1118
0
  if (!LINUX_S_ISDIR(inode.i_mode))
1119
0
    return EXT2_ET_NO_DIRECTORY;
1120
0
  return 0;
1121
0
}
1122