If I open the same file twice, will it give an error, or will it create two different file descriptors? For example
a = open("teste.txt", O_RDONLY);
b = open("teste.txt", O_RDONLY);
To complement what #Drew McGowen has said,
In fact, in this case, when you call open() twice on the same file, you get two different file descriptors pointing to the same file (same physical file). BUT, the two file descriptors are indepedent in that they point to two different open file descriptions(an open file description is an entry in the system-wide table of open files).
So read operations performed later on the two file descriptors are independent, you call read() to read one byte from the first descriptor, then you call again read()on the second file descriptor, since thier offsets are not shared, both read the same thing.
#include <fcntl.h>
int main()
{
// have kernel open two connection to file alphabet.txt which contains letters from a to z
int fd1 = open("alphabet.txt",O_RDONLY);
int fd2 = open("alphabet.txt",O_RDONLY);
// read a char & write it to stdout alternately from connections fs1 & fd2
while(1)
{
char c;
if (read(fd1,&c,1) != 1) break;
write(1,&c,1);
if (read(fd2,&c,1) != 1) break;
write(1,&c,1);
}
return 0;
}
This will output aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz
See here for details, especially the examples programs at the end.
In this case, since you're opening both files as read-only, you will get two different file descriptors that refer to the same file. See the man page for open for more details.
It will create a new entry in the file descriptor table and the file table. But both the entries (old and new) in the file table will point to the same entry in the inode table.
Related
Somewhere online I've seen a technique to immediately unlink a temporary file after opening it, since you will discard it anyway. As per my understanding of the man-page for unlink, the file will not be unlinked as long as it has an open file descriptor.
When I execute the following piece of code:
char *file, *command;
asprintf(&file, "/tmp/tempXXXXXX");
int fd = mkstemp(file);
unlink(file);
asprintf(&command, "some_command > %s", file); /*Writes n bytes in temp file*/
FILE *f = popen(command, "re");
pclose(f);
struct stat sbuf;
fstat(fd, &sbuf);
printf("%i\n", sbuf.st_size);
close(fd);
free(file);
free(command);
exit(0);
It will print a size of 0. However, if I comment unlink(file), it will show the correct file size. I would expect both scenarios to show the correct size of the file, since unlink should wait till no processes have the file open anymore. What am I missing here?
You're missing the fact that the file referred to by your fd is not the same file as that created by your call to popen().
In a POSIX-like shell, some_command > some_file will create some_file if it does not already exist, otherwise it will truncate some_file.
Your call to popen() invokes a shell, which in turn creates or truncates the output file before invoking some_command as per POSIX.
Since you have unlinked some_file before the call to popen(), the file is created anew: that is, the output file set up by your popen() shell is allocated under a different inode than the (now anonymous) file created by your previous call to mkstemp().
You can see that the files are different if you compare st_ino values from your fstat() (by fd) and a separate call to stat() (by name) after the popen().
In my code, I create a file with a random name using mkstemp() function (Im on Linux). What this function returns is an int being a file descriptor.
int fd;
char temp[] = "tempXXXXXX";
fd = mkstemp(temp);
Later I can access the file using fdopen() through that int file descriptor.
FILE *file_ptr = NULL;
file_ptr = fdopen(fd);
But at the end of my program, I would like to see if the file still exists with the random name it was given when I created it (the program should change that file name if successful). I can set a flag if the rename() function run on that file is successful, but I still don't know how to delete it when I only have its file descriptor.
if rename files => remove the temp file
How can I do that? Or is there a way to get the files name if I have its file descriptor?
Neither C nor POSIX (since you are using POSIX library functions) defines a way to delete a file via an open file descriptor. And that makes sense, because the kind of deletion you're talking about is actually to remove a directory entry, not the file itself. The same file can be hard linked into the directory tree in multiple places, with multiple names. The OS takes care of removing its data from storage, or at least marking it as available for reuse, after the last hard link to it is removed from the directory tree and no process any longer has it open.
A file descriptor is associated directly with a file, not with any particular path, notwithstanding the fact that under many circumstances, you obtain one via a path. This has several consequences, among them that once a process opens a file, that file cannot be pulled out from under it by manipulating the directory tree. And that is the basis for one of the standard approaches to your problem: unlink (delete) it immediately after opening it, before losing its name. Example:
#include <stdlib.h>
#include <unistd.h>
int make_temp_file() {
char filename[] = "my_temp_file_XXXXXX";
int fd;
fd = mkstemp(filename);
if (fd == -1) {
// handle failure to open ...
} else {
// file successfully opened, now unlink it
int result = unlink(filename);
// ... check for and handle error conditions ...
}
return fd;
}
Not only does that (nearly) ensure that the temp file does not outlive the need for it, but it also prevents the contents from being accessible to users and processes to which the owning process does not explicitly grant access.
Even though this doesn't exactly answer the question you're asking about mkstemp, consider creating a temporary file that will automatically be deleted, unless you rename it.
Instead of mkstemp you could call open combined with the creation flag O_TMPFILE to create a temporary, unnamed file that is automatically deleted when file is closed.
See open(2):
O_TMPFILE (since Linux 3.11)
Create an unnamed temporary regular file. The pathname argu‐
ment specifies a directory; an unnamed inode will be created
in that directory's filesystem. Anything written to the
resulting file will be lost when the last file descriptor is
closed, unless the file is given a name.
Instead of a filename, you call open with the path where you prefer to place the temporary file, like:
temp_fd = open("/path/to/dir", O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR);
If you like to give the temporary file a permanent location/name, you can call linkat on it later:
linkat(temp_fd, NULL, AT_FDCWD, "/path/for/file", AT_EMPTY_PATH);
Note: Filesystem support is required for O_TMPFILE, but mainstream Linux filesystems do support it.
readlink provide you the name of your file depending of the file descriptor if you use the path /proc/self/fd/ adding you fd.
Then use remove for deleting the file passing the name readlink gave you
ssize_t readlink(const char *path, char *buf, size_t bufsiz); (also load ernno)
int remove(const char *filename); (returns zero is successful, otherwise nonzero)
I hope something like that could helped you ?
⚠ Don't copy/past this you must edit "filename"; _BUFFER, _BUFSIZE ⚠
#include<stdio.h>
#include <unistd.h>
#include <stdlib.h>
int delete_file(int fd) {
char *str_fd = itoa(fd, str_fd, 10);
char *path = strcat("/proc/self/fd/", str_fd);
if (read_link(path, buffer, bufsize) == -1)
return -1;
int del = remove(filename);
if (!del)
printf("The file is Deleted successfully");
else
printf("The file is not Deleted");
return 0;
}
(feel free to edit this, i didn't test the code and i let you handel the buffer and buffer size)
I have two child processes they share their parent's common pipe descriptors. There is no problem for closing ends etc. The problem is I wish to redirect pipe's read end to a file descriptor instead of holding a buffer and writing the buffer's content to a file. Is it possible? My code snippet as follow
// we're sure we can read from fd[0], I did it sucessfully
// I mean there is no problem about the communication
int open_fd = open(filename, O_WRONLY|O_CREAT, 0666);
if (dup2(open_fd,fd[0]) == -1) {
perror("error ");
return 1;
}
if (close(open_fd) == -1) {
perror("close error");
return 1;
}
When I did the above code, I doesn't write into the file called as filename. By the way, is there a need to close open_fd by calling close(open_fd)? Since dup2 closes it already.
You've probably misunderstood the purpose of dup2. It just changes "the meaning" of the file descriptor, so that it now "points" to the same stream as the other descriptor. But it doesn't in any way transfer data from one file descriptor to another. To actually achieve what you want you can try splice:
int open_fd = open(filename, O_WRONLY|O_CREAT, 0666);
splice(fd[0], NULL, open_fd, NULL, size, 0);
Note that you'll have to specify how much data you want to transfer (size variable in above example).
When I did the above code, I doesn't write into the file called as filename.
Of course not. When you call dup2(open_fd,fd[0]), you make the integer value stored in fd[0] refer to the same file that open_fd does, but that has to has nothing directly to do with what happens to bytes fed into the write end of the pipe. It affects them only indirectly, by causing the file descriptor number whose value was initially stored in fd[0] to first be closed if it is open.
A file descriptor is basically a key to a table mapping integers to open file descriptions in the kernel. dup2() changes what open file description the target FD is mapped to; it does not modify the open file description itself or affect its semantics, and it's at that level where the pipe lives.
Bytes written to the write end of a pipe are obtained from the read end of the pipe by reading it. However you do that, they initially reside in memory and / or in CPU registers. To make them go from there to a file, you need to send them there. For example, you might set up a thread whose purpose is to read whatever bytes are available from the pipe, and then writes them to your file.
As it seems, it is possible to use openat() to reopen an already opened directory. For instance on my Linux system I can do the following:
#define _GNU_SOURCE
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main(void) {
int fd1 = open(".", O_PATH);
if (fd1 == -1) {
perror("open");
return 1;
}
int fd2 = openat(fd1, ".", O_RDONLY);
if (fd2 == -1) {
perror("openat");
close(fd1);
return 1;
}
close(fd1);
// do fancy things with fd2, now opened
// with access mode read-only
return 0;
}
I could not find this documented anywhere and it feels a bit like an edge case. Also I didn't find other code doing this. Is this well-defined behavior?
EDIT: changed the title: file -> directory
This is just the same as calling open twice on the same file, which you are allowed to do:
int fd1 = open("filename", flags1);
int fd2 = open("filename", flags2);
where filename refers to an existing file (of any type) and flags1 and flags2 are any set of O_ flags that can be validly applied to that type of file and won't destroy its contents. (In particular, we assume that they do not include O_CREAT, O_TRUNC, or O_EXCL.)
fd1 and fd2 will refer to separate "open file descriptions", so for instance lseek on one will not affect the other, flock on one will block flock on the other, etc.
With openat(), the first argument, fd, should be the file descriptor for a directory — such as the one you obtained from opening "." — or the special value AT_FDCWD (which means open relative paths relative the current directory). Note that the O_PATH option you use is a Linux-only extension to openat().
So, because you're using a valid file descriptor for a directory, the call to openat() should succeed. You now have two file descriptors both pointing (independently — with separate open file descriptions) to the current directory. In general, it is possible to open the same file multiple times in a single process (or in multiple processes — ensuring access by a single process is actually very hard on Unix-like (POSIX) systems).
There isn't a lot else you can do with those descriptors other than use them in *at() system calls. Either of the file descriptors would have been sufficient; opening both was overkill.
I've got 2 programs, and in one i'm opening a file to read and from the other one i'm trying to read from file :
first program
fd = open("test.txt",O_RDONLY);
printf("%d\n",fd);
while(1);
second program :
char sir[100];
int fd, result;
scanf("%d",&fd);
rez = read(fd,((void*)sir), 2);
In the second program i read what i printed in first program. Why this code doesn't work and how can i read from that file descriptor from program nr 2?
File descriptors are unique to the process. Also you need to write to the file descriptor.
There are several problems:
fd = open("test.txt", O_RDONLY) opens the file for reading. If I understand what you are trying to do, you want to create the file and open it for writing. That would be fd = open("test.txt", O_CREAT | O_WRONLY).
printf("%d\n",fd) displays the value of the file handle. While that might be useful for debugging, I think you want something which writes to the file handle. write (fd, "hello", 5) is closer to that.
while(1); is an infinite CPU busy loop. This is not very useful.
Similarly the second program has issues:
fd = scanf("%d",&fd) is peculiar. I think you want to open the file just written, no? Instead, fd = open("test.txt", O_RDONLY).
With that corrected, the program can then read the content into the variable read (fd, sir, sizeof sir).
See if those help you.
If you are not primarily working with binary data in the files, the fopen() and fprintf() library calls are more convenient.