While working through Zed Shaw's learn C the Hard Way, I encountered the function apr_dir_make_recursive() which according to the documentation here has the type signature

apr_status_t apr_dir_make_recursive(const char *path, apr_fileperms_t perm, apr_pool_t *pool)

Which makes the directory, identical to the Unix command mkdir -p.

Why would the IO function need a memory pool in order to operate?

My first thought was that it was perhaps an optional argument to populate the newly made directory, however the code below uses an initialized but presumptively empty memory pool. Does this mean that the IO function itself needs a memory pool, that we are passing in for it to use? But that doesn't seem likely either; couldn't the function simply create a local memory pool for it to use which is then destroyed upon return or error?

So, what use is the memory pool? The documentation linked is unhelpful on this point.

Code shortened and shown below, for the curious.

int DB_init()
{
     apr_pool_t *p = NULL;
     apr_pool_initialize();
     apr_pool_create(&p, NULL);

     if(access(DB_DIR, W_OK | X_OK) == -1) {
          apr_status_t rc = apr_dir_make_recursive(DB_DIR,
               APR_UREAD | APR_UWRITE | APR_UEXECUTE |
               APR_GREAD | APR_GWRITE | APR_GEXECUTE, p);
     }

     if(access(DB_FILE, W_OK) == -1) {
          FILE *db = DB_open(DB_FILE, "w");
          check(db, "Cannot open database: %s", DB_FILE);
          DB_close(db);
     }

     apr_pool_destroy(p);
     return 0;

}
有帮助吗?

解决方案 2

The implementation of the function (found here) shows that the pool is used to allocate strings representing the individual components of the path.

The reason the function does not create its own local pool is because the pool may be reused across multiple calls to the apr_*() functions. It just so happens that DB_init() does not have a need to reuse an apr_pool_t.

其他提示

If you pull up the source, you'll see: apr_dir_make_recursive() calls path_remove_last_component():

static char *path_remove_last_component (const char *path, apr_pool_t *pool)
{
    const char *newpath = path_canonicalize (path, pool);
    int i;

    for (i = (strlen(newpath) - 1); i >= 0; i--) {
        if (path[i] == PATH_SEPARATOR)
            break;
    }

    return apr_pstrndup (pool, path, (i < 0) ? 0 : i);
}

This function is creating copies of the path in apr_pstrndup(), each representing a smaller component of it.

To answer your question - because of how it was implemented. Would it be possible to do the same without allocating memory, yes. I think in this case everything came out cleaner and more readable by copying the necessary path components.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top