ext2fs_dblist_sort@Base 1.37
ext2fs_default_journal_size@Base 1.40
ext2fs_descriptor_block_loc@Base 1.37
+ ext2fs_get_rec_len@Base 1.41.7
+ ext2fs_set_rec_len@Base 1.41.7
ext2fs_dir_iterate2@Base 1.37
ext2fs_dir_iterate@Base 1.37
ext2fs_dirhash@Base 1.37
char tmp[EXT2_NAME_LEN + 16];
blk_t pblk;
ext2_dirhash_t hash, minor_hash;
- int rec_len, hash_alg;
+ unsigned int rec_len;
+ int hash_alg;
errcode = ext2fs_bmap(fs, ino, inode, buf, 0, blk, &pblk);
if (errcode) {
while (offset < fs->blocksize) {
dirent = (struct ext2_dir_entry *) (buf + offset);
- rec_len = (dirent->rec_len || fs->blocksize < 65536) ?
- dirent->rec_len : 65536;
+ errcode = ext2fs_get_rec_len(fs, dirent, &rec_len);
+ if (errcode) {
+ com_err("htree_dump_leaf_inode", errcode,
+ "while getting rec_len for block %lu",
+ (unsigned long) blk);
+ return;
+ }
if (((offset + rec_len) > fs->blocksize) ||
(rec_len < 8) ||
((rec_len % 4) != 0) ||
struct ext2_dir_entry *dirent;
errcode_t errcode;
unsigned int offset = 0;
- int rec_len;
+ unsigned int rec_len;
if (blockcnt < 0)
return 0;
while (offset < fs->blocksize) {
dirent = (struct ext2_dir_entry *) (p->buf + offset);
- rec_len = (dirent->rec_len || fs->blocksize < 65536) ?
- dirent->rec_len : 65536;
+ errcode = ext2fs_get_rec_len(fs, dirent, &rec_len);
+ if (errcode) {
+ com_err("htree_dump_leaf_inode", errcode,
+ "while getting rec_len for block %lu",
+ (unsigned long) *blocknr);
+ return;
+ }
if (dirent->inode &&
p->len == (dirent->name_len & 0xFF) &&
strncmp(p->search_name, dirent->name,
/*
* This function expands '%dX' expressions
*/
-static _INLINE_ void expand_dirent_expression(char ch,
+static _INLINE_ void expand_dirent_expression(ext2_filsys fs, char ch,
struct problem_context *ctx)
{
struct ext2_dir_entry *dirent;
+ unsigned int rec_len;
int len;
if (!ctx || !ctx->dirent)
len = dirent->name_len & 0xFF;
if (len > EXT2_NAME_LEN)
len = EXT2_NAME_LEN;
- if (len > dirent->rec_len)
- len = dirent->rec_len;
+ if ((ext2fs_get_rec_len(fs, dirent, &rec_len) == 0) &&
+ (len > rec_len))
+ len = rec_len;
safe_print(dirent->name, len);
break;
case 'r':
- printf("%u", dirent->rec_len);
+ (void) ext2fs_get_rec_len(fs, dirent, &rec_len);
+ printf("%u", rec_len);
break;
case 'l':
printf("%u", dirent->name_len & 0xFF);
expand_inode_expression(*cp, pctx);
} else if (cp[0] == '%' && cp[1] == 'D') {
cp += 2;
- expand_dirent_expression(*cp, pctx);
+ expand_dirent_expression(fs, *cp, pctx);
} else if ((cp[0] == '%')) {
cp++;
expand_percent_expression(fs, *cp, pctx);
return;
dirent = (struct ext2_dir_entry *) buf;
- rec_len = (dirent->rec_len || ctx->fs->blocksize < 65536) ?
- dirent->rec_len : 65536;
+ retval = ext2fs_get_rec_len(ctx->fs, dirent, &rec_len);
+ if (retval)
+ return;
if (((dirent->name_len & 0xFF) != 1) ||
(dirent->name[0] != '.') ||
(dirent->inode != pctx->ino) ||
return;
dirent = (struct ext2_dir_entry *) (buf + rec_len);
- rec_len = (dirent->rec_len || ctx->fs->blocksize < 65536) ?
- dirent->rec_len : 65536;
+ retval = ext2fs_get_rec_len(ctx->fs, dirent, &rec_len);
+ if (retval)
+ return;
if (((dirent->name_len & 0xFF) != 2) ||
(dirent->name[0] != '.') ||
(dirent->name[1] != '.') ||
ext2_ino_t ino, struct problem_context *pctx)
{
struct ext2_dir_entry *nextdir;
+ unsigned int rec_len, new_len;
int status = 0;
int created = 0;
- int rec_len, new_len;
int problem = 0;
if (!dirent->inode)
else if (dirent->name[1] != '\0')
problem = PR_2_DOT_NULL_TERM;
- rec_len = (dirent->rec_len || ctx->fs->blocksize < 65536) ?
- dirent->rec_len : 65536;
+ (void) ext2fs_get_rec_len(ctx->fs, dirent, &rec_len);
if (problem) {
if (fix_problem(ctx, problem, pctx)) {
if (rec_len < 12)
nextdir = (struct ext2_dir_entry *)
((char *) dirent + 12);
dirent->rec_len = 12;
- nextdir->rec_len = new_len;
+ (void) ext2fs_set_rec_len(ctx->fs, new_len,
+ nextdir);
nextdir->inode = 0;
nextdir->name_len = 0;
status = 1;
else if (dirent->name[2] != '\0')
problem = PR_2_DOT_DOT_NULL_TERM;
- rec_len = (dirent->rec_len || ctx->fs->blocksize < 65536) ?
- dirent->rec_len : 65536;
+ (void) ext2fs_get_rec_len(ctx->fs, dirent, &rec_len);
if (problem) {
if (fix_problem(ctx, problem, pctx)) {
if (rec_len < 12)
unsigned int *offset)
{
char *cp = (char *) dirent;
- int left, rec_len;
+ int left;
+ unsigned int rec_len, prev_rec_len;
unsigned int name_len = dirent->name_len & 0xFF;
- rec_len = (dirent->rec_len || fs->blocksize < 65536) ?
- dirent->rec_len : 65536;
+ (void) ext2fs_get_rec_len(fs, dirent, &rec_len);
left = fs->blocksize - *offset - rec_len;
/*
* record length.
*/
if ((left < 0) &&
- (name_len + 8 <= rec_len + (unsigned) left) &&
+ ((int) rec_len + left > 8) &&
+ (name_len + 8 <= (int) rec_len + left) &&
dirent->inode <= fs->super->s_inodes_count &&
strnlen(dirent->name, name_len) == name_len) {
- dirent->rec_len += left;
+ (void) ext2fs_set_rec_len(fs, (int) rec_len + left, dirent);
return;
}
/*
*/
if (prev && rec_len && (rec_len % 4) == 0 &&
(*offset + rec_len <= fs->blocksize)) {
- prev->rec_len += rec_len;
+ (void) ext2fs_get_rec_len(fs, prev, &prev_rec_len);
+ prev_rec_len += rec_len;
+ (void) ext2fs_set_rec_len(fs, prev_rec_len, prev);
*offset += rec_len;
return;
}
* new empty directory entry the rest of the directory block.
*/
if (prev) {
- prev->rec_len += fs->blocksize - *offset;
+ (void) ext2fs_get_rec_len(fs, prev, &prev_rec_len);
+ prev_rec_len += fs->blocksize - *offset;
+ (void) ext2fs_set_rec_len(fs, prev_rec_len, prev);
*offset = fs->blocksize;
} else {
- dirent->rec_len = fs->blocksize - *offset;
+ rec_len = fs->blocksize - *offset;
+ (void) ext2fs_set_rec_len(fs, rec_len, dirent);
dirent->name_len = 0;
dirent->inode = 0;
}
dx_db->max_hash = 0;
dirent = (struct ext2_dir_entry *) buf;
- rec_len = (dirent->rec_len || fs->blocksize < 65536) ?
- dirent->rec_len : 65536;
+ (void) ext2fs_get_rec_len(fs, dirent, &rec_len);
limit = (struct ext2_dx_countlimit *) (buf+8);
if (db->blockcnt == 0) {
root = (struct ext2_dx_root_info *) (buf + 24);
problem = 0;
dirent = (struct ext2_dir_entry *) (buf + offset);
- rec_len = (dirent->rec_len || fs->blocksize < 65536) ?
- dirent->rec_len : 65536;
+ (void) ext2fs_get_rec_len(fs, dirent, &rec_len);
cd->pctx.dirent = dirent;
cd->pctx.num = offset;
if (((offset + rec_len) > fs->blocksize) ||
next:
prev = dirent;
if (dir_modified)
- rec_len = (dirent->rec_len || fs->blocksize < 65536) ?
- dirent->rec_len : 65536;
+ (void) ext2fs_get_rec_len(fs, dirent, &rec_len);
offset += rec_len;
dot_state++;
} while (offset < fs->blocksize);
struct hash_entry *new_array, *ent;
struct ext2_dir_entry *dirent;
char *dir;
- unsigned int offset, dir_offset;
- int rec_len, hash_alg;
+ unsigned int offset, dir_offset, rec_len;
+ int hash_alg;
if (blockcnt < 0)
return 0;
if (HOLE_BLKADDR(*block_nr)) {
memset(dir, 0, fs->blocksize);
dirent = (struct ext2_dir_entry *) dir;
- dirent->rec_len = fs->blocksize;
+ (void) ext2fs_set_rec_len(fs, fs->blocksize, dirent);
} else {
fd->err = ext2fs_read_dir_block(fs, *block_nr, dir);
if (fd->err)
dir_offset = 0;
while (dir_offset < fs->blocksize) {
dirent = (struct ext2_dir_entry *) (dir + dir_offset);
- rec_len = (dirent->rec_len || fs->blocksize < 65536) ?
- dirent->rec_len : 65536;
+ (void) ext2fs_get_rec_len(fs, dirent, &rec_len);
if (((dir_offset + rec_len) > fs->blocksize) ||
(rec_len < 8) ||
((rec_len % 4) != 0) ||
char *block_start;
struct hash_entry *ent;
struct ext2_dir_entry *dirent;
- int i, rec_len, left;
+ unsigned int rec_len, prev_rec_len;
+ int i, left;
ext2_dirhash_t prev_hash;
int offset, slack;
if ((retval = get_next_block(fs, outdir, &block_start)))
return retval;
dirent = (struct ext2_dir_entry *) block_start;
+ prev_rec_len = 0;
left = fs->blocksize;
slack = fd->compress ? 12 :
(fs->blocksize * ctx->htree_slack_percentage)/100;
continue;
rec_len = EXT2_DIR_REC_LEN(ent->dir->name_len & 0xFF);
if (rec_len > left) {
- if (left)
- dirent->rec_len += left;
+ if (left) {
+ left += prev_rec_len;
+ retval = ext2fs_set_rec_len(fs, left, dirent);
+ if (retval)
+ return retval;
+ }
if ((retval = get_next_block(fs, outdir,
&block_start)))
return retval;
}
dirent->inode = ent->dir->inode;
dirent->name_len = ent->dir->name_len;
- dirent->rec_len = rec_len;
+ retval = ext2fs_set_rec_len(fs, rec_len, dirent);
+ if (retval)
+ return retval;
+ prev_rec_len = rec_len;
memcpy(dirent->name, ent->dir->name, dirent->name_len & 0xFF);
offset += rec_len;
left -= rec_len;
if (left < slack) {
- dirent->rec_len += left;
+ prev_rec_len += left;
+ retval = ext2fs_set_rec_len(fs, prev_rec_len, dirent);
+ if (retval)
+ return retval;
offset += left;
left = 0;
}
prev_hash = ent->hash;
}
if (left)
- dirent->rec_len += left;
+ retval = ext2fs_set_rec_len(fs, rec_len + left, dirent);
- return 0;
+ return retval;
}
memset(buf, 0, fs->blocksize);
dir = (struct ext2_dir_entry *) buf;
dir->inode = 0;
- dir->rec_len = fs->blocksize;
+ (void) ext2fs_set_rec_len(fs, fs->blocksize, dir);
limits = (struct ext2_dx_countlimit *) (buf+8);
limits->limit = (fs->blocksize - 8) / sizeof(struct ext2_dx_entry);
#include "ext2_fs.h"
#include "ext2fsP.h"
+#define EXT4_MAX_REC_LEN ((1<<16)-1)
+
+errcode_t ext2fs_get_rec_len(ext2_filsys fs,
+ struct ext2_dir_entry *dirent,
+ unsigned int *rec_len)
+{
+ unsigned int len = dirent->rec_len;
+
+ if (len == EXT4_MAX_REC_LEN || len == 0)
+ *rec_len = fs->blocksize;
+ else
+ *rec_len = (len & 65532) | ((len & 3) << 16);
+ return 0;
+}
+
+errcode_t ext2fs_set_rec_len(ext2_filsys fs,
+ unsigned int len,
+ struct ext2_dir_entry *dirent)
+{
+ if ((len > fs->blocksize) || (fs->blocksize > (1 << 18)) || (len & 3))
+ return EINVAL;
+ if (len < 65536) {
+ dirent->rec_len = len;
+ return 0;
+ }
+ if (len == fs->blocksize) {
+ if (fs->blocksize == 65536)
+ dirent->rec_len = EXT4_MAX_REC_LEN;
+ else
+ dirent->rec_len = 0;
+ } else
+ dirent->rec_len = (len & 65532) | ((len >> 16) & 3);
+ return 0;
+}
+
/*
* This function checks to see whether or not a potential deleted
* directory entry looks valid. What we do is check the deleted entry
int final_offset)
{
struct ext2_dir_entry *dirent;
- int rec_len;
+ unsigned int rec_len;
while (offset < final_offset) {
dirent = (struct ext2_dir_entry *)(buf + offset);
- rec_len = (dirent->rec_len || fs->blocksize < 65536) ?
- dirent->rec_len : 65536;
+ if (ext2fs_get_rec_len(fs, dirent, &rec_len))
+ return 0;
offset += rec_len;
if ((rec_len < 8) ||
((rec_len % 4) != 0) ||
int ret = 0;
int changed = 0;
int do_abort = 0;
- int rec_len, entry, size;
+ unsigned int rec_len;
+ int entry, size;
struct ext2_dir_entry *dirent;
if (blockcnt < 0)
while (offset < fs->blocksize) {
dirent = (struct ext2_dir_entry *) (ctx->buf + offset);
- rec_len = (dirent->rec_len || fs->blocksize < 65536) ?
- dirent->rec_len : 65536;
+ if (ext2fs_get_rec_len(fs, dirent, &rec_len))
+ return BLOCK_ABORT;
if (((offset + rec_len) > fs->blocksize) ||
(rec_len < 8) ||
((rec_len % 4) != 0) ||
entry++;
if (ret & DIRENT_CHANGED) {
- rec_len = (dirent->rec_len || fs->blocksize < 65536) ?
- dirent->rec_len : 65536;
+ if (ext2fs_get_rec_len(fs, dirent, &rec_len))
+ return BLOCK_ABORT;
changed++;
}
if (ret & DIRENT_ABORT) {
if (flags & EXT2_DIRBLOCK_V2_STRUCT)
dirent->name_len = ext2fs_swab16(dirent->name_len);
#endif
- rec_len = (dirent->rec_len || fs->blocksize < 65536) ?
- dirent->rec_len : 65536;
+ if ((retval = ext2fs_get_rec_len(fs, dirent, &rec_len)) != 0)
+ return retval;
if ((rec_len < 8) || (rec_len % 4)) {
rec_len = 8;
retval = EXT2_ET_DIR_CORRUPTED;
errcode_t retval;
char *p, *end;
char *buf = 0;
- int rec_len;
+ unsigned int rec_len;
struct ext2_dir_entry *dirent;
retval = ext2fs_get_mem(fs->blocksize, &buf);
end = buf + fs->blocksize;
while (p < end) {
dirent = (struct ext2_dir_entry *) p;
- rec_len = (dirent->rec_len || fs->blocksize < 65536) ?
- dirent->rec_len : 65536;
+ if ((retval = ext2fs_get_rec_len(fs, dirent, &rec_len)) != 0)
+ return retval;
if ((rec_len < 8) ||
(rec_len % 4)) {
ext2fs_free_mem(&buf);
/* dir_iterate.c */
+extern errcode_t ext2fs_get_rec_len(ext2_filsys fs,
+ struct ext2_dir_entry *dirent,
+ unsigned int *rec_len);
+extern errcode_t ext2fs_set_rec_len(ext2_filsys fs,
+ unsigned int len,
+ struct ext2_dir_entry *dirent);
extern errcode_t ext2fs_dir_iterate(ext2_filsys fs,
ext2_ino_t dir,
int flags,
#include "ext2fs.h"
struct link_struct {
+ ext2_filsys fs;
const char *name;
int namelen;
ext2_ino_t inode;
int flags;
int done;
unsigned int blocksize;
+ errcode_t err;
struct ext2_super_block *sb;
};
{
struct link_struct *ls = (struct link_struct *) priv_data;
struct ext2_dir_entry *next;
- int rec_len, min_rec_len, curr_rec_len;
+ unsigned int rec_len, min_rec_len, curr_rec_len;
int ret = 0;
rec_len = EXT2_DIR_REC_LEN(ls->namelen);
- curr_rec_len = (dirent->rec_len || ls->blocksize < 65536) ?
- dirent->rec_len : 65536;
+ ls->err = ext2fs_get_rec_len(ls->fs, dirent, &curr_rec_len);
+ if (ls->err)
+ return DIRENT_ABORT;
/*
* See if the following directory entry (if any) is unused;
if ((offset + curr_rec_len < blocksize - 8) &&
(next->inode == 0) &&
(offset + curr_rec_len + next->rec_len <= blocksize)) {
- dirent->rec_len += next->rec_len;
- curr_rec_len = dirent->rec_len;
+ curr_rec_len += next->rec_len;
+ ls->err = ext2fs_set_rec_len(ls->fs, curr_rec_len, dirent);
+ if (ls->err)
+ return DIRENT_ABORT;
ret = DIRENT_CHANGED;
}
if (curr_rec_len < (min_rec_len + rec_len))
return ret;
rec_len = curr_rec_len - min_rec_len;
- dirent->rec_len = min_rec_len;
+ ls->err = ext2fs_set_rec_len(ls->fs, min_rec_len, dirent);
+ if (ls->err)
+ return DIRENT_ABORT;
next = (struct ext2_dir_entry *) (buf + offset +
dirent->rec_len);
next->inode = 0;
next->name_len = 0;
- next->rec_len = rec_len;
+ ls->err = ext2fs_set_rec_len(ls->fs, rec_len, next);
+ if (ls->err)
+ return DIRENT_ABORT;
return DIRENT_CHANGED;
}
if (!(fs->flags & EXT2_FLAG_RW))
return EXT2_ET_RO_FILSYS;
+ ls.fs = fs;
ls.name = name;
ls.namelen = name ? strlen(name) : 0;
ls.inode = ino;
ls.done = 0;
ls.sb = fs->super;
ls.blocksize = fs->blocksize;
+ ls.err = 0;
retval = ext2fs_dir_iterate(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY,
0, link_proc, &ls);
if (retval)
return retval;
+ if (ls.err)
+ return ls.err;
if (!ls.done)
return EXT2_ET_DIR_NO_SPACE;
return retval;
memset(buf, 0, fs->blocksize);
dir = (struct ext2_dir_entry *) buf;
- dir->rec_len = fs->blocksize;
+
+ retval = ext2fs_set_rec_len(fs, fs->blocksize, dir);
+ if (retval)
+ return retval;
if (dir_ino) {
if (fs->super->s_feature_incompat &
* Set up entry for '..'
*/
dir = (struct ext2_dir_entry *) (buf + dir->rec_len);
- dir->rec_len = rec_len;
+ retval = ext2fs_set_rec_len(fs, rec_len, dir);
+ if (retval)
+ return retval;
dir->inode = parent_ino;
dir->name_len = 2 | filetype;
dir->name[0] = '.';
int name_id[256];
+#define EXT4_MAX_REC_LEN ((1<<16)-1)
+
static void scramble_dir_block(ext2_filsys fs, blk_t blk, char *buf)
{
char *p, *end, *cp;
struct ext2_dir_entry_2 *dirent;
- int rec_len, id, len;
+ unsigned int rec_len;
+ int id, len;
end = buf + fs->blocksize;
for (p = buf; p < end-8; p += rec_len) {
#ifdef WORDS_BIGENDIAN
rec_len = ext2fs_swab16(rec_len);
#endif
- rec_len = (rec_len || fs->blocksize < 65536) ?
- rec_len : 65536;
+ if (rec_len == EXT4_MAX_REC_LEN || rec_len == 0)
+ rec_len = fs->blocksize;
+ else
+ rec_len = (rec_len & 65532) | ((rec_len & 3) << 16);
#if 0
printf("rec_len = %d, name_len = %d\n", rec_len, dirent->name_len);
#endif
"bad rec_len (%d)\n", (unsigned long) blk,
rec_len);
rec_len = end - p;
+ (void) ext2fs_set_rec_len(fs, rec_len,
+ (struct ext2_dir_entry *) dirent);
#ifdef WORDS_BIGENDIAN
- dirent->rec_len = ext2fs_swab16(rec_len);
+ dirent->rec_len = ext2fs_swab16(dirent->rec_len);
#endif
continue;
}
Clone multiply-claimed blocks? yes
Pass 2: Checking directory structure
-Directory inode 11, block 12, offset 0: directory corrupted
-Salvage? yes
+Entry '' in /lost+found (11) has invalid inode #: 24.
+Clear? yes
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Clone multiply-claimed blocks? yes
Pass 2: Checking directory structure
-Directory inode 12, block 1, offset 0: directory corrupted
-Salvage? yes
-
-Directory inode 12, block 2, offset 0: directory corrupted
-Salvage? yes
+Entry '' in ??? (12) has invalid inode #: 4194303.
+Clear? yes
-Directory inode 12, block 3, offset 0: directory corrupted
-Salvage? yes
+Entry 'M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?M-^?' in ??? (12) has invalid inode #: 16383.
+Clear? yes
Entry '' in ??? (12) has a zero-length name.
Clear? yes