C++ substitution of ios::noreplace - c++

I'm using fstream to open a file for write. I don't want to overwrite an existing file so after some searching, I found ios::noreplace. But when I compile this:
#include <fstream>
using namespace std;
//......Did something else.
ofstream fout;
fout.open(outputFile,ios::noreplace);//outputFile is a C string
I get an error
error: ‘noreplace’ is not a member of ‘std::ios’
I'm just wondering is there any std:: subsitution for ios::noreplace?

Some searching on the internet reveals that you can add an existence check manually by attempting to open in "input" mode:
std::fstream myfile("thefile.txt", std::ios::in);
if (myfile)
{
// error, file exists!
}
else
{
myfile.close();
myfile.open("thefile.txt", std::ios::out); // OK now
}

noreplace never got into the standard. About four seconds of googling yields:
http://www.devx.com/tips/Tip/14544
In pre-standard C++, certain implementations of offered the flags ios::nocreate and ios::noreplace for controlling file creation. These flags were too platform-specific and never made it into the standard library, which supersedes the deprecated, pre-standard header. However, you can achieve the functionality of these obsolete flags rather easily.
fstream fs(fname, ios_base::in);// attempt open for read
if (!fs)
{
// file doesn't exist; create a new one
fs.open(fname, ios_base::out);
}
else //ok, file exists; close and reopen in write mode
{
// Should throw an error
}

The suggested answers are risky since they have race conditions.
Unless you can guarantee nobody will ever create that file while your are running this test, you should not use it.
As a workaround, use the non-portable method (on Linux for example open with O_CREAT|O_EXCL).
You can either use the resulting handle with code like boost to wrap it into an ofstream, or in this case use open() only to check and then create a new ofstream on the file (the latter assumes nobody deletes/renames the file in-between and thus might still have a race condition).
C++ not providing ANY safe way to create a file is a bad joke and likely the cause of quite a few security holes. You have to love standards that encourage bad practices by making writing correct code impossible.

The complaints are addressed! C++23 finally standardises the std::ios_base::noreplace flag to open a file for writing in exclusive mode, i.e. to fail if that file already exists.
Paper: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2467r1.html
Common standard library implementations are already supporting this in C++23 mode, including libstdc++ as bundled with GCC/g++.

Related

Can std::ifstream get a file's unique identification [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Getting a FILE* from a std::fstream
I am working on Linux and file descriptors are the main model in this OS.
I was wondering whether is there any library or any way to retrieve the native Linux file descriptor starting from a C++ std::fstream.
I thought about boost::iostream since there is a class called file_descriptor but I understood that its purpose is different from the one I want to achieve.
Do you know some way to do that?
You can go the other way: implement your own stream buffer that wraps a file descriptor and then use it with iostream instead of fstream. Using Boost.Iostreams can make the task easier.
Non-portable gcc solution is:
#include <ext/stdio_filebuf.h>
{
int fd = ...;
__gnu_cxx::stdio_filebuf<char> fd_file_buf{fd, std::ios_base::out | std::ios_base::binary};
std::ostream fd_stream{&fd_file_buf};
// Write into fd_stream.
// ...
// Flushes the stream and closes fd at scope exit.
}
There is no (standard) way to extract the file number from an std::fstream since the standard library does not mandate how file streams will be implemented.
Rather, you need to use the C file API if you want to do this (using FILE*).
There is no official way to get the private file handle of a file stream (or actualy a std::basic_filebuf), just because it should be portable and discourage use of platform-specific functions.
However, you can do ugly hack like inheriting std::basic_filebuf and from that try to pry out the file handle. It's not something I recommend though as it will probably break on different versions of the C++ library.
There is no support of exposing file descriptor neither in standard C++ nor in libstdc++.

C++ open file for writing only if does not exists

I would like to open a file for writing with the standard library, but the file open should fail if the file already exists.
From what I can read in the documentation, ofstream::open only allows appending or truncating.
I could of course try to open for reading to check if the file exists, and reopen for writing if it doesn't, but there is no guarantee that the file will not be created by another process inbetween.
Could someone confirm this is not possible in C++ with the standard library (std::iostream) or with the C functions (FILE* functions)
Since C11 (and thus also in C++17), for fopen you can use mode "x" — exclusive mode, see this:
File access mode flag "x" can optionally be appended to "w" or "w+"
specifiers. This flag forces the function to fail if the file exists,
instead of overwriting it.
There are no fstream ways of doing this, but std::fopen is as much C++ as std::sin.
If you absolutely must have an fstream object of this file and you need the atomic check, you should first call fopen then on success, fclose and fstream::open:
std::ofstream create_new_file_for_writing()
{
FILE* fp = nullptr;
std::string fname;
do {
fname = random_file_name();
fp = fopen(fname.c_str(), "wx");
} while(!fp);
// here the file is created and you "own" the filename
fclose(fp);
return std::ostream(fname);
}
In std::ofstream by itself, no. Opening a file for writing always creates a new file if it does not already exist. There is no option to change that behavior. Opening a file for reading fails if the file does not exist.
However, on Windows at least, the Win32 API CreateFile() function has a CREATE_NEW flag that fails to open the file if it already exists. On other platforms, there may be flags available for _fsopen() and fopen() do accomplish the same thing.
It is possible to attach a FILE* to a std::ofstream (or maybe this is just a Microsoft extension, I am not sure), and in Visual C++ a FILE* can be created for a HANDLE returned by CreateFile() by using _open_osfhandle() with _fdopen(). See this question for examples:
Can I use CreateFile, but force the handle into a std::ofstream?
Other compilers/platforms may provide similar extensions for initializing an std::ofstream, you will have to look around.

C++ Catch if the file was removed

I have some basic code that runs in a loop and writes to file. It looks along the lines of:
std::ofstream myFile;
myFile.open("file.txt", std::ofstream::out);
while (true)
{
if (myFile.is_open() && myFile.good())
{
myFile << "test" <<std::endl;
}
if (myFile.fail())
{
std::cout << "Error\n";
}
}
Everything works fine and errors if I manually insert a myFile.setstate() and set it to fail.
However, if I have the program writing to a file in a loop and then I manually go ahead and delete the file... The program appears to continue writing to file as if it still exists. No error is thrown. I thought maybe using flush() would work since I expected it to set the failbit, but the behaviour didn't seem to change. What am I doing wrong?
Is there a way to check if the file suddenly went missing, without resorting to trying to call open() again? (I'm trying to avoid .open() and .close() in a loop. Rather open at start, and then have it closed when it goes out of scope.)
I don't believe there's a portable way to do this. Many operating systems are designed so that if you delete a file that's being written to, the file appears deleted but still exists until the last program writing to it closes. Others don't even let you delete files that are being written to at all. The C++ standard doesn't have any guarantees about what should happen in this case, so I think you'll need to use a platform-specific API to test for whether the file still exists as you're writing to it.
C++17 has std::filesystem that includes an exists method. Or you can use boost::filesystem with an older compiler.
#ifdef __cpp_lib_filesystem
#include <filesystem>
namespace FS = std::filesystem;
#else
#include <boost/filesystem.hpp>
namespace FS = boost::filesystem;
#endif
At the start of your loop:
if(myFile.is_open() && !FS::exists("file.txt"))
{
myFile.close();
myFile.open("file.txt", std::ofstream::out | std::ofstream::app);
}
boost::filesystem::exists uses ::stat() which according to https://stackoverflow.com/a/12774387/69231 takes just over a 1 microsecond, so is not likely to cause much impact on speed.

Safe use of std::tmpnam

so I am developing an application, which requires to create a file, write into it, call another program with that file is an input, and delete the file.
I looked for possible solution and one solution looks like this.
std::FILE* tmpf = std::tmpfile();
std::fputs("Hello, world", tmpf);
According to the documentation of std::tmpfile, if either the file is closed manually, or the program exits in natural way, the file will be deleted. This looks like good solution with one exception. It looks messy (using C I/O, instead of C++ streams).
Another solution would be to use std::tmpnam, which will generate unique file name.
std::string file_name = std::tmpname(NULL);
// (*)
std::fstream stream{file_name};
stream << "Hello World" << std::endl;
But there is a problem with this one too. If another program creates file with the same name, while my program is in (*), we will both be doing operations on same file, which is certainly something I'd like to avoid.
C++ STL (still) does not support file system operations, like checking if file exists. I could use something like stat to check that, but since checking for file and creating it is not atomic, it would not solve anything. And I did not find C++ STL method of atomic operation, which would: Check if file exists, if not, open it, if yes, fail.
So, my question is, what is the right way of solving this problem? Did I miss something?
Your specification "...create a file, write into it, call another program with that file is an input, and delete the file." is incompatible with tmpfile(). For one thing, there is no (portable) way to get the file name from the FILE pointer you get from tmpfile(), secondly on POSIX platforms tmpfile() will typically delete the file from the directory before returning from tmpfile() (if you're unfamiliar with POSIX filesystem semantics, the file exists as long as your process has an open file descriptor to it even after it's deleted from the directory, meaning there is no way to access it from the filesystem).
Given that, you'll have to use some kind of tmpname() type approach, and figure out a way to prevent two processes from simultaneously accessing it (file locks, check link count with stat(), or such).
Or better yet, don't use files for interprocess communication. For the simplest possible(?) case, create a pipe in the parent, connect it to stdin of the child.
Here is my almost not messy solution:
#include <cstdio>
#include <iostream>
#include <string>
#include <ext/stdio_filebuf.h> // libstdc++ specific
int main()
{
__gnu_cxx::stdio_filebuf<char> tmpfile_buf{std::tmpfile(), std::ios::in | std::ios::out | std::ios::binary};
std::iostream tmpstream{&tmpfile_buf};
// write in stream
tmpstream << "Hello World" << std::endl;
tmpstream.seekg(0);
// read from stream
std::string str;
std::getline(tmpstream, str);
std::cout << str << std::endl;
}
Live example
std::tmpfile() is used and a stream is build from a buffer having an underlying FILE*. This is a GNU extension and thus not portable :(.
I may have a Boost solution to suggest, but I can't test it here.
With a FILE* returned from std::tmpfile(), one can get a file descriptor:
#include <cstdio>
FILE* const tmpfile = std::tmpfile();
const int fd = ::fileno(tmpfile);
and at this stage, everything looks good to use boost::iostreams::file_descriptor_source:
#include <boost/iostreams/code_converter.hpp>
#include <boost/iostreams/maped_file.hpp>
file_descriptor_source tmpstream(fd, boost::iostreams::close_handle);

how a single file can be linked to two different streams at same time?

ifstream fin("test.txt");
ofstream fout ("test.txt");
The above 2 lines, if written in the same programme, does not produce any error or warning.
But how can we write and read into a same file at same time.
How does this works?
So, as comments say, the compiler as such doesn't REALLY know what you are trying to achieve (and there are certainly cases where you'd actually want to something similar to this, for example):
// With exceptions for file operations enabled:
try
{
ifstream fin("test.txt");
return true;
}
catch(...)
{
try
{
ofstream fout("test.txt");
}
catch(...)
{
cout << "Can't create file";
return false;
}
return true;
}
Now, that will (in a rather stupid and complicated way) check if the file exists or can be created. Would you like the compiler to complain about that too? The compiler would have to "understand" a lot of logic to follow when which file is used when, and see that both can't be used at the same (and yes, the compiler probably DOES understand that in this case, since we have a return immediately after the fin use - make the code a bit more complicated, and it won't).
Now, you can't read/write into the same file with the code:
ifstream fin("test.txt");
ofstream fout ("test.txt");
Depending on the OS (and the flags used in the layer below), you may be able to actually execute both of those lines without error - in Unix, files that are open remain open in the system, even if something else removes the file (which the second line will do), so you can read the "old" file, and write to a new one. That is of course not "read and write the same file at the same time", but reading one file and writing to another. And in most non-Unix filesystems, this will not work, since the OS will use the same directory entry for both calls, and open the existing file, then the second call will either make the file empty or fail (depending on what OS, and such).
The solution, if you really want to read and write the same file is to either:
use ios_base::in|ios_base::out as flags when you open the file.
use a temporary file for the output side, and rename the file when it's "done". Since most types of changes to text-files require that the file is "rewritten" [except for adding things to the end], this is often the preferred method. Then when the changes are done, rename the new file to the old one (with a remove of the original one first). This also means you always have at least one complete file (albeit with the wrong name) even if your program crashes.
Nothing in the C++ Standard precludes this - the request is just passed through to the Operating System, which may or may not allow it.
For example, on some OS/filesystems combinations if you go to create a file with the same name as an existing file, the OS hides the existing file's directory entry/entries so other apps can't open it, but existing processes that are using it will be able to continue to do so; when they all close the file will be deleted. Meanwhile, a new file can be created with the same name, and after that any apps opening the file will see whatever's been flushed to that new file.
On other systems, some kind of "in use" or "locked" error message may be generated, leading to a fail/bad state in the std::ofstream.
You should always test the success of file stream creation, e.g.:
if (std::ifstream in("filename.txt"))
...use in...
else
std::cerr << ... or throw std::runtime_error(...)
There is no reason how compiler can understand that you are doing something wrong, it will not remember all filenames you have ever used in your program. Moreover, if the filenames come from user input or simply from a variable, the compiler can never guess that they will be identical:
ifstream fin(s1);
ofstream fout (s2); // is s1==s2?
In fact, your case (hard-coded file name) is very unusual situation, so I do not think such a warning can be useful in a general case.
And, in addition to this all, this code can sometimes even work correctly.
For example, if test.txt is a named pipe, than you can safely open it simultaneously both for reading and writing. You will still have to do some workaround to prevent blocking, a simplest approach will be to open the pipe in different threads. But you can safely imagine an situation where named pipe operations will not block (I do not know whether this is possible in popular OSes by some OS option etc., but anyway you can always imagine such an OS), in such a case the following code should work without any problem:
// (for imaginary OS where named pipe operations do not block)
ifstream fin("test.fifo");
ofstream fout("test.fifo");
fout << 42;
int x;
fin >> x; // produces 42
So there is no reason for a compiler to warn or give an error. If you want to check in runtime whether the file open was successful, just check it.