svn commit: r305952 - head/lib/libc/gen

Ed Schouten ed at FreeBSD.org
Sun Sep 18 20:47:56 UTC 2016


Author: ed
Date: Sun Sep 18 20:47:55 2016
New Revision: 305952
URL: https://svnweb.freebsd.org/changeset/base/305952

Log:
  Replace dirname(3) by a copy that complies to POSIX.
  
  It turns out that the path normalization that our brand new copy of
  dirname(3) does is actually not allowed by the draft version of the
  upcoming version of POSIX. It has to behave identically to the
  dirname(1) utility.
  
  This change replaces our new dirname(3) implementation by yet another
  version that doesn't implement the path normalization logic; it merely
  looks for the end of the directory name and overwrites that with a null
  byte.
  
  More details: See note #3370 at http://austingroupbugs.net/view.php?id=1073
  
  PR:		212193
  Reviewed by:	emaste, jilles
  Differential Revision:	https://reviews.freebsd.org/D7790

Modified:
  head/lib/libc/gen/dirname.3
  head/lib/libc/gen/dirname.c

Modified: head/lib/libc/gen/dirname.3
==============================================================================
--- head/lib/libc/gen/dirname.3	Sun Sep 18 20:23:26 2016	(r305951)
+++ head/lib/libc/gen/dirname.3	Sun Sep 18 20:47:55 2016	(r305952)
@@ -16,7 +16,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd August 12, 2016
+.Dd September 5, 2016
 .Dt DIRNAME 3
 .Os
 .Sh NAME
@@ -60,11 +60,6 @@ space instead.
 The advantage of the former approach is that it ensures thread-safety,
 while also placing no upper limit on the supported length of the
 pathname.
-.Pp
-The algorithm used by this implementation also discards redundant
-slashes and
-.Qq \&.
-pathname components from the pathname string.
 .Sh SEE ALSO
 .Xr basename 1 ,
 .Xr dirname 1 ,

Modified: head/lib/libc/gen/dirname.c
==============================================================================
--- head/lib/libc/gen/dirname.c	Sun Sep 18 20:23:26 2016	(r305951)
+++ head/lib/libc/gen/dirname.c	Sun Sep 18 20:47:55 2016	(r305952)
@@ -27,64 +27,47 @@
 __FBSDID("$FreeBSD$");
 
 #include <libgen.h>
-#include <stdbool.h>
 #include <string.h>
 
 char *
 (dirname)(char *path)
 {
-	const char *in, *prev, *begin, *end;
-	char *out;
-	size_t prevlen;
-	bool skipslash;
+	char *end;
 
 	/*
 	 * If path is a null pointer or points to an empty string,
 	 * dirname() shall return a pointer to the string ".".
 	 */
 	if (path == NULL || *path == '\0')
-		return ((char *)".");
+		return (__DECONST(char *, "."));
 
-	/* Retain at least one leading slash character. */
-	in = out = *path == '/' ? path + 1 : path;
-
-	skipslash = true;
-	prev = ".";
-	prevlen = 1;
-	for (;;) {
-		/* Extract the next pathname component. */
-		while (*in == '/')
-			++in;
-		begin = in;
-		while (*in != '/' && *in != '\0')
-			++in;
-		end = in;
-		if (begin == end)
-			break;
-
-		/*
-		 * Copy over the previous pathname component, except if
-		 * it's dot. There is no point in retaining those.
-		 */
-		if (prevlen != 1 || *prev != '.') {
-			if (!skipslash)
-				*out++ = '/';
-			skipslash = false;
-			memmove(out, prev, prevlen);
-			out += prevlen;
-		}
-
-		/* Preserve the pathname component for the next iteration. */
-		prev = begin;
-		prevlen = end - begin;
-	}
+	/* Find end of last pathname component. */
+	end = path + strlen(path);
+	while (end > path + 1 && *(end - 1) == '/')
+		--end;
+
+	/* Strip off the last pathname component. */
+	while (end > path && *(end - 1) != '/')
+		--end;
 
 	/*
 	 * If path does not contain a '/', then dirname() shall return a
 	 * pointer to the string ".".
 	 */
-	if (out == path)
-		*out++ = '.';
-	*out = '\0';
+	if (end == path) {
+		path[0] = '.';
+		path[1] = '\0';
+		return (path);
+	}
+
+	/*
+	 * Remove trailing slashes from the resulting directory name. Ensure
+	 * that at least one character remains.
+	 */
+	while (end > path + 1 && *(end - 1) == '/')
+		--end;
+
+	/* Null terminate directory name and return it. */
+	*end = '\0';
 	return (path);
 }


More information about the svn-src-all mailing list