Linux 命令 "cp" 代码实现简介

本blog主要是模仿Linux的cp命令的功能,未实现参数,只是基础功能部分。
本文的主要目的在于练习 文件流目录流 中的函数的使用。

主要功能包括两种:

  • 源文件属性为文件,拷贝到其它文件(内容复制)或目录(作为目录子文件)
  • 源文件属性为目录,拷贝到其它目录(作为子目录存在)

其实现的流程图如下所示:
mark

本copy我们通过三个文件来实现:

  • main.c:流程的实现
  • copy.c:拷贝功能的实现
  • copy.h:必要的头文件
  1. main.c

    /*********************************************************
    * File name:
    * Description:
    * Author: Jimmy_Nie
    * Version Modify Time
    * v1.0 creat 2017-09-12
    *
    *********************************************************/

    include "copy_file.h"

    int main(int argc, char *argv[])
    {
    //Check the arguments
    if( 3 != argc)
    {
    printf("%s(%d): arguments error!\n",FILE, LINE);
    exit(EXIT_FAILURE);
    }

    //check the source file is a file or a directory
    struct stat src_stat;

    //destination file check
    struct stat dest_stat;

    //If source is a file
    if( FILES == check_file(argv[1], &src_stat) )
    {
    FILE_ENUM dest_enum;
    dest_enum = check_file( argv[2], &dest_stat );

    char cmd[100] = "";
    char ch;

    switch(dest_enum)
    {
    case NOT_EXIST:
    sprintf(cmd, "touch %s", argv[2]);
    system( cmd );

    check_file( argv[2], &dest_stat );
    cp_file(argv[1], argv[2], &dest_stat);

    break;

    case DIRECTORY:
    cp_file(argv[1], argv[2], &dest_stat);
    break;

    case FILES:
    fprintf(stdout, "Overwrite the dest file %s, [y/n]\n", argv[2]);
    ch = getchar();

    if( ch == 'Y' || ch == 'y' )
    {
    cp_file(argv[1], argv[2], &dest_stat);
    }
    else
    exit(0);

    break;
    default:
    fprintf(stderr, "%s(%d): file type error\n", FILE, LINE);
    }
    }

    //If source file is a directory
    else if( DIRECTORY == check_file(argv[1], &dest_stat) )
    {
    FILE_ENUM dest_enum;
    dest_enum = check_file( argv[2], &dest_stat );

    char cmd[100] = "";

    switch(dest_enum)
    {
    case NOT_EXIST:
    sprintf(cmd, "mkdir -p %s", argv[2]);
    system( cmd );
    cp_dir(argv[1], argv[2] );
    break;

    case DIRECTORY:
    cp_dir(argv[1], argv[2]);
    break;

    case FILES:
    fprintf(stderr, "Can't copy a directory to a file\n");
    exit(EXIT_FAILURE);
    break;

    default:
    fprintf(stderr, "%s(%d): file type error\n", FILE, LINE);
    break;
    }
    }

    return 0;
    }

  2. copy.c

    include "copy_file.h"

    FILE_ENUM check_file(char *var, struct stat *st)
    {
    if( stat(var, st) ) //if stat function error(renturn nonzero)
    {
    if( ENOENT == errno) //No such file or directory
    {
    return NOT_EXIST;
    }
    else
    {
    perror("stat");
    exit(EXIT_FAILURE);
    }
    }

    else // stat() ok, no error
    {
    //check file attr(dir or file)
    if( S_ISDIR(st->st_mode ))
    return DIRECTORY;
    else if( S_ISREG(st->st_mode) )
    return FILES;
    else
    {
    fprintf(stderr, "%s(%d):file type error", FILE , LINE);
    exit(EXIT_FAILURE);
    }
    }
    }

    //-----------------------------------------------------

    int cp_file(char *src_var, char *dest_var, struct stat *st)
    {
    FILE *src = NULL;
    FILE *dest = NULL;

    if( S_ISREG(st->st_mode) ) //if dest is file
    {
    //1. open src and dest file
    if( NULL == (src = fopen(src_var, "r")) )
    {
    perror("fopen");
    exit(EXIT_FAILURE);
    }

    if( NULL == (dest = fopen(dest_var, "w+")) )
    {
    perror("fopen");
    exit(EXIT_FAILURE);
    }

    //2. copy the context from src to dest
    char buf[1024];
    int num;

    while(1)
    {
    // if at the end of file or an error occured
    if( 1024 != (num = fread(buf, 1,1024, src)))
    {
    if( !feof(src))
    {
    perror("fread");
    exit(EXIT_FAILURE);
    }

    else
    {
    fwrite(buf, 1, num, dest);
    fclose(dest); //3. close dest file
    break;
    }
    }
    fwrite(buf, 1, 1024, dest);

    }

    //3. close src file
    fclose(src);
    return 0;
    }

    if( S_ISDIR(st->st_mode) )
    {
    char buf[100]="";

    //make the relative path to absolute path
    strncpy(buf, dest_var, sizeof(dest_var));
    strcat(buf, src_var);

    //if dest file doesn't exist, creat it first
    char cmd[100]="";
    sprintf(cmd, "touch %s",buf);
    system(cmd);

    struct stat new_dest_stat;

    if( stat(buf, &new_dest_stat))
    {
    perror("stat");
    exit(EXIT_FAILURE);
    }

    cp_file(src_var, buf, &new_dest_stat);
    }

    return 0;
    }

    //----------------------------------------------
    //if src file is a dir
    int cp_dir(char *src, char *dest)
    {
    DIR *dirp = NULL;

    //1. open the dir
    if( NULL == (dirp = opendir(src)) )
    {
    perror("opendir");
    exit(EXIT_FAILURE);
    }

    struct dirent *entp = NULL;

    //2. read the dir
    while( NULL != (entp = readdir(dirp))) //read the dir context
    {
    if( 0 == (strcmp(entp->d_name,"..")) || 0 == (strcmp(entp->d_name, ".")))
    {
    continue;
    }

    char src_buf[100] = "";
    char dest_buf[100] = "";

    sprintf(src_buf, "%s/%s\0", src, entp->d_name);
    sprintf(dest_buf, "%s/%s\0", dest, entp->d_name);

    struct stat src_stat;

    if( stat(src_buf,&src_stat) )
    {
    perror("stat");
    exit(EXIT_FAILURE);
    }

    if( S_ISREG(src_stat.st_mode) )
    {
    cp_file(src_buf, dest_buf, &src_stat);
    }

    else if( S_ISDIR(src_stat.st_mode) )
    {
    if( -1 == mkdir(dest_buf, src_stat.st_mode) )
    {
    perror("mkdir");
    exit(EXIT_FAILURE);
    }

    cp_dir(src_buf, dest_buf); //if subdir, recursive call itself
    }
    }

    return 0;
    }

  3. copy.h

    ifndef COPY_H

    define COPY_H

    include <stdio.h>

    include <unistd.h>

    include <sys/types.h>

    include <sys/stat.h>

    include <errno.h>

    include <string.h>

    include <dirent.h>

    include <stdlib.h>

    typedef enum
    {
    NOT_EXIST=1,
    DIRECTORY,
    FILES
    }FILE_ENUM;

    extern FILE_ENUM check_file(char *var, struct stat *st); //检查文件类型

    extern int cp_file(char *src_var, char *dest_var, struct stat *st); //copy文件

    extern int cp_dir(char *src, char *dest); //copy目录

    endif

posted @ 2017-09-12 14:20  Jimmy_Nie  阅读(5228)  评论(0)    收藏  举报