1251881Speter/*
2251881Speter * delete.c: Handling of the in-wc side of the delete operation
3251881Speter *
4251881Speter * ====================================================================
5251881Speter *    Licensed to the Apache Software Foundation (ASF) under one
6251881Speter *    or more contributor license agreements.  See the NOTICE file
7251881Speter *    distributed with this work for additional information
8251881Speter *    regarding copyright ownership.  The ASF licenses this file
9251881Speter *    to you under the Apache License, Version 2.0 (the
10251881Speter *    "License"); you may not use this file except in compliance
11251881Speter *    with the License.  You may obtain a copy of the License at
12251881Speter *
13251881Speter *      http://www.apache.org/licenses/LICENSE-2.0
14251881Speter *
15251881Speter *    Unless required by applicable law or agreed to in writing,
16251881Speter *    software distributed under the License is distributed on an
17251881Speter *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18251881Speter *    KIND, either express or implied.  See the License for the
19251881Speter *    specific language governing permissions and limitations
20251881Speter *    under the License.
21251881Speter * ====================================================================
22251881Speter */
23251881Speter
24251881Speter
25251881Speter
26251881Speter#include <string.h>
27251881Speter#include <stdlib.h>
28251881Speter
29251881Speter#include <apr_pools.h>
30251881Speter
31251881Speter#include "svn_types.h"
32251881Speter#include "svn_pools.h"
33251881Speter#include "svn_string.h"
34251881Speter#include "svn_error.h"
35251881Speter#include "svn_dirent_uri.h"
36251881Speter#include "svn_wc.h"
37251881Speter#include "svn_io.h"
38251881Speter
39251881Speter#include "wc.h"
40251881Speter#include "adm_files.h"
41251881Speter#include "conflicts.h"
42251881Speter#include "workqueue.h"
43251881Speter
44251881Speter#include "svn_private_config.h"
45251881Speter#include "private/svn_wc_private.h"
46251881Speter
47251881Speter
48251881Speter/* Remove/erase PATH from the working copy. This involves deleting PATH
49251881Speter * from the physical filesystem. PATH is assumed to be an unversioned file
50251881Speter * or directory.
51251881Speter *
52251881Speter * If ignore_enoent is TRUE, ignore missing targets.
53251881Speter *
54251881Speter * If CANCEL_FUNC is non-null, invoke it with CANCEL_BATON at various
55251881Speter * points, return any error immediately.
56251881Speter */
57251881Speterstatic svn_error_t *
58251881Spetererase_unversioned_from_wc(const char *path,
59251881Speter                          svn_boolean_t ignore_enoent,
60251881Speter                          svn_cancel_func_t cancel_func,
61251881Speter                          void *cancel_baton,
62251881Speter                          apr_pool_t *scratch_pool)
63251881Speter{
64251881Speter  svn_error_t *err;
65251881Speter
66251881Speter  /* Optimize the common case: try to delete the file */
67251881Speter  err = svn_io_remove_file2(path, ignore_enoent, scratch_pool);
68251881Speter  if (err)
69251881Speter    {
70251881Speter      /* Then maybe it was a directory? */
71251881Speter      svn_error_clear(err);
72251881Speter
73251881Speter      err = svn_io_remove_dir2(path, ignore_enoent, cancel_func, cancel_baton,
74251881Speter                               scratch_pool);
75251881Speter
76251881Speter      if (err)
77251881Speter        {
78251881Speter          /* We're unlikely to end up here. But we need this fallback
79251881Speter             to make sure we report the right error *and* try the
80251881Speter             correct deletion at least once. */
81251881Speter          svn_node_kind_t kind;
82251881Speter
83251881Speter          svn_error_clear(err);
84251881Speter          SVN_ERR(svn_io_check_path(path, &kind, scratch_pool));
85251881Speter          if (kind == svn_node_file)
86251881Speter            SVN_ERR(svn_io_remove_file2(path, ignore_enoent, scratch_pool));
87251881Speter          else if (kind == svn_node_dir)
88251881Speter            SVN_ERR(svn_io_remove_dir2(path, ignore_enoent,
89251881Speter                                       cancel_func, cancel_baton,
90251881Speter                                       scratch_pool));
91251881Speter          else if (kind == svn_node_none)
92251881Speter            return svn_error_createf(SVN_ERR_BAD_FILENAME, NULL,
93251881Speter                                     _("'%s' does not exist"),
94251881Speter                                     svn_dirent_local_style(path,
95251881Speter                                                            scratch_pool));
96251881Speter          else
97251881Speter            return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
98251881Speter                                     _("Unsupported node kind for path '%s'"),
99251881Speter                                     svn_dirent_local_style(path,
100251881Speter                                                            scratch_pool));
101251881Speter
102251881Speter        }
103251881Speter    }
104251881Speter
105251881Speter  return SVN_NO_ERROR;
106251881Speter}
107251881Speter
108251881Speter/* Helper for svn_wc__delete and svn_wc__delete_many */
109251881Speterstatic svn_error_t *
110251881Spetercreate_delete_wq_items(svn_skel_t **work_items,
111251881Speter                       svn_wc__db_t *db,
112251881Speter                       const char *local_abspath,
113251881Speter                       svn_node_kind_t kind,
114251881Speter                       svn_boolean_t conflicted,
115251881Speter                       apr_pool_t *result_pool,
116251881Speter                       apr_pool_t *scratch_pool)
117251881Speter{
118251881Speter  *work_items = NULL;
119251881Speter
120251881Speter  /* Schedule the on-disk delete */
121251881Speter  if (kind == svn_node_dir)
122251881Speter    SVN_ERR(svn_wc__wq_build_dir_remove(work_items, db, local_abspath,
123251881Speter                                        local_abspath,
124251881Speter                                        TRUE /* recursive */,
125251881Speter                                        result_pool, scratch_pool));
126251881Speter  else
127251881Speter    SVN_ERR(svn_wc__wq_build_file_remove(work_items, db, local_abspath,
128251881Speter                                         local_abspath,
129251881Speter                                         result_pool, scratch_pool));
130251881Speter
131251881Speter  /* Read conflicts, to allow deleting the markers after updating the DB */
132251881Speter  if (conflicted)
133251881Speter    {
134251881Speter      svn_skel_t *conflict;
135251881Speter      const apr_array_header_t *markers;
136251881Speter      int i;
137251881Speter
138251881Speter      SVN_ERR(svn_wc__db_read_conflict(&conflict, db, local_abspath,
139251881Speter                                       scratch_pool, scratch_pool));
140251881Speter
141251881Speter      SVN_ERR(svn_wc__conflict_read_markers(&markers, db, local_abspath,
142251881Speter                                            conflict,
143251881Speter                                            scratch_pool, scratch_pool));
144251881Speter
145251881Speter      /* Maximum number of markers is 4, so no iterpool */
146251881Speter      for (i = 0; markers && i < markers->nelts; i++)
147251881Speter        {
148251881Speter          const char *marker_abspath;
149251881Speter          svn_node_kind_t marker_kind;
150251881Speter
151251881Speter          marker_abspath = APR_ARRAY_IDX(markers, i, const char *);
152251881Speter          SVN_ERR(svn_io_check_path(marker_abspath, &marker_kind,
153251881Speter                                    scratch_pool));
154251881Speter
155251881Speter          if (marker_kind == svn_node_file)
156251881Speter            {
157251881Speter              svn_skel_t *work_item;
158251881Speter
159251881Speter              SVN_ERR(svn_wc__wq_build_file_remove(&work_item, db,
160251881Speter                                                   local_abspath,
161251881Speter                                                   marker_abspath,
162251881Speter                                                   result_pool,
163251881Speter                                                   scratch_pool));
164251881Speter
165251881Speter              *work_items = svn_wc__wq_merge(*work_items, work_item,
166251881Speter                                             result_pool);
167251881Speter            }
168251881Speter        }
169251881Speter    }
170251881Speter
171251881Speter  return SVN_NO_ERROR;
172251881Speter}
173251881Speter
174251881Spetersvn_error_t *
175251881Spetersvn_wc__delete_many(svn_wc_context_t *wc_ctx,
176251881Speter                    const apr_array_header_t *targets,
177251881Speter                    svn_boolean_t keep_local,
178251881Speter                    svn_boolean_t delete_unversioned_target,
179251881Speter                    svn_cancel_func_t cancel_func,
180251881Speter                    void *cancel_baton,
181251881Speter                    svn_wc_notify_func2_t notify_func,
182251881Speter                    void *notify_baton,
183251881Speter                    apr_pool_t *scratch_pool)
184251881Speter{
185251881Speter  svn_wc__db_t *db = wc_ctx->db;
186251881Speter  svn_error_t *err;
187251881Speter  svn_wc__db_status_t status;
188251881Speter  svn_node_kind_t kind;
189251881Speter  svn_skel_t *work_items = NULL;
190251881Speter  apr_array_header_t *versioned_targets;
191251881Speter  const char *local_abspath;
192251881Speter  int i;
193251881Speter  apr_pool_t *iterpool;
194251881Speter
195251881Speter  iterpool = svn_pool_create(scratch_pool);
196251881Speter  versioned_targets = apr_array_make(scratch_pool, targets->nelts,
197251881Speter                                     sizeof(const char *));
198251881Speter  for (i = 0; i < targets->nelts; i++)
199251881Speter    {
200251881Speter      svn_boolean_t conflicted = FALSE;
201251881Speter      const char *repos_relpath;
202251881Speter
203251881Speter      svn_pool_clear(iterpool);
204251881Speter
205251881Speter      local_abspath = APR_ARRAY_IDX(targets, i, const char *);
206251881Speter      err = svn_wc__db_read_info(&status, &kind, NULL, &repos_relpath, NULL,
207251881Speter                                 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
208251881Speter                                 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
209251881Speter                                 NULL, &conflicted,
210251881Speter                                 NULL, NULL, NULL, NULL, NULL, NULL,
211251881Speter                                 db, local_abspath, iterpool, iterpool);
212251881Speter
213251881Speter      if (err)
214251881Speter        {
215251881Speter          if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
216251881Speter            {
217251881Speter              svn_error_clear(err);
218251881Speter              if (delete_unversioned_target && !keep_local)
219251881Speter                SVN_ERR(erase_unversioned_from_wc(local_abspath, FALSE,
220251881Speter                                                  cancel_func, cancel_baton,
221251881Speter                                                  iterpool));
222251881Speter              continue;
223251881Speter            }
224251881Speter         else
225251881Speter          return svn_error_trace(err);
226251881Speter        }
227251881Speter
228251881Speter      APR_ARRAY_PUSH(versioned_targets, const char *) = local_abspath;
229251881Speter
230251881Speter      switch (status)
231251881Speter        {
232251881Speter          /* svn_wc__db_status_server_excluded handled by
233251881Speter           * svn_wc__db_op_delete_many */
234251881Speter          case svn_wc__db_status_excluded:
235251881Speter          case svn_wc__db_status_not_present:
236251881Speter            return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
237251881Speter                                     _("'%s' cannot be deleted"),
238251881Speter                                     svn_dirent_local_style(local_abspath,
239251881Speter                                                            iterpool));
240251881Speter
241251881Speter          /* Explicitly ignore other statii */
242251881Speter          default:
243251881Speter            break;
244251881Speter        }
245251881Speter
246251881Speter      if (status == svn_wc__db_status_normal
247251881Speter          && kind == svn_node_dir)
248251881Speter        {
249251881Speter          svn_boolean_t is_wcroot;
250251881Speter          SVN_ERR(svn_wc__db_is_wcroot(&is_wcroot, db, local_abspath,
251251881Speter                                       iterpool));
252251881Speter
253251881Speter          if (is_wcroot)
254251881Speter            return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
255251881Speter                                     _("'%s' is the root of a working copy and "
256251881Speter                                       "cannot be deleted"),
257251881Speter                                     svn_dirent_local_style(local_abspath,
258251881Speter                                                            iterpool));
259251881Speter        }
260251881Speter      if (repos_relpath && !repos_relpath[0])
261251881Speter        return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
262251881Speter                                     _("'%s' represents the repository root "
263251881Speter                                       "and cannot be deleted"),
264251881Speter                                     svn_dirent_local_style(local_abspath,
265251881Speter                                                            iterpool));
266251881Speter
267251881Speter      /* Verify if we have a write lock on the parent of this node as we might
268251881Speter         be changing the childlist of that directory. */
269251881Speter      SVN_ERR(svn_wc__write_check(db, svn_dirent_dirname(local_abspath,
270251881Speter                                                         iterpool),
271251881Speter                                  iterpool));
272251881Speter
273251881Speter      /* Prepare the on-disk delete */
274251881Speter      if (!keep_local)
275251881Speter        {
276251881Speter          svn_skel_t *work_item;
277251881Speter
278251881Speter          SVN_ERR(create_delete_wq_items(&work_item, db, local_abspath, kind,
279251881Speter                                         conflicted,
280251881Speter                                         scratch_pool, iterpool));
281251881Speter
282251881Speter          work_items = svn_wc__wq_merge(work_items, work_item,
283251881Speter                                        scratch_pool);
284251881Speter        }
285251881Speter    }
286251881Speter
287251881Speter  if (versioned_targets->nelts == 0)
288251881Speter    return SVN_NO_ERROR;
289251881Speter
290251881Speter  SVN_ERR(svn_wc__db_op_delete_many(db, versioned_targets,
291251881Speter                                    !keep_local /* delete_dir_externals */,
292251881Speter                                    work_items,
293251881Speter                                    cancel_func, cancel_baton,
294251881Speter                                    notify_func, notify_baton,
295251881Speter                                    iterpool));
296251881Speter
297251881Speter  if (work_items != NULL)
298251881Speter    {
299251881Speter      /* Our only caller locked the wc, so for now assume it only passed
300251881Speter         nodes from a single wc (asserted in svn_wc__db_op_delete_many) */
301251881Speter      local_abspath = APR_ARRAY_IDX(versioned_targets, 0, const char *);
302251881Speter
303251881Speter      SVN_ERR(svn_wc__wq_run(db, local_abspath, cancel_func, cancel_baton,
304251881Speter                             iterpool));
305251881Speter    }
306251881Speter  svn_pool_destroy(iterpool);
307251881Speter
308251881Speter  return SVN_NO_ERROR;
309251881Speter}
310251881Speter
311251881Spetersvn_error_t *
312251881Spetersvn_wc_delete4(svn_wc_context_t *wc_ctx,
313251881Speter               const char *local_abspath,
314251881Speter               svn_boolean_t keep_local,
315251881Speter               svn_boolean_t delete_unversioned_target,
316251881Speter               svn_cancel_func_t cancel_func,
317251881Speter               void *cancel_baton,
318251881Speter               svn_wc_notify_func2_t notify_func,
319251881Speter               void *notify_baton,
320251881Speter               apr_pool_t *scratch_pool)
321251881Speter{
322251881Speter  apr_pool_t *pool = scratch_pool;
323251881Speter  svn_wc__db_t *db = wc_ctx->db;
324251881Speter  svn_error_t *err;
325251881Speter  svn_wc__db_status_t status;
326251881Speter  svn_node_kind_t kind;
327251881Speter  svn_boolean_t conflicted;
328251881Speter  svn_skel_t *work_items = NULL;
329251881Speter  const char *repos_relpath;
330251881Speter
331251881Speter  err = svn_wc__db_read_info(&status, &kind, NULL, &repos_relpath, NULL, NULL,
332251881Speter                             NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
333251881Speter                             NULL, NULL, NULL, NULL, NULL, NULL, &conflicted,
334251881Speter                             NULL, NULL, NULL, NULL, NULL, NULL,
335251881Speter                             db, local_abspath, pool, pool);
336251881Speter
337251881Speter  if (delete_unversioned_target &&
338251881Speter      err != NULL && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
339251881Speter    {
340251881Speter      svn_error_clear(err);
341251881Speter
342251881Speter      if (!keep_local)
343251881Speter        SVN_ERR(erase_unversioned_from_wc(local_abspath, FALSE,
344251881Speter                                          cancel_func, cancel_baton,
345251881Speter                                          pool));
346251881Speter      return SVN_NO_ERROR;
347251881Speter    }
348251881Speter  else
349251881Speter    SVN_ERR(err);
350251881Speter
351251881Speter  switch (status)
352251881Speter    {
353251881Speter      /* svn_wc__db_status_server_excluded handled by svn_wc__db_op_delete */
354251881Speter      case svn_wc__db_status_excluded:
355251881Speter      case svn_wc__db_status_not_present:
356251881Speter        return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
357251881Speter                                 _("'%s' cannot be deleted"),
358251881Speter                                 svn_dirent_local_style(local_abspath, pool));
359251881Speter
360251881Speter      /* Explicitly ignore other statii */
361251881Speter      default:
362251881Speter        break;
363251881Speter    }
364251881Speter
365251881Speter  if (status == svn_wc__db_status_normal
366251881Speter      && kind == svn_node_dir)
367251881Speter    {
368251881Speter      svn_boolean_t is_wcroot;
369251881Speter      SVN_ERR(svn_wc__db_is_wcroot(&is_wcroot, db, local_abspath, pool));
370251881Speter
371251881Speter      if (is_wcroot)
372251881Speter        return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
373251881Speter                                 _("'%s' is the root of a working copy and "
374251881Speter                                   "cannot be deleted"),
375251881Speter                                 svn_dirent_local_style(local_abspath, pool));
376251881Speter    }
377251881Speter  if (repos_relpath && !repos_relpath[0])
378251881Speter    return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
379251881Speter                             _("'%s' represents the repository root "
380251881Speter                               "and cannot be deleted"),
381251881Speter                               svn_dirent_local_style(local_abspath, pool));
382251881Speter
383251881Speter  /* Verify if we have a write lock on the parent of this node as we might
384251881Speter     be changing the childlist of that directory. */
385251881Speter  SVN_ERR(svn_wc__write_check(db, svn_dirent_dirname(local_abspath, pool),
386251881Speter                              pool));
387251881Speter
388251881Speter  /* Prepare the on-disk delete */
389251881Speter      if (!keep_local)
390251881Speter        {
391251881Speter          SVN_ERR(create_delete_wq_items(&work_items, db, local_abspath, kind,
392251881Speter                                         conflicted,
393251881Speter                                         scratch_pool, scratch_pool));
394251881Speter        }
395251881Speter
396251881Speter  SVN_ERR(svn_wc__db_op_delete(db, local_abspath,
397251881Speter                               NULL /*moved_to_abspath */,
398251881Speter                               !keep_local /* delete_dir_externals */,
399251881Speter                               NULL, work_items,
400251881Speter                               cancel_func, cancel_baton,
401251881Speter                               notify_func, notify_baton,
402251881Speter                               pool));
403251881Speter
404251881Speter  if (work_items)
405251881Speter    SVN_ERR(svn_wc__wq_run(db, local_abspath, cancel_func, cancel_baton,
406251881Speter                           scratch_pool));
407251881Speter
408251881Speter  return SVN_NO_ERROR;
409251881Speter}
410251881Speter
411251881Spetersvn_error_t *
412251881Spetersvn_wc__internal_remove_from_revision_control(svn_wc__db_t *db,
413251881Speter                                              const char *local_abspath,
414251881Speter                                              svn_boolean_t destroy_wf,
415251881Speter                                              svn_cancel_func_t cancel_func,
416251881Speter                                              void *cancel_baton,
417251881Speter                                              apr_pool_t *scratch_pool)
418251881Speter{
419251881Speter  svn_boolean_t left_something = FALSE;
420251881Speter  svn_boolean_t is_root;
421251881Speter  svn_error_t *err = NULL;
422251881Speter
423251881Speter  SVN_ERR(svn_wc__db_is_wcroot(&is_root, db, local_abspath, scratch_pool));
424251881Speter
425251881Speter  SVN_ERR(svn_wc__write_check(db, is_root ? local_abspath
426251881Speter                                          : svn_dirent_dirname(local_abspath,
427251881Speter                                                               scratch_pool),
428251881Speter                              scratch_pool));
429251881Speter
430251881Speter  SVN_ERR(svn_wc__db_op_remove_node(&left_something,
431251881Speter                                    db, local_abspath,
432251881Speter                                    destroy_wf /* destroy_wc */,
433251881Speter                                    destroy_wf /* destroy_changes */,
434251881Speter                                    SVN_INVALID_REVNUM,
435251881Speter                                    svn_wc__db_status_not_present,
436251881Speter                                    svn_node_none,
437251881Speter                                    NULL, NULL,
438251881Speter                                    cancel_func, cancel_baton,
439251881Speter                                    scratch_pool));
440251881Speter
441251881Speter  SVN_ERR(svn_wc__wq_run(db, local_abspath,
442251881Speter                         cancel_func, cancel_baton,
443251881Speter                         scratch_pool));
444251881Speter
445251881Speter  if (is_root)
446251881Speter    {
447251881Speter      /* Destroy the administrative area */
448251881Speter      SVN_ERR(svn_wc__adm_destroy(db, local_abspath, cancel_func, cancel_baton,
449251881Speter                                  scratch_pool));
450251881Speter
451251881Speter      /* And if we didn't leave something interesting, remove the directory */
452251881Speter      if (!left_something && destroy_wf)
453251881Speter        err = svn_io_dir_remove_nonrecursive(local_abspath, scratch_pool);
454251881Speter    }
455251881Speter
456251881Speter  if (left_something || err)
457251881Speter    return svn_error_create(SVN_ERR_WC_LEFT_LOCAL_MOD, err, NULL);
458251881Speter
459251881Speter  return SVN_NO_ERROR;
460251881Speter}
461251881Speter
462251881Speter/* Implements svn_wc_status_func4_t for svn_wc_remove_from_revision_control2 */
463251881Speterstatic svn_error_t *
464251881Speterremove_from_revision_status_callback(void *baton,
465251881Speter                                     const char *local_abspath,
466251881Speter                                     const svn_wc_status3_t *status,
467251881Speter                                     apr_pool_t *scratch_pool)
468251881Speter{
469251881Speter  /* For legacy reasons we only check the file contents for changes */
470251881Speter  if (status->versioned
471251881Speter      && status->kind == svn_node_file
472251881Speter      && (status->text_status == svn_wc_status_modified
473251881Speter          || status->text_status == svn_wc_status_conflicted))
474251881Speter    {
475251881Speter      return svn_error_createf(SVN_ERR_WC_LEFT_LOCAL_MOD, NULL,
476251881Speter                               _("File '%s' has local modifications"),
477251881Speter                               svn_dirent_local_style(local_abspath,
478251881Speter                                                      scratch_pool));
479251881Speter    }
480251881Speter  return SVN_NO_ERROR;
481251881Speter}
482251881Speter
483251881Spetersvn_error_t *
484251881Spetersvn_wc_remove_from_revision_control2(svn_wc_context_t *wc_ctx,
485251881Speter                                    const char *local_abspath,
486251881Speter                                    svn_boolean_t destroy_wf,
487251881Speter                                    svn_boolean_t instant_error,
488251881Speter                                    svn_cancel_func_t cancel_func,
489251881Speter                                    void *cancel_baton,
490251881Speter                                    apr_pool_t *scratch_pool)
491251881Speter{
492251881Speter  if (instant_error)
493251881Speter    {
494251881Speter      SVN_ERR(svn_wc_walk_status(wc_ctx, local_abspath, svn_depth_infinity,
495251881Speter                                 FALSE, FALSE, FALSE, NULL,
496251881Speter                                 remove_from_revision_status_callback, NULL,
497251881Speter                                 cancel_func, cancel_baton,
498251881Speter                                 scratch_pool));
499251881Speter    }
500251881Speter  return svn_error_trace(
501251881Speter      svn_wc__internal_remove_from_revision_control(wc_ctx->db,
502251881Speter                                                    local_abspath,
503251881Speter                                                    destroy_wf,
504251881Speter                                                    cancel_func,
505251881Speter                                                    cancel_baton,
506251881Speter                                                    scratch_pool));
507251881Speter}
508251881Speter
509