@@ -104,7 +104,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);
@@ -211,12 +211,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)
@@ -240,6 +244,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}
};
@@ -336,6 +341,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;
@@ -368,6 +381,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;
}
@@ -1056,12 +1072,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));
}
@@ -1074,14 +1090,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);
@@ -1090,12 +1107,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 */
@@ -1105,7 +1135,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 {
@@ -1141,7 +1174,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;
@@ -1175,6 +1211,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) {
+ 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);
} else {
ERR_MSG("unknown or unsupported member \"%s\"\n", opt->mb);
ret = -EINVAL;
@@ -30,6 +30,7 @@ struct inject_option {
int cp; /* which cp */
int nat; /* which nat pack */
int sit; /* which sit pack */
+ int dots; /* . or .. dentry */
bool ssa;
bool node;
bool dent;
@@ -211,12 +211,20 @@ inode i_nid array specified by \fIidx\fP.
.RE
.TP
.BI \-\-dent
-Inject dentry block or dir entry specified \fInid\fP.
+Inject dentry block or dir entry specified by \fInid\fP.
+.RS 1.2i
+.TP
+.BI \-\-dots " 1 or 2"
+The option means the "." or ".." directory entry of \fInid\fP is going to be injected.
+.RE
+.TP
+.BI ""
The available \fImb\fP of \fIdent\fP are:
.RS 1.2i
.TP
.BI d_bitmap
dentry block d_bitmap.
+dentry block d_bitmap.
.TP
.BI d_hash
dentry hash.
@@ -226,6 +234,9 @@ dentry ino.
.TP
.BI d_ftype
dentry ftype.
+.TP
+.BI filename
+dentry filename, and corresponding d_hash and namelen are updated implicitly.
.RE
.TP
.BI \-\-dry\-run
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 <shengyong@oppo.com> --- fsck/inject.c | 94 ++++++++++++++++++++++++++++++++++++++++------- fsck/inject.h | 1 + man/inject.f2fs.8 | 13 ++++++- 3 files changed, 93 insertions(+), 15 deletions(-)