This patch just removes trailing whitespace. Signed-off-by: Jeff Mahoney <jeffm@suse.com>
1130 lines
26 KiB
C
1130 lines
26 KiB
C
/*
|
|
* Copyright 2000-2004 by Hans Reiser, licensing governed by
|
|
* reiserfsprogs/README
|
|
*/
|
|
|
|
#include "debugreiserfs.h"
|
|
#include <regex.h>
|
|
#include <obstack.h>
|
|
#include <search.h>
|
|
|
|
#define obstack_chunk_alloc malloc
|
|
#define obstack_chunk_free free
|
|
|
|
/* -n pattern scans the area (on-disk bitmap, or all the device or extern
|
|
bitmap) and looks for every name matching the pattern. All those names get
|
|
stored in 'name_store' and are indexed by name (name_index) and by a key
|
|
they point to (key_index) */
|
|
|
|
struct obstack name_store;
|
|
struct obstack item_store;
|
|
|
|
int saved_names;
|
|
int saved_items;
|
|
int skipped_names;
|
|
void *key_index;
|
|
void *name_index;
|
|
|
|
regex_t pattern;
|
|
|
|
struct saved_name {
|
|
unsigned int dirid; /* pointed object */
|
|
unsigned int objectid;
|
|
struct saved_name *first_name; /* pointer to name which points to the
|
|
same object and contains list of file
|
|
items */
|
|
|
|
unsigned int parent_dirid; /* parent directory */
|
|
unsigned int parent_objectid;
|
|
unsigned long block; /* where we saw the name for the first time */
|
|
unsigned short count; /* how many times the name appeared */
|
|
|
|
void *items;
|
|
struct saved_name *name_next; /* list of identical names */
|
|
|
|
unsigned short name_len;
|
|
char name[1];
|
|
};
|
|
|
|
/* attach item to every name in the list */
|
|
static void store_item(struct saved_name *name, struct buffer_head *bh,
|
|
struct item_head *ih, int pos)
|
|
{
|
|
struct saved_item *new;
|
|
void *vp;
|
|
struct saved_item *item_in;
|
|
|
|
new = obstack_alloc(&item_store, sizeof(struct saved_item));
|
|
new->si_ih = *ih;
|
|
new->si_block = bh->b_blocknr;
|
|
new->si_item_num = ih - B_N_PITEM_HEAD(bh, 0);
|
|
new->si_next = 0;
|
|
new->si_entry_pos = pos;
|
|
|
|
vp = tfind(new, &name->items, comp_keys);
|
|
if (vp) {
|
|
item_in = *(void **)vp;
|
|
/* add item to the end of list of items having this key */
|
|
while (1) {
|
|
if (!item_in->si_next) {
|
|
item_in->si_next = new;
|
|
break;
|
|
}
|
|
item_in = item_in->si_next;
|
|
}
|
|
} else
|
|
tsearch(new, &name->items, comp_keys);
|
|
|
|
saved_items++;
|
|
}
|
|
|
|
static int comp_names(const void *p1, const void *p2)
|
|
{
|
|
struct saved_name *name1, *name2;
|
|
|
|
name1 = (struct saved_name *)p1;
|
|
name2 = (struct saved_name *)p2;
|
|
|
|
return strcmp(name1->name, name2->name);
|
|
}
|
|
|
|
static int comp_pointed(const void *p1, const void *p2)
|
|
{
|
|
struct saved_name *name1, *name2;
|
|
|
|
name1 = (struct saved_name *)p1;
|
|
name2 = (struct saved_name *)p2;
|
|
|
|
return comp_short_keys(&name1->dirid, &name2->dirid);
|
|
}
|
|
|
|
/* we consider name found only if it points to the same object and from the
|
|
same directory */
|
|
static int name_found(struct saved_name *name, struct saved_name **name_in)
|
|
{
|
|
void *vp;
|
|
struct saved_name *cur;
|
|
|
|
vp = tfind(name, &name_index, comp_names);
|
|
if (!vp) {
|
|
*name_in = 0;
|
|
return 0;
|
|
}
|
|
|
|
*name_in = *(void **)vp;
|
|
|
|
/* check every name in the list */
|
|
cur = *name_in;
|
|
while (cur) {
|
|
if (!not_of_one_file(&name->dirid, &cur->dirid) &&
|
|
!not_of_one_file(&name->parent_dirid, &cur->parent_dirid)) {
|
|
cur->count++;
|
|
*name_in = cur;
|
|
return 1;
|
|
}
|
|
cur = cur->name_next;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* add key name is pointing to to the index of keys. If there was already name
|
|
pointing to this key - add pointer to that name */
|
|
static void add_key(struct saved_name *name)
|
|
{
|
|
void *vp;
|
|
|
|
vp = tfind(name, &key_index, comp_pointed);
|
|
if (vp) {
|
|
/* */
|
|
name->first_name = *(void **)vp;
|
|
} else {
|
|
tsearch(name, &key_index, comp_pointed);
|
|
}
|
|
}
|
|
|
|
static void add_name(struct saved_name *name, struct saved_name *name_in)
|
|
{
|
|
if (name_in) {
|
|
/* add name to the end of list of identical names */
|
|
while (1) {
|
|
if (!name_in->name_next) {
|
|
name_in->name_next = name;
|
|
break;
|
|
}
|
|
name_in = name_in->name_next;
|
|
}
|
|
} else {
|
|
/* add name into name index */
|
|
tsearch(name, &name_index, comp_names);
|
|
}
|
|
}
|
|
|
|
/* take each name matching to a given pattern, */
|
|
static void scan_for_name(struct buffer_head *bh)
|
|
{
|
|
int i, j, i_num;
|
|
struct item_head *ih;
|
|
struct reiserfs_de_head *deh;
|
|
int namelen;
|
|
char *name;
|
|
struct saved_name *new, *name_in;
|
|
char ch;
|
|
int retval;
|
|
int min_entry_size = 1;
|
|
int ih_entry_count = 0;
|
|
|
|
ih = B_N_PITEM_HEAD(bh, 0);
|
|
i_num = leaf_item_number_estimate(bh);
|
|
for (i = 0; i < i_num; i++, ih++) {
|
|
if (!is_direntry_ih(ih))
|
|
continue;
|
|
if (is_it_bad_item(fs, ih, B_I_PITEM(bh, ih), 0, 1))
|
|
continue;
|
|
|
|
deh = B_I_DEH(bh, ih);
|
|
|
|
if ((get_ih_entry_count(ih) >
|
|
(get_ih_item_len(ih) / (DEH_SIZE + min_entry_size)))
|
|
|| (get_ih_entry_count(ih) == 0))
|
|
ih_entry_count =
|
|
get_ih_item_len(ih) / (DEH_SIZE + min_entry_size);
|
|
else
|
|
ih_entry_count = get_ih_entry_count(ih);
|
|
|
|
for (j = 0; j < ih_entry_count; j++, deh++) {
|
|
name = name_in_entry(deh, j);
|
|
namelen = name_in_entry_length(ih, deh, j);
|
|
ch = name[namelen];
|
|
name[namelen] = 0;
|
|
retval = regexec(&pattern, name, 0, NULL, 0);
|
|
name[namelen] = ch;
|
|
if (retval != 0)
|
|
continue;
|
|
|
|
/* name matching given pattern found */
|
|
|
|
new =
|
|
obstack_alloc(&name_store,
|
|
sizeof(struct saved_name) + namelen);
|
|
|
|
/* pointed object */
|
|
new->dirid = get_deh_dirid(deh);
|
|
new->objectid = get_deh_objectid(deh);
|
|
|
|
/* pointer to first name which points the same key */
|
|
new->first_name = 0;
|
|
|
|
/* where this name is from */
|
|
new->parent_dirid = get_key_dirid(&ih->ih_key);
|
|
new->parent_objectid = get_key_objectid(&ih->ih_key);
|
|
new->block = bh->b_blocknr;
|
|
|
|
new->count = 1;
|
|
new->items = 0;
|
|
|
|
/* name */
|
|
new->name_len = namelen;
|
|
memcpy(new->name, name, namelen);
|
|
new->name[namelen] = 0;
|
|
new->name_next = 0;
|
|
|
|
/*
|
|
reiserfs_warning (stdout, "\n(%K):%s-->(%K) - ", &new->parent_dirid,
|
|
new->name, &new->dirid);
|
|
*/
|
|
if (name_found(new, &name_in)) {
|
|
/* there was already exactly this name */
|
|
obstack_free(&name_store, new);
|
|
continue;
|
|
}
|
|
|
|
saved_names++;
|
|
add_name(new, name_in);
|
|
add_key(new);
|
|
} /* for each entry */
|
|
} /* for each item */
|
|
|
|
return;
|
|
}
|
|
|
|
static struct saved_name *scan_for_key(struct reiserfs_key *key)
|
|
{
|
|
char *name;
|
|
struct saved_name *new, *name_in;
|
|
|
|
asprintf(&name, "%u_%u", get_key_dirid(key), get_key_objectid(key));
|
|
new =
|
|
obstack_alloc(&name_store,
|
|
sizeof(struct saved_name) + strlen(name));
|
|
|
|
/* pointed object */
|
|
new->dirid = get_key_dirid(key);
|
|
new->objectid = get_key_objectid(key);
|
|
|
|
/* pointer to first name which points the same key */
|
|
new->first_name = 0;
|
|
|
|
/* where this name is from */
|
|
|
|
new->parent_dirid = 0;
|
|
new->parent_objectid = 0;
|
|
new->block = 0;
|
|
new->count = 1;
|
|
new->items = 0;
|
|
|
|
/* name */
|
|
new->name_len = strlen(name);
|
|
memcpy(new->name, name, new->name_len);
|
|
new->name[new->name_len] = 0;
|
|
new->name_next = 0;
|
|
|
|
free(name);
|
|
|
|
if (name_found(new, &name_in)) {
|
|
/* there was already exactly this name */
|
|
obstack_free(&name_store, new);
|
|
return name_in;
|
|
}
|
|
|
|
saved_names++;
|
|
add_name(new, name_in);
|
|
|
|
return new;
|
|
}
|
|
|
|
static int comp_token_key(struct buffer_head *bh, struct item_head *ih,
|
|
struct reiserfs_key *key)
|
|
{
|
|
struct reiserfs_de_head *deh;
|
|
int j, ih_entry_count = 0;
|
|
int min_entry_size = 1;
|
|
|
|
if ((get_key_dirid(&ih->ih_key) == get_key_dirid(key) ||
|
|
get_key_dirid(key) == ~(__u32) 0) &&
|
|
(get_key_objectid(&ih->ih_key) == get_key_objectid(key) ||
|
|
get_key_objectid(key) == ~(__u32) 0))
|
|
return -1;
|
|
|
|
if (!is_direntry_ih(ih))
|
|
return 0;
|
|
|
|
deh = B_I_DEH(bh, ih);
|
|
|
|
if ((get_ih_entry_count(ih) >
|
|
(get_ih_item_len(ih) / (DEH_SIZE + min_entry_size)))
|
|
|| (get_ih_entry_count(ih) == 0))
|
|
ih_entry_count =
|
|
get_ih_item_len(ih) / (DEH_SIZE + min_entry_size);
|
|
else
|
|
ih_entry_count = get_ih_entry_count(ih);
|
|
|
|
for (j = 0; j < ih_entry_count; j++, deh++) {
|
|
if ((get_deh_dirid(deh) == get_key_dirid(key)
|
|
|| (int)get_key_dirid(key) == -1)
|
|
&& (get_deh_objectid(deh) == get_key_objectid(key)
|
|
|| (int)get_key_objectid(key) == -1)) {
|
|
return j;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* take every item, look for its key in the key index, if it is found - store
|
|
item in the sorted list of items of a file */
|
|
static void scan_items(struct buffer_head *bh, struct reiserfs_key *key)
|
|
{
|
|
int i, i_num, pos;
|
|
struct item_head *ih;
|
|
struct saved_name *name_in_store;
|
|
void *res;
|
|
|
|
ih = B_N_PITEM_HEAD(bh, 0);
|
|
i_num = leaf_item_number_estimate(bh);
|
|
for (i = 0; i < i_num; i++, ih++) {
|
|
if (key) {
|
|
if (!(pos = comp_token_key(bh, ih, key)))
|
|
continue;
|
|
|
|
name_in_store = scan_for_key(&ih->ih_key);
|
|
} else {
|
|
if (!
|
|
(res =
|
|
tfind(&ih->ih_key, &key_index, comp_pointed)))
|
|
continue;
|
|
|
|
/* name pointing to this key found */
|
|
name_in_store = *(struct saved_name **)res;
|
|
pos = -1;
|
|
}
|
|
|
|
store_item(name_in_store, bh, ih, pos);
|
|
}
|
|
}
|
|
|
|
/* FIXME: does not work for long files */
|
|
struct version {
|
|
int flag; /* direct or indirect */
|
|
int len;
|
|
__u32 from;
|
|
int count;
|
|
void *data;
|
|
};
|
|
|
|
struct tail {
|
|
__u32 offset;
|
|
int len;
|
|
char *data;
|
|
};
|
|
|
|
struct file_map {
|
|
int head_len; /* number of unfm pointers */
|
|
void *head;
|
|
|
|
int tail_nr; /* number of tails found */
|
|
struct tail *tails;
|
|
|
|
int version_nr;
|
|
void *versions; /* list of range versions */
|
|
};
|
|
|
|
struct file_map map;
|
|
|
|
static int have_to_append(struct item_head *ih)
|
|
{
|
|
loff_t off = get_offset(&ih->ih_key);
|
|
|
|
if (is_indirect_ih(ih)) {
|
|
if (map.head_len * fs->fs_blocksize + 1 <= off)
|
|
return 1;
|
|
return 0;
|
|
} else if (is_direct_ih(ih)) {
|
|
int i;
|
|
__u32 tail_start;
|
|
|
|
tail_start = (off & ~(fs->fs_blocksize - 1)) + 1;
|
|
|
|
// find correct tail first
|
|
for (i = 0; i < map.tail_nr; i++) {
|
|
if (map.tails[i].offset == tail_start) {
|
|
if (map.tails[i].offset + map.tails[i].len <=
|
|
off)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
}
|
|
// there was no this tail yet
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void do_append(struct item_head *ih, void *data)
|
|
{
|
|
int i;
|
|
int padd;
|
|
unsigned long long off = get_offset(&ih->ih_key);
|
|
|
|
if (is_indirect_ih(ih)) {
|
|
|
|
padd = (off - 1) / fs->fs_blocksize - map.head_len;
|
|
map.head =
|
|
realloc(map.head,
|
|
(map.head_len + padd + I_UNFM_NUM(ih)) * 4);
|
|
if (!map.head)
|
|
reiserfs_panic("realloc failed");
|
|
memset((char *)map.head + map.head_len * 4, 0, padd * 4);
|
|
memcpy((char *)map.head + (map.head_len + padd) * 4, data,
|
|
get_ih_item_len(ih));
|
|
map.head_len += (padd + I_UNFM_NUM(ih));
|
|
|
|
} else if (is_direct_ih(ih)) {
|
|
unsigned int tail_start, skip;
|
|
|
|
// find correct tail first
|
|
tail_start = (off & ~(fs->fs_blocksize - 1)) + 1;
|
|
skip = (off - 1) & (fs->fs_blocksize - 1);
|
|
for (i = 0; i < map.tail_nr; i++) {
|
|
if (map.tails[i].offset == tail_start) {
|
|
map.tails[i].data = realloc(map.tails[i].data,
|
|
off - tail_start +
|
|
get_ih_item_len
|
|
(ih));
|
|
if (!map.tails[i].data)
|
|
reiserfs_panic("realloc failed");
|
|
padd = skip - map.tails[i].len;
|
|
memset(map.tails[i].data + map.tails[i].len, 0,
|
|
padd);
|
|
memcpy(map.tails[i].data + map.tails[i].len +
|
|
padd, data, get_ih_item_len(ih));
|
|
map.tails[i].len +=
|
|
(padd + get_ih_item_len(ih));
|
|
return;
|
|
}
|
|
}
|
|
// allocate memory for new tail
|
|
map.tails =
|
|
realloc(map.tails, (map.tail_nr + 1) * sizeof(struct tail));
|
|
if (!map.tails)
|
|
reiserfs_panic("realloc failed");
|
|
|
|
map.tails[map.tail_nr].offset = off;
|
|
map.tails[map.tail_nr].len = skip + get_ih_item_len(ih);
|
|
map.tails[map.tail_nr].data =
|
|
malloc(map.tails[map.tail_nr].len);
|
|
memset(map.tails[map.tail_nr].data, 0, skip);
|
|
memcpy(map.tails[map.tail_nr].data + skip, data,
|
|
get_ih_item_len(ih));
|
|
map.tail_nr++;
|
|
}
|
|
}
|
|
|
|
// map contains
|
|
static void do_overwrite(struct item_head *ih, void *data)
|
|
{
|
|
unsigned long long off, skip;
|
|
int to_compare, to_append;
|
|
struct item_head tmp_ih;
|
|
char *p;
|
|
|
|
off = get_offset(&ih->ih_key);
|
|
|
|
if (is_indirect_ih(ih)) {
|
|
|
|
skip = (off - 1) / fs->fs_blocksize;
|
|
to_compare = (map.head_len - skip > I_UNFM_NUM(ih)) ?
|
|
I_UNFM_NUM(ih) : (map.head_len - skip);
|
|
to_append = I_UNFM_NUM(ih) - to_compare;
|
|
|
|
p = (char *)map.head + skip * 4;
|
|
|
|
if (memcmp(p, data, to_compare * 4))
|
|
reiserfs_warning(stderr,
|
|
"overwrite (indirect): %H contains different data\n",
|
|
ih);
|
|
|
|
if (to_append) {
|
|
tmp_ih = *ih;
|
|
set_ih_item_len(&tmp_ih,
|
|
get_ih_item_len(ih) - to_compare * 4);
|
|
set_offset(key_format(&ih->ih_key), &tmp_ih.ih_key,
|
|
off + to_compare * fs->fs_blocksize);
|
|
do_append(&tmp_ih, (char *)data + to_compare * 4);
|
|
}
|
|
|
|
} else if (is_direct_ih(ih)) {
|
|
unsigned int tail_start;
|
|
int i;
|
|
|
|
// find correct tail first
|
|
tail_start = (off & ~(fs->fs_blocksize - 1)) + 1;
|
|
for (i = 0; i < map.tail_nr; i++) {
|
|
if (map.tails[i].offset == tail_start) {
|
|
// ih is a part of this tail
|
|
skip = (off - 1) & (fs->fs_blocksize - 1);
|
|
to_compare =
|
|
(map.tails[i].len - skip >
|
|
get_ih_item_len(ih) ? get_ih_item_len(ih) :
|
|
map.tails[i].len - skip);
|
|
to_append = get_ih_item_len(ih) - to_compare;
|
|
|
|
p = (char *)map.tails[i].data + skip;
|
|
|
|
if (memcmp(p, data, to_compare))
|
|
reiserfs_warning(stderr,
|
|
"overwrite (direct): %H contains different data\n",
|
|
ih);
|
|
|
|
if (to_append) {
|
|
tmp_ih = *ih;
|
|
set_ih_item_len(&tmp_ih,
|
|
get_ih_item_len(ih) -
|
|
to_compare);
|
|
set_offset(key_format(&ih->ih_key),
|
|
&tmp_ih.ih_key,
|
|
off + to_compare);
|
|
do_append(&tmp_ih,
|
|
(char *)data + to_compare);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
reiserfs_panic("no appropriate tail found");
|
|
}
|
|
}
|
|
|
|
static void map_one_item(struct saved_item *item)
|
|
{
|
|
struct buffer_head *bh;
|
|
struct item_head *ih;
|
|
void *data;
|
|
|
|
// read the block containing the item
|
|
bh = bread(fs->fs_dev, item->si_block, fs->fs_blocksize);
|
|
if (!bh) {
|
|
reiserfs_warning(stderr, "bread failed\n");
|
|
return;
|
|
}
|
|
|
|
ih = B_N_PITEM_HEAD(bh, item->si_item_num);
|
|
data = B_I_PITEM(bh, ih);
|
|
if (memcmp(&item->si_ih, ih, sizeof(*ih)))
|
|
reiserfs_panic("wrong item");
|
|
|
|
if (have_to_append(ih)) {
|
|
do_append(ih, data);
|
|
} else
|
|
do_overwrite(ih, data);
|
|
|
|
brelse(bh);
|
|
}
|
|
|
|
// flush map which is in variable map
|
|
static void flush_map(reiserfs_filsys_t *fs,
|
|
struct reiserfs_key *dir,
|
|
char *name, struct reiserfs_key *key)
|
|
{
|
|
int i;
|
|
FILE *fp;
|
|
__u32 v32;
|
|
|
|
if (!map_file(fs))
|
|
asprintf(&map_file(fs), "%s", ".map");
|
|
|
|
//reiserfs_warning (stderr, "Saving maps into %s\n", map_file (fs));
|
|
fp = fopen(map_file(fs), "a");
|
|
if (fp == 0) {
|
|
reiserfs_warning(stderr, "flush_map: fopen failed: %m");
|
|
return;
|
|
}
|
|
|
|
v32 = MAP_MAGIC;
|
|
fwrite(&v32, sizeof(v32), 1, fp);
|
|
|
|
// device name
|
|
v32 = strlen(device_name(fs)) + 1;
|
|
fwrite(&v32, sizeof(v32), 1, fp);
|
|
fwrite(device_name(fs), v32, 1, fp);
|
|
|
|
// name length and the name itself
|
|
v32 = strlen(name) + 1;
|
|
fwrite(&v32, sizeof(v32), 1, fp);
|
|
fwrite(name, v32, 1, fp);
|
|
|
|
// short key of a directory
|
|
fwrite(dir, SHORT_KEY_SIZE, 1, fp);
|
|
|
|
// short key of file
|
|
fwrite(key, SHORT_KEY_SIZE, 1, fp);
|
|
|
|
// list of data block pointers
|
|
fwrite(&map.head_len, sizeof(map.head_len), 1, fp);
|
|
fwrite(map.head, map.head_len * 4, 1, fp);
|
|
|
|
// find correct tail first
|
|
for (i = 0; i < map.tail_nr; i++) {
|
|
if (map.tails[i].offset == map.head_len * fs->fs_blocksize) {
|
|
// tail length and the tail itself
|
|
fwrite(&map.tails[i].len, sizeof(map.tails[i].len), 1,
|
|
fp);
|
|
fwrite(map.tails[i].data, map.tails[i].len, 1, fp);
|
|
break;
|
|
}
|
|
}
|
|
if (i == map.tail_nr) {
|
|
// no tail
|
|
v32 = 0;
|
|
fwrite(&v32, sizeof(v32), 1, fp);
|
|
}
|
|
|
|
v32 = MAP_END_MAGIC;
|
|
fwrite(&v32, sizeof(v32), 1, fp);
|
|
|
|
fclose(fp);
|
|
}
|
|
|
|
// write map of file to a map file
|
|
/*
|
|
|
|
static void map_item_list (const void *nodep, VISIT value, int level)
|
|
{
|
|
struct saved_item * item, * longest;
|
|
int bytes, max_bytes;
|
|
|
|
if (value != leaf && value != postorder)
|
|
return;
|
|
|
|
item = *(struct saved_item **)nodep;
|
|
|
|
// 1. find the longest item
|
|
max_bytes = get_bytes_number (&item->si_ih, fs->fs_blocksize);
|
|
longest = item;
|
|
while (item->si_next) {
|
|
item = item->si_next;
|
|
bytes = get_bytes_number (&item->si_ih, fs->fs_blocksize);
|
|
if (bytes > max_bytes) {
|
|
longest = item;
|
|
max_bytes = bytes;
|
|
}
|
|
}
|
|
|
|
map_one_item (longest);
|
|
|
|
// map other items
|
|
item = *(struct saved_item **)nodep;
|
|
while (item) {
|
|
if (item != longest)
|
|
map_one_item (item);
|
|
item = item->si_next;
|
|
}
|
|
}
|
|
|
|
static void make_file_map (const void *nodep, VISIT value, int level)
|
|
{
|
|
struct saved_name * name;
|
|
static int nr = 0;
|
|
|
|
name = *(struct saved_name **)nodep;
|
|
|
|
if (value == leaf || value == postorder) {
|
|
while (name) {
|
|
reiserfs_warning (stdout, "%d - (%d): [%K]:\"%s\":\n", ++nr, name->count,
|
|
&name->parent_dirid, name->name);
|
|
|
|
if (name->items) {
|
|
// initialize the map
|
|
memset (&map, 0, sizeof (struct file_map));
|
|
|
|
// make a map of file
|
|
twalk (name->items, map_item_list);
|
|
|
|
// write map to a file
|
|
flush_map (fs, (struct reiserfs_key *)&name->parent_dirid, name->name,
|
|
(struct reiserfs_key *)&name->dirid);
|
|
|
|
} else if (name->first_name)
|
|
reiserfs_warning (stdout, "[%K]:\"%s\" has item list\n",
|
|
&name->first_name->parent_dirid,
|
|
name->first_name->name);
|
|
else {
|
|
reiserfs_warning (stdout, "No items of the file [%K] found\n",
|
|
&name->dirid);
|
|
}
|
|
|
|
name = name->name_next;
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
static void print_items(FILE * fp, reiserfs_filsys_t *fs)
|
|
{
|
|
struct buffer_head *bh;
|
|
struct item_head *ih;
|
|
struct saved_item item;
|
|
int size = sizeof(struct saved_item) - sizeof(struct saved_item *);
|
|
|
|
while (fread(&item, size, 1, fp) == 1) {
|
|
bh = bread(fs->fs_dev, item.si_block, fs->fs_blocksize);
|
|
if (!bh) {
|
|
reiserfs_warning(fp, "bread failed\n");
|
|
continue;
|
|
}
|
|
ih = B_N_PITEM_HEAD(bh, item.si_item_num);
|
|
reiserfs_print_item(stdout, bh, ih);
|
|
brelse(bh);
|
|
}
|
|
}
|
|
|
|
void print_map(reiserfs_filsys_t *fs)
|
|
{
|
|
FILE *fp;
|
|
|
|
if (map_file(fs)) {
|
|
fp = fopen(map_file(fs), "r");
|
|
if (fp == 0) {
|
|
reiserfs_warning(stderr, "fopen failed: %m\n");
|
|
return;
|
|
}
|
|
} else {
|
|
reiserfs_warning(stderr, "Reading file map from stdin..\n");
|
|
fflush(stderr);
|
|
fp = stdin;
|
|
}
|
|
|
|
print_items(fp, fs);
|
|
|
|
if (fp != stdin) {
|
|
fclose(fp);
|
|
fp = NULL;
|
|
}
|
|
}
|
|
|
|
static FILE *fp = 0;
|
|
FILE *log_to;
|
|
|
|
static void save_items(const void *nodep, VISIT value, int level)
|
|
{
|
|
struct saved_item *item;
|
|
|
|
if (value != leaf && value != postorder)
|
|
return;
|
|
|
|
item = *(struct saved_item **)nodep;
|
|
|
|
while (item) {
|
|
if (fp) {
|
|
fwrite(item,
|
|
sizeof(struct saved_item) -
|
|
sizeof(struct saved_item *), 1, fp);
|
|
} else {
|
|
if (is_direntry_ih(&item->si_ih)
|
|
&& item->si_entry_pos != -1) {
|
|
reiserfs_warning(log_to,
|
|
"block %lu, item %d (%H): entry %d\n",
|
|
item->si_block,
|
|
item->si_item_num,
|
|
&item->si_ih,
|
|
item->si_entry_pos);
|
|
} else {
|
|
reiserfs_warning(log_to,
|
|
"block %lu, item %d belongs to file %K: %H\n",
|
|
item->si_block,
|
|
item->si_item_num,
|
|
&item->si_ih.ih_key,
|
|
&item->si_ih);
|
|
|
|
}
|
|
}
|
|
|
|
item = item->si_next;
|
|
}
|
|
}
|
|
|
|
static void make_map(const void *nodep, VISIT value, int level)
|
|
{
|
|
struct saved_name *name;
|
|
char *file_name = 0;
|
|
static int nr = 0;
|
|
|
|
name = *(struct saved_name **)nodep;
|
|
|
|
if (value == leaf || value == postorder) {
|
|
while (name) {
|
|
if (map_file(fs)) {
|
|
asprintf(&file_name, "%s.%d", map_file(fs),
|
|
++nr);
|
|
reiserfs_warning(log_to,
|
|
"%d - (%d): [%K]:\"%s\": stored in the %s\n",
|
|
nr, name->count,
|
|
&name->parent_dirid,
|
|
name->name, file_name);
|
|
|
|
if (fp == 0) {
|
|
fp = fopen(file_name, "w+");
|
|
if (!fp) {
|
|
reiserfs_exit(1,
|
|
"could open %s: %m",
|
|
file_name);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (name->items)
|
|
twalk(name->items, save_items);
|
|
|
|
name = name->name_next;
|
|
if (fp) {
|
|
fclose(fp);
|
|
fp = NULL;
|
|
free(file_name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* store map if it is a regular file */
|
|
static void locate_file(reiserfs_filsys_t *fs, struct reiserfs_key *key)
|
|
{
|
|
INITIALIZE_REISERFS_PATH(path);
|
|
struct reiserfs_key *next_key;
|
|
int retval;
|
|
|
|
do {
|
|
retval = reiserfs_search_by_key_4(fs, key, &path);
|
|
if (retval != ITEM_FOUND)
|
|
break;
|
|
|
|
if (!is_stat_data_key(key) && !is_direntry_key(key)) {
|
|
struct saved_item si;
|
|
|
|
si.si_block = get_bh(&path)->b_blocknr;
|
|
si.si_item_num = get_item_pos(&path);
|
|
si.si_ih = *get_ih(&path);
|
|
map_one_item(&si);
|
|
}
|
|
|
|
/*reiserfs_warning (stdout, "\t");
|
|
reiserfs_print_item (stdout, get_bh (&path), get_ih (&path)); */
|
|
|
|
next_key = reiserfs_next_key(&path);
|
|
if (!next_key || not_of_one_file(next_key, key))
|
|
break;
|
|
|
|
*key = *next_key;
|
|
pathrelse(&path);
|
|
} while (1);
|
|
|
|
pathrelse(&path);
|
|
}
|
|
|
|
/* read stdin and look for specified name in the specified directory */
|
|
static void look_for_name(reiserfs_filsys_t *fs)
|
|
{
|
|
INITIALIZE_REISERFS_PATH(path);
|
|
char *name, *objectid, *dirid;
|
|
size_t n;
|
|
struct reiserfs_key key = { 0, };
|
|
|
|
reiserfs_warning(stderr,
|
|
"Enter dirid objectid \"name\" or press ^D to quit\n");
|
|
while (1) {
|
|
reiserfs_warning(stderr, ">");
|
|
n = 0;
|
|
dirid = 0;
|
|
if (getdelim(&dirid, &n, ' ', stdin) == -1)
|
|
break;
|
|
if (!strcmp(dirid, "\n"))
|
|
break;
|
|
set_key_dirid(&key, atol(dirid));
|
|
|
|
n = 0;
|
|
objectid = 0;
|
|
if (getdelim(&objectid, &n, ' ', stdin) == -1)
|
|
break;
|
|
set_key_objectid(&key, atol(objectid));
|
|
|
|
n = 0;
|
|
name = 0;
|
|
if (getdelim(&name, &n, '\n', stdin) == -1)
|
|
break;
|
|
|
|
name[strlen(name) - 1] = 0;
|
|
reiserfs_warning(stdout, "looking for file \"%s\" in (%K) - ",
|
|
name, &key);
|
|
|
|
if (reiserfs_locate_entry(fs, &key, name, &path)) {
|
|
struct reiserfs_key fkey = { 0, };
|
|
struct reiserfs_de_head *deh;
|
|
|
|
reiserfs_warning(stdout,
|
|
"name is found in block %lu (item %d, entry %d)\n",
|
|
get_bh(&path)->b_blocknr,
|
|
get_item_pos(&path), path.pos_in_item);
|
|
deh =
|
|
B_I_DEH(get_bh(&path),
|
|
get_ih(&path)) + path.pos_in_item;
|
|
set_key_dirid(&fkey, get_deh_dirid(deh));
|
|
set_key_objectid(&fkey, get_deh_objectid(deh));
|
|
|
|
pathrelse(&path);
|
|
|
|
/* look for file and print its layout */
|
|
memset(&map, 0, sizeof(struct file_map));
|
|
|
|
locate_file(fs, &fkey);
|
|
|
|
flush_map(fs, &key, name, &fkey);
|
|
|
|
} else {
|
|
reiserfs_warning(stdout, "name not found\n");
|
|
}
|
|
|
|
free(dirid);
|
|
free(objectid);
|
|
free(name);
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
static void scan_for_key(struct buffer_head *bh, struct reiserfs_key *key)
|
|
{
|
|
int i, j, i_num;
|
|
struct item_head *ih;
|
|
struct reiserfs_de_head *deh;
|
|
int min_entry_size = 1;
|
|
int ih_entry_count = 0;
|
|
|
|
ih = B_N_PITEM_HEAD(bh, 0);
|
|
i_num = leaf_item_number_estimate(bh);
|
|
for (i = 0; i < i_num; i++, ih++) {
|
|
if ((get_key_dirid(&ih->ih_key) == get_key_dirid(key) ||
|
|
get_key_dirid(key) == ~(__u32) 0) &&
|
|
(get_key_objectid(&ih->ih_key) == get_key_objectid(key) ||
|
|
get_key_objectid(key) == ~(__u32) 0)) {
|
|
reiserfs_warning(log_to,
|
|
"%d-th item of block %lu is item of file %K: %H\n",
|
|
i, bh->b_blocknr, key, ih);
|
|
}
|
|
if (!is_direntry_ih(ih))
|
|
continue;
|
|
deh = B_I_DEH(bh, ih);
|
|
|
|
if ((get_ih_entry_count(ih) >
|
|
(get_ih_item_len(ih) / (DEH_SIZE + min_entry_size)))
|
|
|| (get_ih_entry_count(ih) == 0))
|
|
ih_entry_count =
|
|
get_ih_item_len(ih) / (DEH_SIZE + min_entry_size);
|
|
else
|
|
ih_entry_count = get_ih_entry_count(ih);
|
|
|
|
for (j = 0; j < ih_entry_count; j++, deh++) {
|
|
if ((get_deh_dirid(deh) == get_key_dirid(key)
|
|
|| (int)get_key_dirid(key) == -1)
|
|
&& (get_deh_objectid(deh) == get_key_objectid(key)
|
|
|| (int)get_key_objectid(key) == -1)) {
|
|
reiserfs_warning(log_to,
|
|
"dir item %d (%H) of block %lu has "
|
|
"entry (%d-th) %.*s pointing to %K\n",
|
|
i, ih, bh->b_blocknr, j,
|
|
name_in_entry_length(ih, deh,
|
|
j),
|
|
name_in_entry(deh, j), key);
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
void do_scan(reiserfs_filsys_t *fs)
|
|
{
|
|
unsigned long i;
|
|
struct buffer_head *bh;
|
|
int type;
|
|
char *answer = 0;
|
|
size_t n = 0;
|
|
struct reiserfs_key key = { 0, 0, };
|
|
unsigned long done, total;
|
|
|
|
if (debug_mode(fs) == DO_LOOK_FOR_NAME) {
|
|
/* look for a file in using tree algorithms */
|
|
look_for_name(fs);
|
|
return;
|
|
}
|
|
|
|
/* scan area of disk and store all names matching the pattern */
|
|
|
|
/* initialize storage and two indexes */
|
|
obstack_init(&name_store);
|
|
obstack_init(&item_store);
|
|
key_index = 0;
|
|
name_index = 0;
|
|
|
|
total = reiserfs_bitmap_ones(input_bitmap(fs));
|
|
|
|
log_to = fopen("scan.log", "w+");
|
|
printf("Log file 'scan.log' is opened\n");
|
|
|
|
if (debug_mode(fs) == DO_SCAN_FOR_NAME) {
|
|
if (regcomp(&pattern, name_pattern(fs), 0)) {
|
|
printf("regcomp failed");
|
|
return;
|
|
}
|
|
|
|
printf("Looking for names matching %s\n", name_pattern(fs));
|
|
set_key_dirid(&key, 1);
|
|
} else {
|
|
printf("What key do you want to find: dirid?");
|
|
getline(&answer, &n, stdin);
|
|
set_key_dirid(&key, atoi(answer));
|
|
|
|
printf("objectid?");
|
|
getline(&answer, &n, stdin);
|
|
set_key_objectid(&key, atoi(answer));
|
|
reiserfs_warning(stderr, "looking for (%K)\n", &key);
|
|
}
|
|
|
|
if (debug_mode(fs) == DO_SCAN_FOR_NAME) {
|
|
done = 0;
|
|
for (i = 0; i < get_sb_block_count(fs->fs_ondisk_sb); i++) {
|
|
if (!reiserfs_bitmap_test_bit(input_bitmap(fs), i))
|
|
continue;
|
|
bh = bread(fs->fs_dev, i, fs->fs_blocksize);
|
|
if (!bh) {
|
|
printf("could not read block %lu\n", i);
|
|
continue;
|
|
}
|
|
type = who_is_this(bh->b_data, bh->b_size);
|
|
if (type == THE_LEAF || type == HAS_IH_ARRAY)
|
|
scan_for_name(bh);
|
|
else
|
|
reiserfs_bitmap_clear_bit(input_bitmap(fs), i);
|
|
brelse(bh);
|
|
print_how_far(stderr, &done, total, 1, be_quiet(fs));
|
|
}
|
|
}
|
|
|
|
fprintf(stderr, "\n");
|
|
if (debug_mode(fs) == DO_SCAN_FOR_NAME)
|
|
fprintf(stderr,
|
|
"There were found %d names matching the pattern \"%s\", %d names skipped\n",
|
|
saved_names, name_pattern(fs), skipped_names);
|
|
fflush(stderr);
|
|
|
|
/* step 2: */
|
|
done = 0;
|
|
total = reiserfs_bitmap_ones(input_bitmap(fs));
|
|
printf("%lu bits set in bitmap\n", total);
|
|
for (i = 0; i < get_sb_block_count(fs->fs_ondisk_sb); i++) {
|
|
int type;
|
|
|
|
if (!reiserfs_bitmap_test_bit(input_bitmap(fs), i))
|
|
continue;
|
|
bh = bread(fs->fs_dev, i, fs->fs_blocksize);
|
|
if (!bh) {
|
|
printf("could not read block %lu\n", i);
|
|
continue;
|
|
}
|
|
type = who_is_this(bh->b_data, bh->b_size);
|
|
switch (type) {
|
|
case THE_JDESC:
|
|
if (!get_key_dirid(&key))
|
|
printf("block %lu is journal descriptor\n", i);
|
|
break;
|
|
case THE_SUPER:
|
|
if (!get_key_dirid(&key))
|
|
printf("block %lu is reiserfs super block\n",
|
|
i);
|
|
break;
|
|
case THE_INTERNAL:
|
|
if (!get_key_dirid(&key))
|
|
printf("block %lu is reiserfs internal node\n",
|
|
i);
|
|
break;
|
|
case THE_LEAF:
|
|
case HAS_IH_ARRAY:
|
|
scan_items(bh,
|
|
(debug_mode(fs) ==
|
|
DO_SCAN_FOR_NAME ? NULL : &key));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
brelse(bh);
|
|
print_how_far(stderr, &done, total, 1, be_quiet(fs));
|
|
}
|
|
fprintf(stderr, "\nThere were %d items saved\n", saved_items);
|
|
|
|
/* ok, print what we found */
|
|
/*twalk (name_index, print_file); */
|
|
|
|
/* create map for every file in */
|
|
twalk(name_index, make_map);
|
|
|
|
/* print names of files we have map of in a file 'file.list' */
|
|
/*twalk (name_index, print_name); */
|
|
}
|