/* 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; }
運行結果: