C dup2 overwrite file bug when line > 1 - c

I have the following simple program that catenates infile to outfile
char *execArgs[] = { "cat", NULL};
int outfile = open("outfile", O_WRONLY | O_CREAT, 0644);
int infile = open("infile", O_RDONLY, 0);
dup2(outfile, STDOUT_FILENO);
dup2(infile, STDIN_FILENO);
close(outfile);
close(infile);
execvp(execArgs[0], execArgs);
Now, suppose the content of infile is
this is infile
and outfile is
this is outfile
After running the program, the content of outfile has an extra "e" at the end as such
this is infilee
Also, if the outfile is instead
this is outfile
this is outfile
It becomes
this is infilee
this is outfile
What is wrong?

What you're experiencing is the expected behavior. cat just writes the number of bytes it reads, so since the original outfile is longer, the remaining bytes contain what they contained before.
If you're asking why you get different behavior from using the shell to perform:
cat < infile > outfile
the reason is that the shell opens outfile (or any target of >) with O_TRUNC, which truncates the file to zero length as part of opening it. You can get the same behavior by adding | O_TRUNC to your open call's flags argument.

Try using O_TRUNC this will truncate the file it it exists.
int outfile = open("outfile", O_WRONLY | O_CREAT | O_TRUNC, 0644);

It doesn't have an extra e, it has the same e it always had at that position.
Look at the strings you're writing:
this is infilee
this is outfile
^
+-- lines up
The problem is that the output is not truncated, and thus it retains all its old content. You're just overwriting it from the start.

Related

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.

fstat getting file size zero

File is there and having json data inside it. I want to know length of file.but when i try below code it but size remains 0.
int file_contentl_Len = 0;
int fd_0 ;
fd_0 = open(FILE_PATH_CONFIG_0, O_WRONLY | O_TRUNC | O_CREAT, 0644);
if(fd_0 < 0)
{
printf("\r\nError opening Config file %s: %s\n",FILE_PATH_CONFIG_0, strerror(errno));
return -1;
}
struct stat buf;
fstat(fd_0, &buf);
file_contentl_Len = buf.st_size;
printf("\r\nConfig file %s content length: %d\r\n", FILE_PATH_CONFIG_0, file_contentl_Len);
You opened the file for writing with truncation, creating it if necessary — O_WRONLY | O_TRUNC | O_CREAT.
The size of zero tells you the truncation worked, or the file was created empty.
If you wanted to read what was in the file, use O_RDONLY instead. Or use O_RDWR and think carefully about whether to allow the file to be created.

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).

How to redirect stdin (specific file name) to stdout (specific file name)

I am creating a shell code. Basically, I want to redirect stdin file to stdout file. For instance when I enter a command like sort < hello.c > t.txt, then the hello.c file should be copied in new mentioned file called t.txt.
Here is my code, I am able to redirect output of other commands, when I type ls > t.txt. However, I don't have any idea about redirecting one file's input to other file using dup2.
Here is my code, I am only posting the loop, as this is where I have to create the logic.
int in, out;
for (i = 0; i < arridx; i++) {
if(strcmp( array[i],"<")==0)
{
in = open(array[i+1], O_RDONLY);
array[i]=0;
// array[i+1]=0;
}
if(strcmp( array[i],">")==0)
{
out = open(array[i+1], O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IRGRP | S_IWGRP | S_IWUSR);
array[i]=0;
// array[i+1]=0;
}
}
dup2(in, 0);
dup2(out, 1);
// close unused file descriptors
close(in);
close(out);
Input array would be like
array[0]="sort"
array[1]="<"
array[2]="hello.c"
array[3]=">"
array[4]="t.txt"
In fact, whenever you run something like :
command < hello.c > t.txt
The redirection will take place presuming command is your argv[0] with no of arguments as 1, and redirection taking place by the shell.
However, on another point, going through your program, if redirection is used
not from command prompt but by array contents only,
int dup2(int oldfd, int newfd); - creates a copy of the file descriptor oldfd.
In your case,
dup2(in, 0);
dup2(out, 1);
0 and 1 stands for stdin and stdout file descriptors respectively. So, if you would like to redirect your input to be taken from the stdin instead of hello.c (file opened as in) and output to be taken from the stdout instead of t.txt (file opened as out), then shouldn't be other way round i.e.
dup2(0, in);
dup2(1, out);

Using write() to create a temporary file in C

For homework I have to read from the standard input, save it to a file and then read the file in another process. However, I'm confused as to why this code does not work:
while((n = read(0,buf,sizeof(buf))) > 0) {
int tempfile = open("testfile", O_TRUNC | O_CREAT, 0666);
write ( tempfile , buf , sizeof(buf) );
close(tempfile);
process("testfile");
}
I'm not supposed to use any stdio stuff.
When I look at the file I've created, it has 0 bytes and yet the buffer itself has the correct information....can someone help em see where I've gone wrong?
I can use process on file names and it correctly reads them.
You've specified O_TRUNC | O_CREAT for the open flags, but you've failed to specify O_RDWR or O_WRONLY.
You also probably want to write n bytes, not sizeof(buf), as the remaining sizeof(buf) - n bytes are uninitialized.

Resources