149 lines
3.8 KiB
C
149 lines
3.8 KiB
C
#define _GNU_SOURCE
|
|
#include <dirent.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <strings.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
|
|
#define MAX_PATH_LEN 4096
|
|
|
|
static void usage (void) __attribute__ ((unused));
|
|
|
|
// WARNING WARNING WARNING:
|
|
// When using opendir and readdir to read directory listings, the files
|
|
// are returned in the order they were created. There is randomness to that
|
|
// creation that can cause tests to fail. You MUST sort the file names as
|
|
// expected in the test case files. To avoid making your task harder than
|
|
// it needs to be, we strongly suggest you use scandir instead.
|
|
|
|
int
|
|
filename_cmp (const struct dirent **a, const struct dirent **b)
|
|
{
|
|
const char *name1 = (*a)->d_name;
|
|
const char *name2 = (*b)->d_name;
|
|
|
|
while (*name1 == '.')
|
|
name1++;
|
|
while (*name2 == '.')
|
|
name2++;
|
|
|
|
return strcasecmp (name1, name2);
|
|
}
|
|
|
|
void
|
|
print_permissions (mode_t mode)
|
|
{
|
|
char perms[11];
|
|
|
|
perms[0] = S_ISDIR (mode) ? 'd' : '-';
|
|
perms[1] = (mode & S_IRUSR) ? 'r' : '-';
|
|
perms[2] = (mode & S_IWUSR) ? 'w' : '-';
|
|
perms[3] = (mode & S_IXUSR) ? 'x' : '-';
|
|
perms[4] = (mode & S_IRGRP) ? 'r' : '-';
|
|
perms[5] = (mode & S_IWGRP) ? 'w' : '-';
|
|
perms[6] = (mode & S_IXGRP) ? 'x' : '-';
|
|
perms[7] = (mode & S_IROTH) ? 'r' : '-';
|
|
perms[8] = (mode & S_IWOTH) ? 'w' : '-';
|
|
perms[9] = (mode & S_IXOTH) ? 'x' : '-';
|
|
perms[10] = '\0';
|
|
|
|
printf ("%s", perms);
|
|
}
|
|
|
|
int
|
|
main (int argc, char *argv[])
|
|
{
|
|
int opt;
|
|
int a_flag = false, p_flag = false, s_flag = false;
|
|
|
|
while ((opt = getopt (argc, argv, "aps")) != -1)
|
|
{
|
|
switch (opt)
|
|
{
|
|
case 'a':
|
|
a_flag = true;
|
|
break;
|
|
case 'p':
|
|
p_flag = true;
|
|
break;
|
|
case 's':
|
|
s_flag = true;
|
|
break;
|
|
default:
|
|
printf ("./bin/ls: invalid option -- \'%c\'\n", optopt);
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
char *dirname = optind < argc ? argv[optind] : ".";
|
|
struct stat dirstat;
|
|
|
|
if (stat(dirname, &dirstat) != 0) {
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
struct dirent **namelist;
|
|
int n = scandir (dirname, &namelist, NULL, filename_cmp);
|
|
|
|
for (int i = 0; i < n; i++)
|
|
{
|
|
char path[MAX_PATH_LEN];
|
|
snprintf (path, sizeof (path), "%s/%s", dirname, namelist[i]->d_name);
|
|
|
|
struct stat st;
|
|
lstat (path, &st);
|
|
|
|
bool dot_dir = strcmp (namelist[i]->d_name, ".") == 0
|
|
|| strcmp (namelist[i]->d_name, "..") == 0;
|
|
|
|
bool hidden = namelist[i]->d_name[0] == '.';
|
|
|
|
if (dot_dir || (!a_flag && hidden) || (s_flag && S_ISDIR (st.st_mode)))
|
|
{
|
|
free (namelist[i]);
|
|
continue;
|
|
}
|
|
|
|
if (s_flag)
|
|
{
|
|
printf ("%ld ", st.st_size);
|
|
}
|
|
|
|
if (p_flag)
|
|
{
|
|
print_permissions (st.st_mode);
|
|
printf (" ");
|
|
}
|
|
|
|
printf ("%s\n", namelist[i]->d_name);
|
|
|
|
free (namelist[i]);
|
|
}
|
|
free (namelist);
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
static void
|
|
usage (void)
|
|
{
|
|
printf ("ls, list directory contents\n");
|
|
printf ("usage: ls [FLAG ...] [DIR]\n");
|
|
printf ("FLAG is one or more of:\n");
|
|
printf (" -a list all files (even hidden ones)\n");
|
|
printf (" -p list permission bitmask\n");
|
|
printf (" -s list file sizes\n");
|
|
printf ("If no DIR specified, list current directory contents.\n\n");
|
|
printf ("Files must be sorted alphabetically, case insensitive.\n");
|
|
printf ("Leading dots should be ignored when sorting.\n\n");
|
|
printf ("With the -s flag, do not show entries for subdirectories.\n");
|
|
printf ("Permission bitmasks are 10-character strings such as:\n");
|
|
printf (" -rwxr-x---\n\n");
|
|
printf (
|
|
"The first character is d for directories and - for regular files.\n\n");
|
|
printf ("Do not show the \".\" or \"..\" directory entries.\n");
|
|
}
|