OrionUserland
Barry Using POSIX names in structs 2e11092 (3 years, 1 month ago)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <dirent.h>
#include <termios.h>
#include <pwd.h>
#include <grp.h>
char *progname;
#include "arg.h"
Winsize termsz;
int allFlag = 0;
int longFlag = 0;
/* Structure for a result */
typedef struct Result Result;
struct Result {
Result *next, *prev;
ino_t ino;
enum DirType type;
size_t namelen;
char name[255];
Stat stat;
};
/* Compare results by name */
static int
compare_name(Result *a, Result *b)
{
return (strcmp(a->name, b->name) < 0);
}
/* Compare results by type */
static int
compare_type(Result *a, Result *b)
{
return (a->type == DT_DIR && b->type != DT_DIR);
}
/* Sort a list of results */
static Result *
sort_results(Result *head, int (*compare)(Result *, Result *))
{
Result *curr, *shead = NULL, *slast, *scurr;
int i, len = 0;
for (curr = head; curr; curr = curr->next)
len++;
/* Sort */
for (i = 0; i < len; i++) {
scurr = head;
for (curr = head->next; curr; curr = curr->next) {
if (compare(curr, scurr))
scurr = curr;
}
/* Unlink from old list */
if (scurr == head)
head = scurr->next;
if (scurr->next)
scurr->next->prev = scurr->prev;
if (scurr->prev)
scurr->prev->next = scurr->next;
scurr->prev = scurr->next = NULL;
/* Add to sorted list */
if (!shead) {
shead = scurr;
} else {
scurr->prev = slast;
slast->next = scurr;
}
slast = scurr;
}
return shead;
}
/* Print normal results */
static void
print_normal(Result *head)
{
Result *curr, *next, *prev;
size_t printed = 0;
for (curr = head; curr; curr = next) {
prev = curr->prev;
next = curr->next;
int executable = 0;
if ((curr->stat.st_mode & S_IXUSR)
|| (curr->stat.st_mode & S_IXGRP)
|| (curr->stat.st_mode & S_IXOTH))
executable = 1;
if (curr->type == DT_DIR)
printf("\033[1;34m%s\033[0m ", curr->name);
else if (curr->type == DT_CHR || curr->type == DT_BLK)
printf("\033[1;33m%s\033[0m ", curr->name);
else if (curr->type == DT_LNK)
printf("\033[1;36m%s\033[0m ", curr->name);
else if (curr->type == DT_REG && executable)
printf("\033[1;32m%s\033[0m ", curr->name);
else
printf("%s ", curr->name);
printed++;
/* Remove from list */
if (prev)
prev->next = next;
if (next)
next->prev = prev;
if (curr == head)
head = next;
free(curr);
}
if (printed)
putchar('\n');
}
/* Print long results */
static void
print_long(Result *head)
{
Result *curr, *next, *prev;
size_t printed = 0;
/* Find max column widths */
size_t total = 0;
int linkWidth = 0, unameWidth = 0, groupWidth = 0, sizeWidth = 0;
for (curr = head; curr; curr = curr->next) {
int linkTmp = curr->stat.st_nlink, linkWidthTmp = 1;
while (linkTmp /= 10)
linkWidthTmp++;
if (linkWidthTmp > linkWidth)
linkWidth = linkWidthTmp;
Passwd *pwd = getpwuid(curr->stat.st_uid);
if (strlen(pwd->pw_name) > unameWidth)
unameWidth = strlen(pwd->pw_name);
Group *grp = getgrgid(curr->stat.st_gid);
if (strlen(grp->gr_name) > groupWidth)
groupWidth = strlen(grp->gr_name);
int sizeTmp = curr->stat.st_size, sizeWidthTmp = 1;
while (sizeTmp /= 10)
sizeWidthTmp++;
if (sizeWidthTmp > sizeWidth)
sizeWidth = sizeWidthTmp;
total += (curr->stat.st_size + (1024 - 1)) / 1024;
}
/* Print out */
printf("total %d\n", total);
for (curr = head; curr; curr = next) {
prev = curr->prev;
next = curr->next;
char perm[] = "----------";
char type[] = "?-dcbfsl";
char uname[33], group[33];
int executable = 0;
perm[0] = type[curr->type];
perm[1] = (curr->stat.st_mode & S_IRUSR) ? 'r' : '-';
perm[2] = (curr->stat.st_mode & S_IWUSR) ? 'w' : '-';
perm[3] = (curr->stat.st_mode & S_IXUSR) ? 'x' : '-';
perm[4] = (curr->stat.st_mode & S_IRGRP) ? 'r' : '-';
perm[5] = (curr->stat.st_mode & S_IWGRP) ? 'w' : '-';
perm[6] = (curr->stat.st_mode & S_IXGRP) ? 'x' : '-';
perm[7] = (curr->stat.st_mode & S_IROTH) ? 'r' : '-';
perm[8] = (curr->stat.st_mode & S_IWOTH) ? 'w' : '-';
perm[9] = (curr->stat.st_mode & S_IXOTH) ? 'x' : '-';
Passwd *pwd = getpwuid(curr->stat.st_uid);
Group *grp = getgrgid(curr->stat.st_gid);
if ((curr->stat.st_mode & S_IXUSR)
|| (curr->stat.st_mode & S_IXGRP)
|| (curr->stat.st_mode & S_IXOTH))
executable = 1;
printf("%s %*d %*s %*s %*d ", perm,
linkWidth, curr->stat.st_nlink,
-unameWidth, pwd->pw_name,
-groupWidth, grp->gr_name,
sizeWidth, curr->stat.st_size);
if (curr->type == DT_DIR)
printf("\033[1;34m%s\033[0m\n", curr->name);
else if (curr->type == DT_CHR || curr->type == DT_BLK)
printf("\033[1;33m%s\033[0m\n", curr->name);
else if (curr->type == DT_LNK)
printf("\033[1;36m%s\033[0m\n", curr->name);
else if (curr->type == DT_REG && executable)
printf("\033[1;32m%s\033[0m\n", curr->name);
else
printf("%s\n", curr->name);
printed++;
/* Remove from list */
if (prev)
prev->next = next;
if (next)
next->prev = prev;
if (curr == head)
head = next;
free(curr);
}
}
/* List files in a directory */
static void
ls(char *name)
{
int fd, sz, i;
char *buf, cwd[1024];
struct stat statbuf;
struct dirent *de;
Result *head = NULL, *prev = NULL, *next, *curr;
size_t len = 0, longest = 0;
fd = open(name, O_RDONLY);
if (fd < 0) {
printf("%s: %s: ", progname, name);
perror(NULL);
return;
}
stat(name, &statbuf);
if (!S_ISDIR(statbuf.st_mode)) {
close(fd);
return;
}
getcwd(cwd, 1024);
chdir(name);
/* Get Directory Entries */
buf = malloc(512);
sz = getdents(fd, buf, 512);
for (de = (void *) buf;
de < (struct dirent *) (buf + sz);
de = (void *) de + de->d_namelen + sizeof(struct dirent)) {
if (de->d_name[0] == '.' && !allFlag)
continue;
curr = malloc(sizeof(Result));
curr->next = NULL;
curr->prev = prev;
curr->ino = de->d_ino;
curr->type = de->d_type;
curr->namelen = de->d_namelen;
memcpy(curr->name, de->d_name, de->d_namelen);
curr->name[de->d_namelen] = '\0';
stat(curr->name, &curr->stat);
if (prev)
prev->next = curr;
else
head = curr;
prev = curr;
len++;
if (longest < curr->namelen)
longest = curr->namelen;
}
free(buf);
close(fd);
head = sort_results(head, compare_name);
head = sort_results(head, compare_type);
if (longFlag)
print_long(head);
else
print_normal(head);
chdir(cwd);
}
/* Main function */
int
main(int argc, char *argv[])
{
int i;
ioctl(STDOUT_FILENO, TCGWINSZ, &termsz);
ARGBEGIN {
case 'a':
allFlag = 1;
break;
case 'l':
longFlag = 1;
break;
default:
printf("Usage:\n");
} ARGEND;
if (argc == 0) {
ls(".");
return 0;
}
if (argc == 1) {
ls(argv[0]);
return 0;
}
for (i = 0; i < argc; i++) {
printf("%s:\n", argv[i]);
ls(argv[i]);
if (i < argc-1)
printf("\n");
}
return 0;
}