#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