lose the generated ps files
[debian/dds2tar] / dds_extract.c
1
2 /*
3  * This file is part of dds2tar.
4  * Copyright by J"org Weule
5  */
6
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <sys/mtio.h>
10 #include <string.h>
11 #include <unistd.h>
12
13 /*
14  * fnmatch() and FNM_LEADING_DIR
15  */
16 #define _GNU_SOURCE 1
17 #include <fnmatch.h>
18
19 #include "dds2tar.h"
20 #include "dds_tape.h"
21
22 /*
23  * Compare two strings
24  *
25  */
26 int dds_strcmp(const char*n1,const char*n2){
27         int i = 0 ;
28         int j = 0 ;
29         while ( 1 ){
30                 while ( n1[i] == '\\' ) i++ ;
31                 while ( n2[j] == '\\' ) j++ ;
32                 if ( i > 90 || j > 90 || n1[i] == '\0' || n2[j] == '\0' )
33                         return 0 ;
34                 if  ( n1[i] != n2[j] ) return 1 ;
35                 i++ ;
36                 j++ ;
37         }
38         return 0 ;
39 }
40
41 /*
42  * To count the number of blocks written, we use the variable nblocks.
43  */
44 static int nblocks = 0;
45
46 /*
47  * Fill the buffer 'cur_block' the block of the given number.
48  * first we check the block number of the copy that is hold inside the
49  * buffer cur_block.
50  */
51 static int
52 set_cur_block(int const sb)
53 {
54         int     n;
55
56 #ifdef DDS_TRACE
57         fprintf(stderr,"%d\n",__LINE__);
58         fprintf(stderr, "set_cur_block(%d)\n", sb);
59 #endif
60
61         if (sb != cur_blkno) {
62                 /*
63                  * We have to read the block.
64                  */
65                 next_blkno = dds_getpos(device);
66                 /*
67                  * next_blkno stores now the number of the next block of the
68                  * tape.
69                  */
70                 n = sb - next_blkno;
71                 /*
72                  * In some cases reading is faster then seeking.
73                  */
74                 if ((n > 0) && (n < DONT_SKIP)) {
75                         do {
76                                 dds_read_block();
77                         } while ((--n) > 0);
78                 }
79                 /*
80                  * Now we should be at the position.
81                  */
82                 n = sb - next_blkno;
83                 if (n != 0) {
84                         dds_seek(device, sb);
85                         next_blkno = sb;
86                 }
87                 /*
88                  * Now we read the block. cur_n == 0 indicates a filemark.
89                  */
90                 dds_read_block();
91         }
92         return 0;
93 }
94
95 /*
96  * procedure to extract the files from the specified area (sb:sr-eb:er).
97  * If area is of the form (sb:sr-0:0), the file at position (sb,sr) is
98  * extracted. The length of the file is read from the tar header record.
99  *
100  * If list_only is set to 1, only the name of the extraction is printed.
101  */
102 static int
103 extract(char const *const name, int const sb, int const sr)
104 {
105
106         int     cur_rec, n, size;
107         char   *p;
108
109 #ifdef DDS_TRACE
110         fprintf(stderr,"%d\n",__LINE__);
111         fprintf(stderr, "extract(%s,%d,%d)\n", name, sb, sr);
112 #endif
113
114         /*
115          * Print only the name.
116          */
117         if (list_only == 1) {
118                 printf("%7d%3d: %s\n", sb, sr, name);
119                 return 0;
120         }
121         /*
122          * Print the filename and the location for verbose output.
123          */
124         if (verbose != 0) {
125                 fprintf(stderr,
126                         "dds2tar at rec %d: %7d%3d: %s\n",
127                         nblocks, sb, sr, name);
128         }
129         /*
130          * Check the buffer for the right tape block.
131          */
132         set_cur_block(sb);
133
134         cur_rec = sr;
135         /*
136          * Check the header block.
137          * The Name field should contain the given name.
138          * The Program will stop if its not.
139          *
140          * Note that for links we can only compare the first
141          * characters, when the index contains somethins like
142          * 'linkname -> filename' (soft link) or
143          * 'linkname link to filename' (hard link)
144          * doesn't match 'linkname'.
145          */
146         p = (char*) (cur_block + cur_rec) ;
147         if ( dds_is_tar_header_record((tar_record*)p) == 0 ) {
148                 fprintf(stderr,
149                         " dds2tar: FATAL ERROR\n"
150                         " dds2tar: header expected, not found\n"
151                 );
152                 if ( force_nochk == 0 ) exit(5);
153         }
154         if (name != NULL)
155         if ( ( (dds_strcmp(name, p)!=0 )
156                 && (((tar_record*)p)->hdr.linkflag!='2')
157                 && (((tar_record*)p)->hdr.linkflag!='1')
158                 ) || ( strstr(name, p)!=name ) ) {
159                 fprintf(stderr,
160                         "dds2tar: FATAL ERROR\n"
161                         "dds2tar: Looked for %s at %d %d\n"
162                         "dds2tar: Could not find %s at %d %d.\n"
163                         "dds2tar: Found %s\n"
164                         "dds2tar: Link flag: %c\n"
165                         "dds2tar: Is it the right tape?\n",
166                         name, sb , sr ,
167                         name, dds_getpos(device) - 1, cur_rec,p,
168                         ((tar_record*)p)->hdr.linkflag);
169                 if ( force_nochk == 0 ) exit(5);
170         }
171         /*
172          * First calculate the number of records of the object.
173          */
174         size = 0;
175         n = 1;
176
177         p = cur_block[cur_rec].hdr.size;
178         if (*p != '\0') {
179                 sscanf(p, "%o", &size);
180                 n = size;
181                 n += 1023;
182                 n >>= 9;
183         }
184         /*
185          * Now write the records to stdout.
186          */
187         if (verbose) {
188                 fprintf(stderr,
189                         "dd2tar: %s needs %d blocks\n", name, n);
190         }
191         if ( write_body == 1 ) {
192                 cur_rec++;
193                 while ((size > 0) && (cur_n > 0)) {
194                         if (cur_rec >= cur_bs) {
195                                 dds_read_block();
196                                 cur_rec = 0;
197                         }
198                         write(1, cur_block + cur_rec, (size>=512)? 512:size );
199                         size -= 512 ;
200                         cur_rec++;
201                 }
202                 exit(0);
203         }
204         while ((n > 0) && (cur_n > 0)) {
205                 if (cur_rec >= cur_bs) {
206                         dds_read_block();
207                         cur_rec = 0;
208                 }
209                 write(1, cur_block + cur_rec, 512);
210                 nblocks++;
211                 n--;
212                 cur_rec++;
213         }
214         return 0;
215 }
216
217 #ifdef EXP_STUFF
218 int
219 extract_loc(char const *const *loc_list)
220 {
221         int cur_rec ;
222
223         while (*loc_list != NULL) {
224                 int     eb, er, sb, sr;
225
226                 sscanf(*loc_list, "%u:%u-%u:%u", &sb, &sr, &eb, &er);
227                 set_cur_block(sb);
228                 cur_rec = sr ;
229                 while (cur_n > 0) {
230                         int     i;
231
232                         if ((cur_n & 0x1ff) != 0) {
233                                 fprintf(stderr,
234                                         "tape record size (%d) is not a"
235                                         " multiple of tar records\n"
236                                         , cur_n
237                                         );
238                                 close(device);
239                                 exit(6);
240                         }
241                         i = cur_n >> 9;
242                         if (cur_blkno == eb)
243                                 i = er;
244                         while (cur_rec < i) {
245                                 write(1, cur_block + cur_rec++, 512);
246                                 nblocks++;
247                         }
248                         /*
249                          * if eb==-1 extract until eof
250                          */
251                         if ((cur_rec == er && cur_blkno == eb))
252                                 break;
253                         i = cur_blkno + 1;
254                         cur_rec = 0;
255                         if ((cur_rec == er && cur_blkno == eb))
256                                 break;
257                         dds_read_block();
258                 }
259                 loc_list++;
260         }
261         return 0;
262 }
263
264 #endif
265
266 /*
267  * Now we are scanning the table of contents (index file) and match the
268  * pathnames there with the given pattern. If a pattern matches, we
269  * extract the parent directories (dir_extract()) and the file.
270  */
271 int
272 dds_cmp(char const *const *const pattern_list)
273 {
274         int i ;
275         char *fgets_return_value ;
276         char const *const *p;
277         int so = 0 ; /*scanoffset*/
278
279         /*
280          * To scan the line of the table of contents (index file)
281          * we need some variables.
282          */
283         char   *name = NULL;
284         int     blkno, recno, size;
285
286         /*
287          * List of directories entries.
288          */
289         struct dir_list {
290                 char    n[128-2*sizeof(int)];   /* name of the dir */
291                 int     b, r;   /* block address */
292         }
293                *dl;
294         int     de = 0;         /* first empty list entry */
295
296         /*
297          * Format of the table of contents.
298          *      dds2index --> tar_index_file == 0
299          *      tar -Rvt  --> tar_index_file == 1
300          */
301         int     tar_index_file = 1;
302
303         /*
304          * Bug fix for tar. First record number found inside the
305          * table of contents (index file).
306          */
307         int     tar_first_recno = -1;
308
309 #ifdef DDS_TRACE
310         fprintf(stderr,"%d\n",__LINE__);
311         fprintf(stderr,"dds_cmp(%s ...)\n",*pattern_list);
312 #endif
313
314
315         /*
316          * First we need some memory.
317          */
318         dl = malloc(sizeof (*dl) * 64);
319         if (dl == NULL) {
320                 close(device);
321                 fprintf(stderr, "dds2tar: no address space available\n");
322                 exit(7);
323         }
324         memset(cur_line, 0, 1024);
325
326         /*
327          * Scan the table of conten|s (index file) until eof.
328          */
329 #ifdef DDS_TRACE
330         fprintf(stderr,"%d\n",__LINE__);
331 #endif
332         while (!feof(index_fp)) {
333                 fgets_return_value = fgets(cur_line, MAXPATHLEN<<2, index_fp);
334                 if ( fgets_return_value == NULL ) {
335                         if ( feof(index_fp) ) {
336                                 break ;
337                         } else {
338                                 perror("dds2tar");
339                                 exit(1);
340                         }
341                 }
342 #ifdef DDS_TRACE
343                 fprintf(stderr,"%d\n",__LINE__);
344                 fputs(cur_line, stderr);
345 #endif
346
347                 /*
348                  * Check for comment and empty lines.
349                  */
350                 if ((*cur_line == '#') ||
351                     (*cur_line == ' ') ||
352                     (*cur_line == '\0'))
353                         continue;
354
355                 /*
356                  * Check the line for location information.
357                  */
358 #ifdef DDS_TRACE
359         fprintf(stderr,"%d\n",__LINE__);
360 #endif
361                 if (0 == rt_loc_line())
362                         continue;
363
364                 /*
365                  * Check for the first line of the dds2index.
366                  */
367                 if ((0 == strcmp(cur_line, dds_headline)) 
368                 || (0 == strcmp(cur_line, dds_old_headline))) {
369                         tar_index_file = 0;
370                         tar_n = buf_n ;
371                         tar_bs = buf_n >> 9 ;
372                         if ( vid != HP ) dds_set_bs(tar_n);
373                         continue;
374                 }
375 #ifdef DDS_TRACE
376                 fprintf(stderr,"%d\n",__LINE__);
377 #endif
378
379                 /*
380                  * dds2index indicates eof with the string '-end-'.
381                  * This line has to be processed in the normal way.
382                  * We can stop now processing.
383                  */
384                 if ((*cur_line == '-') &&
385                     (strncmp(cur_line, "-end-", 5) == 0)) {
386 #ifdef DDS_TRACE
387                         fprintf(stderr,"%d\n",__LINE__);
388 #endif
389                         break;
390                 }
391
392                 /*
393                  * Scan the line of the index.
394                  * Note: The index file of dds2index contains the magic string
395                  *   of the tar header, witch depends on the used tar version.
396                  */
397                 if (tar_index_file == 0) {
398                         rt_line(&blkno, &recno, &size, &name);
399                 } else {
400                         /*
401                          * check for record line
402                          */
403                         if ((0 != strncmp(cur_line, "rec", 3)) &&
404                            (0 != strncmp(cur_line, "block", 5)))
405                                 continue;
406
407                         /*
408                          * cook the input line and delete all the quoted
409                          * characters.
410                          */
411                         dds_unquote(cur_line);
412
413                         if (0 == strncmp(cur_line, "block ", 6))
414                         {
415                                 int x;
416                                 int n;
417                                 char c;
418
419                                 so = 6;
420                                 if (2 == sscanf(cur_line + so, "%d%c%n",
421                                                 &x, &c, &n)) {
422                                         so += n + 1;
423                                         recno = x;
424 #ifdef DDS_TRACE
425                                         fprintf(stderr,"Blocks found:%d\n",x);
426 #endif
427                                 }
428                                 else
429                                 {
430                                         recno = 0;
431                                 }
432                         }
433                         else
434                         {
435                                 int x;
436                                 int n;
437                                 char c;
438
439                                 recno = atoi(cur_line + 4);
440
441                                 so = 16;
442                                 if ( 2 == sscanf(
443                                         cur_line+so,"block %d%c%n",&x,&c,&n
444                                         ) && c == ':' ) {
445                                         so += n + 1 ;
446                                         recno = x ;
447 #ifdef DDS_TRACE
448                                         fprintf(stderr,"Blocks found:%d\n",x);
449 #endif
450                                 }
451                         }
452
453                         /*
454                          * Now we are fixing a bug of gnu tar ...
455                          * The first number should be zero, othewise we
456                          * correct all the numbers.
457                          * If tar_first_recno is .lt. zero, no recno is read
458                          * up to now.
459                          */
460                         if (tar_first_recno < 0)
461                                 tar_first_recno = recno;
462                         recno -= tar_first_recno;
463                         /*
464                          * Calculate the block number of the record.
465                          */
466 #ifdef DDS_TRACE
467                         fprintf(stderr,"file-loc(%d,%d)\n",recno,tar_fb);
468 #endif
469                         blkno = recno / tar_bs;
470                         recno -= blkno * tar_bs;
471                         if ( vid != HP ) blkno *= tar_bs ;
472 #ifdef DDS_TRACE
473                         fprintf(stderr,"file-loc(%d:%d,%d)\n",tar_bs,blkno,recno);
474 #endif
475                         blkno += tar_fb;
476 #ifdef DDS_TRACE
477                         fprintf(stderr,"file-loc(%d:%d,%d)\n",tar_bs,blkno,recno);
478 #endif
479
480                         /* skip file permissions */
481                         name = strchr(cur_line + so, ' ');
482                         if (name) {
483                           /* skip owner/group */
484                           name = strchr(name + 1, ' ');
485                           if (name) {
486                             /* skip size */
487                             while (*++name == ' ');
488                             name = strchr(name, ' ');
489                             if (name) {
490                               /* skip date */
491                               name = strchr(name + 1, ' ');
492                               if (name) {
493                                 /* skip time */
494                                 name = strchr(name + 1, ' ');
495
496                                 if (name) {
497                                   ++name;
498                                 }
499                               }
500                             }
501                           }
502                         }
503
504                         if (!name || (name[-4] != ':'))
505                         {
506                           name = cur_line + so;
507                         }
508
509 #ifdef DDS_TRACE
510                         fprintf(stderr,"%d\n",__LINE__);
511                         fprintf(stderr,"filename=%s\n",name);
512 #endif
513                 }
514 #ifdef DDS_TRACE
515                 fprintf(stderr,"%d\n",__LINE__);
516 #endif
517                 i = strlen(name) -1 ;
518                 if (name[i] == '\n') name[i] = '\0', i-- ;
519                 /*
520                  * We leave the list of directories empty on quick mode.
521                  */
522                 if (( name[i] == '/' )&&( quick_mode == 0 )) {
523                         struct dir_list *dp;
524                         for (i = 0 , dp = dl ; i < de; i++ , dp ++ ) {
525                                 if (strstr(name, dp->n) != name)
526                                         break;
527                         }
528                         strcpy(dp->n, name);
529                         dp->b = blkno;
530                         dp->r = recno;
531                         de = i + 1 ;
532                 }
533                 /*
534                  * Now we try to match one pattern with the name.
535                  */
536 #ifdef DDS_TRACE
537                 fprintf(stderr,"%d\n",__LINE__);
538                 fprintf(stderr,"scanning pattern list for '%s'\n",name);
539 #endif
540                 p = pattern_list;
541                 while (*p != NULL) {
542                         static int ll_blkno = -1 ;
543                         static int ll_recno = -1 ;
544                         static int ln_blkno = -1 ;
545                         static int ln_recno = -1 ;
546                         static const char *ll = "././@LongLink" ;
547 #ifdef DDS_TRACE
548                         fprintf(stderr," p = '%p' , *p = %p \n",p,*p);
549 #endif
550                         /*
551                          * Thanks Andreas Bagge for this trick.
552                          * I use the fnmatch function from the
553                          * source of gnu tar.
554                          */
555 #ifdef DDS_TRACE
556                         fprintf(stderr,"fnmatch '%s' for '%s'\n",name,*p);
557 #endif
558                         if (0 == fnmatch(*p, name, FNM_LEADING_DIR)) {
559                                 struct dir_list *dp;
560                                 for (i = 0, dp = dl; i < de; i++, dp++) {
561                                         char   *p = strstr(name, dp->n);
562                                         if (p == name) {
563                                                 extract(dp->n, dp->b, dp->r);
564                                         } else break ;
565                                 }
566                                 de = 0;
567                                 if ( ln_blkno >= 0 ) extract(
568                                                 "././@LongLink",
569                                                 ln_blkno,
570                                                 ln_recno);
571                                 if ( ll_blkno >= 0 ) extract(
572                                                 "././@LongLink",
573                                                 ll_blkno,
574                                                 ll_recno);
575                                 extract(name, blkno, recno);
576                                 break;
577                         }
578                         if ( 0==strncmp(ll,name,strlen(name)) ){
579                                 if ( ln_blkno < 0 )
580                                 ln_blkno = blkno , ln_recno = recno ;
581                                 else
582                                 ll_blkno = blkno , ll_recno = recno ;
583                         } else {
584                                 ln_blkno = -1 ;
585                                 ln_recno = -1 ;
586                                 ll_blkno = -1 ;
587                                 ll_recno = -1 ;
588                         }
589                         p++;
590                 }
591 #ifdef DDS_TRACE
592                 fprintf(stderr,"end of scanning pattern list\n");
593 #endif
594         }
595         /*
596          * Write an empty record to the end of the archive.
597          */
598         memset(cur_block, 0, buf_n );
599         write(1, cur_block, 512);
600         nblocks++;
601         if (verbose)
602                 fprintf(stderr, "dds2tar: %d blocks written\n", nblocks);
603 #ifdef DDS_TRACE
604         fprintf(stderr,"%d\n",__LINE__);
605         fprintf(stderr,"return of dds_cmp(...)");
606 #endif
607         return 0;
608 }