mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs-tools.git
synced 2024-11-15 05:43:39 +08:00
dump.f2fs: Dump symlinks as symlinks
Previously, dumped symlinks would always create regular files instead. This allows symlinks to be dumped as symlinks with the -L option. The i_name field's name may not be the same as the actual name from the dirent, so we use the dirent name when available. Currently hardlinks aren't detected, so print a warning if we notice a nondirectory with a link count over 1. Signed-off-by: Daniel Rosenberg <drosen@google.com> Reviewed-by: Chao Yu <chao@kernel.org> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
parent
4a5da2ef15
commit
a66d49fd26
121
fsck/dump.c
121
fsck/dump.c
@ -253,20 +253,27 @@ static void dump_folder_contents(struct f2fs_sb_info *sbi, u8 *bitmap,
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int name_len;
|
int name_len;
|
||||||
|
char name[F2FS_NAME_LEN + 1] = {0};
|
||||||
|
|
||||||
for (i = 0; i < max; i++) {
|
for (i = 0; i < max; i++) {
|
||||||
if (test_bit_le(i, bitmap) == 0)
|
if (test_bit_le(i, bitmap) == 0)
|
||||||
continue;
|
continue;
|
||||||
name_len = le16_to_cpu(dentry[i].name_len);
|
name_len = le16_to_cpu(dentry[i].name_len);
|
||||||
|
if (name_len == 0 || name_len > F2FS_NAME_LEN) {
|
||||||
|
MSG(c.force, "Wrong name info\n\n");
|
||||||
|
ASSERT(name_len == 0 || name_len > F2FS_NAME_LEN);
|
||||||
|
}
|
||||||
if (name_len == 1 && filenames[i][0] == '.')
|
if (name_len == 1 && filenames[i][0] == '.')
|
||||||
continue;
|
continue;
|
||||||
if (name_len == 2 && filenames[i][0] == '.' && filenames[i][1] == '.')
|
if (name_len == 2 && filenames[i][0] == '.' && filenames[i][1] == '.')
|
||||||
continue;
|
continue;
|
||||||
dump_node(sbi, le32_to_cpu(dentry[i].ino), 1, NULL, 0, 1);
|
strncpy(name, (const char *)filenames[i], name_len);
|
||||||
|
name[name_len] = 0;
|
||||||
|
dump_node(sbi, le32_to_cpu(dentry[i].ino), 1, NULL, 0, 1, name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dump_data_blk(struct f2fs_sb_info *sbi, __u64 offset, u32 blkaddr, bool is_folder)
|
static void dump_data_blk(struct f2fs_sb_info *sbi, __u64 offset, u32 blkaddr, int type)
|
||||||
{
|
{
|
||||||
char buf[F2FS_BLKSIZE];
|
char buf[F2FS_BLKSIZE];
|
||||||
|
|
||||||
@ -307,11 +314,15 @@ static void dump_data_blk(struct f2fs_sb_info *sbi, __u64 offset, u32 blkaddr, b
|
|||||||
ASSERT(ret >= 0);
|
ASSERT(ret >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_folder) {
|
if (S_ISDIR(type)) {
|
||||||
struct f2fs_dentry_block *d = (struct f2fs_dentry_block *) buf;
|
struct f2fs_dentry_block *d = (struct f2fs_dentry_block *) buf;
|
||||||
|
|
||||||
dump_folder_contents(sbi, d->dentry_bitmap, F2FS_DENTRY_BLOCK_DENTRIES(d),
|
dump_folder_contents(sbi, d->dentry_bitmap, F2FS_DENTRY_BLOCK_DENTRIES(d),
|
||||||
F2FS_DENTRY_BLOCK_FILENAMES(d), NR_DENTRY_IN_BLOCK);
|
F2FS_DENTRY_BLOCK_FILENAMES(d), NR_DENTRY_IN_BLOCK);
|
||||||
|
#if !defined(__MINGW32__)
|
||||||
|
} if (S_ISLNK(type)) {
|
||||||
|
dev_write_symlink(buf, c.dump_sym_target_len);
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
/* write blkaddr */
|
/* write blkaddr */
|
||||||
dev_write_dump(buf, offset, F2FS_BLKSIZE);
|
dev_write_dump(buf, offset, F2FS_BLKSIZE);
|
||||||
@ -319,7 +330,7 @@ static void dump_data_blk(struct f2fs_sb_info *sbi, __u64 offset, u32 blkaddr, b
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void dump_node_blk(struct f2fs_sb_info *sbi, int ntype,
|
static void dump_node_blk(struct f2fs_sb_info *sbi, int ntype,
|
||||||
u32 nid, u32 addr_per_block, u64 *ofs, int is_dir)
|
u32 nid, u32 addr_per_block, u64 *ofs, int type)
|
||||||
{
|
{
|
||||||
struct node_info ni;
|
struct node_info ni;
|
||||||
struct f2fs_node *node_blk;
|
struct f2fs_node *node_blk;
|
||||||
@ -356,20 +367,20 @@ static void dump_node_blk(struct f2fs_sb_info *sbi, int ntype,
|
|||||||
switch (ntype) {
|
switch (ntype) {
|
||||||
case TYPE_DIRECT_NODE:
|
case TYPE_DIRECT_NODE:
|
||||||
dump_data_blk(sbi, *ofs * F2FS_BLKSIZE,
|
dump_data_blk(sbi, *ofs * F2FS_BLKSIZE,
|
||||||
le32_to_cpu(node_blk->dn.addr[i]), is_dir);
|
le32_to_cpu(node_blk->dn.addr[i]), type);
|
||||||
(*ofs)++;
|
(*ofs)++;
|
||||||
break;
|
break;
|
||||||
case TYPE_INDIRECT_NODE:
|
case TYPE_INDIRECT_NODE:
|
||||||
dump_node_blk(sbi, TYPE_DIRECT_NODE,
|
dump_node_blk(sbi, TYPE_DIRECT_NODE,
|
||||||
le32_to_cpu(node_blk->in.nid[i]),
|
le32_to_cpu(node_blk->in.nid[i]),
|
||||||
addr_per_block,
|
addr_per_block,
|
||||||
ofs, is_dir);
|
ofs, type);
|
||||||
break;
|
break;
|
||||||
case TYPE_DOUBLE_INDIRECT_NODE:
|
case TYPE_DOUBLE_INDIRECT_NODE:
|
||||||
dump_node_blk(sbi, TYPE_INDIRECT_NODE,
|
dump_node_blk(sbi, TYPE_INDIRECT_NODE,
|
||||||
le32_to_cpu(node_blk->in.nid[i]),
|
le32_to_cpu(node_blk->in.nid[i]),
|
||||||
addr_per_block,
|
addr_per_block,
|
||||||
ofs, is_dir);
|
ofs, type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -377,7 +388,7 @@ static void dump_node_blk(struct f2fs_sb_info *sbi, int ntype,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_FSETXATTR
|
#ifdef HAVE_FSETXATTR
|
||||||
static void dump_xattr(struct f2fs_sb_info *sbi, struct f2fs_node *node_blk, int is_dir)
|
static void dump_xattr(struct f2fs_sb_info *sbi, struct f2fs_node *node_blk, int type)
|
||||||
{
|
{
|
||||||
void *xattr;
|
void *xattr;
|
||||||
void *last_base_addr;
|
void *last_base_addr;
|
||||||
@ -431,19 +442,26 @@ static void dump_xattr(struct f2fs_sb_info *sbi, struct f2fs_node *node_blk, int
|
|||||||
|
|
||||||
DBG(1, "fd %d xattr_name %s\n", c.dump_fd, xattr_name);
|
DBG(1, "fd %d xattr_name %s\n", c.dump_fd, xattr_name);
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
if (is_dir) {
|
if (S_ISDIR(type)) {
|
||||||
ret = setxattr(".", xattr_name, value,
|
ret = setxattr(".", xattr_name, value,
|
||||||
le16_to_cpu(ent->e_value_size), 0);
|
le16_to_cpu(ent->e_value_size), 0);
|
||||||
|
} if (S_ISLNK(type) && c.preserve_symlinks) {
|
||||||
|
ret = lsetxattr(c.dump_symlink, xattr_name, value,
|
||||||
|
le16_to_cpu(ent->e_value_size), 0);
|
||||||
} else {
|
} else {
|
||||||
ret = fsetxattr(c.dump_fd, xattr_name, value,
|
ret = fsetxattr(c.dump_fd, xattr_name, value,
|
||||||
le16_to_cpu(ent->e_value_size), 0);
|
le16_to_cpu(ent->e_value_size), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
if (is_dir) {
|
if (S_ISDIR(type)) {
|
||||||
ret = setxattr(".", xattr_name, value,
|
ret = setxattr(".", xattr_name, value,
|
||||||
le16_to_cpu(ent->e_value_size), 0,
|
le16_to_cpu(ent->e_value_size), 0,
|
||||||
XATTR_CREATE);
|
XATTR_CREATE);
|
||||||
|
} if (S_ISLNK(type) && c.preserve_symlinks) {
|
||||||
|
ret = lsetxattr(c.dump_symlink, xattr_name, value,
|
||||||
|
le16_to_cpu(ent->e_value_size), 0,
|
||||||
|
XATTR_CREATE);
|
||||||
} else {
|
} else {
|
||||||
ret = fsetxattr(c.dump_fd, xattr_name, value,
|
ret = fsetxattr(c.dump_fd, xattr_name, value,
|
||||||
le16_to_cpu(ent->e_value_size), 0,
|
le16_to_cpu(ent->e_value_size), 0,
|
||||||
@ -473,14 +491,21 @@ static int dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
|
|||||||
u32 i = 0;
|
u32 i = 0;
|
||||||
u64 ofs = 0;
|
u64 ofs = 0;
|
||||||
u32 addr_per_block;
|
u32 addr_per_block;
|
||||||
bool is_dir = S_ISDIR(le16_to_cpu(node_blk->i.i_mode));
|
u16 type = le16_to_cpu(node_blk->i.i_mode);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if ((node_blk->i.i_inline & F2FS_INLINE_DATA)) {
|
if ((node_blk->i.i_inline & F2FS_INLINE_DATA)) {
|
||||||
DBG(3, "ino[0x%x] has inline data!\n", nid);
|
DBG(3, "ino[0x%x] has inline data!\n", nid);
|
||||||
/* recover from inline data */
|
/* recover from inline data */
|
||||||
dev_write_dump(inline_data_addr(node_blk),
|
#if !defined(__MINGW32__)
|
||||||
|
if (S_ISLNK(type) && c.preserve_symlinks) {
|
||||||
|
dev_write_symlink(inline_data_addr(node_blk), c.dump_sym_target_len);
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
dev_write_dump(inline_data_addr(node_blk),
|
||||||
0, MAX_INLINE_DATA(node_blk));
|
0, MAX_INLINE_DATA(node_blk));
|
||||||
|
}
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto dump_xattr;
|
goto dump_xattr;
|
||||||
}
|
}
|
||||||
@ -504,7 +529,7 @@ static int dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
|
|||||||
/* check data blocks in inode */
|
/* check data blocks in inode */
|
||||||
for (i = 0; i < ADDRS_PER_INODE(&node_blk->i); i++, ofs++)
|
for (i = 0; i < ADDRS_PER_INODE(&node_blk->i); i++, ofs++)
|
||||||
dump_data_blk(sbi, ofs * F2FS_BLKSIZE, le32_to_cpu(
|
dump_data_blk(sbi, ofs * F2FS_BLKSIZE, le32_to_cpu(
|
||||||
node_blk->i.i_addr[get_extra_isize(node_blk) + i]), is_dir);
|
node_blk->i.i_addr[get_extra_isize(node_blk) + i]), type);
|
||||||
|
|
||||||
/* check node blocks in inode */
|
/* check node blocks in inode */
|
||||||
for (i = 0; i < 5; i++) {
|
for (i = 0; i < 5; i++) {
|
||||||
@ -513,26 +538,26 @@ static int dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
|
|||||||
le32_to_cpu(F2FS_INODE_I_NID(&node_blk->i, i)),
|
le32_to_cpu(F2FS_INODE_I_NID(&node_blk->i, i)),
|
||||||
addr_per_block,
|
addr_per_block,
|
||||||
&ofs,
|
&ofs,
|
||||||
is_dir);
|
type);
|
||||||
else if (i == 2 || i == 3)
|
else if (i == 2 || i == 3)
|
||||||
dump_node_blk(sbi, TYPE_INDIRECT_NODE,
|
dump_node_blk(sbi, TYPE_INDIRECT_NODE,
|
||||||
le32_to_cpu(F2FS_INODE_I_NID(&node_blk->i, i)),
|
le32_to_cpu(F2FS_INODE_I_NID(&node_blk->i, i)),
|
||||||
addr_per_block,
|
addr_per_block,
|
||||||
&ofs,
|
&ofs,
|
||||||
is_dir);
|
type);
|
||||||
else if (i == 4)
|
else if (i == 4)
|
||||||
dump_node_blk(sbi, TYPE_DOUBLE_INDIRECT_NODE,
|
dump_node_blk(sbi, TYPE_DOUBLE_INDIRECT_NODE,
|
||||||
le32_to_cpu(F2FS_INODE_I_NID(&node_blk->i, i)),
|
le32_to_cpu(F2FS_INODE_I_NID(&node_blk->i, i)),
|
||||||
addr_per_block,
|
addr_per_block,
|
||||||
&ofs,
|
&ofs,
|
||||||
is_dir);
|
type);
|
||||||
else
|
else
|
||||||
ASSERT(0);
|
ASSERT(0);
|
||||||
}
|
}
|
||||||
/* last block in extent cache */
|
/* last block in extent cache */
|
||||||
print_extent(true);
|
print_extent(true);
|
||||||
dump_xattr:
|
dump_xattr:
|
||||||
dump_xattr(sbi, node_blk, is_dir);
|
dump_xattr(sbi, node_blk, type);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -555,6 +580,23 @@ static void dump_file(struct f2fs_sb_info *sbi, struct node_info *ni,
|
|||||||
close(c.dump_fd);
|
close(c.dump_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dump_link(struct f2fs_sb_info *sbi, struct node_info *ni,
|
||||||
|
struct f2fs_node *node_blk, char *name)
|
||||||
|
{
|
||||||
|
#if defined(__MINGW32__)
|
||||||
|
dump_file(sbi, ni, node_blk, name);
|
||||||
|
#else
|
||||||
|
struct f2fs_inode *inode = &node_blk->i;
|
||||||
|
int len = le64_to_cpu(inode->i_size);
|
||||||
|
|
||||||
|
if (!c.preserve_symlinks)
|
||||||
|
return dump_file(sbi, ni, node_blk, name);
|
||||||
|
c.dump_symlink = name;
|
||||||
|
c.dump_sym_target_len = len + 1;
|
||||||
|
dump_inode_blk(sbi, ni->ino, node_blk);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static void dump_folder(struct f2fs_sb_info *sbi, struct node_info *ni,
|
static void dump_folder(struct f2fs_sb_info *sbi, struct node_info *ni,
|
||||||
struct f2fs_node *node_blk, char *path, int is_root)
|
struct f2fs_node *node_blk, char *path, int is_root)
|
||||||
{
|
{
|
||||||
@ -580,18 +622,24 @@ static void dump_folder(struct f2fs_sb_info *sbi, struct node_info *ni,
|
|||||||
|
|
||||||
static int dump_filesystem(struct f2fs_sb_info *sbi, struct node_info *ni,
|
static int dump_filesystem(struct f2fs_sb_info *sbi, struct node_info *ni,
|
||||||
struct f2fs_node *node_blk, int force, char *base_path,
|
struct f2fs_node *node_blk, int force, char *base_path,
|
||||||
bool is_base, bool allow_folder)
|
bool is_base, bool allow_folder, char *dirent_name)
|
||||||
{
|
{
|
||||||
struct f2fs_inode *inode = &node_blk->i;
|
struct f2fs_inode *inode = &node_blk->i;
|
||||||
u32 imode = le16_to_cpu(inode->i_mode);
|
u32 imode = le16_to_cpu(inode->i_mode);
|
||||||
u32 namelen = le32_to_cpu(inode->i_namelen);
|
u32 ilinks = le32_to_cpu(inode->i_links);
|
||||||
char name[F2FS_NAME_LEN + 1] = {0};
|
u32 i_namelen = le32_to_cpu(inode->i_namelen);
|
||||||
|
char i_name[F2FS_NAME_LEN + 1] = {0};
|
||||||
|
char *name = NULL;
|
||||||
char path[1024] = {0};
|
char path[1024] = {0};
|
||||||
char ans[255] = {0};
|
char ans[255] = {0};
|
||||||
int is_encrypted = file_is_encrypt(inode);
|
int is_encrypted = file_is_encrypt(inode);
|
||||||
int is_root = sbi->root_ino_num == ni->nid;
|
int is_root = sbi->root_ino_num == ni->nid;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (!S_ISDIR(imode) && ilinks != 1) {
|
||||||
|
MSG(force, "Warning: Hard link detected. Dumped files may be duplicated\n");
|
||||||
|
}
|
||||||
|
|
||||||
if (is_encrypted) {
|
if (is_encrypted) {
|
||||||
MSG(force, "File is encrypted\n");
|
MSG(force, "File is encrypted\n");
|
||||||
return -1;
|
return -1;
|
||||||
@ -601,7 +649,7 @@ static int dump_filesystem(struct f2fs_sb_info *sbi, struct node_info *ni,
|
|||||||
MSG(force, "Not a valid file type\n\n");
|
MSG(force, "Not a valid file type\n\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (!is_root && (namelen == 0 || namelen > F2FS_NAME_LEN)) {
|
if (!is_root && !dirent_name && (i_namelen == 0 || i_namelen > F2FS_NAME_LEN)) {
|
||||||
MSG(force, "Wrong name info\n\n");
|
MSG(force, "Wrong name info\n\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -614,7 +662,7 @@ static int dump_filesystem(struct f2fs_sb_info *sbi, struct node_info *ni,
|
|||||||
return dump_inode_blk(sbi, ni->ino, node_blk);
|
return dump_inode_blk(sbi, ni->ino, node_blk);
|
||||||
|
|
||||||
printf("Do you want to dump this %s into %s/? [Y/N] ",
|
printf("Do you want to dump this %s into %s/? [Y/N] ",
|
||||||
S_ISREG(imode) || S_ISLNK(imode) ? "file" : "folder",
|
S_ISDIR(imode) ? "folder" : "file",
|
||||||
base_path);
|
base_path);
|
||||||
ret = scanf("%s", ans);
|
ret = scanf("%s", ans);
|
||||||
ASSERT(ret >= 0);
|
ASSERT(ret >= 0);
|
||||||
@ -635,23 +683,34 @@ dump:
|
|||||||
|
|
||||||
/* make a file */
|
/* make a file */
|
||||||
if (!is_root) {
|
if (!is_root) {
|
||||||
strncpy(name, (const char *)inode->i_name, namelen);
|
/* The i_name name may be out of date. Prefer dirent_name */
|
||||||
name[namelen] = 0;
|
if (dirent_name) {
|
||||||
|
name = dirent_name;
|
||||||
|
} else {
|
||||||
|
strncpy(i_name, (const char *)inode->i_name, i_namelen);
|
||||||
|
i_name[i_namelen] = 0;
|
||||||
|
name = i_name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (S_ISREG(imode) || S_ISLNK(imode)) {
|
if (S_ISREG(imode)) {
|
||||||
dump_file(sbi, ni, node_blk, name);
|
dump_file(sbi, ni, node_blk, name);
|
||||||
} else {
|
} else if (S_ISDIR(imode)) {
|
||||||
dump_folder(sbi, ni, node_blk, name, is_root);
|
dump_folder(sbi, ni, node_blk, name, is_root);
|
||||||
|
} else {
|
||||||
|
dump_link(sbi, ni, node_blk, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(__MINGW32__)
|
#if !defined(__MINGW32__)
|
||||||
/* fix up mode/owner */
|
/* fix up mode/owner */
|
||||||
if (c.preserve_perms) {
|
if (c.preserve_perms) {
|
||||||
if (is_root)
|
if (is_root) {
|
||||||
|
name = i_name;
|
||||||
strncpy(name, ".", 2);
|
strncpy(name, ".", 2);
|
||||||
ASSERT(chmod(name, imode) == 0);
|
}
|
||||||
ASSERT(chown(name, inode->i_uid, inode->i_gid) == 0);
|
if (!S_ISLNK(imode))
|
||||||
|
ASSERT(chmod(name, imode) == 0);
|
||||||
|
ASSERT(lchown(name, inode->i_uid, inode->i_gid) == 0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (is_base)
|
if (is_base)
|
||||||
@ -705,7 +764,7 @@ void dump_node_scan_disk(struct f2fs_sb_info *sbi, nid_t nid)
|
|||||||
free(node_blk);
|
free(node_blk);
|
||||||
}
|
}
|
||||||
|
|
||||||
int dump_node(struct f2fs_sb_info *sbi, nid_t nid, int force, char *base_path, int base, int allow_folder)
|
int dump_node(struct f2fs_sb_info *sbi, nid_t nid, int force, char *base_path, int base, int allow_folder, char *dirent_name)
|
||||||
{
|
{
|
||||||
struct node_info ni;
|
struct node_info ni;
|
||||||
struct f2fs_node *node_blk;
|
struct f2fs_node *node_blk;
|
||||||
@ -740,7 +799,7 @@ int dump_node(struct f2fs_sb_info *sbi, nid_t nid, int force, char *base_path, i
|
|||||||
print_node_info(sbi, node_blk, force);
|
print_node_info(sbi, node_blk, force);
|
||||||
|
|
||||||
if (ni.ino == ni.nid)
|
if (ni.ino == ni.nid)
|
||||||
ret = dump_filesystem(sbi, &ni, node_blk, force, base_path, base, allow_folder);
|
ret = dump_filesystem(sbi, &ni, node_blk, force, base_path, base, allow_folder, dirent_name);
|
||||||
} else {
|
} else {
|
||||||
print_node_info(sbi, node_blk, force);
|
print_node_info(sbi, node_blk, force);
|
||||||
MSG(force, "Invalid (i)node block\n\n");
|
MSG(force, "Invalid (i)node block\n\n");
|
||||||
|
@ -1651,7 +1651,7 @@ static void print_dentry(struct f2fs_sb_info *sbi, __u8 *name,
|
|||||||
d = d->next;
|
d = d->next;
|
||||||
}
|
}
|
||||||
printf("/%s", new);
|
printf("/%s", new);
|
||||||
if (dump_node(sbi, le32_to_cpu(dentry[idx].ino), 0, NULL, 0, 0))
|
if (dump_node(sbi, le32_to_cpu(dentry[idx].ino), 0, NULL, 0, 0, NULL))
|
||||||
printf("\33[2K\r");
|
printf("\33[2K\r");
|
||||||
} else {
|
} else {
|
||||||
for (i = 1; i < depth; i++)
|
for (i = 1; i < depth; i++)
|
||||||
@ -3632,7 +3632,7 @@ int fsck_verify(struct f2fs_sb_info *sbi)
|
|||||||
if (!strcasecmp(ans, "y")) {
|
if (!strcasecmp(ans, "y")) {
|
||||||
for (i = 0; i < fsck->nr_nat_entries; i++) {
|
for (i = 0; i < fsck->nr_nat_entries; i++) {
|
||||||
if (f2fs_test_bit(i, fsck->nat_area_bitmap))
|
if (f2fs_test_bit(i, fsck->nat_area_bitmap))
|
||||||
dump_node(sbi, i, 1, NULL, 1, 0);
|
dump_node(sbi, i, 1, NULL, 1, 0, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -277,7 +277,7 @@ struct dump_option {
|
|||||||
extern void nat_dump(struct f2fs_sb_info *, nid_t, nid_t);
|
extern void nat_dump(struct f2fs_sb_info *, nid_t, nid_t);
|
||||||
extern void sit_dump(struct f2fs_sb_info *, unsigned int, unsigned int);
|
extern void sit_dump(struct f2fs_sb_info *, unsigned int, unsigned int);
|
||||||
extern void ssa_dump(struct f2fs_sb_info *, int, int);
|
extern void ssa_dump(struct f2fs_sb_info *, int, int);
|
||||||
extern int dump_node(struct f2fs_sb_info *, nid_t, int, char *, int, int);
|
extern int dump_node(struct f2fs_sb_info *, nid_t, int, char *, int, int, char *);
|
||||||
extern int dump_info_from_blkaddr(struct f2fs_sb_info *, u32);
|
extern int dump_info_from_blkaddr(struct f2fs_sb_info *, u32);
|
||||||
extern unsigned int start_bidx_of_node(unsigned int, struct f2fs_node *);
|
extern unsigned int start_bidx_of_node(unsigned int, struct f2fs_node *);
|
||||||
extern void dump_node_scan_disk(struct f2fs_sb_info *sbi, nid_t nid);
|
extern void dump_node_scan_disk(struct f2fs_sb_info *sbi, nid_t nid);
|
||||||
|
13
fsck/main.c
13
fsck/main.c
@ -102,6 +102,7 @@ void dump_usage()
|
|||||||
MSG(0, " -y alias for -f\n");
|
MSG(0, " -y alias for -f\n");
|
||||||
MSG(0, " -o dump inodes to the given path\n");
|
MSG(0, " -o dump inodes to the given path\n");
|
||||||
MSG(0, " -P preserve mode/owner/group for dumped inode\n");
|
MSG(0, " -P preserve mode/owner/group for dumped inode\n");
|
||||||
|
MSG(0, " -L Preserves symlinks. Otherwise symlinks are dumped as regular files.\n");
|
||||||
MSG(0, " -V print the version number and exit\n");
|
MSG(0, " -V print the version number and exit\n");
|
||||||
|
|
||||||
exit(1);
|
exit(1);
|
||||||
@ -389,7 +390,7 @@ void f2fs_parse_options(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
} else if (!strcmp("dump.f2fs", prog)) {
|
} else if (!strcmp("dump.f2fs", prog)) {
|
||||||
#ifdef WITH_DUMP
|
#ifdef WITH_DUMP
|
||||||
const char *option_string = "d:fi:I:n:Mo:Prs:Sa:b:Vy";
|
const char *option_string = "d:fi:I:n:LMo:Prs:Sa:b:Vy";
|
||||||
static struct dump_option dump_opt = {
|
static struct dump_option dump_opt = {
|
||||||
.nid = 0, /* default root ino */
|
.nid = 0, /* default root ino */
|
||||||
.start_nat = -1,
|
.start_nat = -1,
|
||||||
@ -479,6 +480,14 @@ void f2fs_parse_options(int argc, char *argv[])
|
|||||||
err = EWRONG_OPT;
|
err = EWRONG_OPT;
|
||||||
#else
|
#else
|
||||||
c.preserve_perms = 1;
|
c.preserve_perms = 1;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case 'L':
|
||||||
|
#if defined(__MINGW32__)
|
||||||
|
MSG(0, "-L not supported for Windows\n");
|
||||||
|
err = EWRONG_OPT;
|
||||||
|
#else
|
||||||
|
c.preserve_symlinks = 1;
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
case 'V':
|
case 'V':
|
||||||
@ -957,7 +966,7 @@ static void do_dump(struct f2fs_sb_info *sbi)
|
|||||||
if (opt->blk_addr != -1)
|
if (opt->blk_addr != -1)
|
||||||
dump_info_from_blkaddr(sbi, opt->blk_addr);
|
dump_info_from_blkaddr(sbi, opt->blk_addr);
|
||||||
if (opt->nid)
|
if (opt->nid)
|
||||||
dump_node(sbi, opt->nid, c.force, opt->base_path, 1, 1);
|
dump_node(sbi, opt->nid, c.force, opt->base_path, 1, 1, NULL);
|
||||||
if (opt->scan_nid)
|
if (opt->scan_nid)
|
||||||
dump_node_scan_disk(sbi, opt->scan_nid);
|
dump_node_scan_disk(sbi, opt->scan_nid);
|
||||||
|
|
||||||
|
@ -1478,6 +1478,8 @@ struct f2fs_configuration {
|
|||||||
uint16_t s_encoding_flags;
|
uint16_t s_encoding_flags;
|
||||||
int32_t kd;
|
int32_t kd;
|
||||||
int32_t dump_fd;
|
int32_t dump_fd;
|
||||||
|
char *dump_symlink;
|
||||||
|
int dump_sym_target_len;
|
||||||
struct device_info devices[MAX_DEVICES];
|
struct device_info devices[MAX_DEVICES];
|
||||||
int ndevs;
|
int ndevs;
|
||||||
char *extension_list[2];
|
char *extension_list[2];
|
||||||
@ -1540,7 +1542,10 @@ struct f2fs_configuration {
|
|||||||
struct selinux_opt seopt_file[8];
|
struct selinux_opt seopt_file[8];
|
||||||
int nr_opt;
|
int nr_opt;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* dump parameters */
|
||||||
int preserve_perms;
|
int preserve_perms;
|
||||||
|
int preserve_symlinks;
|
||||||
|
|
||||||
/* resize parameters */
|
/* resize parameters */
|
||||||
int safe_resize;
|
int safe_resize;
|
||||||
@ -1614,6 +1619,9 @@ extern int dev_readahead(__u64, size_t UNUSED(len));
|
|||||||
extern int dev_write(void *, __u64, size_t);
|
extern int dev_write(void *, __u64, size_t);
|
||||||
extern int dev_write_block(void *, __u64);
|
extern int dev_write_block(void *, __u64);
|
||||||
extern int dev_write_dump(void *, __u64, size_t);
|
extern int dev_write_dump(void *, __u64, size_t);
|
||||||
|
#if !defined(__MINGW32__)
|
||||||
|
extern int dev_write_symlink(char *, size_t);
|
||||||
|
#endif
|
||||||
/* All bytes in the buffer must be 0 use dev_fill(). */
|
/* All bytes in the buffer must be 0 use dev_fill(). */
|
||||||
extern int dev_fill(void *, __u64, size_t);
|
extern int dev_fill(void *, __u64, size_t);
|
||||||
extern int dev_fill_block(void *, __u64);
|
extern int dev_fill_block(void *, __u64);
|
||||||
|
@ -598,6 +598,16 @@ int dev_write_dump(void *buf, __u64 offset, size_t len)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(__MINGW32__)
|
||||||
|
int dev_write_symlink(char *buf, size_t len)
|
||||||
|
{
|
||||||
|
buf[len] = 0;
|
||||||
|
if (symlink(buf, c.dump_symlink))
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int dev_fill(void *buf, __u64 offset, size_t len)
|
int dev_fill(void *buf, __u64 offset, size_t len)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
|
@ -71,6 +71,9 @@ Dump inodes to the given path
|
|||||||
.BI \-P
|
.BI \-P
|
||||||
Preserve mode/owner/group for dumped inode
|
Preserve mode/owner/group for dumped inode
|
||||||
.TP
|
.TP
|
||||||
|
.BI \-L
|
||||||
|
Preserves symlinks. Otherwise symlinks are dumped as regular files.
|
||||||
|
.TP
|
||||||
.BI \-I " inode number"
|
.BI \-I " inode number"
|
||||||
Specify an inode number and scan full disk to dump out, include history inode block
|
Specify an inode number and scan full disk to dump out, include history inode block
|
||||||
.TP
|
.TP
|
||||||
|
Loading…
Reference in New Issue
Block a user