diff options
author | Ron Yorston <rmy@pobox.com> | 2021-06-28 07:46:32 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2021-06-28 07:46:32 +0100 |
commit | e1ad66c0b8fd58a7158d40771175a7dab224202d (patch) | |
tree | 959d687eee9637151ad5798322586174de331141 /e2fsprogs | |
parent | 0fdf99bee07b6c38795eb5415b5e337ab82cfba8 (diff) | |
parent | 5dbbd0a6f52befe6bc57baf97d39168e595197f1 (diff) | |
download | busybox-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.c | 146 | ||||
-rw-r--r-- | e2fsprogs/e2fs_lib.c | 209 | ||||
-rw-r--r-- | e2fsprogs/e2fs_lib.h | 21 | ||||
-rw-r--r-- | e2fsprogs/lsattr.c | 80 |
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 | ||
76 | struct globals { | 87 | struct 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 | ||
94 | static char** decode_arg(char **argv, struct globals *gp) | 108 | static 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 | ||
155 | static int FAST_FUNC chattr_dir_proc(const char *dir_name, struct dirent *de, void *gp) | 178 | static 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 | ||
166 | static void change_attributes(const char *name, struct globals *gp) | 191 | static 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 | |||
22 | static 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 */ | ||
32 | int 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 */ | ||
53 | int 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 */ | ||
88 | int 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 */ |
137 | int fgetsetflags(const char *name, unsigned long *get_flags, unsigned long set_flags) | 19 | int 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 */ |
162 | const uint32_t e2attr_flags_value[] ALIGN4 = { | 43 | const 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 | ||
184 | const char e2attr_flags_sname[] ALIGN1 = | 71 | const 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 | ||
191 | static const char e2attr_flags_lname[] ALIGN1 = | 77 | static 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 | ||
246 | void print_e2flags(FILE *f, unsigned long flags, unsigned options) | 138 | void 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 { | 160 | void 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 | ||
12 | PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN | 12 | PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN |
13 | 13 | ||
14 | /* Iterate a function on each entry of a directory */ | 14 | #if ENABLE_PLATFORM_MINGW32 |
15 | int iterate_on_dir(const char *dir_name, | 15 | /* Get/set a file flags */ |
16 | int FAST_FUNC (*func)(const char *, struct dirent *, void *), | 16 | int 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 */ | ||
20 | int 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 */ | ||
25 | int 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 */ |
32 | void print_e2flags(FILE *f, unsigned long flags, unsigned options); | 22 | void print_e2flags_long(unsigned flags); |
23 | void print_e2flags(unsigned flags); | ||
33 | 24 | ||
34 | extern const uint32_t e2attr_flags_value[]; | 25 | extern const uint32_t e2attr_flags_value[]; |
35 | extern const char e2attr_flags_sname[]; | 26 | extern 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 | ||
43 | enum { | 45 | enum { |
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 | ||
51 | static void list_attributes(const char *name) | 54 | static 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 | ||
83 | static int FAST_FUNC lsattr_dir_proc(const char *dir_name, | 113 | static 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 | ||