fix ls segfault
This commit is contained in:
parent
f6e64afaee
commit
889b35ebd1
5 changed files with 95 additions and 74 deletions
1
Makefile
1
Makefile
|
@ -12,7 +12,6 @@ CCFLAGS = -std=c99 -Wall -Wextra -pedantic -O2
|
||||||
CCFLAGS += -D_DEFAULT_SOURCE -DMAJOR=$(MAJOR) -DMINOR=$(MINOR) -DPATCH=$(PATCH) -DCHECK_LINK
|
CCFLAGS += -D_DEFAULT_SOURCE -DMAJOR=$(MAJOR) -DMINOR=$(MINOR) -DPATCH=$(PATCH) -DCHECK_LINK
|
||||||
CCFLAGS += $(INCFLAGS)
|
CCFLAGS += $(INCFLAGS)
|
||||||
|
|
||||||
LDFLAGS = -s
|
|
||||||
LDFLAGS += $(INCFLAGS)
|
LDFLAGS += $(INCFLAGS)
|
||||||
|
|
||||||
BIN = bin
|
BIN = bin
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <ftw.h>
|
#include <ftw.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#define FILE_COLOR ANSCII BLACK COLOR
|
#define FILE_COLOR ANSCII BLACK COLOR
|
||||||
#define DIR_COLOR ANSCII BOLD NEXT NORMAL BLUE COLOR
|
#define DIR_COLOR ANSCII BOLD NEXT NORMAL BLUE COLOR
|
||||||
|
@ -28,7 +29,7 @@ static struct {
|
||||||
struct FileInfo {
|
struct FileInfo {
|
||||||
struct passwd* usr;
|
struct passwd* usr;
|
||||||
struct group* grp;
|
struct group* grp;
|
||||||
char name[PATH_MAX];
|
char* name;
|
||||||
char date[13];
|
char date[13];
|
||||||
char mode[11];
|
char mode[11];
|
||||||
char size[5];
|
char size[5];
|
||||||
|
@ -62,41 +63,27 @@ static DIR* get_directory(char* path) {
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void append_path(char buf[PATH_MAX], const char* dir_path, const char* file_path) {
|
static bool get_file_info(const char* file_name, struct FileInfo* info) {
|
||||||
size_t dir_len = strlen(dir_path);
|
|
||||||
size_t file_len = strlen(file_path);
|
|
||||||
|
|
||||||
memcpy(buf, dir_path, dir_len);
|
|
||||||
if (buf[dir_len-1] != '/') {
|
|
||||||
buf[dir_len] = '/';
|
|
||||||
dir_len++;
|
|
||||||
}
|
|
||||||
memcpy(buf + dir_len, file_path, file_len);
|
|
||||||
buf[dir_len + file_len] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool get_file_info(const char* file_path, const char* dir_path, struct FileInfo* info) {
|
|
||||||
|
|
||||||
uid_t uid = getuid();
|
uid_t uid = getuid();
|
||||||
gid_t gid = getgid();
|
gid_t gid = getgid();
|
||||||
|
|
||||||
char buf[PATH_MAX];
|
|
||||||
append_path(buf, dir_path, file_path);
|
|
||||||
|
|
||||||
struct stat s;
|
struct stat s;
|
||||||
memset(&s, 0, sizeof(struct stat));
|
memset(&s, 0, sizeof(struct stat));
|
||||||
|
|
||||||
if (lstat(buf, &s) < 0) {
|
int save = push_path_buffer(file_name);
|
||||||
printf("\x1b[0merror: failed to read file '%s': %s\n", buf, strerror(errno));
|
|
||||||
|
if (lstat(get_path_buffer(), &s) < 0) {
|
||||||
|
printf("\x1b[0merror: failed to read file '%s': %s\n", get_path_buffer(), strerror(errno));
|
||||||
|
pop_path_buffer(save);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ty = (s.st_mode & S_IFMT) >> 12;
|
int ty = (s.st_mode & S_IFMT) >> 12;
|
||||||
|
|
||||||
info->set_uid = false;
|
info->set_uid = false;
|
||||||
info->set_gid = false;
|
info->set_gid = false;
|
||||||
info->exec = false;
|
info->exec = false;
|
||||||
info->name[0] = '\0';
|
|
||||||
|
|
||||||
switch (ty) {
|
switch (ty) {
|
||||||
case DT_BLK:
|
case DT_BLK:
|
||||||
|
@ -168,17 +155,32 @@ static bool get_file_info(const char* file_path, const char* dir_path, struct Fi
|
||||||
info->mode[10] = '\0';
|
info->mode[10] = '\0';
|
||||||
|
|
||||||
info->usr = getpwuid(s.st_uid);
|
info->usr = getpwuid(s.st_uid);
|
||||||
|
if (info->usr == NULL) {
|
||||||
|
fprintf(stderr, "error: failed to get user from %s\n", get_path_buffer());
|
||||||
|
pop_path_buffer(save);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
info->grp = getgrgid(s.st_gid);
|
info->grp = getgrgid(s.st_gid);
|
||||||
|
if (info->grp == NULL) {
|
||||||
|
fprintf(stderr, "error: failed to get user from %s\n", get_path_buffer());
|
||||||
|
pop_path_buffer(save);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
info->links = s.st_nlink;
|
info->links = s.st_nlink;
|
||||||
info->type = ty;
|
info->type = ty;
|
||||||
|
|
||||||
strcpy(info->name, file_path);
|
size_t file_len = strlen(file_name) + 1;
|
||||||
|
info->name = malloc(file_len);
|
||||||
|
memcpy(info->name, file_name, file_len);
|
||||||
|
|
||||||
print_file_size(s.st_size, info->size);
|
print_file_size(s.st_size, info->size);
|
||||||
print_date_time(s.st_mtim.tv_sec + s.st_mtim.tv_nsec / 1000000000, info->date);
|
print_date_time(s.st_mtim.tv_sec + s.st_mtim.tv_nsec / 1000000000, info->date);
|
||||||
|
|
||||||
info->bytes = (s.st_size + s.st_blksize - 1) / s.st_blksize * s.st_blksize;
|
info->bytes = (s.st_size + s.st_blksize - 1) / s.st_blksize;
|
||||||
|
|
||||||
|
pop_path_buffer(save);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,7 +215,7 @@ static char* get_file_color(struct FileInfo* info) {
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void list_files(struct FileInfo* files, int file_len, struct FileListInfo info, const char* dir_path) {
|
static void list_files(struct FileInfo* files, int file_len, struct FileListInfo info) {
|
||||||
|
|
||||||
if (flags.more_info) {
|
if (flags.more_info) {
|
||||||
char total[13];
|
char total[13];
|
||||||
|
@ -254,17 +256,17 @@ static void list_files(struct FileInfo* files, int file_len, struct FileListInfo
|
||||||
flags.colored != NO ? "\x1b[0m" : ""
|
flags.colored != NO ? "\x1b[0m" : ""
|
||||||
);
|
);
|
||||||
if (finfo.type == DT_LNK) {
|
if (finfo.type == DT_LNK) {
|
||||||
char path[PATH_MAX];
|
int save = push_path_buffer(finfo.name);
|
||||||
append_path(path, dir_path, finfo.name);
|
|
||||||
|
|
||||||
char lnk[PATH_MAX];
|
char lnk[PATH_MAX];
|
||||||
ssize_t n;
|
ssize_t n;
|
||||||
if ((n = readlink(path, lnk, PATH_MAX)) != -1) {
|
if ((n = readlink(get_path_buffer(), lnk, PATH_MAX)) != -1) {
|
||||||
printf(" -> %.*s\n", (int)n, lnk);
|
printf(" -> %.*s\n", (int)n, lnk);
|
||||||
} else {
|
} else {
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pop_path_buffer(save);
|
||||||
} else {
|
} else {
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
}
|
}
|
||||||
|
@ -280,6 +282,7 @@ static void list_files(struct FileInfo* files, int file_len, struct FileListInfo
|
||||||
flags.colored != NO ? "\x1b[0m" : "");
|
flags.colored != NO ? "\x1b[0m" : "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
free(finfo.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!flags.more_info) printf("\n");
|
if (!flags.more_info) printf("\n");
|
||||||
|
@ -303,12 +306,10 @@ static void push_file(
|
||||||
struct FileInfo** files,
|
struct FileInfo** files,
|
||||||
struct FileListInfo* info,
|
struct FileListInfo* info,
|
||||||
int* size, int* capacity,
|
int* size, int* capacity,
|
||||||
const char* file_path,
|
const char* file_path
|
||||||
const char* dir_path
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
struct FileInfo finfo;
|
struct FileInfo finfo;
|
||||||
if (!get_file_info(file_path, dir_path, &finfo)) return;
|
if (!get_file_info(file_path, &finfo)) return;
|
||||||
|
|
||||||
if (*size == *capacity) {
|
if (*size == *capacity) {
|
||||||
*capacity *= 2;
|
*capacity *= 2;
|
||||||
|
@ -336,13 +337,15 @@ static void push_file(
|
||||||
(*size)++;
|
(*size)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool recurse_directory(char* path) {
|
static void recurse_directory(char* dir_name) {
|
||||||
DIR* d;
|
DIR* d;
|
||||||
struct dirent* file;
|
struct dirent* file;
|
||||||
bool first = true;
|
int save = push_path_buffer(dir_name);
|
||||||
|
|
||||||
d = get_directory(path);
|
d = get_directory(get_path_buffer());
|
||||||
if (d == NULL) return false;
|
if (d == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int capacity = 8;
|
int capacity = 8;
|
||||||
int size = 0;
|
int size = 0;
|
||||||
|
@ -351,50 +354,42 @@ static bool recurse_directory(char* path) {
|
||||||
memset(&info, 0, sizeof(struct FileListInfo));
|
memset(&info, 0, sizeof(struct FileListInfo));
|
||||||
|
|
||||||
while((file = readdir(d)) != NULL) {
|
while((file = readdir(d)) != NULL) {
|
||||||
if (file->d_type == DT_DIR && !is_dot_dir(file->d_name)) continue;
|
|
||||||
if (!flags.hidden && prefix(".", file->d_name)) continue;
|
if (!flags.hidden && prefix(".", file->d_name)) continue;
|
||||||
if (flags.hide_dot && is_dot_dir(file->d_name)) continue;
|
if (flags.hide_dot && is_dot_dir(file->d_name)) continue;
|
||||||
if (first) {
|
if (file->d_type == DT_DIR && !is_dot_dir(file->d_name)) {
|
||||||
if (flags.colored == NO)
|
recurse_directory(file->d_name);
|
||||||
printf("\n%s:\n", path);
|
} else {
|
||||||
else
|
push_file(&files, &info, &size, &capacity, file->d_name);
|
||||||
printf("\n%s%s:%s\n", DIR_COLOR, path, FILE_COLOR);
|
|
||||||
first = false;
|
|
||||||
}
|
}
|
||||||
push_file(&files, &info, &size, &capacity, file->d_name, path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
list_files(files, size, info, path);
|
|
||||||
|
if (flags.colored == NO)
|
||||||
|
printf("\n%s:\n", get_path_buffer());
|
||||||
|
else
|
||||||
|
printf("\n%s%s:%s\n", DIR_COLOR, get_path_buffer(), FILE_COLOR);
|
||||||
|
|
||||||
|
list_files(files, size, info);
|
||||||
|
|
||||||
free(files);
|
free(files);
|
||||||
|
|
||||||
if (!flags.more_info) printf("\n");
|
if (!flags.more_info) printf("\n");
|
||||||
|
|
||||||
closedir(d);
|
closedir(d);
|
||||||
|
|
||||||
d = get_directory(path);
|
pop_path_buffer(save);
|
||||||
if (d == NULL) return false;
|
|
||||||
|
|
||||||
while((file = readdir(d)) != NULL) {
|
|
||||||
if (file->d_type != DT_DIR) continue;
|
|
||||||
if (!flags.hidden && prefix(".", file->d_name)) continue;
|
|
||||||
if (is_dot_dir(file->d_name)) continue;
|
|
||||||
char buf[PATH_MAX];
|
|
||||||
append_path(buf, path, file->d_name);
|
|
||||||
recurse_directory(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
closedir(d);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool list_directory(char* path) {
|
static void list_directory(char* path) {
|
||||||
if (flags.recurse) {
|
if (flags.recurse) {
|
||||||
return recurse_directory(path);
|
recurse_directory(path);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DIR* d = get_directory(path);
|
DIR* d = get_directory(path);
|
||||||
if (d == NULL) return false;
|
if (d == NULL) return;
|
||||||
|
|
||||||
|
int save = push_path_buffer(path);
|
||||||
|
|
||||||
int capacity = 8;
|
int capacity = 8;
|
||||||
int size = 0;
|
int size = 0;
|
||||||
|
@ -406,14 +401,15 @@ static bool list_directory(char* path) {
|
||||||
while ((file = readdir(d)) != NULL) {
|
while ((file = readdir(d)) != NULL) {
|
||||||
if (!flags.hidden && prefix(".", file->d_name)) continue;
|
if (!flags.hidden && prefix(".", file->d_name)) continue;
|
||||||
if (flags.hide_dot && is_dot_dir(file->d_name)) continue;
|
if (flags.hide_dot && is_dot_dir(file->d_name)) continue;
|
||||||
push_file(&files, &info, &size, &capacity, file->d_name, path);
|
push_file(&files, &info, &size, &capacity, file->d_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size > 0) list_files(files, size, info, path);
|
if (size > 0) list_files(files, size, info);
|
||||||
free(files);
|
free(files);
|
||||||
|
|
||||||
|
pop_path_buffer(save);
|
||||||
|
|
||||||
closedir(d);
|
closedir(d);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_dir(const char* path) {
|
static bool is_dir(const char* path) {
|
||||||
|
@ -431,10 +427,10 @@ static void list_file_args(int start, int argc, char** argv) {
|
||||||
|
|
||||||
for (int i = start; i < argc; i++) {
|
for (int i = start; i < argc; i++) {
|
||||||
if (is_dir(argv[i])) continue;
|
if (is_dir(argv[i])) continue;
|
||||||
push_file((struct FileInfo**) &files, &info, &size, &capacity, argv[i], argv[i][0] == '/' ? "" : ".");
|
push_file((struct FileInfo**) &files, &info, &size, &capacity, argv[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size > 0) list_files(files, size, info, ".");
|
if (size > 0) list_files(files, size, info);
|
||||||
|
|
||||||
free(files);
|
free(files);
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,8 +75,6 @@ static void handle_slash(char n) {
|
||||||
case 'f':
|
case 'f':
|
||||||
putchar('\f');
|
putchar('\f');
|
||||||
break;
|
break;
|
||||||
case 'e':
|
|
||||||
putchar('\e');
|
|
||||||
case 'a':
|
case 'a':
|
||||||
putchar('\a');
|
putchar('\a');
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "shared.h"
|
#include "shared.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -232,3 +233,25 @@ FILE* get_tty_stream(char* type) {
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char path_buffer[PATH_MAX + 1];
|
||||||
|
static int path_buffer_index = 0;
|
||||||
|
|
||||||
|
char* get_path_buffer() {
|
||||||
|
return path_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
int push_path_buffer(const char* string) {
|
||||||
|
int save = path_buffer_index;
|
||||||
|
if (path_buffer_index > 1 || (path_buffer_index == 1 && path_buffer[0] != '/')) {
|
||||||
|
path_buffer[path_buffer_index++] = '/';
|
||||||
|
}
|
||||||
|
int string_len = strlen(string);
|
||||||
|
memcpy(path_buffer + path_buffer_index, string, string_len + 1);
|
||||||
|
path_buffer_index += string_len;
|
||||||
|
return save;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_path_buffer(int i) {
|
||||||
|
path_buffer_index = i;
|
||||||
|
path_buffer[path_buffer_index] = '\0';
|
||||||
|
}
|
||||||
|
|
|
@ -57,3 +57,8 @@ int parse_args (int argc, char** argv, void (*help)(void), int (*short_arg)(char
|
||||||
|
|
||||||
int get_tty();
|
int get_tty();
|
||||||
FILE* get_tty_stream(char* type);
|
FILE* get_tty_stream(char* type);
|
||||||
|
|
||||||
|
char* get_path_buffer();
|
||||||
|
int push_path_buffer(const char* string);
|
||||||
|
void pop_path_buffer(int i);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue