blob: 3fecf23facaa690434f267a584697a65da33961f [file] [log] [blame]
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001/*
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>
Theodore Ts'o4cbe8af1997-08-10 23:07:40 +000014#if HAVE_UNISTD_H
Theodore Ts'o21c84b71997-04-29 16:15:03 +000015#include <unistd.h>
Theodore Ts'o4cbe8af1997-08-10 23:07:40 +000016#endif
Theodore Ts'o21c84b71997-04-29 16:15:03 +000017#if HAVE_ERRNO_H
18#include <errno.h>
19#endif
20
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000021#if EXT2_FLAT_INCLUDES
22#include "ext2_fs.h"
23#else
Theodore Ts'o21c84b71997-04-29 16:15:03 +000024#include <linux/ext2_fs.h>
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000025#endif
Theodore Ts'o21c84b71997-04-29 16:15:03 +000026
27#include "ext2fsP.h"
28
29errcode_t ext2fs_dir_iterate(ext2_filsys fs,
30 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,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000037 void *priv_data),
38 void *priv_data)
Theodore Ts'o21c84b71997-04-29 16:15:03 +000039{
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 {
Theodore Ts'o7b4e4531997-10-26 03:41:24 +000054 retval = ext2fs_get_mem(fs->blocksize, (void **) &ctx.buf);
55 if (retval)
56 return retval;
Theodore Ts'o21c84b71997-04-29 16:15:03 +000057 }
58 ctx.func = func;
59 ctx.func2 = 0;
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000060 ctx.priv_data = priv_data;
Theodore Ts'o21c84b71997-04-29 16:15:03 +000061 ctx.errcode = 0;
Theodore Ts'o36a43d61998-03-24 16:17:51 +000062 retval = ext2fs_block_iterate2(fs, dir, 0, 0,
63 ext2fs_process_dir_block, &ctx);
Theodore Ts'o21c84b71997-04-29 16:15:03 +000064 if (!block_buf)
Theodore Ts'o7b4e4531997-10-26 03:41:24 +000065 ext2fs_free_mem((void **) &ctx.buf);
Theodore Ts'o21c84b71997-04-29 16:15:03 +000066 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 */
Theodore Ts'o2eb374c1998-09-03 01:22:57 +000075int 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)
Theodore Ts'o21c84b71997-04-29 16:15:03 +000081{
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000082 struct dir_context *ctx = (struct dir_context *) priv_data;
Theodore Ts'o21c84b71997-04-29 16:15:03 +000083 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
Theodore Ts'o36a43d61998-03-24 16:17:51 +000093 entry = blockcnt ? DIRENT_OTHER_FILE : DIRENT_DOT_FILE;
94
Theodore Ts'o21c84b71997-04-29 16:15:03 +000095 ctx->errcode = ext2fs_read_dir_block(fs, *blocknr, ctx->buf);
96 if (ctx->errcode)
97 return BLOCK_ABORT;
98
Theodore Ts'o21c84b71997-04-29 16:15:03 +000099 while (offset < fs->blocksize) {
100 dirent = (struct ext2_dir_entry *) (ctx->buf + offset);
Theodore Ts'o813bbb21999-06-22 03:17:45 +0000101 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 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000107 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,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000113 ctx->buf, ctx->priv_data);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000114 else if (ctx->func2) {
115 ret = (ctx->func2)(ctx->dir, entry, dirent, offset,
116 fs->blocksize, ctx->buf,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +0000117 ctx->priv_data);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000118 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:
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000129 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