Index: subversion/include/svn_types.h =================================================================== --- subversion/include/svn_types.h (revision 15206) +++ subversion/include/svn_types.h (working copy) @@ -188,31 +188,6 @@ svn_recursive }; - -/** A general subversion directory entry. */ -typedef struct svn_dirent_t -{ - /** node kind */ - svn_node_kind_t kind; - - /** length of file text, or 0 for directories */ - svn_filesize_t size; - - /** does the node have props? */ - svn_boolean_t has_props; - - /** last rev in which this node changed */ - svn_revnum_t created_rev; - - /** time of created_rev (mod-time) */ - apr_time_t time; - - /** author of created_rev */ - const char *last_author; - -} svn_dirent_t; - - /** Keyword substitution. @@ -458,6 +433,67 @@ svn_lock_t * svn_lock_dup (const svn_lock_t *lock, apr_pool_t *pool); + +/** + * A general subversion directory entry with lock information. + * + * @since New in 1.3. + */ +typedef struct svn_dirent2_t +{ + /** node kind */ + svn_node_kind_t kind; + + /** length of file text, or 0 for directories */ + svn_filesize_t size; + + /** does the node have props? */ + svn_boolean_t has_props; + + /** last rev in which this node changed */ + svn_revnum_t created_rev; + + /** time of created_rev (mod-time) */ + apr_time_t time; + + /** author of created_rev */ + const char *last_author; + + /** repository lock details, if present or NULL */ + svn_lock_t *lock; + +} svn_dirent2_t; + + +/** + * Similar to @c svn_dirent2_t except that @svn_dirent_t give only + * subversion directory entry. + * + * @deprecated Provided for backward compatibility with the 1.2 API. + */ +typedef struct svn_dirent_t +{ + /** node kind */ + svn_node_kind_t kind; + + /** length of file text, or 0 for directories */ + svn_filesize_t size; + + /** does the node have props? */ + svn_boolean_t has_props; + + /** last rev in which this node changed */ + svn_revnum_t created_rev; + + /** time of created_rev (mod-time) */ + apr_time_t time; + + /** author of created_rev */ + const char *last_author; + +} svn_dirent_t; + + #ifdef __cplusplus } #endif /* __cplusplus */ Index: subversion/libsvn_ra_local/ra_plugin.c =================================================================== --- subversion/libsvn_ra_local/ra_plugin.c (revision 15206) +++ subversion/libsvn_ra_local/ra_plugin.c (working copy) @@ -931,111 +931,7 @@ -/* Getting a directory's entries */ static svn_error_t * -svn_ra_local__get_dir (svn_ra_session_t *session, - const char *path, - svn_revnum_t revision, - apr_hash_t **dirents, - svn_revnum_t *fetched_rev, - apr_hash_t **props, - 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 *sbaton = session->priv; - const char *abs_path = sbaton->fs_path; - apr_pool_t *subpool; - - /* ### Not sure if this counts as a workaround or not. The - session baton uses the empty string to mean root, and not - sure that should change. However, it would be better to use - a path library function to add this separator -- hardcoding - it is totally bogus. See issue #559, though it may be only - tangentially related. */ - if (abs_path[0] == '\0') - abs_path = "/"; - - /* If we were given a relative path to append, append it. */ - if (path) - abs_path = svn_path_join (abs_path, path, pool); - - /* Open the revision's root. */ - if (! SVN_IS_VALID_REVNUM (revision)) - { - SVN_ERR (svn_fs_youngest_rev (&youngest_rev, sbaton->fs, pool)); - SVN_ERR (svn_fs_revision_root (&root, sbaton->fs, youngest_rev, pool)); - if (fetched_rev != NULL) - *fetched_rev = youngest_rev; - } - else - SVN_ERR (svn_fs_revision_root (&root, sbaton->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; - - /* node kind */ - fullpath = svn_path_join (abs_path, entryname, subpool); - entry->kind = fs_entry->kind; - - /* size */ - if (entry->kind == svn_node_dir) - entry->size = 0; - else - SVN_ERR (svn_fs_file_length (&(entry->size), root, - fullpath, subpool)); - - /* has_props? */ - SVN_ERR (svn_fs_node_proplist (&prophash, root, fullpath, subpool)); - entry->has_props = (apr_hash_count (prophash)) ? TRUE : FALSE; - - /* 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, sbaton, root, abs_path, pool)); - - return SVN_NO_ERROR; -} - -static svn_error_t * svn_ra_local__get_locations (svn_ra_session_t *session, apr_hash_t **locations, const char *relative_path, @@ -1215,7 +1111,112 @@ +/* Getting a directory's entries */ +static svn_error_t * +svn_ra_local__get_dir (svn_ra_session_t *session, + const char *path, + svn_revnum_t revision, + apr_hash_t **dirents, + svn_revnum_t *fetched_rev, + apr_hash_t **props, + 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 *sbaton = session->priv; + const char *abs_path = sbaton->fs_path; + apr_pool_t *subpool; + /* ### Not sure if this counts as a workaround or not. The + session baton uses the empty string to mean root, and not + sure that should change. However, it would be better to use + a path library function to add this separator -- hardcoding + it is totally bogus. See issue #559, though it may be only + tangentially related. */ + if (abs_path[0] == '\0') + abs_path = "/"; + + /* If we were given a relative path to append, append it. */ + if (path) + abs_path = svn_path_join (abs_path, path, pool); + + /* Open the revision's root. */ + if (! SVN_IS_VALID_REVNUM (revision)) + { + SVN_ERR (svn_fs_youngest_rev (&youngest_rev, sbaton->fs, pool)); + SVN_ERR (svn_fs_revision_root (&root, sbaton->fs, youngest_rev, pool)); + if (fetched_rev != NULL) + *fetched_rev = youngest_rev; + } + else + SVN_ERR (svn_fs_revision_root (&root, sbaton->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_dirent2_t *entry = apr_pcalloc (pool, sizeof(svn_dirent2_t)); + + svn_pool_clear (subpool); + + apr_hash_this (hi, &key, NULL, &val); + entryname = (const char *) key; + fs_entry = (svn_fs_dirent_t *) val; + + /* node kind */ + fullpath = svn_path_join (abs_path, entryname, subpool); + entry->kind = fs_entry->kind; + + /* size */ + if (entry->kind == svn_node_dir) + entry->size = 0; + else + SVN_ERR (svn_fs_file_length (&(entry->size), root, + fullpath, subpool)); + + /* has_props? */ + SVN_ERR (svn_fs_node_proplist (&prophash, root, fullpath, subpool)); + entry->has_props = (apr_hash_count (prophash)) ? TRUE : FALSE; + + /* 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); + + svn_ra_local__get_lock (session, &entry->lock, fullpath, pool); + + /* 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, sbaton, root, abs_path, pool)); + + return SVN_NO_ERROR; +} + /*----------------------------------------------------------------*/ static const svn_version_t * Index: subversion/clients/cmdline/ls-cmd.c =================================================================== --- subversion/clients/cmdline/ls-cmd.c (revision 15206) +++ subversion/clients/cmdline/ls-cmd.c (working copy) @@ -50,7 +50,8 @@ for (i = 0; i < array->nelts; ++i) { const char *utf8_entryname; - svn_dirent_t *dirent; + svn_dirent2_t *dirent; + svn_lock_t *lock; svn_sort__item_t *item; svn_pool_clear (subpool); @@ -63,15 +64,15 @@ utf8_entryname = item->key; dirent = apr_hash_get (dirents, utf8_entryname, item->klen); - + lock = dirent->lock; if (verbose) { apr_time_t now = apr_time_now(); apr_time_exp_t exp_time; apr_status_t apr_err; apr_size_t size; - char timestr[20]; - const char *sizestr, *utf8_timestr; + char timestr[20], lock_timestr[20]; + const char *sizestr, *utf8_timestr, *utf8_lock_timestr; /* svn_time_to_human_cstring gives us something *way* too long to use for this, so we have to roll our own. We include @@ -98,13 +99,42 @@ sizestr = apr_psprintf (subpool, "%" SVN_FILESIZE_T_FMT, dirent->size); + if (lock) + { + apr_time_exp_lt (&exp_time, lock->creation_date); + if (apr_time_sec + (now - lock->creation_date) < (365 * 86400 / 2) + && apr_time_sec + (lock->creation_date - now) < (365 * 86400 / 2)) + { + apr_err = apr_strftime (lock_timestr, &size, + sizeof (lock_timestr), + "%b %d %H:%M", &exp_time); + } + else + { + apr_err = apr_strftime (lock_timestr, &size, + sizeof (timestr), + "%b %d %Y", &exp_time); + } + /* if that failed, just zero out the string and print nothing */ + if (apr_err) + lock_timestr[0] = '\0'; + + /* we need it in UTF-8. */ + SVN_ERR (svn_utf_cstring_to_utf8 + (&utf8_lock_timestr, lock_timestr, subpool)); + } + SVN_ERR (svn_cmdline_printf - (subpool, "%7ld %-8.8s %10s %12s %s%s\n", + (subpool, "%7ld %-12s %10s %12s %12s %-12s %s%s\n", dirent->created_rev, dirent->last_author ? dirent->last_author : " ? ", (dirent->kind == svn_node_file) ? sizestr : "", utf8_timestr, + lock ? utf8_lock_timestr : "", + lock ? lock->owner : "", utf8_entryname, (dirent->kind == svn_node_dir) ? "/" : "")); } @@ -177,8 +207,9 @@ { svn_stringbuf_t *sb; const char *utf8_entryname; - svn_dirent_t *dirent; + svn_dirent2_t *dirent; svn_sort__item_t *item; + svn_lock_t* lock; svn_pool_clear (subpool); @@ -190,6 +221,7 @@ utf8_entryname = item->key; dirent = apr_hash_get (dirents, utf8_entryname, item->klen); + lock = dirent->lock; sb = svn_stringbuf_create ("", subpool); @@ -238,6 +270,49 @@ /* "" */ svn_xml_make_close_tag (&sb, subpool, "commit"); + /* "" */ + if (lock) + { + svn_xml_make_open_tag (&sb, pool, svn_xml_normal, "lock", NULL); + + svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata, + "token", NULL); + svn_xml_escape_cdata_cstring (&sb, lock->token, pool); + svn_xml_make_close_tag (&sb, pool, "token"); + + svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata, + "owner", NULL); + svn_xml_escape_cdata_cstring (&sb, lock->owner, pool); + svn_xml_make_close_tag (&sb, pool, "owner"); + + if (lock->comment) + { + svn_xml_make_open_tag (&sb, pool, svn_xml_normal, + "comment", NULL); + svn_xml_escape_cdata_cstring (&sb, lock->comment, pool); + svn_xml_make_close_tag (&sb, pool, "comment"); + } + + svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata, + "created", NULL); + svn_xml_escape_cdata_cstring (&sb, svn_time_to_cstring + (lock->creation_date, pool), + pool); + svn_xml_make_close_tag (&sb, pool, "created"); + + if (lock->expiration_date != 0) + { + svn_xml_make_open_tag (&sb, pool, svn_xml_protect_pcdata, + "expires", NULL); + svn_xml_escape_cdata_cstring (&sb, svn_time_to_cstring + (lock->expiration_date, pool), + pool); + svn_xml_make_close_tag (&sb, pool, "expires"); + } + + /* "" */ + svn_xml_make_close_tag (&sb, subpool, "lock"); + } /* "" */ svn_xml_make_close_tag (&sb, subpool, "entry"); @@ -325,7 +400,6 @@ SVN_ERR (svn_client_ls2 (&dirents, truepath, &peg_revision, &(opt_state->start_revision), opt_state->recursive, ctx, subpool)); - if (opt_state->xml) SVN_ERR (print_dirents_xml (dirents, truepath, ctx, subpool)); else Index: subversion/clients/cmdline/main.c =================================================================== --- subversion/clients/cmdline/main.c (revision 15206) +++ subversion/clients/cmdline/main.c (working copy) @@ -379,12 +379,14 @@ "current\n" " working directory.\n" "\n" - " With --verbose, the following fields show the status of the item:\n" + " With --verbose, the following fields will be shown for each item:\n" "\n" " Revision number of the last commit\n" " Author of the last commit\n" " Size (in bytes)\n" - " Date and time of the last commit\n"), + " Date and time of the last commit\n" + " Date and time of the lock creation\n" + " Owner of the lock\n"), {'r', 'v', 'R', svn_cl__incremental_opt, svn_cl__xml_opt, SVN_CL__AUTH_OPTIONS, svn_cl__config_dir_opt} }, Index: subversion/clients/cmdline/dtd/list.dtd =================================================================== --- subversion/clients/cmdline/dtd/list.dtd (revision 15206) +++ subversion/clients/cmdline/dtd/list.dtd (working copy) @@ -8,9 +8,16 @@ - + + + + + + + + Index: subversion/libsvn_ra_svn/client.c =================================================================== --- subversion/libsvn_ra_svn/client.c (revision 15206) +++ subversion/libsvn_ra_svn/client.c (working copy) @@ -918,64 +918,6 @@ return SVN_NO_ERROR; } -static svn_error_t *ra_svn_get_dir(svn_ra_session_t *session, const char *path, - svn_revnum_t rev, apr_hash_t **dirents, - svn_revnum_t *fetched_rev, - apr_hash_t **props, - apr_pool_t *pool) -{ - ra_svn_session_baton_t *sess_baton = session->priv; - svn_ra_svn_conn_t *conn = sess_baton->conn; - svn_revnum_t crev; - apr_array_header_t *proplist, *dirlist; - int i; - svn_ra_svn_item_t *elt; - const char *name, *kind, *cdate, *cauthor; - svn_boolean_t has_props; - apr_uint64_t size; - svn_dirent_t *dirent; - - SVN_ERR(svn_ra_svn_write_cmd(conn, pool, "get-dir", "c(?r)bb", path, - rev, (props != NULL), (dirents != NULL))); - SVN_ERR(handle_auth_request(sess_baton, pool)); - SVN_ERR(svn_ra_svn_read_cmd_response(conn, pool, "rll", &rev, &proplist, - &dirlist)); - - if (fetched_rev) - *fetched_rev = rev; - if (props) - SVN_ERR(parse_proplist(proplist, pool, props)); - - /* We're done if dirents aren't wanted. */ - if (!dirents) - return SVN_NO_ERROR; - - /* Interpret the directory list. */ - *dirents = apr_hash_make(pool); - for (i = 0; i < dirlist->nelts; i++) - { - elt = &((svn_ra_svn_item_t *) dirlist->elts)[i]; - if (elt->kind != SVN_RA_SVN_LIST) - return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, - _("Dirlist element not a list")); - SVN_ERR(svn_ra_svn_parse_tuple(elt->u.list, pool, "cwnbr(?c)(?c)", - &name, &kind, &size, &has_props, - &crev, &cdate, &cauthor)); - name = svn_path_canonicalize(name, pool); - dirent = apr_palloc(pool, sizeof(*dirent)); - SVN_ERR(interpret_kind(kind, pool, &dirent->kind)); - dirent->size = size;/* FIXME: svn_filesize_t */ - dirent->has_props = has_props; - dirent->created_rev = crev; - SVN_ERR(svn_time_from_cstring(&dirent->time, cdate, pool)); - dirent->last_author = cauthor; - apr_hash_set(*dirents, name, APR_HASH_KEY_STRING, dirent); - } - - return SVN_NO_ERROR; -} - - static svn_error_t *ra_svn_update(svn_ra_session_t *session, const svn_ra_reporter2_t **reporter, void **report_baton, svn_revnum_t rev, @@ -1579,7 +1521,66 @@ return SVN_NO_ERROR; } +static svn_error_t *ra_svn_get_dir(svn_ra_session_t *session, const char *path, + svn_revnum_t rev, apr_hash_t **dirents, + svn_revnum_t *fetched_rev, + apr_hash_t **props, + apr_pool_t *pool) +{ + ra_svn_session_baton_t *sess_baton = session->priv; + svn_ra_svn_conn_t *conn = sess_baton->conn; + svn_revnum_t crev; + apr_array_header_t *proplist, *dirlist; + int i; + svn_ra_svn_item_t *elt; + const char *name, *kind, *cdate, *cauthor; + svn_boolean_t has_props; + apr_uint64_t size; + svn_dirent2_t *dirent; + SVN_ERR(svn_ra_svn_write_cmd(conn, pool, "get-dir", "c(?r)bb", path, + rev, (props != NULL), (dirents != NULL))); + SVN_ERR(handle_auth_request(sess_baton, pool)); + SVN_ERR(svn_ra_svn_read_cmd_response(conn, pool, "rll", &rev, &proplist, + &dirlist)); + + if (fetched_rev) + *fetched_rev = rev; + if (props) + SVN_ERR(parse_proplist(proplist, pool, props)); + + /* We're done if dirents aren't wanted. */ + if (!dirents) + return SVN_NO_ERROR; + + /* Interpret the directory list. */ + *dirents = apr_hash_make(pool); + for (i = 0; i < dirlist->nelts; i++) + { + elt = &((svn_ra_svn_item_t *) dirlist->elts)[i]; + if (elt->kind != SVN_RA_SVN_LIST) + return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, + _("Dirlist element not a list")); + SVN_ERR(svn_ra_svn_parse_tuple(elt->u.list, pool, "cwnbr(?c)(?c)", + &name, &kind, &size, &has_props, + &crev, &cdate, &cauthor)); + name = svn_path_canonicalize(name, pool); + dirent = apr_palloc(pool, sizeof(*dirent)); + SVN_ERR(interpret_kind(kind, pool, &dirent->kind)); + dirent->size = size;/* FIXME: svn_filesize_t */ + dirent->has_props = has_props; + dirent->created_rev = crev; + SVN_ERR(svn_time_from_cstring(&dirent->time, cdate, pool)); + dirent->last_author = cauthor; + + ra_svn_get_lock(session, &dirent->lock, path, pool); + + apr_hash_set(*dirents, name, APR_HASH_KEY_STRING, dirent); + } + + return SVN_NO_ERROR; +} + static const svn_ra__vtable_t ra_svn_vtable = { svn_ra_svn_version, ra_svn_get_description, Index: subversion/libsvn_ra_dav/fetch.c =================================================================== --- subversion/libsvn_ra_dav/fetch.c (revision 15206) +++ subversion/libsvn_ra_dav/fetch.c (working copy) @@ -980,7 +980,7 @@ svn_ra_dav_resource_t *resource; const svn_string_t *propval; apr_hash_index_t *h; - svn_dirent_t *entry; + svn_dirent2_t *entry; apr_hash_this (hi, &key, NULL, &val); childname = key; @@ -1044,7 +1044,9 @@ APR_HASH_KEY_STRING); if (propval != NULL) entry->last_author = propval->data; - + + svn_ra_dav__get_lock(session, &entry->lock, final_url, pool); + apr_hash_set(*dirents, svn_path_uri_decode(svn_path_basename(childname, pool), pool),