CreateFile CREATE_NEW equivalent on linux - c++

I wrote a method which tries to create a file. However I set the flag CREATE_NEW so it can only create it when it doesnt exist. It looks like this:
for (;;)
{
handle_ = CreateFileA(filePath.c_str(), 0, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_HIDDEN | FILE_FLAG_DELETE_ON_CLOSE, NULL);
if (handle_ != INVALID_HANDLE_VALUE)
break;
boost::this_thread::sleep(boost::posix_time::millisec(10));
}
This works as it should. Now I want to port it to linux and and of course the CreateFile function are only for windows. So I am looking for something equivalent to this but on linux. I already looked at open() but I cant seem to find a flag that works like CREATE_NEW. Does anyone know a solution for this?

Take a look at the open() manpage, the combination of O_CREAT and O_EXCL is what you are looking for.
Example:
mode_t perms = S_IRWXU; // Pick appropriate permissions for the new file.
int fd = open("file", O_CREAT|O_EXCL, perms);
if (fd >= 0) {
// File successfully created.
} else {
// Error occurred. Examine errno to find the reason.
}

fd = open("path/to/file", O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC);
O_CREAT: Creates file if it does not exist. If the file exists, this flag has no effect.
O_EXCL: If O_CREAT and O_EXCL are set, open() will fail if the file exists.
O_RDWR: Open for reading and writing.
Also, creat() is equivalent to open() with flags equal to O_CREAT|O_WRONLY|O_TRUNC.
Check this: http://linux.die.net/man/2/open

This is the correct and working answer:
#include <fcntl2.h> // open
#include <unistd.h> // pwrite
//O_CREAT: Creates file if it does not exist.If the file exists, this flag has no effect.
//O_EXCL : If O_CREAT and O_EXCL are set, open() will fail if the file exists.
//O_RDWR : Open for reading and writing.
int file = open("myfile.txt", O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC);
if (file >= 0) {
// File successfully created.
ssize_t rc = pwrite(file, "your data", sizeof("myfile.txt"), 0);
} else {
// Error occurred. Examine errno to find the reason.
}
I posted this code for another person, inside a comment because his question is closed... but this code is tested by me on Ubuntu and it's working exactly as CreateFileA and WriteFile.
It will create a new file as you are seeking.

Related

google::protobuf::io::GzipOutputStream does not write anything if the file handle is closed at the end

The following code writes to file as expected
int ofd = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0777);
google::protobuf::io::FileOutputStream outp(ofd);
google::protobuf::io::GzipOutputStream fout(&outp);
MyMessage msg;
ConstructMessage(&msg);
CHECK(google::protobuf::util::SerializeDelimitedToZeroCopyStream(msg, &fout));
fout.Close();
// close(ofd);
However if I uncomment the last line // close(ofd);, I get empty file. Why is that?
Also if I skip using the Gzip wrapper, the last line causes no problem. Does this look like a bug?
You should close things in the opposite order of opening:
int ofd = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0777);
google::protobuf::io::FileOutputStream outp(ofd);
google::protobuf::io::GzipOutputStream fout(&outp);
...
fout.Close();
outp.Close();
close(ofd);
With the missing outp.Close();, some data may remain buffered in it. The destructor will eventually flush it out, but at that point the ofd is already closed so there is nothing to write to.

Non blocking pseudo terminal, recovery after POLLHUP

I create a new pseudo-terminal by opening /dev/ptmx with open() function and O_RDWR | O_NOCTTY | O_NONBLOCK flags. Then I use poll() function to wait for incoming data from the remote end:
struct pollfd pollFileDescriptors[numberOfTerminals];
for (unsigned terminalIndex = 0; terminalIndex < numberOfTerminals; terminalIndex++) {
pollFileDescriptors[terminalIndex].fd = terminals[terminalIndex].getFileDescriptor();
pollFileDescriptors[terminalIndex].events = POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND;
}
int ready = poll(pollFileDescriptors, terminals.getNumberOfTerminals(), timeoutMSec);
Everything works like a dream until the remote end closes connection. In such a case the poll() function returns all the time with POLLHUP revents flag. This is by design, however what could I do to make it operating as before i.e. waiting for another process to open and use the pseudo-terminal. I mean it waits, but returns immediately with POLLHUP set. On the other hand, if I close the file descriptor I have no guarantee of receiving the same pseudo-terminal-id that after reopening the /dev/ptmx. Is there any way to remove the POLLHUP revents flag?
I found a similar question: Poll() on Named Pipe returns with POLLHUP constantly and immediately , however I am using already O_RDWR as described there but it doesn't help as in case of named pipes.
The issue can be easily solved by reopening the pseudo-terminal right after it is created. The POLLHUP won't appear as long as at least one writer exists so we can do this by ourselves with open() and ptsname():
// Create a new pseudo terminal
int fileDescriptor = open("/dev/ptmx", O_RDWR | O_NOCTTY | O_NONBLOCK);
grantpt(fileDescriptor);
unlockpt(fileDescriptor);
// Reopen it for write
const char *targetPath = ptsname(fileDescriptor);
int dummyWriterFileDescriptor = open(fileName.c_str(), O_WRONLY | O_NOCTTY | O_NONBLOCK);

Read lines from a file opened with CreateFile [duplicate]

In Unix, if you have a file descriptor (e.g. from a socket, pipe, or inherited from your parent process), you can open a buffered I/O FILE* stream on it with fdopen(3).
Is there an equivalent on Windows for HANDLEs? If you have a HANDLE that was inherited from your parent process (different from stdin, stdout, or stderr) or a pipe from CreatePipe, is it possible to get a buffered FILE* stream from it? MSDN does document _fdopen, but that works with integer file descriptors returned by _open, not generic HANDLEs.
Unfortunately, HANDLEs are completely different beasts from FILE*s and file descriptors. The CRT ultimately handles files in terms of HANDLEs and associates those HANDLEs to a file descriptor. Those file descriptors in turn backs the structure pointer by FILE*.
Fortunately, there is a section on this MSDN page that describes functions that "provide a way to change the representation of the file between a FILE structure, a file descriptor, and a Win32 file handle":
_fdopen, _wfdopen: Associates a stream with a file that was
previously opened for low-level I/O and returns a pointer to the open
stream.
_fileno: Gets the file descriptor associated with a stream.
_get_osfhandle: Return operating-system file handle associated
with existing C run-time file descriptor
_open_osfhandle: Associates C run-time file descriptor with an
existing operating-system file handle.
Looks like what you need is _open_osfhandle followed by _fdopen to obtain a FILE* from a HANDLE.
Here's an example involving HANDLEs obtained from CreateFile(). When I tested it, it shows the first 255 characters of the file "test.txt" and appends " --- Hello World! --- " at the end of the file:
#include <windows.h>
#include <io.h>
#include <fcntl.h>
#include <cstdio>
int main()
{
HANDLE h = CreateFile("test.txt", GENERIC_READ | GENERIC_WRITE, 0, 0,
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if(h != INVALID_HANDLE_VALUE)
{
int fd = _open_osfhandle((intptr_t)h, _O_APPEND | _O_RDONLY);
if(fd != -1)
{
FILE* f = _fdopen(fd, "a+");
if(f != 0)
{
char rbuffer[256];
memset(rbuffer, 0, 256);
fread(rbuffer, 1, 255, f);
printf("read: %s\n", rbuffer);
fseek(f, 0, SEEK_CUR); // Switch from read to write
const char* wbuffer = " --- Hello World! --- \n";
fwrite(wbuffer, 1, strlen(wbuffer), f);
fclose(f); // Also calls _close()
}
else
{
_close(fd); // Also calls CloseHandle()
}
}
else
{
CloseHandle(h);
}
}
}
This should work for pipes as well.
Here is a more elegant way of doing this instead of CreateFile: specify "N" in fopen(). It's a Microsoft-specific extension to fopen, but since this code is platform-specific anyway, it's ok. When called with "N", fopen adds _O_NOINHERIT flag when calling _open internally.
Based on this:
Windows C Run-Time _close(fd) not closing file

Open() syscall filedesriptor

I have to correct the return value of the open() syscall of a posix OS. I understood from the man-Pages that it has to return the file descriptor, and , in case of an error the system call will return -1 and set the errno value. The problem is that I do not know how to get the file descriptor for the opened nod. I checked all the files and didn't found a method that can assign a fd to processes.
Here is the method :
int syscalls::open(const char *path, int oflags, mode_t mode){
syscall_message msg;
msg.call.type = syscalls::open_call;
msg.open_data.path_name = &path[0];
msg.open_data.flags = oflags;
msg.open_data.create_mode = mode;
syscaller::call_system(msg);
return msg.error.number;
}
syscall_message is a struct that holds the data info for the system call. syscalls is the namesapace where all the system calls are. syscaller is used to send the call to the kernel, unsing the call_system method.
The call_system method:
syscalls::open_call:
{
//get the file
i_fs_node_ptr file = i_fs::open_node( msg.open_data.path_name );
//add the file handle
if ( file )
{
cur_process->push_filehandle(
file,
msg.open_data.flags,
msg.open_data.create_mode );
}
else
{
msg.error.type = syscalls::e_no_such_entry;
}
}
I don't know what you mean by "I can't get the file descriptor". As you have mentioned open() returns it. It's simply stored in an integer variable. If this variable is equal to -1, then something has gone wrong. For example if you have
int file = open(path, O_SYNC, O_DIRECT, O_RDONLY);
but you do not have the reading permissions for the file named path the variable file will get a value of -1. Additional manipulation on an opened file can be done via read() (if file was opened in read mode) and write() (if file was opened in write mode). I suggest you read the documentation on the open() function more carefully. If you need more control over the file descriptor I suggest you use fopen():
Discussion on the difference between open() and fopen()
Tutorial on fopen()
Documentation on fopen()

Why does this write() operation just write a single line

I have a small problem with my code in the following. I call it in my class from within a state machine this->write_file(this->d_filename);. The case in the loop gets hit a couple of times, however I only have one line of entries in the CSV file I want to produce.
I'm not sure why this is. I open the file with this->open(filename) in my write function. It returns the file-descriptor. The file is opened with O_TRUNK, and if ((d_new_fp = fdopen(fd, d_is_binary ? "wba" : "w")) == NULL). While the aba refers to write, binary and append. Therefore I expect more than one line.
The fprintf statement writes my data. It also has a \n.
fprintf(d_new_fp, "%s, %d %d\n", this->d_packet, this->d_lqi, this->d_lqi_sample_count);
I simply can't figure out why my file doesn't grow.
Best,
Marius
inline bool
cogra_ieee_802_15_4_sink::open(const char *filename)
{
gruel::scoped_lock guard(d_mutex); // hold mutex for duration of this function
// we use the open system call to get access to the O_LARGEFILE flag.
int fd;
if ((fd = ::open(filename, O_WRONLY | O_CREAT | O_TRUNC | OUR_O_LARGEFILE,
0664)) < 0)
{
perror(filename);
return false;
}
if (d_new_fp)
{ // if we've already got a new one open, close it
fclose(d_new_fp);
d_new_fp = 0;
}
if ((d_new_fp = fdopen(fd, d_is_binary ? "wba" : "w")) == NULL)
{
perror(filename);
::close(fd);
}
d_updated = true;
return d_new_fp != 0;
}
inline void
cogra_ieee_802_15_4_sink::close()
{
gruel::scoped_lock guard(d_mutex); // hold mutex for duration of this function
if (d_new_fp)
{
fclose(d_new_fp);
d_new_fp = 0;
}
d_updated = true;
}
inline void
cogra_ieee_802_15_4_sink::write_file(const char* filename)
{
if (this->open(filename))
{
fprintf(d_new_fp, "%s, %d %d\n", this->d_packet, this->d_lqi,
this->d_lqi_sample_count);
if (true)
{
fprintf(stderr, "Writing file %x\n", this->d_packet);
}
}
}
Description for O_TRUNC from man open:
If the file already exists and is a regular file and the open mode allows writing (i.e., is O_RDWR or O_WRONLY) it will be truncated to length 0. If the file is a FIFO or terminal device file, the O_TRUNC flag is ignored. Otherwise the effect of O_TRUNC is unspecified.
The file is opened in each call to write_file(), removing anything that was previously written. Replace O_TRUNC with O_APPEND.