1289177Speter/*
2289177Speter * stat.c :  file and directory stat and read functions
3289177Speter *
4289177Speter * ====================================================================
5289177Speter *    Licensed to the Apache Software Foundation (ASF) under one
6289177Speter *    or more contributor license agreements.  See the NOTICE file
7289177Speter *    distributed with this work for additional information
8289177Speter *    regarding copyright ownership.  The ASF licenses this file
9289177Speter *    to you under the Apache License, Version 2.0 (the
10289177Speter *    "License"); you may not use this file except in compliance
11289177Speter *    with the License.  You may obtain a copy of the License at
12289177Speter *
13289177Speter *      http://www.apache.org/licenses/LICENSE-2.0
14289177Speter *
15289177Speter *    Unless required by applicable law or agreed to in writing,
16289177Speter *    software distributed under the License is distributed on an
17289177Speter *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18289177Speter *    KIND, either express or implied.  See the License for the
19289177Speter *    specific language governing permissions and limitations
20289177Speter *    under the License.
21289177Speter * ====================================================================
22289177Speter */
23289177Speter
24289177Speter
25289177Speter
26289177Speter#define APR_WANT_STRFUNC
27289177Speter#include <apr_want.h>
28289177Speter
29289177Speter#include <serf.h>
30289177Speter
31289177Speter#include "svn_private_config.h"
32289177Speter#include "svn_pools.h"
33289177Speter#include "svn_xml.h"
34289177Speter#include "../libsvn_ra/ra_loader.h"
35289177Speter#include "svn_config.h"
36289177Speter#include "svn_dirent_uri.h"
37289177Speter#include "svn_hash.h"
38289177Speter#include "svn_path.h"
39289177Speter#include "svn_props.h"
40289177Speter#include "svn_time.h"
41289177Speter#include "svn_version.h"
42289177Speter
43289177Speter#include "private/svn_dav_protocol.h"
44289177Speter#include "private/svn_dep_compat.h"
45289177Speter#include "private/svn_fspath.h"
46289177Speter
47289177Speter#include "ra_serf.h"
48289177Speter
49289177Speter
50289177Speter
51289177Speter/* Implements svn_ra__vtable_t.check_path(). */
52289177Spetersvn_error_t *
53289177Spetersvn_ra_serf__check_path(svn_ra_session_t *ra_session,
54289177Speter                        const char *relpath,
55289177Speter                        svn_revnum_t revision,
56289177Speter                        svn_node_kind_t *kind,
57289177Speter                        apr_pool_t *scratch_pool)
58289177Speter{
59289177Speter  svn_ra_serf__session_t *session = ra_session->priv;
60289177Speter  apr_hash_t *props;
61289177Speter  svn_error_t *err;
62289177Speter  const char *url;
63289177Speter
64289177Speter  url = session->session_url.path;
65289177Speter
66289177Speter  /* If we have a relative path, append it. */
67289177Speter  if (relpath)
68289177Speter    url = svn_path_url_add_component2(url, relpath, scratch_pool);
69289177Speter
70289177Speter  /* If we were given a specific revision, get a URL that refers to that
71289177Speter     specific revision (rather than floating with HEAD).  */
72289177Speter  if (SVN_IS_VALID_REVNUM(revision))
73289177Speter    {
74289177Speter      SVN_ERR(svn_ra_serf__get_stable_url(&url, NULL /* latest_revnum */,
75289177Speter                                          session,
76289177Speter                                          url, revision,
77289177Speter                                          scratch_pool, scratch_pool));
78289177Speter    }
79289177Speter
80289177Speter  /* URL is stable, so we use SVN_INVALID_REVNUM since it is now irrelevant.
81289177Speter     Or we started with SVN_INVALID_REVNUM and URL may be floating.  */
82289177Speter  err = svn_ra_serf__fetch_node_props(&props, session,
83289177Speter                                      url, SVN_INVALID_REVNUM,
84289177Speter                                      check_path_props,
85289177Speter                                      scratch_pool, scratch_pool);
86289177Speter
87289177Speter  if (err && err->apr_err == SVN_ERR_FS_NOT_FOUND)
88289177Speter    {
89289177Speter      svn_error_clear(err);
90289177Speter      *kind = svn_node_none;
91289177Speter    }
92289177Speter  else
93289177Speter    {
94289177Speter      apr_hash_t *dav_props;
95289177Speter      const char *res_type;
96289177Speter
97289177Speter      /* Any other error, raise to caller. */
98289177Speter      SVN_ERR(err);
99289177Speter
100289177Speter      dav_props = apr_hash_get(props, "DAV:", 4);
101289177Speter      res_type = svn_prop_get_value(dav_props, "resourcetype");
102289177Speter      if (!res_type)
103289177Speter        {
104289177Speter          /* How did this happen? */
105289177Speter          return svn_error_create(SVN_ERR_RA_DAV_PROPS_NOT_FOUND, NULL,
106289177Speter                                 _("The PROPFIND response did not include the "
107289177Speter                                   "requested resourcetype value"));
108289177Speter        }
109289177Speter
110289177Speter      if (strcmp(res_type, "collection") == 0)
111289177Speter        *kind = svn_node_dir;
112289177Speter      else
113289177Speter        *kind = svn_node_file;
114289177Speter    }
115289177Speter
116289177Speter  return SVN_NO_ERROR;
117289177Speter}
118289177Speter
119289177Speter
120289177Speter/* Baton for fill_dirent_propfunc() */
121289177Speterstruct fill_dirent_baton_t
122289177Speter{
123289177Speter  /* Update the fields in this entry.  */
124289177Speter  svn_dirent_t *entry;
125289177Speter
126289177Speter  svn_tristate_t *supports_deadprop_count;
127289177Speter
128289177Speter  /* If allocations are necessary, then use this pool.  */
129289177Speter  apr_pool_t *result_pool;
130289177Speter};
131289177Speter
132289177Speter/* Implements svn_ra_serf__prop_func_t */
133289177Speterstatic svn_error_t *
134289177Speterfill_dirent_propfunc(void *baton,
135289177Speter                     const char *path,
136289177Speter                     const char *ns,
137289177Speter                     const char *name,
138289177Speter                     const svn_string_t *val,
139289177Speter                     apr_pool_t *scratch_pool)
140289177Speter{
141289177Speter  struct fill_dirent_baton_t *fdb = baton;
142289177Speter
143289177Speter  if (strcmp(ns, "DAV:") == 0)
144289177Speter    {
145289177Speter      if (strcmp(name, SVN_DAV__VERSION_NAME) == 0)
146289177Speter        {
147289177Speter          apr_int64_t rev;
148289177Speter          SVN_ERR(svn_cstring_atoi64(&rev, val->data));
149289177Speter
150289177Speter          fdb->entry->created_rev = (svn_revnum_t)rev;
151289177Speter        }
152289177Speter      else if (strcmp(name, "creator-displayname") == 0)
153289177Speter        {
154289177Speter          fdb->entry->last_author = apr_pstrdup(fdb->result_pool, val->data);
155289177Speter        }
156289177Speter      else if (strcmp(name, SVN_DAV__CREATIONDATE) == 0)
157289177Speter        {
158289177Speter          SVN_ERR(svn_time_from_cstring(&fdb->entry->time,
159289177Speter                                        val->data,
160289177Speter                                        fdb->result_pool));
161289177Speter        }
162289177Speter      else if (strcmp(name, "getcontentlength") == 0)
163289177Speter        {
164289177Speter          /* 'getcontentlength' property is empty for directories. */
165289177Speter          if (val->len)
166289177Speter            {
167289177Speter              SVN_ERR(svn_cstring_atoi64(&fdb->entry->size, val->data));
168289177Speter            }
169289177Speter        }
170289177Speter      else if (strcmp(name, "resourcetype") == 0)
171289177Speter        {
172289177Speter          if (strcmp(val->data, "collection") == 0)
173289177Speter            {
174289177Speter              fdb->entry->kind = svn_node_dir;
175289177Speter            }
176289177Speter          else
177289177Speter            {
178289177Speter              fdb->entry->kind = svn_node_file;
179289177Speter            }
180289177Speter        }
181289177Speter    }
182289177Speter  else if (strcmp(ns, SVN_DAV_PROP_NS_CUSTOM) == 0)
183289177Speter    {
184289177Speter      fdb->entry->has_props = TRUE;
185289177Speter    }
186289177Speter  else if (strcmp(ns, SVN_DAV_PROP_NS_SVN) == 0)
187289177Speter    {
188289177Speter      fdb->entry->has_props = TRUE;
189289177Speter    }
190289177Speter  else if (strcmp(ns, SVN_DAV_PROP_NS_DAV) == 0)
191289177Speter    {
192289177Speter      if(strcmp(name, "deadprop-count") == 0)
193289177Speter        {
194289177Speter          if (*val->data)
195289177Speter            {
196289177Speter              apr_int64_t deadprop_count;
197289177Speter              SVN_ERR(svn_cstring_atoi64(&deadprop_count, val->data));
198289177Speter              fdb->entry->has_props = deadprop_count > 0;
199289177Speter              if (fdb->supports_deadprop_count)
200289177Speter                *fdb->supports_deadprop_count = svn_tristate_true;
201289177Speter            }
202289177Speter          else if (fdb->supports_deadprop_count)
203289177Speter            *fdb->supports_deadprop_count = svn_tristate_false;
204289177Speter        }
205289177Speter    }
206289177Speter
207289177Speter  return SVN_NO_ERROR;
208289177Speter}
209289177Speter
210289177Speterstatic const svn_ra_serf__dav_props_t *
211289177Speterget_dirent_props(apr_uint32_t dirent_fields,
212289177Speter                 svn_ra_serf__session_t *session,
213289177Speter                 apr_pool_t *pool)
214289177Speter{
215289177Speter  svn_ra_serf__dav_props_t *prop;
216289177Speter  apr_array_header_t *props = apr_array_make
217289177Speter    (pool, 7, sizeof(svn_ra_serf__dav_props_t));
218289177Speter
219289177Speter  if (session->supports_deadprop_count != svn_tristate_false
220289177Speter      || ! (dirent_fields & SVN_DIRENT_HAS_PROPS))
221289177Speter    {
222289177Speter      if (dirent_fields & SVN_DIRENT_KIND)
223289177Speter        {
224289177Speter          prop = apr_array_push(props);
225289177Speter          prop->xmlns = "DAV:";
226289177Speter          prop->name = "resourcetype";
227289177Speter        }
228289177Speter
229289177Speter      if (dirent_fields & SVN_DIRENT_SIZE)
230289177Speter        {
231289177Speter          prop = apr_array_push(props);
232289177Speter          prop->xmlns = "DAV:";
233289177Speter          prop->name = "getcontentlength";
234289177Speter        }
235289177Speter
236289177Speter      if (dirent_fields & SVN_DIRENT_HAS_PROPS)
237289177Speter        {
238289177Speter          prop = apr_array_push(props);
239289177Speter          prop->xmlns = SVN_DAV_PROP_NS_DAV;
240289177Speter          prop->name = "deadprop-count";
241289177Speter        }
242289177Speter
243289177Speter      if (dirent_fields & SVN_DIRENT_CREATED_REV)
244289177Speter        {
245289177Speter          svn_ra_serf__dav_props_t *p = apr_array_push(props);
246289177Speter          p->xmlns = "DAV:";
247289177Speter          p->name = SVN_DAV__VERSION_NAME;
248289177Speter        }
249289177Speter
250289177Speter      if (dirent_fields & SVN_DIRENT_TIME)
251289177Speter        {
252289177Speter          prop = apr_array_push(props);
253289177Speter          prop->xmlns = "DAV:";
254289177Speter          prop->name = SVN_DAV__CREATIONDATE;
255289177Speter        }
256289177Speter
257289177Speter      if (dirent_fields & SVN_DIRENT_LAST_AUTHOR)
258289177Speter        {
259289177Speter          prop = apr_array_push(props);
260289177Speter          prop->xmlns = "DAV:";
261289177Speter          prop->name = "creator-displayname";
262289177Speter        }
263289177Speter    }
264289177Speter  else
265289177Speter    {
266289177Speter      /* We found an old subversion server that can't handle
267289177Speter         the deadprop-count property in the way we expect.
268289177Speter
269289177Speter         The neon behavior is to retrieve all properties in this case */
270289177Speter      prop = apr_array_push(props);
271289177Speter      prop->xmlns = "DAV:";
272289177Speter      prop->name = "allprop";
273289177Speter    }
274289177Speter
275289177Speter  prop = apr_array_push(props);
276289177Speter  prop->xmlns = NULL;
277289177Speter  prop->name = NULL;
278289177Speter
279289177Speter  return (svn_ra_serf__dav_props_t *) props->elts;
280289177Speter}
281289177Speter
282289177Speter/* Implements svn_ra__vtable_t.stat(). */
283289177Spetersvn_error_t *
284289177Spetersvn_ra_serf__stat(svn_ra_session_t *ra_session,
285289177Speter                  const char *relpath,
286289177Speter                  svn_revnum_t revision,
287289177Speter                  svn_dirent_t **dirent,
288289177Speter                  apr_pool_t *pool)
289289177Speter{
290289177Speter  svn_ra_serf__session_t *session = ra_session->priv;
291289177Speter  svn_error_t *err;
292289177Speter  struct fill_dirent_baton_t fdb;
293289177Speter  svn_tristate_t deadprop_count = svn_tristate_unknown;
294289177Speter  svn_ra_serf__handler_t *handler;
295289177Speter  const char *url;
296289177Speter
297289177Speter  url = session->session_url.path;
298289177Speter
299289177Speter  /* If we have a relative path, append it. */
300289177Speter  if (relpath)
301289177Speter    url = svn_path_url_add_component2(url, relpath, pool);
302289177Speter
303289177Speter  /* If we were given a specific revision, get a URL that refers to that
304289177Speter     specific revision (rather than floating with HEAD).  */
305289177Speter  if (SVN_IS_VALID_REVNUM(revision))
306289177Speter    {
307289177Speter      SVN_ERR(svn_ra_serf__get_stable_url(&url, NULL /* latest_revnum */,
308289177Speter                                          session,
309289177Speter                                          url, revision,
310289177Speter                                          pool, pool));
311289177Speter    }
312289177Speter
313289177Speter  fdb.entry = svn_dirent_create(pool);
314289177Speter  fdb.supports_deadprop_count = &deadprop_count;
315289177Speter  fdb.result_pool = pool;
316289177Speter
317289177Speter  SVN_ERR(svn_ra_serf__create_propfind_handler(&handler, session, url,
318289177Speter                                               SVN_INVALID_REVNUM, "0",
319289177Speter                                               get_dirent_props(SVN_DIRENT_ALL,
320289177Speter                                                                session,
321289177Speter                                                                pool),
322289177Speter                                               fill_dirent_propfunc, &fdb, pool));
323289177Speter
324289177Speter  err = svn_ra_serf__context_run_one(handler, pool);
325289177Speter
326289177Speter  if (err)
327289177Speter    {
328289177Speter      if (err->apr_err == SVN_ERR_FS_NOT_FOUND)
329289177Speter        {
330289177Speter          svn_error_clear(err);
331289177Speter          *dirent = NULL;
332289177Speter          return SVN_NO_ERROR;
333289177Speter        }
334289177Speter      else
335289177Speter        return svn_error_trace(err);
336289177Speter    }
337289177Speter
338289177Speter  if (deadprop_count == svn_tristate_false
339289177Speter      && session->supports_deadprop_count == svn_tristate_unknown
340289177Speter      && !fdb.entry->has_props)
341289177Speter    {
342289177Speter      /* We have to requery as the server didn't give us the right
343289177Speter         information */
344289177Speter      session->supports_deadprop_count = svn_tristate_false;
345289177Speter
346289177Speter      /* Run the same handler again */
347289177Speter      SVN_ERR(svn_ra_serf__context_run_one(handler, pool));
348289177Speter    }
349289177Speter
350289177Speter  if (deadprop_count != svn_tristate_unknown)
351289177Speter    session->supports_deadprop_count = deadprop_count;
352289177Speter
353289177Speter  *dirent = fdb.entry;
354289177Speter
355289177Speter  return SVN_NO_ERROR;
356289177Speter}
357289177Speter
358289177Speter/* Baton for get_dir_dirents_cb and get_dir_props_cb */
359289177Speterstruct get_dir_baton_t
360289177Speter{
361289177Speter  apr_pool_t *result_pool;
362289177Speter  apr_hash_t *dirents;
363289177Speter  apr_hash_t *ret_props;
364289177Speter  svn_boolean_t is_directory;
365289177Speter  svn_tristate_t supports_deadprop_count;
366289177Speter  const char *path;
367289177Speter};
368289177Speter
369289177Speter/* Implements svn_ra_serf__prop_func_t */
370289177Speterstatic svn_error_t *
371289177Speterget_dir_dirents_cb(void *baton,
372289177Speter                   const char *path,
373289177Speter                   const char *ns,
374289177Speter                   const char *name,
375289177Speter                   const svn_string_t *value,
376289177Speter                   apr_pool_t *scratch_pool)
377289177Speter{
378289177Speter  struct get_dir_baton_t *db = baton;
379289177Speter  const char *relpath;
380289177Speter
381289177Speter  relpath = svn_fspath__skip_ancestor(db->path, path);
382289177Speter
383289177Speter  if (relpath && relpath[0] != '\0')
384289177Speter    {
385289177Speter      struct fill_dirent_baton_t fdb;
386289177Speter
387289177Speter      relpath = svn_path_uri_decode(relpath, scratch_pool);
388289177Speter      fdb.entry = svn_hash_gets(db->dirents, relpath);
389289177Speter
390289177Speter      if (!fdb.entry)
391289177Speter        {
392289177Speter          fdb.entry = svn_dirent_create(db->result_pool);
393289177Speter          svn_hash_sets(db->dirents,
394289177Speter                        apr_pstrdup(db->result_pool, relpath),
395289177Speter                        fdb.entry);
396289177Speter        }
397289177Speter
398289177Speter      fdb.result_pool = db->result_pool;
399289177Speter      fdb.supports_deadprop_count = &db->supports_deadprop_count;
400289177Speter      SVN_ERR(fill_dirent_propfunc(&fdb, path, ns, name, value, scratch_pool));
401289177Speter    }
402289177Speter  else if (relpath && !db->is_directory)
403289177Speter    {
404289177Speter      if (strcmp(ns, "DAV:") == 0 && strcmp(name, "resourcetype") == 0)
405289177Speter        {
406289177Speter          if (strcmp(value->data, "collection") != 0)
407289177Speter            {
408289177Speter              /* Tell a lie to exit early */
409289177Speter              return svn_error_create(SVN_ERR_FS_NOT_DIRECTORY, NULL,
410289177Speter                                      _("Can't get properties of non-directory"));
411289177Speter            }
412289177Speter          else
413289177Speter            db->is_directory = TRUE;
414289177Speter        }
415289177Speter    }
416289177Speter
417289177Speter  return SVN_NO_ERROR;
418289177Speter}
419289177Speter
420289177Speter/* Implements svn_ra_serf__prop_func */
421289177Speterstatic svn_error_t *
422289177Speterget_dir_props_cb(void *baton,
423289177Speter                 const char *path,
424289177Speter                 const char *ns,
425289177Speter                 const char *name,
426289177Speter                 const svn_string_t *value,
427289177Speter                 apr_pool_t *scratch_pool)
428289177Speter{
429289177Speter  struct get_dir_baton_t *db = baton;
430289177Speter  const char *propname;
431289177Speter
432289177Speter  propname = svn_ra_serf__svnname_from_wirename(ns, name, db->result_pool);
433289177Speter  if (propname)
434289177Speter    {
435289177Speter      svn_hash_sets(db->ret_props, propname,
436289177Speter                    svn_string_dup(value, db->result_pool));
437289177Speter      return SVN_NO_ERROR;
438289177Speter    }
439289177Speter
440289177Speter  if (!db->is_directory)
441289177Speter    {
442289177Speter      if (strcmp(ns, "DAV:") == 0 && strcmp(name, "resourcetype") == 0)
443289177Speter        {
444289177Speter          if (strcmp(value->data, "collection") != 0)
445289177Speter            {
446289177Speter              /* Tell a lie to exit early */
447289177Speter              return svn_error_create(SVN_ERR_FS_NOT_DIRECTORY, NULL,
448289177Speter                                      _("Can't get properties of non-directory"));
449289177Speter            }
450289177Speter          else
451289177Speter            db->is_directory = TRUE;
452289177Speter        }
453289177Speter    }
454289177Speter
455289177Speter  return SVN_NO_ERROR;
456289177Speter}
457289177Speter
458289177Speter/* Implements svn_ra__vtable_t.get_dir(). */
459289177Spetersvn_error_t *
460289177Spetersvn_ra_serf__get_dir(svn_ra_session_t *ra_session,
461289177Speter                     apr_hash_t **dirents,
462289177Speter                     svn_revnum_t *fetched_rev,
463289177Speter                     apr_hash_t **ret_props,
464289177Speter                     const char *rel_path,
465289177Speter                     svn_revnum_t revision,
466289177Speter                     apr_uint32_t dirent_fields,
467289177Speter                     apr_pool_t *result_pool)
468289177Speter{
469289177Speter  svn_ra_serf__session_t *session = ra_session->priv;
470289177Speter  apr_pool_t *scratch_pool = svn_pool_create(result_pool);
471289177Speter  svn_ra_serf__handler_t *dirent_handler = NULL;
472289177Speter  svn_ra_serf__handler_t *props_handler = NULL;
473289177Speter  const char *path;
474289177Speter  struct get_dir_baton_t gdb;
475289177Speter  svn_error_t *err = SVN_NO_ERROR;
476289177Speter
477289177Speter  gdb.result_pool = result_pool;
478289177Speter  gdb.is_directory = FALSE;
479289177Speter  gdb.supports_deadprop_count = svn_tristate_unknown;
480289177Speter
481289177Speter  path = session->session_url.path;
482289177Speter
483289177Speter  /* If we have a relative path, URI encode and append it. */
484289177Speter  if (rel_path)
485289177Speter    {
486289177Speter      path = svn_path_url_add_component2(path, rel_path, scratch_pool);
487289177Speter    }
488289177Speter
489289177Speter  /* If the user specified a peg revision other than HEAD, we have to fetch
490289177Speter     the baseline collection url for that revision. If not, we can use the
491289177Speter     public url. */
492289177Speter  if (SVN_IS_VALID_REVNUM(revision) || fetched_rev)
493289177Speter    {
494289177Speter      SVN_ERR(svn_ra_serf__get_stable_url(&path, fetched_rev,
495289177Speter                                          session,
496289177Speter                                          path, revision,
497289177Speter                                          scratch_pool, scratch_pool));
498289177Speter      revision = SVN_INVALID_REVNUM;
499289177Speter    }
500289177Speter  /* REVISION is always SVN_INVALID_REVNUM  */
501289177Speter  SVN_ERR_ASSERT(!SVN_IS_VALID_REVNUM(revision));
502289177Speter
503289177Speter  gdb.path = path;
504289177Speter
505289177Speter  /* If we're asked for children, fetch them now. */
506289177Speter  if (dirents)
507289177Speter    {
508289177Speter      /* Always request node kind to check that path is really a
509289177Speter       * directory. */
510289177Speter      if (!ret_props)
511289177Speter        dirent_fields |= SVN_DIRENT_KIND;
512289177Speter
513289177Speter      gdb.dirents = apr_hash_make(result_pool);
514289177Speter
515289177Speter      SVN_ERR(svn_ra_serf__create_propfind_handler(
516289177Speter                                          &dirent_handler, session,
517289177Speter                                          path, SVN_INVALID_REVNUM, "1",
518289177Speter                                          get_dirent_props(dirent_fields,
519289177Speter                                                           session,
520289177Speter                                                           scratch_pool),
521289177Speter                                          get_dir_dirents_cb, &gdb,
522289177Speter                                          scratch_pool));
523289177Speter
524289177Speter      svn_ra_serf__request_create(dirent_handler);
525289177Speter    }
526289177Speter  else
527289177Speter    gdb.dirents = NULL;
528289177Speter
529289177Speter  if (ret_props)
530289177Speter    {
531289177Speter      gdb.ret_props = apr_hash_make(result_pool);
532289177Speter      SVN_ERR(svn_ra_serf__create_propfind_handler(
533289177Speter                                          &props_handler, session,
534289177Speter                                          path, SVN_INVALID_REVNUM, "0",
535289177Speter                                          all_props,
536289177Speter                                          get_dir_props_cb, &gdb,
537289177Speter                                          scratch_pool));
538289177Speter
539289177Speter      svn_ra_serf__request_create(props_handler);
540289177Speter    }
541289177Speter  else
542289177Speter    gdb.ret_props = NULL;
543289177Speter
544289177Speter  if (dirent_handler)
545289177Speter    {
546289177Speter      err = svn_error_trace(
547289177Speter              svn_ra_serf__context_run_wait(&dirent_handler->done,
548289177Speter                                            session,
549289177Speter                                            scratch_pool));
550289177Speter
551289177Speter      if (err)
552289177Speter        {
553289177Speter          svn_pool_clear(scratch_pool); /* Unregisters outstanding requests */
554289177Speter          return err;
555289177Speter        }
556289177Speter
557289177Speter      if (gdb.supports_deadprop_count == svn_tristate_false
558289177Speter          && session->supports_deadprop_count == svn_tristate_unknown
559289177Speter          && dirent_fields & SVN_DIRENT_HAS_PROPS)
560289177Speter        {
561289177Speter          /* We have to requery as the server didn't give us the right
562289177Speter             information */
563289177Speter          session->supports_deadprop_count = svn_tristate_false;
564289177Speter
565289177Speter          apr_hash_clear(gdb.dirents);
566289177Speter
567289177Speter          SVN_ERR(svn_ra_serf__create_propfind_handler(
568289177Speter                                              &dirent_handler, session,
569289177Speter                                              path, SVN_INVALID_REVNUM, "1",
570289177Speter                                              get_dirent_props(dirent_fields,
571289177Speter                                                               session,
572289177Speter                                                               scratch_pool),
573289177Speter                                              get_dir_dirents_cb, &gdb,
574289177Speter                                              scratch_pool));
575289177Speter
576289177Speter          svn_ra_serf__request_create(dirent_handler);
577289177Speter        }
578289177Speter    }
579289177Speter
580289177Speter  if (props_handler)
581289177Speter    {
582289177Speter      err = svn_error_trace(
583289177Speter              svn_ra_serf__context_run_wait(&props_handler->done,
584289177Speter                                            session,
585289177Speter                                            scratch_pool));
586289177Speter    }
587289177Speter
588289177Speter  /* And dirent again for the case when we had to send the request again */
589289177Speter  if (! err && dirent_handler)
590289177Speter    {
591289177Speter      err = svn_error_trace(
592289177Speter              svn_ra_serf__context_run_wait(&dirent_handler->done,
593289177Speter                                            session,
594289177Speter                                            scratch_pool));
595289177Speter    }
596289177Speter
597289177Speter  if (!err && gdb.supports_deadprop_count != svn_tristate_unknown)
598289177Speter    session->supports_deadprop_count = gdb.supports_deadprop_count;
599289177Speter
600289177Speter  svn_pool_destroy(scratch_pool); /* Unregisters outstanding requests */
601289177Speter
602289177Speter  SVN_ERR(err);
603289177Speter
604289177Speter  if (!gdb.is_directory)
605289177Speter    return svn_error_create(SVN_ERR_FS_NOT_DIRECTORY, NULL,
606289177Speter                            _("Can't get entries of non-directory"));
607289177Speter
608289177Speter  if (ret_props)
609289177Speter    *ret_props = gdb.ret_props;
610289177Speter
611289177Speter  if (dirents)
612289177Speter    *dirents = gdb.dirents;
613289177Speter
614289177Speter  return SVN_NO_ERROR;
615289177Speter}
616