Thread: Implementation of linux cp (copy) command in C language

  1. #1
    Registered User
    Join Date
    Sep 2011
    Posts
    11

    Thumbs up Implementation of linux cp (copy) command in C language

    I was just going to post my problem, but then I started programming and could not stop because the issue was bothering me so much that I ended up solving it. But I think people can benefit from this program, especially beginners and intermediate people in C. That is why I decided to post it, hopefully you guys will like it. Of course this command already exists on linux so why would I write such program? Well because I am learning systems programming on my own, and it is important to know how to work with files, directories, etc.

    After you compile it, you can do following:

    1) ./cp2 file1.txt file2.txt
    Simply makes a copy of the file with specified name (in this case file2.txt)

    2) ./cp2 file1.txt /someDirInCurrentDir

    Copies file1.txt in current directory to a directory which is in current directory (preserves same file name)


    3) ./cp2 /someDir /anotherDir

    Copies all REGULAR files from someDir to anotherDir (both directories must be in the directory where you are calling the program from, same goes for the previous 2).

    Code:
    /** cp2.c
     *  version 1 of cp - uses read and write with tunable buffer size
     *
     *  
     */
    
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <string.h>
    #include <dirent.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    
    
    #define BUFFERSIZE 1024
    #define COPYMORE 0644
    
    
    
    
    void oops(char *, char *);
    int copyDir(char *src, char *dest);
    int copyFiles(char *src, char *dest);
    int dostat(char *filename);
    int mode_isReg(struct stat info);
    
    
    
    
    int main(int ac, char *av[])
    {
      /* checks args */
      if(ac != 3)
      {
        fprintf(stderr, "usage: %s source destination\n", *av);
        exit(1);
      }
    
    
       char *src = av[1];
       char *dest = av[2];
    
    
       if( src[0] != '/' && dest[0] != '/' )//cp1 file1.txt file2.txt
       {
           copyFiles(src, dest);
       }
       else if( src[0] != '/' && dest[0] == '/' )//cp1 file1.txt /dir 
       {
          int i;
          for(i=1; i<=strlen(dest); i++)
          {
              dest[(i-1)] = dest[i];
          }
          strcat(dest, "/");
          strcat(dest, src);
    
    
          copyFiles(src, dest);
      }
      else if( src[0] == '/' && dest[0] == '/' )//cp1 /dir1 /dir2    
      {                        //- copies all regular files from /dir1 to /dir2
          int i;
          for(i=1; i<=strlen(dest); i++)
          {
              dest[(i-1)] = dest[i];
          }
          for(i=1; i<=strlen(src); i++)
          {
              src[(i-1)] = src[i];
          }
          //printf("COPYING TWO DIRECTORIES:\n");
          //printf("SRC is %s, DEST is %s\n", src, dest);
          copyDir(src, dest);
      }
      else
      {
          fprintf(stderr, "usage: cp1 source destination\n");
          exit(1);
      }
    }
    
    
    int copyDir(char *source, char *destination)
    {
        DIR *dir_ptr = NULL;
        struct dirent *direntp;
        char tempDest[strlen(destination)+1];
        char tempSrc[strlen(source)+1];
        strcat(destination, "/");
        strcat(source, "/");
        strcpy(tempDest, destination);
        strcpy(tempSrc, source);
        
        //char *fileN;
        struct stat fileinfo;
        
        //printf("RIGHT BEFORE COPYING FILES in copyDir()\n");
        //printf("before strcat tempDest=%s\n", tempDest);
    
    
       if( (dir_ptr = opendir(source)) == NULL )
       {
          fprintf(stderr, "cp1: cannot open %s for copying\n", source);
          return 0;
       }
       else
       {
          while( (direntp = readdir(dir_ptr)))
          {      
          //printf("direntp DNAME is %s\n", direntp->d_name);
          //fileN = direntp->d_name;
          //printf("File name before Reg Check is %s\n", fileN);
          
          if(dostat(direntp->d_name))  
          {   
                  strcat(tempDest, direntp->d_name);
              //printf("after strcat tempDest=%s\n", tempDest);          
              strcat(tempSrc, direntp->d_name);
              copyFiles(tempSrc, tempDest);
                  strcpy(tempDest, destination);
              strcpy(tempSrc, source);            
          }
          }
          closedir(dir_ptr);
          return 1;
       }
    
    
    }
    
    
    int dostat(char *filename)
    {
        struct stat fileInfo;
        
        //printf("Next File %s\n", filename);
        if(stat(filename, &fileInfo) >=0)
        if(S_ISREG(fileInfo.st_mode))
          return 1;
        else return 0;
        
        return;
    }
    
    
    
    
    int copyFiles(char *source, char *destination)
    {
      int in_fd, out_fd, n_chars;
      char buf[BUFFERSIZE];
    
    
      /* open files */
      if( (in_fd=open(source, O_RDONLY)) == -1 )
      {
        oops("Cannot open ", source);
      }
    
    
      if( (out_fd=creat(destination, COPYMORE)) == -1 )
      {
        oops("Cannot creat ", destination);
      }
    
    
      /* copy files */
      while( (n_chars = read(in_fd, buf, BUFFERSIZE)) > 0 )
      {
        if( write(out_fd, buf, n_chars) != n_chars )
        {
          oops("Write error to ", destination);
        }
    
    
        if( n_chars == -1 )
        {
          oops("Read error from ", source);
        }
      }
    
    
        /* close files */
        if( close(in_fd) == -1 || close(out_fd) == -1 )
        {
          oops("Error closing files", "");
        }
    
    
        return 1;
    }
    
    
      void oops(char *s1, char *s2)
      {
        fprintf(stderr, "Error: %s ", s1);
        perror(s2);
        exit(1);
      }
    Enjoy

  2. #2
    Registered User
    Join Date
    Sep 2011
    Posts
    11
    How do I obtain the full path of the current directory I am in. Is there any system call for that? Trying to play with above program a little.

  3. #3
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    On *nix, getcwd().

    Make sure you read my next post tho, your program has a serious flaw!
    Last edited by MK27; 11-17-2011 at 10:47 AM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  4. #4
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    You do this a lot without allocating more space, which is very bad:

    Code:
          strcat(dest, "/");
          strcat(dest, src);
    Here dest is a pointer to one of main()'s argv parameters; you do something similiar with the same pointer again when it is copied into some of your functions. Would you consider this acceptable:

    Code:
    char eg[]="hello world,";
    strcat(eg, " okay, no space allocated for this!");
    If so, you do not understand arrays in C properly -- you should figure out or ask why this is wrong before you do ANYTHING else. If you do not fix this, eventually your program will start seg faulting (I'm surprised it doesn't now; very likely it will if you compile it on a machine with a slightly different compiler or architecture).

    If you do understand but had forgotten the issue of proper memory management because you are new to C, I'd suggest you use something like this:

    Code:
    #include <limits.h>
    
    [....]
    char dest[PATH_MAX+1];
    strcpy(dest, av[2]);
    PATH_MAX is a system constant found in limits.h on *nix systems. It represents the maximum length, in bytes, for an absolute file path. Ie, no filename including the path can possibly be longer than that (usually it is 4096). So if you are just building paths in there, it will be long enough to hold all your strcat's, etc.
    Last edited by MK27; 11-17-2011 at 10:44 AM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Creation of a Command Language Interpreter
    By Sicilian_10 in forum C Programming
    Replies: 18
    Last Post: 04-16-2010, 06:36 AM
  2. Simple copy command
    By Danieljax88 in forum C Programming
    Replies: 5
    Last Post: 04-01-2010, 04:04 PM
  3. How to hide command prompt using C language?
    By deob in forum C Programming
    Replies: 6
    Last Post: 03-24-2009, 08:17 PM
  4. copy command
    By munna_dude in forum C Programming
    Replies: 16
    Last Post: 06-20-2007, 11:12 PM
  5. C implementation of unix ls command
    By sinkovich in forum Linux Programming
    Replies: 0
    Last Post: 02-24-2003, 04:38 AM