annotate nt/minitar.c @ 392:1f50e6fe4f3f r21-2-11

Import from CVS: tag r21-2-11
author cvs
date Mon, 13 Aug 2007 11:10:50 +0200
parents 03446687b7cc
children 8e84bee8ddd0 74fd4e045ea6 9d177e8d4150
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
327
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
1
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
2 /* Minitar: extract .tar.gz files on Win32 platforms.
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
3 Uses zlib for decompression.
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
4
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
5 This is very simple-minded, it ignores checksums, and any type of file
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
6 that is not a plain file or a directory. Nonetheless it is useful.
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
7
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
8 Author: Charles G. Waldman (cgw@pgt.com), Aug 4 1998
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
9
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
10 This file is placed in the public domain; you can
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
11 do whatever you like with it. There is NO WARRANTY.
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
12 If it breaks, you get to keep both pieces */
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
13
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
14
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
15 #include <stdio.h>
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
16 #include <Errno.h>
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
17
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
18 #include <zlib.h>
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
19
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
20 Usage(char *name)
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
21 {
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
22 fprintf(stderr,"Usage: %s file.tar.gz [base-dir]\n",name);
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
23 fprintf(stderr,"\tExtracts the contents compressed tar file to base-dir\n");
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
24 exit(-1);
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
25 }
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
26
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
27
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
28 #define BLOCKSIZE 512
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
29 #define MAXNAMELEN 1024
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
30
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
31 int octal(char *str)
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
32 {
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
33 int ret = -1;
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
34 sscanf(str,"%o",&ret);
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
35 return ret;
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
36 }
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
37
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
38 /* this is like mkdir -p, except if there is no trailing slash,
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
39 the final component is assumed to be a file, rather than a
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
40 path component, so it is not created as a directory */
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
41
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
42 int makepath(char *path)
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
43 {
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
44 char tmp[MAXNAMELEN];
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
45 char *cp;
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
46 extern int errno;
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
47
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
48 for (cp=path; cp; cp = (char*)strchr(cp+1,'/')){
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
49 if (!*cp)
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
50 break;
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
51 if (*cp != '/')
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
52 continue;
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
53 strncpy(tmp, path, cp-path);
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
54 tmp[cp-path] = '\0';
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
55 if (strlen(tmp) == 0)
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
56 continue;
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
57 if (mkdir(tmp,0777)){
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
58 if (errno == EEXIST)
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
59 continue;
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
60 else
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
61 return -1;
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
62 }
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
63 }
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
64 return 0;
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
65 }
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
66
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
67
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
68
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
69
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
70 main(int argc, char **argv)
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
71 {
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
72 char fullname[MAXNAMELEN];
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
73 char *basedir = ".";
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
74 char *tarfile;
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
75 char *cp;
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
76 int size;
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
77 char osize[13];
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
78 char name[101];
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
79 char magic[7];
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
80 char type;
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
81
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
82 gzFile *infile = (gzFile*)0;
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
83 FILE *outfile = (FILE*)0;
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
84
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
85 char block[BLOCKSIZE];
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
86 int nbytes, nread, nwritten;
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
87
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
88 int in_block = 0;
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
89 int directory = 0;
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
90
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
91 if (argc < 2 || argc > 3)
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
92 Usage(argv[0]);
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
93
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
94 tarfile = argv[1];
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
95 if (argc==3)
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
96 basedir = argv[2];
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
97
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
98 if (! (infile = gzopen(tarfile,"rb"))){
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
99 fprintf(stderr,"Cannot open %s\n", tarfile);
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
100 exit(-2);
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
101 }
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
102
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
103 while (1){
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
104
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
105
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
106 nread = gzread(infile,block,512);
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
107
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
108 if (!in_block && nread == 0)
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
109 break;
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
110
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
111 if (nread != BLOCKSIZE){
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
112 fprintf(stderr,"Error: incomplete block read. Exiting.\n");
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
113 exit(-2);
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
114 }
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
115
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
116 if (!in_block){
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
117 if (block[0]=='\0') /* We're done */
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
118 break;
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
119
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
120 strncpy(magic,block+257,6);
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
121 magic[6] = '\0';
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
122 if (strcmp(magic,"ustar ")){
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
123 fprintf(stderr,
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
124 "Error: incorrect magic number in tar header. Exiting\n");
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
125 }
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
126
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
127 strncpy(name,block,100);
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
128 name[100] = '\0';
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
129 sprintf(fullname,"%s/%s",basedir,name);
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
130 printf("%s\n",fullname);
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
131 type = block[156];
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
132
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
133 switch(type){
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
134 case '0':
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
135 case '\0':
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
136 directory = 0;
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
137 break;
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
138 case '5':
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
139 directory = 1;
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
140 break;
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
141 default:
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
142 fprintf(stderr,"Error: unknown type flag %c. Exiting.\n",type);
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
143 break;
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
144 }
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
145
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
146 if (directory){
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
147 in_block = 0;
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
148
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
149 /* makepath will ignore the final path component, so make sure
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
150 dirnames have a trailing slash */
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
151
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
152 if (fullname[strlen(fullname)-1] != '/')
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
153 strcat(fullname,"/");
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
154 if (makepath(fullname)){
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
155 fprintf(stderr, "Error: cannot create directory %s. Exiting.\n",
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
156 fullname);
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
157 exit(-2);
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
158 }
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
159 continue;
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
160 } else { /*file */
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
161 in_block = 1;
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
162 if (outfile){
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
163 if (fclose(outfile)){
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
164 fprintf(stderr,"Error: cannot close file %s. Exiting.\n",
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
165 fullname);
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
166 exit(-2);
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
167 }
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
168 outfile = (FILE*)0;
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
169 }
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
170
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
171 if ( !(outfile = fopen(fullname,"wb"))){
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
172 /*try creating the directory, maybe it's not there */
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
173 if (makepath(fullname)){
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
174 fprintf(stderr,"Error: cannot create file %s. Exiting.\n",
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
175 fullname);
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
176 exit(-2);
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
177 }
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
178 /* now try again to open the file */
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
179 if (!(outfile = fopen(fullname,"wb"))){
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
180 fprintf(stderr,"Error: cannot create file %s. Exiting.\n",
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
181 fullname);
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
182 exit(-2);
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
183 }
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
184 }
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
185
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
186 strncpy(osize,block+124,12);
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
187 osize[12] = '\0';
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
188 size = octal(osize);
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
189 if (size<0){
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
190 fprintf(stderr,"Error: invalid size in tar header. Exiting.\n");
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
191 exit(-2);
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
192 }
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
193 }
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
194 } else { /* write or continue writing file contents */
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
195 nbytes = size>512? 512:size;
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
196
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
197 nwritten = fwrite(block, 1, nbytes, outfile);
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
198 if (nwritten != nbytes){
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
199 fprintf(stderr, "Error: only wrote %d bytes to file %s. Exiting.\n",
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
200 nwritten, fullname);
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
201 }
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
202 size -= nbytes;
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
203 if (size==0)
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
204 in_block = 0;
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
205 }
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
206 }
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
207 }
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
208
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
209
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
210
03446687b7cc Import from CVS: tag r21-0-61
cvs
parents:
diff changeset
211