2 * dirinfo.c --- maintains the directory information table for e2fsck.
4 * Copyright (C) 1993 Theodore Ts'o. This file may be redistributed
5 * under the terms of the GNU Public License.
14 #include "uuid/uuid.h"
16 #include "ext2fs/ext2fs.h"
17 #include <ext2fs/tdb.h>
22 struct dir_info
*array
;
23 struct dir_info
*last_lookup
;
30 struct dir_info_iter
{
38 ext2_ino_t dotdot
; /* Parent according to '..' */
39 ext2_ino_t parent
; /* Parent according to treewalk */
43 static void e2fsck_put_dir_info(e2fsck_t ctx
, struct dir_info
*dir
);
46 static void setup_tdb(e2fsck_t ctx
, ext2_ino_t num_dirs
)
48 struct dir_info_db
*db
= ctx
->dir_info
;
52 char *tdb_dir
, uuid
[40];
55 profile_get_string(ctx
->profile
, "scratch_files", "directory", 0, 0,
57 profile_get_uint(ctx
->profile
, "scratch_files",
58 "numdirs_threshold", 0, 0, &threshold
);
59 profile_get_boolean(ctx
->profile
, "scratch_files",
60 "dirinfo", 0, 1, &enable
);
62 if (!enable
|| !tdb_dir
|| access(tdb_dir
, W_OK
) ||
63 (threshold
&& num_dirs
<= threshold
))
66 retval
= ext2fs_get_mem(strlen(tdb_dir
) + 64, &db
->tdb_fn
);
70 uuid_unparse(ctx
->fs
->super
->s_uuid
, uuid
);
71 sprintf(db
->tdb_fn
, "%s/%s-dirinfo-XXXXXX", tdb_dir
, uuid
);
72 save_umask
= umask(077);
73 fd
= mkstemp(db
->tdb_fn
);
81 num_dirs
= 99991; /* largest 5 digit prime */
83 db
->tdb
= tdb_open(db
->tdb_fn
, num_dirs
, TDB_NOLOCK
| TDB_NOSYNC
,
84 O_RDWR
| O_CREAT
| O_TRUNC
, 0600);
89 static void setup_db(e2fsck_t ctx
)
91 struct dir_info_db
*db
;
95 db
= (struct dir_info_db
*)
96 e2fsck_allocate_memory(ctx
, sizeof(struct dir_info_db
),
98 db
->count
= db
->size
= 0;
103 retval
= ext2fs_get_num_dirs(ctx
->fs
, &num_dirs
);
105 num_dirs
= 1024; /* Guess */
108 setup_tdb(ctx
, num_dirs
);
112 printf("Note: using tdb!\n");
118 db
->size
= num_dirs
+ 10;
119 db
->array
= (struct dir_info
*)
120 e2fsck_allocate_memory(ctx
, db
->size
121 * sizeof (struct dir_info
),
126 * This subroutine is called during pass1 to create a directory info
127 * entry. During pass1, the passed-in parent is 0; it will get filled
130 void e2fsck_add_dir_info(e2fsck_t ctx
, ext2_ino_t ino
, ext2_ino_t parent
)
132 struct dir_info
*dir
, *old_array
;
135 unsigned long old_size
;
138 printf("add_dir_info for inode (%u, %u)...\n", ino
, parent
);
143 if (ctx
->dir_info
->count
>= ctx
->dir_info
->size
) {
144 old_size
= ctx
->dir_info
->size
* sizeof(struct dir_info
);
145 ctx
->dir_info
->size
+= 10;
146 old_array
= ctx
->dir_info
->array
;
147 retval
= ext2fs_resize_mem(old_size
, ctx
->dir_info
->size
*
148 sizeof(struct dir_info
),
149 &ctx
->dir_info
->array
);
151 fprintf(stderr
, "Couldn't reallocate dir_info "
152 "structure to %u entries\n",
153 ctx
->dir_info
->size
);
155 ctx
->dir_info
->size
-= 10;
158 if (old_array
!= ctx
->dir_info
->array
)
159 ctx
->dir_info
->last_lookup
= NULL
;
163 if (ctx
->dir_info
->tdb
) {
169 e2fsck_put_dir_info(ctx
, &ent
);
175 * Normally, add_dir_info is called with each inode in
176 * sequential order; but once in a while (like when pass 3
177 * needs to recreate the root directory or lost+found
178 * directory) it is called out of order. In those cases, we
179 * need to move the dir_info entries down to make room, since
180 * the dir_info array needs to be sorted by inode number for
181 * get_dir_info()'s sake.
183 if (ctx
->dir_info
->count
&&
184 ctx
->dir_info
->array
[ctx
->dir_info
->count
-1].ino
>= ino
) {
185 for (i
= ctx
->dir_info
->count
-1; i
> 0; i
--)
186 if (ctx
->dir_info
->array
[i
-1].ino
< ino
)
188 dir
= &ctx
->dir_info
->array
[i
];
190 for (j
= ctx
->dir_info
->count
++; j
> i
; j
--)
191 ctx
->dir_info
->array
[j
] = ctx
->dir_info
->array
[j
-1];
193 dir
= &ctx
->dir_info
->array
[ctx
->dir_info
->count
++];
196 dir
->dotdot
= parent
;
197 dir
->parent
= parent
;
201 * get_dir_info() --- given an inode number, try to find the directory
202 * information entry for it.
204 static struct dir_info
*e2fsck_get_dir_info(e2fsck_t ctx
, ext2_ino_t ino
)
206 struct dir_info_db
*db
= ctx
->dir_info
;
207 ext2_ino_t low
, high
, mid
;
213 printf("e2fsck_get_dir_info %u...", ino
);
218 static struct dir_info ret_dir_info
;
220 struct dir_info_ent
*buf
;
222 key
.dptr
= (unsigned char *) &ino
;
223 key
.dsize
= sizeof(ext2_ino_t
);
225 data
= tdb_fetch(db
->tdb
, key
);
227 if (tdb_error(db
->tdb
) != TDB_ERR_NOEXIST
)
228 printf("fetch failed: %s\n",
229 tdb_errorstr(db
->tdb
));
233 buf
= (struct dir_info_ent
*) data
.dptr
;
234 ret_dir_info
.ino
= ino
;
235 ret_dir_info
.dotdot
= buf
->dotdot
;
236 ret_dir_info
.parent
= buf
->parent
;
238 printf("(%u,%u,%u)\n", ino
, buf
->dotdot
, buf
->parent
);
241 return &ret_dir_info
;
245 if (db
->last_lookup
&& db
->last_lookup
->ino
== ino
)
246 return db
->last_lookup
;
249 high
= ctx
->dir_info
->count
- 1;
250 if (ino
== ctx
->dir_info
->array
[low
].ino
) {
252 printf("(%u,%u,%u)\n", ino
,
253 ctx
->dir_info
->array
[low
].dotdot
,
254 ctx
->dir_info
->array
[low
].parent
);
256 return &ctx
->dir_info
->array
[low
];
258 if (ino
== ctx
->dir_info
->array
[high
].ino
) {
260 printf("(%u,%u,%u)\n", ino
,
261 ctx
->dir_info
->array
[high
].dotdot
,
262 ctx
->dir_info
->array
[high
].parent
);
264 return &ctx
->dir_info
->array
[high
];
268 /* sum may overflow, but result will fit into mid again */
269 mid
= (unsigned long long)(low
+ high
) / 2;
270 if (mid
== low
|| mid
== high
)
272 if (ino
== ctx
->dir_info
->array
[mid
].ino
) {
274 printf("(%u,%u,%u)\n", ino
,
275 ctx
->dir_info
->array
[mid
].dotdot
,
276 ctx
->dir_info
->array
[mid
].parent
);
278 return &ctx
->dir_info
->array
[mid
];
280 if (ino
< ctx
->dir_info
->array
[mid
].ino
)
288 static void e2fsck_put_dir_info(e2fsck_t ctx EXT2FS_NO_TDB_UNUSED
,
289 struct dir_info
*dir EXT2FS_NO_TDB_UNUSED
)
292 struct dir_info_db
*db
= ctx
->dir_info
;
293 struct dir_info_ent buf
;
298 printf("e2fsck_put_dir_info (%u, %u, %u)...", dir
->ino
, dir
->dotdot
,
306 buf
.parent
= dir
->parent
;
307 buf
.dotdot
= dir
->dotdot
;
309 key
.dptr
= (unsigned char *) &dir
->ino
;
310 key
.dsize
= sizeof(ext2_ino_t
);
311 data
.dptr
= (unsigned char *) &buf
;
312 data
.dsize
= sizeof(buf
);
314 if (tdb_store(db
->tdb
, key
, data
, TDB_REPLACE
) == -1) {
315 printf("store failed: %s\n", tdb_errorstr(db
->tdb
));
321 * Free the dir_info structure when it isn't needed any more.
323 void e2fsck_free_dir_info(e2fsck_t ctx
)
327 if (ctx
->dir_info
->tdb
)
328 tdb_close(ctx
->dir_info
->tdb
);
329 if (ctx
->dir_info
->tdb_fn
) {
330 if (unlink(ctx
->dir_info
->tdb_fn
) < 0)
331 com_err("e2fsck_free_dir_info", errno
,
332 _("while freeing dir_info tdb file"));
333 ext2fs_free_mem(&ctx
->dir_info
->tdb_fn
);
336 if (ctx
->dir_info
->array
)
337 ext2fs_free_mem(&ctx
->dir_info
->array
);
338 ctx
->dir_info
->array
= 0;
339 ctx
->dir_info
->size
= 0;
340 ctx
->dir_info
->count
= 0;
341 ext2fs_free_mem(&ctx
->dir_info
);
347 * Return the count of number of directories in the dir_info structure
349 int e2fsck_get_num_dirinfo(e2fsck_t ctx
)
351 return ctx
->dir_info
? ctx
->dir_info
->count
: 0;
354 struct dir_info_iter
*e2fsck_dir_info_iter_begin(e2fsck_t ctx
)
356 struct dir_info_iter
*iter
;
358 iter
= e2fsck_allocate_memory(ctx
, sizeof(struct dir_info_iter
),
359 "dir_info iterator");
362 if (ctx
->dir_info
->tdb
)
363 iter
->tdb_iter
= tdb_firstkey(ctx
->dir_info
->tdb
);
369 void e2fsck_dir_info_iter_end(e2fsck_t ctx
EXT2FS_ATTR((unused
)),
370 struct dir_info_iter
*iter
)
373 free(iter
->tdb_iter
.dptr
);
375 ext2fs_free_mem(&iter
);
379 * A simple interator function
381 struct dir_info
*e2fsck_dir_info_iter(e2fsck_t ctx
, struct dir_info_iter
*iter
)
383 if (!ctx
->dir_info
|| !iter
)
387 if (ctx
->dir_info
->tdb
) {
388 static struct dir_info ret_dir_info
;
389 struct dir_info_ent
*buf
;
392 if (iter
->tdb_iter
.dptr
== 0)
394 key
= iter
->tdb_iter
;
395 data
= tdb_fetch(ctx
->dir_info
->tdb
, key
);
397 printf("iter fetch failed: %s\n",
398 tdb_errorstr(ctx
->dir_info
->tdb
));
401 buf
= (struct dir_info_ent
*) data
.dptr
;
402 ret_dir_info
.ino
= *((ext2_ino_t
*) iter
->tdb_iter
.dptr
);
403 ret_dir_info
.dotdot
= buf
->dotdot
;
404 ret_dir_info
.parent
= buf
->parent
;
405 iter
->tdb_iter
= tdb_nextkey(ctx
->dir_info
->tdb
, key
);
408 return &ret_dir_info
;
412 if (iter
->i
>= ctx
->dir_info
->count
)
416 printf("iter(%u, %u, %u)...", ctx
->dir_info
->array
[iter
->i
].ino
,
417 ctx
->dir_info
->array
[iter
->i
].dotdot
,
418 ctx
->dir_info
->array
[iter
->i
].parent
);
420 ctx
->dir_info
->last_lookup
= ctx
->dir_info
->array
+ iter
->i
++;
421 return(ctx
->dir_info
->last_lookup
);
425 * This function only sets the parent pointer, and requires that
426 * dirinfo structure has already been created.
428 int e2fsck_dir_info_set_parent(e2fsck_t ctx
, ext2_ino_t ino
,
433 p
= e2fsck_get_dir_info(ctx
, ino
);
437 e2fsck_put_dir_info(ctx
, p
);
442 * This function only sets the dot dot pointer, and requires that
443 * dirinfo structure has already been created.
445 int e2fsck_dir_info_set_dotdot(e2fsck_t ctx
, ext2_ino_t ino
,
450 p
= e2fsck_get_dir_info(ctx
, ino
);
454 e2fsck_put_dir_info(ctx
, p
);
459 * This function only sets the parent pointer, and requires that
460 * dirinfo structure has already been created.
462 int e2fsck_dir_info_get_parent(e2fsck_t ctx
, ext2_ino_t ino
,
467 p
= e2fsck_get_dir_info(ctx
, ino
);
475 * This function only sets the dot dot pointer, and requires that
476 * dirinfo structure has already been created.
478 int e2fsck_dir_info_get_dotdot(e2fsck_t ctx
, ext2_ino_t ino
,
483 p
= e2fsck_get_dir_info(ctx
, ino
);