Why can't I open my file using open method? - c

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.

Related

How to delete a file in C using a file-descriptor?

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)

reopen a directory using openat

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.

C open() function fails. Are my parameters wrong?

This function fails to open the file. Are my parameters wrong or what could be causing this problem?
int CreateFile(const char *filename){
char filepath[strlen(filename) + 3];
sprintf(filepath, "./%s", filename);
int fd = open(filepath, O_CREAT, O_APPEND, S_IWGRP);
if(fd == -1) printf("file read failed\n");
return fd;
}
Xcode prints only "file read failed" to the console. I tried to run this via Terminal aswell but that didn't help either.
I fixed an issue pointed by NetMage:
int CreateFile(const char *filename){
char filepath[strlen(filename) + 3];
sprintf(filepath, "./%s", filename);
int fd = open(filepath, O_CREAT|O_APPEND, S_IWGRP);
if(fd == -1) printf("file read failed\n");
return fd;
}
Unfortunately that didn't fix the issue
Step 1 - Verify that filepath is being set correctly, either by printing it to the terminal or examining it in a debugger.
Step 2 - Verify that the file exists in that path, and that its permissions are set so that you can open it. If filepath is "./foo", then a file named foo had better exist in the current working directory (the directory from which you ran the program), and it needs to have at least read permission.
Step 3 - If the file does not exist, verify that you have permission to create new files in the current working directory.
Step 4 - If after doing all of that you still get an error, check errno. It will give you some additional information beyond "it didn't work."
#include <errno.h>
...
if(fd == -1)
{
switch( errno )
{
case EACCESS: // permission issues
handle_permission_issue();
break;
case EEXIST: // file already exists and you used O_CREAT and O_EXCL
handle_already_exists_issue();
break;
case EFAULT: // bad path
handle_bad_path_issue()
break;
...
}
printf("file read failed\n");
}
NetMage has pointed out one problem - your flags need to be bitwise-OR'd together, rather than listed as separate arguments. Surprised the compiler didn't yell at you over that.
The open function takes only one parameter for oflags, which must be bit-ored together:
#include <errno.h>
#include <string.h>
int fd = open(filepath, O_CREAT|O_APPEND, S_IWGRP);
if (fd == -1) printf("file read failed: %s\n", strerror(errno));
Per the POSIX documentation for open() (somewhat reformatted, and note the bolded text):
SYNOPSIS
#include <sys/stat.h> #include <fcntl.h>
int open(const char *path, int oflag, ...);
...
Values for oflag are constructed by a bitwise-inclusive OR of flags
from the following list, defined in . 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_RDWR
Open for reading and writing. The result is undefined if this flag is applied to a FIFO.
O_SEARCH
Open directory for search only. The result is unspecified if this flag is applied to a non-directory file.
O_WRONLY
Open for writing only.
...
You need to include at least one of those five flags, perhaps like:
int fd = open(filepath, O_WRONLY|O_CREAT|O_APPEND, S_IWGRP);
Note that other failures may still occur. As noted in the comments, you're prepending "./" to the file name, which may cause problems if, for example, you get passed "/tmp/filename" and the tmp directory doesn't exist in your current working directory, as open() will not create missing directories in any path.

open file with O_CREAT|O_RDWR will cause the file to be write only

In my c code I write to afile using open() with option O_CREAT|O_RDWR and then write():
readfd = open("ak.bin", O_CREAT|O_RDWR);
if (readfd >= 0) {
res = write(readfd, key, 16);
close(readfd);
}
after executing my program I found that the file "ak.bin" is with write permission only. I can not read it!
$ ls -l | grep ak
-----w---- 1 mohamed mohamed 16 Jun 3 18:30 ak.bin
What I m missing? I want my file to be readeable also.
You should specify the mode when creating (O_CREAT) the file.
From man open(2):
The mode argument specifies the file mode bits be applied when a new
file is created. This argument must be supplied when O_CREAT or
O_TMPFILE is specified in flags; if neither O_CREAT nor O_TMPFILE is specified, then mode is ignored. The
effective mode is modified by the process's umask in the usual
way: in the absence of a default ACL, the mode of the created
file is (mode & ~umask). Note that this mode applies only 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.

create file and assign permissions

It seems as though whatever I put as PERMS the file created has the same permissions - rwx r-x r-x
I tried 755 and 777 and the permissions just stay the same.
#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<unistd.h>
#include<sys/stat.h>
#define PERMS 0777
int main(int argc, char *argv[])
{
int createDescriptor;
char fileName[15]="Filename.txt";
if ((createDescriptor = creat(fileName, PERMS )) == -1)
{
printf("Error creating %s", fileName);
exit(EXIT_FAILURE);
}
if((close(createDescriptor))==-1)
{
write(2, "Error closing file.\n", 19);
}
return 0;
}
I think you might need to change the umask before calling creat:
umask(0000);
See man 2 umask. The default umask is often 0022 which would exactly make the difference between 0777 and 0755 vanish.
Try chmod function. For more detais just right click in the IDE and type chmod.
NAME:
chmod - change mode of a file
SYNOPSIS:
#include <sys/stat.h>
int chmod(const char *path, mode_t mode);
DESCRIPTION:
The chmod() function shall change S_ISUID, S_ISGID, [XSI] S_ISVTX, and the file permission bits of the file named by the pathname pointed to by the path argument to the corresponding bits in the mode argument. The application shall ensure that the effective user ID of the process matches the owner of the file or the process has appropriate privileges in order to do this.
S_ISUID, S_ISGID, [XSI] S_ISVTX, and the file permission bits are described in <sys/stat.h>.
If the calling process does not have appropriate privileges, and if the group ID of the file does not match the effective group ID or one of the supplementary group IDs and if the file is a regular file, bit S_ISGID (set-group-ID on execution) in the file's mode shall be cleared upon successful return from chmod().
Additional implementation-defined restrictions may cause the S_ISUID and S_ISGID bits in mode to be ignored.
The effect on file descriptors for files open at the time of a call to chmod() is implementation-defined.
Upon successful completion, chmod() shall mark for update the st_ctime field of the file.
RETURN VALUE:
Upon successful completion, 0 shall be returned; otherwise, -1 shall be returned and errno set to indicate the error. If -1 is returned, no change to the file mode occurs.
More information can be found at this link.

Resources