I came across this piece of code and it is not supposed to work according to the author, however, it runs successfully. The author recommends the use of O_CREAT which does the same thing but guarantees atomicity. In my opinion whether two processes are running concurrently or not, the code should still work?
if((fd=open("filename.dat", O_WRONLY) < 0)){
if(errno != ENOENT){
perror("open error");
exit(1);
}
else if((fd=open("filename.dat", O_WRONLY | O_CREAT)) < 0){
perror("creation error");
exit(1);
}
}
Atomicity is provided by the operating system: either the file exists, or it doesn't, however, between the calls to e.g. access() to check for existence and open() to create the file, another process may have created the file. So atomically creating a file must be done in one call:
if ((fd=open("filename.dat", O_WRONLY | O_CREAT | O_EXCL, mode))<0) {
// file exists or other error
O_EXCL results in the call failing when the file exists.
mode is a parameter required with O_CREAT to specify the file's access/sharing permission. The flags differ between Linux and Windows.
Related
I'm trying to create a C code which will create a file for which I can read or write from/to. This file can already exist, or need to be created from scratch. If it already exists within the directory, I want it to created from scratch, in other words delete all the contents.
FD = open("p.txt", O_RDWR | O_CREAT | O_TRUNC);
I've tried using that for the time being. I encounter a problem though. If the file doesn't exist, it creates it and returns a positive file descriptor.
If the file however already exists, a -1 FD is returned. So I must be missing a flag?
I assumed O_TRUNC would be enough to clear the contents of a file?
FD = open("p.txt", O_RDWR | O_CREAT | O_TRUNC, 0644);
When a Unix call returns -1, check the value of the errno variable. It contains the reason for the error. Don't speculate as to what might be the problem until you've seen the error code. You can call strerror or perror to get a message describing the numerical value stored in errno.
Also, as others have noted, when you pass O_CREAT to open, you must pass a third argument which determines the file's permission if it's created. (If you don't )
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
int main() {
int fd = open("p.txt", O_RDWR | O_CREAT | O_TRUNC, 0666);
if (fd == -1) {
perror("opening p.txt");
exit(1);
}
/* … */
}
if((fd = creat(file_name,O_RDWR|S_IRWXU|S_IRWXG|S_IRWXO)) < 0){
perror("Create failed!");
return -1;
}
if((fd = open(file_name,O_CREAT | O_RDWR))< 0){
perror("Open failed!");
return -1;
}
write(fd,buff,100);
Why do the fd's are different for creat and open, as its opening the same file.
I want to create , open and write a file.
I should not use the open(filename,O_CREAT|modes);
The creat function opens the file after creating it, so from your description, simply calling creat() is sufficient for your needs.
To answer your question, it gives you multiple file descriptors because you've performed multiple opens (creat is an open with creation). You can access the same file using both descriptors (and your current location within the file can differ for each descriptor).
Literally creat() function is equivalent to open(pathname, O_RWONLY | O_CREAT | O_TRUNCATE, mode) so your second open() is redundant.
You should also keep in mind that the fd is just a handler of your current process. Different handler may point to the same file as we call it "File Sharing".
Another suggestion is, try
if (write(fd, buff, 100) != 100)
/*Error handling codes*/
to make sure the write() works correctly.
I have 10 processes which try open the same file more or less at the same time using open(O_CREAT) call, then delete it. Is there any robust way to find out which process actually did create the file and which did open already create file, for instance, if I want to accurately count how many times that file was opened in such scenario.
I guess I could put a global mutex on file open operation, and do a sequence of open() calls using O_CREAT and O_EXCL flags, but that doesn't fit my definition of "robust".
Use O_EXCL flag with O_CREAT. This will fail if the file exists and errno will be set to EEXIST. If it does fail
then attempt open again without O_CREAT and without O_EXCL modes.
e.g.
int fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0644);
if ((fd == -1) && (EEXIST == errno))
{
/* open the existing file with write flag */
fd = open(path, O_WRONLY);
}
Based roughly on your comments, you want something along the lines of this function:
/* return the fd or negative on error (check errno);
how is 1 if created, or 0 if opened */
int create_or_open (const char *path, int create_flags, int open_flags,
int *how) {
int fd;
create_flags |= (O_CREAT|O_EXCL);
open_flags &= ~(O_CREAT|O_EXCL);
for (;;) {
*how = 1;
fd = open(path, create_flags);
if (fd >= 0) break;
if (errno != EEXIST) break;
*how = 0;
fd = open(path, open_flags);
if (fd >= 0) break;
if (errno != ENOENT) break;
}
return fd;
}
This solution is not bullet proof. There may be cases (symbolic links maybe?) that would cause it to loop forever. Also, it may live-lock in certain concurrency scenarios. I'll leave resolving such issues as an exercise. :-)
In your edited question, you pose:
I have 10 processes which try open the same file more or less at the same time using open(O_CREAT) call, then delete it.
A hack-ish, but more bullet proof, solution would be to give each process a different user ID. Then, just use the regular open(path, O_CREAT|...) call. You can then query the file with fstat() on the file descriptor, and check the st_uid field of the stat structure. If the field equals the processes' user ID, then it was the creator. Otherwise, it was an opener. This works since each process deletes the file after opening.
I created this file
char *output = "big";
creat(output, O_RDWR);
When I'm trying to read the file
cat big
I'm getting permission denied. Whats wrong with my code? How to create a file with read and write permission mode?
with ls -l, the permission of big looked like this
----------
what does this mean?
You have misinterpeted the mode argument. From the man page:
mode specifies the permissions to use in case a new file is cre‐
ated. This argument must be supplied when O_CREAT is specified
in flags; if O_CREAT is not specified, then mode is ignored.
The effective permissions are modified by the process's umask in
the usual way: The permissions of the created file are
(mode & ~umask). Note that this mode only applies to future
accesses of the newly created file; the open() call that creates
a read-only file may well return a read/write file descriptor.
and also
creat() is equivalent to open() with flags equal to
O_CREAT|O_WRONLY|O_TRUNC.
So, a more appropriate call might look like:
int fd = creat(output, 0644); /*-rw-r--r-- */
If you want to open it O_RDWR though, then just use open():
int fd = open(output, O_CREAT|O_RDWR|O_TRUNC, 0644);
This is obviously a permission issue, start trying to see if creat doesn't returns -1, if so, print the errno value, with perror(""), so that you could resolve the problem.
Imho, i'd rather use open() to do this, because as mentionned in the creat man page,
"Note that open() can open device special files, but creat() cannot create them; ..", and
"creat() is equivalent to open() with flags equals to O_CREAT | O_WRONLY | O_TRUNC", and this doesn't talks about the permissions..
it would be the exact same result if you did this:
char* output = "big";
int fd;
fd = open(output, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
// do whaterver you want to do in your file
close(fd);
For more information, "man 2 open"
I have an open device descriptor, where I don't know the device name and the options
passed to open(...).
I want to open a new device descriptor with the same options passed to open.
int newFd = copy(referenceFd);
Where copy would do the job. dup() is certainly the wrong choice as a further ioctl() on newFd would also alter the referenceFd, therefore I want to open a new descriptor.
Is there a system call which provides such functionality?
I have not been able to find something yet.
You can probably do it with a series of fcntl calls:
F_GETFD - Get the file descriptor flags defined in that are associated with the file descriptor fildes.
F_GETFL - Get the file status flags and file access modes, defined in , for the file description associated with fildes.
I linked the SUSv4 page above; you might also be interested in the Linux version.
First, get the descriptor flags of file descriptor fd using
int flags = fcntl(fd, F_GETFL);
Then, reopen the descriptor using the Linux-specific /proc/self/fd/fd entry:
int newfd;
char buffer[32];
if (snprintf(buffer, sizeof buffer, "/proc/self/fd/%d", fd) < sizeof buffer) {
do {
newfd = open(buffer, flags & ~(O_TRUNC | O_EXCL), 0666);
} while (newfd == -1 && errno == EINTR);
if (newfd == -1) {
/* Error: Cannot reopen file. Error in errno. */
}
} else {
/* Error: the path does not fit in the buffer. */
}
The reopened file descriptor is then in newfd.
Note that you most likely want to make sure O_TRUNC (truncate the file) and O_EXCL (fail if exists) are not in the flags, to avoid the cases where reopening using the exact original flags would cause unwanted results.
You do not want to use lstat(), because that opens up a race condition with respect to rename -- a user renaming the target file between the lstat() and the open() in above code. The above avoids that completely.
If you don't want to be Linux-specific, add code that tries the same with /dev/fd/fd if the above fails. It is supported in some Unix systems (and most Linux distros too).