CVE-2016-6663: Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition') (CWE-362)
value: Race condition in Oracle MySQL before 5.5.52, 5.6.x before 5.6.33, 5.7.x before 5.7.15, and 8.x before 8.0.1; MariaDB before 5.5.52, 10.0.x before 10.0.28, and 10.1.x before 10.1.18; Percona Server before 5.5.51-38.2, 5.6.x before 5.6.32-78-1, and 5.7.x before 5.7.14-8; and Percona XtraDB Cluster before 5.5.41-37.0, 5.6.x before 5.6.32-25.17, and 5.7.x before 5.7.14-26.17 allows local users with certain permissions to gain privileges by leveraging use of my_copystat by REPAIR TABLE to repair a MyISAM table.
CWE description: The product contains a code sequence that can run concurrently with other code, and the code sequence requires temporary, exclusive access to a shared resource, but a timing window exists in which the shared resource can be modified by another code sequence that is operating concurrently.
CVSS v3 base score: 7
Published: 2016-12-13T21:59Z
Repository: https://github.com/mysql/mysql-server
Language: C
Files changed: include/my_sys.h, include/myisam.h, mysys/my_redel.c, storage/myisam/ha_myisam.cc, storage/myisam/mi_check.c, storage/myisam/myisamchk.c
Commit date: 2016-08-25 13:38:54 +0530
Commit message: Bug#24388746: PRIVILEGE ESCALATION AND RACE CONDITION USING CREATE TABLE

During REPAIR TABLE of a MyISAM table, a temporary data file (.TMD)
is created. When repair finishes, this file is renamed to the original
.MYD file. The problem was that during this rename, we copied the
stats from the old file to the new file with chmod/chown. If a user
managed to replace the temporary file before chmod/chown was executed,
it was possible to get an arbitrary file with the privileges of the
mysql user.

This patch fixes the problem by not copying stats from the old
file to the new file. This is not needed as the new file was
created with the correct stats. This fix only changes server
behavior - external utilities such as myisamchk still does
chmod/chown.

No test case provided since the problem involves synchronization
with file system operations.

Diff: diff --git a/include/my_sys.h b/include/my_sys.h
index b1b8bf15be3..472c2ba5ca0 100644
--- a/include/my_sys.h
+++ b/include/my_sys.h
@@ -1,6 +1,6 @@
-/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; version 2 of the License.
 
@@ -81,10 +81,11 @@ typedef struct my_aio_result {
 #define MY_COPYTIME	64	/* my_redel() copys time */
 #define MY_DELETE_OLD	256	/* my_create_with_symlink() */
 #define MY_RESOLVE_LINK 128	/* my_realpath(); Only resolve links */
 #define MY_HOLD_ORIGINAL_MODES 128  /* my_copy() holds to file modes */
 #define MY_REDEL_MAKE_BACKUP 256
+#define MY_REDEL_NO_COPY_STAT 512 /* my_redel() doesn't call my_copystat() */
 #define MY_SEEK_NOT_DONE 32	/* my_lock may have to do a seek */
 #define MY_DONT_WAIT	64	/* my_lock() don't wait if can't lock */
 #define MY_ZEROFILL	32	/* my_malloc(), fill array with zero */
 #define MY_ALLOW_ZERO_PTR 64	/* my_realloc() ; zero ptr -> malloc */
 #define MY_FREE_ON_ERROR 128	/* my_realloc() ; Free old ptr on error */
diff --git a/include/myisam.h b/include/myisam.h
index 85d37a81bc6..a9fcd7e4369 100644
--- a/include/myisam.h
+++ b/include/myisam.h
@@ -1,7 +1,7 @@
 /*
-   Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+   Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; version 2 of the License.
 
@@ -424,16 +424,17 @@ int chk_status(MI_CHECK *param, MI_INFO *info);
 int chk_del(MI_CHECK *param, register MI_INFO *info, uint test_flag);
 int chk_size(MI_CHECK *param, MI_INFO *info);
 int chk_key(MI_CHECK *param, MI_INFO *info);
 int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend);
 int mi_repair(MI_CHECK *param, register MI_INFO *info,
-	      char * name, int rep_quick);
-int mi_sort_index(MI_CHECK *param, register MI_INFO *info, char * name);
+	      char * name, int rep_quick, my_bool no_copy_stat);
+int mi_sort_index(MI_CHECK *param, register MI_INFO *info, char * name,
+                  my_bool no_copy_stat);
 int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
-		      const char * name, int rep_quick);
+		      const char * name, int rep_quick, my_bool no_copy_stat);
 int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
-		      const char * name, int rep_quick);
+                       const char * name, int rep_quick, my_bool no_copy_stat);
 int change_to_newfile(const char * filename, const char * old_ext,
 		      const char * new_ext, myf myflags);
 int lock_file(MI_CHECK *param, File file, my_off_t start, int lock_type,
 	      const char *filetype, const char *filename);
 void lock_memory(MI_CHECK *param);
diff --git a/mysys/my_redel.c b/mysys/my_redel.c
index a47df8265c8..25391cd4e8f 100644
--- a/mysys/my_redel.c
+++ b/mysys/my_redel.c
@@ -1,6 +1,6 @@
-/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; version 2 of the License.
 
@@ -33,10 +33,13 @@ struct utimbuf {
 	  Copy stats from old file to new file, deletes orginal and
 	  changes new file name to old file name
 
 	  if MY_REDEL_MAKE_COPY is given, then the orginal file
 	  is renamed to org_name-'current_time'.BAK
+
+          if MY_REDEL_NO_COPY_STAT is given, stats are not copied
+          from org_name to tmp_name.
 	*/
 
 #define REDEL_EXT ".BAK"
 
 int my_redel(const char *org_name, const char *tmp_name, myf MyFlags)
@@ -44,12 +47,15 @@ int my_redel(const char *org_name, const char *tmp_name, myf MyFlags)
   int error=1;
   DBUG_ENTER("my_redel");
   DBUG_PRINT("my",("org_name: '%s' tmp_name: '%s'  MyFlags: %d",
 		   org_name,tmp_name,MyFlags));
 
-  if (my_copystat(org_name,tmp_name,MyFlags) < 0)
-    goto end;
+  if (!(MyFlags & MY_REDEL_NO_COPY_STAT))
+  {
+    if (my_copystat(org_name,tmp_name,MyFlags) < 0)
+      goto end;
+  }
   if (MyFlags & MY_REDEL_MAKE_BACKUP)
   {
     char name_buff[FN_REFLEN+20];    
     char ext[20];
     ext[0]='-';
diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc
index 602a0ae6cc1..21cbef32188 100644
--- a/storage/myisam/ha_myisam.cc
+++ b/storage/myisam/ha_myisam.cc
@@ -1,7 +1,7 @@
 /*
-   Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+   Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; version 2 of the License.
 
@@ -1089,28 +1089,40 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool do_optimize)
       {
         char buf[40];
         /* TODO: respect myisam_repair_threads variable */
         my_snprintf(buf, 40, "Repair with %d threads", my_count_bits(key_map));
         thd_proc_info(thd, buf);
+        /*
+          The new file is created with the right stats, so we can skip
+          copying file stats from old to new.
+        */
         error = mi_repair_parallel(&param, file, fixed_name,
-            param.testflag & T_QUICK);
+                                   param.testflag & T_QUICK, TRUE);
         thd_proc_info(thd, "Repair done"); // to reset proc_info, as
                                       // it was pointing to local buffer
       }
       else
       {
         thd_proc_info(thd, "Repair by sorting");
+        /*
+          The new file is created with the right stats, so we can skip
+          copying file stats from old to new.
+        */
         error = mi_repair_by_sort(&param, file, fixed_name,
-            param.testflag & T_QUICK);
+                                  param.testflag & T_QUICK, TRUE);
       }
     }
     else
     {
       thd_proc_info(thd, "Repair with keycache");
       param.testflag &= ~T_REP_BY_SORT;
+      /*
+        The new file is created with the right stats, so we can skip
+        copying file stats from old to new.
+      */
       error=  mi_repair(&param, file, fixed_name,
-			param.testflag & T_QUICK);
+			param.testflag & T_QUICK, TRUE);
     }
 #ifdef HAVE_MMAP
     if (remap)
       mi_dynmap_file(file, file->state->data_file_length);
 #endif
@@ -1122,11 +1134,15 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool do_optimize)
     if ((local_testflag & T_SORT_INDEX) &&
 	(share->state.changed & STATE_NOT_SORTED_PAGES))
     {
       optimize_done=1;
       thd_proc_info(thd, "Sorting index");
-      error=mi_sort_index(&param,file,fixed_name);
+      /*
+        The new file is created with the right stats, so we can skip
+        copying file stats from old to new.
+      */
+      error=mi_sort_index(&param,file,fixed_name, TRUE);
     }
     if (!statistics_done && (local_testflag & T_STATISTICS))
     {
       if (share->state.changed & STATE_NOT_ANALYZED)
       {
diff --git a/storage/myisam/mi_check.c b/storage/myisam/mi_check.c
index ba1f975549a..fe0d4c9c30b 100644
--- a/storage/myisam/mi_check.c
+++ b/storage/myisam/mi_check.c
@@ -1,7 +1,7 @@
 /*
-   Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+   Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; version 2 of the License.
 
@@ -1510,11 +1510,11 @@ static int mi_drop_all_indexes(MI_CHECK *param, MI_INFO *info, my_bool force)
 
 	/* Recover old table by reading each record and writing all keys */
 	/* Save new datafile-name in temp_filename */
 
 int mi_repair(MI_CHECK *param, register MI_INFO *info,
-	      char * name, int rep_quick)
+	      char * name, int rep_quick, my_bool no_copy_stat)
 {
   int error,got_error;
   ha_rows start_records,new_header_length;
   my_off_t del;
   File new_file;
@@ -1724,10 +1724,15 @@ err:
   if (!got_error)
   {
     /* Replace the actual file with the temporary file */
     if (new_file >= 0)
     {
+      myf flags= 0;
+      if (param->testflag & T_BACKUP_DATA)
+        flags |= MY_REDEL_MAKE_BACKUP;
+      if (no_copy_stat)
+        flags |= MY_REDEL_NO_COPY_STAT;
       mysql_file_close(new_file, MYF(0));
       info->dfile=new_file= -1;
       /*
         On Windows, the old data file cannot be deleted if it is either
         open, or memory mapped. Closing the file won't remove the memory
@@ -1742,12 +1747,11 @@ err:
         (void) my_munmap((char*) info->s->file_map,
                          (size_t) info->s->mmaped_length);
         info->s->file_map= NULL;
       }
       if (change_to_newfile(share->data_file_name, MI_NAME_DEXT, DATA_TMP_EXT,
-			    (param->testflag & T_BACKUP_DATA ?
-			     MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) ||
+                            flags) ||
 	  mi_open_datafile(info,share,name,-1))
 	got_error=1;
 
       param->retry_repair= 0;
     }
@@ -1931,11 +1935,12 @@ int flush_blocks(MI_CHECK *param, KEY_CACHE *key_cache, File file)
 } /* flush_blocks */
 
 
 	/* Sort index for more efficent reads */
 
-int mi_sort_index(MI_CHECK *param, register MI_INFO *info, char * name)
+int mi_sort_index(MI_CHECK *param, register MI_INFO *info, char * name,
+                  my_bool no_copy_stat)
 {
   reg2 uint key;
   reg1 MI_KEYDEF *keyinfo;
   File new_file;
   my_off_t index_pos[HA_MAX_POSSIBLE_KEY];
@@ -2002,11 +2007,11 @@ int mi_sort_index(MI_CHECK *param, register MI_INFO *info, char * name)
   (void) _mi_writeinfo(info,WRITEINFO_UPDATE_KEYFILE);
   (void) mysql_file_close(share->kfile, MYF(MY_WME));
   share->kfile = -1;
   (void) mysql_file_close(new_file, MYF(MY_WME));
   if (change_to_newfile(share->index_file_name, MI_NAME_IEXT, INDEX_TMP_EXT,
-			MYF(0)) ||
+			no_copy_stat ? MYF(MY_REDEL_NO_COPY_STAT) : MYF(0)) ||
       mi_open_keyfile(share))
     goto err2;
   info->lock_type= F_UNLCK;			/* Force mi_readinfo to lock */
   _mi_readinfo(info,F_WRLCK,0);			/* Will lock the table */
   info->lock_type=  old_lock;
@@ -2207,18 +2212,20 @@ err:
     mi_repair_by_sort()
     param		Repair parameters
     info		MyISAM handler to repair
     name		Name of table (for warnings)
     rep_quick		set to <> 0 if we should not change data file
+    no_copy_stat        Don't copy file stats from old to new file,
+                        assume that new file was created with correct stats
 
   RESULT
     0	ok
     <>0	Error
 */
 
 int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
-		      const char * name, int rep_quick)
+		      const char * name, int rep_quick, my_bool no_copy_stat)
 {
   int got_error;
   uint i;
   ulong length;
   ha_rows start_records;
@@ -2541,15 +2548,19 @@ err:
   if (!got_error)
   {
     /* Replace the actual file with the temporary file */
     if (new_file >= 0)
     {
+      myf flags= 0;
+      if (param->testflag & T_BACKUP_DATA)
+        flags |= MY_REDEL_MAKE_BACKUP;
+      if (no_copy_stat)
+        flags |= MY_REDEL_NO_COPY_STAT;
       mysql_file_close(new_file, MYF(0));
       info->dfile=new_file= -1;
       if (change_to_newfile(share->data_file_name,MI_NAME_DEXT, DATA_TMP_EXT,
-			    (param->testflag & T_BACKUP_DATA ?
-			     MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) ||
+                            flags) ||
 	  mi_open_datafile(info,share,name,-1))
 	got_error=1;
     }
   }
   if (got_error)
@@ -2593,10 +2604,12 @@ err:
     mi_repair_parallel()
     param		Repair parameters
     info		MyISAM handler to repair
     name		Name of table (for warnings)
     rep_quick		set to <> 0 if we should not change data file
+    no_copy_stat        Don't copy file stats from old to new file,
+                        assume that new file was created with correct stats
 
   DESCRIPTION
     Same as mi_repair_by_sort but do it multithreaded
     Each key is handled by a separate thread.
     TODO: make a number of threads a parameter
@@ -2627,11 +2640,11 @@ err:
     0	ok
     <>0	Error
 */
 
 int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
-			const char * name, int rep_quick)
+                       const char * name, int rep_quick, my_bool no_copy_stat)
 {
   int got_error;
   uint i,key, total_key_length, istep;
   ulong rec_length;
   ha_rows start_records;
@@ -3074,15 +3087,19 @@ err:
   if (!got_error)
   {
     /* Replace the actual file with the temporary file */
     if (new_file >= 0)
     {
+      myf flags= 0;
+      if (param->testflag & T_BACKUP_DATA)
+        flags |= MY_REDEL_MAKE_BACKUP;
+      if (no_copy_stat)
+        flags |= MY_REDEL_NO_COPY_STAT;
       mysql_file_close(new_file, MYF(0));
       info->dfile=new_file= -1;
       if (change_to_newfile(share->data_file_name, MI_NAME_DEXT, DATA_TMP_EXT,
-			    (param->testflag & T_BACKUP_DATA ?
-			     MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) ||
+			    flags) ||
 	  mi_open_datafile(info,share,name,-1))
 	got_error=1;
     }
   }
   if (got_error)
diff --git a/storage/myisam/myisamchk.c b/storage/myisam/myisamchk.c
index 8606bd7c748..9360a054872 100644
--- a/storage/myisam/myisamchk.c
+++ b/storage/myisam/myisamchk.c
@@ -1,6 +1,6 @@
-/* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; version 2 of the License.
 
@@ -991,18 +991,22 @@ static int myisamchk(MI_CHECK *param, char * filename)
 	     (rep_quick && !param->keys_in_use && !recreate)) &&
 	    mi_test_if_sort_rep(info, info->state->records,
 				info->s->state.key_map,
 				param->force_sort))
 	{
+          /*
+            The new file might not be created with the right stats depending
+            on how myisamchk is run, so we must copy file stats from old to new.
+          */
           if (param->testflag & T_REP_BY_SORT)
-            error=mi_repair_by_sort(param,info,filename,rep_quick);
+            error= mi_repair_by_sort(param, info, filename, rep_quick, FALSE);
           else
-            error=mi_repair_parallel(param,info,filename,rep_quick);
+            error= mi_repair_parallel(param, info, filename, rep_quick, FALSE);
 	  state_updated=1;
 	}
 	else if (param->testflag & T_REP_ANY)
-	  error=mi_repair(param, info,filename,rep_quick);
+	  error= mi_repair(param, info, filename, rep_quick, FALSE);
       }
       if (!error && param->testflag & T_SORT_RECORDS)
       {
 	/*
 	  The data file is nowadays reopened in the repair code so we should
@@ -1038,16 +1042,16 @@ static int myisamchk(MI_CHECK *param, char * filename)
 	  datafile=info->dfile;	/* This is now locked */
 	  if (!error && !update_index)
 	  {
 	    if (param->verbose)
 	      puts("Table had a compressed index;  We must now recreate the index");
-	    error=mi_repair_by_sort(param,info,filename,1);
+	    error= mi_repair_by_sort(param, info, filename, 1, FALSE);
 	  }
 	}
       }
       if (!error && param->testflag & T_SORT_INDEX)
-	error=mi_sort_index(param,info,filename);
+	error= mi_sort_index(param, info, filename, FALSE);
       if (!error)
 	share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
 				 STATE_CRASHED_ON_REPAIR);
       else
 	mi_mark_crashed(info);

Vulnerable code: /* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
   Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
	      char * name, int rep_quick);
int mi_sort_index(MI_CHECK *param, register MI_INFO *info, char * name);
		      const char * name, int rep_quick);
		      const char * name, int rep_quick);
/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
  if (my_copystat(org_name,tmp_name,MyFlags) < 0)
    goto end;
   Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
            param.testflag & T_QUICK);
            param.testflag & T_QUICK);
			param.testflag & T_QUICK);
      error=mi_sort_index(&param,file,fixed_name);
   Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
	      char * name, int rep_quick)
			    (param->testflag & T_BACKUP_DATA ?
			     MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) ||
int mi_sort_index(MI_CHECK *param, register MI_INFO *info, char * name)
			MYF(0)) ||
		      const char * name, int rep_quick)
			    (param->testflag & T_BACKUP_DATA ?
			     MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) ||
			const char * name, int rep_quick)
			    (param->testflag & T_BACKUP_DATA ?
			     MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) ||
/* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
            error=mi_repair_by_sort(param,info,filename,rep_quick);
            error=mi_repair_parallel(param,info,filename,rep_quick);
	  error=mi_repair(param, info,filename,rep_quick);
	    error=mi_repair_by_sort(param,info,filename,1);
	error=mi_sort_index(param,info,filename);
Fixed code: /* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
#define MY_REDEL_NO_COPY_STAT 512 /* my_redel() doesn't call my_copystat() */
   Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
	      char * name, int rep_quick, my_bool no_copy_stat);
int mi_sort_index(MI_CHECK *param, register MI_INFO *info, char * name,
                  my_bool no_copy_stat);
		      const char * name, int rep_quick, my_bool no_copy_stat);
                       const char * name, int rep_quick, my_bool no_copy_stat);
/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.

          if MY_REDEL_NO_COPY_STAT is given, stats are not copied
          from org_name to tmp_name.
  if (!(MyFlags & MY_REDEL_NO_COPY_STAT))
  {
    if (my_copystat(org_name,tmp_name,MyFlags) < 0)
      goto end;
  }
   Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
        /*
          The new file is created with the right stats, so we can skip
          copying file stats from old to new.
        */
                                   param.testflag & T_QUICK, TRUE);
        /*
          The new file is created with the right stats, so we can skip
          copying file stats from old to new.
        */
                                  param.testflag & T_QUICK, TRUE);
      /*
        The new file is created with the right stats, so we can skip
        copying file stats from old to new.
      */
			param.testflag & T_QUICK, TRUE);
      /*
        The new file is created with the right stats, so we can skip
        copying file stats from old to new.
      */
      error=mi_sort_index(&param,file,fixed_name, TRUE);
   Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
	      char * name, int rep_quick, my_bool no_copy_stat)
      myf flags= 0;
      if (param->testflag & T_BACKUP_DATA)
        flags |= MY_REDEL_MAKE_BACKUP;
      if (no_copy_stat)
        flags |= MY_REDEL_NO_COPY_STAT;
                            flags) ||
int mi_sort_index(MI_CHECK *param, register MI_INFO *info, char * name,
                  my_bool no_copy_stat)
			no_copy_stat ? MYF(MY_REDEL_NO_COPY_STAT) : MYF(0)) ||
    no_copy_stat        Don't copy file stats from old to new file,
                        assume that new file was created with correct stats
		      const char * name, int rep_quick, my_bool no_copy_stat)
      myf flags= 0;
      if (param->testflag & T_BACKUP_DATA)
        flags |= MY_REDEL_MAKE_BACKUP;
      if (no_copy_stat)
        flags |= MY_REDEL_NO_COPY_STAT;
                            flags) ||
    no_copy_stat        Don't copy file stats from old to new file,
                        assume that new file was created with correct stats
                       const char * name, int rep_quick, my_bool no_copy_stat)
      myf flags= 0;
      if (param->testflag & T_BACKUP_DATA)
        flags |= MY_REDEL_MAKE_BACKUP;
      if (no_copy_stat)
        flags |= MY_REDEL_NO_COPY_STAT;
			    flags) ||
/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
          /*
            The new file might not be created with the right stats depending
            on how myisamchk is run, so we must copy file stats from old to new.
          */
            error= mi_repair_by_sort(param, info, filename, rep_quick, FALSE);
            error= mi_repair_parallel(param, info, filename, rep_quick, FALSE);
	  error= mi_repair(param, info, filename, rep_quick, FALSE);
	    error= mi_repair_by_sort(param, info, filename, 1, FALSE);
	error= mi_sort_index(param, info, filename, FALSE);