From 734abfb1fac5a215de1b74aa76c76b8c0454ba00 Mon Sep 17 00:00:00 2001 From: Stefan Fritsch Date: Mon, 9 Nov 2009 11:17:01 +0000 Subject: [PATCH] Instead of checking device ids, try rename first and in case of EXDEV, fallback to copy. From rename(2) on Linux: Linux permits a file system to be mounted at multiple points, but rename() does not work across different mount points, even if the same file system is mounted on both. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@834019 13f79535-47bb-0310-9956-ffa450edef68 --- modules/dav/fs/repos.c | 53 +++++++++++------------------------------- 1 file changed, 13 insertions(+), 40 deletions(-) diff --git a/modules/dav/fs/repos.c b/modules/dav/fs/repos.c index 2a6e4c28e1..0149697cb8 100644 --- a/modules/dav/fs/repos.c +++ b/modules/dav/fs/repos.c @@ -506,9 +506,13 @@ static dav_error * dav_fs_copymove_state( dst = apr_pstrcat(p, dst, "/", dst_file, NULL); /* copy/move the file now */ - if (is_move && src_finfo.device == dst_state_finfo.device) { - /* simple rename is possible since it is on the same device */ - if (apr_file_rename(src, dst, p) != APR_SUCCESS) { + if (is_move) { + /* try simple rename first */ + rv = apr_file_rename(src, dst, p); + if (APR_STATUS_IS_EXDEV(rv)) { + return dav_fs_copymove_file(is_move, p, src, dst, NULL, NULL, pbuf); + } + if (rv != APR_SUCCESS) { /* ### use something besides 500? */ return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, "Could not move state file."); @@ -1204,7 +1208,7 @@ static dav_error * dav_fs_move_resource( dav_resource_private *srcinfo = src->info; dav_resource_private *dstinfo = dst->info; dav_error *err; - int can_rename = 0; + apr_status_t rv; #if DAV_DEBUG if (src->hooks != dst->hooks) { @@ -1218,39 +1222,12 @@ static dav_error * dav_fs_move_resource( } #endif - /* determine whether a simple rename will work. - * Assume source exists, else we wouldn't get called. - */ - if (dstinfo->finfo.filetype != 0) { - if (dstinfo->finfo.device == srcinfo->finfo.device) { - /* target exists and is on the same device. */ - can_rename = 1; - } - } - else { - const char *dirpath; - apr_finfo_t finfo; - apr_status_t rv; - /* destination does not exist, but the parent directory should, - * so try it - */ - dirpath = ap_make_dirstr_parent(dstinfo->pool, dstinfo->pathname); - /* - * XXX: If missing dev ... then what test? - * Really need a try and failover for those platforms. - * - */ - rv = apr_stat(&finfo, dirpath, APR_FINFO_DEV, dstinfo->pool); - if ((rv == APR_SUCCESS || rv == APR_INCOMPLETE) - && (finfo.valid & srcinfo->finfo.valid & APR_FINFO_DEV) - && (finfo.device == srcinfo->finfo.device)) { - can_rename = 1; - } - } + /* try rename first */ + rv = apr_file_rename(srcinfo->pathname, dstinfo->pathname, srcinfo->pool); /* if we can't simply rename, then do it the hard way... */ - if (!can_rename) { + if (APR_STATUS_IS_EXDEV(rv)) { if ((err = dav_fs_copymove_resource(1, src, dst, DAV_INFINITY, response)) == NULL) { /* update resource states */ @@ -1263,20 +1240,16 @@ static dav_error * dav_fs_move_resource( return err; } - /* a rename should work. do it, and move properties as well */ - /* no multistatus response */ *response = NULL; - /* ### APR has no rename? */ - if (apr_file_rename(srcinfo->pathname, dstinfo->pathname, - srcinfo->pool) != APR_SUCCESS) { + if (rv != APR_SUCCESS) { /* ### should have a better error than this. */ return dav_new_error(srcinfo->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "Could not rename resource."); } - /* update resource states */ + /* Rename did work. Update resource states and move properties as well */ dst->exists = 1; dst->collection = src->collection; src->exists = 0; -- 2.40.0