I'm doing an exercise for University, which asks:
Create a C program called 'split', which accepts a file, and a number. The program will divide the input file in two files, one called 'part1.txt' which will contain the first n bytes, and one called 'part2.txt' which will contain the other bytes.
If the input file contains less than n bytes, the file 'part2.txt' will not be created.
This is my program. What happens when I execute it, is that it creates the part1.txt file (without anything written in it) and the program hangs.
I've been looking at this for a day, but can't spot the problem. Any help?
I've compiled using:
gcc -o split split.c
When i execute it, i write:
./split text.txt 10
Where 'text.txt' is a text file containing words i accurately typed by pressing random buttons on my keyboard.
int splitter;
int fd, fd1, fd2;
char buffer[5000];
int main(int argc, char** argv){
if(argc<2){
printf("Insert 2 arguments.");
exit(1);
}
splitter = atoi(argv[2]);
if (fd=open(argv[1], O_RDONLY) < 0){
perror("Error\n");
exit(1);
} else {
if (fd1=open("part1.txt", O_RDWR | O_CREAT, S_IRWXU) <0){
perror("Error");
exit(1);
}
if(read(fd,buffer,splitter) == splitter){
write(fd1,buffer,splitter);
if (fd2=open("part2.txt", O_RDWR | O_CREAT, S_IRWXU)<0){
perror("Errore");
exit(1);
};
while (read(fd,buffer,1) ==1){
write(fd2,buffer,1);
}
close(fd1);
close(fd2);
} else {
while (read(fd,buffer,1) ==1){
write(fd1,buffer,1);
}
close(fd1);
}
close(fd);
}
The relational operators reside at the 6th level of C's precedence table, much higher than the assignment operators.
This statement:
if (fd=open(argv[1], O_RDONLY) < 0)
is equivalent to:
if (fd = (open(argv[1], O_RDONLY) < 0))
The < operator returns either 1 or 0, or in other words, true or false, which gets assigned to fd.
Change it to:
if ((fd = open(argv[1], O_RDONLY)) < 0)
You have the same issue in the subsequent if statement.
From Expert C Programming:
Some authorities recommend that there are only two precedence levels
to remember in C: multiplication and division come before addition and
subtraction.
Everything else should be in parentheses. We think that's
excellent advice.
Related
This question already has an answer here:
Using open(), read() and write() system calls to copy a file
(1 answer)
Closed last year.
I am trying to implement the cp command only using read/write system calls.
Here is my code:
/**
* cp file1 file 2
*/
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
int main(int argc, char *argv[])
{
int errsv;
char contents[1024];
int fd_read, fd_write;
fd_read = open(argv[1], O_RDONLY);
if (fd_read == -1)
{
errsv = errno;
printf("Error occured: %d\n", errsv);
}
read(fd_read, contents, sizeof(contents));
fd_write = open(argv[2], O_CREAT | O_WRONLY | O_TRUNC, 0744);
if (fd_write == -1)
{
errsv = errno;
printf("Error occured: %d\n", errsv);
}
write(fd_write, contents, sizeof(contents));
close(fd_read);
close(fd_write);
return 0;
}
I tested the code using the commands:
cc test.c
./a.out file1 file2
Here is my file1:
dummy text
dummy text
After running the code, although file2 contains the text from file1, it also has some gibberish characters. [not keeping this here.]
Why is this so?
You need to call read() and write() in a loop to copy the entire file. read() returns 0 when you reach EOF, or a negative result if there's an error, then you can end the loop.
read() returns the number of bytes that were read, which may be less than the size of the buffer. You need to use that number when calling write(), otherwise you'll write extra characters to the output file. These will be unitialized characters on the first iteration, and on other iterations they'll be left over characters from previous iterations.
int main(int argc, char *argv[])
{
char contents[1024];
int fd_read, fd_write;
fd_read = open(argv[1], O_RDONLY);
if (fd_read == -1)
{
perror("open input file");
exit(1);
}
fd_write = open(argv[2], O_CREAT | O_WRONLY | O_TRUNC, 0744);
if (fd_write == -1)
{
perror("open output file");
exit(1)
}
int n_read;
while ((n_read = read(fd_read, contents, sizeof(contents))) > 0) {
write(fd_write, contents, n_read);
}
close(fd_read);
close(fd_write);
return 0;
}
write(fd_write, contents, strlen(contents));
Strlen returns the filled entries number but sizeof returns the buffer size which is 1024
I wrote this simple code to concatenate two files. Why doesn't this work? Please help.
int main(int arg, char* argv[]){
int fd1, fd2;
char c;
fd1 = open(argv[1], O_APPEND);
fd2 = open(argv[2], O_RDONLY);
while(read(fd2, &c, sizeof(c))) {
write(fd1, &c, sizeof(c));
}
close(fd1);
close(fd2);
return 0;
}
As I noted in a comment:
You need to test the results of open() and write(). Your call with O_APPEND needs O_WRONLY too. And if you want it to create the file too, you need various other options too — O_CREAT; maybe O_TRUNC but probably not; maybe O_EXCL; maybe some others too — and you need a mode argument for the third argument (e.g. 0644 — owner can read or write, group and others can only read; or something more restrictive).
You also need to check that you have 2 file name arguments.
Fixing those issues leads to code similar to this:
int main(int arg, char* argv[]){
if (argc < 3)
{
fprintf(stderr, "Usage: %s out-file in-file\n", argv[0]);
return 1;
}
int fd1 = open(argv[1], O_APPEND|O_WRONLY|O_CREAT, 0644);
if (fd1 < 0)
{
fprintf(stderr, "%s: failed to open/create file %s for writing\n", argv[0], argv[1]);
return 1;
}
int fd2 = open(argv[2], O_RDONLY);
if (fd2 < 0)
{
fprintf(stderr, "%s: failed to open file %s for reading\n", argv[0], argv[2]);
return 1;
}
char c;
while (read(fd2, &c, sizeof(c)) == sizeof(c)) {
if (write(fd1, &c, sizeof(c)) != sizeof(c))
break;
}
close(fd1);
close(fd2);
return 0;
}
I note that you might get warnings about comparing signed and unsigned values with the read() and write() tests — the functions return a ssize_t and sizeof produces a size_t (2 vs 1 letters s). You can cast around that, but it's ugly. The code is also woefully inefficient. Single character reads and writes work, but you get dramatically better performance in general with buffer sizes in the 1 KiB to 4 KiB range, and even bigger. Of course, then you have to trap and use the value returned by read() so that the correct amount of data is written.
Note that the original code would continue the loop if the read() failed (returned -1). It would only stop if the read() was successful at returning 0 when it reached EOF.
Im trying to create a new file / overwrite an existing file using systemcalls , but for some reason I have two problems:
1. When I'm first running the program it exits with value 0, so it seems like it created the file successfully, but I can't see anything in my project directory.
then when I secondly running the program the file is created, but an error message is printed on the screen.
2. Also after the first iteration of the program, I can't see the prinf message at the end of the main function.
Thanks for helping.
int readFileDesc = 0, writeFiledesc = 0;
int sourceFile = 1, destFile = 2, bufferSize = 3, isOverwrite;
if (argc != 4 && argc != 5) {
printf("Invalid number of arguments\n");
printf("Usage:\n");
printf(" ex1 [-f] SOURCE DEST BUFFER_SIZE");
exit(EXIT_FAILURE);
}
//Checking if -f [OP] is activated.
isOverwrite = (strcmp(argv[1], "-f") == 0);
if (isOverwrite) {
sourceFile++;
destFile++;
bufferSize++;
}
//Opening the source file
readFileDesc = open(argv[sourceFile], O_RDONLY);
if (readFileDesc < 0) {
perror("Unable to open source file for reading: ");
exit(EXIT_FAILURE);
}
//opening the destination file
if (!isOverwrite) {
//Case we dont have the -f [op] so we create the file.
writeFiledesc = open(argv[destFile],
O_CREAT | O_EXCL | O_WRONLY ,
S_IRUSR | S_IWUSR);
if (writeFiledesc < 0) {
perror("Unable to open destination file for reading: ");
exit(EXIT_FAILURE);
}
} else {
//Case we have the -f [op] so we override existing file.
writeFiledesc = open(argv[destFile], O_RDONLY | O_WRONLY | O_TRUNC);
if (writeFiledesc < 0) {
perror("Unable to open destination file for writing: ");
exit(EXIT_FAILURE);
}
}
//Assume the buffersize is legal.
bufferSize = atoi(argv[bufferSize]);
char data[bufferSize];
int nread, nwrite;
while ((nread = read(readFileDesc, data, bufferSize)) > 0) {
if ((nwrite = write(writeFiledesc, data, nread)) != nread) {
printf("write problem: ");
}
}
// cant see this!
printf("File %s was copied to %s" , argv[sourceFile] , argv[destFile]);
//handling errors
close(sourceFile);
close(destFile);
return EXIT_SUCCESS;
}
This is wrong:
writeFiledesc = open(argv[destFile], O_RDONLY | O_WRONLY | O_TRUNC);
Using both O_RDONLY and O_WRONLY is wrong. You need to use O_RDWR.
Per the POSIX standard for open():
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.
Any combination of the following may be used:
...
Also, read() and write() return ssize_t, not int.
I'm writing this software that should open a file, that must be passed as an argument, and write the content of the file on the standard output using the open and write system calls. (It's a bit like the cat command)
The problem is that once I run the program as
./a.out /example/pattern/file
it writes on the standard output the pattern of the file and then it gets stuck, without writing anything or terminating, allowing me even to write on the terminal.
I've tried using the ddd debugger, but I wasn't able to find the problem.
All the necessary headers are included.
int main(int argc,char * argv[]){
printf("%s\n", argv[1]);
int fd, lung;
char buf[10];
if(fd = open(argv[1], O_RDONLY)==-1){
perror("argv[1], in apertura");
exit(EXIT_FAILURE);
}
while(lung = read(fd,buf,10)>0){
if( (write(1, buf, lung))==-1) perror("error");
}
if (lung==-1) {perror("error");exit(EXIT_FAILURE);}
fflush(NULL);
close(fd);
return 0;
}
Isn't that suspicious?
if(fd = open(argv[1], O_RDONLY)==-1) {
According to operator precedence, == will be executed before =.
Then:
while(lung = read(fd,buf,10)>0){
will similarly suffer from > been executed before =.
Tip: When in doubt, use parentheses! ;)
while(lung = read(fd,buf,10)>0){
if( (write(1, buf, lung))==-1) perror("error");
}
is the same as (due to operator precedence ):
while(lung = (read(fd,buf,10)>0) ){
if( (write(1, buf, lung))==-1) perror("error");
}
The value of lung will be either 1 or 0. When it is 0, the loop will break When it is 1, only 1 character will be written to stdout.
What you need is:
while( (lung = read(fd,buf,10)) > 0 ){
I'm trying to make a background process named server that uses a named pipe to receive data from a "client" program, and the process saves that data in a file called log. My code is as follows:
server:
main(){
int fd2,fd_log;
char *fifo ="/home/me/fifo";
char c;
mkfifo(fifo, 0666);
int x;
while(fd2 = open(fifo, O_RDONLY)>=0){
fd_log=open("/home/me/log.txt",O_WRONLY | O_CREAT | O_APPEND);
while(read(fd2,&c,1)>=0){
write(fd_log,&c,1);
}
close(fd2);
close(fd_log);
}
}
client:
main(){
int fd1;
char *fifo ="/home/me/fifo";
char c;
fd1 = open(fifo, O_WRONLY);
while(read(0, &c, 1)>=0){
write(fd1,&c,1);
}
close(fd1);
}
However, this doesn't seem to work. There is no action in the log file, and I think the read call in the server file it's not done. Any suggestions?
The problem is in your line here:
while(fd2 = open(fifo, O_RDONLY)>=0){
Due to C operator precedence, this is really evaluated as:
while((fd2 = (open(fifo, O_RDONLY)>=0)) != 0){
I.e. call open(), check if it's return value is greater than 0, then assign that boolean result to fd2, then check if it is zero or not.
That way you are then reading from file no. 1, which is stdout and that surely blocks indefinitely.
Change it to this and everything starts working of course:
while((fd2 = open(fifo, O_RDONLY)) >=0){
Also you are opening the log file without any permissions, you should specify some so that you can access it afterwards somehow, e.g:
fd_log=open("/home/me/log.txt",O_WRONLY | O_CREAT | O_APPEND, 0600);