1 /*
2     Copyright (C) 2000 Masanao Izumo <mo@goice.co.jp>
3 
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18 
19 #include "config.h"
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <ctype.h>
23 #ifndef NO_STRING_H
24 #include <string.h>
25 #else
26 #include <strings.h>
27 #endif
28 #include "libarc/mblock.h"
29 #include "zip.h"
30 #include "libarc/arc.h"
31 
32 #define TARBLKSIZ 512
33 #define TARHDRSIZ 512
34 
35 static long octal_value(char *s, int len);
36 static int tar_checksum(char *hdr);
37 
next_tar_entry(void)38 ArchiveEntryNode *next_tar_entry(void)
39 {
40     char hdr[TARHDRSIZ];
41     long size, sizeb;
42     ArchiveEntryNode *entry;
43     URL url;
44     int flen;
45     int macbin_check;
46 
47     url = arc_handler.url;
48     macbin_check = (arc_handler.counter == 0);
49 
50   retry_read:
51     if(!macbin_check)
52       {
53 	if(url_read(url, hdr, TARHDRSIZ) != TARHDRSIZ)
54 	  return NULL;
55       }
56     else
57       {
58 	int c = url_getc(url);
59 	if(c == 0)
60 	  {
61 	    url_skip(url, 127);
62 	    if(arc_handler.isfile)
63 	      arc_handler.pos += 128;
64 	    if(url_read(url, hdr, TARHDRSIZ) != TARHDRSIZ)
65 	      return NULL;
66 	  }
67 	else
68 	  {
69 	    hdr[0] = c;
70 	    if(url_read(url, hdr+1, TARHDRSIZ-1) != TARHDRSIZ-1)
71 	      return NULL;
72 	  }
73       }
74 
75     macbin_check = 0;
76 
77     if(hdr[0] == '\0')
78       return NULL;
79     if(!tar_checksum(hdr))
80       return NULL;
81     size = octal_value(hdr + 124, 12);
82     flen = strlen(hdr);
83     if(size == 0 && flen > 0 && hdr[flen - 1] == '/')
84     {
85 	if(arc_handler.isfile)
86 	    arc_handler.pos += TARHDRSIZ;
87 	goto retry_read;
88     }
89 
90     entry = new_entry_node(hdr, flen);
91     if(entry == NULL)
92 	return NULL;
93     sizeb = (((size) + (TARBLKSIZ-1)) & ~(TARBLKSIZ-1));
94 
95     if(arc_handler.isfile)
96     {
97 	arc_handler.pos += TARHDRSIZ;
98 	entry->comptype = ARCHIVEC_STORED;
99 	entry->compsize = entry->origsize = size;
100 	entry->start = arc_handler.pos;
101 	url_skip(url, sizeb);
102 	arc_handler.pos += sizeb;
103     }
104     else
105     {
106 	void *data;
107 	long n;
108 
109 	data = url_dump(url, size, &n);
110 	if(size != n)
111 	{
112 	    if(data != NULL)
113 		free(data);
114 	    free_entry_node(entry);
115 	    return NULL;
116 	}
117 	entry->cache = arc_compress(data, size, ARC_DEFLATE_LEVEL,
118 				    &entry->compsize);
119 	free(data);
120 	entry->comptype = ARCHIVEC_DEFLATED;
121 	entry->origsize = size;
122 	entry->start = 0;
123 	url_skip(url, sizeb - size);
124     }
125 
126     return entry;
127 }
128 
octal_value(char * s,int len)129 static long octal_value(char *s, int len)
130 {
131     long val;
132 
133     while(len > 0 && !isdigit((int)(unsigned char)*s))
134     {
135 	s++;
136 	len--;
137     }
138 
139     val = 0;
140     while(len > 0 && isdigit((int)(unsigned char)*s))
141     {
142 	val = ((val<<3) | (*s - '0'));
143 	s++;
144 	len--;
145     }
146     return val;
147 }
148 
tar_checksum(char * hdr)149 static int tar_checksum(char *hdr)
150 {
151     int i;
152 
153     long recorded_sum;
154     long unsigned_sum;		/* the POSIX one :-) */
155     long signed_sum;		/* the Sun one :-( */
156 
157     recorded_sum = octal_value(hdr + 148, 8);
158     unsigned_sum = 0;
159     signed_sum = 0;
160     for(i = 0; i < TARBLKSIZ; i++)
161     {
162 	unsigned_sum += 0xFF & hdr[i];
163 	signed_sum   += hdr[i];
164     }
165 
166     /* Adjust checksum to count the "chksum" field as blanks.  */
167     for(i = 0; i < 8; i++)
168     {
169 	unsigned_sum -= 0xFF & hdr[148 + i];
170 	signed_sum   -= hdr[i];
171     }
172     unsigned_sum += ' ' * 8;
173     signed_sum   += ' ' * 8;
174 
175     return unsigned_sum == recorded_sum || signed_sum == recorded_sum;
176 }
177