Speed up FileName operator==, such that working with child documents on

Windows and Solaris is again possible.


git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@29444 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Enrico Forestieri 2009-04-29 22:42:26 +00:00
parent 1542ddef59
commit 4053db1858
5 changed files with 83 additions and 41 deletions

View File

@ -921,49 +921,18 @@ docstring const FileName::relPath(string const & path) const
}
// Note: According to Qt, QFileInfo::operator== is undefined when
// both files do not exist (Qt4.5 gives true for all non-existent
// files, while Qt4.4 compares the filenames).
// see:
// http://www.qtsoftware.com/developer/task-tracker/
// index_html?id=248471&method=entry.
bool operator==(FileName const & l, FileName const & r)
bool operator==(FileName const & lhs, FileName const & rhs)
{
// FIXME: In future use Qt.
// Qt 4.4: We need to solve this warning from Qt documentation:
// * Long and short file names that refer to the same file on Windows are
// treated as if they referred to different files.
// This is supposed to be fixed for Qt5.
FileName const lhs(os::internal_path(l.absFilename()));
FileName const rhs(os::internal_path(r.absFilename()));
if (lhs.empty())
// QFileInfo::operator==() returns false if the two QFileInfo are empty.
return rhs.empty();
if (rhs.empty())
// Avoid unnecessary checks below.
return false;
lhs.d->refresh();
rhs.d->refresh();
if (!lhs.d->fi.isSymLink() && !rhs.d->fi.isSymLink()) {
// Qt already checks if the filesystem is case sensitive or not.
// see note above why the extra check with fileName is needed.
return lhs.d->fi == rhs.d->fi
&& lhs.d->fi.fileName() == rhs.d->fi.fileName();
// Firstly, compare the filenames.
if (QString::compare(toqstr(lhs.absFilename()),
toqstr(rhs.absFilename()),
os::isFilesystemCaseSensitive() ?
Qt::CaseSensitive : Qt::CaseInsensitive) == 0) {
return true;
}
// FIXME: When/if QFileInfo support symlink comparison, remove this code.
QFileInfo fi1(lhs.d->fi);
if (fi1.isSymLink())
fi1 = QFileInfo(fi1.symLinkTarget());
QFileInfo fi2(rhs.d->fi);
if (fi2.isSymLink())
fi2 = QFileInfo(fi2.symLinkTarget());
// see note above why the extra check with fileName is needed.
return fi1 == fi2 && fi1.fileName() == fi2.fileName();
// They don't match, so check whether they point to the same file.
return os::isSameFile(lhs.toFilesystemEncoding(), rhs.toFilesystemEncoding());
}

View File

@ -112,6 +112,9 @@ 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.
bool isSameFile(std::string const & fileone, std::string const & filetwo);
} // namespace os
} // namespace support
} // namespace lyx

View File

@ -6,6 +6,7 @@
* \author Ruurd A. Reitsma
* \author Claus Hentschel
* \author Angus Leeming
* \author Enrico Forestieri
*
* Full author contact details are available in file CREDITS.
*
@ -26,8 +27,8 @@
#include <shellapi.h>
#include <shlwapi.h>
#include <limits.h>
#include <sys/cygwin.h>
#include <sys/stat.h>
using namespace std;
@ -281,6 +282,21 @@ bool autoOpenFile(string const & filename, auto_open_mode const mode)
win_path.c_str(), NULL, NULL, 1)) > 32;
}
bool isSameFile(string const & fileone, string const & filetwo)
{
struct stat st1;
struct stat st2;
if (::stat(fileone.c_str(), &st1) == 0
&& ::stat(filetwo.c_str(), &st2) == 0) {
return st1.st_ino == st2.st_ino && st1.st_dev == st2.st_dev;
}
// One or both files cannot be accessed.
return false;
}
} // namespace os
} // namespace support
} // namespace lyx

View File

@ -17,6 +17,8 @@
#include "support/FileName.h"
#include "support/lstrings.h"
#include <sys/stat.h>
#ifdef __APPLE__
#include <Carbon/Carbon.h>
#endif
@ -215,6 +217,21 @@ bool autoOpenFile(string const & filename, auto_open_mode const mode)
#endif
}
bool isSameFile(string const & fileone, string const & filetwo)
{
struct stat st1;
struct stat st2;
if (::stat(fileone.c_str(), &st1) == 0
&& ::stat(filetwo.c_str(), &st2) == 0) {
return st1.st_ino == st2.st_ino && st1.st_dev == st2.st_dev;
}
// One or both files cannot be accessed.
return false;
}
} // namespace os
} // namespace support
} // namespace lyx

View File

@ -389,6 +389,43 @@ bool autoOpenFile(string const & filename, auto_open_mode const mode)
to_local8bit(from_utf8(filename)).c_str(), NULL, NULL, 1)) > 32;
}
bool isSameFile(string const & fileone, string const & filetwo)
{
HANDLE h1 = CreateFile(fileone.c_str(), 0,
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
HANDLE h2 = CreateFile(filetwo.c_str(), 0,
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (h1 == INVALID_HANDLE_VALUE || h2 == INVALID_HANDLE_VALUE) {
// One or both files cannot be accessed.
if (h1 != INVALID_HANDLE_VALUE)
CloseHandle(h1);
if (h2 != INVALID_HANDLE_VALUE)
CloseHandle(h2);
return false;
}
BY_HANDLE_FILE_INFORMATION info1;
BY_HANDLE_FILE_INFORMATION info2;
bool samefile = false;
if (GetFileInformationByHandle(h1, &info1) != 0
&& GetFileInformationByHandle(h2, &info2) != 0) {
// Serial number of the volumes containing the files.
ULONG st1_dev = info1.dwVolumeSerialNumber;
ULONG st2_dev = info2.dwVolumeSerialNumber;
// Unique identifiers associated to the files on the volumes.
ULONGLONG highbits = info1.nFileIndexHigh & 0x0000FFFF;
ULONGLONG st1_ino = (highbits << sizeof(ULONG)) | info1.nFileIndexLow;
highbits = info2.nFileIndexHigh & 0x0000FFFF;
ULONGLONG st2_ino = (highbits << sizeof(ULONG)) | info2.nFileIndexLow;
samefile = st1_ino == st2_ino && st1_dev == st2_dev;
}
CloseHandle(h1);
CloseHandle(h2);
return samefile;
}
} // namespace os
} // namespace support
} // namespace lyx