"Michael Susser" <hdmlist_at_googlemail.com> writes:
> do you have any news?
Not yet, but I've been traveling for more than a week now and haven't
had time to dig further yet. I will post here as soon as I know more.
-Karl
> Greetings,
> Michael
>
> 2008/10/12 Karl Fogel <kfogel_at_red-bean.com>
>
> This is a deep one. I'm posting what I've learned so far in case anyone
> has any hunches. On the client, the problem is that in
>
> libsvn_ra_neon/commit.c:commit_add_file()
>
> the following code should get a "file not found" error (i.e., an HTTP
> 404) when it probes for the existence of the file we're about to add,
> but doesn't -- instead, it's as though the file already exists:
>
> svn_ra_neon__resource_t *res;
> svn_error_t *err = svn_ra_neon__get_starting_props(&res,
> file->cc->ras,
> file->rsrc->wr_url,
> NULL, workpool);
> if (!err)
> {
> /* If the PROPFIND succeeds the file already exists */
> return svn_error_createf(SVN_ERR_RA_DAV_ALREADY_EXISTS, NULL,
> _("File '%s' already exists"),
> file->rsrc->url);
> }
>
> Here's what happens on the server side. Let's shortcut directly to
> mod_dav_svn/repos.c:get_resource(). Before the call to
> prep_resource()...
>
> /* prepare the resource for operation */
> if ((err = prep_resource(comb)) != NULL)
> return err;
>
> ...comb->exists is 0, as we would want (so is comb->res.exists, for that
> matter). But after prep_resource(), comb->exists is 1!
>
> prep_resource() is just a dispatch function; the real stuff happens in
> prep_working() (because comb->res.type == DAV_RESOURCE_TYPE_WORKING).
> In prep_working(), we get all the way to this code near the end:
>
> derr = fs_check_path(&kind, comb->priv.root.root,
> comb->priv.repos_path, pool);
>
> if (derr != NULL)
> return derr;
>
> comb->res.exists = (kind == svn_node_none) ? FALSE : TRUE;
> comb->res.collection = (kind == svn_node_dir) ? TRUE : FALSE;
>
> So that's where comb->res.exists gets set to 1. (I'm not sure where
> comb->exists gets set to 1, which might be important, but see below.)
>
> Anyway, that call to fs_check_path() sets kind to svn_node_file, even
> though the file shouldn't be present in this txn yet (that's why we're
> adding it).
>
> Tracing fs_check_path --> svn_fs_fs__check_path() --> node_kind() -->
> fs_node_id() --> get_dag() --> open_path() --> svn_fs_fs__dag_open(),
> shows that, somehow, the file is actually there, according to the FS.
> (It does not appear to be a dag node caching problem; the node isn't
> found in the cache, instead we find it the old-fashioned way, right
> there in the filesystem.)
>
> Back up in http-2.2.9/modules/dav/main/mod_dav.c:dav_method_propfind(),
> this all matters because of this code:
>
> /* Ask repository module to resolve the resource */
> err = dav_get_resource(r, 1 /* label_allowed */, 0 /* use_checked_in */,
> &resource);
> if (err != NULL)
> return dav_handle_err(r, err, NULL);
>
> if (dav_get_resource_state(r, resource) == DAV_RESOURCE_NULL) {
> /* Apache will supply a default error for this. */
> return HTTP_NOT_FOUND;
> }
>
> Not only does dav_get_resource() not get an error, but the call to
> dav_get_resource_state() will not return DAV_RESOURCE_NULL, because that
> code (in httpd-2.2.9/modules/dav/main/util_lock.c) says:
>
> if (resource->exists)
> return DAV_RESOURCE_EXISTS;
>
> Boom. If it weren't for that, the function would return
> DAV_RESOURCE_NULL and we'd be fine.
>
> Note that in the reproduction recipe, if you insert an "svn up Data/wc"
> right before the final svn cp in the reproduction recipe, then none of
> this weirdness happens, and the bug doesn't reproduce.
>
> So why does the file claim to be present in the txn already? And why
> does updating the whole working copy to r2 (instead of having a mixed
> r1/r2 working copy) cause the repository filesystem to correctly answer
> that the file is not there?
>
> I don't know. I will continue to debug, but if anyone has any inspired
> ideas, please post.
>
> -Karl
>
> Karl Fogel <kfogel_at_red-bean.com> writes:
> > "Michael Susser" <hdmlist_at_googlemail.com> writes:
> >> i have found a bug when creating tags from working copy in svn 1.5.2
> >> (and also 1.5.3). Here is a recipe how to reproduce the error: (my
> >> apache is configured to host the repositories in E:\SVNRep)
> >>
> >> [...]
> >>
> >> svn copy -m"tagging" E:\Data\wc\trunk http://myserver/svn/repo/tags/
> V1.0.0
> >>>svn: Commit failed (details follow):
> >>>svn: File '/svn/repo/tags/V1.0.0/dir/file.cpp' already exists
> >
> > Thank you for the excellent recipe. I can reproduce this, and have
> > written a Unix Bourne shell reproduction script (see below). Note that
> > this only reproduces over http://. If you try it with svn:// or
> > file://, the tagging works fine.
> >
> >> This error message is absolutely wrong! I investigated what went wrong
> and
> >> found the following: after the commit action the working copy is not
> updated
> >> correctly(?). The changed file "file.cpp" gets a new revision (2), but
> its
> >> parent directory "dir" stays at revision 1. Is this ok?
> >
> > Well, that part is okay. When you commit, only the committed items get
> > their revisions bumped locally -- in other words, a commit does not do
> > an update on the items that are not part of the commit. However,
> > Subversion is supposed to transparently handle the resultant mixed
> > revisions. They shouldn't matter here.
> >
> > This bug seems familiar, like we've either fixed it before or filed an
> > issue for it. I'll check the logs and the issue tracker. But we have a
> > reproduction recipe, so that means we can fix it or re-fix it :-).
> >
> >
> ----------------------------------------------------------------------------
> > #!/bin/sh
> >
> > # The next line is the only line you should need to adjust.
> > SVNDIR=/home/kfogel/src/subversion
> >
> > SVN=${SVNDIR}/subversion/svn/svn
> > SVNSERVE=${SVNDIR}/subversion/svnserve/svnserve
> > SVNADMIN=${SVNDIR}/subversion/svnadmin/svnadmin
> >
> > # Select an access method. If svn://, the svnserve setup is
> > # handled automagically by this script; but if http://, then
> > # you'll have to configure it yourself first.
> > #
> > URL=http://localhost/ms/repos
> > # URL=svn://localhost/repos
> > # URL=file:///`pwd`/repos
> >
> > rm -rf repos wc Data import-me
> >
> > ${SVNADMIN} create repos
> >
> > # These are for svnserve only.
> > echo "[general]" > repos/conf/svnserve.conf
> > echo "anon-access = write" >> repos/conf/svnserve.conf
> > echo "auth-access = write" >> repos/conf/svnserve.conf
> >
> > # The server will only be contacted if $URL is svn://foo, of course.
> > ${SVNSERVE} --pid-file svnserve-pid -d -r `pwd`
> > # And put the kill command in a file, in case need to run it manually.
> > echo "kill -9 `cat svnserve-pid`" > k
> > chmod a+rwx k
> >
> > mkdir Data
> > svn co ${URL} Data/wc
> > mkdir Data/wc/tags
> > mkdir Data/wc/trunk
> > mkdir Data/wc/trunk/dir
> > cp /dev/null Data/wc/trunk/dir/file.cpp
> > ${SVN} add Data/wc/t*
> > ${SVN} ci -m"test" Data/wc
> >
> > echo "ABC" >> Data/wc/trunk/dir/file.cpp
> >
> > ${SVN} ci -m"test" Data/wc
> >
> > # Using http:// only, the next command fails with this error:
> > #
> > # subversion/libsvn_client/copy.c:1319: (apr_err=175005)
> > # svn: Commit failed (details follow):
> > # subversion/libsvn_ra_neon/commit.c:1036: (apr_err=175005)
> > # svn: File '/ms/repos/tags/V1.0.0/dir/file.cpp' already exists
> > #
> > ${SVN} copy -m"tagging" Data/wc/trunk ${URL}/tags/V1.0.0
> >
> > ./k
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_subversion.tigris.org
> For additional commands, e-mail: users-help_at_subversion.tigris.org
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe_at_subversion.tigris.org
For additional commands, e-mail: users-help_at_subversion.tigris.org
Received on 2008-10-26 21:42:17 CET