List:Commits« Previous MessageNext Message »
From:Ingo Struewing Date:May 19 2009 9:48am
Subject:bzr commit into mysql-6.0-backup branch (ingo.struewing:2808) Bug#43767
View as plain text  
#At file:///home2/mydev/bzrroot/mysql-6.0-bug43767-2/ based on revid:charles.bell@stripped

 2808 Ingo Struewing	2009-05-19
      Bug#43767 - Wrong path if backupdir is symlink and backref path used
      
      Addendum fix to Bug#43747 (BACKUP with backref path succeeds
      on invalid backupdir) and Bug#43767.
      
      The former fix checked every path element for being a symlink.
      Only then it was prevented to let ../ remove this path element.
      
      But the correct solution is to prevent ../ from removing all
      path elements except of real (non-symlinked) directories.
      
      A path like dir/non-existent-file.txt/../existent-file.txt must not
      be cleaned up to dir/existent-file.txt. Normal (operating system)
      file operations don't do that either.
      
      ".." is a valid path element with its back-referencing semantics
      in an existent directory only.
      
      However, on Windows, we need to do the clean-ups irrespectively
      of the file system object. Windows system services do the clean-up
      even after path elements that refer to non-existent objects.
      In the above example, dir/existent-file.txt is used.
      
      safe_cleanup_cat_path(), its unittest, and the regression tests
      do now respect the platform difference.
     @ include/my_sys.h
        Bug#43767 - Wrong path if backupdir is symlink and backref path used
        Added MY_RETURN_SYMLINK.
     @ mysql-test/suite/backup/include/backup_image_path.inc
        Bug#43767 - Wrong path if backupdir is symlink and backref path used
        New body for new test cases.
     @ mysql-test/suite/backup/r/backup_image_path_nonwin.result
        Bug#43767 - Wrong path if backupdir is symlink and backref path used
        New test result.
     @ mysql-test/suite/backup/r/backup_image_path_win.result
        Bug#43767 - Wrong path if backupdir is symlink and backref path used
        New test result.
     @ mysql-test/suite/backup/t/backup_image_path_nonwin.test
        Bug#43767 - Wrong path if backupdir is symlink and backref path used
        New test case.
     @ mysql-test/suite/backup/t/backup_image_path_win.test
        Bug#43767 - Wrong path if backupdir is symlink and backref path used
        New test case.
     @ mysys/mf_pack.c
        Bug#43767 - Wrong path if backupdir is symlink and backref path used
        Fixed comments.
        Changed check for symlink to check for real directory.
     @ mysys/my_lib.c
        Bug#43767 - Wrong path if backupdir is symlink and backref path used
        Added test_if_real_directory().
     @ unittest/mysys/safe_cleanup_cat_path-t.c
        Bug#43767 - Wrong path if backupdir is symlink and backref path used
        Changed unittest to work with real directories.
        Added tests to be more systematic.
        Grouped platform specific tests.

    added:
      mysql-test/suite/backup/include/backup_image_path.inc
      mysql-test/suite/backup/r/backup_image_path_nonwin.result
      mysql-test/suite/backup/r/backup_image_path_win.result
      mysql-test/suite/backup/t/backup_image_path_nonwin.test
      mysql-test/suite/backup/t/backup_image_path_win.test
    modified:
      include/my_sys.h
      mysys/mf_pack.c
      mysys/my_lib.c
      unittest/mysys/safe_cleanup_cat_path-t.c
=== modified file 'include/my_sys.h'
--- a/include/my_sys.h	2009-04-30 09:24:45 +0000
+++ b/include/my_sys.h	2009-05-19 09:48:45 +0000
@@ -84,6 +84,7 @@ extern int NEAR my_errno;		/* Last error
 #define MY_HOLD_ON_ERROR 256	/* my_realloc() ; Return old ptr on error */
 #define MY_DONT_OVERWRITE_FILE 2048 /* my_copy: Don't overwrite file */
 #define MY_THREADSAFE 2048      /* my_seek(): lock fd mutex */
+#define MY_RETURN_SYMLINK 4096  /* my_stat(); Use lstat(2), don't follow link */
 
 #define MY_CHECK_ERROR	1	/* Params to my_end; Check open-close */
 #define MY_GIVE_INFO	2	/* Give time info about process*/

=== added file 'mysql-test/suite/backup/include/backup_image_path.inc'
--- a/mysql-test/suite/backup/include/backup_image_path.inc	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/backup/include/backup_image_path.inc	2009-05-19 09:48:45 +0000
@@ -0,0 +1,82 @@
+#
+# This test is designed to ensure that the backup image file path name
+# is handled like operating system would treat it.
+#
+# Needs the following variables:
+# $WIN      1: Windows, 0: Not Windows
+#
+# Ingo Struewing, 2009-05-18
+#
+
+--echo #
+--echo # Bug#43767 - Wrong path if backupdir is symlink and backref path used
+--echo #
+
+--echo # Select \$BACKUPDIR: \$MYSQLTEST_VARDIR/tmp
+--let $BACKUPDIR = $MYSQLTEST_VARDIR/tmp
+
+--echo # Select \$TESTDIR:   bup_image_path_dir
+--let $TESTDIR = bup_image_path_dir
+
+--echo # Preparatory cleanup.
+--disable_warnings
+--error 0,1
+--remove_file $BACKUPDIR/$TESTDIR/bup_image_path_file.bak
+--error 0,1,2
+--rmdir $BACKUPDIR/$TESTDIR/dir1
+--error 0,1,2
+--rmdir $BACKUPDIR/$TESTDIR
+DROP DATABASE IF EXISTS bup_image_path;
+--enable_warnings
+
+--echo # Create database.
+CREATE DATABASE bup_image_path;
+--echo # Create test directory \$BACKUPDIR/\$TESTDIR
+--mkdir $BACKUPDIR/$TESTDIR
+--echo # Create a subdirectory \$BACKUPDIR/\$TESTDIR/dir1
+--mkdir $BACKUPDIR/$TESTDIR/dir1
+--echo # Set backupdir variable (statement suppressed).
+--disable_query_log
+eval SET @@global.backupdir = '$BACKUPDIR';
+--enable_query_log
+
+--echo # Run BACKUP. Create new backup image file.
+--replace_column 1 #
+eval BACKUP DATABASE bup_image_path TO '$TESTDIR/bup_image_path_file.bak';
+
+if (!$WIN)
+{
+  --echo # Attempt RESTORE through a non-sense path name.
+  --replace_regex /Errcode: [0-9]+/Errcode: #/
+  --replace_result $BACKUPDIR BACKUPDIR
+  --error 29
+  eval RESTORE FROM
+    '$TESTDIR/non-existent-file.txt/../bup_image_path_file.bak'
+    OVERWRITE;
+}
+if ($WIN)
+{
+  --echo # Run RESTORE through a non-sense path name.
+  --replace_column 1 #
+  eval RESTORE FROM
+    '$TESTDIR/non-existent-file.txt/../bup_image_path_file.bak'
+    OVERWRITE;
+}
+
+--echo # Run RESTORE through a valid path name.
+# Replace backup_id and warning numbers
+--replace_column 1 # 2 #
+eval RESTORE FROM '$TESTDIR/bup_image_path_file.bak' OVERWRITE;
+
+--echo # Run RESTORE through a valid path name.
+# Replace backup_id and warning numbers
+--replace_column 1 # 2 #
+eval RESTORE FROM '$TESTDIR/./dir1/.././bup_image_path_file.bak' OVERWRITE;
+
+--echo # Cleanup
+--remove_file $BACKUPDIR/$TESTDIR/bup_image_path_file.bak
+DROP DATABASE bup_image_path;
+--rmdir $BACKUPDIR/$TESTDIR/dir1
+--rmdir $BACKUPDIR/$TESTDIR
+SET @@global.backupdir = DEFAULT;
+

=== added file 'mysql-test/suite/backup/r/backup_image_path_nonwin.result'
--- a/mysql-test/suite/backup/r/backup_image_path_nonwin.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/backup/r/backup_image_path_nonwin.result	2009-05-19 09:48:45 +0000
@@ -0,0 +1,32 @@
+#
+# Bug#43767 - Wrong path if backupdir is symlink and backref path used
+#
+# Select $BACKUPDIR: $MYSQLTEST_VARDIR/tmp
+# Select $TESTDIR:   bup_image_path_dir
+# Preparatory cleanup.
+DROP DATABASE IF EXISTS bup_image_path;
+# Create database.
+CREATE DATABASE bup_image_path;
+# Create test directory $BACKUPDIR/$TESTDIR
+# Create a subdirectory $BACKUPDIR/$TESTDIR/dir1
+# Set backupdir variable (statement suppressed).
+# Run BACKUP. Create new backup image file.
+BACKUP DATABASE bup_image_path TO 'bup_image_path_dir/bup_image_path_file.bak';
+backup_id
+#
+# Attempt RESTORE through a non-sense path name.
+RESTORE FROM
+'bup_image_path_dir/non-existent-file.txt/../bup_image_path_file.bak'
+    OVERWRITE;
+ERROR HY000: File 'BACKUPDIR/bup_image_path_dir/non-existent-file.txt/../bup_image_path_file.bak' not found (Errcode: #)
+# Run RESTORE through a valid path name.
+RESTORE FROM 'bup_image_path_dir/bup_image_path_file.bak' OVERWRITE;
+backup_id
+#
+# Run RESTORE through a valid path name.
+RESTORE FROM 'bup_image_path_dir/./dir1/.././bup_image_path_file.bak' OVERWRITE;
+backup_id
+#
+# Cleanup
+DROP DATABASE bup_image_path;
+SET @@global.backupdir = DEFAULT;

=== added file 'mysql-test/suite/backup/r/backup_image_path_win.result'
--- a/mysql-test/suite/backup/r/backup_image_path_win.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/backup/r/backup_image_path_win.result	2009-05-19 09:48:45 +0000
@@ -0,0 +1,33 @@
+#
+# Bug#43767 - Wrong path if backupdir is symlink and backref path used
+#
+# Select $BACKUPDIR: $MYSQLTEST_VARDIR/tmp
+# Select $TESTDIR:   bup_image_path_dir
+# Preparatory cleanup.
+DROP DATABASE IF EXISTS bup_image_path;
+# Create database.
+CREATE DATABASE bup_image_path;
+# Create test directory $BACKUPDIR/$TESTDIR
+# Create a subdirectory $BACKUPDIR/$TESTDIR/dir1
+# Set backupdir variable (statement suppressed).
+# Run BACKUP. Create new backup image file.
+BACKUP DATABASE bup_image_path TO 'bup_image_path_dir/bup_image_path_file.bak';
+backup_id
+#
+# Run RESTORE through a non-sense path name.
+RESTORE FROM
+'bup_image_path_dir/non-existent-file.txt/../bup_image_path_file.bak'
+    OVERWRITE;
+backup_id
+#
+# Run RESTORE through a valid path name.
+RESTORE FROM 'bup_image_path_dir/bup_image_path_file.bak' OVERWRITE;
+backup_id
+#
+# Run RESTORE through a valid path name.
+RESTORE FROM 'bup_image_path_dir/./dir1/.././bup_image_path_file.bak' OVERWRITE;
+backup_id
+#
+# Cleanup
+DROP DATABASE bup_image_path;
+SET @@global.backupdir = DEFAULT;

=== added file 'mysql-test/suite/backup/t/backup_image_path_nonwin.test'
--- a/mysql-test/suite/backup/t/backup_image_path_nonwin.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/backup/t/backup_image_path_nonwin.test	2009-05-19 09:48:45 +0000
@@ -0,0 +1,17 @@
+#
+# This test is designed to ensure that the backup image file path name
+# is handled like operating system would treat it.
+#
+# Ingo Struewing, 2009-05-18, Bug#43767 - Wrong path if backupdir is symlink
+#                                         and backref path used
+#
+# Test case for non-Windows platforms.
+#
+
+--source include/not_embedded.inc
+--source include/not_windows.inc
+
+--let $WIN=0
+
+--source suite/backup/include/backup_image_path.inc
+

=== added file 'mysql-test/suite/backup/t/backup_image_path_win.test'
--- a/mysql-test/suite/backup/t/backup_image_path_win.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/backup/t/backup_image_path_win.test	2009-05-19 09:48:45 +0000
@@ -0,0 +1,17 @@
+#
+# This test is designed to ensure that the backup image file path name
+# is handled like operating system would treat it.
+#
+# Ingo Struewing, 2009-05-18, Bug#43767 - Wrong path if backupdir is symlink
+#                                         and backref path used
+#
+# Test case for Windows platforms.
+#
+
+--source include/not_embedded.inc
+--source include/windows.inc
+
+--let $WIN=1
+
+--source suite/backup/include/backup_image_path.inc
+

=== modified file 'mysys/mf_pack.c'
--- a/mysys/mf_pack.c	2009-04-30 09:24:45 +0000
+++ b/mysys/mf_pack.c	2009-05-19 09:48:45 +0000
@@ -242,12 +242,12 @@ size_t cleanup_dirname(register char *to
   Empty arguments ("") are ignored. No double FN_LIBCHAR is inserted.
 
   "./" at begin is removed, possibly multiple times.
-  "/./" is replaced by "/".
-  "/." at end is removed.
+  "/./" is replaced by "/" if previous path element is a real directory.
+  "/." at end is removed if previous path element is a real directory.
   "../" at begin is retained.
-  "/../" removes previous path element, unless it is a symlink.
+  "/../" removes previous path element, if it is a real directory.
   "/../" at begin is replaced by "/".
-  "/.." at end removes previous path element, unless it is a symlink.
+  "/.." at end removes previous path element, if it is a real directory.
   "~/" at path begin replaces ~ by home directory.
   "//" is replaced by "/", except on Win32 at begin.
 
@@ -266,16 +266,28 @@ size_t cleanup_dirname(register char *to
   $HOME is an absolute path. If 'path' is absolute, 'to' will be
   absolute too.
 
-  For each path element from the beginning, my_is_symlink() is called.
-  If the element is not a symlink, it can be cleaned out. If a symlink
-  is encountered, the part of the path behind it is treated as a
-  relative path in itself. It is cleaned in itself like the above, but
-  my_is_symlink() takes the concatenated previous path segments
-  prepended. If another symlink is found, the algorithm repeats. That
-  way we might end up with no ../ except possibly after symlinks:
+  For each path element from the beginning, test_if_real_directory() is
+  called. If the element is a real, existent (non-symlinked) directory,
+  it can be cleaned out by a following ../, and a following ./ can be
+  dropped. If a symlink, non-directory object, or non-existent object is
+  encountered, the part of the path behind it is treated as a relative
+  path in itself. It is cleaned in itself like the above, with the
+  exception that leading ./ and ~/ are retained, but
+  test_if_real_directory() takes the concatenated previous path segments
+  prepended. If another non-real-directory is found, the algorithm
+  repeats. That way we might end up with no ../ or ./ except possibly
+  after symlinks or other non-real-directory objects:
+
     Input:  /path/with/symlink/up/../../yet/another/symlink/up/../end
     Output: /path/with/symlink/../yet/another/symlink/end
 
+  After a path element references a non-existent file system object, no
+  further cleaning can be done. Otherwise we might create a path to a
+  wrong object.
+
+    Input:  dir1/../dir2/non-existent-file.txt/../existent-file.txt
+    Output: dir2/non-existent-file.txt/../existent-file.txt
+
   @param[out]   to              address of destination buffer
   @param[in]    to_size         size of destination buffer
   @param[in]    ...             Multiple paths (!= to), terminated by NullS
@@ -360,7 +372,7 @@ size_t safe_cleanup_cat_path(char *to, s
     memcpy(to, home_dir, length);
     /*
       Do not allow $HOME path members to be eaten by ../
-      Otherwise we must check every $HOME path element for symlink.
+      Otherwise we must check every $HOME path element for real directory.
     */
     start= to + length;
     /* Skip ~ and point at / */
@@ -421,12 +433,12 @@ size_t safe_cleanup_cat_path(char *to, s
         }
         /*
           At root, we are back at the beginning.
-          After a symlink, start points to the first dot of /..
+          After a non-real-directory, start points to the first dot of /..
           so we won't enter this branch, but the ../ branch below.
         */
       }
       /*
-        If path starts as ../ or has ../ after a symlink,
+        If path starts as ../ or has ../ after a non-real-directory,
         set a new start to avoid its removal.
       */
       else if (((size_t) (pos - start) == (parent_len - 1)) &&
@@ -435,7 +447,7 @@ size_t safe_cleanup_cat_path(char *to, s
         start= pos + 1;
       }
       /* Remove duplicate '/' */
-      else if ((pos > start) && (pos[-1] == FN_LIBCHAR))
+      else if ((pos > to) && (pos[-1] == FN_LIBCHAR))
       {
 #ifdef FN_NETWORK_DRIVES
         /* Keep // at path begin. */
@@ -443,7 +455,7 @@ size_t safe_cleanup_cat_path(char *to, s
 #endif
           pos--;
       }
-      /* Skip /./ */
+      /* Skip /./ which could also be at path end. */
       else if (((pos - start) > 1) &&
                (pos[-1] == FN_CURLIB) &&
                (pos[-2] == FN_LIBCHAR))
@@ -457,19 +469,22 @@ size_t safe_cleanup_cat_path(char *to, s
         /* This brings pos below to (there is no valid character left). */
         pos-= 2; /* purecov: tested */ /* unittest */
       }
-      /* No cleanup done. Check if path element is a symbolic link. */
+      /* No cleanup done. Check if path element is a real directory. */
       else
       {
+#if !defined(__WIN__)
+        /* ^- Windows cleans up ../ and ./ regardless if directory or not. */
         if (pos > start)
         {
           /* Temporarily terminate the path name. */
           *pos= '\0';
-          if (my_is_symlink(to))
+          if (!test_if_real_directory(to))
           {
-            /* Prevent backstep over symlink. */
+            /* Prevent backstep over non-real-directory. */
             start= pos + 1;
           }
         }
+#endif
         /* Restore FN_LIBCHAR if not at last argument. */
         *pos= from_ptr ? FN_LIBCHAR : '\0';
       }

=== modified file 'mysys/my_lib.c'
--- a/mysys/my_lib.c	2009-04-24 14:55:53 +0000
+++ b/mysys/my_lib.c	2009-05-19 09:48:45 +0000
@@ -512,6 +512,8 @@ error:
 /**
   Test if path is a directory.
 
+  This test follows the symlink, if the path references one.
+
   @param[in]    path            path name
 
   @return       test result
@@ -530,6 +532,30 @@ my_bool test_if_directory(const char* pa
 }
 
 
+/**
+  Test if path is a real (non-symlinked) directory.
+
+  This test does not follow the symlink, if the path references one.
+  It returns FALSE, if the path references a symlink.
+
+  @param[in]    path            path name
+
+  @return       test result
+    @retval     TRUE            path is directory
+    @retval     FALSE           path is not directory
+*/
+
+my_bool test_if_real_directory(const char* path)
+{
+  MY_STAT statbuf;
+
+  if (my_stat(path, &statbuf, MYF(MY_RETURN_SYMLINK)) &&
+      MY_S_ISDIR(statbuf.st_mode))
+    return TRUE;
+  return FALSE;
+}
+
+
 /****************************************************************************
 ** File status
 ** Note that MY_STAT is assumed to be same as struct stat
@@ -552,6 +578,7 @@ int my_fstat(File Filedes, MY_STAT *stat
 MY_STAT *my_stat(const char *path, MY_STAT *stat_area, myf my_flags)
 {
   int m_used;
+  int res;
   DBUG_ENTER("my_stat");
   DBUG_PRINT("my", ("path: '%s'  stat_area: %p  MyFlags: %d", path,
                     stat_area, my_flags));
@@ -560,8 +587,14 @@ MY_STAT *my_stat(const char *path, MY_ST
     if (!(stat_area= (MY_STAT *) my_malloc(sizeof(MY_STAT), my_flags)))
       goto error;
 #ifndef _WIN32
-    if (! stat((char *) path, (struct stat *) stat_area) )
-      DBUG_RETURN(stat_area);
+#if defined (HAVE_LSTAT) && defined (S_ISLNK)
+  if (my_flags & MY_RETURN_SYMLINK)
+    res= lstat((char *) path, (struct stat *) stat_area);
+  else
+#endif
+    res= stat((char *) path, (struct stat *) stat_area);
+  if (!res)
+    DBUG_RETURN(stat_area);
 #else
     if (! my_win_stat(path, stat_area) )
       DBUG_RETURN(stat_area);

=== modified file 'unittest/mysys/safe_cleanup_cat_path-t.c'
--- a/unittest/mysys/safe_cleanup_cat_path-t.c	2009-04-24 14:55:53 +0000
+++ b/unittest/mysys/safe_cleanup_cat_path-t.c	2009-05-19 09:48:45 +0000
@@ -17,6 +17,11 @@
 #include <my_sys.h>
 #include <tap.h>
 #include <string.h>
+#if defined(__WIN__)
+#include <direct.h>
+#define chdir _chdir
+#define rmdir _rmdir
+#endif
 
 #define DST_SIZE 80
 
@@ -129,36 +134,133 @@ do_multi_test(const char *path1, const c
 int
 main(void)
 {
+  MY_INIT("safe_cleanup_cat_path-t");
+
   /* Set HOME for ~/ test. Trailing slash is for coverage test. */
   putenv((char*) "HOME=/home/unittest/");
 
-  MY_INIT("safe_cleanup_cat_path-t");
+  /* Create a directory with unique name and change to it. */
+  if (my_mkdir("safe_cleanup_cat_path_dir", 0777, MYF(MY_WME)))
+    goto end; /* purecov: inspected */
+  if (my_setwd("safe_cleanup_cat_path_dir", MYF(MY_WME)))
+    goto end1; /* purecov: inspected */
+
+  /* Create some test directories. */
+  if (my_mkdir("dir1", 0777, MYF(MY_WME)) ||
+      my_mkdir("dir1/dir2", 0777, MYF(MY_WME)) ||
+      my_mkdir("dir1/dir2/dir3", 0777, MYF(MY_WME)))
+    goto end2;
+
+  /* Use "file" for a non-existent file. */
 
-  plan(39);
+  plan(65);
 
-  do_test("a", "a");
-  do_test("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.bbb",
-          "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.bbb");
-  do_test("ccc/ccc", "ccc/ccc");
-  do_test("ddd/./ddd", "ddd/ddd");
-  do_test("eee/../fff", "fff");
-  do_test("ggg/hhh/iii/../../j", "ggg/j");
-  do_test("/kkk", "/kkk");
-  do_test("~/lll", concat_str(home_dir, "lll"));
-  do_test("./mmm", "mmm");
-  do_test("nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn"
-          "nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn"
-          "nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn",
+  do_test("", "");
+
+  do_test("file", "file");
+  do_test("file.file", "file.file");
+  do_test("file.file.file.file.file.file.file.file.file.file.file",
+          "file.file.file.file.file.file.file.file.file.file.file");
+
+  do_test("/", "/");
+  do_test("///", "/");
+  do_test("/file", "/file");
+#ifdef FN_NETWORK_DRIVES
+  do_test("//file///", "//file");
+  do_test("///file///", "//file");
+#else
+  do_test("//file///", "/file");
+  do_test("///file///", "/file");
+#endif
+
+  do_test("dir1/file", "dir1/file");
+  do_test("dir1///file", "dir1/file");
+  do_test("dir1/dir2/", "dir1/dir2");
+  do_test("dir1/dir2///", "dir1/dir2");
+
+  do_test("file/file", "file/file");
+  do_test("file///file", "file/file");
+  do_test("file/file/", "file/file");
+  do_test("file/file///", "file/file");
+
+  do_test(".", ".");
+  do_test("./", ".");
+  do_test("./.", ".");
+  do_test("././", ".");
+  do_test("./dir1", "dir1");
+  do_test("./file", "file");
+  do_test("././dir1", "dir1");
+  do_test("././file", "file");
+
+  do_test("dir1/./file", "dir1/file");
+  do_test("dir1/././file", "dir1/file");
+  do_test("dir1/.", "dir1");
+  do_test("dir1/./.", "dir1");
+
+#if defined(__WIN__)
+  /* Windows does path cleanup differently. */
+  do_test("file/./file", "file/file");
+  do_test("file/././file", "file/file");
+  do_test("file/.", "file");
+  do_test("file/./.", "file");
+#else
+  do_test("file/./file", "file/./file");
+  do_test("file/././file", "file/././file");
+  do_test("file/.", "file/.");
+  do_test("file/./.", "file/./.");
+#endif
+
+  do_test("..", "..");
+  do_test("../..", "../..");
+  do_test("../../", "../..");
+  do_test("../../file", "../../file");
+  do_test("/../..", "/");
+  do_test("/../file", "/file");
+  do_test("/../../file", "/file");
+  do_test("/../../", "/");
+
+  do_test("dir1/../file", "file");
+  do_test("dir1/dir2/dir3/../../file", "dir1/file");
+  do_test("dir1/dir2/..", "dir1");
+  do_test("dir1/..", ".");
+
+#if defined(__WIN__)
+  /* Windows does path cleanup differently. */
+  do_test("file/../file", "file");
+  do_test("dir1/dir2/file/../../file", "dir1/file");
+  do_test("file/file/..", "file");
+  do_test("file/..", ".");
+  do_test("dir1/../dir2/non-existent-file.txt/../existent-file.txt",
+          "dir2/existent-file.txt");
+  do_test("dir1/../dir2/non-existent-file.txt/./.././existent-file.txt",
+          "dir2/existent-file.txt");
+#else
+  do_test("file/../file", "file/../file");
+  do_test("dir1/dir2/file/../../file", "dir1/dir2/file/../../file");
+  do_test("file/file/..", "file/file/..");
+  do_test("file/..", "file/..");
+  do_test("dir1/../dir2/non-existent-file.txt/../existent-file.txt",
+          "dir2/non-existent-file.txt/../existent-file.txt");
+  do_test("dir1/../dir2/non-existent-file.txt/./.././existent-file.txt",
+          "dir2/non-existent-file.txt/./.././existent-file.txt");
+#endif
+
+  do_test("~/file", concat_str(home_dir, "/file"));
+  do_test("dir1/~/file", "dir1/~/file");
+  /* Exceed DST_SIZE. Result should be empty string. */
+  do_test("file.file.file.file.file.file.file.file.file.file.file"
+          "file.file.file.file.file.file.file.file.file.file.file"
+          "file.file.file.file.file.file.file.file.file.file.file",
           "");
+
 #ifdef HAVE_READLINK
   {
     int rc;
-    (void) my_delete("safe_cleanup_cat_path_symlink", MYF(0));
-    rc= my_symlink("symlink_target", "safe_cleanup_cat_path_symlink",
-                   MYF(MY_WME));
-    do_test("safe_cleanup_cat_path_symlink/../../ooo/././oo/../../o",
-            "safe_cleanup_cat_path_symlink/../../o");
-    (void) my_delete("safe_cleanup_cat_path_symlink", MYF(0));
+    (void) my_delete("symlink1", MYF(0));
+    rc= my_symlink("dir1/dir2", "symlink1", MYF(MY_WME));
+    do_test("symlink1/../../dir1/././dir2/../../file",
+            "symlink1/../../file");
+    (void) my_delete("symlink1", MYF(0));
   }
 #else
   {
@@ -166,41 +268,27 @@ main(void)
             "dummy_test_to_please_the_test_counter");
   }
 #endif
-  do_test("ppp///ppp", "ppp/ppp");
-  do_test("qqq/qqq///", "qqq/qqq");
-  do_test("../../rrr", "../../rrr");
-  do_test("", "");
-  do_test("///", "/");
-  do_test("sss/sss/..", "sss");
-  do_test("ttt/..", ".");
-#ifdef FN_NETWORK_DRIVES
-  do_test("//uuu///", "//uuu");
-  do_test("///uuu///", "//uuu");
-#else
-  do_test("//uuu///", "/uuu");
-  do_test("///uuu///", "/uuu");
-#endif
-  do_test("/../vvv", "/vvv");
-  do_test("/../../www", "/www");
-  do_test("/../../", "/");
-  do_test("/../..", "/");
-  do_test("././", ".");
-  do_test("./.", ".");
-  do_test("../../", "../..");
-  do_test("../..", "../..");
-  do_test("..", "..");
-  do_test("xxx/~/xxx", "xxx/~/xxx");
+  do_test("dir1/dir2/../../dir1/././dir2/../../file",
+          "file");
 
-  do_multi_test(NullS,  NullS,    NullS, "");
-  do_multi_test("",     NullS,    NullS, "");
-  do_multi_test("",     "",       NullS, "");
-  do_multi_test("",     "/AAA",   NullS, "/AAA");
-  do_multi_test("BBB/", "/BBB",   NullS, "BBB/BBB");
-  do_multi_test("CCC",  "CCC",    NullS, "CCC/CCC");
-  do_multi_test("DDD",  "",       "DDD", "DDD/DDD");
-  do_multi_test("EEE/", "../EEE", NullS, "EEE");
-  do_multi_test("",     "FFF",    NullS, "FFF");
+  do_multi_test(NullS,   NullS,     NullS,  "");
+  do_multi_test("",      NullS,     NullS,  "");
+  do_multi_test("",      "",        NullS,  "");
+  do_multi_test("",      "/file",   NullS,  "/file");
+  do_multi_test("dir1/", "/dir2",   NullS,  "dir1/dir2");
+  do_multi_test("dir1",  "dir2",    NullS,  "dir1/dir2");
+  do_multi_test("dir1",  "",        "dir2", "dir1/dir2");
+  do_multi_test("dir1/", "../file", NullS,  "file");
+  do_multi_test("",      "file",    NullS,  "file");
 
+end2:
   my_free(concat_buf, MYF(MY_ALLOW_ZERO_PTR));
+  rmdir("dir1/dir2/dir3");
+  rmdir("dir1/dir2");
+  rmdir("dir1");
+  chdir("..");
+end1:
+  rmdir("safe_cleanup_cat_path_dir");
+end:
   return exit_status();
 }


Attachment: [text/bzr-bundle] bzr/ingo.struewing@sun.com-20090519094845-d1a0tsqervmfwp57.bundle
Thread
bzr commit into mysql-6.0-backup branch (ingo.struewing:2808) Bug#43767Ingo Struewing19 May
  • Re: bzr commit into mysql-6.0-backup branch (ingo.struewing:2808)Bug#43767Chuck Bell20 May
  • Re: bzr commit into mysql-6.0-backup branch (ingo.struewing:2808)Bug#43767Jørgen Løland21 May