mirror of
https://gitlab.com/sortix/sortix.git
synced 2023-02-13 20:55:38 -05:00
Add symbolic link support to ls(1).
This commit is contained in:
parent
b1a2817ada
commit
2b2dd347ec
1 changed files with 130 additions and 42 deletions
172
utils/ls.cpp
172
utils/ls.cpp
|
@ -24,10 +24,12 @@
|
|||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <error.h>
|
||||
#include <fcntl.h>
|
||||
#include <libgen.h>
|
||||
#include <locale.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
@ -111,7 +113,7 @@ int argv_mtim_compare(const void* a_void, const void* b_void)
|
|||
|
||||
struct stat a_st;
|
||||
struct stat b_st;
|
||||
if ( stat(a, &a_st) == 0 && stat(b, &b_st) == 0 )
|
||||
if ( lstat(a, &a_st) == 0 && lstat(b, &b_st) == 0 )
|
||||
{
|
||||
if ( a_st.st_mtim.tv_sec < b_st.st_mtim.tv_sec )
|
||||
return 1;
|
||||
|
@ -151,67 +153,149 @@ int sort_dirents(const void* a_void, const void* b_void)
|
|||
return strcmp(a->d_name, b->d_name);
|
||||
}
|
||||
|
||||
static unsigned char mode_to_dt(mode_t mode)
|
||||
{
|
||||
if ( S_ISBLK(mode) )
|
||||
return DT_BLK;
|
||||
if ( S_ISCHR(mode) )
|
||||
return DT_CHR;
|
||||
if ( S_ISDIR(mode) )
|
||||
return DT_DIR;
|
||||
if ( S_ISFIFO(mode) )
|
||||
return DT_FIFO;
|
||||
if ( S_ISLNK(mode) )
|
||||
return DT_LNK;
|
||||
if ( S_ISREG(mode) )
|
||||
return DT_REG;
|
||||
if ( S_ISSOCK(mode) )
|
||||
return DT_SOCK;
|
||||
return DT_UNKNOWN;
|
||||
}
|
||||
|
||||
static void color_entry(bool enable_colors,
|
||||
const char** pre_ptr,
|
||||
const char** post_ptr,
|
||||
unsigned char type,
|
||||
struct stat* st,
|
||||
bool error_situation)
|
||||
{
|
||||
const char* pre = "";
|
||||
const char* post = "";
|
||||
|
||||
if ( error_situation )
|
||||
{
|
||||
pre = "\e[31m";
|
||||
post = "\e[m";
|
||||
}
|
||||
else if ( enable_colors )
|
||||
{
|
||||
post = "\e[m";
|
||||
switch ( type )
|
||||
{
|
||||
case DT_UNKNOWN: pre = "\e[91m"; break;
|
||||
case DT_BLK: pre = "\e[93m"; break;
|
||||
case DT_CHR: pre = "\e[93m"; break;
|
||||
case DT_DIR: pre = "\e[36m"; break;
|
||||
case DT_FIFO: pre = "\e[33m"; break;
|
||||
case DT_LNK: pre = "\e[96m"; break;
|
||||
case DT_SOCK: pre = "\e[35m"; break;
|
||||
case DT_REG:
|
||||
if ( st && (st->st_mode & 0111) )
|
||||
pre = "\e[32m";
|
||||
else
|
||||
post = "";
|
||||
break;
|
||||
default:
|
||||
post = "";
|
||||
}
|
||||
}
|
||||
|
||||
*pre_ptr = pre;
|
||||
*post_ptr = post;
|
||||
}
|
||||
|
||||
int handle_entry_internal(const char* fullpath, const char* name, unsigned char type)
|
||||
{
|
||||
// TODO: Use openat and fstat.
|
||||
|
||||
struct stat st;
|
||||
memset(&st, 0, sizeof(st));
|
||||
bool stat_error = false;
|
||||
if ( (option_long_format || type == DT_UNKNOWN || type == DT_REG) )
|
||||
if ( option_long_format ||
|
||||
type == DT_UNKNOWN ||
|
||||
type == DT_REG ||
|
||||
type == DT_LNK )
|
||||
{
|
||||
if ( stat(fullpath, &st) == 0 )
|
||||
if ( lstat(fullpath, &st) == 0 )
|
||||
type = mode_to_dt(st.st_mode);
|
||||
else
|
||||
stat_error = true;
|
||||
}
|
||||
|
||||
char* link_dest = NULL;
|
||||
bool link_stat_error = false;
|
||||
struct stat link_st;
|
||||
memset(&link_st, 0, sizeof(link_st));
|
||||
unsigned char link_type = DT_UNKNOWN;
|
||||
if ( type == DT_LNK )
|
||||
{
|
||||
size_t link_dest_length = 0 <= st.st_size ? st.st_size : 256;
|
||||
link_dest = (char*) malloc(link_dest_length + 1);
|
||||
assert(link_dest);
|
||||
ssize_t readlink_ret = readlink(fullpath, link_dest, link_dest_length);
|
||||
if ( readlink_ret <= 0 )
|
||||
{
|
||||
if ( S_ISBLK(st.st_mode) )
|
||||
type = DT_BLK;
|
||||
if ( S_ISCHR(st.st_mode) )
|
||||
type = DT_CHR;
|
||||
if ( S_ISDIR(st.st_mode) )
|
||||
type = DT_DIR;
|
||||
if ( S_ISFIFO(st.st_mode) )
|
||||
type = DT_FIFO;
|
||||
if ( S_ISLNK(st.st_mode) )
|
||||
type = DT_LNK;
|
||||
if ( S_ISREG(st.st_mode) )
|
||||
type = DT_REG;
|
||||
if ( S_ISSOCK(st.st_mode) )
|
||||
type = DT_SOCK;
|
||||
free(link_dest);
|
||||
link_dest = NULL;
|
||||
link_stat_error = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(&st, 0, sizeof(st));
|
||||
stat_error = true;
|
||||
link_dest[readlink_ret] = '\0';
|
||||
const char* next_link_dest = link_dest;
|
||||
char* new_link_dest = NULL;
|
||||
if ( link_dest[0] != '/' )
|
||||
{
|
||||
char* fullpath_dir_raw = strdup(fullpath);
|
||||
const char* fullpath_dir = dirname(fullpath_dir_raw);
|
||||
asprintf(&new_link_dest, "%s/%s", fullpath_dir, link_dest);
|
||||
assert(new_link_dest);
|
||||
free(fullpath_dir_raw);
|
||||
next_link_dest = new_link_dest;
|
||||
}
|
||||
if ( lstat(next_link_dest, &link_st) == 0 )
|
||||
link_type = mode_to_dt(link_st.st_mode);
|
||||
else
|
||||
link_stat_error = true;
|
||||
free(new_link_dest);
|
||||
}
|
||||
}
|
||||
|
||||
const char* color_pre = "";
|
||||
const char* color_post = "";
|
||||
if ( option_colors )
|
||||
{
|
||||
color_post = "\e[m";
|
||||
switch ( type )
|
||||
{
|
||||
case DT_UNKNOWN: color_pre = "\e[91m"; break;
|
||||
case DT_BLK: color_pre = "\e[93m"; break;
|
||||
case DT_CHR: color_pre = "\e[93m"; break;
|
||||
case DT_DIR: color_pre = "\e[36m"; break;
|
||||
case DT_FIFO: color_pre = "\e[33m"; break;
|
||||
case DT_LNK: color_pre = "\e[96m"; break;
|
||||
case DT_SOCK: color_pre = "\e[35m"; break;
|
||||
case DT_REG:
|
||||
if ( type == DT_REG && !stat_error && (st.st_mode & 0111) )
|
||||
color_pre = "\e[32m";
|
||||
else
|
||||
color_post = "";
|
||||
break;
|
||||
default:
|
||||
color_post = "";
|
||||
}
|
||||
}
|
||||
color_entry(option_colors,
|
||||
&color_pre,
|
||||
&color_post,
|
||||
type,
|
||||
!stat_error ? &st : NULL,
|
||||
link_stat_error);
|
||||
|
||||
const char* link_color_pre = "";
|
||||
const char* link_color_post = "";
|
||||
if ( type == DT_LNK )
|
||||
color_entry(option_colors,
|
||||
&link_color_pre,
|
||||
&link_color_post,
|
||||
link_type,
|
||||
!link_stat_error ? &link_st : NULL,
|
||||
link_stat_error);
|
||||
|
||||
if ( option_inode )
|
||||
printf("%ju ", (uintmax_t) st.st_ino);
|
||||
if ( !option_long_format )
|
||||
{
|
||||
printf("%s%s%s\n", color_pre, name, color_post);
|
||||
free(link_dest);
|
||||
return 0;
|
||||
}
|
||||
char perms[11];
|
||||
|
@ -249,12 +333,16 @@ int handle_entry_internal(const char* fullpath, const char* name, unsigned char
|
|||
strftime(time_str, 64, "%b %e %H:%M", &mod_tm);
|
||||
else
|
||||
strftime(time_str, 64, "%b %e %Y", &mod_tm);
|
||||
printf("%s %3ju root root %4ju%s %s %s%s%s\n",
|
||||
printf("%s %3ju root root %4ju%s %s %s%s%s",
|
||||
perms,
|
||||
(uintmax_t) st.st_nlink,
|
||||
(uintmax_t) size, sizeunit,
|
||||
time_str,
|
||||
color_pre, name, color_post);
|
||||
if ( type == DT_LNK && link_dest )
|
||||
printf(" -> %s%s%s", link_color_pre, link_dest, link_color_post);
|
||||
printf("\n");
|
||||
free(link_dest);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue