svn-3475

Version:

1.7.0

Bug Link:

http://subversion.tigris.org/issues/show_bug.cgi?id=3475

Patch Link:

source code patch: http://svn.apache.org/viewvc?view=revision&revision=879496

Symptom:

‘svn patch’ clears executable bit of patched files.

The file with ‘svn:executable’ property loses its executable bit on disk when running ‘svn patch’; ‘svn:executable’ property in file still remains unchanged.

How it is diagnosed:

reproduced

Running ‘svn patch’ to the executable target file.

*Result: Executable bit of the target file has gone.

Root Cause:

Brief:

‘svn patch’ should restore the executable bit of files after renaming the patched result over the target file if the files have previously executable property.

Detail:

‘svn patch’ is the command to apply the patch over the target file. First the patch file and the target file is open with read-only. The applied version is written in tempoary file. The problem is that this temporary file is always created with read/write flags except for executable flag.

In ‘apply_one_patch’ function, it applies the patched result to temporary file and then rename the temp file to the target filename.

To initialize the required files, ‘init_patch_target’ function is called which opens and creates files.

static svn_error_t *

init_patch_target(... ...)

{

  … ...

  if (new_target->kind == svn_node_file && ! new_target->skipped)

    {

      /* Try to open the target file */

      /* open the target file with read-only flag */

      SVN_ERR(svn_io_file_open(&new_target->file, new_target->abs_path,

                               APR_READ | APR_BINARY | APR_BUFFERED,

                               APR_OS_DEFAULT, result_pool));

       … ...

    }

  … ...

  if (! new_target->skipped)

    {

      /* Create a temporary file to write the patched result to,

       * in the same directory as the target file.

       * We want them to be on the same filesystem so we can rename

       * the temporary file to the target file later. */

      /* open the tempory file to write the patched result */

      /* After writing the result, this file would be renamed to the target file */

      /* this file doesn’t have executable bit even if the target file has “svn:executable” property */

/* This function calls tthe system call , open("/home/yyzhou/mmlee/LOG-project/svn/3475/alpha/tempfile.tmp", O_RDWR|O_CREAT|O_EXCL, 0666) = 9.

Also, this file descriptor is used with the following system calls.

write(9, "echo abc\necho hi\n", 17)     = 17

close(9)                                = 0

*/

      dirname = svn_dirent_dirname(new_target->abs_path, scratch_pool);

      SVN_ERR(svn_stream_open_unique(&new_target->result,

                                     &new_target->result_path, dirname,

                                     svn_io_file_del_none,

                                     result_pool, scratch_pool));

        … ...

     }

  …   ...

  *target = new_target;

  return SVN_NO_ERROR;

}

After initiailization,  the ‘apply_one_patch’ functions applies patches. Then, the tempory file which contains the patched result renames to the target file name.

static svn_error_t * apply_one_patch(... ...)

{

  … ...

  SVN_ERR(init_patch_target(&target, patch, adm_access, ctx,

                            tempfiles, pool, pool));

  if (! target->skipped)

    {

      … …

        /* applying patches */

      }

        /* after writing the patched result, close it */

      SVN_ERR(svn_stream_close(target->result));

      if (target->modified)

        {

          … ...

          if (target->deleted)

            {

                … ...

            }

          else

            {

              if (old_file.size == 0 && new_file.size == 0)

                {

                    … ...

                }

              else

                {

                  if (dry_run)

                    {

                       … ...

                    }

                  else

                    {

                      /* Install patched temporary file over working file.

                       * ### Should this rather be done in a loggy fashion? */

                      /* rename the temp file to the target file name. However, the permission of files are not changed */ 

 /* this function leads to the system call, rename("/home/yyzhou/mmlee/LOG-project/svn/3475/alpha/tempfile.tmp", "/home/yyzhou/mmlee/LOG-project/svn/3475/alpha/run.sh") = 0 */

                      SVN_ERR(svn_io_file_rename(target->result_path,

                                               target->abs_path, pool));

                       … ...

                    }

                }

            }

        }

      …  ...

    }

  ...

  return SVN_NO_ERROR;

}

The patch is:

--- subversion/trunk/subversion/libsvn_client/patch.c        2009/09/18 09:37:40        879495

+++ subversion/trunk/subversion/libsvn_client/patch.c        2009/09/18 09:55:27        879496

@@ -123,6 +123,9 @@ typedef struct {

 

   /* True if the target ended up being deleted by the patch. */

   svn_boolean_t deleted;

+

+  /* True if the target has the executable bit set. */

/* the flag to see if the target file has executable property or not */

+  svn_boolean_t executable;

       } patch_target_t;

 

 /* Resolve the exact path for a patch TARGET at path PATH_FROM_PATCHFILE,

@@ -308,6 +311,9 @@ init_patch_target(patch_target_t **targe

       new_target->eol_str = APR_EOL_STR;

     }

       /* initialization */

+  new_target->local_mods = FALSE;

+  new_target->executable = FALSE;

+

   if (! new_target->skipped)

     {

       /* Create a temporary file to write the patched result to,

@@ -322,6 +328,11 @@ init_patch_target(patch_target_t **targe

 

       SVN_ERR(check_local_mods(&new_target->local_mods, ctx->wc_ctx,

                                new_target->abs_path, scratch_pool));

+

/* check if the target file has executable property or not. if so, store the info into new_target->executable variable */

+      if (new_target->kind == svn_node_file)

+        SVN_ERR(svn_io_is_file_executable(&new_target->executable,

+                                          new_target->abs_path,

+                                          scratch_pool));

      }

 

   new_target->patch = patch;

@@ -1003,6 +1014,9 @@ apply_one_patch(svn_patch_t *patch, cons

                        * ### Should this rather be done in a loggy fashion? */

                       SVN_ERR(svn_io_file_rename(target->result_path,

                                                target->abs_path, pool));

/* after renaming the patched result to the target file name, apply the execuable bit to the file if it has the property */

+                      if (target->executable)

+                        SVN_ERR(svn_io_set_file_executable(target->abs_path,

+                                                           TRUE, FALSE, pool));

 

                       if (target->added)

                         {

Failure symptom category

missing functions/incomplete computation

Is there any log message?

No

Can ErrLog help?

No