diff mbox series

[LEDE-DEV] libfstools: support file paths longer than 255 chars

Message ID 20180104140223.4649-1-zajec5@gmail.com
State Changes Requested
Headers show
Series [LEDE-DEV] libfstools: support file paths longer than 255 chars | expand

Commit Message

Rafał Miłecki Jan. 4, 2018, 2:02 p.m. UTC
From: Rafał Miłecki <rafal@milecki.pl>

Alloc globdir buffer dynamically and simply use realloc when needed.
This fixes e.g. segmentation fault in jffs2reset due to an infinite
recurrency when dealing with longs paths.

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
---
 libfstools/overlay.c | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

Comments

Andrey Jr. Melnikov Jan. 6, 2018, 12:17 p.m. UTC | #1
Rafa?? Mi??ecki <zajec5@gmail.com> wrote:
> From: Rafa?? Mi??ecki <rafal@milecki.pl>

> Alloc globdir buffer dynamically and simply use realloc when needed.
> This fixes e.g. segmentation fault in jffs2reset due to an infinite
> recurrency when dealing with longs paths.

> Signed-off-by: Rafa?? Mi??ecki <rafal@milecki.pl>
> ---
>  libfstools/overlay.c | 21 +++++++++++++++++----
>  1 file changed, 17 insertions(+), 4 deletions(-)

> diff --git a/libfstools/overlay.c b/libfstools/overlay.c
> index 8423a57..a7c4f02 100644
> --- a/libfstools/overlay.c
> +++ b/libfstools/overlay.c
> @@ -67,15 +67,28 @@ handle_rmdir(const char *dir)
>  void
>  foreachdir(const char *dir, int (*cb)(const char*))
>  {
> +       static char *globdir;
> +       static size_t globdirlen;
>         struct stat s = { 0 };
> -       char globdir[256];
> +       size_t dirlen = strlen(dir);
>         glob_t gl;
>         int j;
>  
> -       if (dir[strlen(dir) - 1] == '/')
> -               snprintf(globdir, 256, "%s*", dir);
> +       if (dirlen + 3 > globdirlen) {
> +               size_t len = dirlen + 3 + 256;
> +               char *tmp;
> +
> +               tmp = realloc(globdir, len);
> +               if (!tmp)
> +                       return;
> +               globdir = tmp;
> +               globdirlen = len;
> +       }
> +
> +       if (dir[dirlen - 1] == '/')
> +               sprintf(globdir, "%s*", dir);
>         else
> -               snprintf(globdir, 256, "%s/*", dir); /**/
> +               sprintf(globdir, "%s/*", dir);
>  
>         if (!glob(globdir, GLOB_NOESCAPE | GLOB_MARK | GLOB_ONLYDIR, NULL, &gl))
>                 for (j = 0; j < gl.gl_pathc; j++) {

You missed call to free(globdir); at end.
And original source missing globfree(gl); after for (..) loop.
Jo-Philipp Wich Jan. 6, 2018, 12:52 p.m. UTC | #2
Hi,

> You missed call to free(globdir); at end.

the buffer pointed to be globdir is supposed to stay, to be reused by
later invocations of foreachdir(). It's kind of a lazily initialized
global scratch buffer to construct intermediate path strings.

Good catch on the globfree() though, the way it is (not) implemented
right now seems to lead to some quite significant memory leaking,
especially when traversing deep and large directory structures.

~ Jo
diff mbox series

Patch

diff --git a/libfstools/overlay.c b/libfstools/overlay.c
index 8423a57..a7c4f02 100644
--- a/libfstools/overlay.c
+++ b/libfstools/overlay.c
@@ -67,15 +67,28 @@  handle_rmdir(const char *dir)
 void
 foreachdir(const char *dir, int (*cb)(const char*))
 {
+	static char *globdir;
+	static size_t globdirlen;
 	struct stat s = { 0 };
-	char globdir[256];
+	size_t dirlen = strlen(dir);
 	glob_t gl;
 	int j;
 
-	if (dir[strlen(dir) - 1] == '/')
-		snprintf(globdir, 256, "%s*", dir);
+	if (dirlen + 3 > globdirlen) {
+		size_t len = dirlen + 3 + 256;
+		char *tmp;
+
+		tmp = realloc(globdir, len);
+		if (!tmp)
+			return;
+		globdir = tmp;
+		globdirlen = len;
+	}
+
+	if (dir[dirlen - 1] == '/')
+		sprintf(globdir, "%s*", dir);
 	else
-		snprintf(globdir, 256, "%s/*", dir); /**/
+		sprintf(globdir, "%s/*", dir);
 
 	if (!glob(globdir, GLOB_NOESCAPE | GLOB_MARK | GLOB_ONLYDIR, NULL, &gl))
 		for (j = 0; j < gl.gl_pathc; j++) {