ls: Handle symlinks to directories properly

Also, implement the -H and -L options.
This commit is contained in:
Michael Forney 2014-12-08 01:33:52 +00:00 committed by sin
parent c4014b730e
commit 46ea55a258
2 changed files with 28 additions and 13 deletions

9
ls.1
View File

@ -3,7 +3,7 @@
ls \- list directory contents ls \- list directory contents
.SH SYNOPSIS .SH SYNOPSIS
.B ls .B ls
.RB [ \-adFiltU ] .RB [ \-adFHhiLlrtU ]
.RI [ file ...] .RI [ file ...]
.SH DESCRIPTION .SH DESCRIPTION
.B ls .B ls
@ -20,12 +20,19 @@ lists directories themselves, not their contents.
.B \-F .B \-F
append a file type indicator to files. append a file type indicator to files.
.TP .TP
.B \-H
list information about the targets of symbolic links specified on the command
line instead of the links themselves.
.TP
.B \-h .B \-h
show filesizes in human\-readable format. show filesizes in human\-readable format.
.TP .TP
.B \-i .B \-i
print the index number of each file. print the index number of each file.
.TP .TP
.B \-L
list information about the targets of symbolic links instead of the links
themselves.
.B \-l .B \-l
lists detailed information about each file, including their type, permissions, lists detailed information about each file, including their type, permissions,
links, owner, group, size, and modification time. links, owner, group, size, and modification time.

32
ls.c
View File

@ -14,7 +14,7 @@
typedef struct { typedef struct {
char *name; char *name;
mode_t mode; mode_t mode, tmode;
nlink_t nlink; nlink_t nlink;
uid_t uid; uid_t uid;
gid_t gid; gid_t gid;
@ -26,14 +26,16 @@ typedef struct {
static int entcmp(const void *, const void *); static int entcmp(const void *, const void *);
static void ls(Entry *); static void ls(Entry *);
static void lsdir(const char *); static void lsdir(const char *);
static void mkent(Entry *, char *, int); static void mkent(Entry *, char *, int, int);
static void output(Entry *); static void output(Entry *);
static int aflag = 0; static int aflag = 0;
static int dflag = 0; static int dflag = 0;
static int Fflag = 0; static int Fflag = 0;
static int Hflag = 0;
static int hflag = 0; static int hflag = 0;
static int iflag = 0; static int iflag = 0;
static int Lflag = 0;
static int lflag = 0; static int lflag = 0;
static int rflag = 0; static int rflag = 0;
static int tflag = 0; static int tflag = 0;
@ -66,12 +68,18 @@ main(int argc, char *argv[])
case 'F': case 'F':
Fflag = 1; Fflag = 1;
break; break;
case 'H':
Hflag = 1;
break;
case 'h': case 'h':
hflag = 1; hflag = 1;
break; break;
case 'i': case 'i':
iflag = 1; iflag = 1;
break; break;
case 'L':
Lflag = 1;
break;
case 'l': case 'l':
lflag = 1; lflag = 1;
break; break;
@ -95,7 +103,7 @@ main(int argc, char *argv[])
ents = emalloc(argc * sizeof(*ents)); ents = emalloc(argc * sizeof(*ents));
for (i = 0; i < argc; i++) for (i = 0; i < argc; i++)
mkent(&ents[i], argv[i], 1); mkent(&ents[i], argv[i], 1, Hflag || Lflag);
qsort(ents, argc, sizeof *ents, entcmp); qsort(ents, argc, sizeof *ents, entcmp);
for (i = 0; i < argc; i++) for (i = 0; i < argc; i++)
ls(&ents[rflag ? argc-i-1 : i]); ls(&ents[rflag ? argc-i-1 : i]);
@ -117,7 +125,7 @@ entcmp(const void *va, const void *vb)
static void static void
ls(Entry *ent) ls(Entry *ent)
{ {
if (S_ISDIR(ent->mode) && !dflag) { if ((S_ISDIR(ent->mode) || (S_ISLNK(ent->mode) && S_ISDIR(ent->tmode) && !Fflag && !lflag)) && !dflag) {
lsdir(ent->name); lsdir(ent->name);
} else { } else {
output(ent); output(ent);
@ -151,13 +159,13 @@ lsdir(const char *path)
if (d->d_name[0] == '.' && !aflag) if (d->d_name[0] == '.' && !aflag)
continue; continue;
if (Uflag){ if (Uflag){
mkent(&ent, d->d_name, Fflag || lflag || iflag); mkent(&ent, d->d_name, Fflag || lflag || iflag, Lflag);
output(&ent); output(&ent);
} else { } else {
ents = erealloc(ents, ++n * sizeof *ents); ents = erealloc(ents, ++n * sizeof *ents);
p = emalloc((sz = strlen(d->d_name)+1)); p = emalloc((sz = strlen(d->d_name)+1));
memcpy(p, d->d_name, sz); memcpy(p, d->d_name, sz);
mkent(&ents[n-1], p, tflag || Fflag || lflag || iflag); mkent(&ents[n-1], p, tflag || Fflag || lflag || iflag, Lflag);
} }
} }
closedir(dp); closedir(dp);
@ -175,15 +183,15 @@ lsdir(const char *path)
} }
static void static void
mkent(Entry *ent, char *path, int dostat) mkent(Entry *ent, char *path, int dostat, int follow)
{ {
struct stat st; struct stat st;
ent->name = path; ent->name = path;
if (!dostat) if (!dostat)
return; return;
if (lstat(path, &st) < 0) if ((follow ? stat : lstat)(path, &st) < 0)
eprintf("lstat %s:", path); eprintf("%s %s:", follow ? "stat" : "lstat", path);
ent->mode = st.st_mode; ent->mode = st.st_mode;
ent->nlink = st.st_nlink; ent->nlink = st.st_nlink;
ent->uid = st.st_uid; ent->uid = st.st_uid;
@ -191,6 +199,8 @@ mkent(Entry *ent, char *path, int dostat)
ent->size = st.st_size; ent->size = st.st_size;
ent->mtime = st.st_mtime; ent->mtime = st.st_mtime;
ent->ino = st.st_ino; ent->ino = st.st_ino;
if (S_ISLNK(ent->mode))
ent->tmode = stat(path, &st) == 0 ? st.st_mode : 0;
} }
static char * static char *
@ -225,7 +235,6 @@ output(Entry *ent)
struct passwd *pw; struct passwd *pw;
char pwname[_SC_LOGIN_NAME_MAX]; char pwname[_SC_LOGIN_NAME_MAX];
char grname[_SC_LOGIN_NAME_MAX]; char grname[_SC_LOGIN_NAME_MAX];
Entry entlnk;
if (iflag) if (iflag)
printf("%lu ", (unsigned long)ent->ino); printf("%lu ", (unsigned long)ent->ino);
@ -294,8 +303,7 @@ output(Entry *ent)
if ((len = readlink(ent->name, buf, sizeof buf)) < 0) if ((len = readlink(ent->name, buf, sizeof buf)) < 0)
eprintf("readlink %s:", ent->name); eprintf("readlink %s:", ent->name);
buf[len] = '\0'; buf[len] = '\0';
mkent(&entlnk, buf, Fflag); printf(" -> %s%s", buf, indicator(ent->tmode));
printf(" -> %s%s", buf, indicator(entlnk.mode));
} }
putchar('\n'); putchar('\n');
} }