dir_iterate.c revision 31dbecd482405e0d3a67eb58e1a1c8cb9f2ad83e
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->name_len & 0xFF)+8) > dirent->rec_len)) { 104 ctx->errcode = EXT2_ET_DIR_CORRUPTED; 105 return BLOCK_ABORT; 106 } 107 if (!dirent->inode && 108 !(ctx->flags & DIRENT_FLAG_INCLUDE_EMPTY)) 109 goto next; 110 111 if (ctx->func) 112 ret = (ctx->func)(dirent, offset, fs->blocksize, 113 ctx->buf, ctx->priv_data); 114 else if (ctx->func2) { 115 ret = (ctx->func2)(ctx->dir, entry, dirent, offset, 116 fs->blocksize, ctx->buf, 117 ctx->priv_data); 118 if (entry < DIRENT_OTHER_FILE) 119 entry++; 120 } 121 122 if (ret & DIRENT_CHANGED) 123 changed++; 124 if (ret & DIRENT_ABORT) { 125 do_abort++; 126 break; 127 } 128next: 129 offset += dirent->rec_len; 130 } 131 132 if (changed) { 133 ctx->errcode = ext2fs_write_dir_block(fs, *blocknr, ctx->buf); 134 if (ctx->errcode) 135 return BLOCK_ABORT; 136 } 137 if (do_abort) 138 return BLOCK_ABORT; 139 return 0; 140} 141 142