* [f2fs-dev] [PATCH 1/2] dump.f2fs: Add ability to dump folders
@ 2024-05-08 0:57 Daniel Rosenberg via Linux-f2fs-devel
2024-05-08 0:57 ` [f2fs-dev] [PATCH 2/2] dump.f2fs: Fix xattr dumping Daniel Rosenberg via Linux-f2fs-devel
2024-05-20 15:11 ` [f2fs-dev] [PATCH 1/2] dump.f2fs: Add ability to dump folders Daeho Jeong
0 siblings, 2 replies; 4+ messages in thread
From: Daniel Rosenberg via Linux-f2fs-devel @ 2024-05-08 0:57 UTC (permalink / raw)
To: linux-f2fs-devel; +Cc: Jaegeuk Kim, kernel-team, Daniel Rosenberg
This adds the ability to dump folders as well as files. Folders are
dumped recursively. Additionally, dumped files/folders may be directed
to a folder specified by -o [path] instead of ./lost_found. The -r flag
will dump the entire fs from the root inode. -f or -y will skip the
prompt before dumping, and -P will preserve the mode/owner info for the
created file/folder.
Signed-off-by: Daniel Rosenberg <drosen@google.com>
---
fsck/dump.c | 164 +++++++++++++++++++++++++++++++++++++-----------
fsck/fsck.c | 4 +-
fsck/fsck.h | 4 +-
fsck/main.c | 24 ++++++-
man/dump.f2fs.8 | 17 ++++-
5 files changed, 171 insertions(+), 42 deletions(-)
diff --git a/fsck/dump.c b/fsck/dump.c
index b2e990b..f60f6f9 100644
--- a/fsck/dump.c
+++ b/fsck/dump.c
@@ -247,7 +247,26 @@ out:
printf("\n");
}
-static void dump_data_blk(struct f2fs_sb_info *sbi, __u64 offset, u32 blkaddr)
+static void dump_folder_contents(struct f2fs_sb_info *sbi, u8 *bitmap,
+ struct f2fs_dir_entry *dentry,
+ __u8 (*filenames)[F2FS_SLOT_LEN], int max)
+{
+ int i;
+ int name_len;
+
+ for (i = 0; i < max; i++) {
+ if (test_bit_le(i, bitmap) == 0)
+ continue;
+ name_len = le16_to_cpu(dentry[i].name_len);
+ if (name_len == 1 && filenames[i][0] == '.')
+ continue;
+ if (name_len == 2 && filenames[i][0] == '.' && filenames[i][1] == '.')
+ continue;
+ dump_node(sbi, le32_to_cpu(dentry[i].ino), 1, NULL, 0, 1);
+ }
+}
+
+static void dump_data_blk(struct f2fs_sb_info *sbi, __u64 offset, u32 blkaddr, bool is_folder)
{
char buf[F2FS_BLKSIZE];
@@ -288,12 +307,19 @@ static void dump_data_blk(struct f2fs_sb_info *sbi, __u64 offset, u32 blkaddr)
ASSERT(ret >= 0);
}
- /* write blkaddr */
- dev_write_dump(buf, offset, F2FS_BLKSIZE);
+ if (is_folder) {
+ struct f2fs_dentry_block *d = (struct f2fs_dentry_block *) buf;
+
+ dump_folder_contents(sbi, d->dentry_bitmap, F2FS_DENTRY_BLOCK_DENTRIES(d),
+ F2FS_DENTRY_BLOCK_FILENAMES(d), NR_DENTRY_IN_BLOCK);
+ } else {
+ /* write blkaddr */
+ dev_write_dump(buf, offset, F2FS_BLKSIZE);
+ }
}
static void dump_node_blk(struct f2fs_sb_info *sbi, int ntype,
- u32 nid, u32 addr_per_block, u64 *ofs)
+ u32 nid, u32 addr_per_block, u64 *ofs, int is_dir)
{
struct node_info ni;
struct f2fs_node *node_blk;
@@ -330,20 +356,20 @@ static void dump_node_blk(struct f2fs_sb_info *sbi, int ntype,
switch (ntype) {
case TYPE_DIRECT_NODE:
dump_data_blk(sbi, *ofs * F2FS_BLKSIZE,
- le32_to_cpu(node_blk->dn.addr[i]));
+ le32_to_cpu(node_blk->dn.addr[i]), is_dir);
(*ofs)++;
break;
case TYPE_INDIRECT_NODE:
dump_node_blk(sbi, TYPE_DIRECT_NODE,
le32_to_cpu(node_blk->in.nid[i]),
addr_per_block,
- ofs);
+ ofs, is_dir);
break;
case TYPE_DOUBLE_INDIRECT_NODE:
dump_node_blk(sbi, TYPE_INDIRECT_NODE,
le32_to_cpu(node_blk->in.nid[i]),
addr_per_block,
- ofs);
+ ofs, is_dir);
break;
}
}
@@ -435,8 +461,9 @@ static int dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
u32 i = 0;
u64 ofs = 0;
u32 addr_per_block;
+ bool is_dir = S_ISDIR(le16_to_cpu(node_blk->i.i_mode));
- 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);
/* recover from inline data */
dev_write_dump(((unsigned char *)node_blk) + INLINE_DATA_OFFSET,
@@ -444,13 +471,25 @@ static int dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
return -1;
}
+ if ((node_blk->i.i_inline & F2FS_INLINE_DENTRY)) {
+ void *inline_dentry = inline_data_addr(node_blk);
+ struct f2fs_dentry_ptr d;
+
+ make_dentry_ptr(&d, node_blk, inline_dentry, 2);
+
+ DBG(3, "ino[0x%x] has inline dentries!\n", nid);
+ /* recover from inline dentry */
+ dump_folder_contents(sbi, d.bitmap, d.dentry, d.filename, d.max);
+ return -1;
+ }
+
c.show_file_map_max_offset = f2fs_max_file_offset(&node_blk->i);
addr_per_block = ADDRS_PER_BLOCK(&node_blk->i);
/* check data blocks in inode */
for (i = 0; i < ADDRS_PER_INODE(&node_blk->i); i++, ofs++)
dump_data_blk(sbi, ofs * F2FS_BLKSIZE, le32_to_cpu(
- node_blk->i.i_addr[get_extra_isize(node_blk) + i]));
+ node_blk->i.i_addr[get_extra_isize(node_blk) + i]), is_dir);
/* check node blocks in inode */
for (i = 0; i < 5; i++) {
@@ -458,17 +497,20 @@ static int dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
dump_node_blk(sbi, TYPE_DIRECT_NODE,
le32_to_cpu(F2FS_INODE_I_NID(&node_blk->i, i)),
addr_per_block,
- &ofs);
+ &ofs,
+ is_dir);
else if (i == 2 || i == 3)
dump_node_blk(sbi, TYPE_INDIRECT_NODE,
le32_to_cpu(F2FS_INODE_I_NID(&node_blk->i, i)),
addr_per_block,
- &ofs);
+ &ofs,
+ is_dir);
else if (i == 4)
dump_node_blk(sbi, TYPE_DOUBLE_INDIRECT_NODE,
le32_to_cpu(F2FS_INODE_I_NID(&node_blk->i, i)),
addr_per_block,
- &ofs);
+ &ofs,
+ is_dir);
else
ASSERT(0);
}
@@ -479,8 +521,44 @@ static int dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
return 0;
}
-static int dump_file(struct f2fs_sb_info *sbi, struct node_info *ni,
- struct f2fs_node *node_blk, int force)
+static void dump_file(struct f2fs_sb_info *sbi, struct node_info *ni,
+ struct f2fs_node *node_blk, char *path)
+{
+ struct f2fs_inode *inode = &node_blk->i;
+ int ret;
+
+ c.dump_fd = open(path, O_TRUNC|O_CREAT|O_RDWR, 0666);
+ ASSERT(c.dump_fd >= 0);
+
+ /* dump file's data */
+ dump_inode_blk(sbi, ni->ino, node_blk);
+
+ /* adjust file size */
+ ret = ftruncate(c.dump_fd, le32_to_cpu(inode->i_size));
+ ASSERT(ret >= 0);
+
+ close(c.dump_fd);
+}
+
+static void dump_folder(struct f2fs_sb_info *sbi, struct node_info *ni,
+ struct f2fs_node *node_blk, char *path, int is_root)
+{
+ if (!is_root) {
+ if (mkdir(path, 0777) < 0 && errno != EEXIST) {
+ MSG(0, "Failed to create directory %s\n", path);
+ return;
+ }
+ ASSERT(chdir(path) == 0);
+ }
+ /* dump folder data */
+ dump_inode_blk(sbi, ni->ino, node_blk);
+ if (!is_root)
+ ASSERT(chdir("..") == 0);
+}
+
+static int dump_filesystem(struct f2fs_sb_info *sbi, struct node_info *ni,
+ struct f2fs_node *node_blk, int force, char *base_path,
+ bool is_base, bool allow_folder)
{
struct f2fs_inode *inode = &node_blk->i;
u32 imode = le16_to_cpu(inode->i_mode);
@@ -489,6 +567,7 @@ static int dump_file(struct f2fs_sb_info *sbi, struct node_info *ni,
char path[1024] = {0};
char ans[255] = {0};
int is_encrypted = file_is_encrypt(inode);
+ int is_root = sbi->root_ino_num == ni->nid;
int ret;
if (is_encrypted) {
@@ -496,11 +575,15 @@ static int dump_file(struct f2fs_sb_info *sbi, struct node_info *ni,
return -1;
}
- if ((!S_ISREG(imode) && !S_ISLNK(imode)) ||
- namelen == 0 || namelen > F2FS_NAME_LEN) {
- MSG(force, "Not a regular file or wrong name info\n\n");
+ if ((!S_ISREG(imode) && !S_ISLNK(imode) && !(S_ISDIR(imode) && allow_folder))) {
+ MSG(force, "Not a regular file\n\n");
return -1;
}
+ if (!is_root && (namelen == 0 || namelen > F2FS_NAME_LEN)) {
+ MSG(force, "Wrong name info\n\n");
+ return -1;
+ }
+ base_path = base_path ?: "./lost_found";
if (force)
goto dump;
@@ -508,31 +591,42 @@ static int dump_file(struct f2fs_sb_info *sbi, struct node_info *ni,
if (c.show_file_map)
return dump_inode_blk(sbi, ni->ino, node_blk);
- printf("Do you want to dump this file into ./lost_found/? [Y/N] ");
+ printf("Do you want to dump this %s into %s/? [Y/N] ",
+ S_ISREG(imode) || S_ISLNK(imode) ? "file" : "folder",
+ base_path);
ret = scanf("%s", ans);
ASSERT(ret >= 0);
if (!strcasecmp(ans, "y")) {
dump:
- ret = system("mkdir -p ./lost_found");
- ASSERT(ret >= 0);
+ if (is_base) {
+ getcwd(path, sizeof(path));
+ ret = mkdir(base_path, 0777);
+ ASSERT(ret == 0 || errno == EEXIST);
+ ASSERT(chdir(base_path) == 0);
+ }
/* make a file */
- strncpy(name, (const char *)inode->i_name, namelen);
- name[namelen] = 0;
- sprintf(path, "./lost_found/%s", name);
-
- c.dump_fd = open(path, O_TRUNC|O_CREAT|O_RDWR, 0666);
- ASSERT(c.dump_fd >= 0);
-
- /* dump file's data */
- dump_inode_blk(sbi, ni->ino, node_blk);
+ if (!is_root) {
+ strncpy(name, (const char *)inode->i_name, namelen);
+ name[namelen] = 0;
+ }
- /* adjust file size */
- ret = ftruncate(c.dump_fd, le32_to_cpu(inode->i_size));
- ASSERT(ret >= 0);
+ if (S_ISREG(imode) || S_ISLNK(imode)) {
+ dump_file(sbi, ni, node_blk, name);
+ } else {
+ dump_folder(sbi, ni, node_blk, name, is_root);
+ }
- close(c.dump_fd);
+ /* fix up mode/owner */
+ if (c.preserve_perms) {
+ if (is_root)
+ strncpy(name, ".", 2);
+ chmod(name, imode);
+ chown(name, inode->i_uid, inode->i_gid);
+ }
+ if (is_base)
+ chdir(path);
}
return 0;
}
@@ -582,7 +676,7 @@ void dump_node_scan_disk(struct f2fs_sb_info *sbi, nid_t nid)
free(node_blk);
}
-int dump_node(struct f2fs_sb_info *sbi, nid_t nid, int force)
+int dump_node(struct f2fs_sb_info *sbi, nid_t nid, int force, char *base_path, int base, int allow_folder)
{
struct node_info ni;
struct f2fs_node *node_blk;
@@ -617,7 +711,7 @@ int dump_node(struct f2fs_sb_info *sbi, nid_t nid, int force)
print_node_info(sbi, node_blk, force);
if (ni.ino == ni.nid)
- ret = dump_file(sbi, &ni, node_blk, force);
+ ret = dump_filesystem(sbi, &ni, node_blk, force, base_path, base, allow_folder);
} else {
print_node_info(sbi, node_blk, force);
MSG(force, "Invalid (i)node block\n\n");
diff --git a/fsck/fsck.c b/fsck/fsck.c
index 5d345d0..7400dcf 100644
--- a/fsck/fsck.c
+++ b/fsck/fsck.c
@@ -1651,7 +1651,7 @@ static void print_dentry(struct f2fs_sb_info *sbi, __u8 *name,
d = d->next;
}
printf("/%s", new);
- if (dump_node(sbi, le32_to_cpu(dentry[idx].ino), 0))
+ if (dump_node(sbi, le32_to_cpu(dentry[idx].ino), 0, NULL, 0, 0))
printf("\33[2K\r");
} else {
for (i = 1; i < depth; i++)
@@ -3632,7 +3632,7 @@ int fsck_verify(struct f2fs_sb_info *sbi)
if (!strcasecmp(ans, "y")) {
for (i = 0; i < fsck->nr_nat_entries; i++) {
if (f2fs_test_bit(i, fsck->nat_area_bitmap))
- dump_node(sbi, i, 1);
+ dump_node(sbi, i, 1, NULL, 1, 0);
}
}
}
diff --git a/fsck/fsck.h b/fsck/fsck.h
index f5282e2..6cac926 100644
--- a/fsck/fsck.h
+++ b/fsck/fsck.h
@@ -270,12 +270,14 @@ struct dump_option {
int end_ssa;
int32_t blk_addr;
nid_t scan_nid;
+ int use_root_nid;
+ char *base_path;
};
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 ssa_dump(struct f2fs_sb_info *, int, int);
-extern int dump_node(struct f2fs_sb_info *, nid_t, int);
+extern int dump_node(struct f2fs_sb_info *, nid_t, int, char *, int, int);
extern int dump_info_from_blkaddr(struct f2fs_sb_info *, u32);
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);
diff --git a/fsck/main.c b/fsck/main.c
index c4d0956..7d0578a 100644
--- a/fsck/main.c
+++ b/fsck/main.c
@@ -34,7 +34,7 @@ struct f2fs_fsck gfsck;
INIT_FEATURE_TABLE;
-#ifdef WITH_SLOAD
+#if defined(WITH_SLOAD) || defined(WITH_DUMP)
static char *absolute_path(const char *file)
{
char *ret;
@@ -384,7 +384,7 @@ void f2fs_parse_options(int argc, char *argv[])
}
} else if (!strcmp("dump.f2fs", prog)) {
#ifdef WITH_DUMP
- const char *option_string = "d:i:I:n:Ms:Sa:b:V";
+ const char *option_string = "d:fi:I:n:Mo:Prs:Sa:b:Vy";
static struct dump_option dump_opt = {
.nid = 0, /* default root ino */
.start_nat = -1,
@@ -395,6 +395,8 @@ void f2fs_parse_options(int argc, char *argv[])
.end_ssa = -1,
.blk_addr = -1,
.scan_nid = 0,
+ .use_root_nid = 0,
+ .base_path = NULL,
};
c.func = DUMP;
@@ -456,6 +458,19 @@ void f2fs_parse_options(int argc, char *argv[])
ret = sscanf(optarg, "%x",
&dump_opt.blk_addr);
break;
+ case 'y':
+ case 'f':
+ c.force = 1;
+ break;
+ case 'r':
+ dump_opt.use_root_nid = 1;
+ break;
+ case 'o':
+ dump_opt.base_path = absolute_path(optarg);
+ break;
+ case 'P':
+ c.preserve_perms = 1;
+ break;
case 'V':
show_version(prog);
exit(0);
@@ -914,6 +929,9 @@ static void do_dump(struct f2fs_sb_info *sbi)
struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
u32 flag = le32_to_cpu(ckpt->ckpt_flags);
+ if (opt->use_root_nid)
+ opt->nid = sbi->root_ino_num;
+
if (opt->end_nat == -1)
opt->end_nat = NM_I(sbi)->max_nid;
if (opt->end_sit == -1)
@@ -929,7 +947,7 @@ static void do_dump(struct f2fs_sb_info *sbi)
if (opt->blk_addr != -1)
dump_info_from_blkaddr(sbi, opt->blk_addr);
if (opt->nid)
- dump_node(sbi, opt->nid, 0);
+ dump_node(sbi, opt->nid, c.force, opt->base_path, 1, 1);
if (opt->scan_nid)
dump_node_scan_disk(sbi, opt->scan_nid);
diff --git a/man/dump.f2fs.8 b/man/dump.f2fs.8
index 94bf5f3..60d6783 100644
--- a/man/dump.f2fs.8
+++ b/man/dump.f2fs.8
@@ -44,7 +44,8 @@ is used to retrieve f2fs metadata (usually in a disk partition).
\fIdevice\fP is the special file corresponding to the device (e.g.
\fI/dev/sdXX\fP).
-Currently, it can retrieve 1) a file given its inode number, 2) NAT
+Currently, it can retrieve 1) a file or folder given its inode number
+(folders are dumped recursively), 2) NAT
entries into a file, 3) SIT entries into a file, 4) SSA entries into
a file, 5) reverse information from the given block address.
.PP
@@ -56,6 +57,20 @@ is 0 on success and -1 on failure.
.BI \-i " inode number"
Specify an inode number to dump out.
.TP
+.BI \-r
+Dump out from the root inode.
+.TP
+.BI \-f
+Do not prompt before dumping
+.TP
+.BI \-y
+Alias for \-f
+.TP
+.BI \-o " path"
+Dump inodes to the given path
+.BI \-P
+Preserve mode/owner/group for dumped inode
+.TP
.BI \-I " inode number"
Specify an inode number and scan full disk to dump out, include history inode block
.TP
base-commit: 5da4e5241503b385e4a7e75b1b2bb3367b38be96
--
2.45.0.rc1.225.g2a3ae87e7f-goog
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [f2fs-dev] [PATCH 2/2] dump.f2fs: Fix xattr dumping
2024-05-08 0:57 [f2fs-dev] [PATCH 1/2] dump.f2fs: Add ability to dump folders Daniel Rosenberg via Linux-f2fs-devel
@ 2024-05-08 0:57 ` Daniel Rosenberg via Linux-f2fs-devel
2024-05-20 15:12 ` Daeho Jeong
2024-05-20 15:11 ` [f2fs-dev] [PATCH 1/2] dump.f2fs: Add ability to dump folders Daeho Jeong
1 sibling, 1 reply; 4+ messages in thread
From: Daniel Rosenberg via Linux-f2fs-devel @ 2024-05-08 0:57 UTC (permalink / raw)
To: linux-f2fs-devel; +Cc: Jaegeuk Kim, kernel-team, Daniel Rosenberg
Xattrs for files with inline data were being skipped. This dumps those,
as well as xattrs for folders.
Signed-off-by: Daniel Rosenberg <drosen@google.com>
---
fsck/dump.c | 25 +++++++++++++++++--------
1 file changed, 17 insertions(+), 8 deletions(-)
diff --git a/fsck/dump.c b/fsck/dump.c
index f60f6f9..3bd17e3 100644
--- a/fsck/dump.c
+++ b/fsck/dump.c
@@ -377,7 +377,7 @@ static void dump_node_blk(struct f2fs_sb_info *sbi, int ntype,
}
#ifdef HAVE_FSETXATTR
-static void dump_xattr(struct f2fs_sb_info *sbi, struct f2fs_node *node_blk)
+static void dump_xattr(struct f2fs_sb_info *sbi, struct f2fs_node *node_blk, int is_dir)
{
void *xattr;
void *last_base_addr;
@@ -431,8 +431,14 @@ static void dump_xattr(struct f2fs_sb_info *sbi, struct f2fs_node *node_blk)
DBG(1, "fd %d xattr_name %s\n", c.dump_fd, xattr_name);
#if defined(__linux__)
- ret = fsetxattr(c.dump_fd, xattr_name, value,
- le16_to_cpu(ent->e_value_size), 0);
+ if (is_dir) {
+ ret = setxattr(".", xattr_name, value,
+ le16_to_cpu(ent->e_value_size), 0);
+ } else {
+ ret = fsetxattr(c.dump_fd, xattr_name, value,
+ le16_to_cpu(ent->e_value_size), 0);
+ }
+
#elif defined(__APPLE__)
ret = fsetxattr(c.dump_fd, xattr_name, value,
le16_to_cpu(ent->e_value_size), 0,
@@ -462,13 +468,15 @@ static int dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
u64 ofs = 0;
u32 addr_per_block;
bool is_dir = S_ISDIR(le16_to_cpu(node_blk->i.i_mode));
+ int ret = 0;
if ((node_blk->i.i_inline & F2FS_INLINE_DATA)) {
DBG(3, "ino[0x%x] has inline data!\n", nid);
/* recover from inline data */
dev_write_dump(((unsigned char *)node_blk) + INLINE_DATA_OFFSET,
0, MAX_INLINE_DATA(node_blk));
- return -1;
+ ret = -1;
+ goto dump_xattr;
}
if ((node_blk->i.i_inline & F2FS_INLINE_DENTRY)) {
@@ -480,7 +488,8 @@ static int dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
DBG(3, "ino[0x%x] has inline dentries!\n", nid);
/* recover from inline dentry */
dump_folder_contents(sbi, d.bitmap, d.dentry, d.filename, d.max);
- return -1;
+ ret = -1;
+ goto dump_xattr;
}
c.show_file_map_max_offset = f2fs_max_file_offset(&node_blk->i);
@@ -516,9 +525,9 @@ static int dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
}
/* last block in extent cache */
print_extent(true);
-
- dump_xattr(sbi, node_blk);
- return 0;
+dump_xattr:
+ dump_xattr(sbi, node_blk, is_dir);
+ return ret;
}
static void dump_file(struct f2fs_sb_info *sbi, struct node_info *ni,
--
2.45.0.rc1.225.g2a3ae87e7f-goog
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [f2fs-dev] [PATCH 1/2] dump.f2fs: Add ability to dump folders
2024-05-08 0:57 [f2fs-dev] [PATCH 1/2] dump.f2fs: Add ability to dump folders Daniel Rosenberg via Linux-f2fs-devel
2024-05-08 0:57 ` [f2fs-dev] [PATCH 2/2] dump.f2fs: Fix xattr dumping Daniel Rosenberg via Linux-f2fs-devel
@ 2024-05-20 15:11 ` Daeho Jeong
1 sibling, 0 replies; 4+ messages in thread
From: Daeho Jeong @ 2024-05-20 15:11 UTC (permalink / raw)
To: Daniel Rosenberg; +Cc: Jaegeuk Kim, kernel-team, linux-f2fs-devel
On Tue, May 7, 2024 at 6:26 PM Daniel Rosenberg via Linux-f2fs-devel
<linux-f2fs-devel@lists.sourceforge.net> wrote:
>
> This adds the ability to dump folders as well as files. Folders are
> dumped recursively. Additionally, dumped files/folders may be directed
> to a folder specified by -o [path] instead of ./lost_found. The -r flag
> will dump the entire fs from the root inode. -f or -y will skip the
> prompt before dumping, and -P will preserve the mode/owner info for the
> created file/folder.
>
> Signed-off-by: Daniel Rosenberg <drosen@google.com>
> ---
> fsck/dump.c | 164 +++++++++++++++++++++++++++++++++++++-----------
> fsck/fsck.c | 4 +-
> fsck/fsck.h | 4 +-
> fsck/main.c | 24 ++++++-
> man/dump.f2fs.8 | 17 ++++-
> 5 files changed, 171 insertions(+), 42 deletions(-)
>
> diff --git a/fsck/dump.c b/fsck/dump.c
> index b2e990b..f60f6f9 100644
> --- a/fsck/dump.c
> +++ b/fsck/dump.c
> @@ -247,7 +247,26 @@ out:
> printf("\n");
> }
>
> -static void dump_data_blk(struct f2fs_sb_info *sbi, __u64 offset, u32 blkaddr)
> +static void dump_folder_contents(struct f2fs_sb_info *sbi, u8 *bitmap,
> + struct f2fs_dir_entry *dentry,
> + __u8 (*filenames)[F2FS_SLOT_LEN], int max)
> +{
> + int i;
> + int name_len;
> +
> + for (i = 0; i < max; i++) {
> + if (test_bit_le(i, bitmap) == 0)
> + continue;
> + name_len = le16_to_cpu(dentry[i].name_len);
> + if (name_len == 1 && filenames[i][0] == '.')
> + continue;
> + if (name_len == 2 && filenames[i][0] == '.' && filenames[i][1] == '.')
> + continue;
> + dump_node(sbi, le32_to_cpu(dentry[i].ino), 1, NULL, 0, 1);
> + }
> +}
> +
> +static void dump_data_blk(struct f2fs_sb_info *sbi, __u64 offset, u32 blkaddr, bool is_folder)
> {
> char buf[F2FS_BLKSIZE];
>
> @@ -288,12 +307,19 @@ static void dump_data_blk(struct f2fs_sb_info *sbi, __u64 offset, u32 blkaddr)
> ASSERT(ret >= 0);
> }
>
> - /* write blkaddr */
> - dev_write_dump(buf, offset, F2FS_BLKSIZE);
> + if (is_folder) {
> + struct f2fs_dentry_block *d = (struct f2fs_dentry_block *) buf;
> +
> + dump_folder_contents(sbi, d->dentry_bitmap, F2FS_DENTRY_BLOCK_DENTRIES(d),
> + F2FS_DENTRY_BLOCK_FILENAMES(d), NR_DENTRY_IN_BLOCK);
> + } else {
> + /* write blkaddr */
> + dev_write_dump(buf, offset, F2FS_BLKSIZE);
> + }
> }
>
> static void dump_node_blk(struct f2fs_sb_info *sbi, int ntype,
> - u32 nid, u32 addr_per_block, u64 *ofs)
> + u32 nid, u32 addr_per_block, u64 *ofs, int is_dir)
> {
> struct node_info ni;
> struct f2fs_node *node_blk;
> @@ -330,20 +356,20 @@ static void dump_node_blk(struct f2fs_sb_info *sbi, int ntype,
> switch (ntype) {
> case TYPE_DIRECT_NODE:
> dump_data_blk(sbi, *ofs * F2FS_BLKSIZE,
> - le32_to_cpu(node_blk->dn.addr[i]));
> + le32_to_cpu(node_blk->dn.addr[i]), is_dir);
> (*ofs)++;
> break;
> case TYPE_INDIRECT_NODE:
> dump_node_blk(sbi, TYPE_DIRECT_NODE,
> le32_to_cpu(node_blk->in.nid[i]),
> addr_per_block,
> - ofs);
> + ofs, is_dir);
> break;
> case TYPE_DOUBLE_INDIRECT_NODE:
> dump_node_blk(sbi, TYPE_INDIRECT_NODE,
> le32_to_cpu(node_blk->in.nid[i]),
> addr_per_block,
> - ofs);
> + ofs, is_dir);
> break;
> }
> }
> @@ -435,8 +461,9 @@ static int dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
> u32 i = 0;
> u64 ofs = 0;
> u32 addr_per_block;
> + bool is_dir = S_ISDIR(le16_to_cpu(node_blk->i.i_mode));
>
> - 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);
> /* recover from inline data */
> dev_write_dump(((unsigned char *)node_blk) + INLINE_DATA_OFFSET,
> @@ -444,13 +471,25 @@ static int dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
> return -1;
> }
>
> + if ((node_blk->i.i_inline & F2FS_INLINE_DENTRY)) {
> + void *inline_dentry = inline_data_addr(node_blk);
> + struct f2fs_dentry_ptr d;
> +
> + make_dentry_ptr(&d, node_blk, inline_dentry, 2);
> +
> + DBG(3, "ino[0x%x] has inline dentries!\n", nid);
> + /* recover from inline dentry */
> + dump_folder_contents(sbi, d.bitmap, d.dentry, d.filename, d.max);
> + return -1;
> + }
> +
> c.show_file_map_max_offset = f2fs_max_file_offset(&node_blk->i);
> addr_per_block = ADDRS_PER_BLOCK(&node_blk->i);
>
> /* check data blocks in inode */
> for (i = 0; i < ADDRS_PER_INODE(&node_blk->i); i++, ofs++)
> dump_data_blk(sbi, ofs * F2FS_BLKSIZE, le32_to_cpu(
> - node_blk->i.i_addr[get_extra_isize(node_blk) + i]));
> + node_blk->i.i_addr[get_extra_isize(node_blk) + i]), is_dir);
>
> /* check node blocks in inode */
> for (i = 0; i < 5; i++) {
> @@ -458,17 +497,20 @@ static int dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
> dump_node_blk(sbi, TYPE_DIRECT_NODE,
> le32_to_cpu(F2FS_INODE_I_NID(&node_blk->i, i)),
> addr_per_block,
> - &ofs);
> + &ofs,
> + is_dir);
> else if (i == 2 || i == 3)
> dump_node_blk(sbi, TYPE_INDIRECT_NODE,
> le32_to_cpu(F2FS_INODE_I_NID(&node_blk->i, i)),
> addr_per_block,
> - &ofs);
> + &ofs,
> + is_dir);
> else if (i == 4)
> dump_node_blk(sbi, TYPE_DOUBLE_INDIRECT_NODE,
> le32_to_cpu(F2FS_INODE_I_NID(&node_blk->i, i)),
> addr_per_block,
> - &ofs);
> + &ofs,
> + is_dir);
> else
> ASSERT(0);
> }
> @@ -479,8 +521,44 @@ static int dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
> return 0;
> }
>
> -static int dump_file(struct f2fs_sb_info *sbi, struct node_info *ni,
> - struct f2fs_node *node_blk, int force)
> +static void dump_file(struct f2fs_sb_info *sbi, struct node_info *ni,
> + struct f2fs_node *node_blk, char *path)
> +{
> + struct f2fs_inode *inode = &node_blk->i;
> + int ret;
> +
> + c.dump_fd = open(path, O_TRUNC|O_CREAT|O_RDWR, 0666);
> + ASSERT(c.dump_fd >= 0);
> +
> + /* dump file's data */
> + dump_inode_blk(sbi, ni->ino, node_blk);
> +
> + /* adjust file size */
> + ret = ftruncate(c.dump_fd, le32_to_cpu(inode->i_size));
> + ASSERT(ret >= 0);
> +
> + close(c.dump_fd);
> +}
> +
> +static void dump_folder(struct f2fs_sb_info *sbi, struct node_info *ni,
> + struct f2fs_node *node_blk, char *path, int is_root)
> +{
> + if (!is_root) {
> + if (mkdir(path, 0777) < 0 && errno != EEXIST) {
> + MSG(0, "Failed to create directory %s\n", path);
> + return;
> + }
> + ASSERT(chdir(path) == 0);
> + }
> + /* dump folder data */
> + dump_inode_blk(sbi, ni->ino, node_blk);
> + if (!is_root)
> + ASSERT(chdir("..") == 0);
> +}
> +
> +static int dump_filesystem(struct f2fs_sb_info *sbi, struct node_info *ni,
> + struct f2fs_node *node_blk, int force, char *base_path,
> + bool is_base, bool allow_folder)
> {
> struct f2fs_inode *inode = &node_blk->i;
> u32 imode = le16_to_cpu(inode->i_mode);
> @@ -489,6 +567,7 @@ static int dump_file(struct f2fs_sb_info *sbi, struct node_info *ni,
> char path[1024] = {0};
> char ans[255] = {0};
> int is_encrypted = file_is_encrypt(inode);
> + int is_root = sbi->root_ino_num == ni->nid;
> int ret;
>
> if (is_encrypted) {
> @@ -496,11 +575,15 @@ static int dump_file(struct f2fs_sb_info *sbi, struct node_info *ni,
> return -1;
> }
>
> - if ((!S_ISREG(imode) && !S_ISLNK(imode)) ||
> - namelen == 0 || namelen > F2FS_NAME_LEN) {
> - MSG(force, "Not a regular file or wrong name info\n\n");
> + if ((!S_ISREG(imode) && !S_ISLNK(imode) && !(S_ISDIR(imode) && allow_folder))) {
> + MSG(force, "Not a regular file\n\n");
MSG(force, "Not a valid file type\n\n") ?
> return -1;
> }
> + if (!is_root && (namelen == 0 || namelen > F2FS_NAME_LEN)) {
> + MSG(force, "Wrong name info\n\n");
> + return -1;
> + }
> + base_path = base_path ?: "./lost_found";
> if (force)
> goto dump;
>
> @@ -508,31 +591,42 @@ static int dump_file(struct f2fs_sb_info *sbi, struct node_info *ni,
> if (c.show_file_map)
> return dump_inode_blk(sbi, ni->ino, node_blk);
>
> - printf("Do you want to dump this file into ./lost_found/? [Y/N] ");
> + printf("Do you want to dump this %s into %s/? [Y/N] ",
> + S_ISREG(imode) || S_ISLNK(imode) ? "file" : "folder",
> + base_path);
> ret = scanf("%s", ans);
> ASSERT(ret >= 0);
>
> if (!strcasecmp(ans, "y")) {
> dump:
> - ret = system("mkdir -p ./lost_found");
> - ASSERT(ret >= 0);
> + if (is_base) {
> + getcwd(path, sizeof(path));
> + ret = mkdir(base_path, 0777);
> + ASSERT(ret == 0 || errno == EEXIST);
> + ASSERT(chdir(base_path) == 0);
> + }
>
> /* make a file */
> - strncpy(name, (const char *)inode->i_name, namelen);
> - name[namelen] = 0;
> - sprintf(path, "./lost_found/%s", name);
> -
> - c.dump_fd = open(path, O_TRUNC|O_CREAT|O_RDWR, 0666);
> - ASSERT(c.dump_fd >= 0);
> -
> - /* dump file's data */
> - dump_inode_blk(sbi, ni->ino, node_blk);
> + if (!is_root) {
> + strncpy(name, (const char *)inode->i_name, namelen);
> + name[namelen] = 0;
> + }
>
> - /* adjust file size */
> - ret = ftruncate(c.dump_fd, le32_to_cpu(inode->i_size));
> - ASSERT(ret >= 0);
> + if (S_ISREG(imode) || S_ISLNK(imode)) {
> + dump_file(sbi, ni, node_blk, name);
> + } else {
> + dump_folder(sbi, ni, node_blk, name, is_root);
> + }
>
> - close(c.dump_fd);
> + /* fix up mode/owner */
> + if (c.preserve_perms) {
> + if (is_root)
> + strncpy(name, ".", 2);
> + chmod(name, imode);
> + chown(name, inode->i_uid, inode->i_gid);
> + }
> + if (is_base)
> + chdir(path);
> }
> return 0;
> }
> @@ -582,7 +676,7 @@ void dump_node_scan_disk(struct f2fs_sb_info *sbi, nid_t nid)
> free(node_blk);
> }
>
> -int dump_node(struct f2fs_sb_info *sbi, nid_t nid, int force)
> +int dump_node(struct f2fs_sb_info *sbi, nid_t nid, int force, char *base_path, int base, int allow_folder)
> {
> struct node_info ni;
> struct f2fs_node *node_blk;
> @@ -617,7 +711,7 @@ int dump_node(struct f2fs_sb_info *sbi, nid_t nid, int force)
> print_node_info(sbi, node_blk, force);
>
> if (ni.ino == ni.nid)
> - ret = dump_file(sbi, &ni, node_blk, force);
> + ret = dump_filesystem(sbi, &ni, node_blk, force, base_path, base, allow_folder);
> } else {
> print_node_info(sbi, node_blk, force);
> MSG(force, "Invalid (i)node block\n\n");
> diff --git a/fsck/fsck.c b/fsck/fsck.c
> index 5d345d0..7400dcf 100644
> --- a/fsck/fsck.c
> +++ b/fsck/fsck.c
> @@ -1651,7 +1651,7 @@ static void print_dentry(struct f2fs_sb_info *sbi, __u8 *name,
> d = d->next;
> }
> printf("/%s", new);
> - if (dump_node(sbi, le32_to_cpu(dentry[idx].ino), 0))
> + if (dump_node(sbi, le32_to_cpu(dentry[idx].ino), 0, NULL, 0, 0))
> printf("\33[2K\r");
> } else {
> for (i = 1; i < depth; i++)
> @@ -3632,7 +3632,7 @@ int fsck_verify(struct f2fs_sb_info *sbi)
> if (!strcasecmp(ans, "y")) {
> for (i = 0; i < fsck->nr_nat_entries; i++) {
> if (f2fs_test_bit(i, fsck->nat_area_bitmap))
> - dump_node(sbi, i, 1);
> + dump_node(sbi, i, 1, NULL, 1, 0);
> }
> }
> }
> diff --git a/fsck/fsck.h b/fsck/fsck.h
> index f5282e2..6cac926 100644
> --- a/fsck/fsck.h
> +++ b/fsck/fsck.h
> @@ -270,12 +270,14 @@ struct dump_option {
> int end_ssa;
> int32_t blk_addr;
> nid_t scan_nid;
> + int use_root_nid;
> + char *base_path;
> };
>
> 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 ssa_dump(struct f2fs_sb_info *, int, int);
> -extern int dump_node(struct f2fs_sb_info *, nid_t, int);
> +extern int dump_node(struct f2fs_sb_info *, nid_t, int, char *, int, int);
> extern int dump_info_from_blkaddr(struct f2fs_sb_info *, u32);
> 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);
> diff --git a/fsck/main.c b/fsck/main.c
> index c4d0956..7d0578a 100644
> --- a/fsck/main.c
> +++ b/fsck/main.c
> @@ -34,7 +34,7 @@ struct f2fs_fsck gfsck;
>
> INIT_FEATURE_TABLE;
>
> -#ifdef WITH_SLOAD
> +#if defined(WITH_SLOAD) || defined(WITH_DUMP)
> static char *absolute_path(const char *file)
> {
> char *ret;
> @@ -384,7 +384,7 @@ void f2fs_parse_options(int argc, char *argv[])
> }
> } else if (!strcmp("dump.f2fs", prog)) {
> #ifdef WITH_DUMP
> - const char *option_string = "d:i:I:n:Ms:Sa:b:V";
> + const char *option_string = "d:fi:I:n:Mo:Prs:Sa:b:Vy";
> static struct dump_option dump_opt = {
> .nid = 0, /* default root ino */
> .start_nat = -1,
> @@ -395,6 +395,8 @@ void f2fs_parse_options(int argc, char *argv[])
> .end_ssa = -1,
> .blk_addr = -1,
> .scan_nid = 0,
> + .use_root_nid = 0,
> + .base_path = NULL,
> };
>
> c.func = DUMP;
> @@ -456,6 +458,19 @@ void f2fs_parse_options(int argc, char *argv[])
> ret = sscanf(optarg, "%x",
> &dump_opt.blk_addr);
> break;
> + case 'y':
> + case 'f':
> + c.force = 1;
> + break;
> + case 'r':
> + dump_opt.use_root_nid = 1;
> + break;
> + case 'o':
> + dump_opt.base_path = absolute_path(optarg);
> + break;
> + case 'P':
> + c.preserve_perms = 1;
> + break;
> case 'V':
> show_version(prog);
> exit(0);
> @@ -914,6 +929,9 @@ static void do_dump(struct f2fs_sb_info *sbi)
> struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
> u32 flag = le32_to_cpu(ckpt->ckpt_flags);
>
> + if (opt->use_root_nid)
> + opt->nid = sbi->root_ino_num;
> +
> if (opt->end_nat == -1)
> opt->end_nat = NM_I(sbi)->max_nid;
> if (opt->end_sit == -1)
> @@ -929,7 +947,7 @@ static void do_dump(struct f2fs_sb_info *sbi)
> if (opt->blk_addr != -1)
> dump_info_from_blkaddr(sbi, opt->blk_addr);
> if (opt->nid)
> - dump_node(sbi, opt->nid, 0);
> + dump_node(sbi, opt->nid, c.force, opt->base_path, 1, 1);
> if (opt->scan_nid)
> dump_node_scan_disk(sbi, opt->scan_nid);
>
> diff --git a/man/dump.f2fs.8 b/man/dump.f2fs.8
> index 94bf5f3..60d6783 100644
> --- a/man/dump.f2fs.8
> +++ b/man/dump.f2fs.8
> @@ -44,7 +44,8 @@ is used to retrieve f2fs metadata (usually in a disk partition).
> \fIdevice\fP is the special file corresponding to the device (e.g.
> \fI/dev/sdXX\fP).
>
> -Currently, it can retrieve 1) a file given its inode number, 2) NAT
> +Currently, it can retrieve 1) a file or folder given its inode number
> +(folders are dumped recursively), 2) NAT
> entries into a file, 3) SIT entries into a file, 4) SSA entries into
> a file, 5) reverse information from the given block address.
> .PP
> @@ -56,6 +57,20 @@ is 0 on success and -1 on failure.
> .BI \-i " inode number"
> Specify an inode number to dump out.
> .TP
> +.BI \-r
> +Dump out from the root inode.
> +.TP
> +.BI \-f
> +Do not prompt before dumping
> +.TP
> +.BI \-y
> +Alias for \-f
> +.TP
> +.BI \-o " path"
> +Dump inodes to the given path
> +.BI \-P
> +Preserve mode/owner/group for dumped inode
> +.TP
> .BI \-I " inode number"
> Specify an inode number and scan full disk to dump out, include history inode block
> .TP
>
> base-commit: 5da4e5241503b385e4a7e75b1b2bb3367b38be96
> --
> 2.45.0.rc1.225.g2a3ae87e7f-goog
>
>
>
> _______________________________________________
> Linux-f2fs-devel mailing list
> Linux-f2fs-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [f2fs-dev] [PATCH 2/2] dump.f2fs: Fix xattr dumping
2024-05-08 0:57 ` [f2fs-dev] [PATCH 2/2] dump.f2fs: Fix xattr dumping Daniel Rosenberg via Linux-f2fs-devel
@ 2024-05-20 15:12 ` Daeho Jeong
0 siblings, 0 replies; 4+ messages in thread
From: Daeho Jeong @ 2024-05-20 15:12 UTC (permalink / raw)
To: Daniel Rosenberg; +Cc: Jaegeuk Kim, kernel-team, linux-f2fs-devel
On Tue, May 7, 2024 at 6:23 PM Daniel Rosenberg via Linux-f2fs-devel
<linux-f2fs-devel@lists.sourceforge.net> wrote:
>
> Xattrs for files with inline data were being skipped. This dumps those,
> as well as xattrs for folders.
>
> Signed-off-by: Daniel Rosenberg <drosen@google.com>
> ---
> fsck/dump.c | 25 +++++++++++++++++--------
> 1 file changed, 17 insertions(+), 8 deletions(-)
>
> diff --git a/fsck/dump.c b/fsck/dump.c
> index f60f6f9..3bd17e3 100644
> --- a/fsck/dump.c
> +++ b/fsck/dump.c
> @@ -377,7 +377,7 @@ static void dump_node_blk(struct f2fs_sb_info *sbi, int ntype,
> }
>
> #ifdef HAVE_FSETXATTR
> -static void dump_xattr(struct f2fs_sb_info *sbi, struct f2fs_node *node_blk)
> +static void dump_xattr(struct f2fs_sb_info *sbi, struct f2fs_node *node_blk, int is_dir)
> {
> void *xattr;
> void *last_base_addr;
> @@ -431,8 +431,14 @@ static void dump_xattr(struct f2fs_sb_info *sbi, struct f2fs_node *node_blk)
>
> DBG(1, "fd %d xattr_name %s\n", c.dump_fd, xattr_name);
> #if defined(__linux__)
> - ret = fsetxattr(c.dump_fd, xattr_name, value,
> - le16_to_cpu(ent->e_value_size), 0);
> + if (is_dir) {
> + ret = setxattr(".", xattr_name, value,
> + le16_to_cpu(ent->e_value_size), 0);
> + } else {
> + ret = fsetxattr(c.dump_fd, xattr_name, value,
> + le16_to_cpu(ent->e_value_size), 0);
> + }
> +
> #elif defined(__APPLE__)
> ret = fsetxattr(c.dump_fd, xattr_name, value,
> le16_to_cpu(ent->e_value_size), 0,
> @@ -462,13 +468,15 @@ static int dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
> u64 ofs = 0;
> u32 addr_per_block;
> bool is_dir = S_ISDIR(le16_to_cpu(node_blk->i.i_mode));
> + int ret = 0;
>
> if ((node_blk->i.i_inline & F2FS_INLINE_DATA)) {
> DBG(3, "ino[0x%x] has inline data!\n", nid);
> /* recover from inline data */
> dev_write_dump(((unsigned char *)node_blk) + INLINE_DATA_OFFSET,
> 0, MAX_INLINE_DATA(node_blk));
> - return -1;
> + ret = -1;
> + goto dump_xattr;
> }
>
> if ((node_blk->i.i_inline & F2FS_INLINE_DENTRY)) {
> @@ -480,7 +488,8 @@ static int dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
> DBG(3, "ino[0x%x] has inline dentries!\n", nid);
> /* recover from inline dentry */
> dump_folder_contents(sbi, d.bitmap, d.dentry, d.filename, d.max);
> - return -1;
> + ret = -1;
> + goto dump_xattr;
> }
>
> c.show_file_map_max_offset = f2fs_max_file_offset(&node_blk->i);
> @@ -516,9 +525,9 @@ static int dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
> }
> /* last block in extent cache */
> print_extent(true);
> -
> - dump_xattr(sbi, node_blk);
> - return 0;
> +dump_xattr:
> + dump_xattr(sbi, node_blk, is_dir);
> + return ret;
> }
>
> static void dump_file(struct f2fs_sb_info *sbi, struct node_info *ni,
> --
> 2.45.0.rc1.225.g2a3ae87e7f-goog
>
>
Reviewed-by: Daeho Jeong <daehojeong@google.com>
Thanks,
>
> _______________________________________________
> Linux-f2fs-devel mailing list
> Linux-f2fs-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2024-05-20 15:12 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-05-08 0:57 [f2fs-dev] [PATCH 1/2] dump.f2fs: Add ability to dump folders Daniel Rosenberg via Linux-f2fs-devel
2024-05-08 0:57 ` [f2fs-dev] [PATCH 2/2] dump.f2fs: Fix xattr dumping Daniel Rosenberg via Linux-f2fs-devel
2024-05-20 15:12 ` Daeho Jeong
2024-05-20 15:11 ` [f2fs-dev] [PATCH 1/2] dump.f2fs: Add ability to dump folders Daeho Jeong
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).