From 0e3456e0c4a8623fe2d8bc28c51f16c8274b8098 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Thu, 9 Jul 2020 08:58:10 +0100 Subject: chattr, lsattr: enable in the default configuration The chattr and lsattr utilities allow file attributes to be changed and displayed. Modify them to support Windows file attributes using the same names as Cygwin. Only allow a limited subset of attributes to be changed: just most of those supported by SetFileAttributes(). Since it isn't possible to set all attributes the '=' operator isn't allowed. --- configs/mingw32_defconfig | 6 ++--- configs/mingw64_defconfig | 6 ++--- e2fsprogs/chattr.c | 46 ++++++++++++++++++++++++++++++++ e2fsprogs/e2fs_lib.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++- e2fsprogs/e2fs_lib.h | 5 ++++ e2fsprogs/lsattr.c | 15 +++++++++++ 6 files changed, 138 insertions(+), 7 deletions(-) diff --git a/configs/mingw32_defconfig b/configs/mingw32_defconfig index b3dfc0033..379d8265b 100644 --- a/configs/mingw32_defconfig +++ b/configs/mingw32_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Busybox version: 1.32.0.git -# Sun Jun 14 09:30:06 2020 +# Thu Jul 9 08:46:09 2020 # CONFIG_HAVE_DOT_CONFIG=y # CONFIG_PLATFORM_POSIX is not set @@ -562,9 +562,9 @@ CONFIG_SUW32=y # # Linux Ext2 FS Progs # -# CONFIG_CHATTR is not set +CONFIG_CHATTR=y # CONFIG_FSCK is not set -# CONFIG_LSATTR is not set +CONFIG_LSATTR=y # CONFIG_TUNE2FS is not set # diff --git a/configs/mingw64_defconfig b/configs/mingw64_defconfig index 2410d476d..25ed022e4 100644 --- a/configs/mingw64_defconfig +++ b/configs/mingw64_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Busybox version: 1.32.0.git -# Sun Jun 14 09:30:06 2020 +# Thu Jul 9 08:46:09 2020 # CONFIG_HAVE_DOT_CONFIG=y # CONFIG_PLATFORM_POSIX is not set @@ -562,9 +562,9 @@ CONFIG_SUW32=y # # Linux Ext2 FS Progs # -# CONFIG_CHATTR is not set +CONFIG_CHATTR=y # CONFIG_FSCK is not set -# CONFIG_LSATTR is not set +CONFIG_LSATTR=y # CONFIG_TUNE2FS is not set # diff --git a/e2fsprogs/chattr.c b/e2fsprogs/chattr.c index c37469021..e1a798727 100644 --- a/e2fsprogs/chattr.c +++ b/e2fsprogs/chattr.c @@ -20,13 +20,26 @@ //kbuild:lib-$(CONFIG_CHATTR) += chattr.o e2fs_lib.o //usage:#define chattr_trivial_usage +//usage: IF_NOT_PLATFORM_MINGW32( //usage: "[-R] [-v VERSION] [-+=AacDdijsStTu] FILE..." +//usage: ) +//usage: IF_PLATFORM_MINGW32( +//usage: "[-R] [-+rhsatn] FILE..." +//usage: ) //usage:#define chattr_full_usage "\n\n" +//usage: IF_NOT_PLATFORM_MINGW32( //usage: "Change ext2 file attributes\n" +//usage: ) +//usage: IF_PLATFORM_MINGW32( +//usage: "Change file attributes\n" +//usage: ) //usage: "\n -R Recurse" +//usage: IF_NOT_PLATFORM_MINGW32( //usage: "\n -v VER Set version/generation number" +//usage: ) //-V, -f accepted but ignored //usage: "\nModifiers:" +//usage: IF_NOT_PLATFORM_MINGW32( //usage: "\n -,+,= Remove/add/set attributes" //usage: "\nAttributes:" //usage: "\n A Don't track atime" @@ -40,6 +53,17 @@ //usage: "\n S Write synchronously" //usage: "\n t Disable tail-merging of partial blocks with other files" //usage: "\n u Allow file to be undeleted" +//usage: ) +//usage: IF_PLATFORM_MINGW32( +//usage: "\n -,+ Remove/add attributes" +//usage: "\nAttributes:" +//usage: "\n r Read only" +//usage: "\n h Hidden" +//usage: "\n s System" +//usage: "\n a Archive" +//usage: "\n t Temporary" +//usage: "\n n Not indexed" +//usage: ) #include "libbb.h" #include "e2fs_lib.h" @@ -50,7 +74,9 @@ #define OPT_SET_VER 8 struct globals { +#if !ENABLE_PLATFORM_MINGW32 unsigned long version; +#endif unsigned long af; unsigned long rf; int flags; @@ -75,11 +101,17 @@ static char** decode_arg(char **argv, struct globals *gp) if (opt == '-') { gp->flags |= OPT_REM; fl = &gp->rf; +#if ENABLE_PLATFORM_MINGW32 + } else { /* if (opt == '+') */ + gp->flags |= OPT_ADD; + } +#else } else if (opt == '+') { gp->flags |= OPT_ADD; } else { /* if (opt == '=') */ gp->flags |= OPT_SET; } +#endif while (*++arg) { if (opt == '-') { @@ -92,6 +124,7 @@ static char** decode_arg(char **argv, struct globals *gp) gp->recursive = 1; continue; } +#if !ENABLE_PLATFORM_MINGW32 if (*arg == 'V') { /*"verbose and print program version" (nop for now) */; continue; @@ -108,6 +141,7 @@ static char** decode_arg(char **argv, struct globals *gp) continue; } //TODO: "-p PROJECT_NUM" ? +#endif /* not a known option, try as an attribute */ } *fl |= get_flag(*arg); @@ -148,9 +182,11 @@ static void change_attributes(const char *name, struct globals *gp) if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode) && !S_ISDIR(st.st_mode)) return; +#if !ENABLE_PLATFORM_MINGW32 if (gp->flags & OPT_SET_VER) if (fsetversion(name, gp->version) != 0) bb_perror_msg("setting version on %s", name); +#endif if (gp->flags & OPT_SET) { fsflags = gp->af; @@ -163,9 +199,11 @@ static void change_attributes(const char *name, struct globals *gp) fsflags &= ~gp->rf; /*if (gp->flags & OPT_ADD) - not needed, af is zero otherwise */ fsflags |= gp->af; +#if !ENABLE_PLATFORM_MINGW32 // What is this? And why it's not done for SET case? if (!S_ISDIR(st.st_mode)) fsflags &= ~EXT2_DIRSYNC_FL; +#endif } if (fsetflags(name, fsflags) != 0) bb_perror_msg("setting flags on %s", name); @@ -187,7 +225,11 @@ int chattr_main(int argc UNUSED_PARAM, char **argv) char *arg = *++argv; if (!arg) bb_show_usage(); +#if ENABLE_PLATFORM_MINGW32 + if (arg[0] != '-' && arg[0] != '+') +#else if (arg[0] != '-' && arg[0] != '+' && arg[0] != '=') +#endif break; argv = decode_arg(argv, &g); @@ -200,7 +242,11 @@ int chattr_main(int argc UNUSED_PARAM, char **argv) if (g.rf & g.af) bb_simple_error_msg_and_die("can't set and unset a flag"); if (!g.flags) +#if ENABLE_PLATFORM_MINGW32 + bb_simple_error_msg_and_die("must use - or +"); +#else bb_simple_error_msg_and_die("must use '-v', =, - or +"); +#endif /* now run chattr on all the files passed to us */ do change_attributes(*argv, &g); while (*++argv); diff --git a/e2fsprogs/e2fs_lib.c b/e2fsprogs/e2fs_lib.c index 6ce655be3..3b776bc97 100644 --- a/e2fsprogs/e2fs_lib.c +++ b/e2fsprogs/e2fs_lib.c @@ -8,6 +8,7 @@ #include "libbb.h" #include "e2fs_lib.h" +#if !ENABLE_PLATFORM_MINGW32 #define HAVE_EXT2_IOCTLS 1 #if INT_MAX == LONG_MAX @@ -24,6 +25,7 @@ static void close_silently(int fd) close(fd); errno = e; } +#endif /* Iterate a function on each entry of a directory */ @@ -46,6 +48,7 @@ int iterate_on_dir(const char *dir_name, } +#if !ENABLE_PLATFORM_MINGW32 /* Get/set a file version on an ext2 file system */ int fgetsetversion(const char *name, unsigned long *get_version, unsigned long set_version) { @@ -81,7 +84,6 @@ int fgetsetversion(const char *name, unsigned long *get_version, unsigned long s #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) { @@ -124,8 +126,38 @@ int fgetsetflags(const char *name, unsigned long *get_flags, unsigned long set_f errno = EOPNOTSUPP; return -1; } +#else /* ENABLE_PLATFORM_MINGW32 */ +/* Only certain attributes can be set using SetFileAttributes() */ +#define CHATTR_MASK (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \ + FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE | \ + FILE_ATTRIBUTE_TEMPORARY | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | \ + FILE_ATTRIBUTE_OFFLINE) +/* Get/set file attributes on a Windows file system */ +int fgetsetflags(const char *name, unsigned long *get_flags, unsigned long set_flags) +{ + struct stat buf; + + if (stat(name, &buf) == 0 /* stat is ok */ + && !S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode) + ) { + errno = EOPNOTSUPP; + return -1; + } + if (get_flags) { + *get_flags = (unsigned long)buf.st_attr; + } + else if (!SetFileAttributes(name, set_flags & CHATTR_MASK)) { + errno = err_win_to_posix(); + return -1; + } + return 0; +} +#endif + + +#if !ENABLE_PLATFORM_MINGW32 /* Print file attributes on an ext2 file system */ const uint32_t e2attr_flags_value[] = { #ifdef ENABLE_COMPRESSION @@ -177,6 +209,39 @@ static const char e2attr_flags_lname[] ALIGN1 = "No_Tailmerging" "\0" "Top_of_Directory_Hierarchies" "\0" /* Another trailing NUL is added by compiler */; +#else /* ENABLE_PLATFORM_MINGW32 */ +/* Print file attributes on a Windows file system */ +const uint32_t e2attr_flags_value[] = { + FILE_ATTRIBUTE_REPARSE_POINT, + FILE_ATTRIBUTE_OFFLINE, + FILE_ATTRIBUTE_ENCRYPTED, + FILE_ATTRIBUTE_COMPRESSED, + FILE_ATTRIBUTE_SPARSE_FILE, + FILE_ATTRIBUTE_READONLY, + FILE_ATTRIBUTE_HIDDEN, + FILE_ATTRIBUTE_SYSTEM, + FILE_ATTRIBUTE_ARCHIVE, + FILE_ATTRIBUTE_TEMPORARY, + FILE_ATTRIBUTE_NOT_CONTENT_INDEXED, +}; + +const char e2attr_flags_sname[] ALIGN1 = + "roecSrhsatn"; + +static const char e2attr_flags_lname[] ALIGN1 = + "Reparse" "\0" + "Offline" "\0" + "Encrypted" "\0" + "Compressed" "\0" + "Sparse" "\0" + "Readonly" "\0" + "Hidden" "\0" + "System" "\0" + "Archive" "\0" + "Temporary" "\0" + "Notindexed" "\0" + /* Another trailing NUL is added by compiler */; +#endif void print_e2flags(FILE *f, unsigned long flags, unsigned options) { diff --git a/e2fsprogs/e2fs_lib.h b/e2fsprogs/e2fs_lib.h index ae28c353b..4a4d4cc27 100644 --- a/e2fsprogs/e2fs_lib.h +++ b/e2fsprogs/e2fs_lib.h @@ -36,6 +36,7 @@ extern const char e2attr_flags_sname[]; /* If you plan to ENABLE_COMPRESSION, see e2fs_lib.c and chattr.c - */ /* make sure that chattr doesn't accept bad options! */ +#if !ENABLE_PLATFORM_MINGW32 #ifdef ENABLE_COMPRESSION #define e2attr_flags_value_chattr (&e2attr_flags_value[5]) #define e2attr_flags_sname_chattr (&e2attr_flags_sname[5]) @@ -43,5 +44,9 @@ extern const char e2attr_flags_sname[]; #define e2attr_flags_value_chattr (&e2attr_flags_value[1]) #define e2attr_flags_sname_chattr (&e2attr_flags_sname[1]) #endif +#else +#define e2attr_flags_value_chattr (&e2attr_flags_value[5]) +#define e2attr_flags_sname_chattr (&e2attr_flags_sname[5]) +#endif POP_SAVED_FUNCTION_VISIBILITY diff --git a/e2fsprogs/lsattr.c b/e2fsprogs/lsattr.c index be1488b79..b36dd47a5 100644 --- a/e2fsprogs/lsattr.c +++ b/e2fsprogs/lsattr.c @@ -22,14 +22,21 @@ //kbuild:lib-$(CONFIG_LSATTR) += lsattr.o e2fs_lib.o //usage:#define lsattr_trivial_usage +//usage: IF_NOT_PLATFORM_MINGW32( //usage: "[-Radlv] [FILE]..." +//usage: ) +//usage: IF_PLATFORM_MINGW32( +//usage: "[-Radl] [FILE]..." +//usage: ) //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 -l List long flag names" +//usage: IF_NOT_PLATFORM_MINGW32( //usage: "\n -v List version/generation number" +//usage: ) #include "libbb.h" #include "e2fs_lib.h" @@ -45,16 +52,20 @@ enum { static void list_attributes(const char *name) { unsigned long fsflags; +#if !ENABLE_PLATFORM_MINGW32 unsigned long generation; +#endif if (fgetflags(name, &fsflags) != 0) goto read_err; +#if !ENABLE_PLATFORM_MINGW32 if (option_mask32 & OPT_GENERATION) { if (fgetversion(name, &generation) != 0) goto read_err; printf("%5lu ", generation); } +#endif if (option_mask32 & OPT_PF_LONG) { printf("%-28s ", name); @@ -112,7 +123,11 @@ 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) { +#if ENABLE_PLATFORM_MINGW32 + getopt32(argv, "Radl"); +#else getopt32(argv, "Radlv"); +#endif argv += optind; if (!*argv) -- cgit v1.2.3-55-g6feb