static svn_error_t * test_time_invariant(const char **msg, svn_boolean_t msg_only, svn_test_opts_t *opts, apr_pool_t *pool) { apr_time_t current_timestamp = apr_time_now(); const char *timestring; apr_time_t timestamp; *msg = "test svn_time_[to/from]_cstring() invariant"; if (msg_only) return SVN_NO_ERROR; timestring = svn_time_to_cstring(current_timestamp, pool); SVN_ERR(svn_time_from_cstring(×tamp, timestring, pool)); if (timestamp != current_timestamp) { return svn_error_createf (SVN_ERR_TEST_FAILED, NULL, "svn_time_from_cstring ( svn_time_to_cstring (n) ) returned time '%" APR_TIME_T_FMT "' instead of '%" APR_TIME_T_FMT "'", timestamp,current_timestamp); } return SVN_NO_ERROR; }
static svn_error_t * test_time_from_cstring(const char **msg, svn_boolean_t msg_only, svn_test_opts_t *opts, apr_pool_t *pool) { apr_time_t timestamp; *msg = "test svn_time_from_cstring"; if (msg_only) return SVN_NO_ERROR; SVN_ERR(svn_time_from_cstring(×tamp, test_timestring, pool)); if (timestamp != test_timestamp) { return svn_error_createf (SVN_ERR_TEST_FAILED, NULL, "svn_time_from_cstring (%s) returned time '%" APR_TIME_T_FMT "' instead of '%" APR_TIME_T_FMT "'", test_timestring,timestamp,test_timestamp); } return SVN_NO_ERROR; }
svn_error_t * svn_repos__validate_prop(const char *name, const svn_string_t *value, apr_pool_t *pool) { svn_prop_kind_t kind = svn_property_kind2(name); /* Allow deleting any property, even a property we don't allow to set. */ if (value == NULL) return SVN_NO_ERROR; /* Disallow setting non-regular properties. */ if (kind != svn_prop_regular_kind) return svn_error_createf (SVN_ERR_REPOS_BAD_ARGS, NULL, _("Storage of non-regular property '%s' is disallowed through the " "repository interface, and could indicate a bug in your client"), name); /* Validate "svn:" properties. */ if (svn_prop_is_svn_prop(name) && value != NULL) { /* Validate that translated props (e.g., svn:log) are UTF-8 with * LF line endings. */ if (svn_prop_needs_translation(name)) { if (!svn_utf__is_valid(value->data, value->len)) { return svn_error_createf (SVN_ERR_BAD_PROPERTY_VALUE, NULL, _("Cannot accept '%s' property because it is not encoded in " "UTF-8"), name); } /* Disallow inconsistent line ending style, by simply looking for * carriage return characters ('\r'). */ if (strchr(value->data, '\r') != NULL) { return svn_error_createf (SVN_ERR_BAD_PROPERTY_VALUE, NULL, _("Cannot accept non-LF line endings in '%s' property"), name); } } /* "svn:date" should be a valid date. */ if (strcmp(name, SVN_PROP_REVISION_DATE) == 0) { apr_time_t temp; svn_error_t *err; err = svn_time_from_cstring(&temp, value->data, pool); if (err) return svn_error_create(SVN_ERR_BAD_PROPERTY_VALUE, err, NULL); } } return SVN_NO_ERROR; }
/* Helper for svn_repos_dump_fs. Write a revision record of REV in FS to writable STREAM, using POOL. */ static svn_error_t * write_revision_record(svn_stream_t *stream, svn_fs_t *fs, svn_revnum_t rev, apr_pool_t *pool) { apr_size_t len; apr_hash_t *props; svn_stringbuf_t *encoded_prophash; apr_time_t timetemp; svn_string_t *datevalue; svn_stream_t *propstream; /* Read the revision props even if we're aren't going to dump them for verification purposes */ SVN_ERR(svn_fs_revision_proplist(&props, fs, rev, pool)); /* Run revision date properties through the time conversion to canonicalize them. */ /* ### Remove this when it is no longer needed for sure. */ datevalue = apr_hash_get(props, SVN_PROP_REVISION_DATE, APR_HASH_KEY_STRING); if (datevalue) { SVN_ERR(svn_time_from_cstring(&timetemp, datevalue->data, pool)); datevalue = svn_string_create(svn_time_to_cstring(timetemp, pool), pool); apr_hash_set(props, SVN_PROP_REVISION_DATE, APR_HASH_KEY_STRING, datevalue); } encoded_prophash = svn_stringbuf_create_ensure(0, pool); propstream = svn_stream_from_stringbuf(encoded_prophash, pool); SVN_ERR(svn_hash_write2(props, propstream, "PROPS-END", pool)); SVN_ERR(svn_stream_close(propstream)); /* ### someday write a revision-content-checksum */ SVN_ERR(svn_stream_printf(stream, pool, SVN_REPOS_DUMPFILE_REVISION_NUMBER ": %ld\n", rev)); SVN_ERR(svn_stream_printf(stream, pool, SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH ": %" APR_SIZE_T_FMT "\n", encoded_prophash->len)); /* Write out a regular Content-length header for the benefit of non-Subversion RFC-822 parsers. */ SVN_ERR(svn_stream_printf(stream, pool, SVN_REPOS_DUMPFILE_CONTENT_LENGTH ": %" APR_SIZE_T_FMT "\n\n", encoded_prophash->len)); len = encoded_prophash->len; SVN_ERR(svn_stream_write(stream, encoded_prophash->data, &len)); len = 1; return svn_stream_write(stream, "\n", &len); }
static svn_error_t * test_time_from_cstring_old(const char **msg, svn_boolean_t msg_only, svn_test_opts_t *opts, apr_pool_t *pool) { apr_time_t timestamp; const char **ft; *msg = "test svn_time_from_cstring (old format)"; if (msg_only) return SVN_NO_ERROR; SVN_ERR(svn_time_from_cstring(×tamp, test_old_timestring, pool)); if (timestamp != test_timestamp) { return svn_error_createf (SVN_ERR_TEST_FAILED, NULL, "svn_time_from_cstring (%s) returned time '%" APR_TIME_T_FMT "' instead of '%" APR_TIME_T_FMT "'", test_old_timestring,timestamp,test_timestamp); } /* These tests should fail. They've been added to cover a string overflow * found in our code. However, even if they fail that may not indicate * that there is no problem. The strings being tested need to be * sufficently long to cause a segmentation fault in order to exercise * this bug. Unfortunately due to differences in compilers, architectures, * etc. there is no way to be sure that the bug is being exerercised on * all platforms. */ for (ft = failure_old_tests; *ft; ft++) { svn_error_t *err = svn_time_from_cstring(×tamp, *ft, pool); if (! err) return svn_error_createf (SVN_ERR_TEST_FAILED, NULL, "svn_time_from_cstring (%s) succeeded when it should have failed", *ft); svn_error_clear(err); } return SVN_NO_ERROR; }
static svn_error_t * log_callback (void *baton, apr_hash_t *changed_paths, svn_revnum_t revision, const char *author, const char *date, const char *message, apr_pool_t *pool) { SvnLogCommand *self; SvnLogEntry *log_entry; gchar *entry_author; const gchar *human_date; gchar *entry_date; apr_time_t entry_time; gchar *entry_message; self = SVN_LOG_COMMAND (baton); /* Libsvn docs say author, date, and message might be NULL. */ if (author) entry_author = g_strdup (author); else entry_author = g_strdup ("(none)"); if (date && date[0]) { svn_time_from_cstring (&entry_time, date, svn_command_get_pool (SVN_COMMAND (self))); human_date = svn_time_to_human_cstring (entry_time, svn_command_get_pool (SVN_COMMAND (self))); entry_date = g_strdup (human_date); } else entry_date = g_strdup ("(none)"); if (message) entry_message = g_strdup (message); else entry_message = g_strdup ("empty log message"); /* Emulate ViewCVS */ log_entry = svn_log_entry_new (entry_author, entry_date, revision, entry_message); g_free (entry_author); g_free (entry_date); g_free (entry_message); anjuta_async_command_lock (ANJUTA_ASYNC_COMMAND (self)); g_queue_push_head (self->priv->log_entry_queue, log_entry); anjuta_async_command_unlock (ANJUTA_ASYNC_COMMAND (self)); anjuta_command_notify_data_arrived (ANJUTA_COMMAND (self)); return SVN_NO_ERROR; }
void LogEntry::setDate(const char*date_) { apr_time_t date__ = 0; if (date_ != 0) { Pool pool; if (svn_time_from_cstring (&date__, date_, pool) != 0) date__ = 0; } date = date__; }
/* Read a timestamp from [*BUF, END) stopping at the terminator. Set *RESULT to the resulting timestamp, or 0 if there is none. Use POOL for temporary allocations. Make *BUF point after the terminator. */ static svn_error_t * read_time(apr_time_t *result, char **buf, const char *end, apr_pool_t *pool) { const char *val; SVN_ERR(read_val(&val, buf, end)); if (val) SVN_ERR(svn_time_from_cstring(result, val, pool)); else *result = 0; return SVN_NO_ERROR; }
svn_error_t * svn_cl__time_cstring_to_human_cstring(const char **human_cstring, const char *data, apr_pool_t *pool) { svn_error_t *err; apr_time_t when; err = svn_time_from_cstring(&when, data, pool); if (err && err->apr_err == SVN_ERR_BAD_DATE) { svn_error_clear(err); *human_cstring = _("(invalid date)"); return SVN_NO_ERROR; } else if (err) return svn_error_trace(err); *human_cstring = svn_time_to_human_cstring(when, pool); return SVN_NO_ERROR; }
/* Respond to a S:dated-rev-report request. The request contains a * DAV:creationdate element giving the requested date; the response * contains a DAV:version-name element giving the most recent revision * as of that date. */ dav_error * dav_svn__dated_rev_report(const dav_resource *resource, const apr_xml_doc *doc, ap_filter_t *output) { apr_xml_elem *child; int ns; apr_time_t tm = (apr_time_t) -1; svn_revnum_t rev; apr_bucket_brigade *bb; svn_error_t *err; apr_status_t apr_err; dav_error *derr = NULL; /* Find the DAV:creationdate element and get the requested time from it. */ ns = dav_svn__find_ns(doc->namespaces, "DAV:"); if (ns != -1) { for (child = doc->root->first_child; child != NULL; child = child->next) { if (child->ns != ns || strcmp(child->name, SVN_DAV__CREATIONDATE) != 0) continue; /* If this fails, we'll notice below, so ignore any error for now. */ svn_error_clear (svn_time_from_cstring(&tm, dav_xml_get_cdata(child, resource->pool, 1), resource->pool)); } } if (tm == (apr_time_t) -1) { return dav_svn__new_error(resource->pool, HTTP_BAD_REQUEST, 0, "The request does not contain a valid " "'DAV:" SVN_DAV__CREATIONDATE "' element."); } /* Do the actual work of finding the revision by date. */ if ((err = svn_repos_dated_revision(&rev, resource->info->repos->repos, tm, resource->pool)) != SVN_NO_ERROR) { svn_error_clear(err); return dav_svn__new_error(resource->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "Could not access revision times."); } bb = apr_brigade_create(resource->pool, output->c->bucket_alloc); apr_err = ap_fprintf(output, bb, DAV_XML_HEADER DEBUG_CR "<S:dated-rev-report xmlns:S=\"" SVN_XML_NAMESPACE "\" " "xmlns:D=\"DAV:\">" DEBUG_CR "<D:" SVN_DAV__VERSION_NAME ">%ld</D:" SVN_DAV__VERSION_NAME ">""</S:dated-rev-report>", rev); if (apr_err) derr = dav_svn__convert_err(svn_error_create(apr_err, 0, NULL), HTTP_INTERNAL_SERVER_ERROR, "Error writing REPORT response.", resource->pool); return dav_svn__final_flush_or_error(resource->info->r, bb, output, derr, resource->pool); }
svn_error_t* CSVNLogQuery::LogReceiver ( void *baton , svn_log_entry_t *log_entry , apr_pool_t *pool) { // a few globals static const std::string svnLog (SVN_PROP_REVISION_LOG); static const std::string svnDate (SVN_PROP_REVISION_DATE); static const std::string svnAuthor (SVN_PROP_REVISION_AUTHOR); // just in case ... if (log_entry == NULL) return NULL; // where to send the pre-processed in-format SBaton* receiverBaton = reinterpret_cast<SBaton*>(baton); ILogReceiver* receiver = receiverBaton->receiver; assert (receiver != NULL); // parse revprops std::string author; std::string message; __time64_t timeStamp = 0; UserRevPropArray userRevProps; try { if ( (log_entry->revision != SVN_INVALID_REVNUM) && (log_entry->revprops != NULL)) { for ( apr_hash_index_t *index = apr_hash_first (pool, log_entry->revprops) ; index != NULL ; index = apr_hash_next (index)) { // extract next entry from hash const char* key = NULL; ptrdiff_t keyLen; const char** val = NULL; apr_hash_this ( index , reinterpret_cast<const void**>(&key) , &keyLen , reinterpret_cast<void**>(&val)); // decode / dispatch it std::string name = key; std::string value = *val; if (name == svnLog) message = value; else if (name == svnAuthor) author = value; else if (name == svnDate) { timeStamp = NULL; if (value[0]) SVN_ERR (svn_time_from_cstring (&timeStamp, *val, pool)); } else { userRevProps.Add (name, value); } } } } catch (CMemoryException * e) { e->Delete(); } StandardRevProps standardRevProps (author, message, timeStamp); // the individual changes TChangedPaths changedPaths; try { if (log_entry->changed_paths2 != NULL) { apr_array_header_t *sorted_paths = svn_sort__hash (log_entry->changed_paths2, svn_sort_compare_items_as_paths, pool); for (int i = 0, count = sorted_paths->nelts; i < count; ++i) { changedPaths.push_back (SChangedPath()); SChangedPath& entry = changedPaths.back(); // find the item in the hash svn_sort__item_t *item = &(APR_ARRAY_IDX ( sorted_paths , i , svn_sort__item_t)); // extract the path name entry.path = SVN::MakeUIUrlOrPath ((const char *)item->key); // decode the action svn_log_changed_path2_t *log_item = (svn_log_changed_path2_t *) apr_hash_get ( log_entry->changed_paths2 , item->key , item->klen); static const char actionKeys[7] = "AMRDVE"; const char* actionKey = strchr (actionKeys, log_item->action); entry.action = actionKey == NULL ? 0 : 1 << (actionKey - actionKeys); // node type entry.nodeKind = log_item->node_kind; // decode copy-from info if ( log_item->copyfrom_path && SVN_IS_VALID_REVNUM (log_item->copyfrom_rev)) { entry.copyFromPath = SVN::MakeUIUrlOrPath (log_item->copyfrom_path); entry.copyFromRev = log_item->copyfrom_rev; } else { entry.copyFromRev = 0; } entry.text_modified = log_item->text_modified; entry.props_modified = log_item->props_modified; } } else if (log_entry->changed_paths != NULL) { apr_array_header_t *sorted_paths = svn_sort__hash (log_entry->changed_paths, svn_sort_compare_items_as_paths, pool); for (int i = 0, count = sorted_paths->nelts; i < count; ++i) { changedPaths.push_back (SChangedPath()); SChangedPath& entry = changedPaths.back(); // find the item in the hash svn_sort__item_t *item = &(APR_ARRAY_IDX ( sorted_paths , i , svn_sort__item_t)); // extract the path name entry.path = SVN::MakeUIUrlOrPath ((const char *)item->key); // decode the action svn_log_changed_path_t *log_item = (svn_log_changed_path_t *) apr_hash_get ( log_entry->changed_paths , item->key , item->klen); static const char actionKeys[7] = "AMRDVE"; const char* actionKey = strchr (actionKeys, log_item->action); entry.action = actionKey == NULL ? 0 : 1 << (actionKey - actionKeys); // node type entry.nodeKind = svn_node_unknown; // decode copy-from info if ( log_item->copyfrom_path && SVN_IS_VALID_REVNUM (log_item->copyfrom_rev)) { entry.copyFromPath = SVN::MakeUIUrlOrPath (log_item->copyfrom_path); entry.copyFromRev = log_item->copyfrom_rev; } else { entry.copyFromRev = 0; } entry.text_modified = svn_tristate_unknown; entry.props_modified = svn_tristate_unknown; } } } catch (CMemoryException * e) { e->Delete(); } // now, report the change try { // treat revision 0 special: only report/show it if either the author or a message is set, or if user props are set if ( log_entry->revision || userRevProps.GetCount() || !standardRevProps.GetAuthor().empty() || !standardRevProps.GetMessage().empty()) { MergeInfo mergeInfo = { log_entry->has_children != FALSE , log_entry->non_inheritable != FALSE , log_entry->subtractive_merge != FALSE }; receiver->ReceiveLog ( receiverBaton->includeChanges ? &changedPaths : NULL , log_entry->revision , receiverBaton->includeStandardRevProps ? &standardRevProps : NULL , receiverBaton->includeUserRevProps ? &userRevProps : NULL , &mergeInfo); } } catch (SVNError& e) { return svn_error_create (e.GetCode(), NULL, e.GetMessage()); } catch (...) { // we must not leak exceptions back into SVN } return NULL; }
/* Conforms to svn_ra_serf__xml_closed_t */ static svn_error_t * item_closed(svn_ra_serf__xml_estate_t *xes, void *baton, int leaving_state, const svn_string_t *cdata, apr_hash_t *attrs, apr_pool_t *scratch_pool) { list_context_t *list_ctx = baton; if (leaving_state == AUTHOR) { /* For compatibility with liveprops, current servers will not use * base64-encoding for "binary" user names bu simply drop the * offending control chars. * * We might want to switch to revprop-style encoding, though, * and this is the code to do that. */ const char *encoding = svn_hash_gets(attrs, "encoding"); if (encoding) { /* Check for a known encoding type. This is easy -- there's only one. */ if (strcmp(encoding, "base64") != 0) { return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL, _("Unsupported encoding '%s'"), encoding); } cdata = svn_base64_decode_string(cdata, scratch_pool); } /* Remember until the next ITEM closing tag. */ svn_stringbuf_set(list_ctx->author_buf, cdata->data); list_ctx->author = list_ctx->author_buf->data; } else if (leaving_state == ITEM) { const char *dirent_path = cdata->data; const char *kind_word, *date, *crev, *size; svn_dirent_t dirent = { 0 }; kind_word = svn_hash_gets(attrs, "node-kind"); size = svn_hash_gets(attrs, "size"); dirent.has_props = svn_hash__get_bool(attrs, "has-props", FALSE); crev = svn_hash_gets(attrs, "created-rev"); date = svn_hash_gets(attrs, "date"); /* Convert data. */ dirent.kind = svn_node_kind_from_word(kind_word); if (size) SVN_ERR(svn_cstring_atoi64(&dirent.size, size)); else dirent.size = SVN_INVALID_FILESIZE; if (crev) SVN_ERR(svn_revnum_parse(&dirent.created_rev, crev, NULL)); else dirent.created_rev = SVN_INVALID_REVNUM; if (date) SVN_ERR(svn_time_from_cstring(&dirent.time, date, scratch_pool)); if (list_ctx->author) dirent.last_author = list_ctx->author; /* Invoke RECEIVER */ SVN_ERR(list_ctx->receiver(dirent_path, &dirent, list_ctx->receiver_baton, scratch_pool)); /* Reset buffered info. */ list_ctx->author = NULL; } return SVN_NO_ERROR; }
/* Given a mod_dav_svn @a resource, set @a *timeval and @a *datestring to the last-modified-time of the resource. The datestring will be formatted according to @a format. Use @a pool for both scratchwork, and to allocate @a *datestring. If @a timeval or @a datestring is NULL, don't touch it. Return zero on success, non-zero if an error occurs. */ static int get_last_modified_time(const char **datestring, apr_time_t *timeval, const dav_resource *resource, enum time_format format, apr_pool_t *pool) { svn_revnum_t committed_rev = SVN_INVALID_REVNUM; svn_string_t *committed_date = NULL; svn_error_t *serr; apr_time_t timeval_tmp; if ((datestring == NULL) && (timeval == NULL)) return 0; if (resource->baselined && resource->type == DAV_RESOURCE_TYPE_VERSION) { /* A baseline URI. */ committed_rev = resource->info->root.rev; } else if (resource->type == DAV_RESOURCE_TYPE_REGULAR || resource->type == DAV_RESOURCE_TYPE_WORKING || resource->type == DAV_RESOURCE_TYPE_VERSION) { serr = svn_fs_node_created_rev(&committed_rev, resource->info->root.root, resource->info->repos_path, pool); if (serr != NULL) { svn_error_clear(serr); return 1; } } else { /* unsupported resource kind -- has no mod-time */ return 1; } serr = get_path_revprop(&committed_date, resource, committed_rev, SVN_PROP_REVISION_DATE, pool); if (serr) { svn_error_clear(serr); return 1; } if (committed_date == NULL) return 1; /* return the ISO8601 date as an apr_time_t */ serr = svn_time_from_cstring(&timeval_tmp, committed_date->data, pool); if (serr != NULL) { svn_error_clear(serr); return 1; } if (timeval) memcpy(timeval, &timeval_tmp, sizeof(*timeval)); if (! datestring) return 0; if (format == time_format_iso8601) { *datestring = committed_date->data; } else if (format == time_format_rfc1123) { apr_time_exp_t tms; apr_status_t status; /* convert the apr_time_t into an apr_time_exp_t */ status = apr_time_exp_gmt(&tms, timeval_tmp); if (status != APR_SUCCESS) return 1; /* stolen from dav/fs/repos.c :-) */ *datestring = apr_psprintf(pool, "%s, %.2d %s %d %.2d:%.2d:%.2d GMT", apr_day_snames[tms.tm_wday], tms.tm_mday, apr_month_snames[tms.tm_mon], tms.tm_year + 1900, tms.tm_hour, tms.tm_min, tms.tm_sec); } else /* unknown time format */ { return 1; } return 0; }
svn_error_t * svn_client_cat2(svn_stream_t *out, const char *path_or_url, const svn_opt_revision_t *peg_revision, const svn_opt_revision_t *revision, svn_client_ctx_t *ctx, apr_pool_t *pool) { svn_ra_session_t *ra_session; svn_revnum_t rev; svn_string_t *eol_style; svn_string_t *keywords; apr_hash_t *props; const char *url; svn_stream_t *output = out; svn_error_t *err; /* ### Inconsistent default revision logic in this command. */ if (peg_revision->kind == svn_opt_revision_unspecified) { peg_revision = svn_cl__rev_default_to_head_or_working(peg_revision, path_or_url); revision = svn_cl__rev_default_to_head_or_base(revision, path_or_url); } else { peg_revision = svn_cl__rev_default_to_head_or_working(peg_revision, path_or_url); revision = svn_cl__rev_default_to_peg(revision, peg_revision); } if (! svn_path_is_url(path_or_url) && SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(peg_revision->kind) && SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(revision->kind)) { const char *local_abspath; svn_stream_t *normal_stream; SVN_ERR(svn_dirent_get_absolute(&local_abspath, path_or_url, pool)); SVN_ERR(svn_client__get_normalized_stream(&normal_stream, ctx->wc_ctx, local_abspath, revision, TRUE, FALSE, ctx->cancel_func, ctx->cancel_baton, pool, pool)); /* We don't promise to close output, so disown it to ensure we don't. */ output = svn_stream_disown(output, pool); return svn_error_trace(svn_stream_copy3(normal_stream, output, ctx->cancel_func, ctx->cancel_baton, pool)); } /* Get an RA plugin for this filesystem object. */ SVN_ERR(svn_client__ra_session_from_path(&ra_session, &rev, &url, path_or_url, NULL, peg_revision, revision, ctx, pool)); /* Grab some properties we need to know in order to figure out if anything special needs to be done with this file. */ err = svn_ra_get_file(ra_session, "", rev, NULL, NULL, &props, pool); if (err) { if (err->apr_err == SVN_ERR_FS_NOT_FILE) { return svn_error_createf(SVN_ERR_CLIENT_IS_DIRECTORY, err, _("URL '%s' refers to a directory"), url); } else { return svn_error_trace(err); } } eol_style = apr_hash_get(props, SVN_PROP_EOL_STYLE, APR_HASH_KEY_STRING); keywords = apr_hash_get(props, SVN_PROP_KEYWORDS, APR_HASH_KEY_STRING); if (eol_style || keywords) { /* It's a file with no special eol style or keywords. */ svn_subst_eol_style_t eol; const char *eol_str; apr_hash_t *kw; if (eol_style) svn_subst_eol_style_from_value(&eol, &eol_str, eol_style->data); else { eol = svn_subst_eol_style_none; eol_str = NULL; } if (keywords) { svn_string_t *cmt_rev, *cmt_date, *cmt_author; apr_time_t when = 0; cmt_rev = apr_hash_get(props, SVN_PROP_ENTRY_COMMITTED_REV, APR_HASH_KEY_STRING); cmt_date = apr_hash_get(props, SVN_PROP_ENTRY_COMMITTED_DATE, APR_HASH_KEY_STRING); cmt_author = apr_hash_get(props, SVN_PROP_ENTRY_LAST_AUTHOR, APR_HASH_KEY_STRING); if (cmt_date) SVN_ERR(svn_time_from_cstring(&when, cmt_date->data, pool)); SVN_ERR(svn_subst_build_keywords2 (&kw, keywords->data, cmt_rev->data, url, when, cmt_author ? cmt_author->data : NULL, pool)); } else kw = NULL; /* Interject a translating stream */ output = svn_subst_stream_translated(svn_stream_disown(out, pool), eol_str, FALSE, kw, TRUE, pool); } SVN_ERR(svn_ra_get_file(ra_session, "", rev, output, NULL, NULL, pool)); if (out != output) /* Close the interjected stream */ SVN_ERR(svn_stream_close(output)); return SVN_NO_ERROR; }
/* Parse the file at DIGEST_PATH, populating the lock LOCK_P in that file (if it exists, and if *LOCK_P is non-NULL) and the hash of CHILDREN_P (if any exist, and if *CHILDREN_P is non-NULL). Use POOL for all allocations. */ static svn_error_t * read_digest_file(apr_hash_t **children_p, svn_lock_t **lock_p, const char *fs_path, const char *digest_path, apr_pool_t *pool) { svn_error_t *err = SVN_NO_ERROR; svn_lock_t *lock; apr_hash_t *hash; svn_stream_t *stream; const char *val; if (lock_p) *lock_p = NULL; if (children_p) *children_p = apr_hash_make(pool); err = svn_stream_open_readonly(&stream, digest_path, pool, pool); if (err && APR_STATUS_IS_ENOENT(err->apr_err)) { svn_error_clear(err); return SVN_NO_ERROR; } SVN_ERR(err); /* If our caller doesn't care about anything but the presence of the file... whatever. */ if (! (lock_p || children_p)) return svn_stream_close(stream); hash = apr_hash_make(pool); if ((err = svn_hash_read2(hash, stream, SVN_HASH_TERMINATOR, pool))) { svn_error_clear(svn_stream_close(stream)); return svn_error_createf(err->apr_err, err, _("Can't parse lock/entries hashfile '%s'"), svn_dirent_local_style(digest_path, pool)); } SVN_ERR(svn_stream_close(stream)); /* If our caller cares, see if we have a lock path in our hash. If so, we'll assume we have a lock here. */ val = hash_fetch(hash, PATH_KEY, pool); if (val && lock_p) { const char *path = val; /* Create our lock and load it up. */ lock = svn_lock_create(pool); lock->path = path; if (! ((lock->token = hash_fetch(hash, TOKEN_KEY, pool)))) return svn_error_trace(err_corrupt_lockfile(fs_path, path)); if (! ((lock->owner = hash_fetch(hash, OWNER_KEY, pool)))) return svn_error_trace(err_corrupt_lockfile(fs_path, path)); if (! ((val = hash_fetch(hash, IS_DAV_COMMENT_KEY, pool)))) return svn_error_trace(err_corrupt_lockfile(fs_path, path)); lock->is_dav_comment = (val[0] == '1'); if (! ((val = hash_fetch(hash, CREATION_DATE_KEY, pool)))) return svn_error_trace(err_corrupt_lockfile(fs_path, path)); SVN_ERR(svn_time_from_cstring(&(lock->creation_date), val, pool)); if ((val = hash_fetch(hash, EXPIRATION_DATE_KEY, pool))) SVN_ERR(svn_time_from_cstring(&(lock->expiration_date), val, pool)); lock->comment = hash_fetch(hash, COMMENT_KEY, pool); *lock_p = lock; } /* If our caller cares, see if we have any children for this path. */ val = hash_fetch(hash, CHILDREN_KEY, pool); if (val && children_p) { apr_array_header_t *kiddos = svn_cstring_split(val, "\n", FALSE, pool); int i; for (i = 0; i < kiddos->nelts; i++) { apr_hash_set(*children_p, APR_ARRAY_IDX(kiddos, i, const char *), APR_HASH_KEY_STRING, (void *)1); } }
svn_error_t * svn_ra_neon__do_stat(svn_ra_session_t *session, const char *path, svn_revnum_t revision, svn_dirent_t **dirent, apr_pool_t *pool) { svn_ra_neon__session_t *ras = session->priv; const char *url = ras->url->data; const char *final_url; apr_hash_t *resources; apr_hash_index_t *hi; svn_error_t *err; /* If we were given a relative path to append, append it. */ if (path) url = svn_path_url_add_component(url, path, pool); /* Invalid revision means HEAD, which is just the public URL. */ if (! SVN_IS_VALID_REVNUM(revision)) { final_url = url; } else { /* Else, convert (rev, path) into an opaque server-generated URL. */ svn_string_t bc_url, bc_relative; err = svn_ra_neon__get_baseline_info(NULL, &bc_url, &bc_relative, NULL, ras, url, revision, pool); if (err) { if (err->apr_err == SVN_ERR_FS_NOT_FOUND) { /* easy out: */ svn_error_clear(err); *dirent = NULL; return SVN_NO_ERROR; } else return err; } final_url = svn_path_url_add_component(bc_url.data, bc_relative.data, pool); } /* Depth-zero PROPFIND is the One True DAV Way. */ err = svn_ra_neon__get_props(&resources, ras, final_url, SVN_RA_NEON__DEPTH_ZERO, NULL, NULL /* all props */, pool); if (err) { if (err->apr_err == SVN_ERR_FS_NOT_FOUND) { /* easy out: */ svn_error_clear(err); *dirent = NULL; return SVN_NO_ERROR; } else return err; } /* Copying parsing code from svn_ra_neon__get_dir() here. The hash of resources only contains one item, but there's no other way to get the item. */ for (hi = apr_hash_first(pool, resources); hi; hi = apr_hash_next(hi)) { void *val; svn_ra_neon__resource_t *resource; const svn_string_t *propval; apr_hash_index_t *h; svn_dirent_t *entry; apr_hash_this(hi, NULL, NULL, &val); resource = val; entry = apr_pcalloc(pool, sizeof(*entry)); entry->kind = resource->is_collection ? svn_node_dir : svn_node_file; /* entry->size is already 0 by virtue of pcalloc(). */ if (entry->kind == svn_node_file) { propval = apr_hash_get(resource->propset, SVN_RA_NEON__PROP_GETCONTENTLENGTH, APR_HASH_KEY_STRING); if (propval) entry->size = svn__atoui64(propval->data); } /* does this resource contain any 'dead' properties? */ for (h = apr_hash_first(pool, resource->propset); h; h = apr_hash_next(h)) { const void *kkey; apr_hash_this(h, &kkey, NULL, NULL); if (strncmp((const char *)kkey, SVN_DAV_PROP_NS_CUSTOM, sizeof(SVN_DAV_PROP_NS_CUSTOM) - 1) == 0) entry->has_props = TRUE; else if (strncmp((const char *)kkey, SVN_DAV_PROP_NS_SVN, sizeof(SVN_DAV_PROP_NS_SVN) - 1) == 0) entry->has_props = TRUE; } /* created_rev & friends */ propval = apr_hash_get(resource->propset, SVN_RA_NEON__PROP_VERSION_NAME, APR_HASH_KEY_STRING); if (propval != NULL) entry->created_rev = SVN_STR_TO_REV(propval->data); propval = apr_hash_get(resource->propset, SVN_RA_NEON__PROP_CREATIONDATE, APR_HASH_KEY_STRING); if (propval != NULL) SVN_ERR(svn_time_from_cstring(&(entry->time), propval->data, pool)); propval = apr_hash_get(resource->propset, SVN_RA_NEON__PROP_CREATOR_DISPLAYNAME, APR_HASH_KEY_STRING); if (propval != NULL) entry->last_author = propval->data; *dirent = entry; } return SVN_NO_ERROR; }
/* Conforms to svn_ra_serf__xml_closed_t */ static svn_error_t * getlocks_closed(svn_ra_serf__xml_estate_t *xes, void *baton, int leaving_state, const svn_string_t *cdata, apr_hash_t *attrs, apr_pool_t *scratch_pool) { lock_context_t *lock_ctx = baton; if (leaving_state == LOCK) { const char *path = svn_hash_gets(attrs, "path"); svn_boolean_t save_lock = FALSE; /* Filter out unwanted paths. Since Subversion only allows locks on files, we can treat depth=immediates the same as depth=files for filtering purposes. Meaning, we'll keep this lock if: a) its path is the very path we queried, or b) we've asked for a fully recursive answer, or c) we've asked for depth=files or depth=immediates, and this lock is on an immediate child of our query path. */ if (strcmp(lock_ctx->path, path) == 0 || lock_ctx->requested_depth == svn_depth_infinity) { save_lock = TRUE; } else if (lock_ctx->requested_depth == svn_depth_files || lock_ctx->requested_depth == svn_depth_immediates) { const char *relpath = svn_fspath__skip_ancestor(lock_ctx->path, path); if (relpath && (svn_path_component_count(relpath) == 1)) save_lock = TRUE; } if (save_lock) { /* We get to put the structure on the stack rather than using svn_lock_create(). Bwahahaha.... */ svn_lock_t lock = { 0 }; const char *date; svn_lock_t *result_lock; /* Note: these "attributes" came from child elements. Some of them may have not been sent, so the value will be NULL. */ lock.path = path; lock.token = svn_hash_gets(attrs, "token"); lock.owner = svn_hash_gets(attrs, "owner"); lock.comment = svn_hash_gets(attrs, "comment"); date = svn_hash_gets(attrs, SVN_DAV__CREATIONDATE); if (date) SVN_ERR(svn_time_from_cstring(&lock.creation_date, date, scratch_pool)); date = svn_hash_gets(attrs, "expirationdate"); if (date) SVN_ERR(svn_time_from_cstring(&lock.expiration_date, date, scratch_pool)); result_lock = svn_lock_dup(&lock, lock_ctx->pool); svn_hash_sets(lock_ctx->hash, result_lock->path, result_lock); } } else { const char *name; SVN_ERR_ASSERT(cdata != NULL); if (leaving_state == PATH) name = "path"; else if (leaving_state == TOKEN) name = "token"; else if (leaving_state == OWNER) name = "owner"; else if (leaving_state == COMMENT) name = "comment"; else if (leaving_state == CREATION_DATE) name = SVN_DAV__CREATIONDATE; else if (leaving_state == EXPIRATION_DATE) name = "expirationdate"; else SVN_ERR_MALFUNCTION(); /* Store the lock information onto the LOCK elemstate. */ svn_ra_serf__xml_note(xes, LOCK, name, cdata->data); } return SVN_NO_ERROR; }
/* Getting a directory's entries */ static svn_error_t * svn_ra_local__get_dir(svn_ra_session_t *session, apr_hash_t **dirents, svn_revnum_t *fetched_rev, apr_hash_t **props, const char *path, svn_revnum_t revision, apr_uint32_t dirent_fields, apr_pool_t *pool) { svn_fs_root_t *root; svn_revnum_t youngest_rev; apr_hash_t *entries; apr_hash_index_t *hi; svn_ra_local__session_baton_t *sess = session->priv; apr_pool_t *subpool; const char *abs_path = svn_path_join(sess->fs_path->data, path, pool); /* Open the revision's root. */ if (! SVN_IS_VALID_REVNUM(revision)) { SVN_ERR(svn_fs_youngest_rev(&youngest_rev, sess->fs, pool)); SVN_ERR(svn_fs_revision_root(&root, sess->fs, youngest_rev, pool)); if (fetched_rev != NULL) *fetched_rev = youngest_rev; } else SVN_ERR(svn_fs_revision_root(&root, sess->fs, revision, pool)); if (dirents) { /* Get the dir's entries. */ SVN_ERR(svn_fs_dir_entries(&entries, root, abs_path, pool)); /* Loop over the fs dirents, and build a hash of general svn_dirent_t's. */ *dirents = apr_hash_make(pool); subpool = svn_pool_create(pool); for (hi = apr_hash_first(pool, entries); hi; hi = apr_hash_next(hi)) { const void *key; void *val; apr_hash_t *prophash; const char *datestring, *entryname, *fullpath; svn_fs_dirent_t *fs_entry; svn_dirent_t *entry = apr_pcalloc(pool, sizeof(*entry)); svn_pool_clear(subpool); apr_hash_this(hi, &key, NULL, &val); entryname = (const char *) key; fs_entry = (svn_fs_dirent_t *) val; fullpath = svn_path_join(abs_path, entryname, subpool); if (dirent_fields & SVN_DIRENT_KIND) { /* node kind */ entry->kind = fs_entry->kind; } if (dirent_fields & SVN_DIRENT_SIZE) { /* size */ if (entry->kind == svn_node_dir) entry->size = 0; else SVN_ERR(svn_fs_file_length(&(entry->size), root, fullpath, subpool)); } if (dirent_fields & SVN_DIRENT_HAS_PROPS) { /* has_props? */ SVN_ERR(svn_fs_node_proplist(&prophash, root, fullpath, subpool)); entry->has_props = (apr_hash_count(prophash) != 0); } if ((dirent_fields & SVN_DIRENT_TIME) || (dirent_fields & SVN_DIRENT_LAST_AUTHOR) || (dirent_fields & SVN_DIRENT_CREATED_REV)) { /* created_rev & friends */ SVN_ERR(svn_repos_get_committed_info(&(entry->created_rev), &datestring, &(entry->last_author), root, fullpath, subpool)); if (datestring) SVN_ERR(svn_time_from_cstring(&(entry->time), datestring, pool)); if (entry->last_author) entry->last_author = apr_pstrdup(pool, entry->last_author); } /* Store. */ apr_hash_set(*dirents, entryname, APR_HASH_KEY_STRING, entry); } svn_pool_destroy(subpool); } /* Handle props if requested. */ if (props) SVN_ERR(get_node_props(props, sess, root, abs_path, pool)); return SVN_NO_ERROR; }
/* This implements the `svn_ra_neon__endelm_cb_t' prototype. */ static svn_error_t * getlocks_end_element(void *userdata, int state, const char *ns, const char *ln) { get_locks_baton_t *baton = userdata; const svn_ra_neon__xml_elm_t *elm; elm = svn_ra_neon__lookup_xml_elem(getlocks_report_elements, ns, ln); /* Just skip unknown elements. */ if (elm == NULL) return SVN_NO_ERROR; switch (elm->id) { case ELEM_lock: /* is the final svn_lock_t valid? all fields must be present except for 'comment' and 'expiration_date'. */ if ((! baton->current_lock->path) || (! baton->current_lock->token) || (! baton->current_lock->owner) || (! baton->current_lock->creation_date)) SVN_ERR(svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL, _("Incomplete lock data returned"))); /* Filter out unwanted paths. Since Subversion only allows locks on files, we can treat depth=immediates the same as depth=files for filtering purposes. Meaning, we'll keep this lock if: a) its path is the very path we queried, or b) we've asked for a fully recursive answer, or c) we've asked for depth=files or depth=immediates, and this lock is on an immediate child of our query path. */ if ((strcmp(baton->path, baton->current_lock->path) == 0) || (baton->requested_depth == svn_depth_infinity)) { apr_hash_set(baton->lock_hash, baton->current_lock->path, APR_HASH_KEY_STRING, baton->current_lock); } else if ((baton->requested_depth == svn_depth_files) || (baton->requested_depth == svn_depth_immediates)) { const char *rel_uri = svn_fspath__is_child(baton->path, baton->current_lock->path, baton->scratchpool); if (rel_uri && (svn_path_component_count(rel_uri) == 1)) apr_hash_set(baton->lock_hash, baton->current_lock->path, APR_HASH_KEY_STRING, baton->current_lock); svn_pool_clear(baton->scratchpool); } break; case ELEM_lock_path: /* neon has already xml-unescaped the cdata for us. */ baton->current_lock->path = svn_fspath__canonicalize(apr_pstrmemdup(baton->scratchpool, baton->cdata_accum->data, baton->cdata_accum->len), baton->pool); /* clean up the accumulator. */ svn_stringbuf_setempty(baton->cdata_accum); svn_pool_clear(baton->scratchpool); break; case ELEM_lock_token: /* neon has already xml-unescaped the cdata for us. */ baton->current_lock->token = apr_pstrmemdup(baton->pool, baton->cdata_accum->data, baton->cdata_accum->len); /* clean up the accumulator. */ svn_stringbuf_setempty(baton->cdata_accum); svn_pool_clear(baton->scratchpool); break; case ELEM_lock_creationdate: SVN_ERR(svn_time_from_cstring(&(baton->current_lock->creation_date), baton->cdata_accum->data, baton->scratchpool)); /* clean up the accumulator. */ svn_stringbuf_setempty(baton->cdata_accum); svn_pool_clear(baton->scratchpool); break; case ELEM_lock_expirationdate: SVN_ERR(svn_time_from_cstring(&(baton->current_lock->expiration_date), baton->cdata_accum->data, baton->scratchpool)); /* clean up the accumulator. */ svn_stringbuf_setempty(baton->cdata_accum); svn_pool_clear(baton->scratchpool); break; case ELEM_lock_owner: case ELEM_lock_comment: { const char *final_val; if (baton->encoding) { /* Possibly recognize other encodings someday. */ if (strcmp(baton->encoding, "base64") == 0) { svn_string_t *encoded_val; const svn_string_t *decoded_val; encoded_val = svn_string_create_from_buf(baton->cdata_accum, baton->scratchpool); decoded_val = svn_base64_decode_string(encoded_val, baton->scratchpool); final_val = decoded_val->data; } else return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL, _("Got unrecognized encoding '%s'"), baton->encoding); baton->encoding = NULL; } else { /* neon has already xml-unescaped the cdata for us. */ final_val = baton->cdata_accum->data; } if (elm->id == ELEM_lock_owner) baton->current_lock->owner = apr_pstrdup(baton->pool, final_val); if (elm->id == ELEM_lock_comment) baton->current_lock->comment = apr_pstrdup(baton->pool, final_val); /* clean up the accumulator. */ svn_stringbuf_setempty(baton->cdata_accum); svn_pool_clear(baton->scratchpool); break; } default: break; } return SVN_NO_ERROR; }
/* NOTE: this is used for upgrading old XML-based entries file. Be wary of removing items. ### many attributes are no longer used within the old-style log files. ### These attrs need to be recognized for old entries, however. For these ### cases, the code will parse the attribute, but not set *MODIFY_FLAGS ### for that particular field. MODIFY_FLAGS is *only* used by the ### log-based entry modification system, and will go way once we ### completely move away from loggy. Set *NEW_ENTRY to a new entry, taking attributes from ATTS, whose keys and values are both char *. Allocate the entry and copy attributes into POOL as needed. */ static svn_error_t * atts_to_entry(svn_wc_entry_t **new_entry, apr_hash_t *atts, apr_pool_t *pool) { svn_wc_entry_t *entry = alloc_entry(pool); const char *name; /* Find the name and set up the entry under that name. */ name = svn_hash_gets(atts, ENTRIES_ATTR_NAME); entry->name = name ? apr_pstrdup(pool, name) : SVN_WC_ENTRY_THIS_DIR; /* Attempt to set revision (resolve_to_defaults may do it later, too) ### not used by loggy; no need to set MODIFY_FLAGS */ { const char *revision_str = svn_hash_gets(atts, ENTRIES_ATTR_REVISION); if (revision_str) entry->revision = SVN_STR_TO_REV(revision_str); else entry->revision = SVN_INVALID_REVNUM; } /* Attempt to set up url path (again, see resolve_to_defaults). ### not used by loggy; no need to set MODIFY_FLAGS */ entry->url = extract_string(atts, ENTRIES_ATTR_URL, pool); if (entry->url) entry->url = svn_uri_canonicalize(entry->url, pool); /* Set up repository root. Make sure it is a prefix of url. ### not used by loggy; no need to set MODIFY_FLAGS */ entry->repos = extract_string(atts, ENTRIES_ATTR_REPOS, pool); if (entry->repos) entry->repos = svn_uri_canonicalize(entry->repos, pool); if (entry->url && entry->repos && !svn_uri__is_ancestor(entry->repos, entry->url)) return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL, _("Entry for '%s' has invalid repository " "root"), name ? name : SVN_WC_ENTRY_THIS_DIR); /* Set up kind. */ /* ### not used by loggy; no need to set MODIFY_FLAGS */ { const char *kindstr = svn_hash_gets(atts, ENTRIES_ATTR_KIND); entry->kind = svn_node_none; if (kindstr) { if (strcmp(kindstr, ENTRIES_VALUE_FILE) == 0) entry->kind = svn_node_file; else if (strcmp(kindstr, ENTRIES_VALUE_DIR) == 0) entry->kind = svn_node_dir; else return svn_error_createf (SVN_ERR_NODE_UNKNOWN_KIND, NULL, _("Entry '%s' has invalid node kind"), (name ? name : SVN_WC_ENTRY_THIS_DIR)); } } /* Look for a schedule attribute on this entry. */ /* ### not used by loggy; no need to set MODIFY_FLAGS */ { const char *schedulestr = svn_hash_gets(atts, ENTRIES_ATTR_SCHEDULE); entry->schedule = svn_wc_schedule_normal; if (schedulestr) { if (strcmp(schedulestr, ENTRIES_VALUE_ADD) == 0) entry->schedule = svn_wc_schedule_add; else if (strcmp(schedulestr, ENTRIES_VALUE_DELETE) == 0) entry->schedule = svn_wc_schedule_delete; else if (strcmp(schedulestr, ENTRIES_VALUE_REPLACE) == 0) entry->schedule = svn_wc_schedule_replace; else if (strcmp(schedulestr, "") == 0) entry->schedule = svn_wc_schedule_normal; else return svn_error_createf( SVN_ERR_ENTRY_ATTRIBUTE_INVALID, NULL, _("Entry '%s' has invalid 'schedule' value"), (name ? name : SVN_WC_ENTRY_THIS_DIR)); } } /* Is this entry in a state of mental torment (conflict)? */ entry->prejfile = extract_string_normalize(atts, ENTRIES_ATTR_PREJFILE, pool); entry->conflict_old = extract_string_normalize(atts, ENTRIES_ATTR_CONFLICT_OLD, pool); entry->conflict_new = extract_string_normalize(atts, ENTRIES_ATTR_CONFLICT_NEW, pool); entry->conflict_wrk = extract_string_normalize(atts, ENTRIES_ATTR_CONFLICT_WRK, pool); /* Is this entry copied? */ /* ### not used by loggy; no need to set MODIFY_FLAGS */ SVN_ERR(do_bool_attr(&entry->copied, atts, ENTRIES_ATTR_COPIED, name)); /* ### not used by loggy; no need to set MODIFY_FLAGS */ entry->copyfrom_url = extract_string(atts, ENTRIES_ATTR_COPYFROM_URL, pool); /* ### not used by loggy; no need to set MODIFY_FLAGS */ { const char *revstr; revstr = svn_hash_gets(atts, ENTRIES_ATTR_COPYFROM_REV); if (revstr) entry->copyfrom_rev = SVN_STR_TO_REV(revstr); } /* Is this entry deleted? ### not used by loggy; no need to set MODIFY_FLAGS */ SVN_ERR(do_bool_attr(&entry->deleted, atts, ENTRIES_ATTR_DELETED, name)); /* Is this entry absent? ### not used by loggy; no need to set MODIFY_FLAGS */ SVN_ERR(do_bool_attr(&entry->absent, atts, ENTRIES_ATTR_ABSENT, name)); /* Is this entry incomplete? ### not used by loggy; no need to set MODIFY_FLAGS */ SVN_ERR(do_bool_attr(&entry->incomplete, atts, ENTRIES_ATTR_INCOMPLETE, name)); /* Attempt to set up timestamps. */ /* ### not used by loggy; no need to set MODIFY_FLAGS */ { const char *text_timestr; text_timestr = svn_hash_gets(atts, ENTRIES_ATTR_TEXT_TIME); if (text_timestr) SVN_ERR(svn_time_from_cstring(&entry->text_time, text_timestr, pool)); /* Note: we do not persist prop_time, so there is no need to attempt to parse a new prop_time value from the log. Certainly, on any recent working copy, there will not be a log record to alter the prop_time value. */ } /* Checksum. */ /* ### not used by loggy; no need to set MODIFY_FLAGS */ entry->checksum = extract_string(atts, ENTRIES_ATTR_CHECKSUM, pool); /* UUID. ### not used by loggy; no need to set MODIFY_FLAGS */ entry->uuid = extract_string(atts, ENTRIES_ATTR_UUID, pool); /* Setup last-committed values. */ { const char *cmt_datestr, *cmt_revstr; cmt_datestr = svn_hash_gets(atts, ENTRIES_ATTR_CMT_DATE); if (cmt_datestr) { SVN_ERR(svn_time_from_cstring(&entry->cmt_date, cmt_datestr, pool)); } else entry->cmt_date = 0; cmt_revstr = svn_hash_gets(atts, ENTRIES_ATTR_CMT_REV); if (cmt_revstr) { entry->cmt_rev = SVN_STR_TO_REV(cmt_revstr); } else entry->cmt_rev = SVN_INVALID_REVNUM; entry->cmt_author = extract_string(atts, ENTRIES_ATTR_CMT_AUTHOR, pool); } /* ### not used by loggy; no need to set MODIFY_FLAGS */ entry->lock_token = extract_string(atts, ENTRIES_ATTR_LOCK_TOKEN, pool); entry->lock_owner = extract_string(atts, ENTRIES_ATTR_LOCK_OWNER, pool); entry->lock_comment = extract_string(atts, ENTRIES_ATTR_LOCK_COMMENT, pool); { const char *cdate_str = svn_hash_gets(atts, ENTRIES_ATTR_LOCK_CREATION_DATE); if (cdate_str) { SVN_ERR(svn_time_from_cstring(&entry->lock_creation_date, cdate_str, pool)); } } /* ----- end of lock handling. */ /* Note: if there are attributes for the (deprecated) has_props, has_prop_mods, cachable_props, or present_props, then we're just going to ignore them. */ /* Translated size */ /* ### not used by loggy; no need to set MODIFY_FLAGS */ { const char *val = svn_hash_gets(atts, ENTRIES_ATTR_WORKING_SIZE); if (val) { /* Cast to off_t; it's safe: we put in an off_t to start with... */ entry->working_size = (apr_off_t)apr_strtoi64(val, NULL, 0); } } *new_entry = entry; return SVN_NO_ERROR; }