Is is possible to get a file descriptor from a file path in C? And if not, what is the standard way of generating a file descriptor in C?
See below for what I'm trying to do with a file descriptor:
char file[] = "/tmp/run"
int file_descriptor = /* fill in code to get file descriptor */
fchmod(file_descriptor, S_IRUSR | S_IWUSR | S_IXUSR)
That's exactly what the POSIX open() function does: It gives you a file descriptor that refers to the path you passed in.
(Note that neither open nor file descriptors in general are part of standard C.)
Related
Why can't I open my file using open method?
this is my source code:
char* dest;
char cwd1[256];
if (getcwd(cwd1, sizeof(cwd1)) == NULL)
perror("getcwd() error\n");
else
dest=cwd1;
char* destPlus=strcat(dest,"/");
char*myPathName =strcat(destPlus,fileName);
printf("the path name1: %s \n",myPathName);
char* outputPathName=myPathName;
int d;
// FILE* fd;
if(append)
d= open(outputPathName, O_WRONLY, O_APPEND | O_CREAT|O_WRONLY|O_TRUNC);
else
d= open(outputPathName, O_WRONLY,O_CREAT|O_WRONLY|O_TRUNC);
if(d<0){
printf("hello, there's an error with your file, plz check it out\n");
return;
}
in this code d will be negative, why?
Note: the path is true I check it, the error Number is 2
Both uses of open are wrong:
if(append)
d= open(outputPathName, O_WRONLY, O_APPEND | O_CREAT|O_WRONLY|O_TRUNC);
else
d= open(outputPathName, O_WRONLY,O_CREAT|O_WRONLY|O_TRUNC);
open() takes three arguments - the const char *path, the int oflag, and the variable argument mode_t mode, which is only used for newly-created files to specify the most-permissive access mode that can be used for the file (as modified by the process's umask setting). mode only needs to be supplied when O_CREAT is set in in the oflag flags variable.
You are misusing both the oflag and mode argument.
A proper use of open() would be something like this:
if(append)
d= open(outputPathName, O_WRONLY|O_CREAT|O_APPEND, 0644 );
else
d= open(outputPathName, O_WRONLY|O_CREAT, 0644 );
Per [POSIX open() documentation](https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/functions/open.htm
SYNOPSIS
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *path, int oflag, ...);
int openat(int fd, const char *path, int oflag, ...);
DESCRIPTION
The open() function shall establish the connection between a file and
a file descriptor. It shall create an open file description that
refers to a file and a file descriptor that refers to that open file
description. The file descriptor is used by other I/O functions to
refer to that file. The path argument points to a pathname naming the
file.
The open() function shall return a file descriptor for the named file,
allocated as described in File Descriptor Allocation. The open file
description is new, and therefore the file descriptor shall not share
it with any other process in the system. The FD_CLOEXEC file
descriptor flag associated with the new file descriptor shall be
cleared unless the O_CLOEXEC flag is set in oflag.
The file offset used to mark the current position within the file
shall be set to the beginning of the file.
The file status flags and file access modes of the open file
description shall be set according to the value of oflag.
Values for oflag are constructed by a bitwise-inclusive OR of flags
from the following list, defined in <fcntl.h>. Applications shall
specify exactly one of the first five values (file access modes) below
in the value of oflag:
O_EXEC Open for execute only (non-directory files). The result is
unspecified if this flag is applied to a directory.
O_RDONLY Open for reading only.
...
O_CREAT If the file exists, this flag has no effect except as noted
under O_EXCL below. Otherwise, if O_DIRECTORY is not set the file
shall be created as a regular file; the user ID of the file shall be
set to the effective user ID of the process; the group ID of the file
shall be set to the group ID of the file's parent directory or to the
effective group ID of the process; and the access permission bits (see
<sys/stat.h>) of the file mode shall be set to the value of the
argument following the oflag argument taken as type mode_t
modified as follows: a bitwise AND is performed on the file-mode bits
and the corresponding bits in the complement of the process' file mode
creation mask. Thus, all bits in the file mode whose corresponding bit
in the file mode creation mask is set are cleared. When bits other
than the file permission bits are set, the effect is unspecified. The
argument following the oflag argument does not affect whether the
file is open for reading, writing, or for both. Implementations shall
provide a way to initialize the file's group ID to the group ID of the
parent directory. Implementations may, but need not, provide an
implementation-defined way to initialize the file's group ID to the
effective group ID of the calling process.
I am new with open function in C. For now to open a file named file I am doing the following :
open("file", O_CREAT|O_RDWR|O_APPEND, S_IRUSR | S_IWUSR)
If the file doesn't exist it does create the file and it gives the right to read the file and to write at the end of it.
Yet the problem is that if the file already exists it doesn't erase its content. What is the option I should use here ?
O_APPEND means you'll be appending to the file if it exists. You should use O_TRUNC instead:
open("file", O_CREAT|O_RDWR|O_TRUNC, S_IRUSR | S_IWUSR)
/* Here ---------------------^ */
If one can use fopen() then the solution is easy:
FILE *fp;
fp = fopen(path, "r");
fseek (fp, 0, SEEK_END);
size = ftell(fp);
if size is zero the file is empty.
However what if the requirement was that fopen() cannot be used. Instead, what I have to use is system calls like open():
int f = open(path, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR );
ftell() can only be used with FILE type streams. I've googled this and could not find any solutions.
It is not a C question (standard C does not know about open) but a Linux or POSIX one.
You don't necessarily need open(2), and you should realize that on Linux some other process could write into a file that you have opened.
Then you might get the size of a file using stat(2) (with the .st_size field) and you could get the size of an opened file descriptor using fstat
You might also use lseek(2) (it could be used both for setting and querying the current file offset of an opened file descriptor).
I'm working on a linux C project and I'm having trouble working with file descriptors.
I have an orphan file descriptor (the file was open()'d then unlink()'d but the fd is still good) that has write-only permission. The original backing file had full permissions (created with S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH), but alas the file was opened with O_WRONLY. Is it possible to duplicate the file descriptor and change the copy to O_RDWR?
psudo-code:
//open orphan file
int fd = open(fname, O_WRONLY, ...)
unlink(fname)
//fd is still good, but I can't read from it
//...
//I want to be able to read from orphan file
int fd2 = dup(fd)
//----change fd2 to read/write???----
Thanks in advance!
-Andrew
No, there is no POSIX function to change the open mode. You will need to open it in read / write mode. Since you are created a temporary file, though, I strongly recommend that you use mkstemp. That function properly opens the file in read/write mode and unlinks it. Most importantly, it avoids a race condition in naming and creating the file, thereby avoiding a vulnerability in the creation of temporary files.
int fd = open(fname, O_WRONLY, ...)
int fd_ro = open(fname, O_RDONLY, ...)
unlink(fname)
{ write to fd }
close (fd);
read or execute(!) fd_ro
Given the following code (it's supposed to write "helloworld" in a "helloworld" file, and then read the text):
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#define FNAME "helloworld"
int main(){
int filedes, nbytes;
char buf[128];
/* Creates a file */
if((filedes=open(FNAME, O_CREAT | O_EXCL | O_WRONLY | O_APPEND,
S_IRUSR | S_IWUSR)) == -1){
write(2, "Error1\n", 7);
}
/* Writes hello world to file */
if(write(filedes, FNAME, 10) != 10)
write(2, "Error2\n", 7);
/* Close file */
close(filedes);
if((filedes = open(FNAME, O_RDONLY))==-1)
write(2, "Error3\n", 7);
/* Prints file contents on screen */
if((nbytes=read(filedes, buf, 128)) == -1)
write(2, "Error4\n", 7);
if(write(1, buf, nbytes) != nbytes)
write(2, "Error5\n", 7);
/* Close file after read */
close(filedes);
return (0);
}
The first time I run the program, the output is:
helloworld
After that every time I to run the program, the output is:
Error1
Error2
helloworld
I don't understand why the text isn't appended, as I've specified the O_APPEND file.
Is it because I've included O_CREAT?
It the file is already created, shouldn't O_CREAT be ignored?
O_EXCL forces the file to be created. If the file already exists, the call fails.
It is used to ensure that the file has to be created, with the given permissions passed in the third parameter. In short, you have these options:
O_CREAT: Create the file with the given permissions if the file doesn't already exist. If the file exists, it is opened and permissions are ignored.
O_CREAT | O_EXCL: Create the file with the given permissions if the file doesn't already exist. If the file exists, it fails. This is useful in order to create lockfiles and guarantee exclusive access to the file (as long as all programs which use that file follow the same protocol).
O_CREAT | O_TRUNC: Create the file with the given permissions if the file doesn't already exist. Otherwise, truncate the file to zero bytes. This has more of the effect we expect when we think "create a new blank file". Still, it keeps the permissions already present in the existing file.
More information from the manual page:
O_EXCL
When used with O_CREAT, if the file
already exists it is an error and
the open() will fail. In this context,
a symbolic link exists, regardless of
where it points to. O_EXCL is broken
on NFS file systems; programs which
rely on it for performing locking
tasks will contain a race condition.
The solution for performing atomic
file locking using a lockfile is to
create a unique file on the same file
system (e.g., incorporating hostname
and pid), use link(2) to make a link
to the lockfile. If link() returns 0,
the lock is successful. Otherwise, use
stat(2) on the unique file to check if
its link count has increased to 2, in
which case the lock is also
successful.