From: Sheng Yong <shengyo...@xiaomi.com>
This patch adds a new member `filename' in inject_dentry to inject
dentry filename. The dentry is specified by nid option.
Note that '.' and '..' dentries are special, because they are not in the
parent directory of nid. So this patch also adds a new option `--dots'
to inject these two dentries.
Signed-off-by: Sheng Yong <shengyo...@xiaomi.com>
---
fsck/inject.c | 94 ++++++++++++++++++++++++++++++++++++++++-------
fsck/inject.h | 1 +
man/inject.f2fs.8 | 12 +++++-
3 files changed, 92 insertions(+), 15 deletions(-)
diff --git a/fsck/inject.c b/fsck/inject.c
index 8c2f8c5dc332..5eb913fefad7 100644
--- a/fsck/inject.c
+++ b/fsck/inject.c
@@ -105,7 +105,7 @@ void inject_usage(void)
MSG(0, " --sit <0|1|2> --mb <name> --blk <blk> [--idx <index>] --val
<value> inject sit entry\n");
MSG(0, " --ssa --mb <name> --blk <blk> [--idx <index>] --val <value> inject
summary entry\n");
MSG(0, " --node --mb <name> --nid <nid> [--idx <index>] --val <value>
inject node\n");
- MSG(0, " --dent --mb <name> --nid <ino> [--idx <index>] --val <value>
inject ino's dentry\n");
+ MSG(0, " --dent --mb <name> --nid <ino> [--dots <1|2>] --val/str
<value/string> inject ino's dentry\n");
MSG(0, " --dry-run do not really inject\n");
exit(1);
@@ -212,12 +212,16 @@ static void inject_node_usage(void)
static void inject_dent_usage(void)
{
- MSG(0, "inject.f2fs --dent --mb <name> --nid <nid> [--idx <index>] --val
<value> inject dentry\n");
+ MSG(0, "inject.f2fs --dent --mb <name> --nid <nid> [--dots <1|2>] --val/str
<value/string> inject dentry\n");
+ MSG(0, "[dots]:\n");
+ MSG(0, " 1: inject \".\" in directory which is specified by nid\n");
+ MSG(0, " 2: inject \"..\" in directory which is specified by nid\n");
MSG(0, "[mb]:\n");
MSG(0, " d_bitmap: inject dentry block d_bitmap of nid\n");
MSG(0, " d_hash: inject dentry hash\n");
MSG(0, " d_ino: inject dentry ino\n");
MSG(0, " d_ftype: inject dentry ftype\n");
+ MSG(0, " filename: inject dentry filename, its hash and len are updated
implicitly\n");
}
int inject_parse_options(int argc, char *argv[], struct inject_option *opt)
@@ -241,6 +245,7 @@ int inject_parse_options(int argc, char *argv[], struct
inject_option *opt)
{"ssa", no_argument, 0, 12},
{"node", no_argument, 0, 13},
{"dent", no_argument, 0, 14},
+ {"dots", required_argument, 0, 15},
{0, 0, 0, 0}
};
@@ -339,6 +344,14 @@ int inject_parse_options(int argc, char *argv[], struct inject_option *opt)
opt->dent = true;
MSG(0, "Info: inject dentry\n");
break;
+ case 15:
+ opt->dots = atoi(optarg);
+ if (opt->dots != TYPE_DOT &&
+ opt->dots != TYPE_DOTDOT)
+ return -ERANGE;
+ MSG(0, "Info: inject %s dentry\n",
+ opt->dots == TYPE_DOT ? "dot" : "dotdot");
+ break;
case 'd':
if (optarg[0] == '-' || !is_digits(optarg))
return EWRONG_OPT;
@@ -371,6 +384,9 @@ int inject_parse_options(int argc, char *argv[], struct
inject_option *opt)
} else if (opt->dent) {
inject_dent_usage();
exit(0);
+ } else {
+ MSG(0, "\tError: Wrong option -%c (%d) %s\n",
+ o, o, optarg);
}
return EUNKNOWN_OPT;
}
@@ -1146,12 +1162,12 @@ static int find_dir_entry(struct f2fs_dentry_ptr *d,
nid_t ino)
}
de = &d->dentry[slot];
- if (le32_to_cpu(de->ino) == ino && de->hash_code != 0)
- return slot;
if (de->name_len == 0) {
slot++;
continue;
}
+ if (le32_to_cpu(de->ino) == ino)
+ return slot;
slot += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
}
@@ -1164,14 +1180,15 @@ static int inject_dentry(struct f2fs_sb_info *sbi, struct inject_option *opt)
struct f2fs_node *node_blk = NULL;
struct f2fs_inode *inode;
struct f2fs_dentry_ptr d;
- void *inline_dentry;
+ void *buf = NULL, *inline_dentry;
struct f2fs_dentry_block *dent_blk = NULL;
block_t addr = 0;
- void *buf = NULL;
struct f2fs_dir_entry *dent = NULL;
struct dnode_of_data dn;
nid_t pino;
- int slot = -ENOENT, ret;
+ int slot = -ENOENT, namelen, namecap, ret;
+ unsigned int dentry_hash;
+ char *name;
node_blk = malloc(F2FS_BLKSIZE);
ASSERT(node_blk != NULL);
@@ -1180,12 +1197,25 @@ static int inject_dentry(struct f2fs_sb_info *sbi,
struct inject_option *opt)
get_node_info(sbi, opt->nid, &ni);
ret = dev_read_block(node_blk, ni.blk_addr);
ASSERT(ret >= 0);
- pino = le32_to_cpu(node_blk->i.i_pino);
- /* get parent inode */
- get_node_info(sbi, pino, &ni);
- ret = dev_read_block(node_blk, ni.blk_addr);
- ASSERT(ret >= 0);
+ if (opt->dots) {
+ if (!LINUX_S_ISDIR(le16_to_cpu(node_blk->i.i_mode))) {
+ ERR_MSG("ino %u is not a directory, cannot inject "
+ "its %s\n", opt->nid,
+ opt->dots == TYPE_DOT ? "." : "..");
+ ret = -EINVAL;
+ goto out;
+ }
+ /* pino is itself */
+ pino = opt->nid;
+ } else {
+ pino = le32_to_cpu(node_blk->i.i_pino);
+
+ /* get parent inode */
+ get_node_info(sbi, pino, &ni);
+ ret = dev_read_block(node_blk, ni.blk_addr);
+ ASSERT(ret >= 0);
+ }
inode = &node_blk->i;
/* find child dentry */
@@ -1195,7 +1225,10 @@ static int inject_dentry(struct f2fs_sb_info *sbi,
struct inject_option *opt)
addr = ni.blk_addr;
buf = node_blk;
- slot = find_dir_entry(&d, opt->nid);
+ if (opt->dots == TYPE_DOTDOT)
+ slot = find_dir_entry(&d,
le32_to_cpu(node_blk->i.i_pino));
+ else
+ slot = find_dir_entry(&d, opt->nid);
if (slot >= 0)
dent = &d.dentry[slot];
} else {
@@ -1231,7 +1264,10 @@ static int inject_dentry(struct f2fs_sb_info *sbi,
struct inject_option *opt)
ASSERT(ret >= 0);
make_dentry_ptr(&d, node_blk, dent_blk, 1);
- slot = find_dir_entry(&d, opt->nid);
+ if (opt->dots == TYPE_DOTDOT)
+ slot = find_dir_entry(&d,
le32_to_cpu(node_blk->i.i_pino));
+ else
+ slot = find_dir_entry(&d, opt->nid);
if (slot >= 0) {
dent = &d.dentry[slot];
buf = dent_blk;
@@ -1265,6 +1301,36 @@ static int inject_dentry(struct f2fs_sb_info *sbi,
struct inject_option *opt)
"%d -> %d\n", opt->nid, dent->file_type,
(u8)opt->val);
dent->file_type = (u8)opt->val;
+ } else if (!strcmp(opt->mb, "filename")) {
+ if (!opt->str) {
+ ERR_MSG("option str is needed\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ namecap = ALIGN_UP(le16_to_cpu(dent->name_len), F2FS_SLOT_LEN);
+ namelen = strlen(opt->str);
+ if (namelen > namecap || namelen > F2FS_NAME_LEN) {
+ ERR_MSG("option str too long\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ name = (char *)d.filename[slot];
+ MSG(0, "Info: inject dentry filename of nid %u: "
+ "%.*s -> %s\n", opt->nid, le16_to_cpu(dent->name_len),
+ name, opt->str);
+ memcpy(name, opt->str, namelen);
+ MSG(0, "Info: inject dentry namelen of nid %u: "
+ "%d -> %d\n", opt->nid, le16_to_cpu(dent->name_len),
+ namelen);
+ dent->name_len = cpu_to_le16(namelen);
+ dentry_hash = f2fs_dentry_hash(get_encoding(sbi),
+ IS_CASEFOLDED(inode),
+ (unsigned char *)name,
+ namelen);
+ MSG(0, "Info: inject dentry d_hash of nid %u: "
+ "0x%x -> 0x%x\n", opt->nid, le32_to_cpu(dent->hash_code),
+ dentry_hash);
+ dent->hash_code = cpu_to_le32(dentry_hash);