aboutsummaryrefslogtreecommitdiff
path: root/e2fsprogs
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2021-06-28 07:46:32 +0100
committerRon Yorston <rmy@pobox.com>2021-06-28 07:46:32 +0100
commite1ad66c0b8fd58a7158d40771175a7dab224202d (patch)
tree959d687eee9637151ad5798322586174de331141 /e2fsprogs
parent0fdf99bee07b6c38795eb5415b5e337ab82cfba8 (diff)
parent5dbbd0a6f52befe6bc57baf97d39168e595197f1 (diff)
downloadbusybox-w32-e1ad66c0b8fd58a7158d40771175a7dab224202d.tar.gz
busybox-w32-e1ad66c0b8fd58a7158d40771175a7dab224202d.tar.bz2
busybox-w32-e1ad66c0b8fd58a7158d40771175a7dab224202d.zip
Merge branch 'busybox' into merge
Diffstat (limited to 'e2fsprogs')
-rw-r--r--e2fsprogs/chattr.c146
-rw-r--r--e2fsprogs/e2fs_lib.c209
-rw-r--r--e2fsprogs/e2fs_lib.h21
-rw-r--r--e2fsprogs/lsattr.c80
4 files changed, 224 insertions, 232 deletions
diff --git a/e2fsprogs/chattr.c b/e2fsprogs/chattr.c
index e1a798727..c1e90d13f 100644
--- a/e2fsprogs/chattr.c
+++ b/e2fsprogs/chattr.c
@@ -21,7 +21,7 @@
21 21
22//usage:#define chattr_trivial_usage 22//usage:#define chattr_trivial_usage
23//usage: IF_NOT_PLATFORM_MINGW32( 23//usage: IF_NOT_PLATFORM_MINGW32(
24//usage: "[-R] [-v VERSION] [-+=AacDdijsStTu] FILE..." 24//usage: "[-R] [-v VERSION] [-p PROJID] [-+=AacDdijsStTu] FILE..."
25//usage: ) 25//usage: )
26//usage: IF_PLATFORM_MINGW32( 26//usage: IF_PLATFORM_MINGW32(
27//usage: "[-R] [-+rhsatn] FILE..." 27//usage: "[-R] [-+rhsatn] FILE..."
@@ -35,24 +35,34 @@
35//usage: ) 35//usage: )
36//usage: "\n -R Recurse" 36//usage: "\n -R Recurse"
37//usage: IF_NOT_PLATFORM_MINGW32( 37//usage: IF_NOT_PLATFORM_MINGW32(
38//usage: "\n -v VER Set version/generation number" 38//usage: "\n -v NUM Set version/generation number"
39//usage: "\n -p NUM Set project number"
39//usage: ) 40//usage: )
40//-V, -f accepted but ignored 41//-V, -f accepted but ignored
41//usage: "\nModifiers:" 42//usage: "\nModifiers:"
42//usage: IF_NOT_PLATFORM_MINGW32( 43//usage: IF_NOT_PLATFORM_MINGW32(
43//usage: "\n -,+,= Remove/add/set attributes" 44//usage: "\n -,+,= Remove/add/set attributes"
44//usage: "\nAttributes:" 45//usage: "\nAttributes:"
45//usage: "\n A Don't track atime" 46//usage: "\n A No atime"
46//usage: "\n a Append mode only" 47//usage: "\n a Append only"
47//usage: "\n c Enable compress" 48//usage: "\n C No copy-on-write"
48//usage: "\n D Write dir contents synchronously" 49//usage: "\n c Compressed"
50//usage: "\n D Synchronous dir updates"
49//usage: "\n d Don't backup with dump" 51//usage: "\n d Don't backup with dump"
50//usage: "\n i Cannot be modified (immutable)" 52//usage: "\n E Encrypted"
51//usage: "\n j Write all data to journal first" 53//usage: "\n e File uses extents"
52//usage: "\n s Zero disk storage when deleted" 54//usage: "\n F Case-insensitive dir"
53//usage: "\n S Write synchronously" 55//usage: "\n I Indexed dir"
54//usage: "\n t Disable tail-merging of partial blocks with other files" 56//usage: "\n i Immutable"
55//usage: "\n u Allow file to be undeleted" 57//usage: "\n j Write data to journal first"
58//usage: "\n N File is stored in inode"
59//usage: "\n P Hierarchical project ID dir"
60//usage: "\n S Synchronous file updates"
61//usage: "\n s Zero storage when deleted"
62//usage: "\n T Top of dir hierarchy"
63//usage: "\n t Don't tail-merge with other files"
64//usage: "\n u Allow undelete"
65//usage: "\n V Verity"
56//usage: ) 66//usage: )
57//usage: IF_PLATFORM_MINGW32( 67//usage: IF_PLATFORM_MINGW32(
58//usage: "\n -,+ Remove/add attributes" 68//usage: "\n -,+ Remove/add attributes"
@@ -68,18 +78,22 @@
68#include "libbb.h" 78#include "libbb.h"
69#include "e2fs_lib.h" 79#include "e2fs_lib.h"
70 80
71#define OPT_ADD 1 81#define OPT_ADD (1 << 0)
72#define OPT_REM 2 82#define OPT_REM (1 << 1)
73#define OPT_SET 4 83#define OPT_SET (1 << 2)
74#define OPT_SET_VER 8 84#define OPT_SET_VER (1 << 3)
85#define OPT_SET_PROJ (1 << 4)
75 86
76struct globals { 87struct globals {
77#if !ENABLE_PLATFORM_MINGW32 88#if !ENABLE_PLATFORM_MINGW32
78 unsigned long version; 89 unsigned version;
79#endif 90#endif
80 unsigned long af; 91 unsigned af;
81 unsigned long rf; 92 unsigned rf;
82 int flags; 93 int flags;
94#if !ENABLE_PLATFORM_MINGW32
95 uint32_t projid;
96#endif
83 smallint recursive; 97 smallint recursive;
84}; 98};
85 99
@@ -93,13 +107,15 @@ static unsigned long get_flag(char c)
93 107
94static char** decode_arg(char **argv, struct globals *gp) 108static char** decode_arg(char **argv, struct globals *gp)
95{ 109{
96 unsigned long *fl; 110 unsigned *fl;
97 const char *arg = *argv; 111 const char *arg = *argv;
98 char opt = *arg; 112 char opt = *arg;
99 113
100 fl = &gp->af; 114 fl = &gp->af;
101 if (opt == '-') { 115 if (opt == '-') {
102 gp->flags |= OPT_REM; 116 /* gp->flags |= OPT_REM; - WRONG, it can be an option */
117 /* testcase: chattr =ae -R FILE should not complain "= is incompatible with - and +" */
118 /* (and should not read flags, with =FLAGS they can be just set directly) */
103 fl = &gp->rf; 119 fl = &gp->rf;
104#if ENABLE_PLATFORM_MINGW32 120#if ENABLE_PLATFORM_MINGW32
105 } else { /* if (opt == '+') */ 121 } else { /* if (opt == '+') */
@@ -136,15 +152,22 @@ static char** decode_arg(char **argv, struct globals *gp)
136 if (*arg == 'v') { 152 if (*arg == 'v') {
137 if (!*++argv) 153 if (!*++argv)
138 bb_show_usage(); 154 bb_show_usage();
139 gp->version = xatoul(*argv); 155 gp->version = xatou(*argv);
140 gp->flags |= OPT_SET_VER; 156 gp->flags |= OPT_SET_VER;
141 continue; 157 continue;
142 } 158 }
143//TODO: "-p PROJECT_NUM" ? 159 if (*arg == 'p') {
160 if (!*++argv)
161 bb_show_usage();
162 gp->projid = xatou32(*argv);
163 gp->flags |= OPT_SET_PROJ;
164 continue;
165 }
144#endif 166#endif
145 /* not a known option, try as an attribute */ 167 /* not a known option, try as an attribute */
168 gp->flags |= OPT_REM;
146 } 169 }
147 *fl |= get_flag(*arg); 170 *fl |= get_flag(*arg); /* aborts on bad flag letter */
148 } 171 }
149 172
150 return argv; 173 return argv;
@@ -154,6 +177,8 @@ static void change_attributes(const char *name, struct globals *gp);
154 177
155static int FAST_FUNC chattr_dir_proc(const char *dir_name, struct dirent *de, void *gp) 178static int FAST_FUNC chattr_dir_proc(const char *dir_name, struct dirent *de, void *gp)
156{ 179{
180//TODO: use de->d_type (if it's not DT_UNKNOWN) to skip !(REG || DIR || LNK) entries without lstat?
181
157 char *path = concat_subpath_file(dir_name, de->d_name); 182 char *path = concat_subpath_file(dir_name, de->d_name);
158 /* path is NULL if de->d_name is "." or "..", else... */ 183 /* path is NULL if de->d_name is "." or "..", else... */
159 if (path) { 184 if (path) {
@@ -165,15 +190,16 @@ static int FAST_FUNC chattr_dir_proc(const char *dir_name, struct dirent *de, vo
165 190
166static void change_attributes(const char *name, struct globals *gp) 191static void change_attributes(const char *name, struct globals *gp)
167{ 192{
168 unsigned long fsflags; 193 unsigned fsflags;
194#if !ENABLE_PLATFORM_MINGW32
195 int fd;
196#endif
169 struct stat st; 197 struct stat st;
170 198
171 if (lstat(name, &st) != 0) { 199 if (lstat(name, &st) != 0) {
172 bb_perror_msg("stat %s", name); 200 bb_perror_msg("can't stat '%s'", name);
173 return; 201 return;
174 } 202 }
175 if (S_ISLNK(st.st_mode) && gp->recursive)
176 return;
177 203
178 /* Don't try to open device files, fifos etc. We probably 204 /* Don't try to open device files, fifos etc. We probably
179 * ought to display an error if the file was explicitly given 205 * ought to display an error if the file was explicitly given
@@ -183,11 +209,58 @@ static void change_attributes(const char *name, struct globals *gp)
183 return; 209 return;
184 210
185#if !ENABLE_PLATFORM_MINGW32 211#if !ENABLE_PLATFORM_MINGW32
186 if (gp->flags & OPT_SET_VER) 212 /* There is no way to run needed ioctls on a symlink.
187 if (fsetversion(name, gp->version) != 0) 213 * open(O_PATH | O_NOFOLLOW) _can_ be used to get a fd referring to the symlink,
188 bb_perror_msg("setting version on %s", name); 214 * but ioctls fail on such a fd (tried on 4.12.0 kernel).
189#endif 215 * e2fsprogs-1.46.2 uses open(O_NOFOLLOW), it fails on symlinks.
216 */
217 fd = open_or_warn(name, O_RDONLY | O_NONBLOCK | O_NOCTTY | O_NOFOLLOW);
218 if (fd >= 0) {
219 int r;
220
221 if (gp->flags & OPT_SET_VER) {
222 r = ioctl(fd, EXT2_IOC_SETVERSION, &gp->version);
223 if (r != 0)
224 bb_perror_msg("setting %s on %s", "version", name);
225 }
190 226
227 if (gp->flags & OPT_SET_PROJ) {
228 struct ext2_fsxattr fsxattr;
229 r = ioctl(fd, EXT2_IOC_FSGETXATTR, &fsxattr);
230 /* note: ^^^ may fail in 32-bit userspace on 64-bit kernel (seen on 4.12.0) */
231 if (r != 0) {
232 bb_perror_msg("getting %s on %s", "project ID", name);
233 } else {
234 fsxattr.fsx_projid = gp->projid;
235 r = ioctl(fd, EXT2_IOC_FSSETXATTR, &fsxattr);
236 if (r != 0)
237 bb_perror_msg("setting %s on %s", "project ID", name);
238 }
239 }
240
241 if (gp->flags & OPT_SET) {
242 fsflags = gp->af;
243 } else {
244 r = ioctl(fd, EXT2_IOC_GETFLAGS, &fsflags);
245 if (r != 0) {
246 bb_perror_msg("getting %s on %s", "flags", name);
247 goto skip_setflags;
248 }
249 /*if (gp->flags & OPT_REM) - not needed, rf is zero otherwise */
250 fsflags &= ~gp->rf;
251 /*if (gp->flags & OPT_ADD) - not needed, af is zero otherwise */
252 fsflags |= gp->af;
253// What is this? And why it's not done for SET case?
254 if (!S_ISDIR(st.st_mode))
255 fsflags &= ~EXT2_DIRSYNC_FL;
256 }
257 r = ioctl(fd, EXT2_IOC_SETFLAGS, &fsflags);
258 if (r != 0)
259 bb_perror_msg("setting %s on %s", "flags", name);
260 skip_setflags:
261 close(fd);
262 }
263#else /* ENABLE_PLATFORM_MINGW32 */
191 if (gp->flags & OPT_SET) { 264 if (gp->flags & OPT_SET) {
192 fsflags = gp->af; 265 fsflags = gp->af;
193 } else { 266 } else {
@@ -199,16 +272,13 @@ static void change_attributes(const char *name, struct globals *gp)
199 fsflags &= ~gp->rf; 272 fsflags &= ~gp->rf;
200 /*if (gp->flags & OPT_ADD) - not needed, af is zero otherwise */ 273 /*if (gp->flags & OPT_ADD) - not needed, af is zero otherwise */
201 fsflags |= gp->af; 274 fsflags |= gp->af;
202#if !ENABLE_PLATFORM_MINGW32
203// What is this? And why it's not done for SET case?
204 if (!S_ISDIR(st.st_mode))
205 fsflags &= ~EXT2_DIRSYNC_FL;
206#endif
207 } 275 }
208 if (fsetflags(name, fsflags) != 0) 276 if (fsetflags(name, fsflags) != 0)
209 bb_perror_msg("setting flags on %s", name); 277 bb_perror_msg("setting flags on %s", name);
210 278
211 skip_setflags: 279 skip_setflags:
280#endif
281
212 if (gp->recursive && S_ISDIR(st.st_mode)) 282 if (gp->recursive && S_ISDIR(st.st_mode))
213 iterate_on_dir(name, chattr_dir_proc, gp); 283 iterate_on_dir(name, chattr_dir_proc, gp);
214} 284}
@@ -245,7 +315,7 @@ int chattr_main(int argc UNUSED_PARAM, char **argv)
245#if ENABLE_PLATFORM_MINGW32 315#if ENABLE_PLATFORM_MINGW32
246 bb_simple_error_msg_and_die("must use - or +"); 316 bb_simple_error_msg_and_die("must use - or +");
247#else 317#else
248 bb_simple_error_msg_and_die("must use '-v', =, - or +"); 318 bb_simple_error_msg_and_die("must use -v, -p, =, - or +");
249#endif 319#endif
250 320
251 /* now run chattr on all the files passed to us */ 321 /* now run chattr on all the files passed to us */
diff --git a/e2fsprogs/e2fs_lib.c b/e2fsprogs/e2fs_lib.c
index d0cacf14c..48c3b68b5 100644
--- a/e2fsprogs/e2fs_lib.c
+++ b/e2fsprogs/e2fs_lib.c
@@ -8,125 +8,7 @@
8#include "libbb.h" 8#include "libbb.h"
9#include "e2fs_lib.h" 9#include "e2fs_lib.h"
10 10
11#if !ENABLE_PLATFORM_MINGW32 11#if ENABLE_PLATFORM_MINGW32
12#define HAVE_EXT2_IOCTLS 1
13
14#if INT_MAX == LONG_MAX
15#define IF_LONG_IS_SAME(...) __VA_ARGS__
16#define IF_LONG_IS_WIDER(...)
17#else
18#define IF_LONG_IS_SAME(...)
19#define IF_LONG_IS_WIDER(...) __VA_ARGS__
20#endif
21
22static void close_silently(int fd)
23{
24 int e = errno;
25 close(fd);
26 errno = e;
27}
28#endif
29
30
31/* Iterate a function on each entry of a directory */
32int iterate_on_dir(const char *dir_name,
33 int FAST_FUNC (*func)(const char *, struct dirent *, void *),
34 void *private)
35{
36 DIR *dir;
37 struct dirent *de;
38
39 dir = opendir(dir_name);
40 if (dir == NULL) {
41 return -1;
42 }
43 while ((de = readdir(dir)) != NULL) {
44 func(dir_name, de, private);
45 }
46 closedir(dir);
47 return 0;
48}
49
50
51#if !ENABLE_PLATFORM_MINGW32
52/* Get/set a file version on an ext2 file system */
53int fgetsetversion(const char *name, unsigned long *get_version, unsigned long set_version)
54{
55#if HAVE_EXT2_IOCTLS
56 int fd, r;
57 IF_LONG_IS_WIDER(int ver;)
58
59 fd = open(name, O_RDONLY | O_NONBLOCK);
60 if (fd == -1)
61 return -1;
62 if (!get_version) {
63 IF_LONG_IS_WIDER(
64 ver = (int) set_version;
65 r = ioctl(fd, EXT2_IOC_SETVERSION, &ver);
66 )
67 IF_LONG_IS_SAME(
68 r = ioctl(fd, EXT2_IOC_SETVERSION, (void*)&set_version);
69 )
70 } else {
71 IF_LONG_IS_WIDER(
72 r = ioctl(fd, EXT2_IOC_GETVERSION, &ver);
73 *get_version = ver;
74 )
75 IF_LONG_IS_SAME(
76 r = ioctl(fd, EXT2_IOC_GETVERSION, (void*)get_version);
77 )
78 }
79 close_silently(fd);
80 return r;
81#else /* ! HAVE_EXT2_IOCTLS */
82 errno = EOPNOTSUPP;
83 return -1;
84#endif /* ! HAVE_EXT2_IOCTLS */
85}
86
87/* Get/set a file flags on an ext2 file system */
88int fgetsetflags(const char *name, unsigned long *get_flags, unsigned long set_flags)
89{
90#if HAVE_EXT2_IOCTLS
91 struct stat buf;
92 int fd, r;
93 IF_LONG_IS_WIDER(int f;)
94
95 if (stat(name, &buf) == 0 /* stat is ok */
96 && !S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode)
97 ) {
98 goto notsupp;
99 }
100 fd = open(name, O_RDONLY | O_NONBLOCK); /* neither read nor write asked for */
101 if (fd == -1)
102 return -1;
103
104 if (!get_flags) {
105 IF_LONG_IS_WIDER(
106 f = (int) set_flags;
107 r = ioctl(fd, EXT2_IOC_SETFLAGS, &f);
108 )
109 IF_LONG_IS_SAME(
110 r = ioctl(fd, EXT2_IOC_SETFLAGS, (void*)&set_flags);
111 )
112 } else {
113 IF_LONG_IS_WIDER(
114 r = ioctl(fd, EXT2_IOC_GETFLAGS, &f);
115 *get_flags = f;
116 )
117 IF_LONG_IS_SAME(
118 r = ioctl(fd, EXT2_IOC_GETFLAGS, (void*)get_flags);
119 )
120 }
121
122 close_silently(fd);
123 return r;
124 notsupp:
125#endif /* HAVE_EXT2_IOCTLS */
126 errno = EOPNOTSUPP;
127 return -1;
128}
129#else /* ENABLE_PLATFORM_MINGW32 */
130/* Only certain attributes can be set using SetFileAttributes() */ 12/* Only certain attributes can be set using SetFileAttributes() */
131#define CHATTR_MASK (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \ 13#define CHATTR_MASK (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \
132 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE | \ 14 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE | \
@@ -134,7 +16,7 @@ int fgetsetflags(const char *name, unsigned long *get_flags, unsigned long set_f
134 FILE_ATTRIBUTE_OFFLINE) 16 FILE_ATTRIBUTE_OFFLINE)
135 17
136/* Get/set file attributes on a Windows file system */ 18/* Get/set file attributes on a Windows file system */
137int fgetsetflags(const char *name, unsigned long *get_flags, unsigned long set_flags) 19int fgetsetflags(const char *name, unsigned *get_flags, unsigned set_flags)
138{ 20{
139 struct stat buf; 21 struct stat buf;
140 22
@@ -156,7 +38,6 @@ int fgetsetflags(const char *name, unsigned long *get_flags, unsigned long set_f
156} 38}
157#endif 39#endif
158 40
159
160#if !ENABLE_PLATFORM_MINGW32 41#if !ENABLE_PLATFORM_MINGW32
161/* Print file attributes on an ext2 file system */ 42/* Print file attributes on an ext2 file system */
162const uint32_t e2attr_flags_value[] ALIGN4 = { 43const uint32_t e2attr_flags_value[] ALIGN4 = {
@@ -164,9 +45,7 @@ const uint32_t e2attr_flags_value[] ALIGN4 = {
164 EXT2_COMPRBLK_FL, 45 EXT2_COMPRBLK_FL,
165 EXT2_DIRTY_FL, 46 EXT2_DIRTY_FL,
166 EXT2_NOCOMPR_FL, 47 EXT2_NOCOMPR_FL,
167 EXT2_ECOMPR_FL,
168#endif 48#endif
169 EXT2_INDEX_FL,
170 EXT2_SECRM_FL, 49 EXT2_SECRM_FL,
171 EXT2_UNRM_FL, 50 EXT2_UNRM_FL,
172 EXT2_SYNC_FL, 51 EXT2_SYNC_FL,
@@ -176,26 +55,31 @@ const uint32_t e2attr_flags_value[] ALIGN4 = {
176 EXT2_NODUMP_FL, 55 EXT2_NODUMP_FL,
177 EXT2_NOATIME_FL, 56 EXT2_NOATIME_FL,
178 EXT2_COMPR_FL, 57 EXT2_COMPR_FL,
58 EXT2_ECOMPR_FL,
179 EXT3_JOURNAL_DATA_FL, 59 EXT3_JOURNAL_DATA_FL,
60 EXT2_INDEX_FL,
180 EXT2_NOTAIL_FL, 61 EXT2_NOTAIL_FL,
181 EXT2_TOPDIR_FL 62 EXT2_TOPDIR_FL,
63 EXT2_EXTENT_FL,
64 EXT2_NOCOW_FL,
65 EXT2_CASEFOLD_FL,
66 EXT2_INLINE_DATA_FL,
67 EXT2_PROJINHERIT_FL,
68 EXT2_VERITY_FL,
182}; 69};
183 70
184const char e2attr_flags_sname[] ALIGN1 = 71const char e2attr_flags_sname[] ALIGN1 =
185#ifdef ENABLE_COMPRESSION 72#ifdef ENABLE_COMPRESSION
186 "BZXE" 73 "BZX"
187#endif 74#endif
188 "I" 75 "suSDiadAcEjItTeCFNPV";
189 "suSDiadAcjtT";
190 76
191static const char e2attr_flags_lname[] ALIGN1 = 77static const char e2attr_flags_lname[] ALIGN1 =
192#ifdef ENABLE_COMPRESSION 78#ifdef ENABLE_COMPRESSION
193 "Compressed_File" "\0" 79 "Compressed_File" "\0"
194 "Compressed_Dirty_File" "\0" 80 "Compressed_Dirty_File" "\0"
195 "Compression_Raw_Access" "\0" 81 "Compression_Raw_Access" "\0"
196 "Compression_Error" "\0"
197#endif 82#endif
198 "Indexed_directory" "\0"
199 "Secure_Deletion" "\0" 83 "Secure_Deletion" "\0"
200 "Undelete" "\0" 84 "Undelete" "\0"
201 "Synchronous_Updates" "\0" 85 "Synchronous_Updates" "\0"
@@ -205,9 +89,17 @@ static const char e2attr_flags_lname[] ALIGN1 =
205 "No_Dump" "\0" 89 "No_Dump" "\0"
206 "No_Atime" "\0" 90 "No_Atime" "\0"
207 "Compression_Requested" "\0" 91 "Compression_Requested" "\0"
92 "Encrypted" "\0"
208 "Journaled_Data" "\0" 93 "Journaled_Data" "\0"
94 "Indexed_directory" "\0"
209 "No_Tailmerging" "\0" 95 "No_Tailmerging" "\0"
210 "Top_of_Directory_Hierarchies" "\0" 96 "Top_of_Directory_Hierarchies" "\0"
97 "Extents" "\0"
98 "No_COW" "\0"
99 "Casefold" "\0"
100 "Inline_Data" "\0"
101 "Project_Hierarchy" "\0"
102 "Verity" "\0"
211 /* Another trailing NUL is added by compiler */; 103 /* Another trailing NUL is added by compiler */;
212#else /* ENABLE_PLATFORM_MINGW32 */ 104#else /* ENABLE_PLATFORM_MINGW32 */
213/* Print file attributes on a Windows file system */ 105/* Print file attributes on a Windows file system */
@@ -243,36 +135,41 @@ static const char e2attr_flags_lname[] ALIGN1 =
243 /* Another trailing NUL is added by compiler */; 135 /* Another trailing NUL is added by compiler */;
244#endif 136#endif
245 137
246void print_e2flags(FILE *f, unsigned long flags, unsigned options) 138void print_e2flags_long(unsigned flags)
247{ 139{
248 const uint32_t *fv; 140 const uint32_t *fv;
249 const char *fn; 141 const char *fn;
142 int first = 1;
250 143
251 fv = e2attr_flags_value; 144 fv = e2attr_flags_value;
252 if (options & PFOPT_LONG) { 145 fn = e2attr_flags_lname;
253 int first = 1; 146 do {
254 fn = e2attr_flags_lname; 147 if (flags & *fv) {
255 do { 148 if (!first)
256 if (flags & *fv) { 149 fputs(", ", stdout);
257 if (!first) 150 fputs(fn, stdout);
258 fputs(", ", f); 151 first = 0;
259 fputs(fn, f); 152 }
260 first = 0; 153 fv++;
261 } 154 fn += strlen(fn) + 1;
262 fv++; 155 } while (*fn);
263 fn += strlen(fn) + 1; 156 if (first)
264 } while (*fn); 157 fputs("---", stdout);
265 if (first) 158}
266 fputs("---", f); 159
267 } else { 160void print_e2flags(unsigned flags)
268 fn = e2attr_flags_sname; 161{
269 do { 162 const uint32_t *fv;
270 char c = '-'; 163 const char *fn;
271 if (flags & *fv) 164
272 c = *fn; 165 fv = e2attr_flags_value;
273 fputc(c, f); 166 fn = e2attr_flags_sname;
274 fv++; 167 do {
275 fn++; 168 char c = '-';
276 } while (*fn); 169 if (flags & *fv)
277 } 170 c = *fn;
171 putchar(c);
172 fv++;
173 fn++;
174 } while (*fn);
278} 175}
diff --git a/e2fsprogs/e2fs_lib.h b/e2fsprogs/e2fs_lib.h
index 4a4d4cc27..aa92e63af 100644
--- a/e2fsprogs/e2fs_lib.h
+++ b/e2fsprogs/e2fs_lib.h
@@ -11,25 +11,16 @@
11 11
12PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN 12PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
13 13
14/* Iterate a function on each entry of a directory */ 14#if ENABLE_PLATFORM_MINGW32
15int iterate_on_dir(const char *dir_name, 15/* Get/set a file flags */
16 int FAST_FUNC (*func)(const char *, struct dirent *, void *), 16int fgetsetflags(const char *name, unsigned *get_flags, unsigned set_flags);
17 void *private);
18
19/* Get/set a file version on an ext2 file system */
20int fgetsetversion(const char *name, unsigned long *get_version, unsigned long set_version);
21#define fgetversion(name, version) fgetsetversion(name, version, 0)
22#define fsetversion(name, version) fgetsetversion(name, NULL, version)
23
24/* Get/set a file flags on an ext2 file system */
25int fgetsetflags(const char *name, unsigned long *get_flags, unsigned long set_flags);
26#define fgetflags(name, flags) fgetsetflags(name, flags, 0) 17#define fgetflags(name, flags) fgetsetflags(name, flags, 0)
27#define fsetflags(name, flags) fgetsetflags(name, NULL, flags) 18#define fsetflags(name, flags) fgetsetflags(name, NULL, flags)
19#endif
28 20
29/* Must be 1 for compatibility with 'int long_format'. */
30#define PFOPT_LONG 1
31/* Print file attributes on an ext2 file system */ 21/* Print file attributes on an ext2 file system */
32void print_e2flags(FILE *f, unsigned long flags, unsigned options); 22void print_e2flags_long(unsigned flags);
23void print_e2flags(unsigned flags);
33 24
34extern const uint32_t e2attr_flags_value[]; 25extern const uint32_t e2attr_flags_value[];
35extern const char e2attr_flags_sname[]; 26extern const char e2attr_flags_sname[];
diff --git a/e2fsprogs/lsattr.c b/e2fsprogs/lsattr.c
index ed7b67c6f..d82861e14 100644
--- a/e2fsprogs/lsattr.c
+++ b/e2fsprogs/lsattr.c
@@ -22,7 +22,7 @@
22 22
23//usage:#define lsattr_trivial_usage 23//usage:#define lsattr_trivial_usage
24//usage: IF_NOT_PLATFORM_MINGW32( 24//usage: IF_NOT_PLATFORM_MINGW32(
25//usage: "[-Radlv] [FILE]..." 25//usage: "[-Radlpv] [FILE]..."
26//usage: ) 26//usage: )
27//usage: IF_PLATFORM_MINGW32( 27//usage: IF_PLATFORM_MINGW32(
28//usage: "[-Radl] [FILE]..." 28//usage: "[-Radl] [FILE]..."
@@ -30,10 +30,12 @@
30//usage:#define lsattr_full_usage "\n\n" 30//usage:#define lsattr_full_usage "\n\n"
31//usage: "List ext2 file attributes\n" 31//usage: "List ext2 file attributes\n"
32//usage: "\n -R Recurse" 32//usage: "\n -R Recurse"
33//usage: "\n -a Don't hide entries starting with ." 33//usage: "\n -a Include names starting with ."
34//usage: "\n -d List directory entries instead of contents" 34//usage: "\n -d List directory names, not contents"
35// -a,-d text should match ls --help
35//usage: "\n -l List long flag names" 36//usage: "\n -l List long flag names"
36//usage: IF_NOT_PLATFORM_MINGW32( 37//usage: IF_NOT_PLATFORM_MINGW32(
38//usage: "\n -p List project ID"
37//usage: "\n -v List version/generation number" 39//usage: "\n -v List version/generation number"
38//usage: ) 40//usage: )
39 41
@@ -41,43 +43,71 @@
41#include "e2fs_lib.h" 43#include "e2fs_lib.h"
42 44
43enum { 45enum {
44 OPT_RECUR = 0x1, 46 OPT_RECUR = 1 << 0,
45 OPT_ALL = 0x2, 47 OPT_ALL = 1 << 1,
46 OPT_DIRS_OPT = 0x4, 48 OPT_DIRS_OPT = 1 << 2,
47 OPT_PF_LONG = 0x8, 49 OPT_PF_LONG = 1 << 3,
48 OPT_GENERATION = 0x10, 50 OPT_GENERATION = 1 << 4,
51 OPT_PROJID = 1 << 5,
49}; 52};
50 53
51static void list_attributes(const char *name) 54static void list_attributes(const char *name)
52{ 55{
53 unsigned long fsflags; 56 unsigned fsflags;
54#if !ENABLE_PLATFORM_MINGW32 57#if !ENABLE_PLATFORM_MINGW32
55 unsigned long generation; 58 int fd, r;
56#endif 59
57 60 /* There is no way to run needed ioctls on a symlink.
58 if (fgetflags(name, &fsflags) != 0) 61 * open(O_PATH | O_NOFOLLOW) _can_ be used to get a fd referring to the symlink,
59 goto read_err; 62 * but ioctls fail on such a fd (tried on 4.12.0 kernel).
63 * e2fsprogs-1.46.2 uses open(O_NOFOLLOW), it fails on symlinks.
64 */
65 fd = open_or_warn(name, O_RDONLY | O_NONBLOCK | O_NOCTTY | O_NOFOLLOW);
66 if (fd < 0)
67 return;
68
69 if (option_mask32 & OPT_PROJID) {
70 struct ext2_fsxattr fsxattr;
71 r = ioctl(fd, EXT2_IOC_FSGETXATTR, &fsxattr);
72 /* note: ^^^ may fail in 32-bit userspace on 64-bit kernel (seen on 4.12.0) */
73 if (r != 0)
74 goto read_err;
75 printf("%5u ", (unsigned)fsxattr.fsx_projid);
76 }
60 77
61#if !ENABLE_PLATFORM_MINGW32
62 if (option_mask32 & OPT_GENERATION) { 78 if (option_mask32 & OPT_GENERATION) {
63 if (fgetversion(name, &generation) != 0) 79 unsigned generation;
80 r = ioctl(fd, EXT2_IOC_GETVERSION, &generation);
81 if (r != 0)
64 goto read_err; 82 goto read_err;
65 printf("%5lu ", generation); 83 printf("%-10u ", generation);
66 } 84 }
85
86 r = ioctl(fd, EXT2_IOC_GETFLAGS, &fsflags);
87 if (r != 0)
88 goto read_err;
89
90 close(fd);
91#else /* ENABLE_PLATFORM_MINGW32 */
92 if (fgetflags(name, &fsflags) != 0)
93 goto read_err;
67#endif 94#endif
68 95
69 if (option_mask32 & OPT_PF_LONG) { 96 if (option_mask32 & OPT_PF_LONG) {
70 printf("%-28s ", name); 97 printf("%-28s ", name);
71 print_e2flags(stdout, fsflags, PFOPT_LONG); 98 print_e2flags_long(fsflags);
72 bb_putchar('\n'); 99 bb_putchar('\n');
73 } else { 100 } else {
74 print_e2flags(stdout, fsflags, 0); 101 print_e2flags(fsflags);
75 printf(" %s\n", name); 102 printf(" %s\n", name);
76 } 103 }
77 104
78 return; 105 return;
79 read_err: 106 read_err:
80 bb_perror_msg("reading %s", name); 107 bb_perror_msg("reading %s", name);
108#if !ENABLE_PLATFORM_MINGW32
109 close(fd);
110#endif
81} 111}
82 112
83static int FAST_FUNC lsattr_dir_proc(const char *dir_name, 113static int FAST_FUNC lsattr_dir_proc(const char *dir_name,
@@ -90,9 +120,13 @@ static int FAST_FUNC lsattr_dir_proc(const char *dir_name,
90 path = concat_path_file(dir_name, de->d_name); 120 path = concat_path_file(dir_name, de->d_name);
91 121
92 if (lstat(path, &st) != 0) 122 if (lstat(path, &st) != 0)
93 bb_perror_msg("stat %s", path); 123 bb_perror_msg("can't stat '%s'", path);
124
94 else if (de->d_name[0] != '.' || (option_mask32 & OPT_ALL)) { 125 else if (de->d_name[0] != '.' || (option_mask32 & OPT_ALL)) {
95 list_attributes(path); 126 /* Don't try to open device files, fifos etc */
127 if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode) || S_ISDIR(st.st_mode))
128 list_attributes(path);
129
96 if (S_ISDIR(st.st_mode) && (option_mask32 & OPT_RECUR) 130 if (S_ISDIR(st.st_mode) && (option_mask32 & OPT_RECUR)
97 && !DOT_OR_DOTDOT(de->d_name) 131 && !DOT_OR_DOTDOT(de->d_name)
98 ) { 132 ) {
@@ -111,7 +145,7 @@ static void lsattr_args(const char *name)
111 struct stat st; 145 struct stat st;
112 146
113 if (lstat(name, &st) == -1) { 147 if (lstat(name, &st) == -1) {
114 bb_perror_msg("stat %s", name); 148 bb_perror_msg("can't stat '%s'", name);
115 } else if (S_ISDIR(st.st_mode) && !(option_mask32 & OPT_DIRS_OPT)) { 149 } else if (S_ISDIR(st.st_mode) && !(option_mask32 & OPT_DIRS_OPT)) {
116 iterate_on_dir(name, lsattr_dir_proc, NULL); 150 iterate_on_dir(name, lsattr_dir_proc, NULL);
117 } else { 151 } else {
@@ -125,7 +159,7 @@ int lsattr_main(int argc UNUSED_PARAM, char **argv)
125#if ENABLE_PLATFORM_MINGW32 159#if ENABLE_PLATFORM_MINGW32
126 getopt32(argv, "Radl"); 160 getopt32(argv, "Radl");
127#else 161#else
128 getopt32(argv, "Radlv"); 162 getopt32(argv, "Radlvp");
129#endif 163#endif
130 argv += optind; 164 argv += optind;
131 165