How to make open() truncate an existing file - c++

I m opening a file with open() function.
I want that open() function discard the file content if it already exists, and then the file is treated as a new empty file.
I tried with the following code:
int open_file(char *filename)
{
int fd = -1;
fd = open(filename, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
if (fd < 0) {
printf("Couldn't create new file %s: %s\n",
filename, strerror(errno));
return -1;
}
close(fd);
return 0;
}
but I got the following error:
Couldn't create new file kallel333: File exists
What am I missing?

Please add O_TRUNC flag and remove O_EXCL.
open(filename, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
From open man page -
O_EXCL Ensure that this call creates the file: if this flag is
specified in conjunction with O_CREAT, and pathname already
exists, then open() will fail.
O_TRUNC
If the file already exists and is a regular file and the
access mode allows writing (i.e., is O_RDWR or O_WRONLY) it
will be truncated to length

The problem is the O_EXCL flag. From the man page for open(2):
O_EXCL Ensure that this call creates the file: if this flag is specified in conjunction with O_CREAT, and pathname already exists, then open() will fail.
I suggest removing O_EXCL, adding O_TRUNC, and trying again.

The manual page for open() says this about the O_TRUNC flag:
O_TRUNC
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.

As everyone has stated, it's due to using the O_EXCL flag, when it should be the O_TRUNC flag instead. I just had this same issue. My best advice to anyone trying to use these syscalls that involve macros is to read the man page of your syscall. Understand what your macros mean before you try to use them and confuse yourself.
man 2 open

I will tell you what this error is all about ! Open function will have a return type i.e some value will be returned after the execution of this system call (which in your case will be stored in fd). This value will indicate whether the execution of the system call is a success or not. When open system call fails, it automatically returns -1 (to fd) which you are already initializing in the first statement of your function int fd = -1;. Therefore, the statement if (fd < 0) is being validated as correct and hence you are getting that error. Please note that you should not set the return values of the system calls, they are to be returned automatically when the program executes. What you need to do is just make sure you capture that value and validate it. So please change your first statement of the function int fd = -1 to simply int fd.
Bottom line: You are setting the return value of the open system call to -1 thereby telling the compiler that its creation should fail at any cost !! As far as the permissions are concerned, please refer to the other comments !! :)

Related

fstream counterpart to O_RDWR | O_CREAT | O_APPEND [duplicate]

What is the proper set of I/O flags for a std::fstream, where I want to be able to read from and write to the file, without truncating the file if it exists, but creating it if it does not?
I've tried
std::ios::binary | std::ios::in | std::ios::out
std::ios::binary | std::ios::in | std::ios::out | std::ios::ate
but neither of these create the file if it does not already exist.
I don't want std::ios::app, because I also need to be able to seek around the file at will, with both the get and put cursors.
One workaround, I suppose, would be to instantiate an std::ofstream first, then immediately close it and open the stream I really want, but that seems messy if it can be avoided with a single stream object.
At this time, I'm concluding that std::ios::in outright prevents this, and that I must use the workaround.
So:
if (!std::ostream(path.c_str()))
throw std::runtime_error("Could not create/open file");
std::fstream fs(path.c_str(), std::ios::binary | std::ios::in | std::ios::out);
if (!fs)
throw std::runtime_error("Could not open file");
// ... use `fs`
An investigation, from a Linux perspective (though much of this likely applies to other Unices):
At the syscall layer, you want open(O_RDWR | O_CREAT, 0666) (but not O_TRUNC or O_APPEND or a bunch of other flags, though arguably all files should be opened with O_CLOEXEC | O_LARGEFILE, but that's beside the point)
At the libc layer, there is no standard mode string that implies O_CREAT without O_TRUNC. However, you could use open followed by fdopen.
At the C++ library level, there is no standard way to pass the desired flags. However, using implementation-specific classes/functions or third-party libraries, it is possible; see How to construct a c++ fstream from a POSIX file descriptor?
Personally, I tend to do all I/O at the C or even syscall level, since the API is a lot nicer and it's more predictable. For input/output of class instances, I have my own templates.
Taking std::ios::binary as read, the remaining openmode probably you require is:
std::ios::in | std::ios::app
It's effect is as if to open the file with:
std::fopen(filename,"a+")
and the effect of that is:
open or, if it does not exist, create the file for reading and writing
write data at the end of the file.
If you open a file as an std::fstream with this openmode, it is not truncated if it exists. You may
read from the file wherever the fstream's tellg()\tellp() pointer points,
provided there is something there to read, and you can position that pointer
with the stream's seekg()\seekp() for reading. However, all writes will be
appended to the end of the file.
This openmode will therefore fit your bill unless you need to perform writes
into existing data.

How can I open a file for reading & writing, creating it if it does not exist, without truncating it?

What is the proper set of I/O flags for a std::fstream, where I want to be able to read from and write to the file, without truncating the file if it exists, but creating it if it does not?
I've tried
std::ios::binary | std::ios::in | std::ios::out
std::ios::binary | std::ios::in | std::ios::out | std::ios::ate
but neither of these create the file if it does not already exist.
I don't want std::ios::app, because I also need to be able to seek around the file at will, with both the get and put cursors.
One workaround, I suppose, would be to instantiate an std::ofstream first, then immediately close it and open the stream I really want, but that seems messy if it can be avoided with a single stream object.
At this time, I'm concluding that std::ios::in outright prevents this, and that I must use the workaround.
So:
if (!std::ostream(path.c_str()))
throw std::runtime_error("Could not create/open file");
std::fstream fs(path.c_str(), std::ios::binary | std::ios::in | std::ios::out);
if (!fs)
throw std::runtime_error("Could not open file");
// ... use `fs`
An investigation, from a Linux perspective (though much of this likely applies to other Unices):
At the syscall layer, you want open(O_RDWR | O_CREAT, 0666) (but not O_TRUNC or O_APPEND or a bunch of other flags, though arguably all files should be opened with O_CLOEXEC | O_LARGEFILE, but that's beside the point)
At the libc layer, there is no standard mode string that implies O_CREAT without O_TRUNC. However, you could use open followed by fdopen.
At the C++ library level, there is no standard way to pass the desired flags. However, using implementation-specific classes/functions or third-party libraries, it is possible; see How to construct a c++ fstream from a POSIX file descriptor?
Personally, I tend to do all I/O at the C or even syscall level, since the API is a lot nicer and it's more predictable. For input/output of class instances, I have my own templates.
Taking std::ios::binary as read, the remaining openmode probably you require is:
std::ios::in | std::ios::app
It's effect is as if to open the file with:
std::fopen(filename,"a+")
and the effect of that is:
open or, if it does not exist, create the file for reading and writing
write data at the end of the file.
If you open a file as an std::fstream with this openmode, it is not truncated if it exists. You may
read from the file wherever the fstream's tellg()\tellp() pointer points,
provided there is something there to read, and you can position that pointer
with the stream's seekg()\seekp() for reading. However, all writes will be
appended to the end of the file.
This openmode will therefore fit your bill unless you need to perform writes
into existing data.

What mistake am I making if even root cannot delete a lock file created using O_CREAT | O_EXCEL?

We have created a lock file to avoid a race condition. The lockfile is created in /tmp directory, which has the sticky bit set. We are not passing the mode of the file as the optional
third argument during the file creation. And the file is created using fopen function and
int fd = fopen(filename, O_CREAT | O_EXCEL);
We are deleting this lockfile once its use is over. But sometimes the file is not deleted
and it remains in the /tmp folder, blocking the other process and the application remains just active without proceeding further. The lock file is being deleted by sending command to system
and the command used is /usr/bin -rf. What was surprising that neither the file owner nor the root user was able to delete the file after that.
Doing an operation ll lockfile in /tmp folder gave an O/P in permission
section "---x------", which I could not decipher. Changing the permission of
the lockfile with chmod 777 filename through root user id does not work.
And the system has to be rebooted to get the lockfile removed from the /tmp dir.
You say you're creating the file like this:
int fd = fopen(filename, O_CREAT | O_EXCEL);
That does not match the signature of fopen:
FILE *fopen(const char *filename, const char *mode);
So I presume you might actually be using open:
int fd = open(filename, O_CREAT | O_EXCL);
Which is an error because the third argument to open(2) is "mode" and it is mandatory when O_CREAT is used.
Since you are not passing the mode argument, you are invoking undefined behavior, and the mode is probably getting set to some undesired value. Try passing 0666 as the third argument to open(2) and see if that helps.
Meanwhile to fix the problem and delete the file -- as root run this:
chmod 755 /tmp/lockfile
rm /tmp/lockfile

Too many arguments for open()

I'm in the process of open sourcing some code which was written by myself and a few other individuals. In one of the code segments written by one of the other individuals, I am seeing the following:
open(filePath, O_RDONLY | O_CREAT, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
open(filePath, O_WRONLY | O_CREAT, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Some how, this compiled on their system when we needed to execute it. However, on my system, GCC complains that open() is being passed too many arguments (which from my perspective, is accurate, as open only accepts 2 or 3 arguments to my knowledge). I'm also rather confused as to why O_RDONLY | O_CREAT and O_WRONLY | O_CREAT are both being passed in the same call to open.
While I wait to hear back from the other developer, does anyone have an idea as to why there are 4 arguments in this call to open()?
In the POSIX standard, the C interface to open() is declared as:
int open(const char *path, int oflag, ...);
Now, you're only supposed to provide one extra argument, but there's nothing the compiler can do to stop you providing more. If you're compiling with C++, then it could be that you have overloaded declarations of open():
int open(const char *path, int oflag);
int open(const char *path, int oflag, mode_t mode);
This would more accurately reflect what is expected. There are definitely some issues to be resolved implementing that, but it could be done.
So, the compilation probably worked on one machine because it was using the 'official' declaration with variable length argument list. On your system, you seem to be better constrained.
The original code is broken. Fix it. And fix it in the new code.
The people who sent you that code just messed up. Either the second or thrid argument should be removed, depending on what you want to do with the file. For more info, see the man page for open().

C++: File open call fails

I have the following code in one of my library functions that I am calling many times in a loop. After a large number of iterations I find that open returns -1 which it shouldn't have as the previous iterations worked fine. What may be the cause. How can I get more details on the error.?
int mode;
if (fileLen == 0)
mode = O_TRUNC | O_RDWR | O_CREAT;
else
mode = O_RDWR;
myFilDes = open (fName, mode, S_IRUSR | S_IWUSR);
EDIT:After the end of each iteration I am calling a method that library exposes which internally calls close (myFilDes);
perror is the standard function to map errno to string and print it out to stderr:
if (myFilDes == -1)
perror("Unable to open file: ");
man errno / man perror / man strerror for more info.
Are you closing these handles as well? Do you reach a specific number of open calls before it starts failing?
The errno variable should have additional information as to what the failure is. See: http://linux.die.net/man/2/open