about summary refs log tree commit diff
diff options
context:
space:
mode:
authorChristian Neukirchen <chneukirchen@gmail.com>2016-02-26 13:04:32 +0100
committerChristian Neukirchen <chneukirchen@gmail.com>2016-02-26 13:04:32 +0100
commit8b228c157f48718d7dbab8828145609e879d126a (patch)
tree6e92e83eb3f38cd9144479ade83d900879d122d1
parentb2bfdf1c9f7fa149790eda8bb51dda56412d6b80 (diff)
downloadlr-8b228c157f48718d7dbab8828145609e879d126a.tar.gz
lr-8b228c157f48718d7dbab8828145609e879d126a.tar.xz
lr-8b228c157f48718d7dbab8828145609e879d126a.zip
count directory entries when needed
-rw-r--r--README.md4
-rw-r--r--lr.15
-rw-r--r--lr.c31
3 files changed, 33 insertions, 7 deletions
diff --git a/README.md b/README.md
index 7bb4083..d40daf8 100644
--- a/README.md
+++ b/README.md
@@ -51,7 +51,7 @@ Over ls:
 * `-S`: BSD stat(1)-inspired output.
 * `-f FMT`: custom formatting, see below.
 * `-D`: depth first traversal. `prune` does not work, but `entries`
-  and `total` is computed.
+  and `total` are computed on the fly.
 * `-H`: only follow symlinks on command line.
 * `-L`: follow all symlinks.
 * `-1`: don't go below one level of directories.
@@ -94,7 +94,7 @@ Over ls:
 * `%G`: numeric gid.
 * `%u`: user name.
 * `%U`: numeric uid.
-* `%e`: number of entries in directories (only with `-D`).
+* `%e`: number of entries in directories.
 * `%t`: total size used by accepted files in directories (only with `-D`).
 * `%Y`: type of the filesystem the file resides on.
 * `%x`: Linux-only: a combination of: `#` for files with security capabilities, `+` for files with an ACL, `@` for files with other extended attributes.
diff --git a/lr.1 b/lr.1
index de8a56b..6c31017 100644
--- a/lr.1
+++ b/lr.1
@@ -43,7 +43,7 @@ will not work, but
 .Ic entries
 and
 .Ic total
-is computed.
+are computed on the fly.
 .It Fl H
 Only follow symlinks on command line (default: don't follow symlinks).
 .It Fl L
@@ -156,8 +156,7 @@ User name
 .It Ic \&%U
 Numeric uid
 .It Ic \&%e
-Number of entries in directories (only with
-.Fl D )
+Number of entries in directories
 .It Ic \&%t
 Total size used by accepted files in directories (only with
 .Fl D )
diff --git a/lr.c b/lr.c
index ee3119a..3fd66a7 100644
--- a/lr.c
+++ b/lr.c
@@ -1009,6 +1009,33 @@ xattr_string(const char *f)
 #endif
 }
 
+static nlink_t
+count_entries(struct fileinfo *fi)
+{
+	nlink_t c = 0;
+	struct dirent *de;
+	DIR *d;
+
+	if (Dflag)
+		return fi->entries;
+
+	if (!S_ISDIR(fi->sb.st_mode))
+		return 0;
+
+	d = opendir(fi->fpath);
+	if (!d)
+		return 0;
+	while ((de = readdir(d))) {
+		if (de->d_name[0] == '.' &&
+		    (!de->d_name[1] || (de->d_name[1]=='.' && !de->d_name[2])))
+			continue;
+		c++;
+	}
+	closedir(d);
+
+	return c;
+}
+
 int
 eval(struct expr *e, struct fileinfo *fi)
 {
@@ -1038,7 +1065,7 @@ eval(struct expr *e, struct fileinfo *fi)
 		case PROP_CTIME: v = fi->sb.st_ctime; break;
 		case PROP_DEPTH: v = fi->depth; break;
 		case PROP_DEV: v = fi->sb.st_dev; break;
-		case PROP_ENTRIES: v = fi->entries; break;
+		case PROP_ENTRIES: v = count_entries(fi); break;
 		case PROP_GID: v = fi->sb.st_gid; break;
 		case PROP_INODE: v = fi->sb.st_ino; break;
 		case PROP_LINKS: v = fi->sb.st_nlink; break;
@@ -1520,7 +1547,7 @@ print_format(struct fileinfo *fi)
 		case 'u': printf("%*s", -uwid, username(fi->sb.st_uid)); break;
 		case 'U': printf("%*ld", intlen(maxuid), (long)fi->sb.st_uid); break;
 
-		case 'e': printf("%ld", (long)fi->entries); break;
+		case 'e': printf("%ld", (long)count_entries(fi)); break;
 		case 't': printf("%jd", (intmax_t)fi->total); break;
 		case 'Y': printf("%*s", -fwid, fstype(fi->sb.st_dev)); break;
 		case 'x': printf("%*s", -maxxattr, fi->xattr); break;