int bin_search_in_dir_item (struct item_head * ih, struct reiserfs_de_head * deh, struct key * key, int * pos_in_item) { int rbound, lbound, j; lbound = 0; rbound = ih_entry_count (ih) - 1; for (j = (rbound + lbound) / 2; lbound <= rbound; j = (rbound + lbound) / 2) { if (get_offset (key) < deh_offset (deh + j)) { rbound = j - 1; continue; } if (get_offset (key) > deh_offset (deh + j)) { lbound = j + 1; continue; } /* key found */ *pos_in_item = j; return POSITION_FOUND; } *pos_in_item = lbound; return POSITION_NOT_FOUND; }
/* * directory item contains array of entry headers. This performs * binary search through that array */ static int bin_search_in_dir_item(struct reiserfs_dir_entry *de, loff_t off) { struct item_head *ih = de->de_ih; struct reiserfs_de_head *deh = de->de_deh; int rbound, lbound, j; lbound = 0; rbound = ih_entry_count(ih) - 1; for (j = (rbound + lbound) / 2; lbound <= rbound; j = (rbound + lbound) / 2) { if (off < deh_offset(deh + j)) { rbound = j - 1; continue; } if (off > deh_offset(deh + j)) { lbound = j + 1; continue; } /* this is not name found, but matched third key component */ de->de_entry_num = j; return NAME_FOUND; } de->de_entry_num = lbound; return NAME_NOT_FOUND; }
// what entry points to static inline void set_de_object_key (struct reiserfs_dir_entry * de) { if (de->de_entry_num >= ih_entry_count (de->de_ih)) BUG (); de->de_dir_id = deh_dir_id( &(de->de_deh[de->de_entry_num])); de->de_objectid = deh_objectid( &(de->de_deh[de->de_entry_num])); }
int reiserfs_remove_entry (reiserfs_filsys_t fs, struct key * key) { struct path path; struct tree_balance tb; struct item_head * ih; struct reiserfs_de_head * deh; if (_search_by_entry_key (fs, key, &path) != POSITION_FOUND) { pathrelse (&path); return 1; } ih = get_ih (&path); if (ih_entry_count (ih) == 1) { _init_tb_struct (&tb, fs, &path, -(IH_SIZE + ih_item_len (ih))); if (fix_nodes (M_DELETE, &tb, 0) != CARRY_ON) { unfix_nodes (&tb); return 1; } do_balance (&tb, 0, 0, M_DELETE, 0); return 0; } deh = B_I_DEH (get_bh (&path), ih) + path.pos_in_item; _init_tb_struct (&tb, fs, &path, -(DEH_SIZE + entry_length (ih, deh, path.pos_in_item))); if (fix_nodes (M_CUT, &tb, 0) != CARRY_ON) { unfix_nodes (&tb); return 1; } do_balance (&tb, 0, 0, M_CUT, 0); return 0; }
static void check_directory_item (struct item_head * ih, struct buffer_head * bh) { int i; struct reiserfs_de_head * deh; for (i = 0, deh = B_I_DEH (bh, ih); i < ih_entry_count (ih) - 1; i ++) if (deh_offset(&deh[i]) > deh_offset(&deh[i + 1])) die ("check_directory_item: entries are not sorted properly"); }
/* What entry points to */ static inline void set_de_object_key(struct reiserfs_dir_entry *de) { if (de->de_entry_num >= ih_entry_count(de->de_ih)) { reiserfs_log(LOG_DEBUG, "BUG\n"); return; } de->de_dir_id = deh_dir_id(&(de->de_deh[de->de_entry_num])); de->de_objectid = deh_objectid(&(de->de_deh[de->de_entry_num])); }
// de_bh, de_ih, de_deh (points to first element of array), de_item_num is set inline void set_de_name_and_namelen(struct reiserfs_dir_entry *de) { struct reiserfs_de_head *deh = de->de_deh + de->de_entry_num; BUG_ON(de->de_entry_num >= ih_entry_count(de->de_ih)); de->de_entrylen = entry_length(de->de_bh, de->de_ih, de->de_entry_num); de->de_namelen = de->de_entrylen - (de_with_sd(deh) ? SD_SIZE : 0); de->de_name = B_I_PITEM(de->de_bh, de->de_ih) + deh_location(deh); if (de->de_name[de->de_namelen - 1] == 0) de->de_namelen = strlen(de->de_name); }
static inline void store_de_entry_key (struct reiserfs_dir_entry * de) { struct reiserfs_de_head * deh = de->de_deh + de->de_entry_num; if (de->de_entry_num >= ih_entry_count (de->de_ih)) BUG (); /* store key of the found entry */ de->de_entry_key.version = KEY_FORMAT_3_5; de->de_entry_key.on_disk_key.k_dir_id = le32_to_cpu (de->de_ih->ih_key.k_dir_id); de->de_entry_key.on_disk_key.k_objectid = le32_to_cpu (de->de_ih->ih_key.k_objectid); set_cpu_key_k_offset (&(de->de_entry_key), deh_offset (deh)); set_cpu_key_k_type (&(de->de_entry_key), TYPE_DIRENTRY); }
/* * de_bh, de_ih, de_deh (points to first element of array), de_item_num * is set */ void set_de_name_and_namelen(struct reiserfs_dir_entry *de) { struct reiserfs_de_head *deh = de->de_deh + de->de_entry_num; if (de->de_entry_num >= ih_entry_count(de->de_ih)) { reiserfs_log(LOG_DEBUG, "BUG\n"); return; } de->de_entrylen = entry_length(de->de_bp, de->de_ih, de->de_entry_num); de->de_namelen = de->de_entrylen - (de_with_sd(deh) ? SD_SIZE : 0); de->de_name = B_I_PITEM(de->de_bp, de->de_ih) + deh_location(deh); if (de->de_name[de->de_namelen - 1] == 0) de->de_namelen = strlen(de->de_name); }
static inline void store_de_entry_key(struct reiserfs_dir_entry *de) { struct reiserfs_de_head *deh = de->de_deh + de->de_entry_num; if (de->de_entry_num >= ih_entry_count(de->de_ih)) { reiserfs_log(LOG_DEBUG, "BUG\n"); return; } /* Store key of the found entry */ de->de_entry_key.version = KEY_FORMAT_3_5; de->de_entry_key.on_disk_key.k_dir_id = le32toh(de->de_ih->ih_key.k_dir_id); de->de_entry_key.on_disk_key.k_objectid = le32toh(de->de_ih->ih_key.k_objectid); set_cpu_key_k_offset(&(de->de_entry_key), deh_offset(deh)); set_cpu_key_k_type(&(de->de_entry_key), TYPE_DIRENTRY); }
/* %H */ static int print_item_head (FILE * stream, const struct printf_info *info, const void *const *args) { const struct item_head * ih; char * buffer; int len; ih = *((const struct item_head **)(args[0])); len = asprintf (&buffer, "%u %u 0x%Lx %s, " "len %u, entry count %u, fsck need %u, format %s", le32_to_cpu(ih->ih_key.k_dir_id), le32_to_cpu(ih->ih_key.k_objectid), get_offset (&ih->ih_key), key_of_what (&ih->ih_key), ih_item_len(ih), ih_entry_count (ih), ih_fsck_need(ih), ih_key_format (ih) == KEY_FORMAT_2 ? "new" : ((ih_key_format (ih) == KEY_FORMAT_1) ? "old" : "BAD")); FPRINTF; }
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)") : "??"); } }
/* preconditions: reiserfs_read_super already executed, therefore * INFO block is valid * returns: 0 if error, nonzero iff we were able to find the file successfully * postconditions: on a nonzero return, INFO->fileinfo contains the info * of the file we were trying to look up, filepos is 0 and filemax is * the size of the file. */ static int reiserfs_open_file( char *dirname ) { struct reiserfs_de_head *de_head; char *rest, ch; __u32 dir_id, objectid, parent_dir_id = 0, parent_objectid = 0; char linkbuf[PATH_MAX]; /* buffer for following symbolic links */ int link_count = 0; int mode; errnum = 0; dir_id = cpu_to_le32(REISERFS_ROOT_PARENT_OBJECTID); objectid = cpu_to_le32(REISERFS_ROOT_OBJECTID); while ( 1 ) { DEBUG_F( "dirname=%s\n", dirname ); /* Search for the stat info first. */ if ( !search_stat( dir_id, objectid ) ) return 0; DEBUG_F( "sd_mode=0%o sd_size=%Lu\n", sd_mode((struct stat_data *) INFO->current_item ), sd_size(INFO->current_ih, INFO->current_item )); mode = sd_mode((struct stat_data *)INFO->current_item); /* If we've got a symbolic link, then chase it. */ if ( S_ISLNK( mode ) ) { int len = 0; DEBUG_F("link count = %d\n", link_count); DEBUG_SLEEP; if ( ++link_count > MAX_LINK_COUNT ) { DEBUG_F("Symlink loop\n"); errnum = FILE_ERR_SYMLINK_LOOP; return 0; } /* Get the symlink size. */ INFO->file->len = sd_size(INFO->current_ih, INFO->current_item); /* Find out how long our remaining name is. */ while ( dirname[len] && !isspace( dirname[len] ) ) len++; if ( INFO->file->len + len > sizeof ( linkbuf ) - 1 ) { errnum = FILE_ERR_LENGTH; return 0; } /* Copy the remaining name to the end of the symlink data. Note * * that DIRNAME and LINKBUF may overlap! */ memmove( linkbuf + INFO->file->len, dirname, len + 1 ); INFO->fileinfo.k_dir_id = dir_id; INFO->fileinfo.k_objectid = objectid; INFO->file->pos = 0; if ( !next_key() || reiserfs_read_data( linkbuf, INFO->file->len ) != INFO->file->len ) { DEBUG_F("reiserfs_open_file - if !next_key || reiserfs_read_data\n"); DEBUG_SLEEP; errnum = FILE_IOERR; return 0; } DEBUG_F( "symlink=%s\n", linkbuf ); DEBUG_SLEEP; dirname = linkbuf; if ( *dirname == '/' ) { /* It's an absolute link, so look it up in root. */ dir_id = cpu_to_le32(REISERFS_ROOT_PARENT_OBJECTID); objectid = cpu_to_le32(REISERFS_ROOT_OBJECTID); } else { /* Relative, so look it up in our parent directory. */ dir_id = parent_dir_id; objectid = parent_objectid; } /* Now lookup the new name. */ continue; } /* if we have a real file (and we're not just printing * * possibilities), then this is where we want to exit */ if ( !*dirname || isspace( *dirname ) ) { if ( !S_ISREG( mode ) ) { errnum = FILE_ERR_BAD_TYPE; return 0; } INFO->file->pos = 0; INFO->file->len = sd_size(INFO->current_ih, INFO->current_item); INFO->fileinfo.k_dir_id = dir_id; INFO->fileinfo.k_objectid = objectid; return next_key(); } /* continue with the file/directory name interpretation */ while ( *dirname == '/' ) dirname++; if ( !S_ISDIR( mode ) ) { errnum = FILE_ERR_NOTDIR; return 0; } for ( rest = dirname; ( ch = *rest ) && !isspace( ch ) && ch != '/'; rest++ ) ; *rest = 0; while ( 1 ) { char *name_end; int num_entries; if ( !next_key() ) return 0; if ( INFO->current_ih->ih_key.k_objectid != objectid ) break; name_end = INFO->current_item + ih_item_len(INFO->current_ih); de_head = ( struct reiserfs_de_head * ) INFO->current_item; num_entries = ih_entry_count(INFO->current_ih); while ( num_entries > 0 ) { char *filename = INFO->current_item + deh_location(de_head); char tmp = *name_end; if( deh_state(de_head) & (1 << DEH_Visible)) { int cmp; /* Directory names in ReiserFS are not null * terminated. * We write a temporary 0 behind it. * NOTE: that this * may overwrite the first block in * the tree cache. * That doesn't hurt as long as we * don't call next_key * () in between. */ *name_end = 0; cmp = strcmp( dirname, filename ); *name_end = tmp; if ( cmp == 0 ) goto found; } /* The beginning of this name marks the end of the next name. */ name_end = filename; de_head++; num_entries--; } } errnum = FILE_ERR_NOTFOUND; *rest = ch; return 0; found: *rest = ch; dirname = rest; parent_dir_id = dir_id; parent_objectid = objectid; dir_id = de_head->deh_dir_id; /* LE */ objectid = de_head->deh_objectid; /* LE */ } }
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 == ih_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--) { /* hash value does not match, no need to check whole name */ if (GET_HASH_VALUE(deh_offset(deh)) != GET_HASH_VALUE(cpu_key_k_offset(key))) { 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); /* * de's de_name, de_namelen, de_recordlen are set. * Fill the rest. */ if ((retval = reiserfs_match(de, name, namelen)) != NAME_NOT_FOUND) { /* 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; }
int reiserfs_readdir_inode(struct inode *inode, struct dir_context *ctx) { /* key of current position in the directory (key of directory entry) */ struct cpu_key pos_key; INITIALIZE_PATH(path_to_entry); struct buffer_head *bh; int item_num, entry_num; const struct reiserfs_key *rkey; struct item_head *ih, tmp_ih; int search_res; char *local_buf; loff_t next_pos; char small_buf[32]; /* avoid kmalloc if we can */ struct reiserfs_dir_entry de; int ret = 0; int depth; reiserfs_write_lock(inode->i_sb); reiserfs_check_lock_depth(inode->i_sb, "readdir"); /* * form key for search the next directory entry using * f_pos field of file structure */ make_cpu_key(&pos_key, inode, ctx->pos ?: DOT_OFFSET, TYPE_DIRENTRY, 3); next_pos = cpu_key_k_offset(&pos_key); path_to_entry.reada = PATH_READA; while (1) { research: /* * search the directory item, containing entry with * specified key */ search_res = search_by_entry_key(inode->i_sb, &pos_key, &path_to_entry, &de); if (search_res == IO_ERROR) { /* * FIXME: we could just skip part of directory * which could not be read */ ret = -EIO; goto out; } entry_num = de.de_entry_num; bh = de.de_bh; item_num = de.de_item_num; ih = de.de_ih; store_ih(&tmp_ih, ih); /* we must have found item, that is item of this directory, */ RFALSE(COMP_SHORT_KEYS(&ih->ih_key, &pos_key), "vs-9000: found item %h does not match to dir we readdir %K", ih, &pos_key); RFALSE(item_num > B_NR_ITEMS(bh) - 1, "vs-9005 item_num == %d, item amount == %d", item_num, B_NR_ITEMS(bh)); /* * and entry must be not more than number of entries * in the item */ RFALSE(ih_entry_count(ih) < entry_num, "vs-9010: entry number is too big %d (%d)", entry_num, ih_entry_count(ih)); /* * go through all entries in the directory item beginning * from the entry, that has been found */ if (search_res == POSITION_FOUND || entry_num < ih_entry_count(ih)) { struct reiserfs_de_head *deh = B_I_DEH(bh, ih) + entry_num; for (; entry_num < ih_entry_count(ih); entry_num++, deh++) { int d_reclen; char *d_name; ino_t d_ino; loff_t cur_pos = deh_offset(deh); /* it is hidden entry */ if (!de_visible(deh)) continue; d_reclen = entry_length(bh, ih, entry_num); d_name = B_I_DEH_ENTRY_FILE_NAME(bh, ih, deh); if (d_reclen <= 0 || d_name + d_reclen > bh->b_data + bh->b_size) { /* * There is corrupted data in entry, * We'd better stop here */ pathrelse(&path_to_entry); ret = -EIO; goto out; } if (!d_name[d_reclen - 1]) d_reclen = strlen(d_name); /* too big to send back to VFS */ if (d_reclen > REISERFS_MAX_NAME(inode->i_sb-> s_blocksize)) { continue; } /* Ignore the .reiserfs_priv entry */ if (is_privroot_deh(inode, deh)) continue; ctx->pos = deh_offset(deh); d_ino = deh_objectid(deh); if (d_reclen <= 32) { local_buf = small_buf; } else { local_buf = kmalloc(d_reclen, GFP_NOFS); if (!local_buf) { pathrelse(&path_to_entry); ret = -ENOMEM; goto out; } if (item_moved(&tmp_ih, &path_to_entry)) { kfree(local_buf); goto research; } } /* * Note, that we copy name to user space via * temporary buffer (local_buf) because * filldir will block if user space buffer is * swapped out. At that time entry can move to * somewhere else */ memcpy(local_buf, d_name, d_reclen); /* * Since filldir might sleep, we can release * the write lock here for other waiters */ depth = reiserfs_write_unlock_nested(inode->i_sb); if (!dir_emit (ctx, local_buf, d_reclen, d_ino, DT_UNKNOWN)) { reiserfs_write_lock_nested(inode->i_sb, depth); if (local_buf != small_buf) { kfree(local_buf); } goto end; } reiserfs_write_lock_nested(inode->i_sb, depth); if (local_buf != small_buf) { kfree(local_buf); } /* deh_offset(deh) may be invalid now. */ next_pos = cur_pos + 1; if (item_moved(&tmp_ih, &path_to_entry)) { set_cpu_key_k_offset(&pos_key, next_pos); goto research; } } /* for */ } /* end of directory has been reached */ if (item_num != B_NR_ITEMS(bh) - 1) goto end; /* * item we went through is last item of node. Using right * delimiting key check is it directory end */ rkey = get_rkey(&path_to_entry, inode->i_sb); if (!comp_le_keys(rkey, &MIN_KEY)) { /* * set pos_key to key, that is the smallest and greater * that key of the last entry in the item */ set_cpu_key_k_offset(&pos_key, next_pos); continue; } /* end of directory has been reached */ if (COMP_SHORT_KEYS(rkey, &pos_key)) { goto end; } /* directory continues in the right neighboring block */ set_cpu_key_k_offset(&pos_key, le_key_k_offset(KEY_FORMAT_3_5, rkey)); } /* while */ end: ctx->pos = next_pos; pathrelse(&path_to_entry); reiserfs_check_path(&path_to_entry); out: reiserfs_write_unlock(inode->i_sb); return ret; }
/* 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 }
/* 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; }
/* NOTE: this only should be used to look for keys who exists */ int _search_by_entry_key (reiserfs_filsys_t fs, struct key * key, struct path * path) { struct buffer_head * bh; int item_pos; struct item_head * ih; struct key tmpkey; if (_search_by_key (fs, key, path) == ITEM_FOUND) { path->pos_in_item = 0; return POSITION_FOUND; } bh = get_bh (path); item_pos = get_item_pos (path); ih = get_ih (path); if (item_pos == 0) { /* key is less than the smallest key in the tree */ if (not_of_one_file (&(ih->ih_key), key)) /* there are no items of that directory */ return DIRECTORY_NOT_FOUND; if (!is_direntry_ih (ih)) reiserfs_panic ("_search_by_entry_key: found item is not of directory type %H", ih); /* key we looked for should be here */ path->pos_in_item = 0; return POSITION_NOT_FOUND; } /* take previous item */ item_pos --; ih --; PATH_LAST_POSITION (path) --; if (not_of_one_file (&(ih->ih_key), key) || !is_direntry_ih (ih)) { /* previous item belongs to another object or is stat data, check next item */ item_pos ++; PATH_LAST_POSITION (path) ++; if (item_pos < B_NR_ITEMS (bh)) { /* next item is in the same node */ ih ++; if (not_of_one_file (&(ih->ih_key), key)) { /* there are no items of that directory */ path->pos_in_item = 0; return DIRECTORY_NOT_FOUND; } if (!is_direntry_ih (ih)) reiserfs_panic ("_search_by_entry_key: %k is not a directory", key); } else { /* next item is in right neighboring node */ struct key * next_key = _get_rkey (path); if (next_key == 0 || not_of_one_file (next_key, key)) { /* there are no items of that directory */ path->pos_in_item = 0; return DIRECTORY_NOT_FOUND; } if (!is_direntry_key (next_key)) reiserfs_panic ("_search_by_entry_key: %k is not a directory", key); /* we got right delimiting key - search for it - the entry will be pasted in position 0 */ copy_key (&tmpkey, next_key); pathrelse (path); if (_search_by_key (fs, &tmpkey, path) != ITEM_FOUND || PATH_LAST_POSITION (path) != 0) reiserfs_panic ("_search_by_entry_key: item corresponding to delimiting key %k not found", &tmpkey); } /* next item is the part of this directory */ path->pos_in_item = 0; return POSITION_NOT_FOUND; } /* previous item is part of desired directory */ if (_bin_search (&(key->u.k_offset_v1.k_offset), B_I_DEH (bh, ih), ih_entry_count (ih), DEH_SIZE, &(path->pos_in_item), comp_dir_entries) == ITEM_FOUND) return POSITION_FOUND; return POSITION_NOT_FOUND; }
/* FIXME: we can improve fixing of broken keys: we can ssfe direct items which go after stat data and have broken keys */ static void pass0_correct_leaf (reiserfs_filsys_t fs, struct buffer_head * bh) { int i, j; struct item_head * ih; __u32 * ind_item; unsigned long unfm_ptr; int dirty = 0; start_again: ih = B_N_PITEM_HEAD (bh, 0); for (i = 0; i < node_item_number (bh); i ++, ih ++) { if (ih->ih_key.k_dir_id == 0 || ih->ih_key.k_objectid == 0) { /* sometimes stat datas get k_objectid==0 or k_dir_id==0 */ if (i == (node_item_number (bh) - 1)) { /* */ if (i == 0) { fsck_log ("block %lu: item %d: (%H) is alone in the block\n", bh->b_blocknr, i, ih); return; } /* delete last item */ delete_item (fs, bh, i - 1); return; } /* there is next item: if it is not stat data - take its k_dir_id and k_objectid. if key order will be still wrong - the changed item will be deleted */ if (!is_stat_data_ih (ih + 1)) { fsck_log ("block %lu: item %d: (%H) fixed to ", bh->b_blocknr, i, ih); ih->ih_key.k_dir_id = (ih + 1)->ih_key.k_dir_id; ih->ih_key.k_objectid = (ih + 1)->ih_key.k_objectid; set_offset (KEY_FORMAT_1, &ih->ih_key, 0); set_type (KEY_FORMAT_1, &ih->ih_key, TYPE_STAT_DATA); fsck_log ("(%H)\n", ih); dirty = 1; } else if (i == 0) { delete_item (fs, bh, i); goto start_again; } } /* this recovers corruptions like the below: 1774 1732 0 0 116262638 1732 1 3 1774 1736 0 0 */ if (i && is_stat_data_ih (ih - 1) && !is_stat_data_ih (ih)) { if (ih->ih_key.k_objectid != (ih - 1)->ih_key.k_objectid || ih->ih_key.k_dir_id != (ih - 1)->ih_key.k_dir_id || get_offset (&ih->ih_key) != 1) { if (is_direntry_ih (ih)) { fsck_log ("block %lu: item %d: no \".\" entry found in " "the first item of a directory\n", bh->b_blocknr, i); } else { fsck_log ("block %lu: item %d: (%H) fixed to ", bh->b_blocknr, i, ih); ih->ih_key.k_dir_id = (ih - 1)->ih_key.k_dir_id; ih->ih_key.k_objectid = (ih - 1)->ih_key.k_objectid; if (ih_item_len (ih - 1) == SD_SIZE) { /* stat data is new, therefore this item is new too */ set_offset (KEY_FORMAT_2, &(ih->ih_key), 1); if (ih_entry_count (ih) != 0xffff) set_type (KEY_FORMAT_2, &(ih->ih_key), TYPE_INDIRECT); else set_type (KEY_FORMAT_2, &(ih->ih_key), TYPE_DIRECT); set_ih_key_format (ih, KEY_FORMAT_2); } else { /* stat data is old, therefore this item is old too */ set_offset (KEY_FORMAT_1, &(ih->ih_key), 1); if (ih_entry_count (ih) != 0xffff) set_type (KEY_FORMAT_1, &(ih->ih_key), TYPE_INDIRECT); else set_type (KEY_FORMAT_1, &(ih->ih_key), TYPE_DIRECT); set_ih_key_format (ih, KEY_FORMAT_1); } fsck_log ("%H\n", ih); dirty = 1; } } } /* FIXME: corruptions like: 56702 66802 1 2 56702 65536 0 0 56702 66803 1 2 do not get recovered (both last items will be deleted) */ /* delete item if it is not in correct order of object items */ if (i && not_of_one_file (&ih->ih_key, &(ih - 1)->ih_key) && !is_stat_data_ih (ih)) { fsck_log ("block %lu: item %d: %H follows non stat item %H - deleted\n", bh->b_blocknr, i, ih, ih - 1); delete_item (fs, bh, i); goto start_again; } if (i && comp_keys (&(ih - 1)->ih_key, &ih->ih_key) != -1) { /* previous item has key not smaller than the key of currect item */ if (is_stat_data_ih (ih - 1) && !is_stat_data_ih (ih)) { /* fix key of stat data such as if it was stat data of that item */ fsck_log ("pass0: block %lu: %d-th item %k is out of order, made a stat data of %d-th (%k)\n", bh->b_blocknr, i - 1, &(ih - 1)->ih_key, i, &ih->ih_key); (ih - 1)->ih_key.k_dir_id = ih->ih_key.k_dir_id; (ih - 1)->ih_key.k_objectid = ih->ih_key.k_objectid; set_offset (KEY_FORMAT_1, &(ih - 1)->ih_key, 0); set_type (KEY_FORMAT_1, &(ih - 1)->ih_key, TYPE_STAT_DATA); dirty = 1; } else { /* ok, we have to delete one of these two - decide which one */ int retval; /* something will be deleted */ dirty = 1; retval = upper_correct (bh, ih - 1, i - 1); switch (retval) { case 0: /* delete upper item */ fsck_log ("pass0: block %lu: %d-th (upper) item (%k) is out of order, deleted\n", bh->b_blocknr, i - 1, &(ih - 1)->ih_key); delete_item (fs, bh, i - 1); goto start_again; case 1: /* delete lower item */ fsck_log ("pass0: block %lu: %d-th (lower) item (%k) is out of order, deleted\n", bh->b_blocknr, i, &ih->ih_key); delete_item (fs, bh, i); goto start_again; default: /* upper item was the first item of a node */ } retval = lower_correct (bh, ih, i); switch (retval) { case 0: /* delete lower item */ fsck_log ("pass0: block %lu: %d-th (lower) item (%k) is out of order, deleted\n", bh->b_blocknr, i, &ih->ih_key); delete_item (fs, bh, i); goto start_again; case 1: /* delete upper item */ fsck_log ("pass0: block %lu: %d-th (upper) item (%k) is out of order, deleted\n", bh->b_blocknr, i - 1, &(ih - 1)->ih_key); delete_item (fs, bh, i - 1); goto start_again; default: /* there wer only two items in a node, so we could not decide what to delete, go and ask user */ } fsck_log ("pass0: which of these items looks better (other will be deleted)?\n" "%H\n%H\n", ih - 1, ih); if (fsck_user_confirmed (fs, "1 or 2?", "1\n", 1)) delete_item (fs, bh, i - 1); else delete_item (fs, bh, i); goto start_again; } } if (is_stat_data_ih (ih) && (ih_item_len (ih) != SD_SIZE && ih_item_len (ih) != SD_V1_SIZE)) { fsck_log ("pass0: block %lu, stat data of wrong length %H - deleted\n", bh, ih); delete_item (fs, bh, i); goto start_again; } dirty += correct_key_format (ih); if (is_stat_data_ih (ih)) { ;/*correct_stat_data (fs, bh, i);*/ } if (is_direntry_ih (ih)) { verify_directory_item (fs, bh, i); continue; } if (!is_indirect_ih (ih)) continue; ind_item = (__u32 *)B_I_PITEM (bh, ih); for (j = 0; j < I_UNFM_NUM (ih); j ++) { unfm_ptr = le32_to_cpu (ind_item [j]); if (!unfm_ptr) continue; if (fsck_mode (fs) == FSCK_ZERO_FILES) { /* FIXME: this is temporary mode of fsck */ ind_item [j] = 0; reiserfs_bitmap_clear_bit (fsck_new_bitmap(fs), unfm_ptr); tmp_zeroed ++; dirty = 1; continue; } if (not_data_block (fs, unfm_ptr) || /* journal area or bitmap or super block */ unfm_ptr >= SB_BLOCK_COUNT (fs)) {/* garbage in pointer */ stats (fs)->wrong_pointers ++; /* fsck_log ("pass0: %d-th pointer (%lu) in item %k (leaf block %lu) is wrong\n", j, unfm_ptr, &ih->ih_key, bh->b_blocknr); */ ind_item [j] = 0; dirty = 1; continue; } #if 0 if (!was_block_used (unfm_ptr)) { /* this will get to a pool of allocable blocks */ ind_item [j] = 0; dirty = 1; stat_wrong_pointer_found (fs); continue; } #endif /* mark block in bitmaps of unformatted nodes */ register_unfm (unfm_ptr); } } /* mark all objectids in use */ ih = B_N_PITEM_HEAD (bh, 0); for (i = 0; i < node_item_number (bh); i ++, ih ++) { mark_objectid_really_used (proper_id_map (fs), le32_to_cpu (ih->ih_key.k_dir_id)); mark_objectid_really_used (proper_id_map (fs), le32_to_cpu (ih->ih_key.k_objectid)); } if (node_item_number (bh) < 1) { /* pass 1 will skip this */ stats(fs)->all_contents_removed ++; fsck_log ("pass0: block %lu got all items deleted\n", bh->b_blocknr); } else { /* pass1 will use this bitmap */ pass0_mark_leaf (bh->b_blocknr); } if (dirty) { stats(fs)->leaves_corrected ++; mark_buffer_dirty (bh); } } static int is_bad_sd (struct item_head * ih, char * item) { struct stat_data * sd = (struct stat_data *)item; if (le32_to_cpu(ih->ih_key.u.k_offset_v1.k_offset) || le32_to_cpu(ih->ih_key.u.k_offset_v1.k_uniqueness)) { reiserfs_warning (stderr, "Bad SD? %H\n", ih); return 1; } if (ih_item_len (ih) == SD_V1_SIZE) { /* looks like old stat data */ if (ih_key_format (ih) != KEY_FORMAT_1) fsck_log ("item %H has wrong format\n", ih); return 0; } if (!S_ISDIR (sd_v2_mode(sd)) && !S_ISREG(sd_v2_mode(sd)) && !S_ISCHR (sd_v2_mode(sd)) && !S_ISBLK(sd_v2_mode(sd)) && !S_ISLNK (sd_v2_mode(sd)) && !S_ISFIFO(sd_v2_mode(sd)) && !S_ISSOCK(sd_v2_mode(sd))) { /*fsck_log ("file %k unexpected mode encountered 0%o\n", &ih->ih_key, sd_v2_mode(sd))*/; } return 0; } int is_bad_directory (struct item_head * ih, char * item, int dev, int blocksize) { int i; char * name; int namelen, entrylen; struct reiserfs_de_head * deh = (struct reiserfs_de_head *)item; __u32 prev_offset = 0; __u16 prev_location = ih_item_len (ih); int min_entry_size = 1;/* we have no way to understand whether the filesystem were created in 3.6 format or converted to it. So, we assume that minimal name length is 1 */ if (ih_item_len (ih) / (DEH_SIZE + min_entry_size) < ih_entry_count (ih)) /* entry count is too big */ return 1; for (i = 0; i < ih_entry_count (ih); i ++, deh ++) { entrylen = entry_length(ih, deh, i); if (entrylen > REISERFS_MAX_NAME_LEN (blocksize)) { return 1; } if (deh_offset (deh) <= prev_offset) { return 1; } prev_offset = deh_offset (deh); if (deh_location(deh) + entrylen != prev_location) { return 1; } prev_location = deh_location (deh); namelen = name_length (ih, deh, i); name = name_in_entry (deh, i); if (!is_properly_hashed (fs, name, namelen, deh_offset (deh))) { return 1; } } return 0; } /* change incorrect block adresses by 0. Do not consider such item as incorrect */ static int is_bad_indirect (struct item_head * ih, char * item, int dev, int blocksize) { int i; int bad = 0; int blocks; if (ih_item_len(ih) % UNFM_P_SIZE) { fsck_log ("is_bad_indirect: indirect item of %H of invalid length\n", ih); return 1; } blocks = SB_BLOCK_COUNT (fs); for (i = 0; i < I_UNFM_NUM (ih); i ++) { __u32 * ind = (__u32 *)item; if (le32_to_cpu (ind[i]) >= blocks) { bad ++; fsck_log ("is_bad_indirect: %d-th pointer of item %H looks bad (%lu)\n", i, ih, le32_to_cpu (ind [i])); continue; } } return bad; }