summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2008-03-13 23:05:00 -0400
committerTheodore Ts'o <tytso@mit.edu>2008-03-13 23:05:00 -0400
commit7cadc57780f3e3e8e644e8976e11a336902d4a25 (patch)
treefadbaacb706ed50e7f44a8c11797fc4c49aaea07
parent51b263e3690ba3136fe63e5c722e0593772620e2 (diff)
downloade2fsprogs-7cadc57780f3e3e8e644e8976e11a336902d4a25.tar.gz
e2fsck: Support long symlinks which use extents
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
-rw-r--r--e2fsck/e2fsck.h2
-rw-r--r--e2fsck/pass1.c32
-rw-r--r--e2fsck/pass2.c2
3 files changed, 31 insertions, 5 deletions
diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h
index be6efe15..21208e0b 100644
--- a/e2fsck/e2fsck.h
+++ b/e2fsck/e2fsck.h
@@ -429,7 +429,7 @@ extern void e2fsck_setup_tdb_icount(e2fsck_t ctx, int flags,
extern void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int bool);
extern int e2fsck_pass1_check_device_inode(ext2_filsys fs,
struct ext2_inode *inode);
-extern int e2fsck_pass1_check_symlink(ext2_filsys fs,
+extern int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino,
struct ext2_inode *inode, char *buf);
extern void e2fsck_clear_inode(e2fsck_t ctx, ext2_ino_t ino,
struct ext2_inode *inode, int restart_flag,
diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index c598205e..86389898 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -163,17 +163,42 @@ int e2fsck_pass1_check_device_inode(ext2_filsys fs EXT2FS_ATTR((unused)),
* Check to make sure a symlink inode is real. Returns 1 if the symlink
* checks out, 0 if not.
*/
-int e2fsck_pass1_check_symlink(ext2_filsys fs, struct ext2_inode *inode,
- char *buf)
+int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode *inode, char *buf)
{
unsigned int len;
int i;
blk_t blocks;
+ ext2_extent_handle_t handle;
+ struct ext2_extent_info info;
+ struct ext2fs_extent extent;
if ((inode->i_size_high || inode->i_size == 0) ||
(inode->i_flags & EXT2_INDEX_FL))
return 0;
+ if (inode->i_flags & EXT4_EXTENTS_FL) {
+ if (inode->i_size > fs->blocksize)
+ return 0;
+ if (ext2fs_extent_open(fs, ino, &handle))
+ return 0;
+ i = 0;
+ if (ext2fs_extent_get_info(handle, &info) ||
+ (info.num_entries != 1) ||
+ (info.max_depth != 0))
+ goto exit_extent;
+ if (ext2fs_extent_get(handle, EXT2_EXTENT_ROOT, &extent) ||
+ (extent.e_lblk != 0) ||
+ (extent.e_len != 1) ||
+ (extent.e_pblk < fs->super->s_first_data_block) ||
+ (extent.e_pblk >= fs->super->s_blocks_count))
+ goto exit_extent;
+ i = 1;
+ exit_extent:
+ ext2fs_extent_free(handle);
+ return i;
+ }
+
blocks = ext2fs_inode_data_blocks(fs, inode);
if (blocks) {
if ((inode->i_size >= fs->blocksize) ||
@@ -910,7 +935,8 @@ void e2fsck_pass1(e2fsck_t ctx)
check_size(ctx, &pctx);
ctx->fs_blockdev_count++;
} else if (LINUX_S_ISLNK (inode->i_mode) &&
- e2fsck_pass1_check_symlink(fs, inode, block_buf)) {
+ e2fsck_pass1_check_symlink(fs, ino, inode,
+ block_buf)) {
check_immutable(ctx, &pctx);
ctx->fs_symlinks_count++;
if (ext2fs_inode_data_blocks(fs, inode) == 0) {
diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
index a3367552..56f352bd 100644
--- a/e2fsck/pass2.c
+++ b/e2fsck/pass2.c
@@ -1218,7 +1218,7 @@ extern int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
&& !e2fsck_pass1_check_device_inode(fs, &inode))
problem = PR_2_BAD_SOCKET;
else if (LINUX_S_ISLNK(inode.i_mode)
- && !e2fsck_pass1_check_symlink(fs, &inode, buf)) {
+ && !e2fsck_pass1_check_symlink(fs, ino, &inode, buf)) {
problem = PR_2_INVALID_SYMLINK;
}