From c9bf555232c076f8bc08be2856f4d13596ac890d Mon Sep 17 00:00:00 2001 From: Stephan Kulow Date: Fri, 8 Feb 2008 08:52:29 +0000 Subject: [PATCH] ------------------------------------------------------------------------ r8177 | jkupec | 2008-01-02 18:02:39 +0100 (Mi, 02 Jan 2008) | 8 lines - expandlink(Pathname) added - TODO: could be made so that it throws on bad links (better error reporting) - TODO: cyclic links protection can be improved by remembering paths alredy visited and checking them (again better error reporting and performance) ------------------------------------------------------------------------ --- tests/zypp/PathInfo.cc | 53 +++++++++++++++++++++++++++++++++++++++++++++++--- zypp/PathInfo.cc | 44 +++++++++++++++++++++++++++++++++++++++++ zypp/PathInfo.h | 14 +++++++++++++ 3 files changed, 108 insertions(+), 3 deletions(-) diff --git a/tests/zypp/PathInfo.cc b/tests/zypp/PathInfo.cc index 1187700..13e627e 100644 --- a/tests/zypp/PathInfo.cc +++ b/tests/zypp/PathInfo.cc @@ -71,13 +71,59 @@ void pathinfo_is_exist_test() void pathinfo_misc_test() { TmpDir dir; - - - + PathInfo info(dir.path()); BOOST_CHECK(info.isDir()); } +void pathinfo_expandlink_test() +{ + TmpDir dir; + + // ---- not a link + + // create a file + Pathname file(dir / "file"); + ofstream str(file.asString().c_str(),ofstream::out); + str << "foo bar" << endl; + str.flush(); + str.close(); + + // expandlink should return the original Pathname if it does not point to a link + BOOST_CHECK_EQUAL( file, filesystem::expandlink(file) ); + + // ---- valid link + + // create a link to that file + Pathname link1(dir / "link1"); + BOOST_CHECK_EQUAL( filesystem::symlink(file, link1), 0); + + // does the link expand to the file? + BOOST_CHECK_EQUAL( file, filesystem::expandlink(link1) ); + + // ---- broken link + + // create a link to a non-existent file + Pathname brokenlink(dir / "brokenlink"); + Pathname non_existent(dir / "non-existent"); + BOOST_CHECK_EQUAL( filesystem::symlink(non_existent, brokenlink), 0); + PathInfo info(brokenlink, PathInfo::LSTAT); + BOOST_CHECK(info.isLink()); + + // expandlink should return an empty Pathname for a broken link + BOOST_CHECK_EQUAL( Pathname(), filesystem::expandlink(brokenlink) ); + + // ---- cyclic link + + // make the 'non-existent' a link to 'brokenlink' :O) + BOOST_CHECK_EQUAL( filesystem::symlink(brokenlink, non_existent), 0); + // expandlink should return an empty Pathname for such a cyclic link + BOOST_CHECK_EQUAL( Pathname(), filesystem::expandlink(brokenlink) ); + BOOST_CHECK_EQUAL( Pathname(), filesystem::expandlink(non_existent) ); + + cout << brokenlink << " -> " << filesystem::expandlink(brokenlink) << endl; +} + test_suite* init_unit_test_suite( int, char* [] ) { @@ -85,6 +131,7 @@ init_unit_test_suite( int, char* [] ) test->add( BOOST_TEST_CASE( &pathinfo_checksum_test ), 0 /* expected zero error */ ); test->add( BOOST_TEST_CASE( &pathinfo_misc_test ), 0 /* expected zero error */ ); test->add( BOOST_TEST_CASE( &pathinfo_is_exist_test ), 0 /* expected zero error */ ); + test->add( BOOST_TEST_CASE( &pathinfo_expandlink_test ), 0 /* expected zero error */ ); return test; } diff --git a/zypp/PathInfo.cc b/zypp/PathInfo.cc index 9b673ba..ff9db28 100644 --- a/zypp/PathInfo.cc +++ b/zypp/PathInfo.cc @@ -756,6 +756,50 @@ namespace zypp /////////////////////////////////////////////////////////////////// // + // METHOD NAME : expandlink + // METHOD TYPE : Pathname + // + Pathname expandlink( const Pathname & path_r ) + { + static const unsigned int level_limit = 256; + static unsigned int count; + Pathname path(path_r); + PathInfo info(path_r, PathInfo::LSTAT); + + for (count = level_limit; info.isLink() && count; count--) + { + DBG << "following symlink " << path << std::endl; + path = readlink(path); + info = PathInfo(path, PathInfo::LSTAT); + } + + // expand limit reached + if (count == 0) + { + ERR << "Expand level limit reached. Probably a cyclic symbolic link." << endl; + return Pathname(); + } + // symlink + else if (count < level_limit) + { + // check for a broken link + if (PathInfo(path).isExist()) + return path; + // broken link, return and empty path + else + { + ERR << path << " is broken (expanded from " << path_r << ")" << endl; + return Pathname(); + } + } + + // not a symlink, return the original pathname + DBG << "not a symlink" << endl; + return path; + } + + /////////////////////////////////////////////////////////////////// + // // METHOD NAME : copy_file2dir // METHOD TYPE : int // diff --git a/zypp/PathInfo.h b/zypp/PathInfo.h index 2f537d2..15c3344 100644 --- a/zypp/PathInfo.h +++ b/zypp/PathInfo.h @@ -582,6 +582,20 @@ namespace zypp } /** + * Recursively follows the symlink pointed to by \a path_r and returns + * the Pathname to the real file or directory pointed to by the link. + * + * There is a recursion limit of 256 iterations to protect against a cyclic + * link. + * + * @return Pathname of the file or directory pointed to by the given link + * if it is a valid link. If \a path_r is not a link, an exact copy of + * it is returned. If \a path_r is a broken or a cyclic link, an empty + * Pathname is returned and the event logged. + */ + Pathname expandlink( const Pathname & path_r ); + + /** * Like 'cp file dest'. Copy file to dest dir. * * @return 0 on success, EINVAL if file is not a file, ENOTDIR if dest -- 2.7.4