-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
747d814
commit 4583fa7
Showing
9 changed files
with
447 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,9 @@ | ||
OUT := ls | ||
|
||
SRC := ls.c | ||
SRC := main.c | ||
SRC += list_directories.c | ||
SRC += print_info.c | ||
SRC += recursive_walk.c | ||
SRC += sort_entries.c | ||
|
||
include ../shared.mk |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
#include <dirent.h> | ||
#include <errno.h> | ||
#include <grp.h> | ||
#include <pwd.h> | ||
#include <stddef.h> | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <sys/stat.h> | ||
#include <sys/types.h> | ||
#include <unistd.h> | ||
|
||
#include "my_ls.h" | ||
|
||
static | ||
void get_file_info(const char *path, entry_t *entry) | ||
{ | ||
if (stat(path, &entry->stat) < 0) | ||
return; | ||
entry->passwd = getpwuid(entry->stat.st_uid); | ||
entry->group = getgrgid(entry->stat.st_gid); | ||
} | ||
|
||
static | ||
int read_directory(dirbuff_t *db, DIR *dir, char flags) | ||
{ | ||
static char path[PATH_MAX]; | ||
int i = 0; | ||
|
||
if (dir == NULL) | ||
return -1; | ||
for (struct dirent *dirent = readdir(dir); dirent; dirent = readdir(dir)) { | ||
if (dirent->d_name[0] == '.' && ~flags & F_ALL_FILES) | ||
continue; | ||
if (i == db->size) { | ||
db->size <<= 1; | ||
db->entries = realloc( | ||
db->entries, db->size * sizeof(*db->entries)); | ||
} | ||
strcpy(db->entries[i].name, dirent->d_name); | ||
if (flags & (F_LONG_FORM | F_SORT_TIME | F_RECURSIVE)) | ||
get_file_info(path_concat(path, db->name, db->entries[i].name), | ||
&db->entries[i]); | ||
i++; | ||
} | ||
return i; | ||
} | ||
|
||
static | ||
void print_error(char *dirname) | ||
{ | ||
switch (errno) { | ||
case ENOENT: | ||
fprintf(stderr, | ||
"ls: cannot access '%s': No such file or directory\n", | ||
dirname); | ||
return; | ||
case EACCES: | ||
fprintf(stderr, | ||
"ls: cannot open directory '%s': Permission denied\n", | ||
dirname); | ||
return; | ||
default: | ||
fprintf(stderr, "Unknown error\n"); | ||
} | ||
} | ||
|
||
static | ||
int read_arg(dirbuff_t *db, char flags) | ||
{ | ||
struct stat fi; | ||
int count = 1; | ||
DIR *dir; | ||
|
||
db->is_file = 0; | ||
if (stat(db->name, &fi) < 0) { | ||
print_error(db->name); | ||
return -1; | ||
} | ||
if (S_ISDIR(fi.st_mode) && ~flags & F_DIRECTORY) { | ||
dir = opendir(db->name); | ||
count = read_directory(db, dir, flags); | ||
closedir(dir); | ||
} else { | ||
strcpy(db->entries[0].name, db->name); | ||
get_file_info(db->name, &db->entries[0]); | ||
db->is_file = 1; | ||
} | ||
return count; | ||
} | ||
|
||
int list_dir(dirbuff_t *db, char flags) | ||
{ | ||
int count = read_arg(db, flags); | ||
|
||
if (count == -1) | ||
return -1; | ||
sort_entries(db->entries, count); | ||
if (flags & F_SORT_TIME) | ||
sort_entries_by_time(db->entries, count); | ||
if (flags & (F_SHOW_DIRS | F_RECURSIVE) && !db->is_file) | ||
printf("%s:\n", db->name); | ||
print_entries(db->entries, count, flags); | ||
if (flags & F_RECURSIVE && !db->is_file) | ||
recurse(db, count, flags); | ||
return 0; | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
#ifndef MY_LS_H | ||
#define MY_LS_H | ||
|
||
#include <stddef.h> | ||
|
||
#define ZERO_OR(expr, default) ((!!(expr)) * default) | ||
|
||
#define __USE_XOPEN2K8 | ||
#define __USE_MISC | ||
|
||
#include <linux/limits.h> | ||
#include <sys/stat.h> | ||
|
||
#define MIN_ALLOCATED_ENTRY (1024) | ||
|
||
enum { | ||
EXIT_OK = 0, | ||
EXIT_KO = 84 | ||
}; | ||
|
||
enum { | ||
F_ALL_FILES = 1 << 0, | ||
F_LONG_FORM = 1 << 1, | ||
F_RECURSIVE = 1 << 2, | ||
F_DIRECTORY = 1 << 3, | ||
F_REV_ORDER = 1 << 4, | ||
F_SORT_TIME = 1 << 5, | ||
F_SHOW_DIRS = 1 << 6, | ||
}; | ||
|
||
typedef struct { | ||
struct stat stat; | ||
struct passwd *passwd; | ||
struct group *group; | ||
char name[NAME_MAX + 1]; | ||
} entry_t; | ||
|
||
typedef struct { | ||
char *name; | ||
entry_t *entries; | ||
int size; | ||
int is_file; | ||
} dirbuff_t; | ||
|
||
inline | ||
int stridx(const char *str, char c) | ||
{ | ||
for (const char *p = str; *p != '\0'; p++) | ||
if (*p == c) | ||
return p - str; | ||
return -1; | ||
} | ||
|
||
char *strdup(char const *s); | ||
|
||
int list_dir(dirbuff_t *db, char flags); | ||
int recurse(dirbuff_t *db, int count, char flags); | ||
|
||
void print_entries(entry_t *entry, int count, char flags); | ||
char *path_concat(char *dest, char *basepath, char *suffix); | ||
|
||
void sort_entries(entry_t *entries, int count); | ||
void sort_entries_by_time(entry_t *entries, int count); | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
#include <stdlib.h> | ||
|
||
#include "ls.h" | ||
|
||
static const char *FLAGLIST = "alRdrt"; | ||
static char DEFAULT_LOCATION[2] = "."; | ||
|
||
static | ||
char compose_flaglist(int argc, char **argv) | ||
{ | ||
int flags = 0; | ||
|
||
for (int i = 1; i < argc; i++) { | ||
if (argv[i][0] != '-' || argv[i][1] == '\0') | ||
continue; | ||
for (int j = 1; argv[i][j] != '\0'; j++) | ||
flags |= 1 << (stridx(FLAGLIST, argv[i][j]) + 1); | ||
} | ||
return (char)(flags >> 1); | ||
} | ||
|
||
static | ||
int count_targets(int argc, char **argv) | ||
{ | ||
int count = 0; | ||
|
||
for (int i = 1; i < argc; i++) | ||
if (argv[i][0] != '-' || argv[i][1] == '\0') | ||
count++; | ||
return count; | ||
} | ||
|
||
static | ||
int list_dirs(dirbuff_t *db, int argc, char **argv, char flags) | ||
{ | ||
int err = 0; | ||
int count = count_targets(argc, argv); | ||
|
||
if (count == 0) { | ||
db->name = DEFAULT_LOCATION; | ||
err |= list_dir(db, flags); | ||
} | ||
for (int i = 1; i < argc; i++) { | ||
if (argv[i][0] == '-' && argv[i][1] != '\0') | ||
continue; | ||
db->name = argv[i]; | ||
if (count > 1) | ||
flags |= F_SHOW_DIRS; | ||
err |= list_dir(db, flags); | ||
} | ||
return err; | ||
} | ||
|
||
int main(int argc, char **argv) | ||
{ | ||
dirbuff_t db = { .size = MIN_ALLOCATED_ENTRY }; | ||
char flags = compose_flaglist(argc, argv); | ||
int err = 0; | ||
|
||
db.entries = malloc(db.size * sizeof(*db.entries)); | ||
if (db.entries == NULL) | ||
return EXIT_KO; | ||
if (flags & F_DIRECTORY) | ||
flags &= ~F_RECURSIVE; | ||
err |= list_dirs(&db, argc, argv, flags); | ||
free(db.entries); | ||
return err ? EXIT_KO : EXIT_OK; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
#include <dirent.h> | ||
#include <grp.h> | ||
#include <pwd.h> | ||
#include <stddef.h> | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
|
||
#include <sys/sysmacros.h> | ||
#include <sys/types.h> | ||
#include <time.h> | ||
|
||
#include "ls.h" | ||
|
||
static | ||
void get_file_right(char bits[], entry_t *entry) | ||
{ | ||
mode_t mode = entry->stat.st_mode; | ||
static const char *s = "-rwx"; | ||
|
||
bits[0] = s[(unsigned char)ZERO_OR(mode & S_IRUSR, 1)]; | ||
bits[1] = s[(unsigned char)ZERO_OR(mode & S_IWUSR, 2)]; | ||
bits[2] = s[(unsigned char)ZERO_OR(mode & S_IXUSR, 3)]; | ||
bits[3] = s[(unsigned char)ZERO_OR(mode & S_IRGRP, 1)]; | ||
bits[4] = s[(unsigned char)ZERO_OR(mode & S_IWGRP, 2)]; | ||
bits[5] = s[(unsigned char)ZERO_OR(mode & S_IXGRP, 3)]; | ||
bits[6] = s[(unsigned char)ZERO_OR(mode & S_IROTH, 1)]; | ||
bits[7] = s[(unsigned char)ZERO_OR(mode & S_IWOTH, 2)]; | ||
bits[8] = s[(unsigned char)ZERO_OR(mode & S_IXOTH, 3)]; | ||
if (mode & S_ISUID) | ||
bits[1] = (mode & S_IXUSR) ? 's' : 'S'; | ||
if (mode & S_ISGID) | ||
bits[3] = (mode & S_IXGRP) ? 's' : 'l'; | ||
if (mode & S_ISVTX) | ||
bits[8] = (mode & S_IXOTH) ? 't' : 'T'; | ||
} | ||
|
||
static | ||
char get_file_type(entry_t *entry) | ||
{ | ||
const char typ[] = { | ||
[ S_IFBLK ] = 'b', | ||
[ S_IFCHR ] = 'c', | ||
[ S_IFDIR ] = 'd', | ||
[ S_IFIFO ] = 'p', | ||
[ S_IFLNK ] = 'l', | ||
[ S_IFREG ] = '-', | ||
[ S_IFSOCK ] = 's', | ||
[ 0 ] = '?' | ||
}; | ||
|
||
return typ[(entry->stat.st_mode & S_IFMT)]; | ||
} | ||
|
||
static | ||
char *get_creation_time(entry_t *entry) | ||
{ | ||
static char fmt[12]; | ||
char *ct = ctime(&entry->stat.st_mtim.tv_sec); | ||
time_t now = time(NULL); | ||
const int six_month_sec = 6 * 24 * 3600 * 31; | ||
|
||
if (entry->stat.st_mtim.tv_sec + six_month_sec < now) { | ||
strncpy(fmt, ct + 4, 7); | ||
strncpy(fmt + 7, ct + 19, 5); | ||
} else | ||
strncpy(fmt, ct + 4, 12); | ||
return fmt; | ||
} | ||
|
||
static | ||
void print_file_infos(entry_t *entry) | ||
{ | ||
struct stat *fi = &entry->stat; | ||
char perms[10] = { [0] = get_file_type(entry) }; | ||
const char *owner = (entry->passwd == NULL) ? "?" : entry->passwd->pw_name; | ||
const char *grp = (entry->group == NULL) ? "?" : entry->group->gr_name; | ||
char *time = get_creation_time(entry); | ||
|
||
get_file_right(perms + 1, entry); | ||
printf("%.10s %ld %s %s ", perms, fi->st_nlink, owner, grp); | ||
if (stridx("bc", perms[0]) != -1) | ||
printf("%d, %d", major(fi->st_rdev), minor(fi->st_rdev)); | ||
else | ||
printf("%ld", fi->st_size); | ||
printf(" %.12s ", time); | ||
} | ||
|
||
void print_entries(entry_t *entry, int count, char flags) | ||
{ | ||
int d; | ||
|
||
if (flags & F_REV_ORDER) { | ||
d = -1; | ||
entry += (count - 1); | ||
} else | ||
d = 1; | ||
for (int i = 0; i < count; i++) { | ||
if (flags & F_LONG_FORM) | ||
print_file_infos(entry); | ||
printf("%s", entry->name); | ||
printf(((i + 1) == count || flags & F_LONG_FORM) ? "\n" : " "); | ||
entry += d; | ||
} | ||
} |
Oops, something went wrong.