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/chattr.c | |
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/chattr.c')
-rw-r--r-- | e2fsprogs/chattr.c | 146 |
1 files changed, 108 insertions, 38 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 */ |