[git commit] lsattr,chattr: support -p

Denys Vlasenko vda.linux at googlemail.com
Sun Jun 20 09:02:49 UTC 2021


commit: https://git.busybox.net/busybox/commit/?id=526b8347906a18d756386092fafa0b42ba0b4563
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

function                                             old     new   delta
fgetsetprojid                                          -     107    +107
list_attributes                                      169     222     +53
change_attributes                                    277     326     +49
chattr_main                                          272     307     +35
close_silently                                         -      22     +22
.rodata                                           103378  103393     +15
packed_usage                                       33658   33666      +8
fgetsetversion                                        88      74     -14
fgetsetflags                                         162     148     -14
------------------------------------------------------------------------------
(add/remove: 2/0 grow/shrink: 5/2 up/down: 289/-28)           Total: 261 bytes

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 e2fsprogs/chattr.c     | 28 ++++++++++++++++++++--------
 e2fsprogs/e2fs_lib.c   | 34 ++++++++++++++++++++++++++++++----
 e2fsprogs/e2fs_lib.h   |  5 +++++
 e2fsprogs/lsattr.c     | 32 +++++++++++++++++++++-----------
 include/bb_e2fs_defs.h | 12 ++++++++++++
 5 files changed, 88 insertions(+), 23 deletions(-)

diff --git a/e2fsprogs/chattr.c b/e2fsprogs/chattr.c
index 1d267f7a4..5a7545e09 100644
--- a/e2fsprogs/chattr.c
+++ b/e2fsprogs/chattr.c
@@ -20,12 +20,12 @@
 //kbuild:lib-$(CONFIG_CHATTR) += chattr.o e2fs_lib.o
 
 //usage:#define chattr_trivial_usage
-//usage:       "[-R] [-v VERSION] [-+=AacDdijsStTu] FILE..."
+//usage:       "[-R] [-v VERSION] [-p PROJID] [-+=AacDdijsStTu] FILE..."
 //usage:#define chattr_full_usage "\n\n"
 //usage:       "Change ext2 file attributes\n"
 //usage:     "\n	-R	Recurse"
-//TODD?      "\n	-p NUM	Set project number"
 //usage:     "\n	-v NUM	Set version/generation number"
+//usage:     "\n	-p NUM	Set project number"
 //-V, -f accepted but ignored
 //usage:     "\nModifiers:"
 //usage:     "\n	-,+,=	Remove/add/set attributes"
@@ -45,16 +45,18 @@
 #include "libbb.h"
 #include "e2fs_lib.h"
 
-#define OPT_ADD 1
-#define OPT_REM 2
-#define OPT_SET 4
-#define OPT_SET_VER 8
+#define OPT_ADD      (1 << 0)
+#define OPT_REM      (1 << 1)
+#define OPT_SET      (1 << 2)
+#define OPT_SET_VER  (1 << 3)
+#define OPT_SET_PROJ (1 << 4)
 
 struct globals {
 	unsigned long version;
 	unsigned long af;
 	unsigned long rf;
 	int flags;
+	uint32_t projid;
 	smallint recursive;
 };
 
@@ -108,7 +110,13 @@ static char** decode_arg(char **argv, struct globals *gp)
 				gp->flags |= OPT_SET_VER;
 				continue;
 			}
-//TODO: "-p PROJECT_NUM" ?
+			if (*arg == 'p') {
+				if (!*++argv)
+					bb_show_usage();
+				gp->projid = xatou32(*argv);
+				gp->flags |= OPT_SET_PROJ;
+				continue;
+			}
 			/* not a known option, try as an attribute */
 		}
 		*fl |= get_flag(*arg);
@@ -151,7 +159,11 @@ static void change_attributes(const char *name, struct globals *gp)
 
 	if (gp->flags & OPT_SET_VER)
 		if (fsetversion(name, gp->version) != 0)
-			bb_perror_msg("setting version on %s", name);
+			bb_perror_msg("setting %s on %s", "version", name);
+
+	if (gp->flags & OPT_SET_PROJ)
+		if (fsetprojid(name, gp->projid) != 0)
+			bb_perror_msg("setting %s on %s", "project ID", name);
 
 	if (gp->flags & OPT_SET) {
 		fsflags = gp->af;
diff --git a/e2fsprogs/e2fs_lib.c b/e2fsprogs/e2fs_lib.c
index 8bd4da622..bc9aa53e5 100644
--- a/e2fsprogs/e2fs_lib.c
+++ b/e2fsprogs/e2fs_lib.c
@@ -51,14 +51,14 @@ int fgetsetversion(const char *name, unsigned long *get_version, unsigned long s
 {
 #if HAVE_EXT2_IOCTLS
 	int fd, r;
-	IF_LONG_IS_WIDER(int ver;)
+	IF_LONG_IS_WIDER(unsigned ver;)
 
 	fd = open(name, O_RDONLY | O_NONBLOCK);
 	if (fd == -1)
 		return -1;
 	if (!get_version) {
 		IF_LONG_IS_WIDER(
-			ver = (int) set_version;
+			ver = (unsigned) set_version;
 			r = ioctl(fd, EXT2_IOC_SETVERSION, &ver);
 		)
 		IF_LONG_IS_SAME(
@@ -81,6 +81,32 @@ int fgetsetversion(const char *name, unsigned long *get_version, unsigned long s
 #endif /* ! HAVE_EXT2_IOCTLS */
 }
 
+int fgetsetprojid(const char *name, uint32_t *get, uint32_t set)
+{
+#if HAVE_EXT2_IOCTLS
+	struct ext2_fsxattr fsxattr;
+	int fd, r;
+
+	fd = open(name, O_RDONLY | O_NONBLOCK);
+	if (fd == -1)
+		return -1;
+	r = ioctl(fd, EXT2_IOC_FSGETXATTR, &fsxattr);
+	/* note: ^^^ may fail in 32-bit userspace on 64-bit kernel (seen on 4.12.0) */
+	if (r == 0) {
+		if (get) {
+			*get = fsxattr.fsx_projid;
+		} else {
+			fsxattr.fsx_projid = set;
+			r = ioctl(fd, EXT2_IOC_FSSETXATTR, &fsxattr);
+		}
+	}
+	close_silently(fd);
+	return r;
+#else /* ! HAVE_EXT2_IOCTLS */
+	errno = EOPNOTSUPP;
+	return -1;
+#endif /* ! HAVE_EXT2_IOCTLS */
+}
 
 /* Get/set a file flags on an ext2 file system */
 int fgetsetflags(const char *name, unsigned long *get_flags, unsigned long set_flags)
@@ -88,7 +114,7 @@ int fgetsetflags(const char *name, unsigned long *get_flags, unsigned long set_f
 #if HAVE_EXT2_IOCTLS
 	struct stat buf;
 	int fd, r;
-	IF_LONG_IS_WIDER(int f;)
+	IF_LONG_IS_WIDER(unsigned f;)
 
 	if (stat(name, &buf) == 0 /* stat is ok */
 	 && !S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode)
@@ -101,7 +127,7 @@ int fgetsetflags(const char *name, unsigned long *get_flags, unsigned long set_f
 
 	if (!get_flags) {
 		IF_LONG_IS_WIDER(
-			f = (int) set_flags;
+			f = (unsigned) set_flags;
 			r = ioctl(fd, EXT2_IOC_SETFLAGS, &f);
 		)
 		IF_LONG_IS_SAME(
diff --git a/e2fsprogs/e2fs_lib.h b/e2fsprogs/e2fs_lib.h
index ae28c353b..82a1581cb 100644
--- a/e2fsprogs/e2fs_lib.h
+++ b/e2fsprogs/e2fs_lib.h
@@ -21,6 +21,11 @@ int fgetsetversion(const char *name, unsigned long *get_version, unsigned long s
 #define fgetversion(name, version) fgetsetversion(name, version, 0)
 #define fsetversion(name, version) fgetsetversion(name, NULL, version)
 
+/* Get/set a file project ID on an ext2 file system */
+int fgetsetprojid(const char *name, uint32_t *get, uint32_t set);
+#define fgetprojid(name, projid) fgetsetprojid(name, projid, 0)
+#define fsetprojid(name, projid) fgetsetprojid(name, NULL, projid)
+
 /* Get/set a file flags on an ext2 file system */
 int fgetsetflags(const char *name, unsigned long *get_flags, unsigned long set_flags);
 #define fgetflags(name, flags) fgetsetflags(name, flags, 0)
diff --git a/e2fsprogs/lsattr.c b/e2fsprogs/lsattr.c
index 91205ff65..9b035f584 100644
--- a/e2fsprogs/lsattr.c
+++ b/e2fsprogs/lsattr.c
@@ -21,38 +21,48 @@
 //kbuild:lib-$(CONFIG_LSATTR) += lsattr.o e2fs_lib.o
 
 //usage:#define lsattr_trivial_usage
-//usage:       "[-Radlv] [FILE]..."
+//usage:       "[-Radlpv] [FILE]..."
 //usage:#define lsattr_full_usage "\n\n"
 //usage:       "List ext2 file attributes\n"
 //usage:     "\n	-R	Recurse"
-//usage:     "\n	-a	Don't hide entries starting with ."
-//usage:     "\n	-d	List directory entries instead of contents"
+//usage:     "\n	-a	Include names starting with ."
+//usage:     "\n	-d	List directory names, not contents"
+// -a,-d text should match ls --help
 //usage:     "\n	-l	List long flag names"
+//usage:     "\n	-p	List project ID"
 //usage:     "\n	-v	List version/generation number"
 
 #include "libbb.h"
 #include "e2fs_lib.h"
 
 enum {
-	OPT_RECUR      = 0x1,
-	OPT_ALL        = 0x2,
-	OPT_DIRS_OPT   = 0x4,
-	OPT_PF_LONG    = 0x8,
-	OPT_GENERATION = 0x10,
+	OPT_RECUR      = 1 << 0,
+	OPT_ALL        = 1 << 1,
+	OPT_DIRS_OPT   = 1 << 2,
+	OPT_PF_LONG    = 1 << 3,
+	OPT_GENERATION = 1 << 4,
+	OPT_PROJID     = 1 << 5,
 };
 
 static void list_attributes(const char *name)
 {
 	unsigned long fsflags;
-	unsigned long generation;
 
 	if (fgetflags(name, &fsflags) != 0)
 		goto read_err;
 
+	if (option_mask32 & OPT_PROJID) {
+		uint32_t p;
+		if (fgetprojid(name, &p) != 0)
+			goto read_err;
+		printf("%5lu ", (unsigned long)p);
+	}
+
 	if (option_mask32 & OPT_GENERATION) {
+		unsigned long generation;
 		if (fgetversion(name, &generation) != 0)
 			goto read_err;
-		printf("%5lu ", generation);
+		printf("%-10lu ", generation);
 	}
 
 	if (option_mask32 & OPT_PF_LONG) {
@@ -111,7 +121,7 @@ static void lsattr_args(const char *name)
 int lsattr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int lsattr_main(int argc UNUSED_PARAM, char **argv)
 {
-	getopt32(argv, "Radlv");
+	getopt32(argv, "Radlvp");
 	argv += optind;
 
 	if (!*argv)
diff --git a/include/bb_e2fs_defs.h b/include/bb_e2fs_defs.h
index 3f5e3c45b..2d72288ed 100644
--- a/include/bb_e2fs_defs.h
+++ b/include/bb_e2fs_defs.h
@@ -195,6 +195,18 @@ struct ext2_dx_countlimit {
 #define EXT2_IOC_SETFLAGS		_IOW('f', 2, long)
 #define EXT2_IOC_GETVERSION		_IOR('v', 1, long)
 #define EXT2_IOC_SETVERSION		_IOW('v', 2, long)
+//NB: despite "long" in defs above, these ioctls use an _int_!
+//passing them a pointer to long will read/write only int-sized data!
+struct ext2_fsxattr {
+	uint32_t	fsx_xflags;	/* xflags field value (get/set) */
+	uint32_t	fsx_extsize;	/* extsize field value (get/set)*/
+	uint32_t	fsx_nextents;	/* nextents field value (get)	*/
+	uint32_t	fsx_projid;	/* project identifier (get/set) */
+	uint32_t	fsx_cowextsize;	/* CoW extsize field value (get/set)*/
+	unsigned char	fsx_pad[8];
+};
+#define EXT2_IOC_FSGETXATTR		_IOR('X', 31, struct ext2_fsxattr)
+#define EXT2_IOC_FSSETXATTR		_IOW('X', 32, struct ext2_fsxattr)
 
 /*
  * Structure of an inode on the disk


More information about the busybox-cvs mailing list