* Find entry point *
*************************************************/
+#define RET_FULL BIT(0)
+#define FILTER_TYPE BIT(1)
+#define FILTER_ALL BIT(1)
+#define FILTER_FILE BIT(2)
+#define FILTER_DIR BIT(3)
+#define FILTER_SUBDIR BIT(4)
+
/* See local README for interface description. We use lstat() instead of
scanning the directory, as it is hopefully faster to let the OS do the scanning
for us. */
static int
dsearch_find(void * handle, const uschar * dirname, const uschar * keystring,
- int length, uschar ** result, uschar ** errmsg, uint * do_cache)
+ int length, uschar ** result, uschar ** errmsg, uint * do_cache,
+ const uschar * opts)
{
struct stat statbuf;
int save_errno;
uschar * filename;
+unsigned flags = 0;
handle = handle; /* Keep picky compilers happy */
length = length;
return DEFER;
}
+if (opts)
+ {
+ int sep = ',';
+ uschar * ele;
+
+ while ((ele = string_nextinlist(&opts, &sep, NULL, 0)))
+ if (Ustrcmp(ele, "ret=full") == 0)
+ flags |= RET_FULL;
+ else if (Ustrncmp(ele, "filter=", 7) == 0)
+ {
+ ele += 7;
+ if (Ustrcmp(ele, "file") == 0)
+ flags |= FILTER_TYPE | FILTER_FILE;
+ else if (Ustrcmp(ele, "dir") == 0)
+ flags |= FILTER_TYPE | FILTER_DIR;
+ else if (Ustrcmp(ele, "subdir") == 0)
+ flags |= FILTER_TYPE | FILTER_SUBDIR; /* like dir but not "." or ".." */
+ }
+ }
+
filename = string_sprintf("%s/%s", dirname, keystring);
-if (Ulstat(filename, &statbuf) >= 0)
+if ( Ulstat(filename, &statbuf) >= 0
+ && ( !(flags & FILTER_TYPE)
+ || (flags & FILTER_FILE && S_ISREG(statbuf.st_mode))
+ || ( flags & (FILTER_DIR | FILTER_SUBDIR)
+ && S_ISDIR(statbuf.st_mode)
+ && ( flags & FILTER_DIR
+ || keystring[0] != '.'
+ || keystring[1] != '.'
+ || keystring[1] && keystring[2]
+ ) ) ) )
{
/* Since the filename exists in the filesystem, we can return a
non-tainted result. */
- *result = string_copy_taint(keystring, FALSE);
+ *result = string_copy_taint(flags & RET_FULL ? filename : keystring, FALSE);
return OK;
}