svn_error_t * svn_fs_type(const char **fs_type, const char *path, apr_pool_t *pool) { const char *filename; char buf[128]; svn_error_t *err; apr_file_t *file; apr_size_t len; /* Read the fsap-name file to get the FSAP name, or assume the (old) default. For old repositories I suppose we could check some other file, DB_CONFIG or strings say, but for now just check the directory exists. */ filename = svn_dirent_join(path, FS_TYPE_FILENAME, pool); err = svn_io_file_open(&file, filename, APR_READ|APR_BUFFERED, 0, pool); if (err && APR_STATUS_IS_ENOENT(err->apr_err)) { svn_node_kind_t kind; svn_error_t *err2 = svn_io_check_path(path, &kind, pool); if (err2) { svn_error_clear(err2); return err; } if (kind == svn_node_dir) { svn_error_clear(err); *fs_type = SVN_FS_TYPE_BDB; return SVN_NO_ERROR; } return err; } else if (err) return err; len = sizeof(buf); SVN_ERR(svn_io_read_length_line(file, buf, &len, pool)); SVN_ERR(svn_io_file_close(file, pool)); *fs_type = apr_pstrdup(pool, buf); return SVN_NO_ERROR; }
/* Process the strace output stored in FILE. */ static void parse_file(apr_file_t *file) { apr_pool_t *pool = svn_pool_create(NULL); apr_pool_t *iterpool = svn_pool_create(pool); /* limit lines to 4k (usually, we need less than 200 bytes) */ svn_stringbuf_t *line = svn_stringbuf_create_ensure(4096, pool); do { svn_error_t *err = NULL; line->len = line->blocksize-1; err = svn_io_read_length_line(file, line->data, &line->len, iterpool); svn_error_clear(err); if (err) break; parse_line(line); svn_pool_clear(iterpool); } while (line->len > 0); }
/* Return the transaction name of the activity stored in file PATHNAME, or NULL if PATHNAME cannot be read for any reason. */ static const char * read_txn(const char *pathname, apr_pool_t *pool) { apr_file_t *activity_file; apr_pool_t *iterpool = svn_pool_create(pool); apr_size_t len; svn_error_t *err = SVN_NO_ERROR; char *txn_name = apr_palloc(pool, SVN_FS__TXN_MAX_LEN+1); int i; /* Try up to 10 times to read the txn name, retrying on ESTALE (stale NFS file handle because of dav_svn__store_activity renaming the activity file into place). */ for (i = 0; i < 10; i++) { svn_error_clear(err); svn_pool_clear(iterpool); err = svn_io_file_open(&activity_file, pathname, APR_READ | APR_BUFFERED, APR_OS_DEFAULT, iterpool); if (err) { #ifdef ESTALE if (APR_TO_OS_ERROR(err->apr_err) == ESTALE) /* Retry on ESTALE... */ continue; #endif /* ...else bail. */ break; } len = SVN_FS__TXN_MAX_LEN; err = svn_io_read_length_line(activity_file, txn_name, &len, iterpool); if (err) { #ifdef ESTALE if (APR_TO_OS_ERROR(err->apr_err) == ESTALE) continue; #endif break; } err = svn_io_file_close(activity_file, iterpool); #ifdef ESTALE if (err) { if (APR_TO_OS_ERROR(err->apr_err) == ESTALE) { /* No retry, just completely ignore this ESTALE. */ svn_error_clear(err); err = SVN_NO_ERROR; } } #endif /* We have a txn_name or had a non-ESTALE close failure; either way, we're finished. */ break; } svn_pool_destroy(iterpool); /* ### let's just assume that any error means the ### activity/transaction doesn't exist */ if (err) { svn_error_clear(err); return NULL; } return txn_name; }
/* There are enough quirks in the deprecated svn_hash_read that we should just preserve its implementation. */ svn_error_t * svn_hash_read(apr_hash_t *hash, apr_file_t *srcfile, apr_pool_t *pool) { svn_error_t *err; char buf[SVN_KEYLINE_MAXLEN]; apr_size_t num_read; char c; int first_time = 1; while (1) { /* Read a key length line. Might be END, though. */ apr_size_t len = sizeof(buf); err = svn_io_read_length_line(srcfile, buf, &len, pool); if (err && APR_STATUS_IS_EOF(err->apr_err) && first_time) { /* We got an EOF on our very first attempt to read, which means it's a zero-byte file. No problem, just go home. */ svn_error_clear(err); return SVN_NO_ERROR; } else if (err) /* Any other circumstance is a genuine error. */ return err; first_time = 0; if (((len == 3) && (buf[0] == 'E') && (buf[1] == 'N') && (buf[2] == 'D')) || ((len == 9) && (buf[0] == 'P') && (buf[1] == 'R') /* We formerly used just "END" to */ && (buf[2] == 'O') /* end a property hash, but later */ && (buf[3] == 'P') /* we added "PROPS-END", so that */ && (buf[4] == 'S') /* the fs dump format would be */ && (buf[5] == '-') /* more human-readable. That's */ && (buf[6] == 'E') /* why we accept either way here. */ && (buf[7] == 'N') && (buf[8] == 'D'))) { /* We've reached the end of the dumped hash table, so leave. */ return SVN_NO_ERROR; } else if ((buf[0] == 'K') && (buf[1] == ' ')) { size_t keylen; int parsed_len; void *keybuf; /* Get the length of the key */ SVN_ERR(svn_cstring_atoi(&parsed_len, buf + 2)); keylen = parsed_len; /* Now read that much into a buffer, + 1 byte for null terminator */ keybuf = apr_palloc(pool, keylen + 1); SVN_ERR(svn_io_file_read_full2(srcfile, keybuf, keylen, &num_read, NULL, pool)); ((char *) keybuf)[keylen] = '\0'; /* Suck up extra newline after key data */ SVN_ERR(svn_io_file_getc(&c, srcfile, pool)); if (c != '\n') return svn_error_create(SVN_ERR_MALFORMED_FILE, NULL, NULL); /* Read a val length line */ len = sizeof(buf); SVN_ERR(svn_io_read_length_line(srcfile, buf, &len, pool)); if ((buf[0] == 'V') && (buf[1] == ' ')) { svn_string_t *value = apr_palloc(pool, sizeof(*value)); apr_size_t vallen; void *valbuf; /* Get the length of the value */ SVN_ERR(svn_cstring_atoi(&parsed_len, buf + 2)); vallen = parsed_len; /* Again, 1 extra byte for the null termination. */ valbuf = apr_palloc(pool, vallen + 1); SVN_ERR(svn_io_file_read_full2(srcfile, valbuf, vallen, &num_read, NULL, pool)); ((char *) valbuf)[vallen] = '\0'; /* Suck up extra newline after val data */ SVN_ERR(svn_io_file_getc(&c, srcfile, pool)); if (c != '\n') return svn_error_create(SVN_ERR_MALFORMED_FILE, NULL, NULL); value->data = valbuf; value->len = vallen; /* The Grand Moment: add a new hash entry! */ apr_hash_set(hash, keybuf, keylen, value); } else { return svn_error_create(SVN_ERR_MALFORMED_FILE, NULL, NULL); } } else { return svn_error_create(SVN_ERR_MALFORMED_FILE, NULL, NULL); } } /* while (1) */ }
static svn_error_t * pack_filesystem(const svn_test_opts_t *opts, apr_pool_t *pool) { int i; svn_node_kind_t kind; const char *path; char buf[80]; apr_file_t *file; apr_size_t len; /* Bail (with success) on known-untestable scenarios */ if ((strcmp(opts->fs_type, "fsfs") != 0) || (opts->server_minor_version && (opts->server_minor_version < 6))) return SVN_NO_ERROR; SVN_ERR(create_packed_filesystem(REPO_NAME, opts, MAX_REV, SHARD_SIZE, pool)); /* Check to see that the pack files exist, and that the rev directories don't. */ for (i = 0; i < (MAX_REV + 1) / SHARD_SIZE; i++) { path = svn_dirent_join_many(pool, REPO_NAME, "revs", apr_psprintf(pool, "%d.pack", i / SHARD_SIZE), "pack", NULL); /* These files should exist. */ SVN_ERR(svn_io_check_path(path, &kind, pool)); if (kind != svn_node_file) return svn_error_createf(SVN_ERR_FS_GENERAL, NULL, "Expected pack file '%s' not found", path); path = svn_dirent_join_many(pool, REPO_NAME, "revs", apr_psprintf(pool, "%d.pack", i / SHARD_SIZE), "manifest", NULL); SVN_ERR(svn_io_check_path(path, &kind, pool)); if (kind != svn_node_file) return svn_error_createf(SVN_ERR_FS_GENERAL, NULL, "Expected manifest file '%s' not found", path); /* This directory should not exist. */ path = svn_dirent_join_many(pool, REPO_NAME, "revs", apr_psprintf(pool, "%d", i / SHARD_SIZE), NULL); SVN_ERR(svn_io_check_path(path, &kind, pool)); if (kind != svn_node_none) return svn_error_createf(SVN_ERR_FS_GENERAL, NULL, "Unexpected directory '%s' found", path); } /* Ensure the min-unpacked-rev jives with the above operations. */ SVN_ERR(svn_io_file_open(&file, svn_dirent_join(REPO_NAME, PATH_MIN_UNPACKED_REV, pool), APR_READ | APR_BUFFERED, APR_OS_DEFAULT, pool)); len = sizeof(buf); SVN_ERR(svn_io_read_length_line(file, buf, &len, pool)); SVN_ERR(svn_io_file_close(file, pool)); if (SVN_STR_TO_REV(buf) != (MAX_REV / SHARD_SIZE) * SHARD_SIZE) return svn_error_createf(SVN_ERR_FS_GENERAL, NULL, "Bad '%s' contents", PATH_MIN_UNPACKED_REV); /* Finally, make sure the final revision directory does exist. */ path = svn_dirent_join_many(pool, REPO_NAME, "revs", apr_psprintf(pool, "%d", (i / SHARD_SIZE) + 1), NULL); SVN_ERR(svn_io_check_path(path, &kind, pool)); if (kind != svn_node_none) return svn_error_createf(SVN_ERR_FS_GENERAL, NULL, "Expected directory '%s' not found", path); return SVN_NO_ERROR; }