Retrieving file descriptor from a std::fstream [duplicate] - c++

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++.

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++.

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);

Convert istream to FILE*

Is it possible to convert an istream like std::cin to a FILE *? A cross-platform solution would be a plus.
EX: (FILE *)std::cin.
No, there is no standard way to obtain a FILE* from an IOStreams stream, nor vice versa.
std::cin is usually bound to file descriptor 1 (or in FILE * form, stdin).
You could just use that. Other than that, the only way to do so is either determine the file descriptor (unlikely) or the filename and use fopen to get a FP
There is no easy way using FILE* I would advise you to use fstream instead.
std::ifstream in("in.txt");
std::cin.rdbuf(in.rdbuf());
This way your redirect cin to your input file stream.
Though it is possible that your IOStreams implementation may be implemented using a FILE*, the standard does not provide any way of you accessing this information. However, it is of my knowledge that libstdc++ has a non-standard extension __gnu_cxx::stdio_filebuf, which is a wrapper around a FILE*. You can use its file() method to return a pointer to the file.
Note that this class is non-portable and non-standard. I think you're better off writing your own stream buffer that emulates its behavior.
If you have a GNU userland (just about guaranteed on Linux), take a look at fopencookie(). That allows you to adapt any source / sink to a FILE*.
The linked man-page contains in-depth guidance on how to write the adaptor.

fstream delete N bytes from the end of a binary file

Is it possible to delete N bytes from the end of a binary file in C++ using fstream (or something similar)? I don´t want to read the whole file, cut it and write it again, but since it´s from the end of a file it seems like it shouldn't be such a problem.
I'm not aware of a generic C++ (platform independent) way to do this without writing a new file. However, on POSIX systems (Linux, etc.) you can use the ftruncate() function. On Windows, you can use SetEndOfFile().
This also means you'll need to open the file using the native functions instead of fstream since you need the native descriptor/handle for those functions.
EDIT: If you are able to use the Boost library, it has a resize_file() function in its Filesystem library which would do what you want.
Update:
Now in C++17 you can use resize_file from filesystem
Live on Coliru
In case you want to use Qt, QFile also provides two resize() methods that allow to truncate a file.

C++ substitution of ios::noreplace

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++.