]>
git.ipfire.org Git - thirdparty/e2fsprogs.git/blob - e2fsck/dirinfo.c
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/tdb.h>
21 struct dir_info
*array
;
22 struct dir_info
*last_lookup
;
27 struct dir_info_iter
{
33 ext2_ino_t dotdot
; /* Parent according to '..' */
34 ext2_ino_t parent
; /* Parent according to treewalk */
38 static void e2fsck_put_dir_info(e2fsck_t ctx
, struct dir_info
*dir
);
40 static void setup_tdb(e2fsck_t ctx
, ext2_ino_t num_dirs
)
42 struct dir_info_db
*db
= ctx
->dir_info
;
43 unsigned int threshold
;
46 char *tdb_dir
, uuid
[40];
49 profile_get_string(ctx
->profile
, "scratch_files", "directory", 0, 0,
51 profile_get_uint(ctx
->profile
, "scratch_files",
52 "numdirs_threshold", 0, 0, &threshold
);
53 profile_get_boolean(ctx
->profile
, "scratch_files",
54 "dirinfo", 0, 1, &enable
);
56 if (!enable
|| !tdb_dir
|| access(tdb_dir
, W_OK
) ||
57 (threshold
&& num_dirs
<= threshold
))
60 retval
= ext2fs_get_mem(strlen(tdb_dir
) + 64, &db
->tdb_fn
);
64 uuid_unparse(ctx
->fs
->super
->s_uuid
, uuid
);
65 sprintf(db
->tdb_fn
, "%s/%s-dirinfo-XXXXXX", tdb_dir
, uuid
);
66 save_umask
= umask(077);
67 fd
= mkstemp(db
->tdb_fn
);
75 num_dirs
= 99991; /* largest 5 digit prime */
77 db
->tdb
= tdb_open(db
->tdb_fn
, num_dirs
, TDB_NOLOCK
| TDB_NOSYNC
,
78 O_RDWR
| O_CREAT
| O_TRUNC
, 0600);
82 static void setup_db(e2fsck_t ctx
)
84 struct dir_info_db
*db
;
88 db
= (struct dir_info_db
*)
89 e2fsck_allocate_memory(ctx
, sizeof(struct dir_info_db
),
91 db
->count
= db
->size
= 0;
96 retval
= ext2fs_get_num_dirs(ctx
->fs
, &num_dirs
);
98 num_dirs
= 1024; /* Guess */
100 setup_tdb(ctx
, num_dirs
);
104 printf("Note: using tdb!\n");
109 db
->size
= num_dirs
+ 10;
110 db
->array
= (struct dir_info
*)
111 e2fsck_allocate_memory(ctx
, db
->size
112 * sizeof (struct dir_info
),
117 * This subroutine is called during pass1 to create a directory info
118 * entry. During pass1, the passed-in parent is 0; it will get filled
121 void e2fsck_add_dir_info(e2fsck_t ctx
, ext2_ino_t ino
, ext2_ino_t parent
)
123 struct dir_info_db
*db
;
124 struct dir_info
*dir
, ent
;
127 unsigned long old_size
;
130 printf("add_dir_info for inode (%lu, %lu)...\n", ino
, parent
);
136 if (ctx
->dir_info
->count
>= ctx
->dir_info
->size
) {
137 old_size
= ctx
->dir_info
->size
* sizeof(struct dir_info
);
138 ctx
->dir_info
->size
+= 10;
139 retval
= ext2fs_resize_mem(old_size
, ctx
->dir_info
->size
*
140 sizeof(struct dir_info
),
141 &ctx
->dir_info
->array
);
143 fprintf(stderr
, "Couldn't reallocate dir_info "
144 "structure to %d entries\n",
145 ctx
->dir_info
->size
);
147 ctx
->dir_info
->size
-= 10;
157 e2fsck_put_dir_info(ctx
, &ent
);
162 * Normally, add_dir_info is called with each inode in
163 * sequential order; but once in a while (like when pass 3
164 * needs to recreate the root directory or lost+found
165 * directory) it is called out of order. In those cases, we
166 * need to move the dir_info entries down to make room, since
167 * the dir_info array needs to be sorted by inode number for
168 * get_dir_info()'s sake.
170 if (ctx
->dir_info
->count
&&
171 ctx
->dir_info
->array
[ctx
->dir_info
->count
-1].ino
>= ino
) {
172 for (i
= ctx
->dir_info
->count
-1; i
> 0; i
--)
173 if (ctx
->dir_info
->array
[i
-1].ino
< ino
)
175 dir
= &ctx
->dir_info
->array
[i
];
177 for (j
= ctx
->dir_info
->count
++; j
> i
; j
--)
178 ctx
->dir_info
->array
[j
] = ctx
->dir_info
->array
[j
-1];
180 dir
= &ctx
->dir_info
->array
[ctx
->dir_info
->count
++];
183 dir
->dotdot
= parent
;
184 dir
->parent
= parent
;
188 * get_dir_info() --- given an inode number, try to find the directory
189 * information entry for it.
191 static struct dir_info
*e2fsck_get_dir_info(e2fsck_t ctx
, ext2_ino_t ino
)
193 struct dir_info_db
*db
= ctx
->dir_info
;
195 struct dir_info_ent
*buf
;
196 static struct dir_info ret_dir_info
;
202 printf("e2fsck_get_dir_info %d...", ino
);
208 key
.dptr
= (unsigned char *) &ino
;
209 key
.dsize
= sizeof(ext2_ino_t
);
211 data
= tdb_fetch(db
->tdb
, key
);
213 if (tdb_error(db
->tdb
) != TDB_ERR_NOEXIST
)
214 printf("fetch failed: %s\n",
215 tdb_errorstr(db
->tdb
));
219 buf
= (struct dir_info_ent
*) data
.dptr
;
220 ret_dir_info
.ino
= ino
;
221 ret_dir_info
.dotdot
= buf
->dotdot
;
222 ret_dir_info
.parent
= buf
->parent
;
224 printf("(%d,%d,%d)\n", ino
, buf
->dotdot
, buf
->parent
);
227 return &ret_dir_info
;
230 if (db
->last_lookup
&& db
->last_lookup
->ino
== ino
)
231 return db
->last_lookup
;
234 high
= ctx
->dir_info
->count
-1;
235 if (ino
== ctx
->dir_info
->array
[low
].ino
) {
237 printf("(%d,%d,%d)\n", ino
,
238 ctx
->dir_info
->array
[low
].dotdot
,
239 ctx
->dir_info
->array
[low
].parent
);
241 return &ctx
->dir_info
->array
[low
];
243 if (ino
== ctx
->dir_info
->array
[high
].ino
) {
245 printf("(%d,%d,%d)\n", ino
,
246 ctx
->dir_info
->array
[high
].dotdot
,
247 ctx
->dir_info
->array
[high
].parent
);
249 return &ctx
->dir_info
->array
[high
];
254 if (mid
== low
|| mid
== high
)
256 if (ino
== ctx
->dir_info
->array
[mid
].ino
) {
258 printf("(%d,%d,%d)\n", ino
,
259 ctx
->dir_info
->array
[mid
].dotdot
,
260 ctx
->dir_info
->array
[mid
].parent
);
262 return &ctx
->dir_info
->array
[mid
];
264 if (ino
< ctx
->dir_info
->array
[mid
].ino
)
272 static void e2fsck_put_dir_info(e2fsck_t ctx
, struct dir_info
*dir
)
274 struct dir_info_db
*db
= ctx
->dir_info
;
275 struct dir_info_ent buf
;
279 printf("e2fsck_put_dir_info (%d, %d, %d)...", dir
->ino
, dir
->dotdot
,
286 buf
.parent
= dir
->parent
;
287 buf
.dotdot
= dir
->dotdot
;
289 key
.dptr
= (unsigned char *) &dir
->ino
;
290 key
.dsize
= sizeof(ext2_ino_t
);
291 data
.dptr
= (unsigned char *) &buf
;
292 data
.dsize
= sizeof(buf
);
294 if (tdb_store(db
->tdb
, key
, data
, TDB_REPLACE
) == -1) {
295 printf("store failed: %s\n", tdb_errorstr(db
->tdb
));
301 * Free the dir_info structure when it isn't needed any more.
303 void e2fsck_free_dir_info(e2fsck_t ctx
)
306 if (ctx
->dir_info
->tdb
)
307 tdb_close(ctx
->dir_info
->tdb
);
308 if (ctx
->dir_info
->tdb_fn
) {
309 unlink(ctx
->dir_info
->tdb_fn
);
310 free(ctx
->dir_info
->tdb_fn
);
312 if (ctx
->dir_info
->array
)
313 ext2fs_free_mem(&ctx
->dir_info
->array
);
314 ctx
->dir_info
->array
= 0;
315 ctx
->dir_info
->size
= 0;
316 ctx
->dir_info
->count
= 0;
317 ext2fs_free_mem(&ctx
->dir_info
);
323 * Return the count of number of directories in the dir_info structure
325 int e2fsck_get_num_dirinfo(e2fsck_t ctx
)
327 return ctx
->dir_info
? ctx
->dir_info
->count
: 0;
330 struct dir_info_iter
*e2fsck_dir_info_iter_begin(e2fsck_t ctx
)
332 struct dir_info_iter
*iter
;
333 struct dir_info_db
*db
= ctx
->dir_info
;
335 iter
= e2fsck_allocate_memory(ctx
, sizeof(struct dir_info_iter
),
336 "dir_info iterator");
339 iter
->tdb_iter
= tdb_firstkey(db
->tdb
);
344 void e2fsck_dir_info_iter_end(e2fsck_t ctx
EXT2FS_ATTR((unused
)),
345 struct dir_info_iter
*iter
)
347 free(iter
->tdb_iter
.dptr
);
348 ext2fs_free_mem(&iter
);
352 * A simple interator function
354 struct dir_info
*e2fsck_dir_info_iter(e2fsck_t ctx
, struct dir_info_iter
*iter
)
357 struct dir_info_db
*db
= ctx
->dir_info
;
358 struct dir_info_ent
*buf
;
359 static struct dir_info ret_dir_info
;
361 if (!ctx
->dir_info
|| !iter
)
365 if (iter
->tdb_iter
.dptr
== 0)
367 key
= iter
->tdb_iter
;
368 data
= tdb_fetch(db
->tdb
, key
);
370 printf("iter fetch failed: %s\n",
371 tdb_errorstr(db
->tdb
));
374 buf
= (struct dir_info_ent
*) data
.dptr
;
375 ret_dir_info
.ino
= *((ext2_ino_t
*) iter
->tdb_iter
.dptr
);
376 ret_dir_info
.dotdot
= buf
->dotdot
;
377 ret_dir_info
.parent
= buf
->parent
;
378 iter
->tdb_iter
= tdb_nextkey(db
->tdb
, key
);
381 return &ret_dir_info
;
384 if (iter
->i
>= ctx
->dir_info
->count
)
388 printf("iter(%d, %d, %d)...", ctx
->dir_info
->array
[iter
->i
].ino
,
389 ctx
->dir_info
->array
[iter
->i
].dotdot
,
390 ctx
->dir_info
->array
[iter
->i
].parent
);
392 ctx
->dir_info
->last_lookup
= ctx
->dir_info
->array
+ iter
->i
++;
393 return(ctx
->dir_info
->last_lookup
);
397 * This function only sets the parent pointer, and requires that
398 * dirinfo structure has already been created.
400 int e2fsck_dir_info_set_parent(e2fsck_t ctx
, ext2_ino_t ino
,
405 p
= e2fsck_get_dir_info(ctx
, ino
);
409 e2fsck_put_dir_info(ctx
, p
);
414 * This function only sets the dot dot pointer, and requires that
415 * dirinfo structure has already been created.
417 int e2fsck_dir_info_set_dotdot(e2fsck_t ctx
, ext2_ino_t ino
,
422 p
= e2fsck_get_dir_info(ctx
, ino
);
426 e2fsck_put_dir_info(ctx
, p
);
431 * This function only sets the parent pointer, and requires that
432 * dirinfo structure has already been created.
434 int e2fsck_dir_info_get_parent(e2fsck_t ctx
, ext2_ino_t ino
,
439 p
= e2fsck_get_dir_info(ctx
, ino
);
447 * This function only sets the dot dot pointer, and requires that
448 * dirinfo structure has already been created.
450 int e2fsck_dir_info_get_dotdot(e2fsck_t ctx
, ext2_ino_t ino
,
455 p
= e2fsck_get_dir_info(ctx
, ino
);