lsattr,chattr: support -p
No binary (build failed)
—
(log yok)
| @@ -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; | |
| @@ -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( | |
| @@ -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) | |
| @@ -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) | |
| @@ -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 | |