apr_os_dir_put doesn't create a working apr_dir_t i.e. apr_dir_read will
not work on the created apr_dir_t
This is not the case with apr_os_file_put which does in fact create a
working apr_file_t
Is this a bug or a feature? There doesn't seem to be any users of
apr_os_dir_put in the httpd tree.
Here is an example from my privilege separated wrapper functions for apr
file io:
The apr_file_open wrapper is quite simple as the apr_os_file_put works
as expected:
static apr_status_t privsep_file_open(privsep_token_t *token,
apr_file_t **new,
const char *fname,
apr_int32_t flag,
apr_fileperms_t perm,
apr_pool_t *pool)
{
privsep_message_t msg;
apr_os_file_t fd;
if(!privsep_inited || !token)
return apr_file_open(new, fname, flag, perm, pool);
memset(&msg, 0, sizeof(msg));
msg.command = privsep_command_file_open;
msg.flags = flag;
msg.perms = perm;
fd = privsep_send_request(&msg, token, fname);
if (msg.retval != APR_SUCCESS)
return msg.retval;
return apr_os_file_put(new, &fd, flag, pool);
}
But I have to resort to ugly hacks in my apr_dir_open implementation:
static apr_status_t privsep_dir_open(privsep_token_t *token,
apr_dir_t **new, const char *dirname,
apr_pool_t *pool)
{
privsep_message_t msg;
apr_os_file_t fd;
DIR *dir;
if(!privsep_inited || !token)
return apr_dir_open(new, dirname, pool);
memset(&msg, 0, sizeof(msg));
msg.command = privsep_command_dir_open;
fd = privsep_send_request(&msg, token, dirname);
if (msg.retval != APR_SUCCESS)
return msg.retval;
/* apr_os_dir_put does not create a fullly allocated apr_dir_t
so we need to open a directory to create one then replace
the fd in the associated apr_os_dir */
if(apr_dir_open(new, "/", pool) != APR_SUCCESS) {
close(fd);
return APR_EGENERAL;
}
/* Ok, now the nasty bit:
Here we assume that an integer file descriptor is the first
element of the opaque DIR structure pointed at by dir
This is the case on Linux, FreeBSD, Mac OS X and Solaris */
apr_os_dir_get(&dir, *new);
close(*(int *)dir);
*(int *)dir = fd;
(*new)->dirname = apr_pstrdup(pool, dirname);
return apr_os_dir_put(new, dir, pool);
}