C實現Linux中copy功能


 

/*
mycp.c
*/
#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>
#include<getopt.h>
#include<stdbool.h>

#define BUFFERSIZE 1024
#define COPYMORE 0644

/*用於處理從目錄文件復制到目錄文件的操作,傳入的參數應該是目錄路徑*/
int copyD2D(char *src, char *dest);

/*用於處理從文件復制到文件的操作,輸入的參數是文件名*/
int copyF2F(char *src, char *dest);

/*判斷filename是否是目錄名*/
bool isdir(char *filename);

/*字符串反轉*/
char *strrev(char *str);

/*main函數用於接收命令行傳進來的參數,並判斷是否符合規范。
然后根據不同的情況調用不同的子函數。*/
int main(int argc, char **argv)
{
    /*
    標記-r/-R選項,該選項代表遞歸復制文件夾
    標記-l選項,-l選項代表創建硬鏈接
    標記-s選項,-s選項代表創建符號鏈接
    */
    bool opt_r = false;
    bool opt_l = false;
    bool opt_s = false;

    /*
    用於記錄源文件
    用於記錄目標文件
    記錄選項的字符
    */
    char *src = NULL;
    char *dest = NULL;

    char c;

    /*循環檢測命令行參數中的選項*/
    while((c = getopt(argc, argv, "rRls")) != -1)
    {
        switch(c)
        {
            case 'R':
            case 'r':
                opt_r = true;
                break;

            case 'l':
                opt_l = true;
                break;

            case 's':
                opt_s = true;
                break;
        }
    }

    /*命令行參數中應該有兩個文件名。若沒有,則輸出提示,並終止程序*/
    if (optind >= argc - 1)
    {
        printf("lack operator \n");
        exit(1);
    }

    /*從命令行參數中讀取源文件和目標文件名*/
    src = argv[optind];
    dest = argv[optind + 1];

     /*根據opt_l選項的真假,做相應操作。
    若為真,則創建硬鏈接,使用link函數。*/
    if (opt_l)
    {
        if (isdir(src))
        {
            printf("dirent canot build hard linker\n");
            exit(1);
        }

        /*link 函數的返回值:若成功,則返回0;若出錯,返回-1*/
        if ((link(src, dest)) == 0)
        {
            return 0;
        }
        else
        {
            printf("create hard linker error\n");
            exit(1);
        }
    }

     /*根據opt_s選項的真假,做相應操作。
    若為真,則創建符號鏈接,使用symlink函數。*/
    if (opt_s)
    {
        if(isdir(src))
        {
            printf("dirent cannot create soft linker\n");
            exit(1);
        }
        
        if (symlink(src, dest) == 0)
        {
            return 0;
        }
        else
        {
            printf("create soft linker error\n");
            exit(1);
        }    
    }

    if (!isdir(src))
    {
        /*若源文件src不是目錄,直接調用copyF2F函數。*/
        if ((copyF2F(src, dest)) == 0)
        {
            return 0;
        }
        else
        {
            printf("copy file error\n");
            exit(1);
        }
    }
    else if(isdir(src))
    {
        if (!isdir(dest))
        {
            printf("Canot copy the dirent to a file\n");
            exit(1);
        }
        /*若源文件src和目標文件dest都是目錄,直接調用copyD2D函數。*/
        else if(isdir(dest) && opt_r)
        {
            if (copyD2D(src, dest) != 0)
            {
                printf("copy catalog error\n");
                exit(1);
            }
            else
            {
                return 0;
            }
        }
        else
        {
            printf("copy catalog need option -r\n");
            exit(1);
        }
    }
    else
    {
        printf("the operation is illegal\n");
        exit(1);
    }
    
    return 0;
}

/*該函數用於處理復制目錄的情況*/
int copyD2D(char *src_dir, char *dest_dir)
{
    DIR *dp = NULL;
    struct dirent *dirp;
    char tempDest[256];
    char tempSrc[256];
    strcpy(tempDest, dest_dir);
    strcpy(tempSrc, src_dir);

    /*使用opendir函數打開src_dir目錄,獲得指向該目錄名字的指針*/
    if ((dp = opendir(src_dir)) == NULL)
    {
        return 1;
    }
    else
    {
        while((dirp = readdir(dp)))
        {
            struct stat  file_stat;
            if (!isdir(dirp->d_name))
            {
                /*將dirent結構中的d_name成員變量鏈接到上級目錄字符串*/
                strcat(tempDest, dirp->d_name);
                strcat(tempSrc, dirp->d_name);

                 /*此處轉換為文件復制函數的方式處理目錄復制*/
                copyF2F(tempSrc, tempDest);

                /*通過字符串拷貝函數,將tempDest和tempSrc還原為上級的目錄名*/
                strcpy(tempDest, dest_dir);
                strcpy(tempSrc, src_dir);
            }
        }
        closedir(dp);
    }
    return 0;
}


/*該函數通過read,write等基本的系統函數,完成文件的拷貝工作*/
int copyF2F(char *src_file, char *dest_file)
{
    int in_fd, out_fd, n_chars;
    char buf[BUFFERSIZE];

    /*如果目標文件是一個目錄,那么默認是在該目錄下建立一個與源文件同名的文件*/
    if (isdir(dest_file))
    {
        char c;
        char temp[10] = {0};
        char *r_temp;
        int n = strlen(src_file);
        int m = 0;

        /*讀取源文件的最后一級文件名作為目標文件名*/
        while((c = src_file[n-1]) != '/')
        {
            temp[m] = c;
            m++;
            n--;
        }
        r_temp = strrev(temp);
        strcat(dest_file, r_temp);
    }
    
     /* 以可讀模式打開源文件 */
    if ((in_fd = open(src_file, O_RDONLY)) == -1)
    {
        printf("%s file read error!\n", src_file);
        return 1;
    }

    /* O_WRONLY代表以讀寫的方式打開目標文件,O_CREAT選項代表若文件不存在則創建,
    COPYMORE = 0644,文件所有者可讀可寫,其他可讀 */
    if ((out_fd = open(dest_file, O_WRONLY | O_CREAT, COPYMORE)) == -1)
    {
        return 1;
    }

    /* 通過read和write系統調用實現文件的復制 */
    while ((n_chars = read(in_fd, buf, BUFFERSIZE)) > 0)
    {
        if (write(out_fd, buf, n_chars) != n_chars)
        {
            printf("%s file write error!\n", src_file);
            return 1;
        }

        if (n_chars == -1)
        {
            printf("%s file read error!\n", src_file);
            return 1;
        }
    }

    if (close(in_fd) == -1 || close(out_fd) == -1)
    {
        printf("close file error\n");
        return 1;
    }

    return 0;
}


/*判斷filename是否為目錄文件*/
bool isdir(char *filename)
{
    struct stat fileInfo;
    if (stat(filename, &fileInfo) >= 0)
    {
        if (S_ISDIR(fileInfo.st_mode))
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

char *strrev(char *str)
{
    int i = strlen(str) - 1, j = 0;

    char ch;
    while(i > j)
    {
        ch = str[i];
        str[i] = str[j];
        str[j] = ch;
        i--;
        j++;
    }

    return str;
}

 

運行結果:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM