Cygwin: Add lsattr and chattr tools
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
parent
af4a65a26d
commit
0d4b39d37b
|
@ -54,7 +54,7 @@ MINGW_CXX := @MINGW_CXX@
|
|||
|
||||
# List all binaries to be linked in Cygwin mode. Each binary on this list
|
||||
# must have a corresponding .o of the same name.
|
||||
CYGWIN_BINS := ${addsuffix .exe,cygpath gencat getconf getfacl ldd locale kill minidumper mkgroup \
|
||||
CYGWIN_BINS := ${addsuffix .exe,chattr cygpath gencat getconf getfacl ldd locale lsattr kill minidumper mkgroup \
|
||||
mkpasswd mount passwd pldd ps regtool setfacl setmetamode ssp tzset umount}
|
||||
|
||||
# List all binaries to be linked in MinGW mode. Each binary on this list
|
||||
|
|
|
@ -0,0 +1,362 @@
|
|||
/* chattr.c
|
||||
|
||||
Written by Corinna Vinschen <vinschen@redhat.com>
|
||||
|
||||
This file is part of Cygwin.
|
||||
|
||||
This software is a copyrighted work licensed under the terms of the
|
||||
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
|
||||
details. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <cygwin/fs.h>
|
||||
#include <cygwin/version.h>
|
||||
|
||||
int Ropt, Vopt, fopt;
|
||||
uint64_t add, del, set;
|
||||
|
||||
struct option longopts[] = {
|
||||
{ "recursive", no_argument, NULL, 'R' },
|
||||
{ "verbose", no_argument, NULL, 'V' },
|
||||
{ "force", no_argument, NULL, 'f' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, 'v' },
|
||||
{ NULL, no_argument, NULL, 0}
|
||||
};
|
||||
|
||||
const char *opts = "+RVfhv";
|
||||
|
||||
struct
|
||||
{
|
||||
uint64_t flagval;
|
||||
char chr;
|
||||
const char *str;
|
||||
} supp_flag[] = {
|
||||
{ FS_READONLY_FL, 'r', "Readonly" },
|
||||
{ FS_HIDDEN_FL, 'h', "Hidden" },
|
||||
{ FS_SYSTEM_FL, 's', "System" },
|
||||
{ FS_ARCHIVE_FL, 'a', "Archive" },
|
||||
{ FS_TEMP_FL, 't', "Temporary" },
|
||||
{ FS_SPARSE_FL, 'S', "Sparse" },
|
||||
{ FS_REPARSE_FL, 'r', NULL },
|
||||
{ FS_COMPRESSED_FL, 'c', "Compressed" },
|
||||
{ FS_OFFLINE_FL, 'o', NULL },
|
||||
{ FS_NOTINDEXED_FL, 'n', "Notindexed" },
|
||||
{ FS_ENCRYPT_FL, 'e', "Encrypted" },
|
||||
{ FS_CASESENS_FL, 'C', "Casesensitive" },
|
||||
{ 0, '\0', NULL },
|
||||
};
|
||||
const char *supp_list = "rhsatSrconeC";
|
||||
|
||||
void
|
||||
print_flags (uint64_t flags)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; supp_flag[i].flagval; ++i)
|
||||
fputc ((flags & supp_flag[i].flagval) ? supp_flag[i].chr : '-', stdout);
|
||||
}
|
||||
|
||||
int
|
||||
get_flags (const char *opt)
|
||||
{
|
||||
const char *p = opt, *sl;
|
||||
uint64_t *mode;
|
||||
ptrdiff_t idx;
|
||||
|
||||
switch (*p)
|
||||
{
|
||||
case '+':
|
||||
mode = &add;
|
||||
break;
|
||||
case '-':
|
||||
mode = &del;
|
||||
break;
|
||||
case '=':
|
||||
mode = &set;
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
while (*++p)
|
||||
{
|
||||
sl = strchr (supp_list, *p);
|
||||
if (!sl)
|
||||
return 1;
|
||||
idx = sl - supp_list;
|
||||
if (!supp_flag[idx].str)
|
||||
return 1;
|
||||
*mode |= supp_flag[idx].flagval;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
sanity_check ()
|
||||
{
|
||||
int ret = -1;
|
||||
if (!set && !add && !del)
|
||||
fprintf (stderr, "%s: Must use at least one of =, + or -\n",
|
||||
program_invocation_short_name);
|
||||
else if (set && (add | del))
|
||||
fprintf (stderr, "%s: = is incompatible with + and -\n",
|
||||
program_invocation_short_name);
|
||||
else if ((add & del) != 0)
|
||||
fprintf (stderr, "%s: Can't both set and unset same flag.\n",
|
||||
program_invocation_short_name);
|
||||
else
|
||||
ret = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
chattr (const char *path)
|
||||
{
|
||||
int fd;
|
||||
uint64_t flags, newflags;
|
||||
|
||||
fd = open (path, O_RDONLY);
|
||||
if (fd < 0)
|
||||
{
|
||||
fprintf (stderr, "%s: %s while trying to open %s\n",
|
||||
program_invocation_short_name, strerror (errno), path);
|
||||
return 1;
|
||||
}
|
||||
if (ioctl (fd, FS_IOC_GETFLAGS, &flags))
|
||||
{
|
||||
close (fd);
|
||||
fprintf (stderr, "%s: %s while trying to fetch flags from %s\n",
|
||||
program_invocation_short_name, strerror (errno), path);
|
||||
return 1;
|
||||
}
|
||||
if (set)
|
||||
newflags = set;
|
||||
else
|
||||
{
|
||||
newflags = flags;
|
||||
newflags |= add;
|
||||
newflags &= ~del;
|
||||
}
|
||||
if (newflags != flags)
|
||||
{
|
||||
if (Vopt)
|
||||
{
|
||||
printf ("Flags of %s set as ", path);
|
||||
print_flags (newflags);
|
||||
fputc ('\n', stdout);
|
||||
}
|
||||
if (ioctl (fd, FS_IOC_SETFLAGS, &newflags))
|
||||
{
|
||||
close (fd);
|
||||
fprintf (stderr, "%s: %s while trying to set flags on %s\n",
|
||||
program_invocation_short_name, strerror (errno), path);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
close (fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
chattr_dir (const char *path)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *de;
|
||||
char *subpath = (char *) malloc (strlen (path) + 1 + NAME_MAX + 1);
|
||||
char *comp;
|
||||
|
||||
dir = opendir (path);
|
||||
if (!dir)
|
||||
{
|
||||
free (subpath);
|
||||
return 1;
|
||||
}
|
||||
comp = stpcpy (subpath, path);
|
||||
if (comp[-1] != '/')
|
||||
*comp++ = '/';
|
||||
while ((de = readdir (dir)))
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (strcmp (de->d_name, ".") == 0 || strcmp (de->d_name, "..") == 0)
|
||||
continue;
|
||||
|
||||
stpcpy (comp, de->d_name);
|
||||
if (lstat (subpath, &st) != 0)
|
||||
fprintf (stderr, "%s: %s while trying to stat %s\n",
|
||||
program_invocation_short_name, strerror (errno),
|
||||
subpath);
|
||||
else
|
||||
{
|
||||
if (S_ISREG (st.st_mode) || S_ISDIR (st.st_mode))
|
||||
chattr (subpath);
|
||||
if (S_ISDIR (st.st_mode) && Ropt)
|
||||
chattr_dir (subpath);
|
||||
}
|
||||
}
|
||||
free (subpath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
print_version ()
|
||||
{
|
||||
printf ("%s (cygwin) %d.%d.%d\n"
|
||||
"Get POSIX ACL information\n"
|
||||
"Copyright (C) 2018 - %s Cygwin Authors\n"
|
||||
"This is free software; see the source for copying conditions. "
|
||||
"There is NO\n"
|
||||
"warranty; not even for MERCHANTABILITY or FITNESS FOR A "
|
||||
"PARTICULAR PURPOSE.\n",
|
||||
program_invocation_short_name,
|
||||
CYGWIN_VERSION_DLL_MAJOR / 1000,
|
||||
CYGWIN_VERSION_DLL_MAJOR % 1000,
|
||||
CYGWIN_VERSION_DLL_MINOR,
|
||||
strrchr (__DATE__, ' ') + 1);
|
||||
}
|
||||
|
||||
static void
|
||||
usage (FILE *stream)
|
||||
{
|
||||
fprintf (stream, "Usage: %s [-RVfhv] [+-=mode]... [file]...\n",
|
||||
program_invocation_short_name);
|
||||
if (stream == stderr)
|
||||
fprintf (stream, "Try '%s --help' for more information\n",
|
||||
program_invocation_short_name);
|
||||
if (stream == stdout)
|
||||
fprintf (stream, "\n"
|
||||
"Change file attributes\n"
|
||||
"\n"
|
||||
" -R, --recursive recursively list attributes of directories and their \n"
|
||||
" contents\n"
|
||||
" -V, --verbose Be verbose during operation\n"
|
||||
" -f, --force suppress error messages\n"
|
||||
" -h, --help this help text\n"
|
||||
" -v, --version display the program version\n"
|
||||
"\n"
|
||||
"The format of 'mode' is {+-=}[acCehnrsSt]\n"
|
||||
"\n"
|
||||
"The operator '+' causes the selected attributes to be added to the\n"
|
||||
"existing attributes of the files; '-' causes them to be removed; and\n"
|
||||
"'=' causes them to be the only attributes that the files have.\n"
|
||||
"\n"
|
||||
"Supported attributes:\n"
|
||||
"\n"
|
||||
" 'r', 'Readonly': file is read-only\n"
|
||||
" 'h', 'Hidden': file or directory is hidden\n"
|
||||
" 's', 'System': file or directory that the operating system uses\n"
|
||||
" 'a', 'Archive': file or directory has the archive marker set\n"
|
||||
" 't', 'Temporary': file is being used for temporary storage\n"
|
||||
" 'S', 'Sparse': file is sparse\n"
|
||||
" 'c', 'Compressed': file or directory is compressed\n"
|
||||
" 'n', 'Notindexed': file or directory is not to be indexed by the\n"
|
||||
" content indexing service\n"
|
||||
" 'e', 'Encrypted': file is encrypted\n"
|
||||
" 'C', 'Casesensitive': directory is handled case sensitive\n"
|
||||
" (Windows 10 1803 or later, local NTFS only,\n"
|
||||
" WSL must be installed)\n");
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int c, ret = 0;
|
||||
int lastoptind = 0;
|
||||
char *opt;
|
||||
|
||||
opterr = 0;
|
||||
while ((c = getopt_long (argc, argv, opts, longopts, NULL)) != EOF)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'R':
|
||||
Ropt = 1;
|
||||
lastoptind = optind;
|
||||
break;
|
||||
case 'V':
|
||||
Vopt = 1;
|
||||
lastoptind = optind;
|
||||
break;
|
||||
case 'f':
|
||||
fopt = 1;
|
||||
lastoptind = optind;
|
||||
break;
|
||||
case 'v':
|
||||
print_version ();
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
if (optind > lastoptind)
|
||||
{
|
||||
--optind;
|
||||
goto next;
|
||||
}
|
||||
/*FALLTHRU*/
|
||||
case 'h':
|
||||
usage (c == 'h' ? stdout : stderr);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
next:
|
||||
while (optind < argc)
|
||||
{
|
||||
if (strcmp (argv[optind], "--") == 0)
|
||||
{
|
||||
++optind;
|
||||
break;
|
||||
}
|
||||
opt = strchr ("+-=", argv[optind][0]);
|
||||
if (!opt)
|
||||
break;
|
||||
if (argv[optind][1] == '\0' || get_flags (argv[optind]))
|
||||
{
|
||||
usage (stderr);
|
||||
return 1;
|
||||
}
|
||||
++optind;
|
||||
}
|
||||
if (sanity_check ())
|
||||
return 1;
|
||||
if (optind > argc - 1)
|
||||
{
|
||||
chattr (".");
|
||||
if (Ropt)
|
||||
chattr_dir (".");
|
||||
}
|
||||
else for (; optind < argc; ++optind)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (lstat (argv[optind], &st) != 0)
|
||||
{
|
||||
fprintf (stderr, "%s: %s while trying to stat %s\n",
|
||||
program_invocation_short_name, strerror (errno),
|
||||
argv[optind]);
|
||||
ret = 1;
|
||||
}
|
||||
else if (!S_ISREG (st.st_mode) && !S_ISDIR (st.st_mode))
|
||||
{
|
||||
fprintf (stderr, "%s: %s on %s\n",
|
||||
program_invocation_short_name, strerror (ENOTSUP),
|
||||
argv[optind]);
|
||||
ret = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (chattr (argv[optind]))
|
||||
ret = 1;
|
||||
if (S_ISDIR (st.st_mode) && chattr_dir (argv[optind]))
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,289 @@
|
|||
/* lsattr.c
|
||||
|
||||
Written by Corinna Vinschen <vinschen@redhat.com>
|
||||
|
||||
This file is part of Cygwin.
|
||||
|
||||
This software is a copyrighted work licensed under the terms of the
|
||||
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
|
||||
details. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <cygwin/fs.h>
|
||||
#include <cygwin/version.h>
|
||||
|
||||
int Ropt, aopt, dopt, lopt, nopt;
|
||||
|
||||
struct option longopts[] = {
|
||||
{ "recursive", no_argument, NULL, 'R' },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ "all", no_argument, NULL, 'a' },
|
||||
{ "directory", no_argument, NULL, 'd' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "long", no_argument, NULL, 'l' },
|
||||
{ "no-headers", no_argument, NULL, 'n' },
|
||||
{ NULL, no_argument, NULL, 0}
|
||||
};
|
||||
|
||||
const char *opts = "+RVadhln";
|
||||
|
||||
struct
|
||||
{
|
||||
uint64_t flagval;
|
||||
char chr;
|
||||
const char *str;
|
||||
} supp_flag[] = {
|
||||
{ FS_READONLY_FL, 'r', "Readonly" },
|
||||
{ FS_HIDDEN_FL, 'h', "Hidden" },
|
||||
{ FS_SYSTEM_FL, 's', "System" },
|
||||
{ FS_ARCHIVE_FL, 'a', "Archive" },
|
||||
{ FS_TEMP_FL, 't', "Temporary" },
|
||||
{ FS_SPARSE_FL, 'S', "Sparse" },
|
||||
{ FS_REPARSE_FL, 'r', "Reparse" },
|
||||
{ FS_COMPRESSED_FL, 'c', "Compressed" },
|
||||
{ FS_OFFLINE_FL, 'o', "Offline" },
|
||||
{ FS_NOTINDEXED_FL, 'n', "Notindexed" },
|
||||
{ FS_ENCRYPT_FL, 'e', "Encrypted" },
|
||||
{ FS_CASESENS_FL, 'C', "Casesensitive" },
|
||||
{ 0, '\0', NULL },
|
||||
};
|
||||
|
||||
void
|
||||
print_long (const char *path, uint64_t flags)
|
||||
{
|
||||
int i;
|
||||
int first = 1;
|
||||
|
||||
printf("%-28s ", path);
|
||||
for (i = 0; supp_flag[i].flagval; ++i)
|
||||
if (flags & supp_flag[i].flagval)
|
||||
{
|
||||
if (!first)
|
||||
fputs (", ", stdout);
|
||||
first = 0;
|
||||
fputs (supp_flag[i].str, stdout);
|
||||
}
|
||||
if (first)
|
||||
fputs ("---", stdout);
|
||||
fputc ('\n', stdout);
|
||||
}
|
||||
|
||||
void
|
||||
print_short (const char *path, uint64_t flags)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; supp_flag[i].flagval; ++i)
|
||||
fputc ((flags & supp_flag[i].flagval) ? supp_flag[i].chr : '-', stdout);
|
||||
printf(" %s\n", path);
|
||||
}
|
||||
|
||||
int
|
||||
lsattr (const char *path)
|
||||
{
|
||||
int fd;
|
||||
uint64_t flags;
|
||||
|
||||
fd = open (path, O_RDONLY);
|
||||
if (fd < 0)
|
||||
{
|
||||
fprintf (stderr, "%s: %s while trying to open %s\n",
|
||||
program_invocation_short_name, strerror (errno),
|
||||
path);
|
||||
return 1;
|
||||
}
|
||||
if (ioctl (fd, FS_IOC_GETFLAGS, &flags))
|
||||
{
|
||||
close (fd);
|
||||
fprintf (stderr, "%s: %s while trying to fetch flags from %s\n",
|
||||
program_invocation_short_name, strerror (errno),
|
||||
path);
|
||||
return 1;
|
||||
}
|
||||
close (fd);
|
||||
if (lopt)
|
||||
print_long (path, flags);
|
||||
else
|
||||
print_short (path, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lsattr_dir (const char *path)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *de;
|
||||
char *subpath = (char *) malloc (strlen (path) + 1 + NAME_MAX + 1);
|
||||
char *comp;
|
||||
|
||||
dir = opendir (path);
|
||||
if (!dir)
|
||||
{
|
||||
free (subpath);
|
||||
return 1;
|
||||
}
|
||||
comp = stpcpy (subpath, path);
|
||||
if (comp[-1] != '/')
|
||||
*comp++ = '/';
|
||||
while ((de = readdir (dir)))
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
stpcpy (comp, de->d_name);
|
||||
if (lstat (subpath, &st) != 0)
|
||||
fprintf (stderr, "%s: %s while trying to stat %s\n",
|
||||
program_invocation_short_name, strerror (errno),
|
||||
subpath);
|
||||
else if (de->d_name[0] != '.' || aopt)
|
||||
{
|
||||
if (S_ISREG (st.st_mode) || S_ISDIR (st.st_mode))
|
||||
lsattr (subpath);
|
||||
if (S_ISDIR (st.st_mode) && Ropt
|
||||
&& strcmp (de->d_name, ".") != 0
|
||||
&& strcmp (de->d_name, "..") != 0)
|
||||
{
|
||||
if (!nopt)
|
||||
printf ("\n%s:\n", path);
|
||||
lsattr_dir (subpath);
|
||||
if (!nopt)
|
||||
fputc ('\n', stdout);
|
||||
}
|
||||
}
|
||||
}
|
||||
free (subpath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
print_version ()
|
||||
{
|
||||
printf ("%s (cygwin) %d.%d.%d\n"
|
||||
"Get POSIX ACL information\n"
|
||||
"Copyright (C) 2018 - %s Cygwin Authors\n"
|
||||
"This is free software; see the source for copying conditions. "
|
||||
"There is NO\n"
|
||||
"warranty; not even for MERCHANTABILITY or FITNESS FOR A "
|
||||
"PARTICULAR PURPOSE.\n",
|
||||
program_invocation_short_name,
|
||||
CYGWIN_VERSION_DLL_MAJOR / 1000,
|
||||
CYGWIN_VERSION_DLL_MAJOR % 1000,
|
||||
CYGWIN_VERSION_DLL_MINOR,
|
||||
strrchr (__DATE__, ' ') + 1);
|
||||
}
|
||||
|
||||
static void
|
||||
usage (FILE *stream)
|
||||
{
|
||||
fprintf (stream, "Usage: %s [-RVadhln] [file]...\n",
|
||||
program_invocation_short_name);
|
||||
if (stream == stderr)
|
||||
fprintf (stream, "Try '%s --help' for more information\n",
|
||||
program_invocation_short_name);
|
||||
if (stream == stdout)
|
||||
fprintf (stream, "\n"
|
||||
"List file attributes\n"
|
||||
"\n"
|
||||
" -R, --recursive recursively list attributes of directories and their \n"
|
||||
" contents\n"
|
||||
" -V, --version display the program version\n"
|
||||
" -a, --all list all files in directories, including files that\n"
|
||||
" start with '.'\n"
|
||||
" -d, --directory list directories like other files, rather than listing\n"
|
||||
" their contents.\n"
|
||||
" -l, --long print options using long names instead of single\n"
|
||||
" character abbreviations\n"
|
||||
" -n, --no-headers don't print directory headers when recursing\n"
|
||||
" -h, --help this help text\n"
|
||||
"\n"
|
||||
"Supported attributes:\n"
|
||||
"\n"
|
||||
" 'r', 'Readonly': file is read-only, directory is system-marked\n"
|
||||
" 'h', 'Hidden': file or directory is hidden\n"
|
||||
" 's', 'System': file or directory that the operating system uses\n"
|
||||
" 'a', 'Archive': file or directory has the archive marker set\n"
|
||||
" 't', 'Temporary': file is being used for temporary storage\n"
|
||||
" 'S', 'Sparse': file is sparse\n"
|
||||
" 'r', 'Reparse': file or directory that has a reparse point\n"
|
||||
" 'c', 'Compressed': file or directory is compressed\n"
|
||||
" 'o', 'Offline': the data of a file is moved to offline storage\n"
|
||||
" 'n', 'Notindexed': file or directory is not to be indexed by the\n"
|
||||
" content indexing service\n"
|
||||
" 'e', 'Encrypted': file is encrypted\n"
|
||||
" 'C', 'Casesensitive': directory is handled case sensitive\n"
|
||||
" (Windows 10 1803 or later, local NTFS only,\n"
|
||||
" WSL must be installed)\n");
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int c, ret = 0;
|
||||
|
||||
opterr = 0;
|
||||
while ((c = getopt_long (argc, argv, opts, longopts, NULL)) != EOF)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'R':
|
||||
Ropt = 1;
|
||||
break;
|
||||
case 'V':
|
||||
print_version ();
|
||||
return 0;
|
||||
case 'a':
|
||||
aopt = 1;
|
||||
break;
|
||||
case 'd':
|
||||
dopt = 1;
|
||||
break;
|
||||
case 'l':
|
||||
lopt = 1;
|
||||
break;
|
||||
case 'n':
|
||||
nopt = 1;
|
||||
break;
|
||||
case 'h':
|
||||
default:
|
||||
usage (c == 'h' ? stdout : stderr);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (optind > argc - 1)
|
||||
lsattr_dir (".");
|
||||
else for (; optind < argc; ++optind)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (lstat (argv[optind], &st) != 0)
|
||||
{
|
||||
fprintf (stderr, "%s: %s while trying to stat %s\n",
|
||||
program_invocation_short_name, strerror (errno),
|
||||
argv[optind]);
|
||||
ret = 1;
|
||||
}
|
||||
else if (!S_ISREG (st.st_mode) && !S_ISDIR (st.st_mode))
|
||||
{
|
||||
fprintf (stderr, "%s: %s on %s\n",
|
||||
program_invocation_short_name, strerror (ENOTSUP),
|
||||
argv[optind]);
|
||||
ret = 1;
|
||||
}
|
||||
else if (S_ISDIR (st.st_mode) && !dopt)
|
||||
{
|
||||
if (lsattr_dir (argv[optind]))
|
||||
ret = 1;
|
||||
}
|
||||
else if (lsattr (argv[optind]))
|
||||
ret = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
Loading…
Reference in New Issue