dir_iterate.c revision 9f8046fc6dfc13eee2f5c363214e60b533872cac
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 24errcode_t ext2fs_dir_iterate(ext2_filsys fs, 25 ext2_ino_t dir, 26 int flags, 27 char *block_buf, 28 int (*func)(struct ext2_dir_entry *dirent, 29 int offset, 30 int blocksize, 31 char *buf, 32 void *priv_data), 33 void *priv_data) 34{ 35 struct dir_context ctx; 36 errcode_t retval; 37 38 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 39 40 retval = ext2fs_check_directory(fs, dir); 41 if (retval) 42 return retval; 43 44 ctx.dir = dir; 45 ctx.flags = flags; 46 if (block_buf) 47 ctx.buf = block_buf; 48 else { 49 retval = ext2fs_get_mem(fs->blocksize, (void **) &ctx.buf); 50 if (retval) 51 return retval; 52 } 53 ctx.func = func; 54 ctx.func2 = 0; 55 ctx.priv_data = priv_data; 56 ctx.errcode = 0; 57 retval = ext2fs_block_iterate2(fs, dir, 0, 0, 58 ext2fs_process_dir_block, &ctx); 59 if (!block_buf) 60 ext2fs_free_mem((void **) &ctx.buf); 61 if (retval) 62 return retval; 63 return ctx.errcode; 64} 65 66/* 67 * Helper function which is private to this module. Used by 68 * ext2fs_dir_iterate() and ext2fs_dblist_dir_iterate() 69 */ 70int ext2fs_process_dir_block(ext2_filsys fs, 71 blk_t *blocknr, 72 e2_blkcnt_t blockcnt, 73 blk_t ref_block, 74 int ref_offset, 75 void *priv_data) 76{ 77 struct dir_context *ctx = (struct dir_context *) priv_data; 78 int offset = 0; 79 int ret = 0; 80 int changed = 0; 81 int do_abort = 0; 82 int entry; 83 struct ext2_dir_entry *dirent; 84 85 if (blockcnt < 0) 86 return 0; 87 88 entry = blockcnt ? DIRENT_OTHER_FILE : DIRENT_DOT_FILE; 89 90 ctx->errcode = ext2fs_read_dir_block(fs, *blocknr, ctx->buf); 91 if (ctx->errcode) 92 return BLOCK_ABORT; 93 94 while (offset < fs->blocksize) { 95 dirent = (struct ext2_dir_entry *) (ctx->buf + offset); 96 if (((offset + dirent->rec_len) > fs->blocksize) || 97 (dirent->rec_len < 8) || 98 ((dirent->rec_len % 4) != 0) || 99 (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) { 100 ctx->errcode = EXT2_ET_DIR_CORRUPTED; 101 return BLOCK_ABORT; 102 } 103 if (!dirent->inode && 104 !(ctx->flags & DIRENT_FLAG_INCLUDE_EMPTY)) 105 goto next; 106 107 if (ctx->func) 108 ret = (ctx->func)(dirent, offset, fs->blocksize, 109 ctx->buf, ctx->priv_data); 110 else if (ctx->func2) { 111 ret = (ctx->func2)(ctx->dir, entry, dirent, offset, 112 fs->blocksize, ctx->buf, 113 ctx->priv_data); 114 if (entry < DIRENT_OTHER_FILE) 115 entry++; 116 } 117 118 if (ret & DIRENT_CHANGED) 119 changed++; 120 if (ret & DIRENT_ABORT) { 121 do_abort++; 122 break; 123 } 124next: 125 offset += dirent->rec_len; 126 } 127 128 if (changed) { 129 ctx->errcode = ext2fs_write_dir_block(fs, *blocknr, ctx->buf); 130 if (ctx->errcode) 131 return BLOCK_ABORT; 132 } 133 if (do_abort) 134 return BLOCK_ABORT; 135 return 0; 136} 137 138