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
;
49 unsigned int threshold
;
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 (%lu, %lu)...\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 %d 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
;
213 printf("e2fsck_get_dir_info %d...", 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("(%d,%d,%d)\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("(%d,%d,%d)\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("(%d,%d,%d)\n", ino
,
261 ctx
->dir_info
->array
[high
].dotdot
,
262 ctx
->dir_info
->array
[high
].parent
);
264 return &ctx
->dir_info
->array
[high
];
269 if (mid
== low
|| mid
== high
)
271 if (ino
== ctx
->dir_info
->array
[mid
].ino
) {
273 printf("(%d,%d,%d)\n", ino
,
274 ctx
->dir_info
->array
[mid
].dotdot
,
275 ctx
->dir_info
->array
[mid
].parent
);
277 return &ctx
->dir_info
->array
[mid
];
279 if (ino
< ctx
->dir_info
->array
[mid
].ino
)
287 static void e2fsck_put_dir_info(e2fsck_t ctx EXT2FS_NO_TDB_UNUSED
,
288 struct dir_info
*dir EXT2FS_NO_TDB_UNUSED
)
291 struct dir_info_db
*db
= ctx
->dir_info
;
292 struct dir_info_ent buf
;
297 printf("e2fsck_put_dir_info (%d, %d, %d)...", dir
->ino
, dir
->dotdot
,
305 buf
.parent
= dir
->parent
;
306 buf
.dotdot
= dir
->dotdot
;
308 key
.dptr
= (unsigned char *) &dir
->ino
;
309 key
.dsize
= sizeof(ext2_ino_t
);
310 data
.dptr
= (unsigned char *) &buf
;
311 data
.dsize
= sizeof(buf
);
313 if (tdb_store(db
->tdb
, key
, data
, TDB_REPLACE
) == -1) {
314 printf("store failed: %s\n", tdb_errorstr(db
->tdb
));
320 * Free the dir_info structure when it isn't needed any more.
322 void e2fsck_free_dir_info(e2fsck_t ctx
)
326 if (ctx
->dir_info
->tdb
)
327 tdb_close(ctx
->dir_info
->tdb
);
328 if (ctx
->dir_info
->tdb_fn
) {
329 if (unlink(ctx
->dir_info
->tdb_fn
) < 0)
330 com_err("e2fsck_free_dir_info", errno
,
331 _("while freeing dir_info tdb file"));
332 free(ctx
->dir_info
->tdb_fn
);
335 if (ctx
->dir_info
->array
)
336 ext2fs_free_mem(&ctx
->dir_info
->array
);
337 ctx
->dir_info
->array
= 0;
338 ctx
->dir_info
->size
= 0;
339 ctx
->dir_info
->count
= 0;
340 ext2fs_free_mem(&ctx
->dir_info
);
346 * Return the count of number of directories in the dir_info structure
348 int e2fsck_get_num_dirinfo(e2fsck_t ctx
)
350 return ctx
->dir_info
? ctx
->dir_info
->count
: 0;
353 struct dir_info_iter
*e2fsck_dir_info_iter_begin(e2fsck_t ctx
)
355 struct dir_info_iter
*iter
;
357 iter
= e2fsck_allocate_memory(ctx
, sizeof(struct dir_info_iter
),
358 "dir_info iterator");
361 if (ctx
->dir_info
->tdb
)
362 iter
->tdb_iter
= tdb_firstkey(ctx
->dir_info
->tdb
);
368 void e2fsck_dir_info_iter_end(e2fsck_t ctx
EXT2FS_ATTR((unused
)),
369 struct dir_info_iter
*iter
)
372 free(iter
->tdb_iter
.dptr
);
374 ext2fs_free_mem(&iter
);
378 * A simple interator function
380 struct dir_info
*e2fsck_dir_info_iter(e2fsck_t ctx
, struct dir_info_iter
*iter
)
382 if (!ctx
->dir_info
|| !iter
)
386 if (ctx
->dir_info
->tdb
) {
387 static struct dir_info ret_dir_info
;
388 struct dir_info_ent
*buf
;
391 if (iter
->tdb_iter
.dptr
== 0)
393 key
= iter
->tdb_iter
;
394 data
= tdb_fetch(ctx
->dir_info
->tdb
, key
);
396 printf("iter fetch failed: %s\n",
397 tdb_errorstr(ctx
->dir_info
->tdb
));
400 buf
= (struct dir_info_ent
*) data
.dptr
;
401 ret_dir_info
.ino
= *((ext2_ino_t
*) iter
->tdb_iter
.dptr
);
402 ret_dir_info
.dotdot
= buf
->dotdot
;
403 ret_dir_info
.parent
= buf
->parent
;
404 iter
->tdb_iter
= tdb_nextkey(ctx
->dir_info
->tdb
, key
);
407 return &ret_dir_info
;
411 if (iter
->i
>= ctx
->dir_info
->count
)
415 printf("iter(%d, %d, %d)...", ctx
->dir_info
->array
[iter
->i
].ino
,
416 ctx
->dir_info
->array
[iter
->i
].dotdot
,
417 ctx
->dir_info
->array
[iter
->i
].parent
);
419 ctx
->dir_info
->last_lookup
= ctx
->dir_info
->array
+ iter
->i
++;
420 return(ctx
->dir_info
->last_lookup
);
424 * This function only sets the parent pointer, and requires that
425 * dirinfo structure has already been created.
427 int e2fsck_dir_info_set_parent(e2fsck_t ctx
, ext2_ino_t ino
,
432 p
= e2fsck_get_dir_info(ctx
, ino
);
436 e2fsck_put_dir_info(ctx
, p
);
441 * This function only sets the dot dot pointer, and requires that
442 * dirinfo structure has already been created.
444 int e2fsck_dir_info_set_dotdot(e2fsck_t ctx
, ext2_ino_t ino
,
449 p
= e2fsck_get_dir_info(ctx
, ino
);
453 e2fsck_put_dir_info(ctx
, p
);
458 * This function only sets the parent pointer, and requires that
459 * dirinfo structure has already been created.
461 int e2fsck_dir_info_get_parent(e2fsck_t ctx
, ext2_ino_t ino
,
466 p
= e2fsck_get_dir_info(ctx
, ino
);
474 * This function only sets the dot dot pointer, and requires that
475 * dirinfo structure has already been created.
477 int e2fsck_dir_info_get_dotdot(e2fsck_t ctx
, ext2_ino_t ino
,
482 p
= e2fsck_get_dir_info(ctx
, ino
);