Whamcloud - gitweb
LU-6722 jbd: double minimum journal size for RHEL7
[tools/e2fsprogs.git] / lib / ext2fs / inode.c
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 struct ext2_struct_inode_scan {
34         errcode_t               magic;
35         ext2_filsys             fs;
36         ext2_ino_t              current_inode;
37         blk64_t                 current_block;
38         dgrp_t                  current_group;
39         ext2_ino_t              inodes_left;
40         blk_t                   blocks_left;
41         dgrp_t                  groups_left;
42         blk_t                   inode_buffer_blocks;
43         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,
51                                               void * priv_data);
52         void *                  done_group_data;
53         int                     bad_block_ptr;
54         int                     scan_flags;
55         int                     reserved[6];
56 };
57
58 /*
59  * This routine flushes the icache, if it exists.
60  */
61 errcode_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         fs->icache->buffer_blk = 0;
72         return 0;
73 }
74
75 static errcode_t create_icache(ext2_filsys fs)
76 {
77         errcode_t       retval;
78
79         if (fs->icache)
80                 return 0;
81         retval = ext2fs_get_mem(sizeof(struct ext2_inode_cache), &fs->icache);
82         if (retval)
83                 return retval;
84
85         memset(fs->icache, 0, sizeof(struct ext2_inode_cache));
86         retval = ext2fs_get_mem(fs->blocksize, &fs->icache->buffer);
87         if (retval) {
88                 ext2fs_free_mem(&fs->icache);
89                 return retval;
90         }
91         fs->icache->buffer_blk = 0;
92         fs->icache->cache_last = -1;
93         fs->icache->cache_size = 4;
94         fs->icache->refcount = 1;
95         retval = ext2fs_get_array(fs->icache->cache_size,
96                                   sizeof(struct ext2_inode_cache_ent),
97                                   &fs->icache->cache);
98         if (retval) {
99                 ext2fs_free_mem(&fs->icache->buffer);
100                 ext2fs_free_mem(&fs->icache);
101                 return retval;
102         }
103         ext2fs_flush_icache(fs);
104         return 0;
105 }
106
107 errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
108                                  ext2_inode_scan *ret_scan)
109 {
110         ext2_inode_scan scan;
111         errcode_t       retval;
112         errcode_t (*save_get_blocks)(ext2_filsys f, ext2_ino_t ino, blk_t *blocks);
113
114         EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
115
116         /*
117          * If fs->badblocks isn't set, then set it --- since the inode
118          * scanning functions require it.
119          */
120         if (fs->badblocks == 0) {
121                 /*
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;
127                 retval = ext2fs_read_bb_inode(fs, &fs->badblocks);
128                 if (retval && fs->badblocks) {
129                         ext2fs_badblocks_list_free(fs->badblocks);
130                         fs->badblocks = 0;
131                 }
132                 fs->get_blocks = save_get_blocks;
133         }
134
135         retval = ext2fs_get_mem(sizeof(struct ext2_struct_inode_scan), &scan);
136         if (retval)
137                 return retval;
138         memset(scan, 0, sizeof(struct ext2_struct_inode_scan));
139
140         scan->magic = EXT2_ET_MAGIC_INODE_SCAN;
141         scan->fs = fs;
142         scan->inode_size = EXT2_INODE_SIZE(fs->super);
143         scan->bytes_left = 0;
144         scan->current_group = 0;
145         scan->groups_left = fs->group_desc_count - 1;
146         scan->inode_buffer_blocks = buffer_blocks ? buffer_blocks : 8;
147         scan->current_block = ext2fs_inode_table_loc(scan->fs,
148                                                      scan->current_group);
149         scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super);
150         scan->blocks_left = scan->fs->inode_blocks_per_group;
151         if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
152                                        EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
153                 __u32 unused = ext2fs_bg_itable_unused(fs, scan->current_group);
154                 if (scan->inodes_left > unused)
155                         scan->inodes_left -= unused;
156                 else
157                         scan->inodes_left = 0;
158                 scan->blocks_left =
159                         (scan->inodes_left +
160                          (fs->blocksize / scan->inode_size - 1)) *
161                         scan->inode_size / fs->blocksize;
162         }
163         retval = io_channel_alloc_buf(fs->io, scan->inode_buffer_blocks,
164                                       &scan->inode_buffer);
165         scan->done_group = 0;
166         scan->done_group_data = 0;
167         scan->bad_block_ptr = 0;
168         if (retval) {
169                 ext2fs_free_mem(&scan);
170                 return retval;
171         }
172         retval = ext2fs_get_mem(scan->inode_size, &scan->temp_buffer);
173         if (retval) {
174                 ext2fs_free_mem(&scan->inode_buffer);
175                 ext2fs_free_mem(&scan);
176                 return retval;
177         }
178         if (scan->fs->badblocks && scan->fs->badblocks->num)
179                 scan->scan_flags |= EXT2_SF_CHK_BADBLOCKS;
180         if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
181                                        EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
182                 scan->scan_flags |= EXT2_SF_DO_LAZY;
183         *ret_scan = scan;
184         return 0;
185 }
186
187 void ext2fs_close_inode_scan(ext2_inode_scan scan)
188 {
189         if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
190                 return;
191
192         ext2fs_free_mem(&scan->inode_buffer);
193         scan->inode_buffer = NULL;
194         ext2fs_free_mem(&scan->temp_buffer);
195         scan->temp_buffer = NULL;
196         ext2fs_free_mem(&scan);
197         return;
198 }
199
200 void ext2fs_set_inode_callback(ext2_inode_scan scan,
201                                errcode_t (*done_group)(ext2_filsys fs,
202                                                        ext2_inode_scan scan,
203                                                        dgrp_t group,
204                                                        void * priv_data),
205                                void *done_group_data)
206 {
207         if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
208                 return;
209
210         scan->done_group = done_group;
211         scan->done_group_data = done_group_data;
212 }
213
214 int ext2fs_inode_scan_flags(ext2_inode_scan scan, int set_flags,
215                             int clear_flags)
216 {
217         int     old_flags;
218
219         if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
220                 return 0;
221
222         old_flags = scan->scan_flags;
223         scan->scan_flags &= ~clear_flags;
224         scan->scan_flags |= set_flags;
225         return old_flags;
226 }
227
228 /*
229  * This function is called by ext2fs_get_next_inode when it needs to
230  * get ready to read in a new blockgroup.
231  */
232 static errcode_t get_next_blockgroup(ext2_inode_scan scan)
233 {
234         ext2_filsys fs = scan->fs;
235
236         scan->current_group++;
237         scan->groups_left--;
238
239         scan->current_block = ext2fs_inode_table_loc(scan->fs,
240                                                      scan->current_group);
241         scan->current_inode = scan->current_group *
242                 EXT2_INODES_PER_GROUP(fs->super);
243
244         scan->bytes_left = 0;
245         scan->inodes_left = EXT2_INODES_PER_GROUP(fs->super);
246         scan->blocks_left = fs->inode_blocks_per_group;
247         if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
248                                        EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
249                 __u32 unused = ext2fs_bg_itable_unused(fs, scan->current_group);
250                 if (scan->inodes_left > unused)
251                         scan->inodes_left -= unused;
252                 else
253                         scan->inodes_left = 0;
254                 scan->blocks_left =
255                         (scan->inodes_left +
256                          (fs->blocksize / scan->inode_size - 1)) *
257                         scan->inode_size / fs->blocksize;
258         }
259
260         return 0;
261 }
262
263 errcode_t ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan,
264                                             int group)
265 {
266         scan->current_group = group - 1;
267         scan->groups_left = scan->fs->group_desc_count - group;
268         return get_next_blockgroup(scan);
269 }
270
271 /*
272  * This function is called by get_next_blocks() to check for bad
273  * blocks in the inode table.
274  *
275  * This function assumes that badblocks_list->list is sorted in
276  * increasing order.
277  */
278 static errcode_t check_for_inode_bad_blocks(ext2_inode_scan scan,
279                                             blk64_t *num_blocks)
280 {
281         blk64_t blk = scan->current_block;
282         badblocks_list  bb = scan->fs->badblocks;
283
284         /*
285          * If the inode table is missing, then obviously there are no
286          * bad blocks.  :-)
287          */
288         if (blk == 0)
289                 return 0;
290
291         /*
292          * If the current block is greater than the bad block listed
293          * in the bad block list, then advance the pointer until this
294          * is no longer the case.  If we run out of bad blocks, then
295          * we don't need to do any more checking!
296          */
297         while (blk > bb->list[scan->bad_block_ptr]) {
298                 if (++scan->bad_block_ptr >= bb->num) {
299                         scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS;
300                         return 0;
301                 }
302         }
303
304         /*
305          * If the current block is equal to the bad block listed in
306          * the bad block list, then handle that one block specially.
307          * (We could try to handle runs of bad blocks, but that
308          * only increases CPU efficiency by a small amount, at the
309          * expense of a huge expense of code complexity, and for an
310          * uncommon case at that.)
311          */
312         if (blk == bb->list[scan->bad_block_ptr]) {
313                 scan->scan_flags |= EXT2_SF_BAD_INODE_BLK;
314                 *num_blocks = 1;
315                 if (++scan->bad_block_ptr >= bb->num)
316                         scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS;
317                 return 0;
318         }
319
320         /*
321          * If there is a bad block in the range that we're about to
322          * read in, adjust the number of blocks to read so that we we
323          * don't read in the bad block.  (Then the next block to read
324          * will be the bad block, which is handled in the above case.)
325          */
326         if ((blk + *num_blocks) > bb->list[scan->bad_block_ptr])
327                 *num_blocks = (int) (bb->list[scan->bad_block_ptr] - blk);
328
329         return 0;
330 }
331
332 /*
333  * This function is called by ext2fs_get_next_inode when it needs to
334  * read in more blocks from the current blockgroup's inode table.
335  */
336 static errcode_t get_next_blocks(ext2_inode_scan scan)
337 {
338         blk64_t         num_blocks;
339         errcode_t       retval;
340
341         /*
342          * Figure out how many blocks to read; we read at most
343          * inode_buffer_blocks, and perhaps less if there aren't that
344          * many blocks left to read.
345          */
346         num_blocks = scan->inode_buffer_blocks;
347         if (num_blocks > scan->blocks_left)
348                 num_blocks = scan->blocks_left;
349
350         /*
351          * If the past block "read" was a bad block, then mark the
352          * left-over extra bytes as also being bad.
353          */
354         if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK) {
355                 if (scan->bytes_left)
356                         scan->scan_flags |= EXT2_SF_BAD_EXTRA_BYTES;
357                 scan->scan_flags &= ~EXT2_SF_BAD_INODE_BLK;
358         }
359
360         /*
361          * Do inode bad block processing, if necessary.
362          */
363         if (scan->scan_flags & EXT2_SF_CHK_BADBLOCKS) {
364                 retval = check_for_inode_bad_blocks(scan, &num_blocks);
365                 if (retval)
366                         return retval;
367         }
368
369         if ((scan->scan_flags & EXT2_SF_BAD_INODE_BLK) ||
370             (scan->current_block == 0)) {
371                 memset(scan->inode_buffer, 0,
372                        (size_t) num_blocks * scan->fs->blocksize);
373         } else {
374                 retval = io_channel_read_blk64(scan->fs->io,
375                                              scan->current_block,
376                                              (int) num_blocks,
377                                              scan->inode_buffer);
378                 if (retval)
379                         return EXT2_ET_NEXT_INODE_READ;
380         }
381         scan->ptr = scan->inode_buffer;
382         scan->bytes_left = num_blocks * scan->fs->blocksize;
383
384         scan->blocks_left -= num_blocks;
385         if (scan->current_block)
386                 scan->current_block += num_blocks;
387         return 0;
388 }
389
390 #if 0
391 /*
392  * Returns 1 if the entire inode_buffer has a non-zero size and
393  * contains all zeros.  (Not just deleted inodes, since that means
394  * that part of the inode table was used at one point; we want all
395  * zeros, which means that the inode table is pristine.)
396  */
397 static inline int is_empty_scan(ext2_inode_scan scan)
398 {
399         int     i;
400
401         if (scan->bytes_left == 0)
402                 return 0;
403
404         for (i=0; i < scan->bytes_left; i++)
405                 if (scan->ptr[i])
406                         return 0;
407         return 1;
408 }
409 #endif
410
411 errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino,
412                                      struct ext2_inode *inode, int bufsize)
413 {
414         errcode_t       retval;
415         int             extra_bytes = 0;
416
417         EXT2_CHECK_MAGIC(scan, EXT2_ET_MAGIC_INODE_SCAN);
418
419         /*
420          * Do we need to start reading a new block group?
421          */
422         if (scan->inodes_left <= 0) {
423         force_new_group:
424                 if (scan->done_group) {
425                         retval = (scan->done_group)
426                                 (scan->fs, scan, scan->current_group,
427                                  scan->done_group_data);
428                         if (retval)
429                                 return retval;
430                 }
431                 if (scan->groups_left <= 0) {
432                         *ino = 0;
433                         return 0;
434                 }
435                 retval = get_next_blockgroup(scan);
436                 if (retval)
437                         return retval;
438         }
439         /*
440          * These checks are done outside the above if statement so
441          * they can be done for block group #0.
442          */
443         if ((scan->scan_flags & EXT2_SF_DO_LAZY) &&
444             (ext2fs_bg_flags_test(scan->fs, scan->current_group, EXT2_BG_INODE_UNINIT)
445              ))
446                 goto force_new_group;
447         if (scan->inodes_left == 0)
448                 goto force_new_group;
449         if (scan->current_block == 0) {
450                 if (scan->scan_flags & EXT2_SF_SKIP_MISSING_ITABLE) {
451                         goto force_new_group;
452                 } else
453                         return EXT2_ET_MISSING_INODE_TABLE;
454         }
455
456
457         /*
458          * Have we run out of space in the inode buffer?  If so, we
459          * need to read in more blocks.
460          */
461         if (scan->bytes_left < scan->inode_size) {
462                 memcpy(scan->temp_buffer, scan->ptr, scan->bytes_left);
463                 extra_bytes = scan->bytes_left;
464
465                 retval = get_next_blocks(scan);
466                 if (retval)
467                         return retval;
468 #if 0
469                 /*
470                  * XXX test  Need check for used inode somehow.
471                  * (Note: this is hard.)
472                  */
473                 if (is_empty_scan(scan))
474                         goto force_new_group;
475 #endif
476         }
477
478         retval = 0;
479         if (extra_bytes) {
480                 memcpy(scan->temp_buffer+extra_bytes, scan->ptr,
481                        scan->inode_size - extra_bytes);
482                 scan->ptr += scan->inode_size - extra_bytes;
483                 scan->bytes_left -= scan->inode_size - extra_bytes;
484
485 #ifdef WORDS_BIGENDIAN
486                 memset(inode, 0, bufsize);
487                 ext2fs_swap_inode_full(scan->fs,
488                                (struct ext2_inode_large *) inode,
489                                (struct ext2_inode_large *) scan->temp_buffer,
490                                0, bufsize);
491 #else
492                 *inode = *((struct ext2_inode *) scan->temp_buffer);
493 #endif
494                 if (scan->scan_flags & EXT2_SF_BAD_EXTRA_BYTES)
495                         retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
496                 scan->scan_flags &= ~EXT2_SF_BAD_EXTRA_BYTES;
497         } else {
498 #ifdef WORDS_BIGENDIAN
499                 memset(inode, 0, bufsize);
500                 ext2fs_swap_inode_full(scan->fs,
501                                 (struct ext2_inode_large *) inode,
502                                 (struct ext2_inode_large *) scan->ptr,
503                                 0, bufsize);
504 #else
505                 memcpy(inode, scan->ptr, bufsize);
506 #endif
507                 scan->ptr += scan->inode_size;
508                 scan->bytes_left -= scan->inode_size;
509                 if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK)
510                         retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
511         }
512
513         scan->inodes_left--;
514         scan->current_inode++;
515         *ino = scan->current_inode;
516         return retval;
517 }
518
519 errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino,
520                                 struct ext2_inode *inode)
521 {
522         return ext2fs_get_next_inode_full(scan, ino, inode,
523                                                 sizeof(struct ext2_inode));
524 }
525
526 /*
527  * Functions to read and write a single inode.
528  */
529 errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
530                                  struct ext2_inode * inode, int bufsize)
531 {
532         blk64_t         block_nr;
533         unsigned long   group, block, offset;
534         char            *ptr;
535         errcode_t       retval;
536         int             clen, i, inodes_per_block, length;
537         io_channel      io;
538
539         EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
540
541         /* Check to see if user has an override function */
542         if (fs->read_inode &&
543             ((bufsize == sizeof(struct ext2_inode)) ||
544              (EXT2_INODE_SIZE(fs->super) == sizeof(struct ext2_inode)))) {
545                 retval = (fs->read_inode)(fs, ino, inode);
546                 if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
547                         return retval;
548         }
549         if ((ino == 0) || (ino > fs->super->s_inodes_count))
550                 return EXT2_ET_BAD_INODE_NUM;
551         /* Create inode cache if not present */
552         if (!fs->icache) {
553                 retval = create_icache(fs);
554                 if (retval)
555                         return retval;
556         }
557         /* Check to see if it's in the inode cache */
558         if (bufsize == sizeof(struct ext2_inode)) {
559                 /* only old good inode can be retrieved from the cache */
560                 for (i=0; i < fs->icache->cache_size; i++) {
561                         if (fs->icache->cache[i].ino == ino) {
562                                 *inode = fs->icache->cache[i].inode;
563                                 return 0;
564                         }
565                 }
566         }
567         if (fs->flags & EXT2_FLAG_IMAGE_FILE) {
568                 inodes_per_block = fs->blocksize / EXT2_INODE_SIZE(fs->super);
569                 block_nr = fs->image_header->offset_inode / fs->blocksize;
570                 block_nr += (ino - 1) / inodes_per_block;
571                 offset = ((ino - 1) % inodes_per_block) *
572                         EXT2_INODE_SIZE(fs->super);
573                 io = fs->image_io;
574         } else {
575                 group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
576                 if (group > fs->group_desc_count)
577                         return EXT2_ET_BAD_INODE_NUM;
578                 offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
579                         EXT2_INODE_SIZE(fs->super);
580                 block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super);
581                 if (!ext2fs_inode_table_loc(fs, (unsigned) group))
582                         return EXT2_ET_MISSING_INODE_TABLE;
583                 block_nr = ext2fs_inode_table_loc(fs, group) +
584                         block;
585                 io = fs->io;
586         }
587         offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
588
589         length = EXT2_INODE_SIZE(fs->super);
590         if (bufsize < length)
591                 length = bufsize;
592
593         ptr = (char *) inode;
594         while (length) {
595                 clen = length;
596                 if ((offset + length) > fs->blocksize)
597                         clen = fs->blocksize - offset;
598
599                 if (block_nr != fs->icache->buffer_blk) {
600                         retval = io_channel_read_blk64(io, block_nr, 1,
601                                                      fs->icache->buffer);
602                         if (retval)
603                                 return retval;
604                         fs->icache->buffer_blk = block_nr;
605                 }
606
607                 memcpy(ptr, ((char *) fs->icache->buffer) + (unsigned) offset,
608                        clen);
609
610                 offset = 0;
611                 length -= clen;
612                 ptr += clen;
613                 block_nr++;
614         }
615
616 #ifdef WORDS_BIGENDIAN
617         ext2fs_swap_inode_full(fs, (struct ext2_inode_large *) inode,
618                                (struct ext2_inode_large *) inode,
619                                0, bufsize);
620 #endif
621
622         /* Update the inode cache */
623         fs->icache->cache_last = (fs->icache->cache_last + 1) %
624                 fs->icache->cache_size;
625         fs->icache->cache[fs->icache->cache_last].ino = ino;
626         fs->icache->cache[fs->icache->cache_last].inode = *inode;
627
628         return 0;
629 }
630
631 errcode_t ext2fs_read_inode(ext2_filsys fs, ext2_ino_t ino,
632                             struct ext2_inode * inode)
633 {
634         return ext2fs_read_inode_full(fs, ino, inode,
635                                         sizeof(struct ext2_inode));
636 }
637
638 errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
639                                   struct ext2_inode * inode, int bufsize)
640 {
641         blk64_t block_nr;
642         unsigned long group, block, offset;
643         errcode_t retval = 0;
644         struct ext2_inode_large temp_inode, *w_inode;
645         char *ptr;
646         int clen, i, length;
647
648         EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
649
650         /* Check to see if user provided an override function */
651         if (fs->write_inode) {
652                 retval = (fs->write_inode)(fs, ino, inode);
653                 if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
654                         return retval;
655         }
656
657         /* Check to see if the inode cache needs to be updated */
658         if (fs->icache) {
659                 for (i=0; i < fs->icache->cache_size; i++) {
660                         if (fs->icache->cache[i].ino == ino) {
661                                 fs->icache->cache[i].inode = *inode;
662                                 break;
663                         }
664                 }
665         } else {
666                 retval = create_icache(fs);
667                 if (retval)
668                         return retval;
669         }
670
671         if (!(fs->flags & EXT2_FLAG_RW))
672                 return EXT2_ET_RO_FILSYS;
673
674         if ((ino == 0) || (ino > fs->super->s_inodes_count))
675                 return EXT2_ET_BAD_INODE_NUM;
676
677         length = bufsize;
678         if (length < EXT2_INODE_SIZE(fs->super))
679                 length = EXT2_INODE_SIZE(fs->super);
680
681         if (length > (int) sizeof(struct ext2_inode_large)) {
682                 w_inode = malloc(length);
683                 if (!w_inode) {
684                         retval = ENOMEM;
685                         goto errout;
686                 }
687         } else
688                 w_inode = &temp_inode;
689         memset(w_inode, 0, length);
690
691 #ifdef WORDS_BIGENDIAN
692         ext2fs_swap_inode_full(fs, w_inode,
693                                (struct ext2_inode_large *) inode,
694                                1, bufsize);
695 #else
696         memcpy(w_inode, inode, bufsize);
697 #endif
698
699         group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
700         offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
701                 EXT2_INODE_SIZE(fs->super);
702         block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super);
703         if (!ext2fs_inode_table_loc(fs, (unsigned) group)) {
704                 retval = EXT2_ET_MISSING_INODE_TABLE;
705                 goto errout;
706         }
707         block_nr = ext2fs_inode_table_loc(fs, (unsigned) group) + block;
708
709         offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
710
711         length = EXT2_INODE_SIZE(fs->super);
712         if (length > bufsize)
713                 length = bufsize;
714
715         ptr = (char *) w_inode;
716
717         while (length) {
718                 clen = length;
719                 if ((offset + length) > fs->blocksize)
720                         clen = fs->blocksize - offset;
721
722                 if (fs->icache->buffer_blk != block_nr) {
723                         retval = io_channel_read_blk64(fs->io, block_nr, 1,
724                                                      fs->icache->buffer);
725                         if (retval)
726                                 goto errout;
727                         fs->icache->buffer_blk = block_nr;
728                 }
729
730
731                 memcpy((char *) fs->icache->buffer + (unsigned) offset,
732                        ptr, clen);
733
734                 retval = io_channel_write_blk64(fs->io, block_nr, 1,
735                                               fs->icache->buffer);
736                 if (retval)
737                         goto errout;
738
739                 offset = 0;
740                 ptr += clen;
741                 length -= clen;
742                 block_nr++;
743         }
744
745         fs->flags |= EXT2_FLAG_CHANGED;
746 errout:
747         if (w_inode && w_inode != &temp_inode)
748                 free(w_inode);
749         return retval;
750 }
751
752 errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino,
753                              struct ext2_inode *inode)
754 {
755         return ext2fs_write_inode_full(fs, ino, inode,
756                                        sizeof(struct ext2_inode));
757 }
758
759 /*
760  * This function should be called when writing a new inode.  It makes
761  * sure that extra part of large inodes is initialized properly.
762  */
763 errcode_t ext2fs_write_new_inode(ext2_filsys fs, ext2_ino_t ino,
764                                  struct ext2_inode *inode)
765 {
766         struct ext2_inode       *buf;
767         int                     size = EXT2_INODE_SIZE(fs->super);
768         struct ext2_inode_large *large_inode;
769         errcode_t               retval;
770         __u32                   t = fs->now ? fs->now : time(NULL);
771
772         if (!inode->i_ctime)
773                 inode->i_ctime = t;
774         if (!inode->i_mtime)
775                 inode->i_mtime = t;
776         if (!inode->i_atime)
777                 inode->i_atime = t;
778
779         if (size == sizeof(struct ext2_inode))
780                 return ext2fs_write_inode_full(fs, ino, inode,
781                                                sizeof(struct ext2_inode));
782
783         buf = malloc(size);
784         if (!buf)
785                 return ENOMEM;
786
787         memset(buf, 0, size);
788         *buf = *inode;
789
790         large_inode = (struct ext2_inode_large *) buf;
791         large_inode->i_extra_isize = sizeof(struct ext2_inode_large) -
792                 EXT2_GOOD_OLD_INODE_SIZE;
793         if (!large_inode->i_crtime)
794                 large_inode->i_crtime = t;
795
796         retval = ext2fs_write_inode_full(fs, ino, buf, size);
797         free(buf);
798         return retval;
799 }
800
801
802 errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks)
803 {
804         struct ext2_inode       inode;
805         int                     i;
806         errcode_t               retval;
807
808         EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
809
810         if (ino > fs->super->s_inodes_count)
811                 return EXT2_ET_BAD_INODE_NUM;
812
813         if (fs->get_blocks) {
814                 if (!(*fs->get_blocks)(fs, ino, blocks))
815                         return 0;
816         }
817         retval = ext2fs_read_inode(fs, ino, &inode);
818         if (retval)
819                 return retval;
820         for (i=0; i < EXT2_N_BLOCKS; i++)
821                 blocks[i] = inode.i_block[i];
822         return 0;
823 }
824
825 errcode_t ext2fs_check_directory(ext2_filsys fs, ext2_ino_t ino)
826 {
827         struct  ext2_inode      inode;
828         errcode_t               retval;
829
830         EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
831
832         if (ino > fs->super->s_inodes_count)
833                 return EXT2_ET_BAD_INODE_NUM;
834
835         if (fs->check_directory) {
836                 retval = (fs->check_directory)(fs, ino);
837                 if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
838                         return retval;
839         }
840         retval = ext2fs_read_inode(fs, ino, &inode);
841         if (retval)
842                 return retval;
843         if (!LINUX_S_ISDIR(inode.i_mode))
844                 return EXT2_ET_NO_DIRECTORY;
845         return 0;
846 }
847