C++ remove() and rename() gives "Permission error" - c++

I can't figure out what is happening in my program, it's a simple function to clear all the Windows '\r' from a file, putting all the chars in another file and then rename it to substitute the old file. Every time I execute the function the rename() and remove() functions give me "Permission error" even if I had all the file pointers closed and the file on my PC is closed in every program. Here's the code
static bool correctFile(string fileName) {
string name = fileName;
FILE* test = fopen(fileName.c_str(), "rb");
FILE *in, *out;
char stringTest[1000];
bool isWinFile = false;
if (!test) {
return false;
}
fread(stringTest, 1, 1000, test);
fclose(test);
for (size_t i = 0; i < strlen(stringTest) && !isWinFile; i++) {
if (stringTest[i] == '\r') {
isWinFile = true;
}
}
if (isWinFile) {
in = fopen(fileName.c_str(), "rb");
string tempFile = name + ".temp";
out = fopen(tempFile.c_str(), "wb");
if (!in || !out) {
return false;
}
char temp;
while (fread(&temp, sizeof(temp), 1, in) > 0) {
if (temp != '\r') {
fwrite(&temp, sizeof(temp), 1, out);
}
}
fclose(in);
fclose(out);
if (std::remove(fileName.c_str())) {
std::cerr << "Error: " << strerror(errno);
return false;
}
if (std::rename(tempFile.c_str(), fileName.c_str())) {
return false;
}
}
return true;
}
If you find an error in this please tell me, thanks

I found out that the old file and the new file must not be in the same folder for some reason

Disable the virus scanner and see if the problem persists. Some antivirus products block access to files for a couple of microseconds after they have been written or modified. I know of Kaspersky for example.
I have a "Antivirus" retry loop in some of my batch files because of this. So one (ugly) solution is to retry the rename/remove operations a couple of times.

Related

Enabling C code to run as C++ code

I have a C program that finds duplicate files within a directory. The program is executed on the command line and passed 2 arguments. One is the parent directory, and argument two is the file name. It is working code in c, but I have a GUI and other files for "microservices" written in c++.
How would one call this C code from a c++ file?
#include<stdio.h>
#include<dirent.h>
#include<sys/stat.h>
#include<errno.h>
#include<string.h>
#include<stdlib.h>
#include<fcntl.h>
//Compile: gcc dreamduplicatefinder.c -o dreamduplicatefinder.exe
//Run: ./dreamduplicateFinder.exe parent_dir filename...
#define false 0
#define true 1
int duplicateCount = 0;
int FindDuplicates(char* path, char* fileName);
int CompareFiles(char* originalFile, char* currFile);
int main(int argc, char *argv[])
{
//Two additional arguments are expected: Parent dir, file to find duplicates of...
if (argc != 3)
{
printf("Usage: %s 'Base Directory' 'File Name'\n", argv[0]);
return -1;
}
//argv[1] = base dir, argv[2] = file to find duplicates of; e.g argv[1] = /home,
//argv[2] = "file.txt"...
FindDuplicates(argv[1], argv[2]);
printf("\n\nFound %d duplicate(s)\n", duplicateCount);
return 0;
}
int FindDuplicates(char* path, char* fileName)
{
DIR *dir;
struct dirent *dp;
struct dirent *result;
struct stat statp;
char absoluteFilePath[255];
if ((dir = opendir(path)) == NULL)
{
//printf(dir); //error could becuase trying to open shortcut or corrupt folder.
printf("%s\n",path);
perror("Failed to open directory");
return -1;
}
while ((dp = readdir(dir)) != NULL)
{
//readdir returns . and .. which we should ignore...
if (strcmp(dp->d_name, ".") && strcmp(dp->d_name, ".."))
{
//find file full path, relative to base path. e.g, a /home/file.txt...
//copy path to absoluteFilePath...
strcpy(absoluteFilePath, path);
//append / at end...
strcat(absoluteFilePath, "/");
//append filename to path...
strcat(absoluteFilePath, dp->d_name);
//check if the current file is actually file or dir...
stat(absoluteFilePath, &statp);
if (S_ISDIR(statp.st_mode)) //is a directory...
{
//recurse through this dir...
FindDuplicates(absoluteFilePath, fileName);
}
else if (S_ISREG(statp.st_mode)) //is a file...
{
//check for duplicates here...
//compare current file with the file specified by user...
if (strcmp(fileName, absoluteFilePath))
{
if (CompareFiles(fileName, absoluteFilePath))
{
//yes, duplicate; print it...
printf("%s\n", absoluteFilePath);
duplicateCount++;
}
}
} //end else if (S_ISREG(statp.st_mode))...
} //if (strcmp(dp->d_name, ".") && strcmp(dp->d_name,".."))...
} //end while...
closedir(dir);
return 0;
}
int CompareFiles(char* originalFile, char* currFile)
{
//two step comparison: (1) first check size; if not same, return false.
//If equal, (2) compare file content.If equal, return true, false otherwise...
struct stat statOriginal, statCurr;
stat(originalFile, &statOriginal);
stat(currFile, &statCurr);
//Step 1...
if ((int)statOriginal.st_size != (int)statCurr.st_size) //size not same...
return false;
//Step 2...
//size matches, files can be same; confirm it by matching both file contents...
int fdOriginal = open(originalFile, O_RDONLY);
int fdCurr = open(currFile, O_RDONLY);
if (fdOriginal == -1 || fdCurr == -1)
return false; //error occurred, not sure if file is duplicate...
//we will read file in small chunks and compare...
int chunkSize = 1024, bytesRead;
char *bufferOriginal = (char*)malloc(chunkSize * sizeof(char));
char *bufferCurr = (char*)malloc(chunkSize * sizeof(char));
while (true)
{
//read file in chunk...
bytesRead = read(fdOriginal, bufferOriginal, chunkSize);
if (bytesRead <= 0)
break; //end of file...
bytesRead = read(fdCurr, bufferCurr, bytesRead);
//compare buffer...
if (strcmp(bufferOriginal, bufferCurr)) //if content not matching...
return false;
}
return true;
}
My errors include: (from compareFiles function)
2x 'open' identifier not found
2x 'read' identifier not found
The working code for those curious.
Thank you #MarcusMüller & #JesperJuhl
#include "stdafx.h" //there is nothing in this header
#include<stdio.h>
#include<dirent.h>
#include<sys/stat.h>
#include<errno.h>
#include<string.h>
#include<stdlib.h>
#include<fcntl.h>
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
//Compile: gcc <name of this file>.cpp -o <nameOfThisFile>.exe
//Run: <nameOfThisFile> parent_dir filename...
#define false 0
#define true 1
int duplicateCount = 0;
int FindDuplicates(char* path, char* fileName);
int CompareFiles(char* originalFile, char* currFile);
int main(int argc, char *argv[])
{
//Two additional arguments are expected: Parent dir, file to find duplicates of...
if (argc != 3)
{
printf("Usage: %s 'Base Directory' 'File Name'\n", argv[0]);
return -1;
}
//argv[1] = base dir, argv[2] = file to find duplicates of; e.g argv[1] = /home,
//argv[2] = "file.txt"...
FindDuplicates(argv[1], argv[2]);
printf("\n\nFound %d duplicate(s)\n", duplicateCount);
return 0;
}
int FindDuplicates(char* path, char* fileName)
{
DIR *dir;
struct dirent *dp;
struct dirent *result;
struct stat statp;
char absoluteFilePath[255];
if ((dir = opendir(path)) == NULL)
{
//possibly trying to open shortcut or corrupt folder typically.
printf("Failed to open directory %s \n",path);
return -1;
}
while ((dp = readdir(dir)) != NULL)
{
//readdir returns . and .. which we should ignore...
if (strcmp(dp->d_name, ".") && strcmp(dp->d_name, ".."))
{
//find file full path, relative to base path. e.g, a /home/file.txt...
//copy path to absoluteFilePath...
strcpy(absoluteFilePath, path);
//append / at end...
strcat(absoluteFilePath, "/");
//append filename to path...
strcat(absoluteFilePath, dp->d_name);
//check if the current file is actually file or dir...
stat(absoluteFilePath, &statp);
if (S_ISDIR(statp.st_mode)) //is a directory...
{
//recurse through this dir...
FindDuplicates(absoluteFilePath, fileName);
}
else if (S_ISREG(statp.st_mode)) //is a file...
{
//check for duplicates here...
//compare current file with the file specified by user...
if (strcmp(fileName, absoluteFilePath))
{
if (CompareFiles(fileName, absoluteFilePath))
{
//yes, duplicate; print it...
printf("This is a duplicate! %s\n", absoluteFilePath);
duplicateCount++;
}
}
} //end else if (S_ISREG(statp.st_mode))...
} //if (strcmp(dp->d_name, ".") && strcmp(dp->d_name,".."))...
} //end while...
closedir(dir);
return 0;
}
int CompareFiles(char* originalFile, char* currFile)
{
//two step comparison: (1) first check size; if not same, return false.
//If equal, (2) compare file content.If equal, return true, false otherwise...
struct stat statOriginal, statCurr;
stat(originalFile, &statOriginal);
stat(currFile, &statCurr);
//Step 1...
if ((int)statOriginal.st_size != (int)statCurr.st_size) //size not same...
return false;
FILE* fdOriginal;
if (fdOriginal = fopen(originalFile, "r")) {
if (fdOriginal == NULL) { fputs("File error", stderr); return false; }
}
else return false; //error occurred, not sure if duplicate
FILE* fdCurr;
if (fdCurr = fopen(currFile, "r")) {
if (fdCurr == NULL) { fputs("File error", stderr); return false; }
}
else return false;
int chunkSize = 1024, objsRead;
char *bufferOriginal = (char*)malloc(chunkSize * sizeof(char));
if (bufferOriginal == NULL) { fputs("Memory error for buff orig", stderr); exit(2); }
char *bufferCurr = (char*)malloc(chunkSize * sizeof(char));
if (bufferCurr == NULL) { fputs("Memory error for buff curr", stderr); exit(2); }
while (true)
{
//read file in chunk...
//std::size_t fread( void* buffer, std::size_t size, std::size_t count, std::FILE* stream );
objsRead = fread(bufferOriginal, sizeof(char), chunkSize , fdOriginal);
if (objsRead <= 0)
break; //end of file...
objsRead = fread(bufferCurr, sizeof(char), objsRead, fdCurr);
//compare buffer...
if (strcmp(bufferOriginal, bufferCurr)) //if content not matching...
return false;
}
return true;
}
You usually just wouldn't do that. You'd wrap it in a C function, and compile it to an object file.
Then you'd include your C header with extern "C" {…}, and just call that function from C++.
When building your executable, you'd link in the object file containing your C function. Done!
Note: C isn't C++, and albeit your code not being illegal in C++ (as far as I can instantly tell), it does very "ugly" things (like #defineing true and false – ugh, that would already be a bad idea in C, to be honest). So, deal with it like you would deal with code in Fortran, or Java, or any other language that has a calling convention that you can use from C++ (which, usually, is the C calling convention): Just use it as an extern object.
Using ::open and ::read should cause the functions to be found.
You may also want to replace the C headers (like "string.h") with their C++ equivalent versions (like "cstring").
Your defines for true and false should also go. In C++ those are proper bools, not integers. This means the return type of CompareFiles should be changed to bool.
And you should wrap duplicateCount in an anonymous namespace - or return it from the function that updates it (either by returning a small struct with two ints, or by using a std::pair or std::tuple) - global variables are evil.

fgets only read the first line of file

I am trying to read a file from my .cpp file. I am using C libraries, so do not confuse on that.
So the problem is as clear as what I said in the title. fgets method can read the first line but when it comes to the second line, it cannot read neither the second line nor the rest of the file (since it exits when a problem occurs).
You can find the associated part of code:
void read_input()
{
int i = 0, N = 5;
char str[STR_SIZE], line[STR_SIZE];
FILE *fp;
fp = fopen("out", "r");
if (!fp)
{
fprintf(stderr, "error: file could not be opened\n");
exit(1);
}
for (i = 0; i<2; i++)
{
if (fgets(str, STR_SIZE, fp) == NULL)
{
fprintf(stderr, "error: failed at file reading\n");
exit(1);
}
if (feof(fp))
{
fprintf(stderr, "error: not enough lines in file\n");
exit(1);
}
if ((sscanf(str, "%s", line) != 1) )
{
fprintf(stderr, "error: invalid file format\n");
exit(1);
}
printf("%d\t%s\n", i, line);
fclose(fp);
}
}
I believe, the problem is there, because you've used fclose(fp); inside the loop. So, after the very first iteration, the fp is passed to fclose() and for any recurring use of fp in any further iteration will invoke undefined behavior as the fp is not valid anymore.
Solution: Move the fclose(fp); outside the loop.
You are closing the file in the loop! Put the fclose function outside of the loop.
for (i = 0; i<2; i++)
{
....
printf("%d\t%s\n", i, line);
fclose(fp); // <-- here, move out of the loop.
}

How to download binary file using wxwidgets

I found this code snippet for downloading file:
wxURL url(wxT("http://www.example.com/file.txt"));
if(url.GetError()==wxURL_NOERR)
{
wxString htmldata;
wxInputStream *in = url.GetInputStream();
if(in && in->IsOk())
{
wxStringOutputStream html_stream(&htmldata);
in->Read(html_stream);
wxLogMessage(htmldata);
}
delete in;
}
But fistly it just logs content of file and only for text-files. But I need to download *.exe file to execute it later. So I need to adapt this code to work with binary data, and save this data to file on the disk. Too many Streams used here for my understanding what's going on here. Please help.
I have written below code previously...
This will work fine to download binary files in any platforms.
/** START */
// ex) ht tp://mysite.com/mypath.jpg
wxString path = wxT("/mypath.jpg");
wxString server = wxT("mysite.com");
wxHTTP http;
http.SetHeader(_T("Content-type"), contentType);
http.SetTimeout(10);
// wxString imageFilePath = wxT("/tmp/image.jpg");
wxFileOutputStream output(imageFilePath);
wxDataOutputStream store(output);
if (http.Connect(server, 80))
{
wxInputStream *stream;
stream = http.GetInputStream(path);
if (stream == NULL)
{
output.Close();
}
else
{
unsigned char buffer[1024];
int byteRead;
// receive stream
while (!stream->Eof())
{
stream->Read(buffer, sizeof(buffer));
store.Write8(buffer, sizeof(buffer));
byteRead = stream->LastRead();
if (byteRead <= 0)
{
break;
}
}
output.Close();
}
}
else
{
output.Close();
}

libzip can't close file

I'm currently using libzip in a C++11 program to extract the contents of a compressed file and store them into a data structure that will also hold metadata related to the file.
I'm using the current method to explode the zip file and get the content of each file in it:
void explodeArchive(const string& path, vector<ZipFileModel>& files) {
int error = 0;
zip *zip = zip_open(path.c_str(), 0, &error);
if (zip == nullptr) {
throw logic_error("Could not extract content of file " + path);
}
const zip_int64_t n_entries = zip_get_num_entries(zip, ZIP_FL_UNCHANGED);
for (zip_int64_t i = 0; i < n_entries; i++) {
const char *file_name = zip_get_name(zip, i, ZIP_FL_ENC_GUESS);
struct zip_stat st;
zip_stat_init(&st);
zip_stat(zip, file_name, ZIP_FL_NOCASE, &st);
char *content = new char[st.size];
std::cerr << file_name << std::endl;
zip_file *file = zip_fopen(zip, file_name, ZIP_FL_NOCASE);
const zip_int64_t did_read = zip_fread(file, content, st.size);
if (did_read <= 0) {
continue;
}
if (strlen(content) < st.size) {
LOG(WARNING)<< "File " << file_name << " is truncated.";
}
if (strlen(content) > st.size) {
content[st.size] = '\0';
}
ZipFileModel model;
model.name = string(file_name);
model.content = string(content);
model.order = -1;
files.push_back(model);
zip_fclose(file);
delete[] content;
}
zip_close(zip);
}
My problem is that I get random segmentation faults with gdb pointing to zip_fclose(file);:
Program received signal SIGSEGV, Segmentation fault.
0x00000001001ef8a0 in zip_source_close (src=0x105001b00) at /Users/xxx/Projects/xxx/xxx/src/libzip/zip_source_close.c:48
48 (void)src->cb.l(src->src, src->ud, NULL, 0, ZIP_SOURCE_CLOSE);
What's the best way to debug this? As I said it happens intermittently so it's hard to pin down the exact cause.
You aren't closing the zip_file when there's nothing to read.
First you open the file inside:
zip_file *file = zip_fopen(zip, file_name, ZIP_FL_NOCASE);
Then try to read something:
const zip_int64_t did_read = zip_fread(file, content, st.size);
and if there's nothing to read you continue and the file is never closed.
if (did_read <= 0) {
continue;
}
So, just add:
if (did_read <= 0) {
zip_fclose(file);
continue;
}

Lingering open files resulting in "Too many open files"

I have code using boost to list directory contents, iterate through each file, and do some data processing stuff. The results are being printed to an output file ('histFile').
After ~2555 files have been processed, I get the error:
boost::filesystem::directory_iterator::construct: Too many open files: "/Users/.../.../.../directory_with_files"
My code is:
for(int i = 0; i < 10000; i++) {
FILE *histFile;
string outputFileName = "somename";
bool ifRet = initFile(histFile, outputFileName.c_str(), "a"); // 1
fclose(histFile); // 2
}
If I comment out the last two lines above ('1' and '2'), the code finishes fine. Thus it seems copies of 'histFile' are being left open, but I don't understand how! This is the operative part of the method:
bool initFile(FILE *&ofFile, const char *fileName, const char *openType, int overwriteOption) {
if(overwriteOption < 0 || overwriteOption > 2) {
fprintf(stderr, "ERROR: ToolBox - initFile() : unknown 'overwriteOption' (%d), setting to (0)!\n", overwriteOption);
}
// Read-Only
if(openType == "r") {
if(ofFile = fopen(fileName, "r")) { return true; }
fprintf(stderr, "ERROR: Could not open file (%s)!\n", fileName);
return false;
}
// Appending:
if(openType == "a" || openType == "a+") {
// Check if file already exists
if(!fopen(fileName, "r")){
fprintf(stderr, "ERROR: (%s) File does not Exist, cannot append!\n", fileName);
return false;
}
if(ofFile = fopen(fileName, openType)) { return true; }
}
// Writing:
// if file already exists
if(FILE *temp = fopen(fileName, "r")){
if(overwriteOption == 2) {
fprintf(stderr, "ERROR: (%s) File Exists!\n", fileName);
return false;
}
if(overwriteOption == 1) {
}
if(overwriteOption == 0) {
char backupFileName[TB_CHARLIMIT], backupPrefix[TB_CHARLIMIT];
strcpy(backupFileName, fileName); // copy filename
// create a prefix w/ format '<YYYYMMDD>BACKUP_'
DateTime now;
sprintf(backupPrefix, "%s", now.getDateStr().c_str());
strcat(backupPrefix, "BACKUP_");
// add to copied filename, and move file
strcpy(backupFileName, prependFileName(backupFileName, backupPrefix));
moveFile(fileName, backupFileName);
}
fclose(temp);
}
if(ofFile = fopen(fileName, openType)) { return true; }
// Default: Return error and false
fprintf(stderr, "ERROR: Could not open file (%s)!\n", fileName);
return false;
}
Am I doing something wrong with pointers/references?
Any help greatly appreciated!
You're leaking a handle in this bit of code when you're testing if the file exists already:
// Appending:
if(openType == "a" || openType == "a+") {
// Check if file already exists
if(!fopen(fileName, "r")){ // <-- the FILE* opened here is leaked
fprintf(stderr, "ERROR: (%s) File does not Exist, cannot append!\n", fileName);
return false;
}
if(ofFile = fopen(fileName, openType)) { return true; }
}
Is there really a reason to make that check? Why not just let the file be created if it doesn't already exist?