From dfe471b77c0d3673fed4973f4642cd34440eefda Mon Sep 17 00:00:00 2001 From: Glenn Strauss Date: Tue, 29 Dec 2020 08:56:01 -0500 Subject: [PATCH] [mod_dirlisting] place vars closer to where used allocate memory for PATH_MAX to avoid pathconf() for _PC_NAME_MAX --- src/mod_dirlisting.c | 101 ++++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 60 deletions(-) diff --git a/src/mod_dirlisting.c b/src/mod_dirlisting.c index f4761efb..ac39c0f5 100644 --- a/src/mod_dirlisting.c +++ b/src/mod_dirlisting.c @@ -813,45 +813,24 @@ static void http_list_directory_footer(const request_st * const r, plugin_data * } static int http_list_directory(request_st * const r, plugin_data * const p, buffer * const dir) { - DIR *dp; - buffer *out; - struct dirent *dent; - struct stat st; - char *path, *path_file; - size_t i; - int hide_dotfiles = p->conf.hide_dot_files; - dirls_list_t dirs, files, *list; - dirls_entry_t *tmp; - char sizebuf[sizeof("999.9K")]; - const buffer *content_type; - long name_max; - log_error_st * const errh = r->conf.errh; - struct tm tm; - - if (buffer_string_is_empty(dir)) return -1; - - i = buffer_string_length(dir); - -#ifdef HAVE_PATHCONF - if (0 >= (name_max = pathconf(dir->ptr, _PC_NAME_MAX))) { - /* some broken fs (fuse) return 0 instead of -1 */ -#ifdef NAME_MAX - name_max = NAME_MAX; + const uint32_t dlen = buffer_string_length(dir); +#if defined __WIN32 + const uint32_t name_max = FILENAME_MAX; #else - name_max = 255; /* stupid default */ +#ifndef PATH_MAX +#define PATH_MAX 4096 #endif - } -#elif defined __WIN32 - name_max = FILENAME_MAX; -#else - name_max = NAME_MAX; + /* allocate based on PATH_MAX rather than pathconf() to get _PC_NAME_MAX */ + const uint32_t name_max = PATH_MAX - dlen - 1; #endif - - path = malloc(i + name_max + 1); + char * const path = malloc(dlen + name_max + 1); force_assert(NULL != path); - memcpy(path, dir->ptr, i+1); - path_file = path + i; + memcpy(path, dir->ptr, dlen+1); + char *path_file = path + dlen; + log_error_st * const errh = r->conf.errh; + DIR *dp; + struct dirent *dent; if (NULL == (dp = opendir(path))) { log_error(errh, __FILE__, __LINE__, "opendir failed: %s", dir->ptr); @@ -860,6 +839,7 @@ static int http_list_directory(request_st * const r, plugin_data * const p, buff return -1; } + dirls_list_t dirs, files; dirs.ent = (dirls_entry_t**) malloc(sizeof(dirls_entry_t*) * DIRLIST_BLOB_SIZE); force_assert(dirs.ent); dirs.size = DIRLIST_BLOB_SIZE; @@ -869,60 +849,58 @@ static int http_list_directory(request_st * const r, plugin_data * const p, buff files.size = DIRLIST_BLOB_SIZE; files.used = 0; + const int hide_dotfiles = p->conf.hide_dot_files; + struct stat st; while ((dent = readdir(dp)) != NULL) { - if (dent->d_name[0] == '.') { + const char * const d_name = dent->d_name; + if (d_name[0] == '.') { if (hide_dotfiles) continue; - if (dent->d_name[1] == '\0') + if (d_name[1] == '\0') continue; - if (dent->d_name[1] == '.' && dent->d_name[2] == '\0') + if (d_name[1] == '.' && d_name[2] == '\0') continue; } if (p->conf.hide_readme_file && !buffer_string_is_empty(p->conf.show_readme)) { - if (strcmp(dent->d_name, p->conf.show_readme->ptr) == 0) + if (strcmp(d_name, p->conf.show_readme->ptr) == 0) continue; } if (p->conf.hide_header_file && !buffer_string_is_empty(p->conf.show_header)) { - if (strcmp(dent->d_name, p->conf.show_header->ptr) == 0) + if (strcmp(d_name, p->conf.show_header->ptr) == 0) continue; } - i = strlen(dent->d_name); + const uint32_t dsz = (uint32_t)strlen(d_name); /* compare d_name against excludes array * elements, skipping any that match. */ if (p->conf.excludes - && mod_dirlisting_exclude(errh, p->conf.excludes, dent->d_name, i)) + && mod_dirlisting_exclude(errh, p->conf.excludes, d_name, dsz)) continue; /* NOTE: the manual says, d_name is never more than NAME_MAX * so this should actually not be a buffer-overflow-risk */ - if (i > (size_t)name_max) continue; + if (dsz > name_max) continue; - memcpy(path_file, dent->d_name, i + 1); + memcpy(path_file, d_name, dsz + 1); if (stat(path, &st) != 0) continue; - list = &files; - if (S_ISDIR(st.st_mode)) - list = &dirs; - + dirls_list_t * const list = !S_ISDIR(st.st_mode) ? &files : &dirs; if (list->used == list->size) { list->size += DIRLIST_BLOB_SIZE; list->ent = (dirls_entry_t**) realloc(list->ent, sizeof(dirls_entry_t*) * list->size); force_assert(list->ent); } - - tmp = (dirls_entry_t*) malloc(sizeof(dirls_entry_t) + 1 + i); + dirls_entry_t * const tmp = list->ent[list->used++] = + (dirls_entry_t*) malloc(sizeof(dirls_entry_t) + 1 + dsz); tmp->mtime = st.st_mtime; tmp->size = st.st_size; - tmp->namelen = (uint32_t)i; - memcpy(DIRLIST_ENT_NAME(tmp), dent->d_name, i + 1); - - list->ent[list->used++] = tmp; + tmp->namelen = dsz; + memcpy(DIRLIST_ENT_NAME(tmp), d_name, dsz + 1); } closedir(dp); @@ -930,12 +908,15 @@ static int http_list_directory(request_st * const r, plugin_data * const p, buff if (files.used) http_dirls_sort(files.ent, files.used); - out = chunkqueue_append_buffer_open(&r->write_queue); + char sizebuf[sizeof("999.9K")]; + struct tm tm; + + buffer * const out = chunkqueue_append_buffer_open(&r->write_queue); http_list_directory_header(r, p, out); /* directories */ - for (i = 0; i < dirs.used; i++) { - tmp = dirs.ent[i]; + for (uint32_t i = 0; i < dirs.used; ++i) { + dirls_entry_t * const tmp = dirs.ent[i]; buffer_append_string_len(out, CONST_STR_LEN("namelen, ENCODING_REL_URI_PART); @@ -950,9 +931,9 @@ static int http_list_directory(request_st * const r, plugin_data * const p, buff /* files */ const array * const mimetypes = r->conf.mimetypes; - for (i = 0; i < files.used; i++) { - tmp = files.ent[i]; - + for (uint32_t i = 0; i < files.used; ++i) { + dirls_entry_t * const tmp = files.ent[i]; + const buffer *content_type; #if defined(HAVE_XATTR) || defined(HAVE_EXTATTR) /*(pass full path)*/ content_type = NULL; if (r->conf.use_xattr) { @@ -1016,7 +997,7 @@ URIHANDLER_FUNC(mod_dirlisting_subrequest) { if (buffer_string_is_empty(&r->uri.path)) return HANDLER_GO_ON; if (r->uri.path.ptr[buffer_string_length(&r->uri.path) - 1] != '/') return HANDLER_GO_ON; if (!http_method_get_or_head(r->http_method)) return HANDLER_GO_ON; - if (buffer_is_empty(&r->physical.path)) return HANDLER_GO_ON; + if (buffer_string_is_empty(&r->physical.path)) return HANDLER_GO_ON; mod_dirlisting_patch_config(r, p);