2015-04-07 13:12 UTC+02:00, Sebastian Ramacher <[email protected]>:
> On 2015-04-06 22:33:28, Celelibi wrote:
>> Package: yafc
>> Version: 1.3.5-2
>> Severity: important
>> Tags: upstream patch
>>
>> Dear maintainer,
>>
>> There is a bug in the path shortener that makes yafc crash on some
>> specific input.
>>
>> When it tries to replace a short directory name with "..." it tries to
>> push the remaining of the string farther away, without reallocating a
>> larger buffer.
>>
>> For instance:
>> /w/some/very/long/pathname/whichis/really/too/long/andshouldbeshortened.html
>> is likely to cause the bug.
>>
>> The actual bug is in src/libmhe/shortpath.c when using strpush.
>>
>> I propose here a patch that simplifies the path shortening code so that
>> it has no loop, no complex condition, no temporary memory allocation, no
>> complex string handling.
>>
>> In short: half the size, twice the fun. :)
>>
>> The patch hasn't been extensively tested, but I guess it should be
>> bug-free and behave like the original code.
>
> The behavior of the new code differs from the old code. Previously,
> "averylongdirectoryname/filename.extension" was shortened to
> "...me/filename.extension". The new code returns
> "averylongdirectoryname/...t".

True, this patch was also buggy in some cases. :)

> Also, "/usr/bin/averylongfilenamethatistoolongindeed.tar.gz =
> ...stoolongindeed.tar.gz" was shortened to "...stoolongindeed.tar.gz" and
> now
> it's "/...stoolongindeed.tar.gz".

That's true too.
I'll fix that, but notice that this is inconsistent with the comment
above the current code that say:
/usr/bin/averylongfilenamethatistoolongindeed.tar.gz => /...oolongindeed.tar.gz


Since I could decide exactly what behavior was expected, it's not 1,
not 2, but 3 patches to choose from that I send there. :)

- The first one (0001-shortpath-exact.patch) just try to mimic the
behavior of the original code. The only difference in behavior that I
could observe is that it doesn't generate some silly "....../file.txt"
that the current code does sometime when a previous "..." collide with
the new one.

- The second one (0001-shortpath-short-dir.patch) improves a bit the
first one by handling better short directory names. For instance,
"longdirectory/a/file.txt" doesn't get shortened to
"...ngdir/.../thefile.txt" but to "...longdir/a/thefile.txt". Same
goes for "a/some/dirs/goes/here/file.txt" which never gets shortened
to ".../.../here/file.txt", but to "a/.../goes/here/file.txt".

- The third one (0001-shortpath-simple.patch) completely remove that
double "..." that can appear (like in the previous examples). This
help a lot with code clarity and simplicity.


I tried to test my patches as much as possible, but I'm still just a human. :)

Best regards,
Celelibi
From 53ac4ebc449af6b2d02dcc3c421273153ba70e9f Mon Sep 17 00:00:00 2001
From: Celelibi <[email protected]>
Date: Wed, 8 Apr 2015 19:58:24 +0200
Subject: [PATCH] shortpath: simpler code

Code shorter, simple, without loops.

Signed-off-by: Celelibi <[email protected]>
---
 src/libmhe/shortpath.c | 77 +++++++++++++++++++++++---------------------------
 1 file changed, 35 insertions(+), 42 deletions(-)

diff --git a/src/libmhe/shortpath.c b/src/libmhe/shortpath.c
index 12a46d7..35f67d1 100644
--- a/src/libmhe/shortpath.c
+++ b/src/libmhe/shortpath.c
@@ -22,54 +22,47 @@
  * /usr/bin/averylongfilenamethatistoolongindeed.tar.gz => /...oolongindeed.tar.gz
  */
 
-static char* chop(const char *str, size_t maxlen)
+static char *_shortpath(char *path, size_t maxlen)
 {
-	const size_t len = strlen(str);
+	size_t len = strlen(path);
+	char *result = NULL;
+	const char *copy_from = NULL;
+	const char *first_slash = NULL;
+	const char *last_slash = NULL;
+	size_t start_len = 0;
+	size_t last_len = 0;
+
 	if (len <= maxlen)
-		return xstrdup(str);
+		return xstrdup(path);
 
-	char* result = malloc(maxlen + 1);
-	strncpy(result, "...", 3);
-	strncpy(result + 3, str+(len-maxlen+3), maxlen - 3);
-	result[maxlen] = '\0';
-	return result;
-}
+	result = xmalloc(maxlen + 1);
+	result[0] = '\0';
 
-static char* dirtodots(const char *path, size_t maxlen)
-{
-	const char* first_slash = strchr(path, '/');
-	if (!first_slash)
-		return chop(path, maxlen);
-
-	const char* end_slash = NULL;
-	if (strncmp(first_slash+1, "...", 3) == 0)
-		end_slash = strchr(first_slash+5, '/');
-	else
-		end_slash = strchr(first_slash+1, '/');
-
-	if (!end_slash)
-		return chop(path, maxlen);
-
-	size_t first = first_slash - path,
-				 end = end_slash - path;
-	char* result = xstrdup(path);
-	if (end - first < 4) /* /fu/ */
-		strpush(result + first +1, 4 - (end - first));
-	else /* /foobar/ */
-		strcpy(result + first + 4, end_slash);
-	strncpy(result + first + 1, "...", 3);
-	return result;
-}
+	first_slash = strchr(path, '/');
+	if (first_slash)
+		start_len = first_slash - path + 1;
 
-static char *_shortpath(char *path, size_t maxlen)
-{
-	const size_t len = strlen(path);
-	if (len <= maxlen)
-		return xstrdup(path);
+	last_slash = strrchr(path + start_len + 1, '/');
+	if (last_slash)
+		last_len = strlen(last_slash);
+
+	if (last_slash && start_len + 3 + last_len <= maxlen)
+		strncpy(result, path, start_len);
+
+	if (last_slash && start_len + 3 + last_len > maxlen && last_len + 7 <= maxlen) {
+		size_t lead_len = maxlen - (last_len + 3) - 3;
+		strcpy(result, "...");
+		strncat(result, first_slash - lead_len + 1, lead_len);
+		start_len = lead_len + 3;
+	}
+
+	copy_from = strchr(path + len - (maxlen - start_len - 3), '/');
+	if (!copy_from)
+		copy_from = path + len - (maxlen - 3);
+
+	strcat(result, "...");
+	strcat(result, copy_from);
 
-	char* tmp = dirtodots(path, maxlen);
-	char* result = _shortpath(tmp, maxlen);
-	free(tmp);
 	return result;
 }
 
-- 
2.1.4

From 5bd8ef62b85ef4440193cd6b05da23ca4b2e125a Mon Sep 17 00:00:00 2001
From: Celelibi <[email protected]>
Date: Wed, 8 Apr 2015 19:58:24 +0200
Subject: [PATCH] shortpath: simpler code

Code shorter, simple, without loops, handles short directories better.

Signed-off-by: Celelibi <[email protected]>
---
 src/libmhe/shortpath.c | 80 ++++++++++++++++++++++++--------------------------
 1 file changed, 38 insertions(+), 42 deletions(-)

diff --git a/src/libmhe/shortpath.c b/src/libmhe/shortpath.c
index 12a46d7..c54afe9 100644
--- a/src/libmhe/shortpath.c
+++ b/src/libmhe/shortpath.c
@@ -22,54 +22,50 @@
  * /usr/bin/averylongfilenamethatistoolongindeed.tar.gz => /...oolongindeed.tar.gz
  */
 
-static char* chop(const char *str, size_t maxlen)
+static char *_shortpath(char *path, size_t maxlen)
 {
-	const size_t len = strlen(str);
+	size_t len = strlen(path);
+	char *result = NULL;
+	const char *copy_from = NULL;
+	const char *first_slash = NULL;
+	const char *last_slash = NULL;
+	size_t start_len = 0;
+
 	if (len <= maxlen)
-		return xstrdup(str);
+		return xstrdup(path);
 
-	char* result = malloc(maxlen + 1);
-	strncpy(result, "...", 3);
-	strncpy(result + 3, str+(len-maxlen+3), maxlen - 3);
-	result[maxlen] = '\0';
-	return result;
-}
+	result = xmalloc(maxlen + 1);
+	result[0] = '\0';
 
-static char* dirtodots(const char *path, size_t maxlen)
-{
-	const char* first_slash = strchr(path, '/');
-	if (!first_slash)
-		return chop(path, maxlen);
-
-	const char* end_slash = NULL;
-	if (strncmp(first_slash+1, "...", 3) == 0)
-		end_slash = strchr(first_slash+5, '/');
-	else
-		end_slash = strchr(first_slash+1, '/');
-
-	if (!end_slash)
-		return chop(path, maxlen);
-
-	size_t first = first_slash - path,
-				 end = end_slash - path;
-	char* result = xstrdup(path);
-	if (end - first < 4) /* /fu/ */
-		strpush(result + first +1, 4 - (end - first));
-	else /* /foobar/ */
-		strcpy(result + first + 4, end_slash);
-	strncpy(result + first + 1, "...", 3);
-	return result;
-}
+	first_slash = strchr(path, '/');
+	if (first_slash)
+		start_len = first_slash - path + 1;
 
-static char *_shortpath(char *path, size_t maxlen)
-{
-	const size_t len = strlen(path);
-	if (len <= maxlen)
-		return xstrdup(path);
+	// Do not try to shorten short directory name
+	if (start_len + 5 < len)
+		last_slash = strrchr(path + start_len + 4, '/');
+
+	if (last_slash) {
+		size_t last_len = 0;
+		last_len = strlen(last_slash);
+
+		if (start_len + 3 + last_len <= maxlen) {
+			strncpy(result, path, start_len);
+		} else if (last_len + min(start_len, 4) + 3 <= maxlen) {
+			size_t lead_len = maxlen - (last_len + 3) - 3;
+			strcpy(result, "...");
+			strncat(result, first_slash - lead_len + 1, lead_len);
+			start_len = lead_len + 3;
+		}
+	}
+
+	copy_from = strchr(path + len - (maxlen - start_len - 3), '/');
+	if (!copy_from)
+		copy_from = path + len - (maxlen - 3);
+
+	strcat(result, "...");
+	strcat(result, copy_from);
 
-	char* tmp = dirtodots(path, maxlen);
-	char* result = _shortpath(tmp, maxlen);
-	free(tmp);
 	return result;
 }
 
-- 
2.1.4

From 2ed5951e3b8b0ba465fe2d343e19bd94548e6233 Mon Sep 17 00:00:00 2001
From: Celelibi <[email protected]>
Date: Wed, 8 Apr 2015 19:58:24 +0200
Subject: [PATCH] shortpath: simpler code

Code shorter, simple, without loops, handles short directories better.
Doesn't insert multiples "...".

Signed-off-by: Celelibi <[email protected]>
---
 src/libmhe/shortpath.c | 61 +++++++++++++++++---------------------------------
 1 file changed, 21 insertions(+), 40 deletions(-)

diff --git a/src/libmhe/shortpath.c b/src/libmhe/shortpath.c
index 12a46d7..1bce60a 100644
--- a/src/libmhe/shortpath.c
+++ b/src/libmhe/shortpath.c
@@ -22,54 +22,35 @@
  * /usr/bin/averylongfilenamethatistoolongindeed.tar.gz => /...oolongindeed.tar.gz
  */
 
-static char* chop(const char *str, size_t maxlen)
+static char *_shortpath(char *path, size_t maxlen)
 {
-	const size_t len = strlen(str);
+	size_t len = strlen(path);
+	char *result = NULL;
+	const char *copy_from = NULL;
+	const char *first_slash = NULL;
+	size_t start_len = 0;
+
 	if (len <= maxlen)
-		return xstrdup(str);
+		return xstrdup(path);
 
-	char* result = malloc(maxlen + 1);
-	strncpy(result, "...", 3);
-	strncpy(result + 3, str+(len-maxlen+3), maxlen - 3);
-	result[maxlen] = '\0';
-	return result;
-}
+	result = xmalloc(maxlen + 1);
+	result[0] = '\0';
 
-static char* dirtodots(const char *path, size_t maxlen)
-{
-	const char* first_slash = strchr(path, '/');
-	if (!first_slash)
-		return chop(path, maxlen);
+	first_slash = strchr(path, '/');
+	if (first_slash)
+		start_len = first_slash - path + 1;
 
-	const char* end_slash = NULL;
-	if (strncmp(first_slash+1, "...", 3) == 0)
-		end_slash = strchr(first_slash+5, '/');
+	if (maxlen - start_len - 3 > 0)
+		copy_from = strchr(path + len - (maxlen - start_len - 3), '/');
+
+	if (copy_from)
+		strncpy(result, path, start_len);
 	else
-		end_slash = strchr(first_slash+1, '/');
-
-	if (!end_slash)
-		return chop(path, maxlen);
-
-	size_t first = first_slash - path,
-				 end = end_slash - path;
-	char* result = xstrdup(path);
-	if (end - first < 4) /* /fu/ */
-		strpush(result + first +1, 4 - (end - first));
-	else /* /foobar/ */
-		strcpy(result + first + 4, end_slash);
-	strncpy(result + first + 1, "...", 3);
-	return result;
-}
+		copy_from = path + len - (maxlen - 3);
 
-static char *_shortpath(char *path, size_t maxlen)
-{
-	const size_t len = strlen(path);
-	if (len <= maxlen)
-		return xstrdup(path);
+	strcat(result, "...");
+	strcat(result, copy_from);
 
-	char* tmp = dirtodots(path, maxlen);
-	char* result = _shortpath(tmp, maxlen);
-	free(tmp);
 	return result;
 }
 
-- 
2.1.4

Reply via email to