Fix updater failing to uninstall broken symlinks

When checking whether a file exists before uninstalling it, FileUtils::fileExists()
checked whether the link target existed instead of the link itself.  Change fileExists()
to use lstat() instead of stat().

The updater uninstalls files in the order they are listed, if a file and a symlink to it
are both being uninstalled (eg. libMendeley.so.1.6.0 and the symlink libMendeley.so.1.6)
and the real file is removed first, uninstalling the symlink later failed due to the
above issue with uninstalling broken symlinks.

MD-19006
This commit is contained in:
Robert Knight 2012-11-06 12:27:00 +00:00
parent 92ef486dc6
commit 80fdc5b048
9 changed files with 36 additions and 6 deletions

View file

@ -80,7 +80,7 @@ bool FileUtils::fileExists(const char* path) throw (IOException)
{
#ifdef PLATFORM_UNIX
struct stat fileInfo;
if (stat(path,&fileInfo) != 0)
if (lstat(path,&fileInfo) != 0)
{
if (errno == ENOENT)
{

View file

@ -67,8 +67,17 @@ class FileUtils
* Unix mode_t values.
*/
static void chmod(const char* path, int permissions) throw (IOException);
/** Returns true if the file at @p path exists. If @p path is a symlink,
* returns true if the symlink itself exists, not the target.
*/
static bool fileExists(const char* path) throw (IOException);
/** Returns the Unix mode flags of @p path. If @p path is a symlink,
* returns the mode flags of the target.
*/
static int fileMode(const char* path) throw (IOException);
static void moveFile(const char* src, const char* dest) throw (IOException);
static void mkdir(const char* dir) throw (IOException);
static void rmdir(const char* dir) throw (IOException);

View file

@ -25,7 +25,7 @@
#include <iostream>
#define UPDATER_VERSION "0.13"
#define UPDATER_VERSION "0.14"
void runWithUi(int argc, char** argv, UpdateInstaller* installer);

View file

@ -23,9 +23,21 @@ void TestFileUtils::testIsRelative()
#endif
}
void TestFileUtils::testSymlinkFileExists()
{
#ifdef PLATFORM_UNIX
const char* linkName = "link-name";
FileUtils::removeFile(linkName);
FileUtils::createSymLink(linkName, "target-that-does-not-exist");
TEST_COMPARE(FileUtils::fileExists(linkName), true);
#endif
}
int main(int,char**)
{
TestList<TestFileUtils> tests;
tests.addTest(&TestFileUtils::testDirName);
tests.addTest(&TestFileUtils::testIsRelative);
tests.addTest(&TestFileUtils::testSymlinkFileExists);
return TestUtils::runTest(tests);
}

View file

@ -5,4 +5,5 @@ class TestFileUtils
public:
void testDirName();
void testIsRelative();
void testSymlinkFileExists();
};

View file

@ -105,3 +105,4 @@ inline std::string TestUtils::toString(const char* value, const char*)
#define TEST_COMPARE(x,y) \
TestUtils::compare(x,y,#x,#y);

View file

@ -47,5 +47,6 @@
<uninstall>
<!-- TODO - List some files to uninstall here !-->
<file>file-to-uninstall.txt</file>
<file>symlink-to-file-to-uninstall.txt</file>
</uninstall>
</update>

View file

@ -104,6 +104,13 @@ def compare_dirs(src_dir, dest_dir)
return change_map
end
def create_test_file(name, content)
File.open(name, 'w') do |file|
file.puts content
end
return name
end
force_elevation = false
run_in_debugger = false
@ -140,10 +147,8 @@ Dir.mkdir(INSTALL_DIR)
FileUtils.cp(OLDAPP_NAME,"#{INSTALL_DIR}/#{APP_NAME}")
# Create a dummy file to uninstall
uninstall_test_file = "#{INSTALL_DIR}/file-to-uninstall.txt"
File.open(uninstall_test_file,"w") do |file|
file.puts "this file should be removed after the update"
end
uninstall_test_file = create_test_file("#{INSTALL_DIR}/file-to-uninstall.txt", "this file should be removed after the update")
uninstall_test_symlink = FileUtils.ln_s("#{INSTALL_DIR}/file-to-uninstall.txt", "#{INSTALL_DIR}/symlink-to-file-to-uninstall.txt")
# Populate package source dir with files to install
Dir.mkdir(PACKAGE_SRC_DIR)

View file

@ -62,5 +62,6 @@
<uninstall>
<!-- TODO - List some files to uninstall here !-->
<file>file-to-uninstall.txt</file>
<file>symlink-to-file-to-uninstall.txt</file>
</uninstall>
</update>