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