dirinfo.c revision 86c627ec1136446409a0170d439e60c148e6eb48
1/*
2 * dirinfo.c --- maintains the directory information table for e2fsck.
3 *
4 * Copyright (C) 1993 Theodore Ts'o.  This file may be redistributed
5 * under the terms of the GNU Public License.
6 */
7
8#include "e2fsck.h"
9
10/*
11 * This subroutine is called during pass1 to create a directory info
12 * entry.  During pass1, the passed-in parent is 0; it will get filled
13 * in during pass2.
14 */
15void e2fsck_add_dir_info(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t parent)
16{
17	struct dir_info *dir;
18	int		i, j;
19	ext2_ino_t	num_dirs;
20	errcode_t	retval;
21	unsigned long	old_size;
22
23#if 0
24	printf("add_dir_info for inode %lu...\n", ino);
25#endif
26	if (!ctx->dir_info) {
27		ctx->dir_info_count = 0;
28		retval = ext2fs_get_num_dirs(ctx->fs, &num_dirs);
29		if (retval)
30			num_dirs = 1024;	/* Guess */
31		ctx->dir_info_size = num_dirs + 10;
32		ctx->dir_info  = (struct dir_info *)
33			e2fsck_allocate_memory(ctx, ctx->dir_info_size
34					       * sizeof (struct dir_info),
35					       "directory map");
36	}
37
38	if (ctx->dir_info_count >= ctx->dir_info_size) {
39		old_size = ctx->dir_info_size * sizeof(struct dir_info);
40		ctx->dir_info_size += 10;
41		retval = ext2fs_resize_mem(old_size, ctx->dir_info_size *
42					   sizeof(struct dir_info),
43					   (void **) &ctx->dir_info);
44		if (retval) {
45			ctx->dir_info_size -= 10;
46			return;
47		}
48	}
49
50	/*
51	 * Normally, add_dir_info is called with each inode in
52	 * sequential order; but once in a while (like when pass 3
53	 * needs to recreate the root directory or lost+found
54	 * directory) it is called out of order.  In those cases, we
55	 * need to move the dir_info entries down to make room, since
56	 * the dir_info array needs to be sorted by inode number for
57	 * get_dir_info()'s sake.
58	 */
59	if (ctx->dir_info_count &&
60	    ctx->dir_info[ctx->dir_info_count-1].ino >= ino) {
61		for (i = ctx->dir_info_count-1; i > 0; i--)
62			if (ctx->dir_info[i-1].ino < ino)
63				break;
64		dir = &ctx->dir_info[i];
65		if (dir->ino != ino)
66			for (j = ctx->dir_info_count++; j > i; j--)
67				ctx->dir_info[j] = ctx->dir_info[j-1];
68	} else
69		dir = &ctx->dir_info[ctx->dir_info_count++];
70
71	dir->ino = ino;
72	dir->dotdot = parent;
73	dir->parent = parent;
74}
75
76/*
77 * get_dir_info() --- given an inode number, try to find the directory
78 * information entry for it.
79 */
80struct dir_info *e2fsck_get_dir_info(e2fsck_t ctx, ext2_ino_t ino)
81{
82	int	low, high, mid;
83
84	low = 0;
85	high = ctx->dir_info_count-1;
86	if (!ctx->dir_info)
87		return 0;
88	if (ino == ctx->dir_info[low].ino)
89		return &ctx->dir_info[low];
90	if  (ino == ctx->dir_info[high].ino)
91		return &ctx->dir_info[high];
92
93	while (low < high) {
94		mid = (low+high)/2;
95		if (mid == low || mid == high)
96			break;
97		if (ino == ctx->dir_info[mid].ino)
98			return &ctx->dir_info[mid];
99		if (ino < ctx->dir_info[mid].ino)
100			high = mid;
101		else
102			low = mid;
103	}
104	return 0;
105}
106
107/*
108 * Free the dir_info structure when it isn't needed any more.
109 */
110void e2fsck_free_dir_info(e2fsck_t ctx)
111{
112	if (ctx->dir_info) {
113		ext2fs_free_mem((void **) &ctx->dir_info);
114		ctx->dir_info = 0;
115	}
116	ctx->dir_info_size = 0;
117	ctx->dir_info_count = 0;
118}
119
120/*
121 * Return the count of number of directories in the dir_info structure
122 */
123int e2fsck_get_num_dirinfo(e2fsck_t ctx)
124{
125	return ctx->dir_info_count;
126}
127
128/*
129 * A simple interator function
130 */
131struct dir_info *e2fsck_dir_info_iter(e2fsck_t ctx, int *control)
132{
133	if (*control >= ctx->dir_info_count)
134		return 0;
135
136	return(ctx->dir_info + (*control)++);
137}
138