aboutsummaryrefslogtreecommitdiff
path: root/e2fsprogs/chattr.c
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/chattr.c
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/chattr.c')
-rw-r--r--e2fsprogs/chattr.c146
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
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 */