Linux cp command in C

This is a simple implementation of cp command in linux, if you are student in University of Adelaide who happens to take SPC course, please do not copy this code directly.
Code still can be optimized but I’m not gonna fix it since no mark will be given for coding style.

CP命令的C实现~


Compile:

gcc -o cp cp.c

参数可为 -i (confirmation)或 -r (dir to dir copy)

#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h> // for strtol
#include <libgen.h> //char *dirname(char *path); char *basename(char *path);
#include <string.h>
#include <dirent.h> //for DIR
#include <sys/stat.h> //S_ISREG
#include <sys/types.h>

#define COPYMODE 0644
typedef enum { false, true } bool;

void errExit(char*, char*);
void copyFile(char* formFile, char* toPath);
char* absolute_pathname(char* formFile, char* toPath);
void copyDir(char* source_path, char *destination_path);
int nextfile(char *filename);
int is_valid_folder(char *source);
char* str_joint(char* str1, char* str2);
int endwith(char* s, char c);

main(int argC, char* argV[])
{
  int i;
  char *dest_temp = malloc(sizeof(char) * 254);
  char str1[3], str2[2];
  bool interactive = false;
  bool recursive = false;
  DIR *dir_ptr = NULL;

  /* for file to file / file to dest */
  /*for more than 2 arguements*/
  if (argC > 2)
  {
    //rewrite loop for -i and -r option
    for (i = 1; i < argC – 1; i++)
    {
      if (strcmp(argV[i], "-i") == 0)
      {
        fprintf(stderr, "copy %s? (y/n[n])", dest_temp);
        scanf("%s", str1);
        if (strcmp(str1, "y") == 0 || strcmp(str1, "Y") == 0)
        {
          interactive = false;
        }
        else
        {
          interactive = true;
          fprintf(stderr, "User canceled this copy");
          exit(1);
        }
      }
      if (strcmp(argV[i], "-r") == 0)
      {
        recursive = true;
      }
    }
    if (recursive == false)
    {
      for (i = 1; i < argC – 1; i++)
      {
        strcpy(dest_temp, argV[argC – 1]);
        if (interactive == false)
        {
          if (is_valid_folder(argV[i]) == 1)
          {
            fprintf(stderr, "Skipping directory %s\n", argV[i]);
            continue;
          }
          else
          {
            strcat(dest_temp, "/");
            copyFile(argV[i], dest_temp);
          }
        }
      }
    }
    else //recursive == true (DIR TO DIR)
    {
      //Error Check
      for (i = 1; i < argC – 1; i++) {
        strcpy(dest_temp, argV[argC – 1]); if (strcmp(argV[i], "-i") != 0 && strcmp(argV[i], "-r") != 0) {
          if (is_valid_folder(argV[i]) == 1) //folder, try file. { if (!endwith(dest_temp, "/")) strcat(dest_temp, "/"); strcat(dest_temp, basename(argV[i])); strcat(dest_temp, "/"); copyDir(argV[i], dest_temp); } else { /*strcat(dest_temp, "/");*/ copyFile(argV[i], dest_temp); } } } } } else exit(1); free(dest_temp); exit(0); } void errExit(char* s1, char* s2) { fprintf(stderr, "Error: %s ", s1); perror(s2); exit(1); } //get file name and add end of to toPath if no filename specified char* absolute_pathname(char* formFile, char* toPath) { if (endwith(toPath, "/") == 0) { strcat(toPath, "/"); } return strcat(toPath, basename(formFile)); } void copyFile(char* formFile, char* toPath) { char* size = "4096"; int srcFd; int dstFd; int charCnt; int buffersize = strtol(size, NULL, 10); char buf[buffersize]; char* finalpath; /*Check args*/ /* if (argC != 4) { fprintf(stderr, "usage: %s fromDir toDir\n", argV[0]); exit(1); } */ /*Open the files*/ srcFd = open(formFile, O_RDONLY); if (srcFd == -1) { errExit("Cannot open ", formFile); } dstFd = creat(toPath, COPYMODE); if (dstFd == -1) { finalpath = absolute_pathname(formFile, toPath); //fprintf(stderr, "FINALPATH:%s\n", finalpath); dstFd = creat(finalpath, COPYMODE); if (dstFd == -1) { errExit("No working path", finalpath); } } else finalpath = toPath; /*Copy the data*/ while ((charCnt = read(srcFd, buf, buffersize)) > 0) {
            if (write(dstFd, buf, charCnt) != charCnt) {
              errExit("Write error to ", finalpath);
            }
        }
        if (charCnt == -1) {
          errExit("Read error from ", finalpath);
        }

        /*Close files*/
        if (close(srcFd) == -1 || close(dstFd) == -1) {
          errExit("Error closing files", "");
        }
      }

      int nextfile(char *filename)
      {
        struct stat fileInfo;
        if (stat(filename, &fileInfo) >= 0)
          if (S_ISREG(fileInfo.st_mode))
            return 1;
          else return 0;
          return;
      }

      int is_valid_folder(char* path) {
        struct stat st;
        stat(path, &st);
        if (S_ISDIR(st.st_mode)) {
          return 1;
        }
        else {
          return 0;
        }
      }

      int endwith(char* s, char c)
      {
        if (s[strlen(s) – 1] == c)
        {
          return 1;
        }
        else
        {
          return 0;
        }
      }

      /*str1+str2*/
      char* str_joint(char* str1, char* str2) {
        char* result;
        result = (char*)malloc(strlen(str1) + strlen(str2) + 1);
        if (!result) {
          printf("Malloc failed~\n");
          exit(1);
        }
        strcat(result, str1);
        strcat(result, str2);
        return result;
      }

      void copyDir(char* source_path, char *destination_path)
      {
        if (!opendir(destination_path))
        {
          if (mkdir(destination_path, 0777))
          {
            errExit("Creating destination %s failed!", destination_path);
          }
        }
        char *path;
        path = (char*)malloc(512);
        path = str_joint(path, source_path);
        struct dirent* filename;
        DIR* dp = opendir(path);
        while (filename = readdir(dp))
        {
          memset(path, 0, sizeof(path));
          path = str_joint(path, source_path);
          char *file_source_path;
          file_source_path = (char*)malloc(512);
          if (!endwith(source_path, ‘ / ’))
          {
            file_source_path = str_joint(file_source_path, source_path);
            file_source_path = str_joint(source_path, "/");
          }
          else
          {
            file_source_path = str_joint(file_source_path, source_path);
          }
          char *file_destination_path;
          file_destination_path = (char*)malloc(512);
          if (!endwith(destination_path, ‘ / ’))
          {
            file_destination_path = str_joint(file_destination_path, destination_path);
            file_destination_path = str_joint(destination_path, "/");
          }
          else
          {
            file_destination_path = str_joint(file_destination_path, destination_path);
          }

          file_source_path = str_joint(file_source_path, filename->d_name);
          file_destination_path = str_joint(file_destination_path, filename->d_name);
          if (is_valid_folder(file_source_path))
          {
            if (!endwith(file_source_path, ‘.’))
            {
              copyDir(file_source_path, file_destination_path);
            }
          }
          else
          {
            copyFile(file_source_path, file_destination_path);
            fprintf(stderr, "Successfully Copied %s to %s \n", file_source_path, file_destination_path);
          }
        }
      }
    }
  }
}


References:

http://man7.org/linux/man-pages/man1/basename.1.html
http://man7.org/linux/man-pages/man3/basename.3.html
http://stackoverflow.com/questions/19342155/how-to-store-characters-into-a-char-pointer-using-the-strcpy-function
http://stackoverflow.com/questions/3365569/comparing-command-parameter-with-argv-is-not-working
https://cboard.cprogramming.com/c-programming/143382-implementation-linux-cp-copy-command-c-language.html
http://www.cplusplus.com/reference/cstring/strncat/
http://blog.csdn.net/habbyge/article/details/18086311

 

Leave a Reply

Your email address will not be published. Required fields are marked *