Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 30 Jan 2010 14:44:32 +0000 (UTC)
From:      Edward Tomasz Napierala <trasz@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r203187 - stable/8/bin/ls
Message-ID:  <201001301444.o0UEiWIr021612@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: trasz
Date: Sat Jan 30 14:44:32 2010
New Revision: 203187
URL: http://svn.freebsd.org/changeset/base/203187

Log:
  MFC r196712:
  
  Add NFSv4 ACL support to ls(1).
  
  MFC r196773:
  
  Fix regression introduced in r196712 - the 'name' string needs
  to be rewritten for each file we want to check ACL on.  Without
  this change, ls(1) would check only the ACL on the first file
  to list.

Modified:
  stable/8/bin/ls/print.c
Directory Properties:
  stable/8/bin/ls/   (props changed)

Modified: stable/8/bin/ls/print.c
==============================================================================
--- stable/8/bin/ls/print.c	Sat Jan 30 14:40:42 2010	(r203186)
+++ stable/8/bin/ls/print.c	Sat Jan 30 14:44:32 2010	(r203187)
@@ -70,7 +70,7 @@ static void	printsize(size_t, off_t);
 static void	endcolor(int);
 static int	colortype(mode_t);
 #endif
-static void	aclmode(char *, const FTSENT *, int *);
+static void	aclmode(char *, const FTSENT *);
 
 #define	IS_NOPRINT(p)	((p)->fts_number == NO_PRINT)
 
@@ -139,16 +139,12 @@ printlong(const DISPLAY *dp)
 #ifdef COLORLS
 	int color_printed = 0;
 #endif
-	int haveacls;
-	dev_t prevdev;
 
 	if ((dp->list == NULL || dp->list->fts_level != FTS_ROOTLEVEL) &&
 	    (f_longform || f_size)) {
 		(void)printf("total %lu\n", howmany(dp->btotal, blocksize));
 	}
 
-	haveacls = 1;
-	prevdev = (dev_t)-1;
 	for (p = dp->list; p; p = p->fts_link) {
 		if (IS_NOPRINT(p))
 			continue;
@@ -159,14 +155,7 @@ printlong(const DISPLAY *dp)
 			(void)printf("%*jd ",
 			    dp->s_block, howmany(sp->st_blocks, blocksize));
 		strmode(sp->st_mode, buf);
-		/*
-		 * Cache whether or not the filesystem supports ACL's to
-		 * avoid expensive syscalls. Try again when we change devices.
-		 */
-		if (haveacls || sp->st_dev != prevdev) {
-			aclmode(buf, p, &haveacls);
-			prevdev = sp->st_dev;
-		}
+		aclmode(buf, p);
 		np = p->fts_pointer;
 		(void)printf("%s %*u %-*s  %-*s  ", buf, dp->s_nlink,
 		    sp->st_nlink, dp->s_user, np->user, dp->s_group,
@@ -612,56 +601,73 @@ printsize(size_t width, off_t bytes)
 		(void)printf("%*jd ", (u_int)width, bytes);
 }
 
+/*
+ * Add a + after the standard rwxrwxrwx mode if the file has an
+ * ACL. strmode() reserves space at the end of the string.
+ */
 static void
-aclmode(char *buf, const FTSENT *p, int *haveacls)
+aclmode(char *buf, const FTSENT *p)
 {
 	char name[MAXPATHLEN + 1];
-	int entries, ret;
+	int ret, trivial;
+	static dev_t previous_dev = NODEV;
+	static int supports_acls = -1;
+	static int type = ACL_TYPE_ACCESS;
 	acl_t facl;
-	acl_entry_t ae;
 
 	/*
-	 * Add a + after the standard rwxrwxrwx mode if the file has an
-	 * extended ACL. strmode() reserves space at the end of the string.
+	 * XXX: ACLs are not supported on whiteouts and device files
+	 * residing on UFS.
 	 */
+	if (S_ISCHR(p->fts_statp->st_mode) || S_ISBLK(p->fts_statp->st_mode) ||
+	    S_ISWHT(p->fts_statp->st_mode))
+		return;
+
+	if (previous_dev == p->fts_statp->st_dev && supports_acls == 0)
+		return;
+
 	if (p->fts_level == FTS_ROOTLEVEL)
 		snprintf(name, sizeof(name), "%s", p->fts_name);
 	else
 		snprintf(name, sizeof(name), "%s/%s",
 		    p->fts_parent->fts_accpath, p->fts_name);
-	/*
-	 * We have no way to tell whether a symbolic link has an ACL since
-	 * pathconf() and acl_get_file() both follow them.  They also don't
-	 * support whiteouts.
-	 */
-	if (S_ISLNK(p->fts_statp->st_mode) || S_ISWHT(p->fts_statp->st_mode)) {
-		*haveacls = 1;
-		return;
-	}
-	if ((ret = pathconf(name, _PC_ACL_EXTENDED)) <= 0) {
-		if (ret < 0 && errno != EINVAL)
+
+	if (previous_dev != p->fts_statp->st_dev) {
+		previous_dev = p->fts_statp->st_dev;
+		supports_acls = 0;
+
+		ret = lpathconf(name, _PC_ACL_NFS4);
+		if (ret > 0) {
+			type = ACL_TYPE_NFS4;
+			supports_acls = 1;
+		} else if (ret < 0 && errno != EINVAL) {
 			warn("%s", name);
-		else
-			*haveacls = 0;
+			return;
+		}
+		if (supports_acls == 0) {
+			ret = lpathconf(name, _PC_ACL_EXTENDED);
+			if (ret > 0) {
+				type = ACL_TYPE_ACCESS;
+				supports_acls = 1;
+			} else if (ret < 0 && errno != EINVAL) {
+				warn("%s", name);
+				return;
+			}
+		}
+	}
+	if (supports_acls == 0)
+		return;
+	facl = acl_get_link_np(name, type);
+	if (facl == NULL) {
+		warn("%s", name);
 		return;
 	}
-	*haveacls = 1;
-	if ((facl = acl_get_file(name, ACL_TYPE_ACCESS)) != NULL) {
-		if (acl_get_entry(facl, ACL_FIRST_ENTRY, &ae) == 1) {
-			entries = 1;
-			while (acl_get_entry(facl, ACL_NEXT_ENTRY, &ae) == 1)
-				if (++entries > 3)
-					break;
-			/*
-			 * POSIX.1e requires that ACLs of type ACL_TYPE_ACCESS
-			 * must have at least three entries (owner, group,
-			 * and other). So anything with more than 3 ACLs looks
-			 * interesting to us.
-			 */
-			if (entries > 3)
-				buf[10] = '+';
-		}
+	if (acl_is_trivial_np(facl, &trivial)) {
 		acl_free(facl);
-	} else
 		warn("%s", name);
+		return;
+	}
+	if (!trivial)
+		buf[10] = '+';
+	acl_free(facl);
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201001301444.o0UEiWIr021612>