Copy program: File Permission Denied - c

My following program, which copies a file, won't allow me to copy files because of "permission denied". However, I gave it permissions.
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
int fdinput, fdoutput; //file pointers
char arrbuf[5000]; //size of what can be read in file
ssize_t bytesR, bytesW;//number of what input returns
mode_t mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IROTH |S_IXOTH ;
fdinput = open(argv[1], O_RDONLY); //pointing to read file
fdoutput = open(argv[2], O_WRONLY);//pointing to write file
if(fdinput == -1){
perror("the source file cant be opened");
return 1;
}
if(fdoutput == -1){
perror("the written file cant be opened");
return 2;
}
while((bytesR = read(fdinput, arrbuf, sizeof arrbuf)) > 0){
bytesW = write(fdoutput, arrbuf, (ssize_t) bytesR);
}
close(fdinput);
close(fdoutput);
return 0;
}

The problem is in the call to the system call open() for the destination file (i.e.: the file to be created as a result of the copy):
fdoutput = open(argv[2], O_WRONLY);
Making possible the creation of the destination file
First, the call above to open() opens the file with the given name by argv[2], only if it already exits. Otherwise, the system call fails (errno is set to ENOENT) and perror() produces:
the written file cant be opened: No such file or directory
In order to create the file if it does not exist yet, the O_CREAT flag has to ORed together with O_WRONLY.
Truncating an already existing destination file
If the destination file already exist you surely want to truncate the length of that already existing file to zero at the moment of open()ing. That can by achieved by ORing the O_TRUNC flag together with the other flags.
Providing the permissions for the file to be created
Let's look at the open() system call's prototype:
int open(const char *path, int oflag, ...);
The ... at the end is to specify a kind of optional argument. That argument is used by open() only when a new file is being created. It provides the mode bits to be applied for the file to be created. This is not exactly the permissions for the file to be created, but it is strongly related to them (for more info see: file mode creation mask).
You created mode of type mode_t but just forgot to pass it to open().
With all exposed above in mind, your call should look like:
fdoutput = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, mode);

Related

why if I redirect the STD_OUT on a file and write to STD_OUT the file remains empty?

I can't solve a problem with standard output laugh, I'm on Unix operating system, so the file-descriptor of STD_IN = 0, STD_OUT = 1, STD_ERR = 2, basically I tried to close the descriptor associated with the standard output, and then overwrite it with that of the file I want to write to, but when I open the file it is empty.
CODE:
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
/*special file's descriptor --use it or constants in unistd.h-- */
#define STD_IN 0 /*standard input stream*/
#define STD_OUT 1 /*standard output stream*/
#define STD_ERR 2 /*standard output-error stream*/
int main(unsigned int num_of_args, char** args)
{
if(num_of_args != 3)
{
write(STD_ERR, "Few argouments.\nThe use = ./executable <message> <file>\n", 69);
return -1;
}
int file_des= open(args[2], O_CREAT, 0640);
if(file_des < 0)
{
write(STD_ERR, "Error, we couldn't open file.\n", 31);
return -1;
}
//I close the descriptor associated with STD_OUT
close(STD_OUT);
//I copy the descriptor associated with fil_des on the first available descriptor(so STD_OUT)
dup(file_des);
write(STD_OUT, args[1], sizeof(args[1]));
close(file_des);
return 0;
}
It should be fine, I don't see any errors, but when I open the file I don't find the message written.
Because? help me
This code is incorrect:
int file_des= open(args[2], O_CREAT, 0640);
Per the POSIX documentation for open() (note the bolded portion - my bolding):
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 ...
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_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.
Your open() call needs to include either O_WRONLY or O_RDWR as you are writing to the file:
int file_des= open(args[2], O_CREAT | O_WRONLY, 0640);
The Problem
The problem here is that the file descriptor which is being assigned to file_des isn't really 1.
int test = dup(file_des);
fprintf(stderr, "%d", test);
3
Now, what could the reason be?
The problem is with how you are opening your file. O_CREAT creates a file if it does not exist.
There is no specification whether you are opening the file for read, write, or read/write.
Since you are associating your file to the file descriptor of stdout, you must use the O_WRONLY flag as well.
int file_des = open(args[2], O_CREAT | O_WRONLY, 0640);

How to check if a file exist, delete content or create it

i would like to check if a file exist, delete content if it exists or create it if not.
I have tried :
open("screenshot.bmp", O_CREAT | O_RDWR | O_TRUNC);
But the file don't update if it already exists, if it doesn't the file is created correctly.
if ((fd = open("screenshot.bmp", O_CREAT, S_IRWXU)) > -1)
return (-1);
close (fd);
if ((fd = open("screenshot.bmp", O_TRUNC)) > -1)
return (-1);
But the file looks corrupted/empty after that (it should be filled by the rest of my code)
I also tried other ways.
Thanks for help !
Try using FILE *fd = fopen("screenshot.bmp", "w");
Accorsing to tutorialspoint:
FILE *fopen(const char *filename, const char *mode)
"w"
Creates an empty file for writing. If a file with the same name already exists, its content is erased and the file is considered as a new empty file.
Update:
OP says fopen(...) isn't allowed, but...
According to the docs you can achieve the same result as the fopen(...) call using:
open (filename, O_WRONLY | O_CREAT | O_TRUNC, mode)
For example (from the docs):
The following example opens the file /tmp/file, either by creating it (if it does not already exist), or by truncating its length to 0 (if it does exist). In the former case, if the call creates a new file, the access permission bits in the file mode of the file are set to permit reading and writing by the owner, and to permit reading only by group members and others.
If the call to open() is successful, the file is opened for writing.
#include <fcntl.h>
...
int fd;
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
char *filename = "/tmp/file";
...
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, mode);
...

C: Executing and outputing shell commands in C

Aside from using popen() (as was discussed in this question) is this a valid way of doing it ?
Say we had a program who's name is hexdump_dup and wanted the program to output the exact output of the hexdump command.
#include <fcntl.h>
#include <unistd.h>
int main(void)
{
int fd;
fd = open("hexdump_dup", O_CREAT | O_TRUNC | O_WRONLY, 0755); // (line 8)
write(fd, "/usr/bin/hexdump $#;", 20); // (line 9)
close(fd);
return (0);
}
Also could someone briefly explain what line 8 and 9 do, and how afterwards the command gets executed ? Like when, where does it say to execute the command or what makes the command execute ?
After this
fd = open("hexdump_dup", O_CREAT | O_TRUNC | O_WRONLY, 0755); // (line 8)
write(fd, "/usr/bin/hexdump $#;", 20);
you need to execute hexdump_dup executable, for that you need to use either system() or exec() family function. For e.g
system("./hexdump_dup 1 2 3"); /* after creating binary file(hexdump_dup) & writing command into it, you need to run it, for that use system() or exec() */
This
fd = open("hexdump_dup", O_CREAT | O_TRUNC | O_WRONLY, 0755);
will create the hexdump_dup binary if it doesn't exist before & if exists before it will truncate its content to 0. You can refer the man page of open() , it says
int open(const char *pathname, int flags, mode_t mode);
The argument flags must include one of the following access
modes: O_RDONLY, O_WRONLY, or O_RDWR. These request opening
the file read-only, write-only, or read/write, respectively.
O_CREAT
If the file does not exist it will be created. The
owner (user ID) of the file is set to the effective
user ID of the process.
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.
Lastly this
write(fd, "/usr/bin/hexdump $#;", 20);
writes 20 bytes containing array of characters /usr/bin/hexdump $#; in this case into a file where fd points i.e it will put this into hexdump_dup file.
Here $# means when you execute hexdump_dup like
./hexdump_dup 1 2 3
it will take all the parameters to be passed.

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.

C: cannot create or append to a file

I am trying to open a file for both read and write operations.
If the file is already there, it should append. (I want to be able to write to it, and maybe read from it later)
However, if the file is there, I cannot append to it (I get a permission denied: cannot create file)
int main()
{
int file;
file = open("redirect.txt", O_RDWR | O_APPEND | O_CREAT, 777);
if(!(file == -1)) //edited per comment
{
close(file);
}
else
perror("File could not be created\n");
return 0;
}
This only opens a new file if it does not exist, but does not append to an existing file if it does exist.
You're forgetting that the mode parameter to open() must be in octal. This will work:
file = open("redirect.txt", O_RDWR | O_APPEND | O_CREAT, 0777);
As zwol also mentioned, it's generally a good idea to create files with 0666 (since they don't need to be executable).

Resources