]> sourceware.org Git - newlib-cygwin.git/blob - winsup/utils/chattr.c
Cygwin: add 3.2.1 release file and add fixes up to this point
[newlib-cygwin.git] / winsup / utils / chattr.c
1 /* chattr.c
2
3 Written by Corinna Vinschen <vinschen@redhat.com>
4
5 This file is part of Cygwin.
6
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
9 details. */
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <fcntl.h>
15 #include <errno.h>
16 #include <string.h>
17 #include <getopt.h>
18 #include <dirent.h>
19 #include <sys/stat.h>
20 #include <sys/ioctl.h>
21 #include <cygwin/fs.h>
22 #include <cygwin/version.h>
23
24 int Ropt, Vopt, fopt;
25 uint64_t add, del, set;
26
27 struct option longopts[] = {
28 { "recursive", no_argument, NULL, 'R' },
29 { "verbose", no_argument, NULL, 'V' },
30 { "force", no_argument, NULL, 'f' },
31 { "help", no_argument, NULL, 'h' },
32 { "version", no_argument, NULL, 'v' },
33 { NULL, no_argument, NULL, 0}
34 };
35
36 const char *opts = "+RVfhv";
37
38 struct
39 {
40 uint64_t flagval;
41 char chr;
42 const char *str;
43 } supp_flag[] = {
44 { FS_READONLY_FL, 'r', "Readonly" },
45 { FS_HIDDEN_FL, 'h', "Hidden" },
46 { FS_SYSTEM_FL, 's', "System" },
47 { FS_ARCHIVE_FL, 'a', "Archive" },
48 { FS_TEMP_FL, 't', "Temporary" },
49 { FS_SPARSE_FL, 'S', "Sparse" },
50 { FS_REPARSE_FL, 'r', NULL },
51 { FS_COMPRESSED_FL, 'c', "Compressed" },
52 { FS_OFFLINE_FL, 'o', NULL },
53 { FS_NOTINDEXED_FL, 'n', "Notindexed" },
54 { FS_ENCRYPT_FL, 'e', "Encrypted" },
55 { FS_CASESENS_FL, 'C', "Casesensitive" },
56 { 0, '\0', NULL },
57 };
58 const char *supp_list = "rhsatSrconeC";
59
60 void
61 print_flags (uint64_t flags)
62 {
63 int i;
64
65 for (i = 0; supp_flag[i].flagval; ++i)
66 fputc ((flags & supp_flag[i].flagval) ? supp_flag[i].chr : '-', stdout);
67 }
68
69 int
70 get_flags (const char *opt)
71 {
72 const char *p = opt, *sl;
73 uint64_t *mode;
74 ptrdiff_t idx;
75
76 switch (*p)
77 {
78 case '+':
79 mode = &add;
80 break;
81 case '-':
82 mode = &del;
83 break;
84 case '=':
85 mode = &set;
86 break;
87 default:
88 return 1;
89 }
90 while (*++p)
91 {
92 sl = strchr (supp_list, *p);
93 if (!sl)
94 return 1;
95 idx = sl - supp_list;
96 if (!supp_flag[idx].str)
97 return 1;
98 *mode |= supp_flag[idx].flagval;
99 }
100 return 0;
101 }
102
103 int
104 sanity_check ()
105 {
106 int ret = -1;
107 if (!set && !add && !del)
108 fprintf (stderr, "%s: Must use at least one of =, + or -\n",
109 program_invocation_short_name);
110 else if (set && (add | del))
111 fprintf (stderr, "%s: = is incompatible with + and -\n",
112 program_invocation_short_name);
113 else if ((add & del) != 0)
114 fprintf (stderr, "%s: Can't both set and unset same flag.\n",
115 program_invocation_short_name);
116 else
117 ret = 0;
118 return ret;
119 }
120
121 int
122 chattr (const char *path)
123 {
124 int fd;
125 uint64_t flags, newflags;
126
127 fd = open (path, O_RDONLY);
128 if (fd < 0)
129 {
130 fprintf (stderr, "%s: %s while trying to open %s\n",
131 program_invocation_short_name, strerror (errno), path);
132 return 1;
133 }
134 if (ioctl (fd, FS_IOC_GETFLAGS, &flags))
135 {
136 close (fd);
137 fprintf (stderr, "%s: %s while trying to fetch flags from %s\n",
138 program_invocation_short_name, strerror (errno), path);
139 return 1;
140 }
141 if (set)
142 newflags = set;
143 else
144 {
145 newflags = flags;
146 newflags |= add;
147 newflags &= ~del;
148 }
149 if (newflags != flags)
150 {
151 if (Vopt)
152 {
153 printf ("Flags of %s set as ", path);
154 print_flags (newflags);
155 fputc ('\n', stdout);
156 }
157 if (ioctl (fd, FS_IOC_SETFLAGS, &newflags))
158 {
159 close (fd);
160 fprintf (stderr, "%s: %s while trying to set flags on %s\n",
161 program_invocation_short_name, strerror (errno), path);
162 return 1;
163 }
164 }
165 close (fd);
166 return 0;
167 }
168
169 int
170 chattr_dir (const char *path)
171 {
172 DIR *dir;
173 struct dirent *de;
174 char *subpath = (char *) malloc (strlen (path) + 1 + NAME_MAX + 1);
175 char *comp;
176
177 dir = opendir (path);
178 if (!dir)
179 {
180 free (subpath);
181 return 1;
182 }
183 comp = stpcpy (subpath, path);
184 if (comp[-1] != '/')
185 *comp++ = '/';
186 while ((de = readdir (dir)))
187 {
188 struct stat st;
189
190 if (strcmp (de->d_name, ".") == 0 || strcmp (de->d_name, "..") == 0)
191 continue;
192
193 stpcpy (comp, de->d_name);
194 if (lstat (subpath, &st) != 0)
195 fprintf (stderr, "%s: %s while trying to stat %s\n",
196 program_invocation_short_name, strerror (errno),
197 subpath);
198 else
199 {
200 if (S_ISREG (st.st_mode) || S_ISDIR (st.st_mode))
201 chattr (subpath);
202 if (S_ISDIR (st.st_mode) && Ropt)
203 chattr_dir (subpath);
204 }
205 }
206 free (subpath);
207 return 0;
208 }
209
210 static void
211 print_version ()
212 {
213 printf ("%s (cygwin) %d.%d.%d\n"
214 "Get POSIX ACL information\n"
215 "Copyright (C) 2018 - %s Cygwin Authors\n"
216 "This is free software; see the source for copying conditions. "
217 "There is NO\n"
218 "warranty; not even for MERCHANTABILITY or FITNESS FOR A "
219 "PARTICULAR PURPOSE.\n",
220 program_invocation_short_name,
221 CYGWIN_VERSION_DLL_MAJOR / 1000,
222 CYGWIN_VERSION_DLL_MAJOR % 1000,
223 CYGWIN_VERSION_DLL_MINOR,
224 strrchr (__DATE__, ' ') + 1);
225 }
226
227 static void __attribute__ ((__noreturn__))
228 usage (FILE *stream)
229 {
230 fprintf (stream, "Usage: %s [-RVfhv] [+-=mode]... [file]...\n",
231 program_invocation_short_name);
232 if (stream == stderr)
233 fprintf (stream, "Try '%s --help' for more information\n",
234 program_invocation_short_name);
235 if (stream == stdout)
236 fprintf (stream, "\n"
237 "Change file attributes\n"
238 "\n"
239 " -R, --recursive recursively list attributes of directories and their \n"
240 " contents\n"
241 " -V, --verbose Be verbose during operation\n"
242 " -f, --force suppress error messages\n"
243 " -h, --help this help text\n"
244 " -v, --version display the program version\n"
245 "\n"
246 "The format of 'mode' is {+-=}[acCehnrsSt]\n"
247 "\n"
248 "The operator '+' causes the selected attributes to be added to the\n"
249 "existing attributes of the files; '-' causes them to be removed; and\n"
250 "'=' causes them to be the only attributes that the files have.\n"
251 "\n"
252 "Supported attributes:\n"
253 "\n"
254 " 'r', 'Readonly': file is read-only\n"
255 " 'h', 'Hidden': file or directory is hidden\n"
256 " 's', 'System': file or directory that the operating system uses\n"
257 " 'a', 'Archive': file or directory has the archive marker set\n"
258 " 't', 'Temporary': file is being used for temporary storage\n"
259 " 'S', 'Sparse': file is sparse\n"
260 " 'c', 'Compressed': file or directory is compressed\n"
261 " 'n', 'Notindexed': file or directory is not to be indexed by the\n"
262 " content indexing service\n"
263 " 'e', 'Encrypted': file is encrypted\n"
264 " 'C', 'Casesensitive': directory is handled case sensitive\n"
265 " (Windows 10 1803 or later, local NTFS only,\n"
266 " WSL must be installed)\n");
267 exit (stream == stdout ? 0 : 1);
268 }
269
270 int
271 main (int argc, char **argv)
272 {
273 int c, ret = 0;
274 int lastoptind = 0;
275 char *opt;
276
277 opterr = 0;
278 while ((c = getopt_long (argc, argv, opts, longopts, NULL)) != EOF)
279 {
280 switch (c)
281 {
282 case 'R':
283 Ropt = 1;
284 lastoptind = optind;
285 break;
286 case 'V':
287 Vopt = 1;
288 lastoptind = optind;
289 break;
290 case 'f':
291 fopt = 1;
292 lastoptind = optind;
293 break;
294 case 'v':
295 print_version ();
296 return 0;
297 break;
298 default:
299 if (optind > lastoptind)
300 {
301 --optind;
302 goto next;
303 }
304 /*FALLTHRU*/
305 case 'h':
306 usage (c == 'h' ? stdout : stderr);
307 }
308 }
309 next:
310 while (optind < argc)
311 {
312 if (strcmp (argv[optind], "--") == 0)
313 {
314 ++optind;
315 break;
316 }
317 opt = strchr ("+-=", argv[optind][0]);
318 if (!opt)
319 break;
320 if (argv[optind][1] == '\0' || get_flags (argv[optind]))
321 usage (stderr);
322 ++optind;
323 }
324 if (sanity_check ())
325 return 1;
326 if (optind > argc - 1)
327 {
328 chattr (".");
329 if (Ropt)
330 chattr_dir (".");
331 }
332 else for (; optind < argc; ++optind)
333 {
334 struct stat st;
335
336 if (lstat (argv[optind], &st) != 0)
337 {
338 fprintf (stderr, "%s: %s while trying to stat %s\n",
339 program_invocation_short_name, strerror (errno),
340 argv[optind]);
341 ret = 1;
342 }
343 else if (!S_ISREG (st.st_mode) && !S_ISDIR (st.st_mode))
344 {
345 fprintf (stderr, "%s: %s on %s\n",
346 program_invocation_short_name, strerror (ENOTSUP),
347 argv[optind]);
348 ret = 1;
349 }
350 else
351 {
352 if (chattr (argv[optind]))
353 ret = 1;
354 if (S_ISDIR (st.st_mode) && chattr_dir (argv[optind]))
355 ret = 1;
356 }
357 }
358 return ret;
359 }
This page took 0.052753 seconds and 5 git commands to generate.