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