blob: 9912a98e6f323aa1630fcb9f2e044ea8fd21122f [file] [log] [blame]
Theodore Ts'o3839e651997-04-26 13:21:57 +00001/*
2 * inode.c --- utility routines to read and write inodes
3 *
Theodore Ts'o19c78dc1997-04-29 16:17:09 +00004 * 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%
Theodore Ts'o3839e651997-04-26 13:21:57 +000010 */
11
12#include <stdio.h>
13#include <string.h>
Theodore Ts'o4cbe8af1997-08-10 23:07:40 +000014#if HAVE_UNISTD_H
Theodore Ts'o3839e651997-04-26 13:21:57 +000015#include <unistd.h>
Theodore Ts'o4cbe8af1997-08-10 23:07:40 +000016#endif
Theodore Ts'o1d2ff461997-10-19 23:00:21 +000017#if HAVE_SYS_STAT_H
Theodore Ts'o3839e651997-04-26 13:21:57 +000018#include <sys/stat.h>
Theodore Ts'o1d2ff461997-10-19 23:00:21 +000019#endif
20#if HAVE_SYS_TYPES_H
Theodore Ts'o3839e651997-04-26 13:21:57 +000021#include <sys/types.h>
Theodore Ts'o1d2ff461997-10-19 23:00:21 +000022#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +000023
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000024#if EXT2_FLAT_INCLUDES
25#include "ext2_fs.h"
26#else
Theodore Ts'o3839e651997-04-26 13:21:57 +000027#include <linux/ext2_fs.h>
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000028#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +000029
Theodore Ts'o19c78dc1997-04-29 16:17:09 +000030#include "ext2fsP.h"
Theodore Ts'oa78926e2001-05-03 04:02:29 +000031#include "e2image.h"
Theodore Ts'o19c78dc1997-04-29 16:17:09 +000032
33struct ext2_struct_inode_scan {
Theodore Ts'o3cb6c501997-08-11 20:29:22 +000034 errcode_t magic;
Theodore Ts'o19c78dc1997-04-29 16:17:09 +000035 ext2_filsys fs;
Theodore Ts'o31dbecd2001-01-11 04:54:39 +000036 ext2_ino_t current_inode;
Theodore Ts'o19c78dc1997-04-29 16:17:09 +000037 blk_t current_block;
38 dgrp_t current_group;
Theodore Ts'o31dbecd2001-01-11 04:54:39 +000039 ext2_ino_t inodes_left;
Theodore Ts'o3cb6c501997-08-11 20:29:22 +000040 blk_t blocks_left;
41 dgrp_t groups_left;
42 blk_t inode_buffer_blocks;
Theodore Ts'o19c78dc1997-04-29 16:17:09 +000043 char * inode_buffer;
44 int inode_size;
45 char * ptr;
46 int bytes_left;
47 char *temp_buffer;
48 errcode_t (*done_group)(ext2_filsys fs,
49 ext2_inode_scan scan,
50 dgrp_t group,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000051 void * priv_data);
Theodore Ts'o19c78dc1997-04-29 16:17:09 +000052 void * done_group_data;
53 int bad_block_ptr;
54 int scan_flags;
55 int reserved[6];
56};
Theodore Ts'o3839e651997-04-26 13:21:57 +000057
Theodore Ts'o6a7f4552000-11-12 19:07:06 +000058/*
59 * This routine flushes the icache, if it exists.
60 */
61errcode_t ext2fs_flush_icache(ext2_filsys fs)
62{
63 int i;
64
65 if (!fs->icache)
66 return 0;
67
68 for (i=0; i < fs->icache->cache_size; i++)
69 fs->icache->cache[i].ino = 0;
70
71 return 0;
72}
73
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000074static errcode_t create_icache(ext2_filsys fs)
75{
Theodore Ts'o7b4e4531997-10-26 03:41:24 +000076 errcode_t retval;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000077
78 if (fs->icache)
79 return 0;
Theodore Ts'o7b4e4531997-10-26 03:41:24 +000080 retval = ext2fs_get_mem(sizeof(struct ext2_inode_cache),
81 (void **) &fs->icache);
82 if (retval)
83 return retval;
84
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000085 memset(fs->icache, 0, sizeof(struct ext2_inode_cache));
Theodore Ts'o7b4e4531997-10-26 03:41:24 +000086 retval = ext2fs_get_mem(fs->blocksize, (void **) &fs->icache->buffer);
87 if (retval) {
88 ext2fs_free_mem((void **) &fs->icache);
89 return retval;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000090 }
91 fs->icache->buffer_blk = 0;
92 fs->icache->cache_last = -1;
93 fs->icache->cache_size = 4;
94 fs->icache->refcount = 1;
Theodore Ts'o7b4e4531997-10-26 03:41:24 +000095 retval = ext2fs_get_mem(sizeof(struct ext2_inode_cache_ent)
96 * fs->icache->cache_size,
97 (void **) &fs->icache->cache);
98 if (retval) {
99 ext2fs_free_mem((void **) &fs->icache->buffer);
100 ext2fs_free_mem((void **) &fs->icache);
101 return retval;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000102 }
Theodore Ts'o6a7f4552000-11-12 19:07:06 +0000103 ext2fs_flush_icache(fs);
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000104 return 0;
105}
106
Theodore Ts'o3839e651997-04-26 13:21:57 +0000107errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
108 ext2_inode_scan *ret_scan)
109{
110 ext2_inode_scan scan;
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000111 errcode_t retval;
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000112 errcode_t (*save_get_blocks)(ext2_filsys f, ext2_ino_t ino, blk_t *blocks);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000113
Theodore Ts'of3db3561997-04-26 13:34:30 +0000114 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
115
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000116 /*
117 * If fs->badblocks isn't set, then set it --- since the inode
118 * scanning functions require it.
119 */
120 if (fs->badblocks == 0) {
Theodore Ts'o521e3681997-04-29 17:48:10 +0000121 /*
122 * Temporarly save fs->get_blocks and set it to zero,
123 * for compatibility with old e2fsck's.
124 */
125 save_get_blocks = fs->get_blocks;
126 fs->get_blocks = 0;
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000127 retval = ext2fs_read_bb_inode(fs, &fs->badblocks);
128 if (retval && fs->badblocks) {
129 badblocks_list_free(fs->badblocks);
130 fs->badblocks = 0;
131 }
Theodore Ts'o521e3681997-04-29 17:48:10 +0000132 fs->get_blocks = save_get_blocks;
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000133 }
134
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000135 retval = ext2fs_get_mem(sizeof(struct ext2_struct_inode_scan),
136 (void **) &scan);
137 if (retval)
138 return retval;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000139 memset(scan, 0, sizeof(struct ext2_struct_inode_scan));
140
Theodore Ts'of3db3561997-04-26 13:34:30 +0000141 scan->magic = EXT2_ET_MAGIC_INODE_SCAN;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000142 scan->fs = fs;
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000143 scan->inode_size = EXT2_INODE_SIZE(fs->super);
144 scan->bytes_left = 0;
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000145 scan->current_group = 0;
146 scan->groups_left = fs->group_desc_count - 1;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000147 scan->inode_buffer_blocks = buffer_blocks ? buffer_blocks : 8;
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000148 scan->current_block = scan->fs->
149 group_desc[scan->current_group].bg_inode_table;
150 scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super);
151 scan->blocks_left = scan->fs->inode_blocks_per_group;
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000152 retval = ext2fs_get_mem((size_t) (scan->inode_buffer_blocks *
153 fs->blocksize),
154 (void **) &scan->inode_buffer);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000155 scan->done_group = 0;
156 scan->done_group_data = 0;
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000157 scan->bad_block_ptr = 0;
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000158 if (retval) {
159 ext2fs_free_mem((void **) &scan);
160 return retval;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000161 }
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000162 retval = ext2fs_get_mem(scan->inode_size,
163 (void **) &scan->temp_buffer);
164 if (retval) {
165 ext2fs_free_mem((void **) &scan->inode_buffer);
166 ext2fs_free_mem((void **) &scan);
167 return retval;
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000168 }
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000169 if (scan->fs->badblocks && scan->fs->badblocks->num)
170 scan->scan_flags |= EXT2_SF_CHK_BADBLOCKS;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000171 *ret_scan = scan;
172 return 0;
173}
174
175void ext2fs_close_inode_scan(ext2_inode_scan scan)
176{
Theodore Ts'of3db3561997-04-26 13:34:30 +0000177 if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
178 return;
179
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000180 ext2fs_free_mem((void **) &scan->inode_buffer);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000181 scan->inode_buffer = NULL;
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000182 ext2fs_free_mem((void **) &scan->temp_buffer);
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000183 scan->temp_buffer = NULL;
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000184 ext2fs_free_mem((void **) &scan);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000185 return;
186}
187
Theodore Ts'of3db3561997-04-26 13:34:30 +0000188void ext2fs_set_inode_callback(ext2_inode_scan scan,
189 errcode_t (*done_group)(ext2_filsys fs,
190 ext2_inode_scan scan,
191 dgrp_t group,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000192 void * priv_data),
Theodore Ts'of3db3561997-04-26 13:34:30 +0000193 void *done_group_data)
194{
195 if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
196 return;
197
198 scan->done_group = done_group;
199 scan->done_group_data = done_group_data;
200}
201
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000202int ext2fs_inode_scan_flags(ext2_inode_scan scan, int set_flags,
203 int clear_flags)
204{
205 int old_flags;
206
207 if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
208 return 0;
209
210 old_flags = scan->scan_flags;
211 scan->scan_flags &= ~clear_flags;
212 scan->scan_flags |= set_flags;
213 return old_flags;
214}
215
216/*
217 * This function is called by ext2fs_get_next_inode when it needs to
218 * get ready to read in a new blockgroup.
219 */
220static errcode_t get_next_blockgroup(ext2_inode_scan scan)
221{
222 scan->current_group++;
223 scan->groups_left--;
224
225 scan->current_block = scan->fs->
226 group_desc[scan->current_group].bg_inode_table;
227
Theodore Ts'o818180c1998-06-27 05:11:14 +0000228 scan->current_inode = scan->current_group *
229 EXT2_INODES_PER_GROUP(scan->fs->super);
230
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000231 scan->bytes_left = 0;
232 scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super);
233 scan->blocks_left = scan->fs->inode_blocks_per_group;
234 return 0;
235}
236
237errcode_t ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan,
238 int group)
239{
240 scan->current_group = group - 1;
241 scan->groups_left = scan->fs->group_desc_count - group;
242 return get_next_blockgroup(scan);
243}
244
245/*
246 * This function is called by get_next_blocks() to check for bad
247 * blocks in the inode table.
248 *
249 * This function assumes that badblocks_list->list is sorted in
250 * increasing order.
251 */
252static errcode_t check_for_inode_bad_blocks(ext2_inode_scan scan,
Theodore Ts'o3cb6c501997-08-11 20:29:22 +0000253 blk_t *num_blocks)
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000254{
255 blk_t blk = scan->current_block;
256 badblocks_list bb = scan->fs->badblocks;
257
258 /*
259 * If the inode table is missing, then obviously there are no
260 * bad blocks. :-)
261 */
262 if (blk == 0)
263 return 0;
264
265 /*
266 * If the current block is greater than the bad block listed
267 * in the bad block list, then advance the pointer until this
268 * is no longer the case. If we run out of bad blocks, then
269 * we don't need to do any more checking!
270 */
271 while (blk > bb->list[scan->bad_block_ptr]) {
272 if (++scan->bad_block_ptr >= bb->num) {
273 scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS;
274 return 0;
275 }
276 }
277
278 /*
279 * If the current block is equal to the bad block listed in
280 * the bad block list, then handle that one block specially.
281 * (We could try to handle runs of bad blocks, but that
282 * only increases CPU efficiency by a small amount, at the
283 * expense of a huge expense of code complexity, and for an
284 * uncommon case at that.)
285 */
286 if (blk == bb->list[scan->bad_block_ptr]) {
287 scan->scan_flags |= EXT2_SF_BAD_INODE_BLK;
288 *num_blocks = 1;
289 if (++scan->bad_block_ptr >= bb->num)
290 scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS;
291 return 0;
292 }
293
294 /*
295 * If there is a bad block in the range that we're about to
296 * read in, adjust the number of blocks to read so that we we
297 * don't read in the bad block. (Then the next block to read
298 * will be the bad block, which is handled in the above case.)
299 */
300 if ((blk + *num_blocks) > bb->list[scan->bad_block_ptr])
Theodore Ts'o3cb6c501997-08-11 20:29:22 +0000301 *num_blocks = (int) (bb->list[scan->bad_block_ptr] - blk);
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000302
303 return 0;
304}
305
306/*
307 * This function is called by ext2fs_get_next_inode when it needs to
308 * read in more blocks from the current blockgroup's inode table.
309 */
310static errcode_t get_next_blocks(ext2_inode_scan scan)
311{
Theodore Ts'o3cb6c501997-08-11 20:29:22 +0000312 blk_t num_blocks;
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000313 errcode_t retval;
314
315 /*
316 * Figure out how many blocks to read; we read at most
317 * inode_buffer_blocks, and perhaps less if there aren't that
318 * many blocks left to read.
319 */
320 num_blocks = scan->inode_buffer_blocks;
321 if (num_blocks > scan->blocks_left)
322 num_blocks = scan->blocks_left;
323
324 /*
325 * If the past block "read" was a bad block, then mark the
326 * left-over extra bytes as also being bad.
327 */
328 if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK) {
329 if (scan->bytes_left)
330 scan->scan_flags |= EXT2_SF_BAD_EXTRA_BYTES;
331 scan->scan_flags &= ~EXT2_SF_BAD_INODE_BLK;
332 }
333
334 /*
335 * Do inode bad block processing, if necessary.
336 */
337 if (scan->scan_flags & EXT2_SF_CHK_BADBLOCKS) {
338 retval = check_for_inode_bad_blocks(scan, &num_blocks);
339 if (retval)
340 return retval;
341 }
342
343 if ((scan->scan_flags & EXT2_SF_BAD_INODE_BLK) ||
344 (scan->current_block == 0)) {
345 memset(scan->inode_buffer, 0,
Theodore Ts'o3cb6c501997-08-11 20:29:22 +0000346 (size_t) num_blocks * scan->fs->blocksize);
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000347 } else {
348 retval = io_channel_read_blk(scan->fs->io,
349 scan->current_block,
Theodore Ts'o3cb6c501997-08-11 20:29:22 +0000350 (int) num_blocks,
351 scan->inode_buffer);
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000352 if (retval)
353 return EXT2_ET_NEXT_INODE_READ;
354 }
355 scan->ptr = scan->inode_buffer;
356 scan->bytes_left = num_blocks * scan->fs->blocksize;
357
358 scan->blocks_left -= num_blocks;
359 if (scan->current_block)
360 scan->current_block += num_blocks;
361 return 0;
362}
363
Theodore Ts'o818180c1998-06-27 05:11:14 +0000364#if 0
365/*
366 * Returns 1 if the entire inode_buffer has a non-zero size and
367 * contains all zeros. (Not just deleted inodes, since that means
368 * that part of the inode table was used at one point; we want all
369 * zeros, which means that the inode table is pristine.)
370 */
371static inline int is_empty_scan(ext2_inode_scan scan)
372{
373 int i;
374
375 if (scan->bytes_left == 0)
376 return 0;
377
378 for (i=0; i < scan->bytes_left; i++)
379 if (scan->ptr[i])
380 return 0;
381 return 1;
382}
383#endif
384
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000385errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000386 struct ext2_inode *inode)
387{
388 errcode_t retval;
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000389 int extra_bytes = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000390
Theodore Ts'of3db3561997-04-26 13:34:30 +0000391 EXT2_CHECK_MAGIC(scan, EXT2_ET_MAGIC_INODE_SCAN);
392
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000393 /*
394 * Do we need to start reading a new block group?
395 */
Theodore Ts'o3839e651997-04-26 13:21:57 +0000396 if (scan->inodes_left <= 0) {
Theodore Ts'o818180c1998-06-27 05:11:14 +0000397 force_new_group:
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000398 if (scan->done_group) {
399 retval = (scan->done_group)
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000400 (scan->fs, scan, scan->current_group,
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000401 scan->done_group_data);
402 if (retval)
403 return retval;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000404 }
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000405 if (scan->groups_left <= 0) {
406 *ino = 0;
407 return 0;
408 }
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000409 retval = get_next_blockgroup(scan);
410 if (retval)
411 return retval;
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000412 }
Theodore Ts'o218a4861998-02-21 01:41:39 +0000413 /*
414 * This is done outside the above if statement so that the
415 * check can be done for block group #0.
416 */
417 if (scan->current_block == 0) {
418 if (scan->scan_flags & EXT2_SF_SKIP_MISSING_ITABLE) {
Theodore Ts'o818180c1998-06-27 05:11:14 +0000419 goto force_new_group;
Theodore Ts'o218a4861998-02-21 01:41:39 +0000420 } else
421 return EXT2_ET_MISSING_INODE_TABLE;
422 }
423
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000424
425 /*
426 * Have we run out of space in the inode buffer? If so, we
427 * need to read in more blocks.
428 */
429 if (scan->bytes_left < scan->inode_size) {
430 memcpy(scan->temp_buffer, scan->ptr, scan->bytes_left);
431 extra_bytes = scan->bytes_left;
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000432
433 retval = get_next_blocks(scan);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000434 if (retval)
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000435 return retval;
Theodore Ts'o818180c1998-06-27 05:11:14 +0000436#if 0
437 /*
438 * XXX test Need check for used inode somehow.
439 * (Note: this is hard.)
440 */
441 if (is_empty_scan(scan))
442 goto force_new_group;
443#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000444 }
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000445
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000446 retval = 0;
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000447 if (extra_bytes) {
448 memcpy(scan->temp_buffer+extra_bytes, scan->ptr,
449 scan->inode_size - extra_bytes);
450 scan->ptr += scan->inode_size - extra_bytes;
451 scan->bytes_left -= scan->inode_size - extra_bytes;
452
Theodore Ts'o5c576471997-04-29 15:29:49 +0000453 if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
454 (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000455 ext2fs_swap_inode(scan->fs, inode,
456 (struct ext2_inode *) scan->temp_buffer, 0);
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000457 else
458 *inode = *((struct ext2_inode *) scan->temp_buffer);
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000459 if (scan->scan_flags & EXT2_SF_BAD_EXTRA_BYTES)
460 retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
461 scan->scan_flags &= ~EXT2_SF_BAD_EXTRA_BYTES;
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000462 } else {
Theodore Ts'o5c576471997-04-29 15:29:49 +0000463 if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
464 (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000465 ext2fs_swap_inode(scan->fs, inode,
466 (struct ext2_inode *) scan->ptr, 0);
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000467 else
468 *inode = *((struct ext2_inode *) scan->ptr);
469 scan->ptr += scan->inode_size;
470 scan->bytes_left -= scan->inode_size;
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000471 if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK)
472 retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000473 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000474
Theodore Ts'o3839e651997-04-26 13:21:57 +0000475 scan->inodes_left--;
476 scan->current_inode++;
477 *ino = scan->current_inode;
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000478 return retval;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000479}
480
481/*
482 * Functions to read and write a single inode.
483 */
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000484errcode_t ext2fs_read_inode (ext2_filsys fs, ext2_ino_t ino,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000485 struct ext2_inode * inode)
486{
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000487 unsigned long group, block, block_nr, offset;
488 char *ptr;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000489 errcode_t retval;
Theodore Ts'oa78926e2001-05-03 04:02:29 +0000490 int clen, length, i, inodes_per_block;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000491
Theodore Ts'of3db3561997-04-26 13:34:30 +0000492 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
493
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000494 /* Check to see if user has an override function */
495 if (fs->read_inode) {
496 retval = (fs->read_inode)(fs, ino, inode);
497 if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
498 return retval;
499 }
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000500 /* Create inode cache if not present */
501 if (!fs->icache) {
502 retval = create_icache(fs);
503 if (retval)
504 return retval;
505 }
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000506 /* Check to see if it's in the inode cache */
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000507 for (i=0; i < fs->icache->cache_size; i++) {
508 if (fs->icache->cache[i].ino == ino) {
509 *inode = fs->icache->cache[i].inode;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000510 return 0;
511 }
512 }
Theodore Ts'o665f7101999-01-08 13:33:39 +0000513 if ((ino == 0) || (ino > fs->super->s_inodes_count))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000514 return EXT2_ET_BAD_INODE_NUM;
Theodore Ts'oa78926e2001-05-03 04:02:29 +0000515 if (fs->flags & EXT2_FLAG_IMAGE_FILE) {
516 inodes_per_block = fs->blocksize / EXT2_INODE_SIZE(fs->super);
517 block_nr = fs->image_header->offset_inode / fs->blocksize;
518 block_nr += (ino - 1) / inodes_per_block;
519 offset = ((ino - 1) % inodes_per_block) *
520 EXT2_INODE_SIZE(fs->super);
521 } else {
522 group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
523 offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
524 EXT2_INODE_SIZE(fs->super);
525 block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super);
526 if (!fs->group_desc[(unsigned)group].bg_inode_table)
527 return EXT2_ET_MISSING_INODE_TABLE;
528 block_nr = fs->group_desc[(unsigned)group].bg_inode_table +
529 block;
530 }
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000531 if (block_nr != fs->icache->buffer_blk) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000532 retval = io_channel_read_blk(fs->io, block_nr, 1,
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000533 fs->icache->buffer);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000534 if (retval)
535 return retval;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000536 fs->icache->buffer_blk = block_nr;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000537 }
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000538 offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
Theodore Ts'o3cb6c501997-08-11 20:29:22 +0000539 ptr = ((char *) fs->icache->buffer) + (unsigned) offset;
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000540
541 memset(inode, 0, sizeof(struct ext2_inode));
542 length = EXT2_INODE_SIZE(fs->super);
543 if (length > sizeof(struct ext2_inode))
544 length = sizeof(struct ext2_inode);
545
546 if ((offset + length) > EXT2_BLOCK_SIZE(fs->super)) {
Theodore Ts'o3cb6c501997-08-11 20:29:22 +0000547 clen = (int) (EXT2_BLOCK_SIZE(fs->super) - offset);
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000548 memcpy((char *) inode, ptr, clen);
549 length -= clen;
550
551 retval = io_channel_read_blk(fs->io, block_nr+1, 1,
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000552 fs->icache->buffer);
553 if (retval) {
554 fs->icache->buffer_blk = 0;
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000555 return retval;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000556 }
557 fs->icache->buffer_blk = block_nr+1;
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000558
559 memcpy(((char *) inode) + clen,
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000560 fs->icache->buffer, length);
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000561 } else
562 memcpy((char *) inode, ptr, length);
563
Theodore Ts'o5c576471997-04-29 15:29:49 +0000564 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
565 (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000566 ext2fs_swap_inode(fs, inode, inode, 0);
567
568 /* Update the inode cache */
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000569 fs->icache->cache_last = (fs->icache->cache_last + 1) %
570 fs->icache->cache_size;
571 fs->icache->cache[fs->icache->cache_last].ino = ino;
572 fs->icache->cache[fs->icache->cache_last].inode = *inode;
573
Theodore Ts'o3839e651997-04-26 13:21:57 +0000574 return 0;
575}
576
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000577errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino,
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000578 struct ext2_inode * inode)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000579{
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000580 unsigned long group, block, block_nr, offset;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000581 errcode_t retval;
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000582 struct ext2_inode temp_inode;
583 char *ptr;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000584 int clen, length, i;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000585
Theodore Ts'of3db3561997-04-26 13:34:30 +0000586 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
587
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000588 /* Check to see if user provided an override function */
589 if (fs->write_inode) {
590 retval = (fs->write_inode)(fs, ino, inode);
591 if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
592 return retval;
593 }
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000594
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000595 /* Check to see if the inode cache needs to be updated */
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000596 if (fs->icache) {
597 for (i=0; i < fs->icache->cache_size; i++) {
598 if (fs->icache->cache[i].ino == ino) {
599 fs->icache->cache[i].inode = *inode;
600 break;
601 }
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000602 }
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000603 } else {
604 retval = create_icache(fs);
605 if (retval)
606 return retval;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000607 }
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000608
Theodore Ts'o3839e651997-04-26 13:21:57 +0000609 if (!(fs->flags & EXT2_FLAG_RW))
610 return EXT2_ET_RO_FILSYS;
611
Theodore Ts'o665f7101999-01-08 13:33:39 +0000612 if ((ino == 0) || (ino > fs->super->s_inodes_count))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000613 return EXT2_ET_BAD_INODE_NUM;
614
Theodore Ts'o5c576471997-04-29 15:29:49 +0000615 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
616 (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000617 ext2fs_swap_inode(fs, &temp_inode, inode, 1);
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000618 else
619 memcpy(&temp_inode, inode, sizeof(struct ext2_inode));
620
Theodore Ts'o3839e651997-04-26 13:21:57 +0000621 group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000622 offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
623 EXT2_INODE_SIZE(fs->super);
624 block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super);
Theodore Ts'o3cb6c501997-08-11 20:29:22 +0000625 if (!fs->group_desc[(unsigned) group].bg_inode_table)
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000626 return EXT2_ET_MISSING_INODE_TABLE;
Theodore Ts'o3cb6c501997-08-11 20:29:22 +0000627 block_nr = fs->group_desc[(unsigned) group].bg_inode_table + block;
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000628 offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
Theodore Ts'o3cb6c501997-08-11 20:29:22 +0000629 ptr = (char *) fs->icache->buffer + (unsigned) offset;
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000630
631 length = EXT2_INODE_SIZE(fs->super);
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000632 clen = length;
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000633 if (length > sizeof(struct ext2_inode))
634 length = sizeof(struct ext2_inode);
635
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000636 if (fs->icache->buffer_blk != block_nr) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000637 retval = io_channel_read_blk(fs->io, block_nr, 1,
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000638 fs->icache->buffer);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000639 if (retval)
640 return retval;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000641 fs->icache->buffer_blk = block_nr;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000642 }
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000643
644 if ((offset + length) > EXT2_BLOCK_SIZE(fs->super)) {
Theodore Ts'o3cb6c501997-08-11 20:29:22 +0000645 clen = (int) (EXT2_BLOCK_SIZE(fs->super) - offset);
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000646 length -= clen;
647 } else {
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000648 length = 0;
649 }
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000650 memcpy(ptr, &temp_inode, clen);
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000651 retval = io_channel_write_blk(fs->io, block_nr, 1, fs->icache->buffer);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000652 if (retval)
653 return retval;
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000654
655 if (length) {
656 retval = io_channel_read_blk(fs->io, ++block_nr, 1,
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000657 fs->icache->buffer);
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000658 if (retval) {
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000659 fs->icache->buffer_blk = 0;
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000660 return retval;
661 }
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000662 fs->icache->buffer_blk = block_nr;
663 memcpy(fs->icache->buffer, ((char *) &temp_inode) + clen,
664 length);
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000665
666 retval = io_channel_write_blk(fs->io, block_nr, 1,
Theodore Ts'oa29f4d31997-04-29 21:26:48 +0000667 fs->icache->buffer);
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000668 if (retval)
669 return retval;
670 }
671
Theodore Ts'o3839e651997-04-26 13:21:57 +0000672 fs->flags |= EXT2_FLAG_CHANGED;
673 return 0;
674}
675
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000676errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000677{
678 struct ext2_inode inode;
679 int i;
680 errcode_t retval;
681
Theodore Ts'of3db3561997-04-26 13:34:30 +0000682 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
683
Theodore Ts'o3839e651997-04-26 13:21:57 +0000684 if (ino > fs->super->s_inodes_count)
685 return EXT2_ET_BAD_INODE_NUM;
686
687 if (fs->get_blocks) {
688 if (!(*fs->get_blocks)(fs, ino, blocks))
689 return 0;
690 }
691 retval = ext2fs_read_inode(fs, ino, &inode);
692 if (retval)
693 return retval;
694 for (i=0; i < EXT2_N_BLOCKS; i++)
695 blocks[i] = inode.i_block[i];
696 return 0;
697}
698
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000699errcode_t ext2fs_check_directory(ext2_filsys fs, ext2_ino_t ino)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000700{
701 struct ext2_inode inode;
702 errcode_t retval;
703
Theodore Ts'of3db3561997-04-26 13:34:30 +0000704 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
705
Theodore Ts'o3839e651997-04-26 13:21:57 +0000706 if (ino > fs->super->s_inodes_count)
707 return EXT2_ET_BAD_INODE_NUM;
708
Theodore Ts'od163b091997-10-03 17:42:28 +0000709 if (fs->check_directory) {
710 retval = (fs->check_directory)(fs, ino);
711 if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
712 return retval;
713 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000714 retval = ext2fs_read_inode(fs, ino, &inode);
715 if (retval)
716 return retval;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000717 if (!LINUX_S_ISDIR(inode.i_mode))
Theodore Ts'o1f0b6c11997-10-31 06:07:47 +0000718 return EXT2_ET_NO_DIRECTORY;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000719 return 0;
720}
721