Fix QDir::mkpath() when the path contains "symlink/../"
It is incorrect to collapse a "symlink/.." segment because the parent directory of the symlink's target may not be the directory where the symlink itself is located. [ChangeLog][QtCore][QDir] Fixed a bug that caused QDir::mkpath() to create the wrong directory if the requested path contained a symbolic link and "../". Change-Id: Iaddbecfbba5441c8b2e4fffd14a3e367730a1e24 Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@qt.io> Reviewed-by: David Faure <david.faure@kdab.com>
This commit is contained in:
parent
49163ca689
commit
23d08ce2ed
@ -1,5 +1,6 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
|
** Copyright (C) 2017 Intel Corporation.
|
||||||
** Copyright (C) 2016 The Qt Company Ltd.
|
** Copyright (C) 2016 The Qt Company Ltd.
|
||||||
** Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch>
|
** Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch>
|
||||||
** Contact: https://www.qt.io/licensing/
|
** Contact: https://www.qt.io/licensing/
|
||||||
@ -603,25 +604,7 @@ bool QFileSystemEngine::createDirectory(const QFileSystemEntry &entry, bool crea
|
|||||||
if (!createParents)
|
if (!createParents)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// we need the cleaned path in order to create the parents
|
return createDirectoryWithParents(nativeName, false);
|
||||||
// and we save errno just in case encodeName needs to load codecs
|
|
||||||
int savedErrno = errno;
|
|
||||||
bool pathChanged;
|
|
||||||
{
|
|
||||||
QString cleanName = QDir::cleanPath(dirName);
|
|
||||||
|
|
||||||
// Check if the cleaned name is the same or not. If we were given a
|
|
||||||
// path with resolvable "../" sections, cleanPath will remove them, but
|
|
||||||
// this may change the target dir if one of those segments was a
|
|
||||||
// symlink. This operation depends on cleanPath's optimization of
|
|
||||||
// returning the original string if it didn't modify anything.
|
|
||||||
pathChanged = !dirName.isSharedWith(cleanName);
|
|
||||||
if (pathChanged)
|
|
||||||
nativeName = QFile::encodeName(cleanName);
|
|
||||||
}
|
|
||||||
|
|
||||||
errno = savedErrno;
|
|
||||||
return createDirectoryWithParents(nativeName, pathChanged);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//static
|
//static
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
|
** Copyright (C) 2017 Intel Corporation.
|
||||||
** Copyright (C) 2016 The Qt Company Ltd.
|
** Copyright (C) 2016 The Qt Company Ltd.
|
||||||
** Contact: https://www.qt.io/licensing/
|
** Contact: https://www.qt.io/licensing/
|
||||||
**
|
**
|
||||||
@ -101,6 +102,7 @@ private slots:
|
|||||||
|
|
||||||
void mkdirRmdir_data();
|
void mkdirRmdir_data();
|
||||||
void mkdirRmdir();
|
void mkdirRmdir();
|
||||||
|
void mkdirOnSymlink();
|
||||||
|
|
||||||
void makedirReturnCode();
|
void makedirReturnCode();
|
||||||
|
|
||||||
@ -387,6 +389,56 @@ void tst_QDir::mkdirRmdir()
|
|||||||
QVERIFY(!fi.exists());
|
QVERIFY(!fi.exists());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QDir::mkdirOnSymlink()
|
||||||
|
{
|
||||||
|
#ifndef Q_OS_UNIX
|
||||||
|
QSKIP("Test only valid on an OS that supports symlinks");
|
||||||
|
#else
|
||||||
|
// Create the structure:
|
||||||
|
// .
|
||||||
|
// ├── symlink -> two/three
|
||||||
|
// └── two
|
||||||
|
// └── three
|
||||||
|
// so when we mkdir("symlink/../four/five"), we end up with:
|
||||||
|
// .
|
||||||
|
// ├── symlink -> two/three
|
||||||
|
// └── two
|
||||||
|
// ├── four
|
||||||
|
// │ └── five
|
||||||
|
// └── three
|
||||||
|
|
||||||
|
QDir dir;
|
||||||
|
struct Clean {
|
||||||
|
QDir &dir;
|
||||||
|
Clean(QDir &dir) : dir(dir) {}
|
||||||
|
~Clean() { doClean(); }
|
||||||
|
void doClean() {
|
||||||
|
dir.rmpath("two/three");
|
||||||
|
dir.rmpath("two/four/five");
|
||||||
|
// in case the test fails, don't leave junk behind
|
||||||
|
dir.rmpath("four/five");
|
||||||
|
QFile::remove("symlink");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Clean clean(dir);
|
||||||
|
clean.doClean();
|
||||||
|
|
||||||
|
// create our structure:
|
||||||
|
dir.mkpath("two/three");
|
||||||
|
::symlink("two/three", "symlink");
|
||||||
|
|
||||||
|
// try it:
|
||||||
|
QString path = "symlink/../four/five";
|
||||||
|
QVERIFY(dir.mkpath(path));
|
||||||
|
QFileInfo fi(path);
|
||||||
|
QVERIFY2(fi.exists() && fi.isDir(), msgDoesNotExist(path).constData());
|
||||||
|
|
||||||
|
path = "two/four/five";
|
||||||
|
fi.setFile(path);
|
||||||
|
QVERIFY2(fi.exists() && fi.isDir(), msgDoesNotExist(path).constData());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void tst_QDir::makedirReturnCode()
|
void tst_QDir::makedirReturnCode()
|
||||||
{
|
{
|
||||||
QString dirName = QString::fromLatin1("makedirReturnCode");
|
QString dirName = QString::fromLatin1("makedirReturnCode");
|
||||||
|
Loading…
Reference in New Issue
Block a user