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* [] )
{
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;
}
return 0;
}
+ ///////////////////////////////////////////////////////////////////
+ //
+ // 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
return target;
}
+ /**
+ * 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.
*