[ CCing dev@ ]
Karl, is this bug still open? And how many bugs are there here (bug in
mod_dav_svn? bug in the fs layer?)?
I'd like to file an issue for it, at least, but I'm not sure I'll describe
it correctly. Could you do that?
Thanks,
Daniel
Karl Fogel wrote on Sat, 11 Oct 2008 at 18:25 -0400:
> 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
------------------------------------------------------
http://subversion.tigris.org/ds/viewMessage.do?dsForumId=462&dsMessageId=993658
Received on 2008-12-27 11:42:19 CET