首页 > 代码库 > 编写自己的cp命令
编写自己的cp命令
有时候要对整个目录做备份,修改cp1.c使得当两个参数都是目录时,把第一个目录中的所有文件复制到第二个目录中,文件名不变。那么该如何实现?
我们先来看看cp1.c的实现方式,它从一个文件中读取数据然后写到另一个文件中,通过系统调用open(或者creat)、read、wirte和close来完成。从上面我们看出,cp1.c只是针对于一个文件进行的复制操作,而现在我们需要完成对整个目录的备份。参数由一个单独的文件(file)变成一个目录(directory),所以我们首先想到的就是要先进入到这个目录下,然后对该目录下的文件依次进行cp操作,那么这就涉及到了目录的操作,而我们在第三章ls命令的实现过程中,用到的就是对目录的操作,涉及到的系统调用包含有opendir、readdir和closedir。所以现在我们需要把两者用到的技术联系起来,以便完成对目录的备份工作。
具体实现:
1、命令行参数
int argc、char *argv[]
2、cp源、目的的类型判断
src为dir,dst也必须是dir
src为file,dst可以是anything
3、目录操作
opendir进入src目录下;
while{
readdir获得当前目录下的文件(或目录),递归判断是否还是目录,如果是继续深入;
srcpath、dstpath获取,调用cp完成复制;
}
closedir完成目录复制
4、cp实现
in=open(src);out=creat(dst)
while{
read(in);
write(out);
}
close(in);close(out)
具体的代码如下:
1 /** cp1.c 2 * version 1 of cp - uses read and write with tunable buffer size 3 * 4 * usage: cp1 src dest 5 */ 6 #include <stdio.h> 7 #include <unistd.h> 8 #include <fcntl.h> 9 10 #define BUFFERSIZE 4096 11 #define COPYMODE 0644 12 13 void oops(char *, char *); 14 15 main(int ac, char *av[]) 16 { 17 int in_fd, out_fd, n_chars; 18 char buf[BUFFERSIZE]; 19 /* check args */ 20 if ( ac != 3 ){ 21 fprintf( stderr, "usage: %s source destination\n", *av); 22 exit(1); 23 } 24 /* open files */ 25 26 if ( (in_fd=open(av[1], O_RDONLY)) == -1 ) 27 oops("Cannot open ", av[1]); 28 29 if ( (out_fd=creat( av[2], COPYMODE)) == -1 ) 30 oops( "Cannot creat", av[2]); 31 32 /* copy files */ 33 34 while ( (n_chars = read(in_fd , buf, BUFFERSIZE)) > 0 ) 35 if ( write( out_fd, buf, n_chars ) != n_chars ) 36 oops("Write error to ", av[2]); 37 if ( n_chars == -1 ) 38 oops("Read error from ", av[1]); 39 40 /* close files */ 41 42 if ( close(in_fd) == -1 || close(out_fd) == -1 ) 43 oops("Error closing files",""); 44 } 45 46 void oops(char *s1, char *s2) 47 { 48 fprintf(stderr,"Error: %s ", s1); 49 perror(s2); 50 exit(1); 51 }
改进(添加目录判断)之后的具体实现:
1 /** cp2.c 2 ** ------------------------------------------------------------ 3 cp2.c is a 4 revised version of cp1.c that can copy an entire directory 5 file by file to a second directory. It also supports some 6 of the features required by earlier exercises. 7 8 ** ------------------------------------------------------------ 9 ** 10 ** 11 * A version of cp1.c that works if src or dest name directories 12 * (but not if src is a directory and dest is not) 13 * 14 * usage: cp1 src dest 15 * If dest names a directory, then copy src to dest/src 16 * If src names a directory, then copy all files in src to dest 17 * If src is a directory and dest is NOT a directory, quit 18 * Note: if src has a leading path, then only use last component 19 * 20 * build: cc sol03.14.c -o sol03.14 21 */ 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <unistd.h> 25 #include <fcntl.h> 26 #include <sys/stat.h> 27 #include <string.h> 28 #include <dirent.h> 29 30 #define BUFFERSIZE 4096 31 /* 32 * note: the real copy takes the mode of the copy from 33 * the mode of the source. 34 */ 35 #define COPYMODE 0644 36 37 void oops(char *, char *); 38 void *emalloc(size_t); 39 40 int 41 main(int ac, char *av[]) 42 { 43 if ( ac != 3 ){ 44 fprintf( stderr, "usage: %s source destination\n", *av); 45 exit(1); 46 } 47 48 /* 49 * if source is a dir, then the dest has to be, too 50 */ 51 52 if ( isadir(av[1]) ){ 53 if ( isadir(av[2]) ) 54 copydir(av[1], av[2]); 55 else { 56 fprintf(stderr,"cp1: %s is not a directory\n", av[2]); 57 exit(1); 58 } 59 } 60 /* 61 * if source is not a dir, then the dest can be anything 62 */ 63 else 64 do_copy( av[1], av[2] ); 65 return 0; 66 } 67 68 /* 69 * copydir() 70 * loops through all files in srcdir, copying each to destdir 71 * uses do_copy but builds the paths here 72 * Note: this function skips subdirectories of srcdir 73 */ 74 copydir(char *srcdir, char *destdir) 75 { 76 char *srcpath, *destpath; 77 DIR *dir_ptr; 78 struct dirent *direntp; 79 80 srcpath = (char *) emalloc(strlen(srcdir)+1+MAXNAMLEN+1); 81 destpath = (char *) emalloc(strlen(destdir)+1+MAXNAMLEN+1); 82 if ( (dir_ptr = opendir(srcdir)) == NULL ) 83 oops("Cannot open directory", srcdir); 84 85 /* 86 * loop through all items in src dir 87 * Do not copy directories, and report that so user 88 * realizes not all the items are copied. 89 */ 90 while( ( direntp = readdir(dir_ptr)) != NULL ) 91 { 92 sprintf(srcpath,"%s/%s", srcdir, direntp->d_name); 93 if ( isadir(srcpath) ){ 94 if ( strcmp(direntp->d_name,".") != 0 && 95 strcmp(direntp->d_name,"..") != 0 ) 96 printf("skipping directory %s\n", srcpath); 97 continue; 98 } 99 sprintf(destpath, "%s/%s", destdir, direntp->d_name); 100 do_copy( srcpath, destpath ); 101 } 102 closedir(dir_ptr); 103 free(srcpath); 104 free(destpath); 105 } 106 107 /* 108 * copies a file from src to dest 109 * If dest is a directory, then do_copy() copies to 110 * a file in dest with the name taken from the filename for 111 * src 112 */ 113 do_copy(char *src, char *dest) 114 { 115 int in_fd, out_fd, n_chars; 116 char buf[BUFFERSIZE]; 117 char *destfilename; 118 char *make_destfilename(char*,char*); 119 120 destfilename = make_destfilename(src, dest); 121 122 /* 123 * open files 124 */ 125 126 if ( (in_fd=open(src, O_RDONLY)) == -1 ) 127 oops("Cannot open ", src); 128 129 if ( (out_fd=creat( destfilename, COPYMODE)) == -1 ) 130 oops( "Cannot creat", destfilename); 131 132 /* 133 * copy files 134 */ 135 136 while ( (n_chars = read(in_fd , buf, BUFFERSIZE)) > 0 ) 137 if ( write( out_fd, buf, n_chars ) != n_chars ) 138 oops("Write error to ", destfilename); 139 if ( n_chars == -1 ) 140 oops("Read error from ", src); 141 142 /* 143 * close files 144 */ 145 146 if ( close(in_fd) == -1 || close(out_fd) == -1 ) 147 oops("Error closing files",""); 148 } 149 150 void oops(char *s1, char *s2) 151 { 152 fprintf(stderr,"Error: %s ", s1); 153 perror(s2); 154 exit(1); 155 } 156 157 /* 158 * if dest is a directory, then combine src and dest 159 * (see header to this program) 160 */ 161 162 char * 163 make_destfilename(char *src, char *dest) 164 { 165 struct stat info; 166 char *srcfilename; 167 char *rv; 168 169 if ( stat(dest, &info) == -1 ) /* let someone else handle this */ 170 return dest; 171 172 if ( ! S_ISDIR(info.st_mode) ) /* ok to copy to other types */ 173 return dest; 174 175 /* find last component of source name */ 176 if ( (srcfilename = strrchr(src, ‘/‘)) != NULL ) 177 srcfilename++; 178 else 179 srcfilename = src; 180 181 /* use that to construct target name */ 182 rv = emalloc(strlen(srcfilename) + strlen(dest) + 2); 183 sprintf(rv, "%s/%s", dest, srcfilename); 184 185 return rv; 186 } 187 188 void * 189 emalloc(size_t n) 190 { 191 void *rv = malloc(n); 192 if ( rv == NULL ) 193 oops("Out of memory",""); 194 return rv; 195 } 196 /* 197 * boolean: tells if arg names a directory 198 */ 199 isadir(char *str) 200 { 201 struct stat info; 202 203 return ( stat(str,&info) != -1 && S_ISDIR(info.st_mode) ); 204 }