]> granicus.if.org Git - apache/commitdiff
Instead of checking device ids, try rename first and in case of EXDEV,
authorStefan Fritsch <sf@apache.org>
Mon, 9 Nov 2009 11:17:01 +0000 (11:17 +0000)
committerStefan Fritsch <sf@apache.org>
Mon, 9 Nov 2009 11:17:01 +0000 (11:17 +0000)
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

index 2a6e4c28e1c815d5c1b881e7dbf2deea8e937aa8..0149697cb8ee31fd75702da9cc291f29134980f7 100644 (file)
@@ -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;