From b0936fac4c9897d647561f05af6ec09c3d7f1f05 Mon Sep 17 00:00:00 2001 From: Enrico Forestieri Date: Fri, 1 May 2009 15:18:11 +0000 Subject: [PATCH] When performing a reverse DVI search and the tmpdir is a symlink, the DVI viewer passes back the resolved path, such that the search fails, as internally LyX uses the unresolved path. This patch fixes this bug by using the new method FileName::realPath which resolves a path by getting rid of any '.', '..', or symlink path components. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@29476 a592a061-630c-0410-9148-cb99ea01b6c8 --- configure.ac | 2 + development/cmake/src/support/CMakeLists.txt | 2 +- development/cmake/src/tex2lyx/CMakeLists.txt | 2 +- development/scons/SConstruct | 4 +- src/LyXFunc.cpp | 12 ++- src/Makefile.am | 2 +- src/client/Makefile.am | 2 +- src/support/FileName.cpp | 10 ++ src/support/FileName.h | 6 ++ src/support/os.h | 10 +- src/support/os_cygwin.cpp | 9 ++ src/support/os_unix.cpp | 10 ++ src/support/os_win32.cpp | 96 ++++++++++++++++++++ src/support/os_win32.h | 2 + src/tex2lyx/Makefile.am | 2 +- 15 files changed, 160 insertions(+), 11 deletions(-) diff --git a/configure.ac b/configure.ac index 5d4a100989..a4a929988d 100644 --- a/configure.ac +++ b/configure.ac @@ -112,6 +112,8 @@ LYX_ADD_INC_DIR(CPPFLAGS,$dir/include) ### These are needed in windows AC_CHECK_LIB(shlwapi, main, [LIBSHLWAPI=-lshlwapi]) AC_SUBST(LIBSHLWAPI) +AC_CHECK_LIB(psapi, main, [LIBPSAPI=-lpsapi]) +AC_SUBST(LIBPSAPI) AC_CHECK_LIB(gdi32, main) AC_ARG_WITH(mythes, diff --git a/development/cmake/src/support/CMakeLists.txt b/development/cmake/src/support/CMakeLists.txt index bb7be6c73e..d902a2f581 100644 --- a/development/cmake/src/support/CMakeLists.txt +++ b/development/cmake/src/support/CMakeLists.txt @@ -69,7 +69,7 @@ target_link_libraries(support boost_signals ${QT_QTCORE_LIBRARY} ${ZLIB_LIBRARY} if(APPLE) target_link_libraries(support "objc" "-framework Appkit" "-framework CoreFoundation") elseif(WIN32) - target_link_libraries(support shlwapi) + target_link_libraries(support shlwapi psapi) endif() project_source_group("${GROUP_CODE}" support_sources support_headers) diff --git a/development/cmake/src/tex2lyx/CMakeLists.txt b/development/cmake/src/tex2lyx/CMakeLists.txt index bddb186eb9..76922d92d8 100644 --- a/development/cmake/src/tex2lyx/CMakeLists.txt +++ b/development/cmake/src/tex2lyx/CMakeLists.txt @@ -46,7 +46,7 @@ target_link_libraries(${_tex2lyx} ${ICONV_LIBRARY}) if(WIN32) - target_link_libraries(${_tex2lyx} shlwapi ole32) + target_link_libraries(${_tex2lyx} shlwapi ole32 psapi) endif() if(APPLE) diff --git a/development/scons/SConstruct b/development/scons/SConstruct index 06500c57b8..d1f7457d52 100644 --- a/development/scons/SConstruct +++ b/development/scons/SConstruct @@ -1212,9 +1212,9 @@ if platform_name in ['win32', 'cygwin']: # the final link step needs stdc++ to succeed under mingw # FIXME: shouldn't g++ automatically link to stdc++? if use_vc: - system_libs += ['ole32', 'shlwapi', 'shell32', 'advapi32', 'zdll'] + system_libs += ['ole32', 'shlwapi', 'psapi', 'shell32', 'advapi32', 'zdll'] else: - system_libs += ['shlwapi', 'stdc++', 'z'] + system_libs += ['shlwapi', 'psapi', 'stdc++', 'z'] elif platform_name == 'cygwin' and env['X11']: system_libs += ['GL', 'Xmu', 'Xi', 'Xrender', 'Xrandr', 'Xcursor', 'Xft', 'freetype', 'fontconfig', 'Xext', 'X11', 'SM', 'ICE', diff --git a/src/LyXFunc.cpp b/src/LyXFunc.cpp index 5892a27cd5..d65568ba19 100644 --- a/src/LyXFunc.cpp +++ b/src/LyXFunc.cpp @@ -1079,11 +1079,17 @@ void LyXFunc::dispatch(FuncRequest const & cmd) is >> file_name >> row; Buffer * buf = 0; bool loaded = false; - if (prefixIs(file_name, package().temp_dir().absFilename())) + string const abstmp = package().temp_dir().absFilename(); + string const realtmp = package().temp_dir().realPath(); + if (prefixIs(file_name, abstmp) || prefixIs(file_name, realtmp)) { // Needed by inverse dvi search. If it is a file - // in tmpdir, call the apropriated function + // in tmpdir, call the apropriated function. + // If tmpdir is a symlink, we may have the real + // path passed back, so we correct for that. + if (prefixIs(file_name, realtmp)) + file_name = subst(file_name, realtmp, abstmp); buf = theBufferList().getBufferFromTmp(file_name); - else { + } else { // Must replace extension of the file to be .lyx // and get full path FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx"); diff --git a/src/Makefile.am b/src/Makefile.am index f0263553d4..4100ac7ad4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -21,7 +21,7 @@ EXTRA_DIST = Section.h \ pch.h OTHERLIBS = $(BOOST_LIBS) $(INTLLIBS) $(MYTHES_LIBS) $(AIKSAURUS_LIBS) \ - @LIBS@ $(SOCKET_LIBS) $(LIBSHLWAPI) + @LIBS@ $(SOCKET_LIBS) $(LIBSHLWAPI) $(LIBPSAPI) noinst_LIBRARIES = liblyxcore.a bin_PROGRAMS = lyx diff --git a/src/client/Makefile.am b/src/client/Makefile.am index 4844ef28ae..49ded9fd65 100644 --- a/src/client/Makefile.am +++ b/src/client/Makefile.am @@ -13,7 +13,7 @@ AM_CPPFLAGS += -I$(srcdir)/.. $(BOOST_INCLUDES) lyxclient_LDADD = \ $(top_builddir)/src/support/liblyxsupport.a \ $(BOOST_LIBS) $(INTLLIBS) @LIBS@ $(SOCKET_LIBS) \ - $(QT4_LIB) $(QT4_LDFLAGS) $(LIBSHLWAPI) + $(QT4_LIB) $(QT4_LDFLAGS) $(LIBSHLWAPI) $(LIBPSAPI) # everything below the line containing the single backslashs # an ugly hack and needed because of the diff --git a/src/support/FileName.cpp b/src/support/FileName.cpp index 0af295ad25..58d2222ad7 100644 --- a/src/support/FileName.cpp +++ b/src/support/FileName.cpp @@ -194,6 +194,12 @@ string FileName::absFilename() const } +string FileName::realPath() const +{ + return os::real_path(toFilesystemEncoding()); +} + + void FileName::set(string const & name) { d->fi.setFile(toqstr(name)); @@ -923,6 +929,10 @@ docstring const FileName::relPath(string const & path) const bool operator==(FileName const & lhs, FileName const & rhs) { + // Avoid unnecessary checks below + if (lhs.empty() || rhs.empty()) + return lhs.empty() && rhs.empty(); + // Firstly, compare the filenames. if (QString::compare(toqstr(lhs.absFilename()), toqstr(rhs.absFilename()), diff --git a/src/support/FileName.h b/src/support/FileName.h index e2bbb84114..88c137207e 100644 --- a/src/support/FileName.h +++ b/src/support/FileName.h @@ -64,6 +64,12 @@ public: /// get the absolute file name in UTF-8 encoding std::string absFilename() const; + + /** returns an absolute pathname (whose resolution does not involve + * '.', '..', or symbolic links) in UTF-8 encoding + */ + std::string realPath() const; + /** * Get the file name in the encoding used by the file system. * Only use this for accessing the file, e.g. with an fstream. diff --git a/src/support/os.h b/src/support/os.h index 872858bb53..dbc9b61859 100644 --- a/src/support/os.h +++ b/src/support/os.h @@ -112,9 +112,17 @@ bool canAutoOpenFile(std::string const & ext, auto_open_mode const mode = VIEW); */ bool autoOpenFile(std::string const & filename, auto_open_mode const mode = VIEW); -/// Check whether two filenames point to the same file. +/** Check whether two filenames point to the same file. + * \warning the filenames must already be in the filesystem encoding. + */ bool isSameFile(std::string const & fileone, std::string const & filetwo); +/** Resolves a path such that it does not contain '.', '..', or symbolic links. + * \warning the path must already be in the filesystem encoding. + * \returns the resolved path in utf8 encoding. + */ +std::string real_path(std::string const & path); + } // namespace os } // namespace support } // namespace lyx diff --git a/src/support/os_cygwin.cpp b/src/support/os_cygwin.cpp index 44f6caf87e..7479c98afd 100644 --- a/src/support/os_cygwin.cpp +++ b/src/support/os_cygwin.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -297,6 +298,14 @@ bool isSameFile(string const & fileone, string const & filetwo) return false; } + +string real_path(string const & path) +{ + char rpath[PATH_MAX + 1]; + char * result = realpath(path.c_str(), rpath); + return FileName::fromFilesystemEncoding(result ? rpath : path).absFilename(); +} + } // namespace os } // namespace support } // namespace lyx diff --git a/src/support/os_unix.cpp b/src/support/os_unix.cpp index 6ca1094fdd..a9c040c6c9 100644 --- a/src/support/os_unix.cpp +++ b/src/support/os_unix.cpp @@ -17,6 +17,8 @@ #include "support/FileName.h" #include "support/lstrings.h" +#include +#include #include #ifdef __APPLE__ @@ -232,6 +234,14 @@ bool isSameFile(string const & fileone, string const & filetwo) return false; } + +string real_path(string const & path) +{ + char rpath[PATH_MAX + 1]; + char * result = realpath(path.c_str(), rpath); + return FileName::fromFilesystemEncoding(result ? rpath : path).absFilename(); +} + } // namespace os } // namespace support } // namespace lyx diff --git a/src/support/os_win32.cpp b/src/support/os_win32.cpp index 5035edb296..ad5fb42592 100644 --- a/src/support/os_win32.cpp +++ b/src/support/os_win32.cpp @@ -426,6 +426,102 @@ bool isSameFile(string const & fileone, string const & filetwo) return samefile; } + +string real_path(string const & path) +{ + // See http://msdn.microsoft.com/en-us/library/aa366789(VS.85).aspx + HANDLE hpath = CreateFile(subst(path, '/', '\\').c_str(), GENERIC_READ, + FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + + if (hpath == INVALID_HANDLE_VALUE) { + // The file cannot be accessed. + return FileName::fromFilesystemEncoding(path).absFilename(); + } + + // Get the file size. + DWORD size_hi = 0; + DWORD size_lo = GetFileSize(hpath, &size_hi); + + if (size_lo == 0 && size_hi == 0) { + // A zero-length file cannot be mapped. + CloseHandle(hpath); + return FileName::fromFilesystemEncoding(path).absFilename(); + } + + // Create a file mapping object. + HANDLE hmap = CreateFileMapping(hpath, NULL, PAGE_READONLY, 0, 1, NULL); + + if (!hmap) { + CloseHandle(hpath); + return FileName::fromFilesystemEncoding(path).absFilename(); + } + + // Create a file mapping to get the file name. + void * pmem = MapViewOfFile(hmap, FILE_MAP_READ, 0, 0, 1); + + if (!pmem) { + CloseHandle(hmap); + CloseHandle(hpath); + return FileName::fromFilesystemEncoding(path).absFilename(); + } + + TCHAR realpath[MAX_PATH + 1]; + + if (!GetMappedFileName(GetCurrentProcess(), pmem, realpath, MAX_PATH)) { + UnmapViewOfFile(pmem); + CloseHandle(hmap); + CloseHandle(hpath); + return FileName::fromFilesystemEncoding(path).absFilename(); + } + + // Translate device name to UNC prefix or drive letters. + TCHAR tmpbuf[MAX_PATH] = TEXT("\\Device\\Mup\\"); + UINT namelen = _tcslen(tmpbuf); + if (_tcsnicmp(realpath, tmpbuf, namelen) == 0) { + // UNC path + snprintf(tmpbuf, MAX_PATH, "\\\\%s", realpath + namelen); + strncpy(realpath, tmpbuf, MAX_PATH); + realpath[MAX_PATH] = '\0'; + } else if (GetLogicalDriveStrings(MAX_PATH - 1, tmpbuf)) { + // Check whether device name corresponds to some local drive. + TCHAR name[MAX_PATH]; + TCHAR drive[3] = TEXT(" :"); + bool found = false; + TCHAR * p = tmpbuf; + do { + // Copy the drive letter to the template string + drive[0] = *p; + // Look up each device name + if (QueryDosDevice(drive, name, MAX_PATH)) { + namelen = _tcslen(name); + if (namelen < MAX_PATH) { + found = _tcsnicmp(realpath, name, namelen) == 0; + if (found) { + // Repl. device spec with drive + TCHAR tempfile[MAX_PATH]; + snprintf(tempfile, + MAX_PATH, + "%s%s", + drive, + realpath + namelen); + strncpy(realpath, + tempfile, + MAX_PATH); + realpath[MAX_PATH] = '\0'; + } + } + } + // Advance p to the next NULL character. + while (*p++) ; + } while (!found && *p); + } + UnmapViewOfFile(pmem); + CloseHandle(hmap); + CloseHandle(hpath); + string const retpath = subst(string(realpath), '\\', '/'); + return FileName::fromFilesystemEncoding(retpath).absFilename(); +} + } // namespace os } // namespace support } // namespace lyx diff --git a/src/support/os_win32.h b/src/support/os_win32.h index bf748f629a..618c5315ef 100644 --- a/src/support/os_win32.h +++ b/src/support/os_win32.h @@ -43,6 +43,8 @@ #endif #include +#include +#include namespace lyx { diff --git a/src/tex2lyx/Makefile.am b/src/tex2lyx/Makefile.am index f0e4c0b75b..8f53955bf6 100644 --- a/src/tex2lyx/Makefile.am +++ b/src/tex2lyx/Makefile.am @@ -72,4 +72,4 @@ tex2lyx_LDADD = \ $(top_builddir)/src/support/liblyxsupport.a \ $(LIBICONV) $(BOOST_LIBS) \ $(QT4_LIB) $(QT4_LDFLAGS) \ - @LIBS@ $(LIBSHLWAPI) + @LIBS@ $(LIBSHLWAPI) $(LIBPSAPI)