3 Written by Corinna Vinschen <vinschen@redhat.com>
5 This file is part of Cygwin.
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
20 #include <sys/ioctl.h>
21 #include <cygwin/fs.h>
22 #include <cygwin/version.h>
25 uint64_t add
, del
, set
;
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}
36 const char *opts
= "+RVfhv";
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" },
58 const char *supp_list
= "rhsatSrconeC";
61 print_flags (uint64_t flags
)
65 for (i
= 0; supp_flag
[i
].flagval
; ++i
)
66 fputc ((flags
& supp_flag
[i
].flagval
) ? supp_flag
[i
].chr
: '-', stdout
);
70 get_flags (const char *opt
)
72 const char *p
= opt
, *sl
;
92 sl
= strchr (supp_list
, *p
);
96 if (!supp_flag
[idx
].str
)
98 *mode
|= supp_flag
[idx
].flagval
;
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
);
122 chattr (const char *path
)
125 uint64_t flags
, newflags
;
127 fd
= open (path
, O_RDONLY
);
130 fprintf (stderr
, "%s: %s while trying to open %s\n",
131 program_invocation_short_name
, strerror (errno
), path
);
134 if (ioctl (fd
, FS_IOC_GETFLAGS
, &flags
))
137 fprintf (stderr
, "%s: %s while trying to fetch flags from %s\n",
138 program_invocation_short_name
, strerror (errno
), path
);
149 if (newflags
!= flags
)
153 printf ("Flags of %s set as ", path
);
154 print_flags (newflags
);
155 fputc ('\n', stdout
);
157 if (ioctl (fd
, FS_IOC_SETFLAGS
, &newflags
))
160 fprintf (stderr
, "%s: %s while trying to set flags on %s\n",
161 program_invocation_short_name
, strerror (errno
), path
);
170 chattr_dir (const char *path
)
174 char *subpath
= (char *) malloc (strlen (path
) + 1 + NAME_MAX
+ 1);
177 dir
= opendir (path
);
183 comp
= stpcpy (subpath
, path
);
186 while ((de
= readdir (dir
)))
190 if (strcmp (de
->d_name
, ".") == 0 || strcmp (de
->d_name
, "..") == 0)
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
),
200 if (S_ISREG (st
.st_mode
) || S_ISDIR (st
.st_mode
))
202 if (S_ISDIR (st
.st_mode
) && Ropt
)
203 chattr_dir (subpath
);
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. "
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);
227 static void __attribute__ ((__noreturn__
))
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"
239 " -R, --recursive recursively list attributes of directories and their \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"
246 "The format of 'mode' is {+-=}[acCehnrsSt]\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"
252 "Supported attributes:\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);
271 main (int argc
, char **argv
)
278 while ((c
= getopt_long (argc
, argv
, opts
, longopts
, NULL
)) != EOF
)
299 if (optind
> lastoptind
)
306 usage (c
== 'h' ? stdout
: stderr
);
310 while (optind
< argc
)
312 if (strcmp (argv
[optind
], "--") == 0)
317 opt
= strchr ("+-=", argv
[optind
][0]);
320 if (argv
[optind
][1] == '\0' || get_flags (argv
[optind
]))
326 if (optind
> argc
- 1)
332 else for (; optind
< argc
; ++optind
)
336 if (lstat (argv
[optind
], &st
) != 0)
338 fprintf (stderr
, "%s: %s while trying to stat %s\n",
339 program_invocation_short_name
, strerror (errno
),
343 else if (!S_ISREG (st
.st_mode
) && !S_ISDIR (st
.st_mode
))
345 fprintf (stderr
, "%s: %s on %s\n",
346 program_invocation_short_name
, strerror (ENOTSUP
),
352 if (chattr (argv
[optind
]))
354 if (S_ISDIR (st
.st_mode
) && chattr_dir (argv
[optind
]))