ls: Handle symlinks to directories properly
Also, implement the -H and -L options.
This commit is contained in:
parent
c4014b730e
commit
46ea55a258
9
ls.1
9
ls.1
|
@ -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
32
ls.c
|
@ -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');
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user