Detail File IO error reporting in C++ - c++

Is there any open source File IO library or easy way in C++ which reports a detail and exact errors for File IO. For examples; If user doesnt have the read or right permission - or if the disk got full etc.

C style file ops do this by default, you just need to include cerrorno and cstring and use strerror after an unsuccessful file operation call:
hFile = fopen(fname, "r+b");
/*-- attempt to create the file if we can't open it for reading --*/
if(!hFile) {
/*-- print out relevant error information --*/
printf("Open File %s Failed, %s\n", fname, std::strerror(errno));
return 1;
}
return 0;
That is of course if you use C style file operations. I think ifstream also supports these on most compilers.
A note, this functionality is not thread safe on some implementations. There is strerror_r on linux which is thread safe.

Related

C++: Problems of file write using FILE Library when file beat process is running

I have a code for file write using FILE Library, and usually works, but I found a case where doesn't work: When the code runs concurrently with filebeat process.
I don't know this cause of the problem because my c++ project does not support debugging mode.
I am participating in an open source project developed by someone else and i am not familiar with this project yet.
This is my c++ code:
FILE *fptr;
fptr = fopen("log_path.c_str()", "w");
if (fptr == NULL)
{
printf("Error!");
exit(1);
}
fprintf(fptr, "%s", log.c_str());
fclose(fptr);
Is there a any other good way to save log files?
Please give me some advice.
Your code have broken-pipe exception when you try to write a file.
This exception occurs when a c++ code try to write a log file while the filebeat software is reading the log file.
So, I recommend using this C++ code:
#include <fstream>
#include <iostream>
logFilePath = "this is path string of log file";
log = "this is log string";
ofstream output(logFilePath, ios::app);
output << log << endl;
output.close();
This code that used the offstream library will be solve the broken pipe exception.
If you use this c++ code, it is able to use string type for file write process, so it's not necessary to type convert via c_str().
I checked that this code able to used with File beat 7.10.0.
Thank you.

Correct way of using fdopen

I mean to associate a file descriptor with a file pointer and use that for writing.
I put together program io.cc below:
int main() {
ssize_t nbytes;
const int fd = 3;
char c[100] = "Testing\n";
nbytes = write(fd, (void *) c, strlen(c)); // Line #1
FILE * fp = fdopen(fd, "a");
fprintf(fp, "Writing to file descriptor %d\n", fd);
cout << "Testing alternate writing to stdout and to another fd" << endl;
fprintf(fp, "Writing again to file descriptor %d\n", fd);
close(fd); // Line #2
return 0;
}
I can alternately comment lines 1 and/or 2, compile/run
./io 3> io_redirect.txt
and check the contents of io_redirect.txt.
Whenever line 1 is not commented, it produces in io_redirect.txt the expected line Testing\n.
If line 2 is commented, I get the expected lines
Writing to file descriptor 3
Writing again to file descriptor 3
in io_redirect.txt.
But if it is not commented, those lines do not show up in io_redirect.txt.
Why is that?
What is the correct way of using fdopen?
NOTE.
This seems to be the right approach for a (partial) answer to Smart-write to arbitrary file descriptor from C/C++
I say "partial" since I would be able to use C-style fprintf.
I still would like to also use C++-style stream<<.
EDIT:
I was forgetting about fclose(fp).
That "closes" part of the question.
Why is that?
The opened stream ("stream" is an opened FILE*) is block buffered, so nothing gets written to the destination before the file is flushed. Exiting from an application closes all open streams, which flushes the stream.
Because you close the underlying file descriptor before flushing the stream, the behavior of your program is undefined. I would really recommend you to read posix 2.5.1 Interaction of File Descriptors and Standard I/O Streams (which is written in a horrible language, nonetheless), from which:
... if two or more handles are used, and any one of them is a stream, the application shall ensure that their actions are coordinated as described below. If this is not done, the result is undefined.
...
For the first handle, the first applicable condition below applies. ...
...
If it is a stream which is open for writing or appending (but not also open for reading), the application shall either perform an fflush(), or the stream shall be closed.
A "handle" is a file descriptor or a stream. An "active handle" is the last handle that you did something with.
The fp stream is the active handle that is open for appending to file descriptor 3. Because fp is an active handle and is not flushed and you switch the active handle to fd with close(fd), the behavior of your program is undefined.
What is my guess and most probably happens is that your C standard library implementation calls fflush(fp) after main returns, because fd is closed, some internal write(3, ...) call returns an error and nothing is written to the output.
What is the correct way of using fdopen?
The usage you presented is the correct way of using fdopen.

How to share file delete privilege when I opening a file by ifstream

I want to make the file that can be delete when it was opened by ifstream.
I know it is easy when using Windows API: CreateFile
CreateFile(...,FILE_SHARE_DELETE,...)
But when I test with opening a file by ifstream.
It can't be deleted when I opening it.
I didn't find any document about setting attribute such like FILE_SHARE_DELETE on ifstream.
How should I do to solve this problem?
Visual Studio's version of std::ifstream has a non-standard constructor and a non-standard open() overload that both have an extra optional _Prot parameter for specifying "file protection/sharing flags" (see _fsopen() for the list of available flags). However, delete sharing is not one of supported flags.
There is an alternative, though. Visual Studio's version of both std::ifstream and std::ofstream have non-standard constructors that accept a FILE* for the file access. You can wrap a HANDLE from CreateFile() into a FILE* using Microsoft's _open_osfhandle() and _fdopen() functions, for example (error handling removed for brevity):
Can I use CreateFile, but force the handle into a std::ofstream?
HANDLE file_handle = CreateFile(...,FILE_SHARE_DELETE,...);
int file_descriptor = _open_osfhandle((intptr_t)file_handle, _O_RDONLY);
FILE* file = _fdopen(file_descriptor, "r");
std::ifstream stream(file);
...
// Closes stream, file, file_descriptor, and file_handle.
stream.close();
If you need something more portable to non-Microsoft compilers, you will likely have to resort to writing a custom std::basic_streambuf class (or maybe derived from std::filebuf) to wrap your HANDLE, and then pass an object of that class to the std::basic_istream constructor directly.
File permissions differ by operating system:
Windows has:
Whole-file access-sharing for read, write, or delete
*nix systems provide read, write, and execute permissions, but as far as delete permissions, all that is needed is:
write+execute permission on the parent directory. The permissions of the file itself are irrelevant
Since Windows is really the only system with delete access, and it already provides it's own accessor in the form of CreateFile with FILE_SHARE_DELETE, there really isn't a motivation to standardize this functionality.
If this functionality is pivotal to your program you could implement this cross-platform function (note that depending upon file size this could be very expensive):
Open file for read and write with an fstream; if this fails something else has a lock on the file and it would not be possible to open it for delete
Slurp the file
close the file
remove the file; if this fails you do not have delete permissions on the file
Reopen the file for writing with an ofstream
"Unslurp" the file into the ofstream
Return the ofstream
As long as the returned ofstream is open the operating system is responsible for preventing changes to the permissions on the file or it's containing directories. So by virtue of the fact that you have already deleted the file you know that you can still delete the file upon closing the ofstream.

Refactoring fopen_s

I am attempting to refactor a very old piece of code that generates a log file:
FILE *File = NULL;
errno_t err = fopen_s(&File, m_pApp->LogFilename(), "a+"); // Open log file to append to
if (err == 0)
{
::fprintf(File, "Date,Time,Serial Number,ASIC Voltage,Ink Temp,Heater Temp, Heater Set Point, PSOC Version,");
if (m_ExtraLog)
::fprintf(File, "T1 Temperature,ASIC Temperature,Proc Temperature,Voltage mA");
::fprintf(File, "\n");
fclose(File);
}
The reason for refactoring is that some users report that it is not possible to copy the file that is being produced (they want to copy it so that it can be analysed by a labview program). I read the documentation regarding fopen_s and saw that "Files that are opened by fopen_s and _wfopen_s are not sharable" - is this the cause of my problem? I am unsure because actually, I do not see the copying problem and seem to be able to copy and paste the file without issue. In any case I have replaced it with the recommended _fsopen function like so:
FILE *File = NULL;
if((File = _fsopen(m_pApp->LogFilename(),"a+", _SH_DENYNO))!= NULL)
{
::fprintf(File, "Date,Time,Serial Number,ASIC Voltage,Ink Temp,Heater Temp, Heater Set Point, PSOC Version,");
if(m_ExtraLog)
{
::fprintf(File, "T1 Temperature,ASIC Temperature,Proc Temperature,Voltage mA");
}
::fprintf(File, "\n");
fclose(File);
}
I've given the refactored code to the user but they still report being unable to copy or access the file from labview. I have very limited knowledge of C++ so I am wondering is there any other explanation as to why the file being generated is not able to copied by another process?
Lets have look into doc
Open a file. These are versions of fopen, _wfopen with security enhancements as described in Security Enhancements in the CRT.
Follow by: link
We can read:
Filesystem security. Secure file I/O APIs support secure file access in the default case.
So to fix that, you must change 'file security' to match 'all users/read access'

Saving log text file regardless of crashing

My program saves all kinds of log information into text file. But if the program is crashing due to some problems such as memory access violation, the log text file has nothing in there.
I believe it is because the program failed to close opened log text file.
Currently, I am using FILE* for saving log text files. I probably can open and close every time to write each log but I think that is too much overhead.
Is there any other way that I can keep the log regardless of crashing or unexpected stopping of program?
I do want to see the log right before the program is crashing.
I am using C++/CLI for my program. Thank you very much in advance.
FILE* logfile;
errno_t err;
char LogFileNameBuf[512] = {0,};
sprintf_s(LogFileNameBuf, "LogFile.txt");
err = fopen_s(&logfile, LogFileNameBuf, "wt");
if(logfile != NULL)
{
bLogfile = true;
GetLocalTime(&st);
sprintf_s(logBuf, "[%04d-%02d-%02d][%02d:%02d:%02d] SUCCESS:: Log Started\n", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
fputs(logBuf, logfile);
}
// close log file
if(bLogfile == true)
{
GetLocalTime(&st);
sprintf_s(logBuf, "[%04d-%02d-%02d][%02d:%02d:%02d] SUCCESS:: Log File Closed\n", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
fputs(logBuf, logfile);
fclose(logfile);
}
You can try forcing I/O operation in the file using fflush(). You could do that each time you write in your logs to make sure you have as much data actually written as possible.
Although I would suggest, as you are using C++, using fstream instead of FILE*