#include <sys/stat.h>
#ifdef __APPLE__
#include <sys/acl.h>
+#include <sys/xattr.h>
#include <sys/types.h>
#include <grp.h>
#include <pwd.h>
+#include <TargetConditionals.h>
#include <membership.h>
#include <membershipPriv.h>
#include <uuid/uuid.h>
#include <fts.h>
#include <math.h>
#include <langinfo.h>
+#include <libutil.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termcap.h>
#include <signal.h>
#endif
+#include <stdint.h> /* intmax_t */
+#include <assert.h>
+#ifdef __APPLE__
+#include <get_compat.h>
+#else
+#define COMPAT_MODE(a,b) (1)
+#endif /* __APPLE__ */
#include "ls.h"
#include "extern.h"
#define IS_NOPRINT(p) ((p)->fts_number == NO_PRINT)
-#define KILO_SZ(n) (n)
-#define MEGA_SZ(n) ((n) * (n))
-#define GIGA_SZ(n) ((n) * (n) * (n))
-#define TERA_SZ(n) ((n) * (n) * (n) * (n))
-#define PETA_SZ(n) ((n) * (n) * (n) * (n) * (n))
-
-#define KILO_2_SZ (KILO_SZ(1024ULL))
-#define MEGA_2_SZ (MEGA_SZ(1024ULL))
-#define GIGA_2_SZ (GIGA_SZ(1024ULL))
-#define TERA_2_SZ (TERA_SZ(1024ULL))
-#define PETA_2_SZ (PETA_SZ(1024ULL))
-
-static u_int64_t vals_base2[] = {1, KILO_2_SZ, MEGA_2_SZ, GIGA_2_SZ, TERA_2_SZ, PETA_2_SZ};
-
-typedef enum {
- NONE, KILO, MEGA, GIGA, TERA, PETA, UNIT_MAX
-} unit_t;
-static unit_t unit_adjust(off_t *);
-
-static int unitp[] = {NONE, KILO, MEGA, GIGA, TERA, PETA};
-
#ifdef COLORLS
/* Most of these are taken from <sys/stat.h> */
typedef enum Colors {
{
FTSENT *p;
+ assert(dp);
+ if (COMPAT_MODE("bin/ls", "Unix2003") && (dp->list != NULL)) {
+ if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
+ (void)printf("total %qu\n", (u_int64_t)howmany(dp->btotal, blocksize));
+ }
+
for (p = dp->list; p; p = p->fts_link) {
if (IS_NOPRINT(p))
continue;
else if (f_nonprint)
return prn_printable(name);
else
- return printf("%s", name);
+ return prn_normal(name);
}
/*
static char *
uuid_to_name(uuid_t *uu)
{
- int is_gid = -1;
- struct group *tgrp = NULL;
- struct passwd *tpass = NULL;
- char *name = NULL;
- uid_t id;
-
-
+ int type;
+ char *name = NULL;
+ char *recname = NULL;
+
#define MAXNAMETAG (MAXLOGNAME + 6) /* + strlen("group:") */
- name = (char *) malloc(MAXNAMETAG);
-
- if (NULL == name)
- err(1, "malloc");
-
- if (0 != mbr_uuid_to_id(uu, &id, &is_gid))
- goto errout;
-
- switch (is_gid) {
- case ID_TYPE_UID:
- tpass = getpwuid(id);
- if (!tpass) {
- goto errout;
- }
- snprintf(name, MAXNAMETAG, "%s:%s", "user", tpass->pw_name);
- break;
- case ID_TYPE_GID:
- tgrp = getgrgid((gid_t) id);
- if (!tgrp) {
- goto errout;
- }
- snprintf(name, MAXNAMETAG, "%s:%s", "group", tgrp->gr_name);
- break;
- default:
- if (0 != mbr_uuid_to_string(uu, name))
- goto errout;
- }
- return name;
- errout:
- fprintf(stderr, "Unable to translate qualifier on ACL\n");
- strcpy(name, "<UNKNOWN>");
- return name;
+ name = (char *) malloc(MAXNAMETAG);
+
+ if (NULL == name) {
+ err(1, "malloc");
+ }
+
+ if (f_numericonly) {
+ goto errout;
+ }
+
+ if (mbr_identifier_translate(ID_TYPE_UUID, *uu, sizeof(*uu), ID_TYPE_NAME, (void **) &recname, &type)) {
+ goto errout;
+ }
+
+ snprintf(name, MAXNAMETAG, "%s:%s", (type == MBR_REC_TYPE_USER ? "user" : "group"), recname);
+ free(recname);
+
+ return name;
+errout:
+ uuid_unparse_upper(*uu, name);
+
+ return name;
+}
+
+static void
+printxattr(DISPLAY *dp, int count, char *buf, int sizes[])
+{
+ for (int i = 0; i < count; i++) {
+ putchar('\t');
+ printname(buf);
+ putchar('\t');
+ printsize(dp->s_size, sizes[i]);
+ putchar('\n');
+ buf += strlen(buf) + 1;
+ }
}
static void
printacl(acl_t acl, int isdir)
{
- acl_entry_t entry;
+ acl_entry_t entry = NULL;
int index;
uuid_t *applicable;
char *name = NULL;
for (index = 0;
acl_get_entry(acl, entry == NULL ? ACL_FIRST_ENTRY : ACL_NEXT_ENTRY, &entry) == 0;
index++) {
- if ((applicable = (uuid_t *) acl_get_qualifier(entry)) == NULL)
- continue;
if (acl_get_tag_type(entry, &tag) != 0)
continue;
if (acl_get_flagset_np(entry, &flags) != 0)
continue;
if (acl_get_permset(entry, &perms) != 0)
continue;
-
+ if ((applicable = (uuid_t *) acl_get_qualifier(entry)) == NULL)
+ continue;
name = uuid_to_name(applicable);
acl_free(applicable);
-
switch(tag) {
case ACL_EXTENDED_ALLOW:
type = "allow";
FTSENT *p;
NAMES *np;
char buf[20];
-#ifdef __APPLE__
- acl_t acl = NULL;
- char full_path[MAXPATHLEN];
-#endif
#ifdef COLORLS
int color_printed = 0;
#endif
if (IS_NOPRINT(p))
continue;
sp = p->fts_statp;
- if (f_inode)
+ if (f_inode)
+#if _DARWIN_FEATURE_64_BIT_INODE
+ (void)printf("%*llu ", dp->s_inode, (u_quad_t)sp->st_ino);
+#else
(void)printf("%*lu ", dp->s_inode, (u_long)sp->st_ino);
+#endif
if (f_size)
(void)printf("%*qu ",
dp->s_block, (u_int64_t)howmany(sp->st_blocks, blocksize));
strmode(sp->st_mode, buf);
np = p->fts_pointer;
#ifdef __APPLE__
- if (p->fts_parent->fts_name && *p->fts_parent->fts_name)
- {
- snprintf(full_path, sizeof full_path, "%s/%s",
- p->fts_parent->fts_accpath, p->fts_accpath);
- acl = acl_get_file(full_path, ACL_TYPE_EXTENDED);
- } else
- acl = acl_get_file(p->fts_accpath, ACL_TYPE_EXTENDED);
+ buf[10] = '\0'; /* make +/@ abut the mode */
+ char str[2] = { np->mode_suffix, '\0' };
#endif /* __APPLE__ */
- if (f_group) {
+ if (f_group && f_owner) { /* means print neither */
+#ifdef __APPLE__
+ (void)printf("%s%s %*u ", buf, str, dp->s_nlink,
+ sp->st_nlink);
+#else /* ! __APPLE__ */
+ (void)printf("%s %*u ", buf, dp->s_nlink,
+ sp->st_nlink);
+#endif /* __APPLE__ */
+ }
+ else if (f_group) {
#ifdef __APPLE__
- (void)printf("%s%s %*u %-*s ", buf, acl == NULL ? " " : "+", dp->s_nlink,
+ (void)printf("%s%s %*u %-*s ", buf, str, dp->s_nlink,
sp->st_nlink, dp->s_group, np->group);
#else /* ! __APPLE__ */
(void)printf("%s %*u %-*s ", buf, dp->s_nlink,
sp->st_nlink, dp->s_group, np->group);
+#endif /* __APPLE__ */
+ }
+ else if (f_owner) {
+#ifdef __APPLE__
+ (void)printf("%s%s %*u %-*s ", buf, str, dp->s_nlink,
+ sp->st_nlink, dp->s_user, np->user);
+#else /* ! __APPLE__ */
+ (void)printf("%s %*u %-*s ", buf, dp->s_nlink,
+ sp->st_nlink, dp->s_user, np->user);
#endif /* __APPLE__ */
}
else {
#ifdef __APPLE__
- (void)printf("%s%s %*u %-*s %-*s ", buf, acl == NULL ? " " : "+", dp->s_nlink,
+ (void)printf("%s%s %*u %-*s %-*s ", buf, str, dp->s_nlink,
sp->st_nlink, dp->s_user, np->user, dp->s_group,
np->group);
#else /* ! __APPLE__ */
printtime(sp->st_atime);
else if (f_statustime)
printtime(sp->st_ctime);
+ else if (f_birthtime)
+ printtime(sp->st_birthtime);
else
printtime(sp->st_mtime);
#ifdef COLORLS
printlink(p);
(void)putchar('\n');
#ifdef __APPLE__
- if (f_acl && (acl != NULL))
- printacl(acl, S_ISDIR(sp->st_mode));
- acl_free(acl);
+ if (np->xattr_count && f_xattr) {
+ printxattr(dp, np->xattr_count, np->xattr_names, np->xattr_sizes);
+ }
+ if (np->acl != NULL && f_acl) {
+ printacl(np->acl, S_ISDIR(sp->st_mode));
+ }
#endif /* __APPLE__ */
}
}
* Have to do random access in the linked list -- build a table
* of pointers.
*/
- if (dp->entries > lastentries) {
+ if ((lastentries == -1) || (dp->entries > lastentries)) {
lastentries = dp->entries;
- if ((array =
- realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) {
+ if ((array = realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) {
warn(NULL);
printscol(dp);
+ return;
}
}
+ memset(array, 0, dp->entries * sizeof(FTSENT *));
for (p = dp->list, num = 0; p; p = p->fts_link)
if (p->fts_number != NO_PRINT)
array[num++] = p;
if (num % numcols)
++numrows;
+ assert(dp->list);
if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
(void)printf("total %qu\n", (u_int64_t)howmany(dp->btotal, blocksize));
if (!f_sortacross)
base = row;
for (col = 0, chcnt = 0; col < numcols; ++col) {
- chcnt += printaname(array[base], dp->s_inode,
- dp->s_block);
+ assert(base < dp->entries);
+ chcnt += printaname(array[base], dp->s_inode, dp->s_block);
if (f_sortacross)
base++;
else
sp = p->fts_statp;
chcnt = 0;
if (f_inode)
+#if _DARWIN_FEATURE_64_BIT_INODE
+ chcnt += printf("%*llu ", (int)inodefield, (u_quad_t)sp->st_ino);
+#else
chcnt += printf("%*lu ", (int)inodefield, (u_long)sp->st_ino);
+#endif
if (f_size)
chcnt += printf("%*qu ",
(int)sizefield, (u_int64_t)howmany(sp->st_blocks, blocksize));
if (f_sectime)
/* mmm dd hh:mm:ss yyyy || dd mmm hh:mm:ss yyyy */
format = d_first ? "%e %b %T %Y " : "%b %e %T %Y ";
+ else if (COMPAT_MODE("bin/ls", "Unix2003")) {
+ if (ftime + SIXMONTHS > now && ftime <= now)
+ /* mmm dd hh:mm || dd mmm hh:mm */
+ format = d_first ? "%e %b %R " : "%b %e %R ";
+ else
+ /* mmm dd yyyy || dd mmm yyyy */
+ format = d_first ? "%e %b %Y " : "%b %e %Y ";
+ }
else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS)
/* mmm dd hh:mm || dd mmm hh:mm */
format = d_first ? "%e %b %R " : "%b %e %R ";
static void
printsize(size_t width, off_t bytes)
{
- unit_t unit;
-
- if (f_humanval) {
- unit = unit_adjust(&bytes);
- if (bytes == 0)
- (void)printf("%*s ", (int)width, "0B");
- else
- (void)printf("%*lld%c ", (int)width - 1, bytes,
- "BKMGTPE"[unit]);
- } else
- (void)printf("%*lld ", (int)width, bytes);
-}
-
-/*
- * Output in "human-readable" format. Uses 3 digits max and puts
- * unit suffixes at the end. Makes output compact and easy to read,
- * especially on huge disks.
- *
- */
-unit_t
-unit_adjust(off_t *val)
-{
- double abval;
- unit_t unit;
- unsigned int unit_sz;
-
- abval = fabs((double)*val);
-
- unit_sz = abval ? ilogb(abval) / 10 : 0;
-
- if (unit_sz >= UNIT_MAX) {
- unit = NONE;
- } else {
- unit = unitp[unit_sz];
- *val /= (double)vals_base2[unit_sz];
- }
+ if (f_humanval) {
+ char buf[5];
- return (unit);
+ humanize_number(buf, sizeof(buf), (int64_t)bytes, "",
+ HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
+ (void)printf("%5s ", buf);
+ } else
+ (void)printf("%*jd ", (u_int)width, (intmax_t)bytes);
}