Пример #1
0
/*++

StreamCreateBinaryConsole

    Creates a binary console I/O stream.

Arguments:
    console - Console type.

    pool    - Pointer to a memory pool.

Return Values:
    If the function succeeds, the return value is a pointer to a STREAM structure.

    If the function fails, the return value is null.

--*/
STREAM *
StreamCreateBinaryConsole(
    int console,
    apr_pool_t *pool
    )
{
    apr_file_t *file;
    apr_status_t status;

    ASSERT(pool != NULL);

    switch (console) {
        case CONSOLE_INPUT:
            status = apr_file_open_stdin(&file, pool);
            break;
        case CONSOLE_OUTPUT:
            status = apr_file_open_stdout(&file, pool);
            break;
        case CONSOLE_ERROR:
            status = apr_file_open_stderr(&file, pool);
            break;
        default:
            return NULL;
    }

    if (status != APR_SUCCESS) {
        return NULL;
    }

    return StreamCreateFile(file, TRUE, pool);
}
Пример #2
0
/* Main driver.

   Arguments (may be any combination):
     -sstring - digests string
     -t       - runs time trial
     -x       - runs test script
     filename - digests file
     (none)   - digests standard input
 */
int main (int argc, char **argv)
{
    int i;

    apr_initialize();
    atexit(apr_terminate);

    if (apr_pool_create(&local_pool, NULL) != APR_SUCCESS)
        exit(-1);

    apr_file_open_stdin(&in, local_pool); 
    apr_file_open_stdout(&out, local_pool); 
    apr_file_open_stderr(&err, local_pool); 

    if (argc > 1)
    {
        for (i = 1; i < argc; i++)
            if (argv[i][0] == '-' && argv[i][1] == 's')
                MDString(argv[i] + 2);
            else if (strcmp(argv[i], "-t") == 0)
                MDTimeTrial();
            else if (strcmp (argv[i], "-x") == 0)
                MDTestSuite();
            else
                MDFile(argv[i]);
    }
    else
        MDFilter();

    return 0;
}
Пример #3
0
/* return an OSHandle representing one of the standard streams */
static MVMObject * MVM_file_get_stdstream(MVMThreadContext *tc, MVMuint8 type) {
    MVMOSHandle *result;
    apr_file_t  *handle;
    apr_status_t rv;
    MVMObject *type_object = tc->instance->boot_types->BOOTIO;

    result = (MVMOSHandle *)REPR(type_object)->allocate(tc, STABLE(type_object));

    /* need a temporary pool */
    if ((rv = apr_pool_create(&result->body.mem_pool, NULL)) != APR_SUCCESS) {
        MVM_exception_throw_apr_error(tc, rv, "get_stream failed to create pool: ");
    }

    switch(type) {
        case 0:
            apr_file_open_stdin(&handle, result->body.mem_pool);
            break;
        case 1:
            apr_file_open_stdout(&handle, result->body.mem_pool);
            break;
        case 2:
            apr_file_open_stderr(&handle, result->body.mem_pool);
            break;
    }
    result->body.file_handle = handle;
    result->body.handle_type = MVM_OSHANDLE_FILE;
    result->body.encoding_type = MVM_encoding_type_utf8;

    return (MVMObject *)result;
}
int get_password(struct passwd_ctx *ctx)
{
    char buf[MAX_STRING_LEN + 1];
    if (ctx->passwd_src == PW_STDIN) {
        apr_file_t *file_stdin;
        apr_size_t nread;
        if (apr_file_open_stdin(&file_stdin, ctx->pool) != APR_SUCCESS) {
            ctx->errstr = "Unable to read from stdin.";
            return ERR_GENERAL;
        }
        if (apr_file_read_full(file_stdin, buf, sizeof(buf) - 1,
                               &nread) != APR_EOF
            || nread == sizeof(buf) - 1) {
            goto err_too_long;
        }
        buf[nread] = '\0';
        if (nread >= 1 && buf[nread-1] == '\n') {
            buf[nread-1] = '\0';
            if (nread >= 2 && buf[nread-2] == '\r')
                buf[nread-2] = '\0';
        }
        apr_file_close(file_stdin);
        ctx->passwd = apr_pstrdup(ctx->pool, buf);
    }
    else if (ctx->passwd_src == PW_PROMPT_VERIFY) {
        apr_size_t bufsize = sizeof(buf);
        if (apr_password_get("Enter password: "******"New password: "******"Re-type new password: "******"password verification error";
            memset(ctx->passwd, '\0', strlen(ctx->passwd));
            memset(buf, '\0', sizeof(buf));
            return ERR_PWMISMATCH;
        }
    }
    memset(buf, '\0', sizeof(buf));
    return 0;

err_too_long:
    ctx->errstr = apr_psprintf(ctx->pool,
                               "password too long (>%" APR_SIZE_T_FMT ")",
                               ctx->out_len - 1);
    return ERR_OVERFLOW;
}
Пример #5
0
svn_error_t *
svn_stream_for_stdin(svn_stream_t **in, apr_pool_t *pool)
{
  apr_file_t *stdin_file;
  apr_status_t apr_err;

  apr_err = apr_file_open_stdin(&stdin_file, pool);
  if (apr_err)
    return svn_error_wrap_apr(apr_err, "Can't open stdin");

  *in = svn_stream_from_aprfile2(stdin_file, TRUE, pool);

  return SVN_NO_ERROR;
}
Пример #6
0
/* Read a dumpstream from stdin, and use it to feed a loader capable
 * of transmitting that information to the repository located at URL
 * (to which SESSION has been opened).  AUX_SESSION is a second RA
 * session opened to the same URL for performing auxiliary out-of-band
 * operations.
 */
static svn_error_t *
load_revisions(svn_ra_session_t *session,
               svn_ra_session_t *aux_session,
               const char *url,
               svn_boolean_t quiet,
               apr_pool_t *pool)
{
    apr_file_t *stdin_file;
    svn_stream_t *stdin_stream;

    apr_file_open_stdin(&stdin_file, pool);
    stdin_stream = svn_stream_from_aprfile2(stdin_file, FALSE, pool);

    SVN_ERR(svn_rdump__load_dumpstream(stdin_stream, session, aux_session,
                                       quiet, check_cancel, NULL, pool));

    SVN_ERR(svn_stream_close(stdin_stream));

    return SVN_NO_ERROR;
}
Пример #7
0
int main(int argc, const char *const argv[])
{
    apr_pool_t *pool;
    apr_status_t rv = APR_SUCCESS;
    apr_getopt_t *opt;
    const char *opt_arg;
    char ch;
    apr_file_t *infile;
    apr_dbm_t *outdbm;

    apr_app_initialize(&argc, &argv, NULL);
    atexit(apr_terminate);

    verbose = 0;
    format = NULL;
    input = NULL;
    output = NULL;

    apr_pool_create(&pool, NULL);

    if (argc) {
        shortname = apr_filepath_name_get(argv[0]);
    }
    else {
        shortname = "httxt2dbm";
    }

    apr_file_open_stderr(&errfile, pool);
    rv = apr_getopt_init(&opt, pool, argc, argv);

    if (rv != APR_SUCCESS) {
        apr_file_printf(errfile, "Error: apr_getopt_init failed."NL NL);
        return 1;
    }

    if (argc <= 1) {
        usage();
        return 1;
    }

    while ((rv = apr_getopt(opt, "vf::i::o::", &ch, &opt_arg)) == APR_SUCCESS) {
        switch (ch) {
        case 'v':
            if (verbose) {
                apr_file_printf(errfile, "Error: -v can only be passed once" NL NL);
                usage();
                return 1;
            }
            verbose = 1;
            break;
        case 'f':
            if (format) {
                apr_file_printf(errfile, "Error: -f can only be passed once" NL NL);
                usage();
                return 1;
            }
            format = apr_pstrdup(pool, opt_arg);
            break;
        case 'i':
            if (input) {
                apr_file_printf(errfile, "Error: -i can only be passed once" NL NL);
                usage();
                return 1;
            }
            input = apr_pstrdup(pool, opt_arg);
            break;
        case 'o':
            if (output) {
                apr_file_printf(errfile, "Error: -o can only be passed once" NL NL);
                usage();
                return 1;
            }
            output = apr_pstrdup(pool, opt_arg);
            break;
        }
    }

    if (rv != APR_EOF) {
        apr_file_printf(errfile, "Error: Parsing Arguments Failed" NL NL);
        usage();
        return 1;
    }

    if (!input) {
        apr_file_printf(errfile, "Error: No input file specified." NL NL);
        usage();
        return 1;
    }

    if (!output) {
        apr_file_printf(errfile, "Error: No output DBM specified." NL NL);
        usage();
        return 1;
    }

    if (!format) {
        format = "default";
    }

    if (verbose) {
        apr_file_printf(errfile, "DBM Format: %s"NL, format);
    }

    if (!strcmp(input, "-")) {
        rv = apr_file_open_stdin(&infile, pool);
    }
    else {
        rv = apr_file_open(&infile, input, APR_READ|APR_BUFFERED,
                           APR_OS_DEFAULT, pool);
    }

    if (rv != APR_SUCCESS) {
        apr_file_printf(errfile,
                        "Error: Cannot open input file '%s': (%d) %s" NL NL,
                         input, rv, apr_strerror(rv, errbuf, sizeof(errbuf)));
        return 1;
    }

    if (verbose) {
        apr_file_printf(errfile, "Input File: %s"NL, input);
    }

    rv = apr_dbm_open_ex(&outdbm, format, output, APR_DBM_RWCREATE,
                    APR_OS_DEFAULT, pool);

    if (APR_STATUS_IS_ENOTIMPL(rv)) {
        apr_file_printf(errfile,
                        "Error: The requested DBM Format '%s' is not available." NL NL,
                         format);
        return 1;
    }

    if (rv != APR_SUCCESS) {
        apr_file_printf(errfile,
                        "Error: Cannot open output DBM '%s': (%d) %s" NL NL,
                         output, rv, apr_strerror(rv, errbuf, sizeof(errbuf)));
        return 1;
    }

    if (verbose) {
        apr_file_printf(errfile, "DBM File: %s"NL, output);
    }

    rv = to_dbm(outdbm, infile, pool);

    if (rv != APR_SUCCESS) {
        apr_file_printf(errfile,
                        "Error: Converting to DBM: (%d) %s" NL NL,
                         rv, apr_strerror(rv, errbuf, sizeof(errbuf)));
        return 1;
    }

    apr_dbm_close(outdbm);

    if (verbose) {
        apr_file_printf(errfile, "Conversion Complete." NL);
    }

    return 0;
}
int main (int argc, const char * const argv[])
{
    char buf[BUFSIZE];
    apr_size_t nRead, nWrite;
    apr_file_t *f_stdin;
    apr_file_t *f_stdout;
    apr_getopt_t *opt;
    apr_status_t rv;
    char c;
    const char *opt_arg;
    const char *err = NULL;
#if APR_FILES_AS_SOCKETS
    apr_pollfd_t pollfd = { 0 };
    apr_status_t pollret = APR_SUCCESS;
    int polltimeout;
#endif

    apr_app_initialize(&argc, &argv, NULL);
    atexit(apr_terminate);

    memset(&config, 0, sizeof config);
    memset(&status, 0, sizeof status);
    status.rotateReason = ROTATE_NONE;

    apr_pool_create(&status.pool, NULL);
    apr_getopt_init(&opt, status.pool, argc, argv);
#if APR_FILES_AS_SOCKETS
    while ((rv = apr_getopt(opt, "lL:p:ftvecn:", &c, &opt_arg)) == APR_SUCCESS) {
#else
    while ((rv = apr_getopt(opt, "lL:p:ftven:", &c, &opt_arg)) == APR_SUCCESS) {
#endif
        switch (c) {
        case 'l':
            config.use_localtime = 1;
            break;
        case 'L':
            config.linkfile = opt_arg;
            break;
        case 'p':
            config.postrotate_prog = opt_arg;
            break;
        case 'f':
            config.force_open = 1;
            break;
        case 't':
            config.truncate = 1;
            break;
        case 'v':
            config.verbose = 1;
            break;
        case 'e':
            config.echo = 1;
            break;
#if APR_FILES_AS_SOCKETS
        case 'c':
            config.create_empty = 1;
            break;
#endif
        case 'n':
            config.num_files = atoi(opt_arg);
            status.fileNum = -1;
            break;
        }
    }

    if (rv != APR_EOF) {
        usage(argv[0], NULL /* specific error message already issued */ );
    }

    /*
     * After the initial flags we need 2 to 4 arguments,
     * the file name, either the rotation interval time or size
     * or both of them, and optionally the UTC offset.
     */
    if ((argc - opt->ind < 2) || (argc - opt->ind > 4) ) {
        usage(argv[0], "Incorrect number of arguments");
    }

    config.szLogRoot = argv[opt->ind++];

    /* Read in the remaining flags, namely time, size and UTC offset. */
    for(; opt->ind < argc; opt->ind++) {
        if ((err = get_time_or_size(&config, argv[opt->ind],
                                    opt->ind < argc - 1 ? 0 : 1)) != NULL) {
            usage(argv[0], err);
        }
    }

    config.use_strftime = (strchr(config.szLogRoot, '%') != NULL);

    if (config.use_strftime && config.num_files > 0) { 
        fprintf(stderr, "Cannot use -n with %% in filename\n");
        exit(1);
    }

    if (status.fileNum == -1 && config.num_files < 1) { 
        fprintf(stderr, "Invalid -n argument\n");
        exit(1);
    }

    if (apr_file_open_stdin(&f_stdin, status.pool) != APR_SUCCESS) {
        fprintf(stderr, "Unable to open stdin\n");
        exit(1);
    }

    if (apr_file_open_stdout(&f_stdout, status.pool) != APR_SUCCESS) {
        fprintf(stderr, "Unable to open stdout\n");
        exit(1);
    }

    /*
     * Write out result of config parsing if verbose is set.
     */
    if (config.verbose) {
        dumpConfig(&config);
    }

#if APR_FILES_AS_SOCKETS
    if (config.create_empty && config.tRotation) {
        pollfd.p = status.pool;
        pollfd.desc_type = APR_POLL_FILE;
        pollfd.reqevents = APR_POLLIN;
        pollfd.desc.f = f_stdin;
    }
#endif

    /*
     * Immediately open the logfile as we start, if we were forced
     * to do so via '-f'.
     */
    if (config.force_open) {
        doRotate(&config, &status);
    }

    for (;;) {
        nRead = sizeof(buf);
#if APR_FILES_AS_SOCKETS
        if (config.create_empty && config.tRotation) {
            polltimeout = status.tLogEnd ? status.tLogEnd - get_now(&config) : config.tRotation;
            if (polltimeout <= 0) {
                pollret = APR_TIMEUP;
            }
            else {
                pollret = apr_poll(&pollfd, 1, &pollret, apr_time_from_sec(polltimeout));
            }
        }
        if (pollret == APR_SUCCESS) {
            rv = apr_file_read(f_stdin, buf, &nRead);
            if (APR_STATUS_IS_EOF(rv)) {
                break;
            }
            else if (rv != APR_SUCCESS) {
                exit(3);
            }
        }
        else if (pollret == APR_TIMEUP) {
            *buf = 0;
            nRead = 0;
        }
        else {
            fprintf(stderr, "Unable to poll stdin\n");
            exit(5);
        }
#else /* APR_FILES_AS_SOCKETS */
        rv = apr_file_read(f_stdin, buf, &nRead);
        if (APR_STATUS_IS_EOF(rv)) {
            break;
        }
        else if (rv != APR_SUCCESS) {
            exit(3);
        }
#endif /* APR_FILES_AS_SOCKETS */
        checkRotate(&config, &status);
        if (status.rotateReason != ROTATE_NONE) {
            doRotate(&config, &status);
        }

        nWrite = nRead;
        rv = apr_file_write_full(status.current.fd, buf, nWrite, &nWrite);
        if (nWrite != nRead) {
            apr_off_t cur_offset;

            cur_offset = 0;
            if (apr_file_seek(status.current.fd, APR_CUR, &cur_offset) != APR_SUCCESS) {
                cur_offset = -1;
            }
            status.nMessCount++;
            apr_snprintf(status.errbuf, sizeof status.errbuf,
                         "Error %d writing to log file at offset %" APR_OFF_T_FMT ". "
                         "%10d messages lost (%pm)\n",
                         rv, cur_offset, status.nMessCount, &rv);

            truncate_and_write_error(&status);
        }
        else {
            status.nMessCount++;
        }
        if (config.echo) {
            if (apr_file_write_full(f_stdout, buf, nRead, &nWrite)) {
                fprintf(stderr, "Unable to write to stdout\n");
                exit(4);
            }
        }
    }

    return 0; /* reached only at stdin EOF. */
}
Пример #9
0
double write_allocs(ibp_capset_t *caps, int qlen, int n, int asize, int block_size)
{
    int count, i, j, nleft, nblocks, rem, len, err, block_start, alloc_start;
    int *slot;
    op_status_t status;
    int64_t nbytes, last_bytes, print_bytes, delta_bytes;
    apr_int32_t nfds, finished;
    double dbytes, r1, r2;
    apr_pool_t *pool;
    apr_file_t *fd_in;
    opque_t *q;
    op_generic_t *op;
    char *buffer = (char *)malloc(block_size);
    apr_interval_time_t dt = 10;
    apr_pollfd_t pfd;
    apr_time_t stime, dtime;
    int *tbuf_index;
    tbuffer_t *buf;
    Stack_t *tbuf_free;


    tbuf_free = new_stack();
    type_malloc_clear(tbuf_index, int, qlen);
    type_malloc_clear(buf, tbuffer_t, qlen);
    for (i=0; i<qlen; i++) {
        tbuf_index[i] = i;
        push(tbuf_free, &(tbuf_index[i]));
    }

    //** Make the stuff to capture the kbd
    apr_pool_create(&pool, NULL);

    nfds = 1;
    apr_file_open_stdin(&fd_in, pool);

    pfd.p = pool;
    pfd.desc_type = APR_POLL_FILE;
    pfd.reqevents = APR_POLLIN|APR_POLLHUP;
    pfd.desc.f = fd_in;
    pfd.client_data = NULL;


    //** Init the ibp stuff
    init_buffer(buffer, 'W', block_size);
    q = new_opque();
    opque_start_execution(q);

    nblocks = asize / block_size;
    rem = asize % block_size;
    if (rem > 0) nblocks++;
    block_start = 0;
    alloc_start = 0;

    finished = 0;
    apr_poll(&pfd, nfds, &finished, dt);
    count = 0;
    nbytes=0;
    last_bytes = 0;
    delta_bytes = 1024 * 1024 * 1024;
    print_bytes = delta_bytes;
    stime = apr_time_now();

    while (finished == 0) {
//    nleft = qlen - opque_tasks_left(q);
        nleft = stack_size(tbuf_free);
//    printf("\nLOOP: nleft=%d qlen=%d\n", nleft, qlen);
        if (nleft > 0) {
            for (j=block_start; j < nblocks; j++) {
                for (i=alloc_start; i<n; i++) {
                    nleft--;
                    if (nleft <= 0) {
                        block_start = j;
                        alloc_start = i;
                        goto skip_submit;
                    }

                    slot = (int *)pop(tbuf_free);

                    if ((j==(nblocks-1)) && (rem > 0)) {
                        len = rem;
                    } else {
                        len = block_size;
                    }
//             printf("%d=(%d,%d) ", count, j, i);

                    tbuffer_single(&(buf[*slot]), len, buffer);
                    op = new_ibp_write_op(ic, get_ibp_cap(&(caps[i]), IBP_WRITECAP), j*block_size, &(buf[*slot]), 0, len, ibp_timeout);
                    gop_set_id(op, *slot);
                    ibp_op_set_cc(ibp_get_iop(op), cc);
                    ibp_op_set_ncs(ibp_get_iop(op), ncs);
                    opque_add(q, op);
                }

                alloc_start = 0;
            }

            block_start = 0;
        }

skip_submit:
        finished = 1;
        apr_poll(&pfd, nfds, &finished, dt);

        do {  //** Empty the finished queue.  Always wait for for at least 1 to complete
            op = opque_waitany(q);
            status = gop_get_status(op);
            if (status.error_code != IBP_OK) {
                printf("ERROR: Aborting with error code %d\n", status.error_code);
                finished = 0;
            }

            count++;
            i = gop_get_id(op);
            nbytes = nbytes + tbuffer_size(&(buf[i]));
            if (nbytes > print_bytes) {
                dbytes = nbytes / (1.0*1024*1024*1024);
                dtime = apr_time_now() - stime;
                r2 = dtime / (1.0 * APR_USEC_PER_SEC);
                r1 = nbytes - last_bytes;
                r1 = r1 / (r2 * 1024.0 * 1024.0);
                printf("%.2lfGB written (%.2lfMB/s : %.2lf secs)\n", dbytes, r1, r2);
                print_bytes = print_bytes + delta_bytes;
                last_bytes = nbytes;
                stime = apr_time_now();
            }

            push(tbuf_free, &(tbuf_index[i]));
            gop_free(op, OP_DESTROY);
        } while (opque_tasks_finished(q) > 0);
    }

    err = opque_waitall(q);
    if (err != OP_STATE_SUCCESS) {
        printf("write_allocs: At least 1 error occured! * ibp_errno=%d * nfailed=%d\n", err, opque_tasks_failed(q));
    }
    opque_free(q, OP_DESTROY);

    free_stack(tbuf_free, 0);
    free(tbuf_index);
    free(buf);
    free(buffer);

    apr_pool_destroy(pool);

    dbytes = nbytes;
    return(dbytes);
}
Пример #10
0
/* Drive EDITOR to affect the change represented by OPERATION.  HEAD
   is the last-known youngest revision in the repository. */
static svn_error_t *
drive(struct operation *operation,
      svn_revnum_t head,
      const svn_delta_editor_t *editor,
      apr_pool_t *pool)
{
  apr_pool_t *subpool = svn_pool_create(pool);
  apr_hash_index_t *hi;
  struct driver_state state;
  for (hi = apr_hash_first(pool, operation->children);
       hi; hi = apr_hash_next(hi))
    {
      const void *key;
      void *val;
      struct operation *child;
      void *file_baton = NULL;

      svn_pool_clear(subpool);
      apr_hash_this(hi, &key, NULL, &val);
      child = val;

      /* Deletes and replacements are simple -- delete something. */
      if (child->operation == OP_DELETE || child->operation == OP_REPLACE)
        {
          SVN_ERR(editor->delete_entry(key, head, operation->baton, subpool));
        }
      /* Opens could be for directories or files. */
      if (child->operation == OP_OPEN)
        {
          if (child->kind == svn_node_dir)
            {
              SVN_ERR(editor->open_directory(key, operation->baton, head,
                                             subpool, &child->baton));
            }
          else
            {
              SVN_ERR(editor->open_file(key, operation->baton, head,
                                        subpool, &file_baton));
            }
        }
      /* Adds and replacements could also be for directories or files. */
      if (child->operation == OP_ADD || child->operation == OP_REPLACE
          || child->operation == OP_PROPSET)
        {
          if (child->kind == svn_node_dir)
            {
              SVN_ERR(editor->add_directory(key, operation->baton,
                                            child->url, child->rev,
                                            subpool, &child->baton));
            }
          else
            {
              SVN_ERR(editor->add_file(key, operation->baton, child->url,
                                       child->rev, subpool, &file_baton));
            }
        }
      /* If there's a source file and an open file baton, we get to
         change textual contents. */
      if ((child->src_file) && (file_baton))
        {
          svn_txdelta_window_handler_t handler;
          void *handler_baton;
          svn_stream_t *contents;
          apr_file_t *f = NULL;

          SVN_ERR(editor->apply_textdelta(file_baton, NULL, subpool,
                                          &handler, &handler_baton));
          if (strcmp(child->src_file, "-"))
            {
              SVN_ERR(svn_io_file_open(&f, child->src_file, APR_READ,
                                       APR_OS_DEFAULT, pool));
            }
          else
            {
              apr_status_t apr_err = apr_file_open_stdin(&f, pool);
              if (apr_err)
                return svn_error_wrap_apr(apr_err, "Can't open stdin");
            }
          contents = svn_stream_from_aprfile(f, pool);
          SVN_ERR(svn_txdelta_send_stream(contents, handler,
                                          handler_baton, NULL, pool));
          SVN_ERR(svn_io_file_close(f, pool));
        }
      /* If we opened a file, we need to apply outstanding propmods,
         then close it. */
      if (file_baton)
        {
          if ((child->kind == svn_node_file)
              && (! apr_is_empty_table(child->props)))
            {
              state.baton = file_baton;
              state.pool = subpool;
              state.editor = editor;
              state.kind = child->kind;
              if (! apr_table_do(set_props, &state, child->props, NULL))
                SVN_ERR(state.err);
            }
          SVN_ERR(editor->close_file(file_baton, NULL, subpool));
        }
      /* If we opened, added, or replaced a directory, we need to
         recurse, apply outstanding propmods, and then close it. */
      if ((child->kind == svn_node_dir)
          && (child->operation == OP_OPEN
              || child->operation == OP_ADD
              || child->operation == OP_REPLACE))
        {
          SVN_ERR(drive(child, head, editor, subpool));
          if ((child->kind == svn_node_dir)
              && (! apr_is_empty_table(child->props)))
            {
              state.baton = child->baton;
              state.pool = subpool;
              state.editor = editor;
              state.kind = child->kind;
              if (! apr_table_do(set_props, &state, child->props, NULL))
                SVN_ERR(state.err);
            }
          SVN_ERR(editor->close_directory(child->baton, subpool));
        }
    }
  svn_pool_destroy(subpool);
  return SVN_NO_ERROR;
}