From patchwork Thu May 23 22:46:59 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Rosenberg X-Patchwork-Id: 13672348 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.sourceforge.net (lists.sourceforge.net [216.105.38.7]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 5A178C25B79 for ; Thu, 23 May 2024 22:47:18 +0000 (UTC) Received: from [127.0.0.1] (helo=sfs-ml-1.v29.lw.sourceforge.com) by sfs-ml-1.v29.lw.sourceforge.com with esmtp (Exim 4.95) (envelope-from ) id 1sAHDQ-0003eD-QE; Thu, 23 May 2024 22:47:18 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-1.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from <3aMdPZgYKAG8QebfRaTbbTYR.PbZ@flex--drosen.bounces.google.com>) id 1sAHDP-0003e6-L0 for linux-f2fs-devel@lists.sourceforge.net; Thu, 23 May 2024 22:47:16 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Type:Cc:To:From:Subject:Message-ID: Mime-Version:Date:Sender:Reply-To:Content-Transfer-Encoding:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=vyVQV284sS/EOjCusdN6JI2zjuhpl1ZPsmOsymYsB84=; b=eAo1ae/EOAHtf6yxgIHU8vTN52 64ZKuDnHUp2TwO58iNUAcJtjGbXGyUaR5ML6pNC8luVmYfAONPcbsolwGtfwkUQLSGDn+yafC/2a+ kY/iuQgMEcziDnjpsT7yFjBTLoZ6dMbMKmUSu9S3cZa/6ffCbxuVIWFtibVIZAlzPRMI=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Type:Cc:To:From:Subject:Message-ID:Mime-Version:Date:Sender: Reply-To:Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date :Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To: References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post: List-Owner:List-Archive; bh=vyVQV284sS/EOjCusdN6JI2zjuhpl1ZPsmOsymYsB84=; b=X PqihrGbuBo5vkhL8KG7AZjLWqHJInt9lXLgjz70aYdwQB8fY3IFIJ9EBYJuWpHVl6f/z3XSaBLS4R 8oPks3P7mqojC2eJh8yHjmT72uWixNxZ5zSLKvRedC1QJ19sPB/XYPvv+1e/BteI8mVbYWfohOe8R 5SWab00z9TAHIwck=; Received: from mail-yb1-f202.google.com ([209.85.219.202]) by sfi-mx-2.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES128-GCM-SHA256:128) (Exim 4.95) id 1sAHDQ-0005ji-AB for linux-f2fs-devel@lists.sourceforge.net; Thu, 23 May 2024 22:47:16 +0000 Received: by mail-yb1-f202.google.com with SMTP id 3f1490d57ef6-dee5f035dd6so24412405276.0 for ; Thu, 23 May 2024 15:47:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1716504425; x=1717109225; darn=lists.sourceforge.net; h=cc:to:from:subject:message-id:mime-version:date:from:to:cc:subject :date:message-id:reply-to; bh=vyVQV284sS/EOjCusdN6JI2zjuhpl1ZPsmOsymYsB84=; b=bRad+HU0FVOKh1eLwCYgf6VRkEQ025V1xmlJNQrNmkM2sNa8EdV6zAG+G+hMo6uf0a oC5qpQYen20nXwPSpK7KHHNvZzTjlCMEY5KaZ4eIz7GhVjss1G66kjg6yCE95lQxQl9y TqTt44MfosHWBTV3xfWZGzPJNG4TVv/ZMrZBDO74wp6jhmnuMLaKeXkJq+FVnJgOWRhF Hd9/9g07SH1qRZlTk0izDnE8470P4iH4hXFcFVzCyk6qw4+GQlLWCeZD4/ITgRGKcCx2 BVnmmz6oEdEg1WIoYmosgktLU15RBjf48vM1Qum4EFdMIWpqoJ63qcctb8bS/IyiZpfe YFIg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1716504425; x=1717109225; h=cc:to:from:subject:message-id:mime-version:date:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=vyVQV284sS/EOjCusdN6JI2zjuhpl1ZPsmOsymYsB84=; b=i0TcNjRETkTk3eLZ+nbJb6h3RMZ/JfdcWBo4Iw7gBgZBq8UjPrRq+laih9PpOT0AkN Mfsxshc66E54ZPwB3VrkD8/qRF98v7mKZSPN6hjjA1qFJj2aNNClHx8QGsmaKZHgIwND hQT7YDLJeZmoFqnlTwo4khPuYh8CCtugAaiph5Ou8HkmwhgdvGbtPvkNf+1V8tcwXBZr iqznW/r0RjwGHfuR5NUZCESw92gq8WM3uHb7QgCD4JU5fJshpKxpt+SxXzG4ADCKb34u CK5QVuXvMUVZzSLS9AKbRuZ2MIZ0QN46g5OxgEUhk1/ILTW4hiKiuTZzdyz8IK08O39Q CR8A== X-Gm-Message-State: AOJu0Ywza/ST4v1x+Mcvk1cRYO5pxM/ahueQD66mRA5o/IdQuRQFZu7c 0bOyX0OAP4YLgpnk5tEynfYnHA9pGyTR3sdrowInTmLJj4bZmwlYlZ1rykGOgfdNQOvROA8nfSG HjQfHJzFCJpTDJ9ycQEu2fkQXg0ATnEtINsHp9ezpDMoUnBG6eF8/dphuxhbYgeuYsHKMuxQgwL 4UQCDxXy0N8NiCZ7+7IPsAARC3wvw6Tq5fDsQIXgo6lvLafwQLNl7lLA== X-Google-Smtp-Source: AGHT+IFNjWn1IzlsEJljSwgaoCzOUsUP+qgVpie1FnoRTs/Ih+x8wFrpTLDEDvrrh9YOek+YP34HWezPNE4= X-Received: from drosen.mtv.corp.google.com ([2620:15c:211:201:3506:bc94:4f44:4a86]) (user=drosen job=sendgmr) by 2002:a05:6902:e89:b0:dc9:c54e:c5eb with SMTP id 3f1490d57ef6-df77219d04fmr124483276.7.1716504424697; Thu, 23 May 2024 15:47:04 -0700 (PDT) Date: Thu, 23 May 2024 15:46:59 -0700 Mime-Version: 1.0 X-Mailer: git-send-email 2.45.1.288.g0e0cd299f1-goog Message-ID: <20240523224700.265251-1-drosen@google.com> To: linux-f2fs-devel@lists.sourceforge.net X-Headers-End: 1sAHDQ-0005ji-AB Subject: [f2fs-dev] [PATCH v4 1/2] dump.f2fs: Add ability to dump folders X-BeenThere: linux-f2fs-devel@lists.sourceforge.net X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Daniel Rosenberg via Linux-f2fs-devel From: Daniel Rosenberg Reply-To: Daniel Rosenberg Cc: Jaegeuk Kim , kernel-team@android.com, Daeho Jeong , Daniel Rosenberg Errors-To: linux-f2fs-devel-bounces@lists.sourceforge.net 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 Reviewed-by: Daeho Jeong Reviewed-by: Daeho Jeong --- fsck/dump.c | 178 ++++++++++++++++++++++++++++++++++++++---------- fsck/fsck.c | 4 +- fsck/fsck.h | 4 +- fsck/main.c | 29 +++++++- man/dump.f2fs.8 | 17 ++++- 5 files changed, 190 insertions(+), 42 deletions(-) base-commit: 5da4e5241503b385e4a7e75b1b2bb3367b38be96 diff --git a/fsck/dump.c b/fsck/dump.c index b2e990b..fa68456 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,51 @@ 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 defined(__MINGW32__) + if (mkdir(path) < 0 && errno != EEXIST) { + MSG(0, "Failed to create directory %s\n", path); + return; + } +#else + if (mkdir(path, 0777) < 0 && errno != EEXIST) { + MSG(0, "Failed to create directory %s\n", path); + return; + } +#endif + 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 +574,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 +582,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 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 +598,49 @@ 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); - - /* make a file */ - strncpy(name, (const char *)inode->i_name, namelen); - name[namelen] = 0; - sprintf(path, "./lost_found/%s", name); + if (is_base) { + ASSERT(getcwd(path, sizeof(path)) != NULL); +#if defined(__MINGW32__) + ret = mkdir(base_path); +#else + ret = mkdir(base_path, 0777); +#endif - c.dump_fd = open(path, O_TRUNC|O_CREAT|O_RDWR, 0666); - ASSERT(c.dump_fd >= 0); + ASSERT(ret == 0 || errno == EEXIST); + ASSERT(chdir(base_path) == 0); + } - /* dump file's data */ - dump_inode_blk(sbi, ni->ino, node_blk); + /* make a file */ + 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); +#if !defined(__MINGW32__) + /* fix up mode/owner */ + if (c.preserve_perms) { + if (is_root) + strncpy(name, ".", 2); + ASSERT(chmod(name, imode) == 0); + ASSERT(chown(name, inode->i_uid, inode->i_gid) == 0); + } +#endif + if (is_base) + ASSERT(chdir(path) == 0); } return 0; } @@ -582,7 +690,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 +725,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..6edc902 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,24 @@ 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': +#if defined(__MINGW32__) + MSG(0, "-P not supported for Windows\n"); + err = EWRONG_OPT; +#else + c.preserve_perms = 1; +#endif + break; case 'V': show_version(prog); exit(0); @@ -914,6 +934,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 +952,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 From patchwork Thu May 23 22:47:00 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Rosenberg X-Patchwork-Id: 13672347 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.sourceforge.net (lists.sourceforge.net [216.105.38.7]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id D11EDC25B75 for ; Thu, 23 May 2024 22:47:16 +0000 (UTC) Received: from [127.0.0.1] (helo=sfs-ml-4.v29.lw.sourceforge.com) by sfs-ml-4.v29.lw.sourceforge.com with esmtp (Exim 4.95) (envelope-from ) id 1sAHDO-0004Au-6T; Thu, 23 May 2024 22:47:14 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-4.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from <3asdPZgYKAHESgdhTcVddVaT.Rdb@flex--drosen.bounces.google.com>) id 1sAHDN-0004Ao-2Q for linux-f2fs-devel@lists.sourceforge.net; Thu, 23 May 2024 22:47:13 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Type:Cc:To:From:Subject:Message-ID: References:Mime-Version:In-Reply-To:Date:Sender:Reply-To: Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id: List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive; bh=tYSWFZlsHPFH8fDa5o3xDdSuHwsfIEAIGI4hrt6rJok=; b=ITHsdAs4uG/NgAJYq7blZvLuy7 S/vreaRc/qH4FcHK1ibDEPicK8TGjlTkrxqwFyJMV6ELEsORQ5uq0M4rR9JN0NyFngiPHwrWaAEAK t2dcZc9q07Ncrx1Cjb+CGqy29q74OefV3UlK3MvQFZ2tg5Uk7uW9SASYmTnb5o/q1Ufg=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Type:Cc:To:From:Subject:Message-ID:References:Mime-Version: In-Reply-To:Date:Sender:Reply-To:Content-Transfer-Encoding:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=tYSWFZlsHPFH8fDa5o3xDdSuHwsfIEAIGI4hrt6rJok=; b=EK5k3eUF5Ay9uMCRJ8SOYf2heW guIe+9PcdrKsNt4L3a3sn7DO485MaqCb0qxMU4bQoSv9Qos0tOlcsKWGgC9jnhHprAxWuvFkJlGyL J7B6IqOKDhxz1gprqGseiRYl63Bf+9lrPRwDo2kz8S2ClUhu70rE+x2diDnsqXHeeels=; Received: from mail-yw1-f201.google.com ([209.85.128.201]) by sfi-mx-2.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES128-GCM-SHA256:128) (Exim 4.95) id 1sAHDN-0005je-Eu for linux-f2fs-devel@lists.sourceforge.net; Thu, 23 May 2024 22:47:13 +0000 Received: by mail-yw1-f201.google.com with SMTP id 00721157ae682-627e4afa326so46333747b3.2 for ; Thu, 23 May 2024 15:47:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1716504427; x=1717109227; darn=lists.sourceforge.net; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=tYSWFZlsHPFH8fDa5o3xDdSuHwsfIEAIGI4hrt6rJok=; b=NDG2Y+1ofUj423p7yhyGygczN6gnhf8Ed4L5q9g8C4eV5wF4vF2KTrc46cuwdJ1KM9 cYyhm6ZhOdvO0nLfbgf1m/O6maS6Tp5BcfY5o6JYH4M0P+3e0PlERBv6Bn3G6EDKGBPb pTaWmq+1P2+m5MR4E2cvz0hqqobU5978LebdbTcXjtc+VoYfo76ysneYd1FwGfa/Om8o wZGeZkRs11/qaTaDKZkJkVRKnwRTFgafOG48/BwclV6DC9qvFm6PmHUtDV6VRwGzUF8w 2sd6S0Hfp/QocTUmqSK1OxvF2iJg37/m9Edlo/Y1Yw/in9VCKPtrDiIGizv2fzkOKEn2 6QFg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1716504427; x=1717109227; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=tYSWFZlsHPFH8fDa5o3xDdSuHwsfIEAIGI4hrt6rJok=; b=iAyR92Zs8CwFQ4VkpZ8z1DIf9R3Npf9qBzRjVTSKtvm7SISoXexZeSt0kuBpspjzWK O69J/DR0QFO3TAntuLVzn5T35aCXYRXJJJEoyGRDOLYXfBRt44a4FUlQJllGYQXzU817 3O0vMl2H4iinhfxr5ysz1wYen6GSk5jccW0/8s+4B4xI2pi1sSwS7CzbpnDPmTAoa0Q2 Gy6xWuOvI7DHavAr5tJy1acyQVyg2VMAsbhyntz09fknDmJJdsG5XsMaSBV3xBy7oE+O 5OcqRUC+NwEhHREpWRwk0Xhwt7u84anELs1c0/LSTS5h2hfnmBkmBySij9aevnSUt3x5 HdPQ== X-Gm-Message-State: AOJu0YzBoYpoLv8TRZ7AHUEMOnvQpwiZBswBD5LwG1xOQyLrGykXoMVl HBiovVjxcfu87etQNKkG3YllR0JHH3qRZ2p3pUCe3vAJCss77vFfffgTyhJzKDu+52lOVyN1OV1 SPS4LVUXnOCXzs6MfSkl63lAdmNV7vX7EqEoJeo6tSB/YSpR1qvQAvMYyaGmCFPDxVkPIQhC3gh doSK8xt5FFHW3IphP86Tk51F4Viu0dbLwF2DUUJT6R4D9kZ+UGUhV1yA== X-Google-Smtp-Source: AGHT+IGJA3hwWZEopZSNPZUKF3ShgtMf2na7OvtKvEeynJiD3vZcQ6dI/j2+8wByqLpwttI7k/CMVOL/IxY= X-Received: from drosen.mtv.corp.google.com ([2620:15c:211:201:3506:bc94:4f44:4a86]) (user=drosen job=sendgmr) by 2002:a05:690c:25c8:b0:61b:e103:804d with SMTP id 00721157ae682-62a08b258a8mr1273797b3.0.1716504426804; Thu, 23 May 2024 15:47:06 -0700 (PDT) Date: Thu, 23 May 2024 15:47:00 -0700 In-Reply-To: <20240523224700.265251-1-drosen@google.com> Mime-Version: 1.0 References: <20240523224700.265251-1-drosen@google.com> X-Mailer: git-send-email 2.45.1.288.g0e0cd299f1-goog Message-ID: <20240523224700.265251-2-drosen@google.com> To: linux-f2fs-devel@lists.sourceforge.net X-Headers-End: 1sAHDN-0005je-Eu Subject: [f2fs-dev] [PATCH v4 2/2] dump.f2fs: Fix xattr dumping X-BeenThere: linux-f2fs-devel@lists.sourceforge.net X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Daniel Rosenberg via Linux-f2fs-devel From: Daniel Rosenberg Reply-To: Daniel Rosenberg Cc: Jaegeuk Kim , kernel-team@android.com, Daeho Jeong , Daniel Rosenberg Errors-To: linux-f2fs-devel-bounces@lists.sourceforge.net Xattrs for files with inline data were being skipped. This dumps those, as well as xattrs for folders. Signed-off-by: Daniel Rosenberg Reviewed-by: Daeho Jeong Reviewed-by: Daeho Jeong Reviewed-by: Chao Yu --- fsck/dump.c | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/fsck/dump.c b/fsck/dump.c index fa68456..90e3e0e 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,12 +431,24 @@ 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, - XATTR_CREATE); + if (is_dir) { + ret = setxattr(".", xattr_name, value, + le16_to_cpu(ent->e_value_size), 0, + XATTR_CREATE); + } else { + ret = fsetxattr(c.dump_fd, xattr_name, value, + le16_to_cpu(ent->e_value_size), 0, + XATTR_CREATE); + } #endif if (ret) MSG(0, "XATTR index 0x%x set xattr failed error %d\n", @@ -449,7 +461,7 @@ static void dump_xattr(struct f2fs_sb_info *sbi, struct f2fs_node *node_blk) } #else static void dump_xattr(struct f2fs_sb_info *UNUSED(sbi), - struct f2fs_node *UNUSED(node_blk)) + struct f2fs_node *UNUSED(node_blk), int UNUSED(is_dir)) { MSG(0, "XATTR does not support\n"); } @@ -462,13 +474,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 +494,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 +531,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,