1
+ /* Copyright (C) 2022 Lars Brinkhoff <[email protected] >
2
+
3
+ This program is free software: you can redistribute it and/or modify
4
+ it under the terms of the GNU General Public License as published by
5
+ the Free Software Foundation, either version 2 of the License, or
6
+ (at your option) any later version.
7
+
8
+ This program is distributed in the hope that it will be useful,
9
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ GNU General Public License for more details.
12
+
13
+ You should have received a copy of the GNU General Public License
14
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
15
+
1
16
#include <time.h>
2
17
#include <stdio.h>
3
18
#include <stdlib.h>
4
19
#include <stdint.h>
5
20
#include <string.h>
21
+ #include <fcntl.h>
22
+ #include <sys/stat.h>
23
+ #include <sys/time.h>
24
+ #include <sys/types.h>
6
25
7
26
#define RECORD_SIZE 5120
8
27
static uint8_t buffer [2 * RECORD_SIZE ];
9
28
static uint32_t buf_size = RECORD_SIZE ;
10
29
static uint8_t * ptr = & buffer [RECORD_SIZE ];
11
30
static char name [65535 ];
31
+ static int extract = 0 ;
12
32
13
33
static uint8_t
14
34
read_frame (void )
@@ -114,12 +134,58 @@ read_octal (uint8_t *data, int size)
114
134
return strtoul (tmp , NULL , 8 );
115
135
}
116
136
137
+ static void
138
+ mkdirs (char * dir )
139
+ {
140
+ char * p = dir ;
141
+ for (;;)
142
+ {
143
+ p = strchr (p , '/' );
144
+ if (p == NULL )
145
+ return ;
146
+ * p = 0 ;
147
+ mkdir (dir , 0700 );
148
+ * p ++ = '/' ;
149
+ }
150
+ }
151
+
152
+ static FILE *
153
+ open_file (char * name , mode_t mode )
154
+ {
155
+ int fd ;
156
+
157
+ if (* name == '/' )
158
+ name ++ ;
159
+
160
+ mkdirs (name );
161
+
162
+ if (mode & 040000 )
163
+ {
164
+ mkdir (name , mode & 0777 );
165
+ return NULL ;
166
+ }
167
+
168
+ fd = creat (name , mode & 0777 );
169
+ return fdopen (fd , "w" );
170
+ }
171
+
172
+ static void
173
+ timestamp (char * name , time_t timestamp )
174
+ {
175
+ struct timeval tv [2 ];
176
+ tv [0 ].tv_sec = timestamp ;
177
+ tv [0 ].tv_usec = 0 ;
178
+ tv [1 ] = tv [0 ];
179
+ utimes (name , tv );
180
+ }
181
+
117
182
static void
118
183
read_file (void )
119
184
{
120
185
uint32_t i , mode , uid , gid , links , mtime , name_size , file_size ;
121
186
uint8_t * data ;
122
187
uint8_t adjust = 0 ;
188
+ FILE * f = NULL ;
123
189
time_t t ;
124
190
char * s ;
125
191
@@ -172,11 +238,22 @@ read_file (void)
172
238
printf ("%06o %3u %5u %5u %7u %s %s\n" ,
173
239
mode , links , uid , gid , file_size , s , name );
174
240
175
- if (file_size & 1 )
176
- file_size += adjust ;
241
+ if (extract )
242
+ f = open_file (name , mode );
243
+
244
+ /* The file data must start on an even boundary. */
245
+ if ((ptr - buffer ) & 1 )
246
+ read_data (adjust );
177
247
for (i = 0 ; i < file_size ; i ++ )
178
248
{
179
249
data = read_data (1 );
250
+ if (f )
251
+ fputc (* data , f );
252
+ }
253
+ if (f )
254
+ {
255
+ fclose (f );
256
+ timestamp (name , mtime );
180
257
}
181
258
}
182
259
@@ -186,8 +263,14 @@ read_file (void)
186
263
187
264
}
188
265
189
- int main (void )
266
+ int main (int argc , char * * argv )
190
267
{
268
+ if (argc == 2 && strcmp (argv [1 ], "-x" ) == 0 )
269
+ {
270
+ extract = 1 ;
271
+ umask (0 );
272
+ }
273
+
191
274
for (;;)
192
275
read_file ();
193
276
0 commit comments