Check if a file is readonly in c++ - c++

I want to check if a .ini file is readonly or not in c++ for windows systems
for example:
if(file == readonly){
//Do this
}
so far i have tried with this and it worked:
ofstream ofs(filename); //test to see if the file successfully opened for writing or not
but as a result it would delete the .ini file and it leave the file blank
PS:
1.it is not a duplicate
2. I have searched all over internet and i found some examples that could have worked but as a result the did not compiled as they should.

If you're on Windows you can use:
DWORD attr = GetFileAttributes(filename);
if (attr != INVALID_FILE_ATTRIBUTES) {
bool isReadOnly = attr & FILE_ATTRIBUTE_READONLY;
}

Related

Add files to the existing archive in XZip, C++, Windows

I am creating a windows service that periodically copies the contents of a folder to an archive. I've searched for archiving libraries and found suggestions to use XZip.
Now I can create a new archive using code like this:
HZIP arch = CreateZip((void*)Archive.c_str(), 0, ZIP_FILENAME);
if (arch == nullptr)
return addLogMessage("Unable to open archive.");
for (const auto& file : std::filesystem::directory_iterator(Directory)) {
const std::wstring filePath = file.path().wstring();
const std::wstring nameInArchive = file.path().filename().wstring();
if (ZipAdd(arch, (TCHAR*)nameInArchive.c_str(), (TCHAR*)filePath.c_str(), 0, ZIP_FILENAME) != ZR_OK) {
std::string what = "Error: Adding '" + std::string(filePath.begin(), filePath.end()) + "' to the archive.";
addLogMessage(what.c_str());
}
}
CloseZip(arch);
I also want to add files to an existing archive. When I run the code below, I get a ZR_ZMODE error from the ZipAdd function, which means tried to mix create / open zip archive:
if (std::filesystem::exists(Archive)) {
HZIP arch = OpenZip((void*)Archive.c_str(), 0, ZIP_FILENAME);
if (arch == nullptr)
return addLogMessage("Unable to re-open existing archive.");
for (const auto& file : std::filesystem::directory_iterator(Directory)) {
const std::wstring filePath = file.path().wstring();
const std::wstring nameInArchive = file.path().filename().wstring();
if (ZipAdd(arch, (TCHAR*)nameInArchive.c_str(), (TCHAR*)filePath.c_str(), 0, ZIP_FILENAME) != ZR_OK) {
std::string what = "Error: Adding '" + std::string(filePath.begin(), filePath.end()) + "' to the archive.";
addLogMessage(what.c_str());
}
}
CloseZip(arch);
}
I assume that in XZip library, I'm not able to add files to the existing archive. Is it true?
EDIT: I've solved the problem with different library, libzip. Now I can add new files to the old archive, and everything works fine. I've posted source code and compiling/linking instruction here.
I am still interested, if there is an option for adding files to the existing archive in XZip library, so I will not close the question for now.

MFC C++: How to actually save a certain file to the system, not just open a save as dialog box

I searched everywhere but I can't find sample on how to actually save a file to the system. Threads about opening a Save File dialog box can be read in numerous sites but the successful saving of the user created file to a user selected path is always cut (//add your code here). Please bear with me as I am new in C++ (MFC).
I know I need to actually code the saving of the data to the file path but I just don't know how.
Code snippet (via CFileDialog):
void CTryDlg::OnBnClickedSaveAs()
{
CFileDialog dlg(FALSE);
dlg.m_ofn.nMaxFile = MAX_PATH;
dlg.m_ofn.lpstrFilter = _T("Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0\0");
dlg.m_ofn.lpstrTitle = _T("Save File As");
CString filename;
if (dlg.DoModal() == IDOK)
{
filename = dlg.GetPathName(); // return full path and filename
//write your sample code here to save the file to the user selected path
}
}
Code snippet via GetSaveFileName():
OPENFILENAME SfnInit()
{
OPENFILENAME t_sfn;
char szFileName[MAX_PATH] = "";
ZeroMemory(&t_sfn, sizeof(t_sfn));
t_sfn.lStructSize = sizeof(t_sfn);
t_sfn.hwndOwner = NULL;
t_sfn.lpstrFilter = _T("Text file\0*.txt\0");
t_sfn.lpstrFile = szFileName;
t_sfn.lpstrTitle = _T("Save As\0");
t_sfn.nMaxFile = MAX_PATH;
t_sfn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
t_sfn.lpstrDefExt = _T("Text file\0*.txt\0");
if (GetSaveFileName(&t_sfn2) != true)
{
AfxMessageBox(_T("Saving file canceled!"));
}
else
{
//write your sample code here to save the file to the user selected path
}
}
Anybody who can provide a very simple sample code that could actually save a user desired file (ex: text file) to the user selected path will be greatly appreciated.
I have also read that the program should run as administrator.
Thank you.
Since you are using MFC, I would recommend sticking with MFC classes for such file I/O.
Sadly, I am using VS 2008, but here is the class hierarchy for CFile:
If it's a text file, using/deriving from CStdioFile makes sense. It has the basic ReadString WriteString methods.
However, if you are wanting to serialize something derived from CDocument (Document/View architecture), you will want to utilize streams, possibly with schemas/versioning to go with your serialization. That's a completely different topic/answer.
EDIT: duh - here's a simple CStdioFile output
CFileDialog fd(FALSE, "txt", "MyFile.txt", OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, "Text files (*.txt)|*.txt|All files (*.*)|*.*", this);
if (fd.DoModal() == IDOK)
{
CStdioFile fOut(fd.GetPathName(), CFile::modeCreate | CFile::modeWrite);
for (int i = 0; i < asData.GetSize(); i++)
{
fOut.WriteString(asData[i] + '\n');
}
fOut.Close();
}
Here is a very basic sample:
...
if (dlg.DoModal() == IDOK)
{
filename = dlg.GetPathName(); // return full path and filename
FILE *file = fopen(filename, "w"); // open file for writing
if (file == NULL)
AfxMessageBox("File couild not be created."};
else
{
// file could be created, write something
fprintf(file, "Some text\n");
// and close the file
fclose(file);
}
}
...
This will write "some text" into the file whose name has been provided by the user with the CFileDialog file picker.
In real world you need to write whatever text according to the data of your program.
This is really most basic knowledge.

Append files to an existing zip file with Poco::Zip

After successfully compress the folder, here is my situation :
If append = true and overWrite = false I have to check whether if the target zip file exists or not if existed I will check the existed zip file which files it doesn't contain and append new file from the source folder to it.
My question is:
How can I open the zip file and put it to the compress object? or which others library in Poco should I use to open zip stream? I'm trying to use std::ifstream but Poco::zip::Compress doesn't seem to receive an std::ifstream
I surely have to modify the Poco source code itself to match with my requirement. Thanks in advance.
void ZipFile(string source, string target, List extensions, bool append, bool overWrite)
{
Poco::File tempFile(source);
if (tempFile.exists())
{
if (Poco::File(target).exists() && append && !overWrite) {
fs::path targetPath = fs::path(target);
std::ifstream targetFileStream(targetPath.string(), std::ios::binary);
std::ofstream outStream(target, ios::binary);
CompressEx compress(outStream, false, false);
if (tempFile.isDirectory())
{
Poco::Path sourceDir(source);
sourceDir.makeDirectory();
compress.addRecursive(sourceDir, Poco::Zip::ZipCommon::CompressionMethod::CM_AUTO,
Poco::Zip::ZipCommon::CL_NORMAL, false);
}
else if (tempFile.isFile())
{
Poco::Path path(tempFile.path());
compress.addFile(path, path.getFileName(), Poco::Zip::ZipCommon::CompressionMethod::CM_AUTO,
Poco::Zip::ZipCommon::CL_NORMAL);
}
compress.close(); // MUST be done to finalize the Zip file
outStream.close();
}
}
No need to modify the Poco source code. Poco allows you to get the contents of an archive and add files to it.
First, open the target archive to check which files are already in there:
Poco::ZipArchive archive(targetFileStream);
Then collect all files you want to add, that are not in the archive, yet:
std::vector<fs::path> files;
if (fs::is_directory(source)) {
for(auto &entry : fs::recursive_directory_iterator())
// if entry is file and not in zip
if (fs::is_regular_file(entry)
&& archive.findHeader(fs::relative(entry.path, source)) == archive.headerEnd()) {
files.push_back(entry.path);
}
} else if (fs::is_regular_file(entry)
&& archive.findHeader(source) == archive.headerEnd()) {
files.push_back(source);
}
Finally, add the files to your zip
Poco::Zip::ZipManipulator manipulator(target, false);
for(auto &file : files)
manipulator.addFile(fs::relative(file, source), file,
Poco::Zip::ZipCommon::CompressionMethod::CM_AUTO,
Poco::Zip::ZipCommon::CL_NORMAL);
I had no opportunity to test this. So try it out and see what needs to be done to make it work.

Poco::Zip set Extension List

After successfully compress the zip file, I want to add extensions list in order to only zip any files that have extensions within the Extensions List.
set <string> extensionsSet;
std::ofstream fos(target, ios::binary);
Poco::Zip::Compress c(fos, true);
extensionsSet.insert("txt");
c.setStoreExtensions(extensionsSet);//set extensions List
set <string> a = c.getStoreExtensions();//a contains 1 string which is txt
Poco::File aFile(source);
if (aFile.exists())
{
if (aFile.isDirectory())
{
Poco::Path sourceDir(source);
sourceDir.makeDirectory();
c.addRecursive(sourceDir, Poco::Zip::ZipCommon::CompressionMethod::CM_DEFLATE,
Poco::Zip::ZipCommon::CL_NORMAL, false);
}
else if (aFile.isFile())
{
Poco::Path p(aFile.path());
c.addFile(p, p.getFileName(), Poco::Zip::ZipCommon::CompressionMethod::CM_AUTO,
Poco::Zip::ZipCommon::CL_NORMAL);
}
}
else {
_log.EndMethod();
throw new FileNotFoundException("File Not Found");
}
c.close(); // MUST be done to finalize the Zip file
fos.close();
Can anyone help me to find out what's wrong within my code, because I don't see any difference when I set the extensions List? I want to zip a file(e.g test.txt), following my code should "test.txt" be included in the zip file?

Windows: File rename and directory iteration clash

I'm using boost::filesystem to rename a file like this:
boost::filesystem::rename(tmpFileName, targetFile);
tmpFileName / targetFile are of type boost::filsystem::path.
While doing this, I iterate over the directory using this code in another thread:
directory_iterator end_itr;
for (directory_iterator itr(dirInfoPath); itr != end_itr; ++itr)
{
path currentPath = itr->path();
if (is_directory(itr->status()))
{
// skip directories
}
else
{
std::string file_name = currentPath.leaf();
if (!boost::algorithm::starts_with(file_name, "new")
&& !boost::algorithm::starts_with(file_name, "finished")
&& boost::algorithm::ends_with(file_name, ".info"))
{
// save found filename in some variable
return true;
}
}
}
When this code is executed, I get an exception while renaming:
boost::filesystem::rename: The process cannot access the file because it is being used by another process
Is it possible that the iteration and the rename operation clash, because they both access the directory inode, or do I have some other problem?
code you provided doesn't contain any file open operations, so it cannot lock the file. you iterate over directory and renaming file, right? so it's possible this file is really used by another application like file viewer or something else, it's quite typical error. or you have it opened in your app somewhere else