How to check if a file is write protected in QT? - c++

I need to check if a file is writable, to display a warning message when users try to open a file that is not writable.
I found on the QT forums the following examples to check if a file is writable:
const QFileInfo info(fileName);
if (info.permission(QFile::WriteOwner | QFile::WriteGroup | QFile::WriteUser)) {
qDebug() << "File is writable";
} else {
qDebug() << "Read Only file";
}
// Or even simpler:
if (info.isWritable()) {
qDebug() << "File is writable";
} else {
qDebug() << "Read Only file";
}
But unfortunately the above examples only works if a file has a read-only attribute, like this (this file is simple txt and I marked it as read-only):
I found in QT forums that I should look at the file permissions first. So, as you can see my file is not a read-only file (this is the permission of the real file I'm working).
If I go to the security section of the file's properties, I realize that the file only has permissions to read and execute, and of course not to write.
I tried to get the file permissions with the following code, but it doesn't seem to work.
QFileDevice::Permissions p = QFile(fileName).permissions();
if (p & QFileDevice::ReadOwner)
{
qDebug() << "Read file";
}
if (p & QFileDevice::WriteOwner)
{
qDebug() << "Write file";
}
if (p & QFileDevice::ExeOwner)
{
qDebug() << "Exec file";
}
output:
Read file
Write file
I tried with another variants like writeUser, but I get the same result.
Any idea or suggestion.
I'm using Windows 10.
Sorry, I can't share the file for testing.

I am not familiar with Qt, but this can be done with std::filesystem:
auto p = std::filesystem::status(file_name).permission();
if(p & std::filesystem::perms::owner_read) { ... }
if(p & std::filesystem::perms::owner_write) { ... }
if(p & std::filesystem::perms::owner_exec) { ... }
You can also create a filesystem::perms with the octal value:
if(p & std::filesystem::perms{0400}) { ... }
For more about different perms available values: https://en.cppreference.com/w/cpp/filesystem/perms

Related

Qt QFile return non existent but still opens and writes to file

I have this file which is located in my C drive, I know it exists. When I access it with QFile.exists() it returns false, however it still opens the file and writes to it, I just cant read it. I've been working on this for a while and cannot find a solution, any suggestions are appreciated.
QFile tmpfile("C:/file.txt");
QString tmpcontent;
if(!QFile::exists("C:/file.txt"))
qDebug() << "File not found"; // This is outputted
if (tmpfile.open(QIODevice::ReadWrite | QIODevice::Truncate)) {
QTextStream stream(&tmpfile);
stream << "test"; //this is written
tmpcontent = tmpfile.readAll(); // this returns nothing
}
If file is not exist it will be created by open because you do it in write mode.
readAll function return all remaining data from device, since you just write something you are currently at the end of a file, and there is no data, try to seek( 0 ) to return to the beginnig of a file and then use readAll.
qDebug() << "File exists: " << QFile::exists("text.txt");
QFile test( "text.txt" );
if ( test.open( QIODevice::ReadWrite | QIODevice::Truncate ) ){
QTextStream str( &test );
str << "Test string";
qDebug() << str.readAll();
str.seek( 0 );
qDebug() << str.readAll();
test.close();
}else{
qDebug() << "Fail to open file";
}
As I can see from your code you need that file as a temporary, in such case I suggest to use QTemporaryFile, it will be created in temp directory (I belive there will be no problem with permissions), with unique name and will be auto deleted in object dtor.

Write file to Linux Application data directory

I need to write files to the Application Data directory of the application that I'm designing. Im developing under Ubuntu using Qt. The following snippet shows my write function:
FileOperations::Error FileOperations::saveUsage(SensorIdentification sensorID, QList<UsageListModel::Usage> &usageList)
{
QString fileName(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
fileName.append("/");
fileName.append("testnaam");
fileName.append(FILE_EXTENSION);
this->sensorID = sensorID;
QFile file(fileName);
if(!file.open(QIODevice::WriteOnly))
{
return Error::FileNotOpen;
}
QDataStream out(&file);
out << sensorID;
for(int i = 0; i < usageList.size(); i++)
out << usageList.at(i).date << usageList.at(i).totalSteps << usageList.at(i).wearTime;
if(file.size())
{
file.close();
return Error::NoError;
}
else
{
file.close();
return Error::WritingToFileFailed;
}
}
The fileName after the appends is: "/home/jan/.local/share/Foo/Bar With Spaces/testnaam.liv"
For some reason I cant write a file in that directory. It does work correctly when i write to the users documents folder. Why cant i write to the appdata folder?

Detect if file is open in C++

Is there any way in C++ to detect if a file is already open in another program?.I want to delete and rewrite some files, but in case a file is opened I want to display an error message. I am using Windows OS.
Taking an action depending on the result of the "is file open query" is a race condition (the query returns false and then a program opens the file before your program attempts to delete it for example).
Attempt to delete the file using DeleteFile() and if it fails display the reason the file delete failed, using GetLastError(). See System Error Codes for the list of error codes (ERROR_SHARING_VIOLATION which states "The process cannot access the file because it is being used by another process.")
You can use CreateFile API function with the share mode of NULL, which opens the file for exclusive use.
You can use remove("filename") function.
you can use is_open() to check if the file is open. If it is you can close it or do somehting else.
Here is an exampe:
int main ()
{
fstream filestr;
filestr.open ("test.txt");
if (filestr.is_open())
{
filestr << "File successfully open";
filestr.close();
}
else
{
cout << "Error opening file";
}
return 0;
}
#include <iostream> // std::cout
#include <fstream> // std::ofstream
int main () {
std::ofstream ofs;
ofs.open ("example.txt");
if (ofs.is_open())
{
ofs << "anything";
std::cout << "operation successfully performed\n";
ofs.close();
}
else
{
std::cout << "Error opening file";
}
return 0;
}

How to check if a file exists before creating a new file

I want to input some contents to a file, but I'd like to check first if a file with the name I wish to create exists. If so, I don't want to create any file, even if the file is empty.
My attempt
bool CreateFile(char name[], char content[]){
std::ofstream file(name);
if(file){
std::cout << "This account already exists" << std::endl;
return false;
}
file << content;
file.close();
return true;
}
Is there any way to do what I want?
Assuming it is OK that the operation is not atomic, you can do:
if (std::ifstream(name))
{
std::cout << "File already exists" << std::endl;
return false;
}
std::ofstream file(name);
if (!file)
{
std::cout << "File could not be created" << std::endl;
return false;
}
...
Note that this doesn't work if you run multiple threads trying to create the same file, and certainly will not prevent a second process from "interfering" with the file creation because you have TOCTUI problems. [We first check if the file exists, and then create it - but someone else could have created it in between the check and the creation - if that's critical, you will need to do something else, which isn't portable].
A further problem is if you have permissions such as the file is not readable (so we can't open it for read) but is writeable, it will overwrite the file.
In MOST cases, neither of these things matter, because all you care about is telling someone that "you already have a file like that" (or something like that) in a "best effort" approach.
you can also use Boost.
boost::filesystem::exists( filename );
it works for files and folders.
And you will have an implementation close to something ready for C++14 in which filesystem should be part of the STL (see here).
Try
ifstream my_file("test.txt");
if (my_file)
{
// do stuff
}
From: How to check if a file exists and is readable in C++?
or you could use boost functions.
Try this (copied-ish from Erik Garrison: https://stackoverflow.com/a/3071528/575530)
#include <sys/stat.h>
bool FileExists(char* filename)
{
struct stat fileInfo;
return stat(filename, &fileInfo) == 0;
}
stat returns 0 if the file exists and -1 if not.
As of C++17 there is:
if (std::filesystem::exists(pathname)) {
...
Looked around a bit, and the only thing I find is using the open system call. It is the only function I found that allows you to create a file in a way that will fail if it already exists
#include <fcntl.h>
#include <errno.h>
int fd=open(filename, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
if (fd < 0) {
/* file exists or otherwise uncreatable
you might want to check errno*/
}else {
/* File is open to writing */
}
Note that you have to give permissions since you are creating a file.
This also removes any race conditions there might be
I just saw this test:
bool getFileExists(const TCHAR *file)
{
return (GetFileAttributes(file) != 0xFFFFFFFF);
}
C++17, cross-platform: Using std::filesystem::exists and std::filesystem::is_regular_file.
#include <filesystem> // C++17
#include <fstream>
#include <iostream>
namespace fs = std::filesystem;
bool CreateFile(const fs::path& filePath, const std::string& content)
{
try
{
if (fs::exists(filePath))
{
std::cout << filePath << " already exists.";
return false;
}
if (!fs::is_regular_file(filePath))
{
std::cout << filePath << " is not a regular file.";
return false;
}
}
catch (std::exception& e)
{
std::cerr << __func__ << ": An error occurred: " << e.what();
return false;
}
std::ofstream file(filePath);
file << content;
return true;
}
int main()
{
if (CreateFile("path/to/the/file.ext", "Content of the file"))
{
// Your business logic.
}
}
The easiest way to do this is using ios :: noreplace.

C++ Qt - opening text file operation failure

I'm using Qt to develop my C++ application using QML as well.
Here's my code
QFile inputFile("data.txt");
//QFile inputFile("/:data.txt");
qDebug() << "Hello:";
if (!inputFile.open(QIODevice::ReadOnly | QIODevice::Text))
{
qDebug() << "Wasn't ready:";
}
else{
qDebug() << "Txt file ready:";
QTextStream in(&inputFile);
while ( !in.atEnd() )
{
QString line = in.readLine();
qDebug() << "message: " << line;
}
}
I was wondering why it doesn't work. The console always prints "Wasn't ready".
Please help.
In the error handling block where you do qDebug() << "Wasn't ready:"; you should call inputFile.error() and print out the returned value to get more details of what went wrong.
It might also be an idea to start the program with printing out the current directory, to make sure that the file is searched for in the correct location.