// if root directory is empty - we set default - Yura's - hash and // warn about it // FIXME: we look for only one name in a directory. If tea and yura // bith have the same value - we ask user to send report to the // mailing list __u32 find_hash_out (struct super_block * s) { int retval; struct inode * inode; struct cpu_key key; INITIALIZE_PATH (path); struct reiserfs_dir_entry de; __u32 hash = DEFAULT_HASH; inode = s->s_root->d_inode; do { // Some serious "goto"-hater was there ;) u32 teahash, r5hash, yurahash; make_cpu_key (&key, inode, ~0, TYPE_DIRENTRY, 3); retval = search_by_entry_key (s, &key, &path, &de); if (retval == IO_ERROR) { pathrelse (&path); return UNSET_HASH ; } if (retval == NAME_NOT_FOUND) de.de_entry_num --; set_de_name_and_namelen (&de); if (deh_offset( &(de.de_deh[de.de_entry_num]) ) == DOT_DOT_OFFSET) { /* allow override in this case */ if (reiserfs_rupasov_hash(s)) { hash = YURA_HASH ; } reiserfs_warning("reiserfs: FS seems to be empty, autodetect " "is using the default hash\n"); break; } r5hash=GET_HASH_VALUE (r5_hash (de.de_name, de.de_namelen)); teahash=GET_HASH_VALUE (keyed_hash (de.de_name, de.de_namelen)); yurahash=GET_HASH_VALUE (yura_hash (de.de_name, de.de_namelen)); if ( ( (teahash == r5hash) && (GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num]))) == r5hash) ) || ( (teahash == yurahash) && (yurahash == GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num])))) ) || ( (r5hash == yurahash) && (yurahash == GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num])))) ) ) { reiserfs_warning("reiserfs: Unable to automatically detect hash" "function for device %s\n" "please mount with -o hash={tea,rupasov,r5}\n", kdevname (s->s_dev)); hash = UNSET_HASH; break; } if (GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num])) ) == yurahash) hash = YURA_HASH; else if (GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num])) ) == teahash) hash = TEA_HASH; else if (GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num])) ) == r5hash) hash = R5_HASH; else { reiserfs_warning("reiserfs: Unrecognised hash function for " "device %s\n", kdevname (s->s_dev)); hash = UNSET_HASH; } } while (0); pathrelse (&path); return hash; }
// if root directory is empty - we set default - Yura's - hash and // warn about it // FIXME: we look for only one name in a directory. If tea and yura // bith have the same value - we ask user to send report to the // mailing list __u32 find_hash_out (struct super_block * s) { int retval; struct inode * inode; struct cpu_key key; INITIALIZE_PATH (path); struct reiserfs_dir_entry de; __u32 hash = DEFAULT_HASH; inode = s->s_root->d_inode; while (1) { make_cpu_key (&key, inode, ~0, TYPE_DIRENTRY, 3); retval = search_by_entry_key (s, &key, &path, &de); if (retval == IO_ERROR) { pathrelse (&path); return UNSET_HASH ; } if (retval == NAME_NOT_FOUND) de.de_entry_num --; set_de_name_and_namelen (&de); if (deh_offset( &(de.de_deh[de.de_entry_num]) ) == DOT_DOT_OFFSET) { /* allow override in this case */ if (reiserfs_rupasov_hash(s)) { hash = YURA_HASH ; } reiserfs_warning("reiserfs: FS seems to be empty, autodetect " "is using the default hash\n"); break; } if (GET_HASH_VALUE(yura_hash (de.de_name, de.de_namelen)) == GET_HASH_VALUE(keyed_hash (de.de_name, de.de_namelen))) { reiserfs_warning ("reiserfs: Could not detect hash function " "please mount with -o hash={tea,rupasov,r5}\n") ; hash = UNSET_HASH ; break; } if (GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num])) ) == GET_HASH_VALUE (yura_hash (de.de_name, de.de_namelen))) hash = YURA_HASH; else hash = TEA_HASH; break; } pathrelse (&path); return hash; }
/* after this function de_entry_num is set correctly only if name found or there was no entries with given hash value */ static int linear_search_in_dir_item (struct key * key, struct reiserfs_dir_entry * de, const char * name, int namelen) { int retval; int i; i = de->de_entry_num; if (i == I_ENTRY_COUNT (de->de_ih) || GET_HASH_VALUE (de->de_deh[i].deh_offset) != GET_HASH_VALUE (key->k_offset)) { i --; } #ifdef REISERFS_CHECK if (de->de_deh != B_I_DEH (de->de_bh, de->de_ih)) reiserfs_panic (0, "vs-7010: linear_search_in_dir_item: array of entry headers not found"); #endif /* REISERFS_CHECK */ de->de_deh += i; for (; i >= 0; i --, de->de_deh --) { if (GET_HASH_VALUE (de->de_deh->deh_offset) != GET_HASH_VALUE (key->k_offset)) { return POSITION_NOT_FOUND; } /* mark, that this generation number is used */ if (de->de_gen_number_bit_string) set_bit (GET_GENERATION_NUMBER (de->de_deh->deh_offset), de->de_gen_number_bit_string); /* de_bh, de_item_num, de_ih, de_deh are already set. Set others fields */ get_entry_attributes (de, i); if ((retval = try_name (de, name, namelen)) != POSITION_NOT_FOUND) { de->de_entry_num = i; return retval; } } if (GET_GENERATION_NUMBER (de->de_ih->ih_key.k_offset) == 0) return POSITION_NOT_FOUND; #ifdef REISERFS_CHECK if (de->de_ih->ih_key.k_offset <= DOT_DOT_OFFSET || de->de_item_num != 0) reiserfs_panic (0, "vs-7015: linear_search_in_dir_item: item must be 0-th item in block (%d)", de->de_item_num); #endif /* REISERFS_CHECK */ return GOTO_PREVIOUS_ITEM; }
static char * reiserfs_cpu_offset (struct cpu_key * key) { if (cpu_key_k_type(key) == TYPE_DIRENTRY) sprintf (off_buf, "%Lu(%Lu)", (unsigned long long)GET_HASH_VALUE (cpu_key_k_offset (key)), (unsigned long long)GET_GENERATION_NUMBER (cpu_key_k_offset (key))); else sprintf (off_buf, "0x%Lx", (unsigned long long)cpu_key_k_offset (key)); return off_buf; }
static char * le_offset (struct key * key) { int version; version = le_key_version (key); if (le_key_k_type (version, key) == TYPE_DIRENTRY) sprintf (off_buf, "%Lu(%Lu)", (unsigned long long)GET_HASH_VALUE (le_key_k_offset (version, key)), (unsigned long long)GET_GENERATION_NUMBER (le_key_k_offset (version, key))); else sprintf (off_buf, "0x%Lx", (unsigned long long)le_key_k_offset (version, key)); return off_buf; }
/* Keyed 32-bit hash function using TEA in a Davis-Meyer function */ static unsigned long get_third_component (const char * name, int len) { unsigned long res; if (!len || (len == 1 && name[0] == '.')) return DOT_OFFSET; if (len == 2 && name[0] == '.' && name[1] == '.') return DOT_DOT_OFFSET; res = keyed_hash (name, len); res = GET_HASH_VALUE(res); if (res == 0) res = 128; return res + MAX_GEN_NUMBER; }
static __u32 hash_value (reiserfs_filsys_t fs, char * name) { __u32 res; if (!strcmp (name, ".")) return DOT_OFFSET; if (!strcmp (name, "..")) return DOT_DOT_OFFSET; res = reiserfs_hash (fs) (name, strlen (name)); res = GET_HASH_VALUE(res); if (res == 0) res = 128; return res; }
static __u32 get_third_component(struct super_block *s, const char *name, int len) { __u32 res; if (!len || (len == 1 && name[0] == '.')) return DOT_OFFSET; if (len == 2 && name[0] == '.' && name[1] == '.') return DOT_DOT_OFFSET; res = REISERFS_SB(s)->s_hash_function(name, len); // take bits from 7-th to 30-th including both bounds res = GET_HASH_VALUE(res); if (res == 0) // needed to have no names before "." and ".." those have hash // value == 0 and generation conters 1 and 2 accordingly res = 128; return res + MAX_GENERATION_NUMBER; }
void print_directory_item (FILE * fp, reiserfs_filsys_t fs, struct buffer_head * bh, struct item_head * ih) { int i; int namelen; struct reiserfs_de_head * deh; char * name; /* static char namebuf [80];*/ if (!I_IS_DIRECTORY_ITEM (ih)) return; //printk ("\n%2%-25s%-30s%-15s%-15s%-15s\n", " Name", "length", "Object key", "Hash", "Gen number", "Status"); reiserfs_warning (fp, "%3s: %-25s%s%-22s%-12s%s\n", "###", "Name", "length", " Object key", " Hash", "Gen number"); deh = B_I_DEH (bh, ih); for (i = 0; i < ih_entry_count (ih); i ++, deh ++) { if (dir_entry_bad_location (deh, ih, i == 0 ? 1 : 0)) { reiserfs_warning (fp, "%3d: wrong entry location %u, deh_offset %u\n", i, deh_location (deh), deh_offset (deh)); continue; } if (i && dir_entry_bad_location (deh - 1, ih, ((i - 1) == 0) ? 1 : 0)) /* previous entry has bad location so we can not calculate entry length */ namelen = 25; else namelen = name_length (ih, deh, i); name = name_in_entry (deh, i); reiserfs_warning (fp, "%3d: \"%-25.*s\"(%3d)%20K%12d%5d, loc %u, state %x %s\n", i, namelen, name, namelen, /* this gets converted in print_short_key() */ (struct key *)&(deh->deh_dir_id), GET_HASH_VALUE (deh_offset(deh)), GET_GENERATION_NUMBER (deh_offset(deh)), deh_location (deh), deh_state(deh), fs ? (is_properly_hashed (fs, name, namelen, deh_offset (deh)) ? "" : "(BROKEN)") : "??"); } }
static uint32_t get_third_component(struct reiserfs_sb_info *sbi, const char *name, int len) { uint32_t res; if (!len || (len == 1 && name[0] == '.')) return (DOT_OFFSET); if (len == 2 && name[0] == '.' && name[1] == '.') return (DOT_DOT_OFFSET); res = REISERFS_SB(sbi)->s_hash_function(name, len); /* Take bits from 7-th to 30-th including both bounds */ res = GET_HASH_VALUE(res); if (res == 0) /* * Needed to have no names before "." and ".." those have hash * value == 0 and generation counters 1 and 2 accordingly */ res = 128; return (res + MAX_GENERATION_NUMBER); }
static int linear_search_in_dir_item(struct cpu_key *key, struct reiserfs_dir_entry *de, const char *name, int namelen) { struct reiserfs_de_head *deh = de->de_deh; int retval; int i; i = de->de_entry_num; if (i == I_ENTRY_COUNT(de->de_ih) || GET_HASH_VALUE(deh_offset(deh + i)) != GET_HASH_VALUE(cpu_key_k_offset(key))) { i--; } RFALSE(de->de_deh != B_I_DEH(de->de_bh, de->de_ih), "vs-7010: array of entry headers not found"); deh += i; for (; i >= 0; i--, deh--) { if (GET_HASH_VALUE(deh_offset(deh)) != GET_HASH_VALUE(cpu_key_k_offset(key))) { // hash value does not match, no need to check whole name return NAME_NOT_FOUND; } /* mark, that this generation number is used */ if (de->de_gen_number_bit_string) set_bit(GET_GENERATION_NUMBER(deh_offset(deh)), de->de_gen_number_bit_string); // calculate pointer to name and namelen de->de_entry_num = i; set_de_name_and_namelen(de); if ((retval = reiserfs_match(de, name, namelen)) != NAME_NOT_FOUND) { // de's de_name, de_namelen, de_recordlen are set. Fill the rest: // key of pointed object set_de_object_key(de); store_de_entry_key(de); // retval can be NAME_FOUND or NAME_FOUND_INVISIBLE return retval; } } if (GET_GENERATION_NUMBER(le_ih_k_offset(de->de_ih)) == 0) /* we have reached left most entry in the node. In common we have to go to the left neighbor, but if generation counter is 0 already, we know for sure, that there is no name with the same hash value */ // FIXME: this work correctly only because hash value can not // be 0. Btw, in case of Yura's hash it is probably possible, // so, this is a bug return NAME_NOT_FOUND; RFALSE(de->de_item_num, "vs-7015: two diritems of the same directory in one node?"); return GOTO_PREVIOUS_ITEM; }
/* * de's de_bh, de_ih, de_deh, de_item_num, de_entry_num are set already * Used when hash collisions exist */ static int linear_search_in_dir_item(struct cpu_key *key, struct reiserfs_dir_entry *de, const char *name, int namelen) { int i; int retval; struct reiserfs_de_head * deh = de->de_deh; i = de->de_entry_num; if (i == I_ENTRY_COUNT(de->de_ih) || GET_HASH_VALUE(deh_offset(deh + i)) != GET_HASH_VALUE(cpu_key_k_offset(key))) { i--; } /*RFALSE( de->de_deh != B_I_DEH (de->de_bh, de->de_ih), "vs-7010: array of entry headers not found");*/ deh += i; for (; i >= 0; i--, deh--) { if (GET_HASH_VALUE(deh_offset(deh)) != GET_HASH_VALUE(cpu_key_k_offset(key))) { /* * Hash value does not match, no need to check * whole name */ reiserfs_log(LOG_DEBUG, "name `%s' not found\n", name); return (NAME_NOT_FOUND); } /* Mark that this generation number is used */ if (de->de_gen_number_bit_string) set_bit(GET_GENERATION_NUMBER(deh_offset(deh)), (unsigned long *)de->de_gen_number_bit_string); /* Calculate pointer to name and namelen */ de->de_entry_num = i; set_de_name_and_namelen(de); if ((retval = reiserfs_match(de, name, namelen)) != NAME_NOT_FOUND) { /* * de's de_name, de_namelen, de_recordlen are set. * Fill the rest: */ /* key of pointed object */ set_de_object_key(de); store_de_entry_key(de); /* retval can be NAME_FOUND or NAME_FOUND_INVISIBLE */ reiserfs_log(LOG_DEBUG, "reiserfs_match answered `%d'\n", retval); return (retval); } } if (GET_GENERATION_NUMBER(le_ih_k_offset(de->de_ih)) == 0) /* * We have reached left most entry in the node. In common * we have to go to the left neighbor, but if generation * counter is 0 already, we know for sure, that there is * no name with the same hash value */ /* FIXME: this work correctly only because hash value can * not be 0. Btw, in case of Yura's hash it is probably * possible, so, this is a bug */ return (NAME_NOT_FOUND); /*RFALSE(de->de_item_num, "vs-7015: two diritems of the same directory in one node?");*/ return (GOTO_PREVIOUS_ITEM); }
/* returns 0 if name is not found in a directory and objectid of pointed object otherwise and returns minimal not used generation counter. dies if found object is not a directory. */ int reiserfs_find_entry (reiserfs_filsys_t fs, struct key * dir, char * name, int * min_gen_counter) { struct key entry_key; int retval; int i; INITIALIZE_PATH (path); struct item_head * ih; struct reiserfs_de_head * deh; struct key * rdkey; __u32 hash; entry_key.k_dir_id = cpu_to_le32(dir->k_dir_id); entry_key.k_objectid = cpu_to_le32(dir->k_objectid); hash = hash_value (fs, name); set_type_and_offset (KEY_FORMAT_1, &entry_key, hash, TYPE_DIRENTRY); *min_gen_counter = 0; if (_search_by_entry_key (fs, &entry_key, &path) == DIRECTORY_NOT_FOUND) { pathrelse (&path); return 0; } do { ih = get_ih (&path); deh = B_I_DEH (get_bh (&path), ih) + path.pos_in_item; for (i = path.pos_in_item; i < ih_entry_count (ih); i ++, deh ++) { if (GET_HASH_VALUE (deh_offset (deh)) != GET_HASH_VALUE (hash)) { /* all entries having the same hash were scanned */ pathrelse (&path); return 0; } if (GET_GENERATION_NUMBER (deh_offset (deh)) == *min_gen_counter) (*min_gen_counter) ++; if (!memcmp (name_in_entry (deh, i), name, strlen (name))) { pathrelse (&path); return deh_objectid (deh) ? deh_objectid (deh) : 1; } } rdkey = _get_rkey (&path); if (!rdkey || not_of_one_file (rdkey, dir)) { pathrelse (&path); return 0; } if (!is_direntry_key (rdkey)) reiserfs_panic ("reiserfs_find_entry: can not find name in broken directory yet"); /* next item is the item of the directory we are looking name in */ if (GET_HASH_VALUE (get_offset (rdkey)) != hash) { /* but there is no names with given hash */ pathrelse (&path); return 0; } /* first name of that item may be a name we are looking for */ entry_key = *rdkey; pathrelse (&path); retval = _search_by_entry_key (fs, &entry_key, &path); if (retval != POSITION_FOUND) reiserfs_panic ("reiserfs_find_entry: wrong delimiting key in the tree"); } while (1); return 0; }
/* check directory item and try to recover something */ static int verify_directory_item (reiserfs_filsys_t fs, struct buffer_head * bh, int item_num) { struct item_head * ih; struct item_head tmp; char * item; struct reiserfs_de_head * deh; char * name; int name_len; int bad; int i, j; #if 0 int bad_entries; /* how many bad neighboring entries */ int total_entry_len; char * entries, * end; #endif int dirty; int entry_count; int hash_code; int bad_locations; #ifdef DEBUG_VERIFY_DENTRY char * direntries; #endif ih = B_N_PITEM_HEAD (bh, item_num); item = B_I_PITEM (bh,ih); deh = (struct reiserfs_de_head *)item; dirty = 0; bad_locations = 0; entry_count = ih_entry_count (ih); /* check deh_location */ for (i = 0; i < ih_entry_count (ih); i ++) { /* silently fix deh_state */ if (deh [i].deh_state != (1 << DEH_Visible)) { deh [i].deh_state = cpu_to_le16 (1 << DEH_Visible); mark_buffer_dirty (bh); } if (dir_entry_bad_location (deh + i, ih, !i)) mark_de_bad_location (deh + i); } #ifdef DEBUG_VERIFY_DENTRY direntries = getmem (ih_entry_count (ih) * sizeof (int)); printf ("entries with bad locations: "); for (i = 0; i < ih_entry_count (ih); i ++) { if (de_bad_location (deh + i)) printf ("%d ", i); } printf ("\n"); #endif /* DEBUG_VERIFY_DENTRY */ /* find entries names in which have mismatching deh_offset */ for (i = ih_entry_count (ih) - 1; i >= 0; i --) { if (de_bad (deh + i)) /* bad location */ continue; if (i) { if (deh_location (deh + i - 1) < deh_location (deh + i)) mark_de_bad_location (deh + i - 1); } name = name_in_entry (deh + i, i); /* we found a name, but we not always we can get its length as it depends on deh_location of previous entry */ name_len = try_to_get_name_length (ih, deh + i, i); #ifdef DEBUG_VERIFY_DENTRY if (name_len == 0) printf ("trying to find name length for %d-th entry\n", i); #endif /* DEBUG_VERIFY_DENTRY */ if (is_dot (name, name_len)) { if (i != 0) fsck_log ("block %lu: item %d: \".\" is %d-th entry\n", bh->b_blocknr, item_num, i); /* check and fix "." */ if (deh_offset (deh + i) != DOT_OFFSET) { set_deh_offset(&(deh[i]), DOT_OFFSET); mark_buffer_dirty (bh); } /* "." must point to the directory it is in */ if (not_of_one_file (&(deh[i].deh_dir_id), &(ih->ih_key))) { /* endian safe */ fsck_log ("verify_direntry: block %lu, item %H has entry \".\" " "pointing to (%K) instead of (%K)\n", bh->b_blocknr, ih, &(deh[i].deh_dir_id), &(ih->ih_key)); deh[i].deh_dir_id = ih->ih_key.k_dir_id; /* both LE */ deh[i].deh_objectid = ih->ih_key.k_objectid; /* both LE */ mark_buffer_dirty (bh); } } else if (is_dot_dot (name, name_len)) { if (i != 1) fsck_log ("block %lu: item %d: \"..\" is %d-th entry\n", bh->b_blocknr, item_num, i); /* check and fix ".." */ if (deh_offset (deh + i) != DOT_DOT_OFFSET) set_deh_offset(&(deh[i]), DOT_DOT_OFFSET); } else { int min_length, max_length; /* check other name */ if (name_len == 0) { /* we do not know the length of name - we will try to find it */ min_length = 1; max_length = item + ih_item_len (ih) - name; } else /* we kow name length, so we will try only one name length */ min_length = max_length = name_len; for (j = min_length; j <= max_length; j ++) { hash_code = find_hash_in_use (name, j, GET_HASH_VALUE (deh_offset (deh + i)), rs_hash (fs->s_rs)); add_hash_hit (fs, hash_code); if (code2func (hash_code) != 0) { /* deh_offset matches to some hash of the name */ if (!name_len) { fsck_log ("pass0: block %lu, item %H: entry %d. found a name \"%.*s\" " "matching to deh_offset %u. FIXME: should set deh_location " "of previous entry (not ready)\n", bh->b_blocknr, ih, i, j, name, deh_offset (deh + i)); /* FIXME: if next byte is 0 we think that the name is aligned to 8 byte boundary */ if (i) { set_deh_location( &(deh[i - 1]), deh_location (deh + i) + ((name[j] || SB_VERSION (fs) == REISERFS_VERSION_1) ? j : ROUND_UP (j))); mark_de_good_location (deh + i - 1); mark_buffer_dirty (bh); } } break; } } if (j == max_length + 1) { /* deh_offset does not match to anything. it will be deleted for now, but maybe we could just fix a deh_offset if it is in ordeer */ mark_de_bad_offset (deh + i); } } } /* for */ #if 0 /* find entries names in which have mismatching deh_offset */ for (i = 0; i < ih_entry_count (ih); i ++) { if (de_bad (deh + i)) /* bad location */ continue; name = name_in_entry (deh + i, i); /* we found a name, but we not always we can get its length as it depends on deh_location of previous entry */ name_len = try_to_get_name_length (ih, deh + i, i); if (i == 0 && is_dot (name, name_len)) { /* check and fix "." */ if (deh_offset (deh + i) != DOT_OFFSET) { deh[i].deh_offset = cpu_to_le32 (DOT_OFFSET); } /* "." must point to the directory it is in */ if (not_of_one_file (&(deh[i].deh_dir_id), &(ih->ih_key))) { fsck_log ("verify_direntry: block %lu, item %H has entry \".\" " "pointing to (%K) instead of (%K)\n", bh->b_blocknr, ih, &(deh[i].deh_dir_id), &(ih->ih_key)); deh[i].deh_dir_id = ih->ih_key.k_dir_id; /* both 32 bit LE */ deh[i].deh_objectid = ih->ih_key.k_objectid; /* both 32 bit LE */ mark_buffer_dirty (bh); } } else if (i == 1 && is_dot_dot (name, name_len)) { /* check and fix ".." */ if (deh_offset (deh + i) != DOT_DOT_OFFSET) deh[i].deh_offset = cpu_to_le32 (DOT_DOT_OFFSET); } else { int min_length, max_length; /* check other name */ if (name_len == 0) { /* we do not know the length of name - we will try to find it */ min_length = 1; max_length = item + ih_item_len (ih) - name; } else /* we kow name length, so we will try only one name length */ min_length = max_length = name_len; for (j = min_length; j <= max_length; j ++) { hash_code = find_hash_in_use (name, j, GET_HASH_VALUE (deh_offset (deh + i)), rs_hash (fs->s_rs)); add_hash_hit (fs, hash_code); if (code2func (hash_code) != 0) { /* deh_offset matches to some hash of the name */ if (!name_len) { fsck_log ("pass0: block %lu, item %H: entry %d. found a name \"%.*s\" " "matching to deh_offset %u. FIXME: should set deh_location " "of previous entry (not ready)\n", bh->b_blocknr, ih, i, j, name, deh_offset (deh + i)); /* FIXME: if next byte is 0 we think that the name is aligned to 8 byte boundary */ deh[i - 1].deh_location = cpu_to_le16 (deh_location (deh + i) + ((name[j] || SB_VERSION (fs) == REISERFS_VERSION_1) ? j : ROUND_UP (j))); } break; } } if (j == max_length + 1) { /* deh_offset does not match to anything. it will be deleted for now, but maybe we could just fix a deh_offset if it is in ordeer */ mark_de_bad_offset (deh + i); } } } #endif #ifdef DEBUG_VERIFY_DENTRY printf ("entries with mismatching deh_offsets: "); for (i = 0; i < ih_entry_count (ih); i ++) { if (de_bad_offset (deh + i)) printf ("%d ", i); } printf ("\n"); #endif /* DEBUG_VERIFY_DENTRY */ /* correct deh_locations such that code cutting entries will not get screwed up */ { int prev_loc; int loc_fixed; prev_loc = ih_item_len (ih); for (i = 0; i < ih_entry_count (ih); i ++) { loc_fixed = 0; if (de_bad_location (deh + i)) { set_deh_location(&(deh[i]), prev_loc/* - 1*/); mark_buffer_dirty (bh); loc_fixed = 1; } else { if (deh_location (deh + i) >= prev_loc) { set_deh_location(&(deh[i]), prev_loc/* - 1*/); mark_buffer_dirty (bh); loc_fixed = 1; } } prev_loc = deh_location (deh + i); if (i == ih_entry_count (ih) - 1) { /* last entry starts right after an array of dir entry headers */ if (!de_bad (deh + i) && deh_location (deh + i) != (DEH_SIZE * ih_entry_count (ih))) { /* free space in the directory item */ fsck_log ("verify_direntry: block %lu, item %H has free pace\n", bh->b_blocknr, ih); cut_entry (fs, bh, item_num, ih_entry_count (ih), 0); } if (deh_location (deh + i) != (DEH_SIZE * ih_entry_count (ih))) { set_deh_location(&(deh[i]), DEH_SIZE * ih_entry_count (ih)); loc_fixed = 1; mark_buffer_dirty (bh); } } #ifdef DEBUG_VERIFY_DENTRY if (loc_fixed) direntries [i] = 1; #endif } /* for */ #ifdef DEBUG_VERIFY_DENTRY printf ("entries with fixed deh_locations: "); for (i = 0; i < ih_entry_count (ih); i ++) { if (direntries [i]) printf ("%d ", i); } printf ("\n"); #endif /* DEBUG_VERIFY_DENTRY */ } #ifdef DEBUG_VERIFY_DENTRY printf (" N location name\n"); for (i = 0; i < ih_entry_count (ih); i ++) { if (de_bad (deh + i) || (i && de_bad (deh + i - 1)) || /* previous entry marked bad */ (i < ih_entry_count (ih) - 1 && de_bad (deh + i + 1))) { /* next ntry is marked bad */ /* print only entries to be deleted and their nearest neighbors */ printf ("%3d: %8d ", i, deh_location (deh + i)); if (de_bad (deh + i)) printf ("will be deleted\n"); else printf ("\"%.*s\"\n", name_length (ih, deh + i, i), name_in_entry (deh + i, i)); } } #endif bad = 0; tmp = *ih; /* delete entries which are marked bad */ for (i = 0; i < ih_entry_count (ih); i ++) { deh = B_I_DEH (bh, ih) + i; if (de_bad (deh)) { bad ++; if (ih_entry_count (ih) == 1) { delete_item (fs, bh, item_num); break; } else { cut_entry (fs, bh, item_num, i, 1); } i --; } } if (bad == ih_entry_count (&tmp)) { fsck_log ("pass0: block %lu, item %H - all entries were deleted\n", bh->b_blocknr, &tmp); return 0; } deh = B_I_DEH (bh, ih); if (get_offset (&ih->ih_key) != deh_offset (deh)) { fsck_log ("verify_direntry: block %lu, item %H: k_offset and deh_offset %u mismatched\n", bh->b_blocknr, ih, deh_offset (deh)); set_offset (KEY_FORMAT_1, &ih->ih_key, deh_offset (deh)); mark_buffer_dirty (bh); } if (bad) fsck_log ("pass0: block %lu, item %H: %d entries were deleted of \n", bh->b_blocknr, &tmp, bad); return 0; #if 0 /* FIXME: temporary */ if (bad_locations > ih_entry_count (ih) / 2) { fsck_log ("pass0: block %u: item %d (%H) had too bad directory - deleted\n", bh->b_blocknr, item_num, ih); delete_item (fs, bh, item_num); return 0; } if (!dirty) return 0; /* something is broken */ fsck_log ("pass0: block %lu: %d-th item (%H) has %d bad entries..", bh->b_blocknr, item_num, ih, dirty); if (get_offset (&ih->ih_key) == DOT_OFFSET) { /* first item of directory - make sure that "." and ".." are in place */ if (deh_offset (deh) != DOT_OFFSET || name_in_entry (deh, 0)[0] != '.') { set_deh_offset(deh, DOT_OFFSET); name_in_entry (deh, 0)[0] = '.'; } if (deh_offset (deh + 1) != DOT_DOT_OFFSET || name_in_entry (deh + 1, 1)[0] != '.' || name_in_entry (deh + 1, 1)[1] != '.') { set_deh_offset((deh + 1), DOT_DOT_OFFSET); name_in_entry (deh + 1, 1)[0] = '.'; name_in_entry (deh + 1, 1)[1] = '.'; } } end = item + ih_item_len (ih); deh += ih_entry_count (ih); entries = (char *)deh; total_entry_len = ih_item_len (ih) - DEH_SIZE * ih_entry_count (ih); i = ih_entry_count (ih); bad_entries = 0; do { i --; deh --; name_len = prob_name (fs, &entries, total_entry_len, deh_offset (deh)); if (!name_len) { if (!bad_entries) { set_deh_location(deh, entries - item); } else { set_deh_location(deh, deh_location((deh + 1)) + 1 ); } bad_entries ++; /*fsck_log ("verify_directory_item: entry %d: in string \'%s\' there is no substring matching hash %ld\n", i, bad_name (entries, total_entry_len), masked_offset);*/ mark_de_bad (deh); continue; } bad_entries = 0; /*fsck_log ("verify_directory_item: entry %d: found \"%s\" name matching hash %ld\n", i, bad_name (entries, name_len), masked_offset);*/ /* 'entries' points now to the name which match given offset - so, set deh_location */ set_deh_location(deh, entries - item); deh->deh_state = 0; mark_de_visible (deh); entries += name_len; total_entry_len = end - entries; /* skip padding zeros */ while (!*entries) { entries ++; total_entry_len --; } /* 'entries' points now at the place where next (previous) entry should start */ } while ((char *)deh != item); /* fixme: this will not work if all entries are to be deleted */ for (i = 0; i < ih_entry_count (ih); i ++, deh ++) { deh = (struct reiserfs_de_head *)B_I_PITEM (bh, ih) + i; if (de_bad (deh)) { if (ih_entry_count (ih) == 1) { delete_item (fs, bh, i); break; } else { cut_entry (fs, bh, item_num, i); } i --; } /* fsck_log ("verify_directory_item: %d-th entry is to be deleted: " "\"%s\" does not match to hash %lu\n", i, bad_name (name_in_entry (deh, i), name_length (ih, deh, i)), deh_offset (deh)); */ } fsck_log ("%d entries were deleted\n", entry_count - ih_entry_count (ih)); mark_buffer_dirty (bh); return 0; #endif }
/* * If root directory is empty - we set default - Yura's - hash and warn * about it. * FIXME: we look for only one name in a directory. If tea and yura both * have the same value - we ask user to send report to the mailing list */ uint32_t find_hash_out(struct reiserfs_mount *rmp) { int retval; struct cpu_key key; INITIALIZE_PATH(path); struct reiserfs_node *ip; struct reiserfs_sb_info *sbi; struct reiserfs_dir_entry de; uint32_t hash = DEFAULT_HASH; get_root_node(rmp, &ip); if (!ip) return (UNSET_HASH); sbi = rmp->rm_reiserfs; do { uint32_t teahash, r5hash, yurahash; reiserfs_log(LOG_DEBUG, "make_cpu_key\n"); make_cpu_key(&key, ip, ~0, TYPE_DIRENTRY, 3); reiserfs_log(LOG_DEBUG, "search_by_entry_key for " "key(objectid=%d,dirid=%d)\n", key.on_disk_key.k_objectid, key.on_disk_key.k_dir_id); retval = search_by_entry_key(sbi, &key, &path, &de); if (retval == IO_ERROR) { pathrelse(&path); return (UNSET_HASH); } if (retval == NAME_NOT_FOUND) de.de_entry_num--; reiserfs_log(LOG_DEBUG, "name found\n"); set_de_name_and_namelen(&de); if (deh_offset(&(de.de_deh[de.de_entry_num])) == DOT_DOT_OFFSET) { /* Allow override in this case */ if (reiserfs_rupasov_hash(sbi)) { hash = YURA_HASH; } reiserfs_log(LOG_DEBUG, "FS seems to be empty, autodetect " "is using the default hash"); break; } r5hash = GET_HASH_VALUE(r5_hash(de.de_name, de.de_namelen)); teahash = GET_HASH_VALUE(keyed_hash(de.de_name, de.de_namelen)); yurahash = GET_HASH_VALUE(yura_hash(de.de_name, de.de_namelen)); if (((teahash == r5hash) && (GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num]))) == r5hash)) || ((teahash == yurahash) && (yurahash == GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num]))))) || ((r5hash == yurahash) && (yurahash == GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num])))))) { reiserfs_log(LOG_ERR, "unable to automatically detect hash " "function. Please mount with -o " "hash={tea,rupasov,r5}"); hash = UNSET_HASH; break; } if (GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num]))) == yurahash) { reiserfs_log(LOG_DEBUG, "detected YURA hash\n"); hash = YURA_HASH; } else if (GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num]))) == teahash) { reiserfs_log(LOG_DEBUG, "detected TEA hash\n"); hash = TEA_HASH; } else if (GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num]))) == r5hash) { reiserfs_log(LOG_DEBUG, "detected R5 hash\n"); hash = R5_HASH; } else { reiserfs_log(LOG_WARNING, "unrecognised hash function"); hash = UNSET_HASH; } } while (0); pathrelse(&path); return (hash); }