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

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

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

File size: 5.1 KB
Line 
1/*
2 * dir_iterate.c --- ext2fs directory iteration operations
3 *
4 * Copyright (C) 1993, 1994, 1994, 1995, 1996, 1997 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#include <string.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17#if HAVE_ERRNO_H
18#include <errno.h>
19#endif
20
21#include "ext2_fs.h"
22#include "ext2fsP.h"
23
24/*
25 * This function checks to see whether or not a potential deleted
26 * directory entry looks valid.  What we do is check the deleted entry
27 * and each successive entry to make sure that they all look valid and
28 * that the last deleted entry ends at the beginning of the next
29 * undeleted entry.  Returns 1 if the deleted entry looks valid, zero
30 * if not valid.
31 */
32static int ext2fs_validate_entry(char *buf, int offset, int final_offset)
33{
34    struct ext2_dir_entry *dirent;
35
36    while (offset < final_offset) {
37        dirent = (struct ext2_dir_entry *)(buf + offset);
38        offset += dirent->rec_len;
39        if ((dirent->rec_len < 8) ||
40            ((dirent->rec_len % 4) != 0) ||
41            (((dirent->name_len & 0xFF)+8) > dirent->rec_len))
42            return 0;
43    }
44    return (offset == final_offset);
45}
46
47errcode_t ext2fs_dir_iterate2(ext2_filsys fs,
48                  ext2_ino_t dir,
49                  int flags,
50                  char *block_buf,
51                  int (*func)(ext2_ino_t    dir,
52                      int       entry,
53                      struct ext2_dir_entry *dirent,
54                      int   offset,
55                      int   blocksize,
56                      char  *buf,
57                      void  *priv_data),
58                  void *priv_data)
59{
60    struct      dir_context ctx;
61    errcode_t   retval;
62
63    EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
64
65    retval = ext2fs_check_directory(fs, dir);
66    if (retval)
67        return retval;
68
69    ctx.dir = dir;
70    ctx.flags = flags;
71    if (block_buf)
72        ctx.buf = block_buf;
73    else {
74        retval = ext2fs_get_mem(fs->blocksize, &ctx.buf);
75        if (retval)
76            return retval;
77    }
78    ctx.func = func;
79    ctx.priv_data = priv_data;
80    ctx.errcode = 0;
81    retval = ext2fs_block_iterate2(fs, dir, 0, 0,
82                       ext2fs_process_dir_block, &ctx);
83    if (!block_buf)
84        ext2fs_free_mem(&ctx.buf);
85    if (retval)
86        return retval;
87    return ctx.errcode;
88}
89
90struct xlate {
91    int (*func)(struct ext2_dir_entry *dirent,
92            int     offset,
93            int     blocksize,
94            char    *buf,
95            void    *priv_data);
96    void *real_private;
97};
98
99static int xlate_func(ext2_ino_t dir EXT2FS_ATTR((unused)),
100              int entry EXT2FS_ATTR((unused)),
101              struct ext2_dir_entry *dirent, int offset,
102              int blocksize, char *buf, void *priv_data)
103{
104    struct xlate *xl = (struct xlate *) priv_data;
105
106    return (*xl->func)(dirent, offset, blocksize, buf, xl->real_private);
107}
108
109extern errcode_t ext2fs_dir_iterate(ext2_filsys fs,
110                  ext2_ino_t dir,
111                  int flags,
112                  char *block_buf,
113                  int (*func)(struct ext2_dir_entry *dirent,
114                      int   offset,
115                      int   blocksize,
116                      char  *buf,
117                      void  *priv_data),
118                  void *priv_data)
119{
120    struct xlate xl;
121
122    xl.real_private = priv_data;
123    xl.func = func;
124
125    return ext2fs_dir_iterate2(fs, dir, flags, block_buf,
126                   xlate_func, &xl);
127}
128
129
130/*
131 * Helper function which is private to this module.  Used by
132 * ext2fs_dir_iterate() and ext2fs_dblist_dir_iterate()
133 */
134int ext2fs_process_dir_block(ext2_filsys fs,
135                 blk_t  *blocknr,
136                 e2_blkcnt_t blockcnt,
137                 blk_t  ref_block EXT2FS_ATTR((unused)),
138                 int    ref_offset EXT2FS_ATTR((unused)),
139                 void   *priv_data)
140{
141    struct dir_context *ctx = (struct dir_context *) priv_data;
142    unsigned int    offset = 0;
143    unsigned int    next_real_entry = 0;
144    int     ret = 0;
145    int     changed = 0;
146    int     do_abort = 0;
147    int     entry, size;
148    struct ext2_dir_entry *dirent;
149
150    if (blockcnt < 0)
151        return 0;
152
153    entry = blockcnt ? DIRENT_OTHER_FILE : DIRENT_DOT_FILE;
154
155    ctx->errcode = ext2fs_read_dir_block(fs, *blocknr, ctx->buf);
156    if (ctx->errcode)
157        return BLOCK_ABORT;
158
159    while (offset < fs->blocksize) {
160        dirent = (struct ext2_dir_entry *) (ctx->buf + offset);
161        if (((offset + dirent->rec_len) > fs->blocksize) ||
162            (dirent->rec_len < 8) ||
163            ((dirent->rec_len % 4) != 0) ||
164            (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) {
165            ctx->errcode = EXT2_ET_DIR_CORRUPTED;
166            return BLOCK_ABORT;
167        }
168        if (!dirent->inode &&
169            !(ctx->flags & DIRENT_FLAG_INCLUDE_EMPTY))
170            goto next;
171
172        ret = (ctx->func)(ctx->dir,
173                  (next_real_entry > offset) ?
174                  DIRENT_DELETED_FILE : entry,
175                  dirent, offset,
176                  fs->blocksize, ctx->buf,
177                  ctx->priv_data);
178        if (entry < DIRENT_OTHER_FILE)
179            entry++;
180
181        if (ret & DIRENT_CHANGED)
182            changed++;
183        if (ret & DIRENT_ABORT) {
184            do_abort++;
185            break;
186        }
187next:
188        if (next_real_entry == offset)
189            next_real_entry += dirent->rec_len;
190
191        if (ctx->flags & DIRENT_FLAG_INCLUDE_REMOVED) {
192            size = ((dirent->name_len & 0xFF) + 11) & ~3;
193
194            if (dirent->rec_len != size)  {
195                unsigned int final_offset;
196
197                final_offset = offset + dirent->rec_len;
198                offset += size;
199                while (offset < final_offset &&
200                       !ext2fs_validate_entry(ctx->buf,
201                                  offset,
202                                  final_offset))
203                    offset += 4;
204                continue;
205            }
206        }
207        offset += dirent->rec_len;
208    }
209
210    if (changed) {
211        ctx->errcode = ext2fs_write_dir_block(fs, *blocknr, ctx->buf);
212        if (ctx->errcode)
213            return BLOCK_ABORT;
214    }
215    if (do_abort)
216        return BLOCK_ABORT;
217    return 0;
218}
219
Note: See TracBrowser for help on using the repository browser.