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().
Related
I wanted to give the permission of read to group and others, while read and write permission to Owner in Linux and Windows platform. Linux has macros S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH to do that. Does windows also have some macros as these or any other alternative?
I went through https://learn.microsoft.com/en-us/cpp/c-runtime-library/file-permission-constants?view=vs-2019. _S_IREAD seem to be one option. But it just says "Reading permitted". Not sure whether it will full fill my requirement
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 !! :)
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 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.
I want to create a file using c++ in linux with particular file permissions(1644).I know i can achieve this with chmod but I want to do it programatically via c++.
Is this possible?Kindly help.
Thanks.
Use stat(2) to retrieve the permissions, then use chmod(2) to change them.
More generally, to understand what syscalls are done by some (command-line) program (e.g. /bin/chmod...), use strace(1)....
You need to use struct stat in sys/stat.h
man 2 stat to see the various st_mode field values.
You can use the chmod function from sys/stat.h:
int chmod(const char *path, mode_t mode);
So something like:
#include <sys/stat.h>
...
if (!chmod("/tmp/testfile",
S_ISVTX | // Sticky bit
S_IRUSR | // User read
S_IWUSR | // User write
S_IRGRP | // Group read
S_IROTH // Other read
))
{
// Handle error case
}