GIDForums  

Go Back   GIDForums > Computer Programming Forums > C Programming Language
User Name
Password
Register FAQ Members List Calendar Search Today's Posts Mark Forums Read

 
 
Thread Tools Search this Thread Rate Thread
  #1  
Old 14-Nov-2009, 06:42
aijazbaig1's Avatar
aijazbaig1 aijazbaig1 is offline
Member
 
Join Date: May 2006
Location: India
Posts: 156
aijazbaig1 has a spectacular aura aboutaijazbaig1 has a spectacular aura about
Question

File copy using pipes - inter process communication


Hello folks,

Im trying to create a simple program that allows a process to create a copy of a certain file. The parent reads from the file, sends the data over a pipe to child process. the child then reads data from the pipe. It creates a file and dumps the data that it read into this newly created file.

sounds simple. But it has given me a good amount of headache. Before we see the code, lets see the issues that i face. I have been instructed to stick to either the fopen, fwrite etc calls or to the more low level open and write system APIs. I have decided to stick to the latter ones. nonetheless, I still have to find a graceful way to use read and write on regular files (not FIFOs or pipes) such that I can terminate the transfers on encountering EOF.

Besides that, the real issues that I have been facing are these:
1.I am able to send the data across as long as it is less that the size of the intermediate buffers. But on the receiving end, which in my case is the child process I cannot write it in a file.
2.As of now (in the code below), I cannot even write to the pipe.. This is strange as I do receive the data in the child process as I verify that in the code itself.

The file does get created, but file permissions are locked. And then the files contains nothing (0 bytes). Enough words. Time for the real deal here

CPP / C++ / C Code:
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

int main()
{    
    int fd1,fd2;
    int pfd[2];
    int pid;
    char spath[] = "/home/aijazbaig1/Documents/os/assign5/tst.txt";
    char dpath[] = "/home/aijazbaig1/Documents/os/assign5/tst1.txt";
    int wrcnt,rdcnt;
    char snd_buf[200],rcv_buf[200];    
    char ch;
    sigset_t mask,oldmask;

    fflush(stdin);
    fflush(stdout);

    sigfillset(&mask);
    sigprocmask(SIG_SETMASK,&mask,&oldmask);

    memset(snd_buf,'\0',sizeof(snd_buf));
    memset(rcv_buf,'\0',sizeof(rcv_buf));

    //creating file
    fd1 = open(spath,O_RDONLY);
    if (fd1 == -1) {
        perror("file open for reading failed:");
        exit(1);
    }

    //read from file into snd_buf
    if((rdcnt = read(fd1,snd_buf,sizeof(snd_buf))) == -1) { 
        perror("reading file failed:");
        exit(1);
    }
    close(fd1);

    printf("snd_buf = %s\n",snd_buf);

    //pipe operations
    if(pipe(pfd) == -1) {
        perror("error creating pipe:");
        exit(1);
    }

    pid = fork();

    if(pid == 0) {
        puts("in child");
        close(pfd[1]);//close write end in child

        fd2 = open(dpath,O_CREAT | O_RDWR);
        if (fd2 == -1) {
            perror("child file creation failed:");
            exit(1);
        }

        if((rdcnt = read(pfd[0],rcv_buf,sizeof(rcv_buf))) == -1) {
            perror("reading from file failed:");
            exit(1);
        }
        printf("rdcnt = %d,rcv_buf = %s\n",rdcnt,rcv_buf);


       
        if((wrcnt = write(fd2,rcv_buf,sizeof(rcv_buf))) == -1) {
            perror("writing to file2 failed:");
            exit(1);
        }        
        close(fd2);
        close(pfd[0]);//close read end in child process
        //exit(0);
    }

    close(pfd[0]);//close read end in parent

    if((wrcnt = write(pfd[1],snd_buf,strlen(snd_buf))) == -1) {
        perror("writing to pipe failed:");
        exit(1);
    }
    printf("wrcnt = %d\n",wrcnt);
    exit(0);
}

So summarizing, the code above
  1. parent process fails to write to pipe
  2. child process cannot write data to newly created file
The error message which I get is writing to pipe failed:: Bad file descriptor. Even so, I can receive the data that the parent process sends.
All in all, heres the output i see on my console:
Code:
snd_buf = hay there whats up? in child rdcnt = 20,rcv_buf = hay there whats up? writing to pipe failed:: Bad file descriptor wrcnt = 20

Im confused. ...helppppppp!!!!!!!!!!!!!!
__________________
Hope to hear from you guys!

--------------------------------------------------

Best Regards,
Aijaz Baig.
  #2  
Old 14-Nov-2009, 10:24
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 5,311
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold

Re: file copy using pipes - inter process communication


Quote:
Originally Posted by aijazbaig1
...issues..
First of all: the following are unnecessary, and, in fact the effects of fflush(stdin) is undefined in the C standard. I really don't like to see superfluous stuff like this, even though it may not cause actual harm. I'm funny that way.
CPP / C++ / C Code:
    /* fflush(stdin); */
    /* fflush(stdout); */

Now to get to some of your issues:
Quote:
Originally Posted by aijazbaig1
The file does get created, but file permissions are locked


Then use something like the following to open the file for writing:

CPP / C++ / C Code:
        /*
           Create a now file if it does not exist.
           If it exists, open for appending.

           Everyone can read and write

         */
        fd2 = open(dpath, O_CREAT| O_WRONLY | O_APPEND, 0666);
or
CPP / C++ / C Code:
        /* 
           If the file already exists, this will overwrite it.
           If the file does not exist, this will create a
           new empty file.

           Everyone can read and write.

         */
        fd2 = open(dpath, O_CREAT| O_WRONLY | O_TRUNC, 0666);

I have put a couple of comments in your code in hopes of showing why you get the error trying to write to the pipe. By commenting out the exit(0) at the end of the child part of the program, it continues on into the parent's code and tries to write to the pipe after it has been closed.
Quote:
Originally Posted by aijazbaig1

CPP / C++ / C Code:
..
.
.
    if(pid == 0) {
        puts("in child");
       .
.
.
        printf("rdcnt = %d,rcv_buf = %s\n",rdcnt,rcv_buf);


       
        if((wrcnt = write(fd2,rcv_buf,sizeof(rcv_buf))) == -1) {/* No! Write rdcnt bytes */
            perror("writing to file2 failed:");
            exit(1);
        }        
        close(fd2);
        close(pfd[0]);//close read end in child process
        //exit(0);    /* Why the heck did you comment this out? */
    } /* This should be he end of the child thread's process. Do NOT continue from here */

    close(pfd[0]);//close read end in parent

    /* By commenting out the exit from the child process, the child
     * is still active here and tries to write to the buffer, so this
     * fails, since the child has closed
     */
    if((wrcnt = write(pfd[1],snd_buf,strlen(snd_buf))) == -1) {
        perror("writing to pipe failed:");
        exit(1);
    }
    printf("wrcnt = %d\n",wrcnt);
    exit(0);
}

A summary:

CPP / C++ / C Code:
#include <stdio.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    int fd1, fd2;
    int pfd[2];
    int pid;
    char spath[] = "./tst.txt";  /* or whatever path you need */
    char dpath[] = "./tst1.txt"; /* or whatever path you need */
    int wrcnt, rdcnt;
    char snd_buf[200], rcv_buf[200];
    sigset_t mask, oldmask;

    sigfillset(&mask);
    sigprocmask(SIG_SETMASK, &mask, &oldmask);

    memset(snd_buf, '\0', sizeof(snd_buf));
    memset(rcv_buf, '\0', sizeof(rcv_buf));

    /*creating file */
    fd1 = open(spath, O_RDONLY);
    if (fd1 == -1) {
        perror("file open for reading failed:");
        exit(1);
    }

    /*read from file into snd_buf */
    if ((rdcnt = read(fd1, snd_buf, sizeof(snd_buf))) == -1) {
        perror("reading file failed:");
        exit(1);
    }
    close(fd1);

    printf("snd_buf = %s\n", snd_buf);

    /*pipe operations */
    if (pipe(pfd) == -1) {
        perror("error creating pipe:");
        exit(1);
    }

    pid = fork();

    if (pid == 0) {
        puts("in child");
        close(pfd[1]); /*close write end in child */

        /* 
           If the file already exists, this will overwrite it.
           If the file does not exist, this will create a
           new empty file.

           Everyone can read and write.

         */
        fd2 = open(dpath, O_CREAT| O_WRONLY | O_TRUNC, 0666);
        /*
           Create a now file if it does not exist.
           If it exists, open for appending.

           Everyone can read and write

         */
        /*fd2 = open(dpath, O_CREAT| O_WRONLY | O_APPEND, 0666); */

        if (fd2 == -1) {
            perror("child file creation failed:");
            exit(1);
        }

        if ((rdcnt = read(pfd[0], rcv_buf, sizeof(rcv_buf))) == -1) {
            perror("reading from file failed:");
            exit(1);
        }
        printf("rdcnt = %d,rcv_buf = %s\n", rdcnt, rcv_buf);

        if ((wrcnt = write(fd2, rcv_buf, rdcnt)) == -1) {
            perror("writing to file2 failed:");
            exit(1);
        }
        close(fd2);
        close(pfd[0]); /*close read end in child process */
        exit(0);
    } /* end of the child stuff */

    close(pfd[0]);    /*close read end in parent */

    if ((wrcnt = write(pfd[1], snd_buf, strlen(snd_buf))) == -1) {
        perror("writing to pipe failed:");
        exit(1);
    }
    printf("wrcnt = %d\n", wrcnt);
    exit(0);
}

Maybe the following is what you had in mind when you commented out the exit(0) in the child process.

CPP / C++ / C Code:
    if (pid == 0) {
        puts("in child");
.
.
.
        close(pfd[0]);          /*close read end in child process */
    }                           /* end of the child stuff */
    else {                      /* The parent process */

        close(pfd[0]);          /*close read end in parent */

        if ((wrcnt = write(pfd[1], snd_buf, strlen(snd_buf))) == -1) {
            perror("writing to pipe failed:");
            exit(1);
        }
        printf("wrcnt = %d\n", wrcnt);
    }
    exit(0);
}

At any rate, you can't let the child process continue into the parent's code to try to write to the pipe.

Regards,

Dave

Footnote: Many of the functions and headers are not part of the C standard library. I am assuming that you are using some GNU-compatible compiler. The modified program that I show works for me with GNU gcc on Linux (Centos 5) and with cygwin/gcc on Windows xp.
  #3  
Old 26-Feb-2010, 21:39
murugaperumal murugaperumal is offline
New Member
 
Join Date: Feb 2010
Posts: 15
murugaperumal has a little shameless behaviour in the past

Re: File copy using pipes - inter process communication


Dear Friend,

I have written the following code. This is working fine. This code also used pipe only to copy the content from one file to another file.

CPP / C++ / C Code:

#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define BUFFER_SIZE 80
#define READ_END 0
#define WRITE_END 1

int main(int argc, char *argv[]) {

/* argc must be 3 to ensure the correct usage */
if (argc != 3) {
printf("The usage of this program is:\n");
printf("FileCopy input.txt copy.txt\n");
return 1;
}

else {
/* initialize the pipe and fork variables */
int fd[2];
pid_t pid;

/* argv[0] is the program name, argv[1] and argv[2] are the file names */
char *infile = argv[1];
char *outfile = argv[2];

/* create a pipe */
if (pipe(fd) == -1) {
fprintf(stderr, "Pipe failed");
return 1;
}

/* fork */
pid = fork();

/* if pid < 0 there is an error */
if (pid < 0) {
fprintf(stderr, "Fork error");
return 1;
}

/* parent code */
if (pid > 0) {
/* close the unused end of the pipe */
close(fd[READ_END]);
/* make a buffer to store input file information */
char buffer[BUFFER_SIZE];
/* open input file */
FILE *in;
in = fopen(infile, "r");

/* make sure it's not null */
if (in == NULL) {
fprintf(stderr, "Error opening file %s\n", infile);
return 1;
}

/* read from the file into the pipe thru the buffer */
while (fgets(buffer, BUFFER_SIZE, in)){
write(fd[WRITE_END], buffer, strlen(buffer)+1);
buffer[0]='\0';
//fprintf(in, buffer, strlen(buffer)+1);
}

/* close the input file */
fclose(in);/* child process has pid == 0 */
else {

/* create a buffer to read from the pipe and store into the out file */
//char buffer[BUFFER_SIZE];

/* close the unused end of the pipe */
close(fd[WRITE_END]);

/* initialize the output file */
FILE *out;

/* w+ means open a file for writing and create it if it doesn't exist */
out = fopen(outfile, "w+");

/* read from the pipe to the buffer */
//read(fd[READ_END], buffer, BUFFER_SIZE);

/* write from the buffer to the file */
//fprintf(out, "%s", buffer);

while(1) {
char buffer[BUFFER_SIZE];
if (read(fd[READ_END], buffer, BUFFER_SIZE) != 0)
{fprintf(out,"%s",buffer);
fflush(out);
}
else
break;
}

/* close the file and the pipe */
fclose(out);
close(fd[READ_END]);
}
}
}

/* close the pipe */
//close(fd[WRITE_END]);
}

Last edited by admin : 01-Mar-2010 at 09:46. Reason: Please insert your example C/C++ codes between [CPP] and [/CPP] tags
  #4  
Old 26-Feb-2010, 23:03
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 5,311
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold

Re: File copy using pipes - inter process communication


Quote:
Originally Posted by murugaperumal
...This is working fine....
Your code will not compile with GNU gcc version 4.1.2 on my Linux workstation. I can't understand how any C compiler would accept it since the "else" on your line number 68 doesn't belong there.

I would like to know what compiler and operating system you are using. Did you really test the code that you posted? Did it really copy a text file to another file? (There are other errors that I believe would not let it copy correctly even if you fix the "else" problem.)

Note that the changes that I suggested to the Original Poster will not make the code function the way that he wanted. I just wanted to try to answer his question about why his code was giving the "can not write to pipe" error, and to show how to get past that point.

A complete example that works for binary files as well as text files could look something like
CPP / C++ / C Code:
/* 
   pipe_example.c

   Simple pipe example, not really useful other than for
   purposes of illustration.

   For a Reference, see  [url]http://beej.us/guide/bgipc/[/url]

   Tested with GNU gcc on my Centos 5.4 workstation (YMMV)

   Compile with gcc -W -Wall -pedantic pipe_example.c -o pipe_example

   When executing, give input file name and output file name on
   the command line.

   I used open(), read(), write() instead of fopen(), fgets() and
   fprintf() on the user I/O files, so that it can work on any kind
   of files (binary or text).

   davekw7x

 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

#define READ_END  0   /* fileno(stdin)  */
#define WRITE_END 1   /* fileno(stdout) */

/* Larger buffer sizes are almost certainly more efficient */
#define BUFFER_SIZE   100 /* Try different buffer sizes    */

int main(int argc, char *argv[])
{
    int fd[2];
    pid_t pid;

    const char *inname  = argv[1];
    const char *outname = argv[2];

    if (argc != 3) {
        printf("usage: pipe_example input_file output_file\n");
        exit(EXIT_FAILURE);
    }

    if (pipe(fd) == -1) {
        fprintf(stderr, "Pipe failed");
        exit(EXIT_FAILURE);
    }

    if ((pid  = fork()) < 0) {
        fprintf(stderr, "Fork error");
        exit(EXIT_FAILURE);
    }

    if (pid > 0) { /* The parent will write to the pipe */
        char buffer[BUFFER_SIZE]; /* Try different buffer sizes */
        int fdr;
        int num;

        close(fd[READ_END]); /* Close the unused end of the pipe */
        if ((fdr = open(inname, O_RDONLY)) < 0) {
            fprintf(stderr, "Parent: Error opening file %s for reading.\n", inname);
            exit(EXIT_FAILURE);
        }

        while ((num = read(fdr, buffer, BUFFER_SIZE)) > 0) {
            if (write(fd[WRITE_END], buffer, num) < 0) {
                fprintf(stderr, "Parent: Error writing to pipe.\n");
                exit(EXIT_FAILURE);
            }
        }
        if (num < 0) {
            fprintf(stderr, "Parent: Error reading from %s\n", inname);
            exit(EXIT_FAILURE);
        }
        close(fdr);
    }
    else { /* The child will read from the pipe */
        char inbuf[BUFFER_SIZE]; /* Try different buffer sizes */
        int fdw;
        int num;

        close(fd[WRITE_END]); /* Close the unused end of the pipe */

        fdw = open(outname, O_CREAT|O_WRONLY|O_TRUNC, 0644);
        if (fdw < 0) {
            fprintf(stderr, "Child: Can't open file %s for writing\n", outname);
            exit(EXIT_FAILURE);
        }

        while ((num = read(fd[READ_END], inbuf, BUFFER_SIZE)) > 0) {
            if (write(fdw, inbuf, num) < 0) {
                fprintf(stderr, "Child: Error writing to %s\n", outname);
                exit(EXIT_FAILURE);
            }
        }
        if (num < 0) {
            fprintf(stderr, "Child: Error reading from pipe.\n");
            exit(EXIT_FAILURE);
        }
        close(fdw);
        close(fd[READ_END]);
    }
    return 0;
}




Regards,

Dave
Last edited by davekw7x : 27-Feb-2010 at 00:32.
 
 

Recent GIDBlogProblems with the Navy (Enlisted) by crystalattice

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
Power Calibration Error In Nero Fix (hopefully) matt3678 Computer Hardware Forum 60 20-Aug-2009 05:04
Airport Log program using 3D linked List : problem reading from file batrsau C Programming Language 11 29-Feb-2008 07:44
[TUTORIAL] Calling an external program in C (Linux) dsmith C Programming Language 4 22-Apr-2005 13:30
After execution - Error cannot locate /Skin File? WSCH C++ Forum 1 05-Mar-2005 20:03
[Tutorial] Standard I/O aaroncohn C Programming Language 20 27-Feb-2004 21:07

Network Sites: GIDNetwork · GIDWebHosts · GIDSearch · Learning Journal by J de Silva, The

All times are GMT -6. The time now is 16:08.


vBulletin, Copyright © 2000 - 2010, Jelsoft Enterprises Ltd.