QFile::rename: use the open file's ID, instead of using the file name

To do that, we needed to add virtual id() in QAbstractFileEngine and
override it in QFSFileEngine. It might be useful to return other types
of IDs for the other file engines, but this commit does not attempt that
just yet.

Change-Id: I1eba2b016de74620bfc8fffd14ccafe0762b3c38
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Thiago Macieira 2017-06-29 12:55:54 -07:00
parent f9bfc8b91c
commit ad3b41a06d
9 changed files with 66 additions and 3 deletions

View File

@ -677,6 +677,17 @@ bool QAbstractFileEngine::setPermissions(uint perms)
return false;
}
/*!
\since 5.9
Return an identifier that (hopefully) uniquely identifies this file in the
system. Returns an invalid QByteArray() if that cannot be calculated.
*/
QByteArray QAbstractFileEngine::id() const
{
return QByteArray();
}
/*!
Return the file engine's current file name in the format
specified by \a file.

View File

@ -141,6 +141,7 @@ public:
virtual QStringList entryList(QDir::Filters filters, const QStringList &filterNames) const;
virtual FileFlags fileFlags(FileFlags type=FileInfoAll) const;
virtual bool setPermissions(uint perms);
virtual QByteArray id() const;
virtual QString fileName(FileName file=DefaultName) const;
virtual uint ownerId(FileOwner) const;
virtual QString owner(FileOwner) const;

View File

@ -570,7 +570,9 @@ QFile::rename(const QString &newName)
// Note: this does not take file engines into account.
QByteArray targetId = QFileSystemEngine::id(QFileSystemEntry(newName));
if (!targetId.isNull()) {
QByteArray fileId = QFileSystemEngine::id(QFileSystemEntry(d->fileName));
QByteArray fileId = d->fileEngine ?
d->fileEngine->id() :
QFileSystemEngine::id(QFileSystemEntry(d->fileName));
if (fileId != targetId || d->fileName.compare(newName, Qt::CaseInsensitive)) {
// ### Race condition. If a file is moved in after this, it /will/ be
// overwritten. On Unix, the proper solution is to use hardlinks:

View File

@ -92,6 +92,7 @@ public:
QFileSystemMetaData::MetaDataFlags what);
#if defined(Q_OS_UNIX)
static bool fillMetaData(int fd, QFileSystemMetaData &data); // what = PosixStatFlags
static QByteArray id(int fd);
static bool setPermissions(int fd, QFile::Permissions permissions, QSystemError &error,
QFileSystemMetaData *data = nullptr);
#endif
@ -104,6 +105,7 @@ public:
QFileSystemMetaData::MetaDataFlags what);
static bool fillPermissions(const QFileSystemEntry &entry, QFileSystemMetaData &data,
QFileSystemMetaData::MetaDataFlags what);
static QByteArray id(HANDLE fHandle);
static QString owner(const QFileSystemEntry &entry, QAbstractFileEngine::FileOwner own);
static QString nativeAbsoluteFilePath(const QString &path);
#endif

View File

@ -348,6 +348,20 @@ QByteArray QFileSystemEngine::id(const QFileSystemEntry &entry)
return result;
}
//static
QByteArray QFileSystemEngine::id(int id)
{
QT_STATBUF statResult;
if (QT_FSTAT(id, &statResult)) {
qErrnoWarning("fstat() failed for fd %d", id);
return QByteArray();
}
QByteArray result = QByteArray::number(quint64(statResult.st_dev), 16);
result += ':';
result += QByteArray::number(quint64(statResult.st_ino));
return result;
}
//static
QString QFileSystemEngine::resolveUserName(uint userId)
{

View File

@ -621,13 +621,19 @@ QByteArray QFileSystemEngine::id(const QFileSystemEntry &entry)
FILE_SHARE_READ, OPEN_EXISTING, NULL);
#endif // Q_OS_WINRT
if (handle != INVALID_HANDLE_VALUE) {
result = QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8 ?
fileIdWin8(handle) : fileId(handle);
result = id(handle);
CloseHandle(handle);
}
return result;
}
//static
QByteArray QFileSystemEngine::id(HANDLE fHandle)
{
return QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8 ?
fileIdWin8(HANDLE(fHandle)) : fileId(HANDLE(fHandle));
}
//static
QString QFileSystemEngine::owner(const QFileSystemEntry &entry, QAbstractFileEngine::FileOwner own)
{

View File

@ -93,6 +93,7 @@ public:
QStringList entryList(QDir::Filters filters, const QStringList &filterNames) const Q_DECL_OVERRIDE;
FileFlags fileFlags(FileFlags type) const Q_DECL_OVERRIDE;
bool setPermissions(uint perms) Q_DECL_OVERRIDE;
QByteArray id() const override;
QString fileName(FileName file) const Q_DECL_OVERRIDE;
uint ownerId(FileOwner) const Q_DECL_OVERRIDE;
QString owner(FileOwner) const Q_DECL_OVERRIDE;

View File

@ -596,6 +596,14 @@ QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(FileFlags type) const
return ret;
}
QByteArray QFSFileEngine::id() const
{
Q_D(const QFSFileEngine);
if (d->fd != -1)
return QFileSystemEngine::id(d->fd);
return QFileSystemEngine::id(d->fileEntry);
}
QString QFSFileEngine::fileName(FileName file) const
{
Q_D(const QFSFileEngine);

View File

@ -718,6 +718,24 @@ QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(QAbstractFileEngine::Fil
return ret;
}
QByteArray QFSFileEngine::id() const
{
Q_D(const QFSFileEngine);
HANDLE h = d->fileHandle;
if (h == INVALID_HANDLE_VALUE) {
int localFd = d->fd;
if (d->fh && d->fileEntry.isEmpty())
localFd = QT_FILENO(d->fh);
if (localFd != -1)
h = HANDLE(_get_osfhandle(localFd));
}
if (h != INVALID_HANDLE_VALUE)
return QFileSystemEngine::id(h);
// file is not open, try by path
return QFileSystemEngine::id(d->fileEntry);
}
QString QFSFileEngine::fileName(FileName file) const
{
Q_D(const QFSFileEngine);