diff options
author | Scott J. Goldman <scottjgo@gmail.com> | 2012-05-09 23:45:55 -0700 |
---|---|---|
committer | Scott J. Goldman <scottjgo@gmail.com> | 2012-05-12 09:51:32 -0700 |
commit | 6fb1c0b489c49b761eeddd655dd01e61d402722d (patch) | |
tree | 439eda0a4863656b4301280e2671d25c84994a04 | |
parent | b1ec25facc4fe0cf7633e05f340e689c9f728ed0 (diff) | |
download | libgit2-6fb1c0b489c49b761eeddd655dd01e61d402722d.tar.gz |
Fix readdir_r() usage for Solaris
On Solaris, struct dirent is defined differently than Linux. The field
containing the path name is of size 0, rather than NAME_MAX. So, we need to
use a properly sized buffer on Solaris to avoid a stack overflow.
Also fix some DIR* leaks on cleanup.
-rw-r--r-- | src/path.c | 33 | ||||
-rw-r--r-- | src/unix/posix.h | 2 |
2 files changed, 29 insertions, 6 deletions
diff --git a/src/path.c b/src/path.c index 9f31676b1..84edf6d89 100644 --- a/src/path.c +++ b/src/path.c @@ -494,7 +494,7 @@ int git_path_direach( { ssize_t wd_len; DIR *dir; - struct dirent de_buf, *de; + struct dirent *de, *de_buf; if (git_path_to_dir(path) < 0) return -1; @@ -506,14 +506,23 @@ int git_path_direach( return -1; } - while (p_readdir_r(dir, &de_buf, &de) == 0 && de != NULL) { +#ifdef __sun + de_buf = git__malloc(sizeof(struct dirent) + FILENAME_MAX + 1); +#else + de_buf = git__malloc(sizeof(struct dirent)); +#endif + + while (p_readdir_r(dir, de_buf, &de) == 0 && de != NULL) { int result; if (is_dot_or_dotdot(de->d_name)) continue; - if (git_buf_puts(path, de->d_name) < 0) + if (git_buf_puts(path, de->d_name) < 0) { + closedir(dir); + git__free(de_buf); return -1; + } result = fn(arg, path); @@ -521,11 +530,13 @@ int git_path_direach( if (result < 0) { closedir(dir); + git__free(de_buf); return -1; } } closedir(dir); + git__free(de_buf); return 0; } @@ -537,7 +548,7 @@ int git_path_dirload( { int error, need_slash; DIR *dir; - struct dirent de_buf, *de; + struct dirent *de, *de_buf; size_t path_len; assert(path != NULL && contents != NULL); @@ -549,11 +560,17 @@ int git_path_dirload( return -1; } +#ifdef __sun + de_buf = git__malloc(sizeof(struct dirent) + FILENAME_MAX + 1); +#else + de_buf = git__malloc(sizeof(struct dirent)); +#endif + path += prefix_len; path_len -= prefix_len; need_slash = (path_len > 0 && path[path_len-1] != '/') ? 1 : 0; - while ((error = p_readdir_r(dir, &de_buf, &de)) == 0 && de != NULL) { + while ((error = p_readdir_r(dir, de_buf, &de)) == 0 && de != NULL) { char *entry_path; size_t entry_len; @@ -573,11 +590,15 @@ int git_path_dirload( memcpy(&entry_path[path_len + need_slash], de->d_name, entry_len); entry_path[path_len + need_slash + entry_len] = '\0'; - if (git_vector_insert(contents, entry_path) < 0) + if (git_vector_insert(contents, entry_path) < 0) { + closedir(dir); + git__free(de_buf); return -1; + } } closedir(dir); + git__free(de_buf); if (error != 0) giterr_set(GITERR_OS, "Failed to process directory entry in '%s'", path); diff --git a/src/unix/posix.h b/src/unix/posix.h index 6d0d0dfa6..48b492941 100644 --- a/src/unix/posix.h +++ b/src/unix/posix.h @@ -14,6 +14,8 @@ # include "compat/fnmatch.h" #endif +#include <stdio.h> + #define p_lstat(p,b) lstat(p,b) #define p_readlink(a, b, c) readlink(a, b, c) #define p_link(o,n) link(o, n) |