首页 > 代码库 > 编写自己的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 }