summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThiago Macieira <[email protected]>2025-06-06 16:33:30 -0300
committerThiago Macieira <[email protected]>2025-07-04 10:24:00 -0700
commit32756f7213d53a397eadc0773c34767cdc718845 (patch)
treebcbd0eb431c701b76a4507d9b9e73311fe5395c8
parent423278c6ee18a86320d253d8f873347c12f882f5 (diff)
QFileSystemEngine/Unix: avoid removing WasDeletedFlag
As the comment says, the flag can only come from a prior call that used fstat() on the file descriptor, so don't remove it when we couldn't have added it in the first place. Pick-to: 6.10 6.9 6.8 Fixes: QTBUG-137438 Change-Id: Ia75e29d28665c334dea6fffdb498a99c416bc3ac Reviewed-by: Lars Schmertmann <[email protected]> Reviewed-by: Ahmad Samir <[email protected]> Reviewed-by: Edward Welbourne <[email protected]>
-rw-r--r--src/corelib/io/qfilesystemengine_unix.cpp11
-rw-r--r--tests/auto/corelib/io/qfile/tst_qfile.cpp32
-rw-r--r--tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp29
3 files changed, 72 insertions, 0 deletions
diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp
index 6f995fe082e..5a0be1d895e 100644
--- a/src/corelib/io/qfilesystemengine_unix.cpp
+++ b/src/corelib/io/qfilesystemengine_unix.cpp
@@ -893,6 +893,12 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
{
Q_CHECK_FILE_NAME(entry, false);
+ // Detection of WasDeletedAttribute is imperfect: in general, if we can
+ // successfully stat() or access() a file, it hasn't been deleted (though
+ // there are exceptions, like /proc/XXX/fd/ entries on Linux). So we have
+ // to restore this flag in case we fail to stat() anything.
+ auto hadBeenDeleted = data.entryFlags & QFileSystemMetaData::WasDeletedAttribute;
+
#if defined(Q_OS_DARWIN)
if (what & (QFileSystemMetaData::BundleType | QFileSystemMetaData::CaseSensitive)) {
if (!data.hasFlags(QFileSystemMetaData::DirectoryType))
@@ -1103,6 +1109,11 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
if (entryErrno != 0) {
what &= ~QFileSystemMetaData::LinkType; // don't clear link: could be broken symlink
data.clearFlags(what);
+
+ // see comment at the top
+ data.entryFlags |= hadBeenDeleted;
+ data.knownFlagsMask |= hadBeenDeleted;
+
return false;
}
return true;
diff --git a/tests/auto/corelib/io/qfile/tst_qfile.cpp b/tests/auto/corelib/io/qfile/tst_qfile.cpp
index 781f64a31ab..66c3db2e2f0 100644
--- a/tests/auto/corelib/io/qfile/tst_qfile.cpp
+++ b/tests/auto/corelib/io/qfile/tst_qfile.cpp
@@ -228,6 +228,7 @@ private slots:
void getCharFF();
void remove_and_exists();
void removeOpenFile();
+ void removedFileDoesntExist();
void fullDisk();
void writeLargeDataBlock_data();
void writeLargeDataBlock();
@@ -2526,6 +2527,37 @@ void tst_QFile::removeOpenFile()
}
}
+void tst_QFile::removedFileDoesntExist()
+{
+#ifdef Q_OS_WIN
+ QSKIP("Not relevant for Windows - can't remove still-open files");
+#endif
+ QFile::remove("remove_unclosed.txt");
+ QFile f("remove_unclosed.txt");
+ QVERIFY(!f.exists());
+ bool opened = f.open(QIODevice::ReadWrite | QIODevice::Unbuffered);
+ QVERIFY(opened);
+ f.write("blah blah blah");
+
+ QVERIFY(f.exists());
+
+ // delete by path, not using f.remove() (that's tested above)
+ QVERIFY(QFile::remove(f.fileName()));
+ QVERIFY(!QFile::exists(f.fileName()));
+ QVERIFY(!f.exists());
+
+#ifdef Q_OS_LINUX
+ QString procPath = u"/proc/self/fd/"_s;
+ if (QFile::exists(procPath)) {
+ // reopen the deleted file
+ procPath += QString::number(f.handle());
+ QFile f2(procPath);
+ QVERIFY(f2.open(QIODevice::ReadOnly));
+ QVERIFY(!f2.exists());
+ }
+#endif
+}
+
void tst_QFile::fullDisk()
{
QFile file("/dev/full");
diff --git a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp
index 761f0552eec..e2190477441 100644
--- a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp
+++ b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp
@@ -141,6 +141,7 @@ private slots:
void exists_data();
void exists();
+ void deletedFileLinuxProcExists();
void absolutePath_data();
void absolutePath();
@@ -615,6 +616,34 @@ void tst_QFileInfo::exists()
QVERIFY(!exists);
}
+void tst_QFileInfo::deletedFileLinuxProcExists()
+{
+#ifdef Q_OS_LINUX
+ static const char msg[] = "Hello, World\n";
+ QFileInfo fi("/proc/self/fd/");
+ if (!fi.isDir())
+ QSKIP("/proc appears not to be mounted");
+
+ QFile f("removed_file.txt");
+ QVERIFY(f.open(QIODevice::ReadWrite | QIODevice::Unbuffered));
+ f.write(msg, strlen(msg));
+
+ fi.setFile(fi.filePath() + QString::number(f.handle()));
+ QVERIFY(fi.exists());
+ QCOMPARE(fi.size(), strlen(msg));
+
+ QFile::remove("removed_file.txt");
+ fi.refresh();
+ QVERIFY(fi.exists());
+
+ fi.refresh();
+ QCOMPARE(fi.size(), strlen(msg)); // this stats, so may change flags
+ QVERIFY(fi.exists());
+#else
+ QSKIP("Linux-only test");
+#endif
+}
+
void tst_QFileInfo::absolutePath_data()
{
QTest::addColumn<QString>("file");