有时候要对整个目录做备份,修改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 }