summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjorton <jorton@13f79535-47bb-0310-9956-ffa450edef68>2019-06-25 14:21:56 +0000
committerjorton <jorton@13f79535-47bb-0310-9956-ffa450edef68>2019-06-25 14:21:56 +0000
commitfc20af17e8f587c9f69082905cbeec0e964362c2 (patch)
tree75ac7cea477231ea31a07f15b37a47a6cd5e010b
parent108a10513ef5ca961b195a66423db8d724459bd1 (diff)
downloadlibapr-fc20af17e8f587c9f69082905cbeec0e964362c2.tar.gz
Add apr_dir_pread(), a variant of apr_dir_read() which allows callers
to read a directory with constant memory consumption: * include/apr_file_info.h: Add warning on memory consumption for apr_dir_read; declare apr_dir_pread. * file_io/unix/dir.c (apr_dir_pread): Rename from apr_dir_read and take pool argument. (apr_dir_read): Reimplement using it. * file_io/win32/dir.c, file_io/os2/dir.c: Likewise, but untested. * test/testdir.c (test_pread) [APR_POOL_DEBUG]: Add test case. git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1862071 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--file_io/os2/dir.c12
-rw-r--r--file_io/unix/dir.c12
-rw-r--r--file_io/win32/dir.c8
-rw-r--r--include/apr_file_info.h22
-rw-r--r--test/testdir.c35
5 files changed, 80 insertions, 9 deletions
diff --git a/file_io/os2/dir.c b/file_io/os2/dir.c
index f1554b6f3..d1a0072cc 100644
--- a/file_io/os2/dir.c
+++ b/file_io/os2/dir.c
@@ -79,24 +79,28 @@ APR_DECLARE(apr_status_t) apr_dir_close(apr_dir_t *thedir)
return APR_FROM_OS_ERROR(rv);
}
-
-
APR_DECLARE(apr_status_t) apr_dir_read(apr_finfo_t *finfo, apr_int32_t wanted,
apr_dir_t *thedir)
{
+ return apr_dir_pread(finfo, wanted, thedir, thedir->pool);
+}
+
+APR_DECLARE(apr_status_t) apr_dir_pread(apr_finfo_t *finfo, apr_int32_t wanted,
+ apr_dir_t *thedir, apr_pool_t *pool)
+{
int rv;
ULONG entries = 1;
if (thedir->handle == 0) {
thedir->handle = HDIR_CREATE;
- rv = DosFindFirst(apr_pstrcat(thedir->pool, thedir->dirname, "/*", NULL), &thedir->handle,
+ rv = DosFindFirst(apr_pstrcat(pool, thedir->dirname, "/*", NULL), &thedir->handle,
FILE_ARCHIVED|FILE_DIRECTORY|FILE_SYSTEM|FILE_HIDDEN|FILE_READONLY,
&thedir->entry, sizeof(thedir->entry), &entries, FIL_STANDARD);
} else {
rv = DosFindNext(thedir->handle, &thedir->entry, sizeof(thedir->entry), &entries);
}
- finfo->pool = thedir->pool;
+ finfo->pool = pool;
finfo->fname = NULL;
finfo->valid = 0;
diff --git a/file_io/unix/dir.c b/file_io/unix/dir.c
index d9b344f30..5a17b8601 100644
--- a/file_io/unix/dir.c
+++ b/file_io/unix/dir.c
@@ -142,6 +142,12 @@ static apr_filetype_e filetype_from_dirent_type(int type)
apr_status_t apr_dir_read(apr_finfo_t *finfo, apr_int32_t wanted,
apr_dir_t *thedir)
{
+ return apr_dir_pread(finfo, wanted, thedir, thedir->pool);
+}
+
+apr_status_t apr_dir_pread(apr_finfo_t *finfo, apr_int32_t wanted,
+ apr_dir_t *thedir, apr_pool_t *pool)
+{
apr_status_t ret = 0;
#ifdef DIRENT_TYPE
apr_filetype_e type;
@@ -251,7 +257,7 @@ apr_status_t apr_dir_read(apr_finfo_t *finfo, apr_int32_t wanted,
apr_cpystrn(end, thedir->entry->d_name,
sizeof fspec - (end - fspec));
- ret = apr_stat(finfo, fspec, APR_FINFO_LINK | wanted, thedir->pool);
+ ret = apr_stat(finfo, fspec, APR_FINFO_LINK | wanted, pool);
/* We passed a stack name that will disappear */
finfo->fname = NULL;
}
@@ -263,7 +269,7 @@ apr_status_t apr_dir_read(apr_finfo_t *finfo, apr_int32_t wanted,
/* We don't bail because we fail to stat, when we are only -required-
* to readdir... but the result will be APR_INCOMPLETE
*/
- finfo->pool = thedir->pool;
+ finfo->pool = pool;
finfo->valid = 0;
#ifdef DIRENT_TYPE
if (type != APR_UNKFILE) {
@@ -279,7 +285,7 @@ apr_status_t apr_dir_read(apr_finfo_t *finfo, apr_int32_t wanted,
#endif
}
- finfo->name = apr_pstrdup(thedir->pool, thedir->entry->d_name);
+ finfo->name = apr_pstrdup(pool, thedir->entry->d_name);
finfo->valid |= APR_FINFO_NAME;
if (wanted)
diff --git a/file_io/win32/dir.c b/file_io/win32/dir.c
index f44bceb97..1703ac4b3 100644
--- a/file_io/win32/dir.c
+++ b/file_io/win32/dir.c
@@ -91,6 +91,12 @@ APR_DECLARE(apr_status_t) apr_dir_close(apr_dir_t *dir)
APR_DECLARE(apr_status_t) apr_dir_read(apr_finfo_t *finfo, apr_int32_t wanted,
apr_dir_t *thedir)
{
+ return apr_dir_pread(finfo, wanted, thedir, thedir->pool);
+}
+
+APR_DECLARE(apr_status_t) apr_dir_pread(apr_finfo_t *finfo, apr_int32_t wanted,
+ apr_dir_t *thedir, apr_pool_t *pool)
+{
apr_status_t rv;
char *fname;
apr_wchar_t wdirname[APR_PATH_MAX];
@@ -150,7 +156,7 @@ APR_DECLARE(apr_status_t) apr_dir_read(apr_finfo_t *finfo, apr_int32_t wanted,
fillin_fileinfo(finfo, (WIN32_FILE_ATTRIBUTE_DATA *) thedir->entry,
0, 1, fname, wanted);
- finfo->pool = thedir->pool;
+ finfo->pool = pool;
finfo->valid |= APR_FINFO_NAME;
finfo->name = fname;
diff --git a/include/apr_file_info.h b/include/apr_file_info.h
index cfddc68da..f08762cea 100644
--- a/include/apr_file_info.h
+++ b/include/apr_file_info.h
@@ -263,11 +263,33 @@ APR_DECLARE(apr_status_t) apr_dir_close(apr_dir_t *thedir);
* not be filled in, and you need to check the @c finfo->valid bitmask
* to verify that what you're looking for is there. When no more
* entries are available, APR_ENOENT is returned.
+ *
+ * @warning Memory will be allocated in the pool passed to apr_dir_open;
+ * use apr_dir_pread() and a temporary pool to restrict memory
+ * consumption for a large directory.
*/
APR_DECLARE(apr_status_t) apr_dir_read(apr_finfo_t *finfo, apr_int32_t wanted,
apr_dir_t *thedir);
/**
+ * Read the next entry from the specified directory.
+ * @param finfo the file info structure and filled in by apr_dir_read
+ * @param wanted The desired apr_finfo_t fields, as a bit flag of APR_FINFO_
+ values
+ * @param thedir the directory descriptor returned from apr_dir_open
+ * @param pool the pool to use for allocations
+ * @remark No ordering is guaranteed for the entries read.
+ *
+ * @note If @c APR_INCOMPLETE is returned all the fields in @a finfo may
+ * not be filled in, and you need to check the @c finfo->valid bitmask
+ * to verify that what you're looking for is there. When no more
+ * entries are available, APR_ENOENT is returned.
+ */
+APR_DECLARE(apr_status_t) apr_dir_pread(apr_finfo_t *finfo, apr_int32_t wanted,
+ apr_dir_t *thedir, apr_pool_t *pool);
+
+
+/**
* Rewind the directory to the first entry.
* @param thedir the directory descriptor to rewind.
*/
diff --git a/test/testdir.c b/test/testdir.c
index 21876be5d..bb3399cbf 100644
--- a/test/testdir.c
+++ b/test/testdir.c
@@ -430,6 +430,36 @@ static void test_readmore_info(abts_case* tc, void* data)
ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
}
+#if APR_POOL_DEBUG
+static void test_pread(abts_case *tc, void *data)
+{
+ apr_dir_t *dir;
+ apr_finfo_t finfo;
+ apr_size_t before, after;
+ apr_pool_t *subp;
+
+ APR_ASSERT_SUCCESS(tc, "apr_dir_open failed", apr_dir_open(&dir, "data", p));
+
+ apr_pool_create(&subp, p);
+
+ before = apr_pool_num_bytes(p, 0);
+
+ APR_ASSERT_SUCCESS(tc, "apr_dir_read failed",
+ apr_dir_pread(&finfo, APR_FINFO_DIRENT, dir, subp));
+
+ after = apr_pool_num_bytes(p, 0);
+
+ ABTS_PTR_EQUAL(tc, finfo.pool, subp);
+
+ apr_pool_destroy(subp);
+
+ APR_ASSERT_SUCCESS(tc, "apr_dir_close failed", apr_dir_close(dir));
+
+ ABTS_INT_EQUAL(tc, before, after);
+
+}
+#endif
+
abts_suite *testdir(abts_suite *suite)
{
suite = ADD_SUITE(suite)
@@ -451,7 +481,10 @@ abts_suite *testdir(abts_suite *suite)
abts_run_test(suite, test_closedir, NULL);
abts_run_test(suite, test_uncleared_errno, NULL);
abts_run_test(suite, test_readmore_info, NULL);
-
+#if APR_POOL_DEBUG
+ abts_run_test(suite, test_pread, NULL);
+#endif
+
return suite;
}