编写自己的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 }

时间: 2024-10-14 10:51:00

编写自己的cp命令的相关文章

cp&amp;tar&amp;用c语言编写程序 实现cp命令的效果

1.cp (拷贝) 已存在文件路径  要拷贝的文件路径 实现cp命令的代码如下: 2 #include <stdio.h> 3 4 //因为要在命令中得到两个路径,所以要用到main函数的两个参数 5 int main(int argc,char **argv){ 6 7 char buf[100]={0}; 8 9 int size=0; 10 /* int buf[100]={0} ; 代表数组里的单个存储区占四个字节. 如果我们从原始文件> 里拿出来的数据是3个字节,那么就放不进去

每天一个Linux命令(10)cp命令

cp命令用来将一个或多个源文件或者目录复制到指定的目的文件或目录.它可以将单个源文件复制成一个指定文件名的具体的文件或一个已经存在的目录下.cp命令还支持同时复制多个文件,当一次复制多个文件时,目标文件参数必须是一个已经存在的目录,否则将出现错误.     (1)用法: 用法: cp [选项]... [-T]   源文件    目标文件 或: cp  [选项]...         源文件...  目录 或: cp  [选项]... -t      目录         源文件...     (

关于cp命令中拷贝所有的写法

今天在编写一个脚本的时候,发现一个比较奇怪的问题:就是在使用cp拷贝当前目录下所有文件到目标目录的时候,源和目标目录大小不同.原来一直没有留意有这样的问题,后来查了些资料,才知道以前一直使用的格式有误,.一.预备cp就是拷贝,最简单的使用方式就是: cp oldfile newfile 但这样只能拷贝文件,不能拷贝目录,所以通常用: cp -r old/ new/ 那就会把old目录整个拷贝到new目录下.注意,不是把old目录里面的文件拷贝到new目录,而是把old直接拷贝到new下面,结果是

Linux命令篇之stat命令和cp命令

# stat: ls 命令可能是每一个Unix 使用者第一个学习的命令之一, 但它仅仅显示了 stat 命令能给出的信息的一小部分. stat 命令从文件的索引节点获取信息.正如你可能已经了解的那样, 每一个系统里的文件都存有三组日期和时间, 它们包括最近修改时间(即使用 ls -l 命令时显示的日期和时间), 最近状态改变时间(包括对文件重命名)和最近访问时间. 使用长列表模式查看文件信息, 你会看到类似下面的内容: 代码如下: $ ls -l trythis -rwx------ 1 shs

每天一个Linux命令(08)--cp命令

cp命令用来复制文件或者目录,是Linux系统中最常用的命令之一.一般情况下,shell会设置一个别名,在命令行下复制文件时,如果目标文件已经存在,就会询问是否覆盖,不管你是否使用-i参数.但是如果是在shell脚本中执行cp时,没有-i参数时不会询问是否覆盖.这说明命令行和shell脚本的执行方式有些不同. 1.命令格式: 用法: cp [选项] [-T] 源 目的 或:cp  [选项] 源 目录 或:cp  [选项] -t 目录 源 2.命令功能: 将源文件复制至目标文件,或将多个源文件复制

install命令和cp命令的区别

基本上,在Makefile里会用到install,其他地方会用cp命令. 它们完成同样的任务——拷贝文件,它们之间的区别主要如下: 1.最重要的一点,如果目标文件存在,cp会先清空文件后往里写入新文件,而install则会先删除掉原先的文件然后写入新文件.这是因为往正在使用的文件中写入内容可能会导致一些问题,比如说写入正在执行的文件可能会失败,比如说往已经在持续写入的文件句柄中写入新文件会产生错误的文件.而使用install先删除后写入(会生成新的文件句柄)的方式去安装就能避免这些问题了: 2.

cp 命令(转)

原文:http://www.cnblogs.com/peida/archive/2012/10/29/2744185.html cp命令用来复制文件或者目录,是Linux系统中最常用的命令之一.一般情况下,shell会设置一个别名,在命令行下复制文件时,如果目标文件已经存在,就会询问是否覆盖,不管你是否使用-i参数.但是如果是在shell脚本中执行cp时,没有-i参数时不会询问是否覆盖.这说明命令行和shell脚本的执行方式有些不同. 1.命令格式: 用法: cp [选项]... [-T] 源 

每天一个linux命令(8):cp 命令

cp 命令用来复制文件或者目录,是Linux系统中最常用的命令之一.一般情况下,shell会设置一个别名,在命令行下复制文件时,如果目标文件已经存在, 就会询问是否覆盖,不管你是否使用-i参数.但是如果是在shell脚本中执行cp时,没有-i参数时不会询问是否覆盖.这说明命令行和shell脚本的 执行方式有些不同. 1.命令格式: 用法: cp [选项]... [-T] 源 目的 或:cp [选项]... 源... 目录 或:cp [选项]... -t 目录 源... 2.命令功能: 将源文件复

cp命令总结

1.cp:顾名思义copy,用于拷贝文件或者文件夹到指定位置,也可以拷贝并重命名. 格式:cp source destination cp 源文件 目标文件 2.具体使用: cp -a 所有属性,包含drp的所有属性(文件的权限,属主,属组,时间戳,链接文件等).归档文件,保留属性.通常-a用于备份拷贝. [[email protected] tmp]# cp -a 1 2 [[email protected] tmp]# ll total 20 -rw-r--r--  1 root root