声明:
1、由于笔者是初学Linux下的C编程,很多对于文件的操作还不是很习惯,所以代码的很多部分写的比较拙劣和冗长,如果此文有幸被您拜读,请不吝指正。本文全文为半香仙笛(Woody.c)原创
2、如果需要转载本文,请注明出处:http://blog.csdn.net/mcg890414/archive/2010/08/04/5787910.aspx
3、如果需要和笔者交流,请邮件至[email protected]
前言:学习乃循序渐进之过程,或深入浅出,或者由浅入深,或有所得,或有所失,但得必大于失,谓之曰:“长进” 也。
这个初步实现的拷贝命令,我断断续续写了有一天多,主要原因是初学,而且手上还有其他工作要做,总体查资料和写代码的时间差不多有5个小时左右,比较慢,不过这个过程中学到了不少东西,也认识到了自己之前的不少错误,现在还是果断把代码发上来,大家分享一下。
/* * File Info: * * WoodyCp.h * Composer : Woody * * Create Date : Aug-2nd-2010 * Last Modify : Aug-3rd-1020 * * Create Version : v1.0 * Current Version : v1.0 * * Composer's E-mail : [email protected] * Waiting For Ur Voice * * */ #ifndef _WOODY_CP_H_ #define _WOODY_CP_H_ // Head File Include #include
/* * File Info: * * WoodyCpOperating.h * Composer : Woody * * Create Date : Aug-2nd-2010 * Last Modify : Aug-3rd-1020 * * Create Version : v1.0 * Current Version : v1.0 * * Composer's E-mail : [email protected] * Waiting For Ur Voice * * */ #ifndef _WOODY_CP_OPERATING_H_ #define _WOODY_CP_OPERATING_H_ #define NOTING 0x00000000 #define ARCHIVE 0x00000001 #define BACKUP 0x00000002 #define B 0x00000004 #define COPYCONT 0x00000008 #define D 0x00000010 #define FORCE 0x00000020 #define INTERACTIVE 0x00000040 #define H 0x00000080 #define LINK 0x00000100 #define DEREFERENCE 0x00000200 #define NOCLOBBER 0x00000400 #define NODEREF 0x00000800 #define PRESERVE 0x00001000 #define SNOPRESERVE 0x00002000 #define PARENTS 0x00004000 #define RECURSIVE 0x00008000 #define REMOVEDEST 0x00010000 #define SPARSE 0x00020000 #define STRIP 0x00040000 #define SYMLINK 0x00080000 #define SUFFIX 0x00100000 #define TARGET 0x00200000 #define NOTARGET 0x00400000 #define UPDATE 0x00800000 #define VERBOSE 0x01000000 #define ONEFS 0x02000000 #define HELP 0x04000000 #define VERSIONCHK 0x08000000 #endif
/* * File Info: * * WoodyCpHelp.h * Composer : Woody * * Create Date : Aug-2nd-2010 * Last Modify : Aug-3rd-1020 * * Create Version : v1.0 * Current Version : v1.0 * * Composer's E-mail : [email protected] * Waiting For Ur Voice * * */ #ifndef _WOODY_CP_HELP_H_ #define _WOODY_CP_HELP_H_ #include "WoodyCp.h" // Some Macro are Defined here.. #define APPNAME "WoodyCp" #define VERSION "v1.0" void ShowHelp(void); void ShowVersion(void); #endif
/* * File Info: * * WoodyCpHelp.c * Composer : Woody * * Create Date : Aug-2nd-2010 * Last Modify : Aug-3rd-1020 * * Create Version : v1.0 * Current Version : v1.0 * * Composer's E-mail : [email protected] * Waiting For Ur Voice * * */ #include "WoodyCpHelp.h" void ShowHelp(void) { printf(" Usage: cp [option] ... [-T] source target file /n"); printf(" Or: cp [options] source ... directory ... /n"); printf(" Or: cp [option] ...-t directory source ... /n"); printf(" The source files to the target file, or copy multiple source files to the target directory. /n"); printf(" Long options must use the parameters necessary for the short option is used. /n"); printf(" /n"); printf(" -a, --archive mean-dR --preserve = all /n"); printf(" --backup [= CONTROL for each existing destination file to create a backup /n"); printf(" -b like --backup but does not accept the argument /n"); printf(" --copy-contents copy in the recursive processing is a special file contents /n"); printf(" -d equal to --no-dereference --preserve = links/n"); printf(" -f, --force if the target file will not open it to remove and try again (when the-n option /n"); printf(" There is no need for further elections this time)/n"); printf(" -i, --interactive Ask before overwrite (in front of the-n option to lapse) /n"); printf(" -H follow the source file in the command line symbolic links /n"); printf(" -l, --link link files instead of copying /n"); printf(" -L, --dereference always follow symbolic links /n"); printf(" -n, --no-clobber do not overwrite existing file (the-i option to the previous failure) /n"); printf(" -P, --no-dereference do not follow the symbolic link in the source file /n"); printf(" -p equal to - preserve = mode, ownership, timestamps /n"); printf(" --preserve[=attribute list to maintain the specified attributes (default: mode, ownership, timestamps), if /n"); printf(" May maintain additional attributes: environment, links, xattr, etc. /n"); printf(" --sno-preserve=attribute list does not preserve the specified attributes /n"); printf(" --parents in the target directory before copying the source file to create all the directory path /n"); printf(" -R, -r, --recursive copy directories for all projects within /n"); printf(" --remove-destination before trying to open the destination file to delete existing destination /n"); printf(" File (with the - force option for comparison) /n"); printf(" --sparse=WHEN control means to create sparse file /n"); printf(" --strip-trailing-slashes remove the parameter all
/* * File Info: * * WoodyCp.c * Composer : Woody * * Create Date : Aug-2nd-2010 * Last Modify : Aug-3rd-1020 * * Create Version : v1.0 * Current Version : v1.0 * * Composer's E-mail : [email protected] * Waiting For Ur Voice * * */ #include "WoodyCp.h" int main(int argc, char * argv[]) { /* Initlized WoodyCp */ if(0 != WoodyCp_Init(argc)) { printf(" WoodyCp: Initlized failed, ReInput /"WoodyCp/" to try again~ /n"); return -1; } /* missing operand, give failed running info, end with this.. */ if(argc <= 1) { printf(" WoodyCp: missing file operand/n Try /"WoodyCp --help/" to get more information. /n"); WoodyCpRelease(argc); return 1; } else if(argc == 2) { /* Check if the user is calling for some help info.. */ int uSR = seekCmd(argv[1]); if(HELP == uSR) { /* Give some help infomation to user ^_^ */ ShowHelp(); WoodyCpRelease(argc); return 0; } /* Check if the user is calling for the version info.. */ if(VERSIONCHK == uSR) { /* Give the user version info ^_^ */ ShowVersion(); WoodyCpRelease(argc); return 0; } /* Unknown CMD-line */ if('-' == argv[1][0] && 0 == seekCmd(argv[1])) { printf(" WoodyCp: invalid option -%s /n Try the /"WoodyCp --help/" to get more information. /n", argv[1]); WoodyCpRelease(argc); return 1; } /* OK Cmd-line */ if('-' == argv[1][0]) { printf(" WoodyCp: missing file operand/n Try /"WoodyCp --help/" to get more information. /n"); WoodyCpRelease(argc); return 1; } /* * At here, U can add some other case, all depends on U * Try more ~ * - Woody * */ /* end with target missing.. */ printf(" WoodyCp: the /"%s/" to action after missing the target file /n", argv[1]); printf(" Try the /"WoodyCp --help/" to get more information. /n"); WoodyCpRelease(argc); return 2; } int nGtPathRslt = GetFilePath(argc, argv); /* * Check the path-get return value * Knowing what happened * and telling the user how to correct his/her CMD-line * */ if(GnDstNotDir == nGtPathRslt) { printf("Target /"%s/" is not a directory /n", GszDst); WoodyCpRelease(argc); return 4; } else if(GnNoFileOpe == nGtPathRslt) { printf(" WoodyCp: missing file operand/n Try /"WoodyCp --help/" to get more information. /n"); WoodyCpRelease(argc); return 1; } else if(GnNoDstPath == nGtPathRslt) { printf(" WoodyCp: the /"%s/" to action after missing the target file /n", GsztblSrc[0]); printf(" Try the /"WoodyCp --help/" to get more information. /n"); WoodyCpRelease(argc); return 2; } else if(nGtPathRslt < 0) { int x = 0 - nGtPathRslt; printf(" WoodyCp: Unable to get /"%s/" of the file status (stat): No such file or directory", argv[x]); WoodyCpRelease(argc); return 2; } else if(0 < nGtPathRslt && nGtPathRslt < argc) { printf(" WoodyCp: invalid option -%s /n Try the /"WoodyCp --help/" to get more information. /n", argv[nGtPathRslt]); WoodyCpRelease(argc); return 1; } else if(nGtPathRslt > argc) { printf(" WoodyCp: Unable to get /"%s/" of the file status (stat): No such file or directory", argv[nGtPathRslt - argc]); WoodyCpRelease(argc); return 2; } if(0 != DoCopy()) { printf(" Copy Failed.. /n"); WoodyCpRelease(argc); return 3; } WoodyCpRelease(argc); return 0; } int WoodyCp_Init(int argc) { GnOperating = NOTING; GsztblSrc = (char **)malloc(argc * sizeof(char *)); /* Malloc Failed */ if(NULL == GsztblSrc) { return -1; } int i; for(i = 0; i < argc; i++) { GsztblSrc[i] = (char *)malloc(PATH_MAX * sizeof(char)); /* Malloc Failed */ if(NULL == GsztblSrc[i]) { return -1; } } GszDst = (char *)malloc(PATH_MAX * sizeof(char)); return 0; } /* Checking CMD line for opening some switch */ int seekCmd(char * szCmd) { if(0 == strcmp(szCmd, "-a") || 0 == strcmp(szCmd, "--archive")) { GnOperating += ARCHIVE; return GnOperating; } else if(0 == strcmp(szCmd, "--backup")) { GnOperating += BACKUP; return GnOperating; } else if(0 == strcmp(szCmd, "-b")) { GnOperating += B; return GnOperating; } else if(0 == strcmp(szCmd, "--copy-contents")) { GnOperating += COPYCONT; return GnOperating; } else if(0 == strcmp(szCmd, "-d")) { GnOperating += D; return GnOperating; }else if(0 == strcmp(szCmd, "-f") || 0 == strcmp(szCmd, "--force")) { GnOperating += FORCE; return GnOperating; } else if(0 == strcmp(szCmd, "-i") || 0 == strcmp(szCmd, "--interactive")) { GnOperating += INTERACTIVE; return GnOperating; } else if(0 == strcmp(szCmd, "-H")) { GnOperating += H; return GnOperating; } else if(0 == strcmp(szCmd, "-l") || 0 == strcmp(szCmd, "--link")) { GnOperating += LINK; return GnOperating; } else if(0 == strcmp(szCmd, "-L") || 0 == strcmp(szCmd, "--dereference")) { GnOperating += DEREFERENCE; return GnOperating; } else if(0 == strcmp(szCmd, "-n") || 0 == strcmp(szCmd, "--no-clobber")) { GnOperating += NOCLOBBER; return GnOperating; } else if(0 == strcmp(szCmd, "-P") || 0 == strcmp(szCmd, "--no-dereference")) { GnOperating += NODEREF; return GnOperating; } else if(0 == strcmp(szCmd, "-p") || 0 == strcmp(szCmd, "--preserve")) { GnOperating += PRESERVE; return GnOperating; } else if(0 == strcmp(szCmd, "--sno-preserve")) { GnOperating += SNOPRESERVE; return GnOperating; } else if(0 == strcmp(szCmd, "--parents")) { GnOperating += PARENTS; return GnOperating; } else if(0 == strcmp(szCmd, "-R") || 0 == strcmp(szCmd, "-r") || 0 == strcmp(szCmd, "--recursive")) { GnOperating += RECURSIVE; return GnOperating; } else if(0 == strcmp(szCmd, "--remove-destination")) { GnOperating += REMOVEDEST; return GnOperating; } else if(0 == strcmp(szCmd, "--sparse")) { GnOperating += SPARSE; return GnOperating; } else if(0 == strcmp(szCmd, "--strip-trailing-slashes")) { GnOperating += STRIP; return GnOperating; } else if(0 == strcmp(szCmd, "-s") || 0 == strcmp(szCmd, "--symbolic-link")) { GnOperating += SYMLINK; return GnOperating; } else if(0 == strcmp(szCmd, "-S") || 0 == strcmp(szCmd, "--suffix")) { GnOperating += SUFFIX; return GnOperating; } else if(0 == strcmp(szCmd, "-t") || 0 == strcmp(szCmd, "--target-directory")) { GnOperating += TARGET; return GnOperating; } else if(0 == strcmp(szCmd, "-T") || 0 == strcmp(szCmd, "--no-target-directory")) { GnOperating += NOTARGET; return GnOperating; } else if(0 == strcmp(szCmd, "-u") || 0 == strcmp(szCmd, "--update")) { GnOperating += UPDATE; return GnOperating; } else if(0 == strcmp(szCmd, "-v") || 0 == strcmp(szCmd, "--verbose")) { GnOperating += VERBOSE; return GnOperating; } else if(0 == strcmp(szCmd, "-x") || 0 == strcmp(szCmd, "--one-file-system")) { GnOperating += ONEFS; return GnOperating; } else if(0 == strcmp(szCmd, "--help")) { GnOperating += HELP; return GnOperating; } else if(0 == strcmp(szCmd, "--version")) { GnOperating += VERSIONCHK; return GnOperating; } /* Command no found, return 0 */ return 0; } int GetFilePath(int argc, char * argv[]) { /* * Since The last GszSrc[][] will be given to GszDst * We may try to start with -1 * and need not to minus it * */ GnSrcCount = -1; int i; for(i = 1; i < argc; i++) { /* Illegal command line, Treate it As an Error * If it's a legitimate command line * The GnOperating will remeber what to do * */ if('-' == argv[i][0] && 0 == seekCmd(argv[i])) { return i; } /* Here to treate every "UNCommand-Line" as file path, check it later */ else if('-' != argv[i][0]) { GnSrcCount++; strcpy(GsztblSrc[GnSrcCount], argv[i]); } } /* * As The argv is all given to GszSrc[][], * the last one should be given to GszDst[]. * * */ if(GnSrcCount >= 1) { GiveLastSrc2Dst(); } if(GnSrcCount >= 2) { if(0 != CheckDstDirAttr()) { return GnDstNotDir; } } int nSrcTblChkRs = CheckSrcTbl(); if(0 != nSrcTblChkRs) { if(nSrcTblChkRs > 0) { for(i = 0; i < argc; i++) { /* Get The bad argv No. which was treated as a good file path */ if(0 == strcmp(GsztblSrc[nSrcTblChkRs - 1], argv[i])) { break; } } /* * Return i plus argc for use... * this will seperate this kind of error with Illegal command line * */ return i + argc; } else // nSrcTblChkRs < 0 { nSrcTblChkRs = 0 - nSrcTblChkRs; for(i = 0; i < argc; i++) { /* Get The bad argv No. which was treated as a good file path */ if(0 == strcmp(GsztblSrc[nSrcTblChkRs], argv[i])) { break; } } return (0 - i); } } /* File path getting failed, return GnNoFileOpe */ if(-1 == GnSrcCount) { return GnNoFileOpe; } else if(0 == GnSrcCount) { return GnNoDstPath; } /* File path getting successfully, return 0 */ return 0; } /* Check the src table to see if there is some path or file IS unreachable */ int CheckSrcTbl(void) { int i; int nChkRs; for(i = 0; i < GnSrcCount; i++) { /* Try to open */ nChkRs = open(GsztblSrc[i], O_RDONLY); /* -r switch is open, check if it is an directory */ /* SORRY here for -r and other switch is not REALIZED yet ..*/ if(-1 == nChkRs && (GnOperating & RECURSIVE)) { struct stat dirinfo; stat(GsztblSrc[i], &dirinfo); if(S_IFDIR == (dirinfo.st_mode & S_IFMT)) { return (0 - i); } } else if(-1 == nChkRs) { return i + 1; } } return 0; } void GiveLastSrc2Dst(void) { /* Give And... */ strcpy(GszDst, GsztblSrc[GnSrcCount]); /* Flush it */ strcpy(GsztblSrc[GnSrcCount], ""); return; } int CheckDstDirAttr(void) { struct stat dst; stat(GszDst, &dst); /* See if it is a directory */ if(S_IFDIR == (dst.st_mode & S_IFMT)) { /* if do so, return 0 */ return 0; } /* Not dir, return -1 */ return -1; } int DoCopy(void) /* Core function */ { int i; int fSrc, fDst; int nSize; char szBuffer[10]; char szDstPath[PATH_MAX]; char szSrcFileName[PATH_MAX]; if(0 != (VERBOSE & GnOperating)) { printf("Copying File(s)... "); } /* Single File Copy Task... */ if(GnSrcCount == 1) { if(0 != (VERBOSE & GnOperating)) { printf("/nCopying "); printf("%s to %s", GsztblSrc[0], GszDst); } /* Acturally Do Copy HERE.. */ fSrc = open(GsztblSrc[0], O_RDONLY); /* * Check if the destnation is a directory, * then this can make sure destnation file path correct * */ if(0 == CheckDstDirAttr()) { GetSrcFileName(szSrcFileName, GsztblSrc[0]); strcpy(szDstPath, GszDst); strcat(szDstPath, "/"); strcat(szDstPath, szSrcFileName); fDst = open(szDstPath, O_WRONLY | O_CREAT, S_IREAD | S_IWRITE | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); } /* Only a file name (Can BE HERE ONLY in SINGLE-FILE task) */ else { fDst = open(GszDst, O_WRONLY | O_CREAT, S_IREAD | S_IWRITE | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); } /* Try to read a byte */ nSize = read(fSrc, szBuffer, 1); /* Keep Copying if sth. can be read out */ while(0 < nSize) { write(fDst, szBuffer, 1); nSize = read(fSrc, szBuffer, 1); } close(fSrc); close(fDst); if(0 != (VERBOSE & GnOperating)) { printf("/r/t/t/t/t/t/t/t/t[100%%/100%%-OK]"); } } /* Mutil-Files Copy Task... */ else { for(i = 0; i < GnSrcCount; i++) { if(0 != (VERBOSE & GnOperating)) { printf("/nCopying "); printf("%s to %s", GsztblSrc[i], GszDst); } /* Acturally Do Multi-Copy HERE.. */ fSrc = open(GsztblSrc[i], O_RDONLY); /* * Try to make sure file path correct * */ GetSrcFileName(szSrcFileName, GsztblSrc[i]); strcpy(szDstPath, GszDst); strcat(szDstPath, "/"); strcat(szDstPath, szSrcFileName); /* Create file can be read & write */ fDst = open(szDstPath, O_WRONLY | O_CREAT, S_IREAD | S_IWRITE | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); /* Here is same to the single task.. */ nSize = read(fSrc, szBuffer, 1); while(0 < nSize) { write(fDst, szBuffer, 1); nSize = read(fSrc, szBuffer, 1); } close(fSrc); close(fDst); /* Telling User it is successfully if -v switch is open */ if(0 != (VERBOSE & GnOperating)) { printf("/r/t/t/t/t/t/t/t/t[100%%/100%%-OK]"); } } } /* Give the last RETURN mark (make user confortablly reading) */ if(0 != (VERBOSE & GnOperating)) { printf("/n"); } return 0; } void GetSrcFileName(char * szSrc, char * szFilePath) { int i; /* Get to the last char of the path.. */ i = strlen(szFilePath); /* Get to the first char of the file name */ do { i--; }while(i >= 0 && szFilePath[i] != '/' && szFilePath[i] != '//'); /* Copy the file name and return it */ strcpy(szSrc, &szFilePath[i + 1]); return; } /* Release the alloced space */ int WoodyCpRelease(int argc) { int i; for(i = 0; i < argc; i++) { free(GsztblSrc[i]); } free(GsztblSrc); free(GszDst); return 0; }
代码已经贴完了,注释我用英语写的,方便不同的编码环境下阅读,本人CET-4得分两次404,相对来说不会用什么比较难的英语,所以读者们很大可放心阅读,应该没有单词障碍。
还是说说心得,由于在实验室的环境下,个人能力有限,我多次请教了周围的同学,如HXL,大家都给了我不少帮助,也促成了这个小工具的诞生,虽然它现在还没有GNU的cp那么完善,但是我相信这将会是一个很好的里程碑。