1+ /* Copyright (C) 2022 Lars Brinkhoff <lars@nocrew.org>
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+
116#include <time.h>
217#include <stdio.h>
318#include <stdlib.h>
419#include <stdint.h>
520#include <string.h>
21+ #include <fcntl.h>
22+ #include <sys/stat.h>
23+ #include <sys/time.h>
24+ #include <sys/types.h>
625
726#define RECORD_SIZE 5120
827static uint8_t buffer [2 * RECORD_SIZE ];
928static uint32_t buf_size = RECORD_SIZE ;
1029static uint8_t * ptr = & buffer [RECORD_SIZE ];
1130static char name [65535 ];
31+ static int extract = 0 ;
1232
1333static uint8_t
1434read_frame (void )
@@ -114,12 +134,58 @@ read_octal (uint8_t *data, int size)
114134 return strtoul (tmp , NULL , 8 );
115135}
116136
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+
117182static void
118183read_file (void )
119184{
120185 uint32_t i , mode , uid , gid , links , mtime , name_size , file_size ;
121186 uint8_t * data ;
122187 uint8_t adjust = 0 ;
188+ FILE * f = NULL ;
123189 time_t t ;
124190 char * s ;
125191
@@ -172,11 +238,22 @@ read_file (void)
172238 printf ("%06o %3u %5u %5u %7u %s %s\n" ,
173239 mode , links , uid , gid , file_size , s , name );
174240
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 );
177247 for (i = 0 ; i < file_size ; i ++ )
178248 {
179249 data = read_data (1 );
250+ if (f )
251+ fputc (* data , f );
252+ }
253+ if (f )
254+ {
255+ fclose (f );
256+ timestamp (name , mtime );
180257 }
181258 }
182259
@@ -186,8 +263,14 @@ read_file (void)
186263
187264}
188265
189- int main (void )
266+ int main (int argc , char * * argv )
190267{
268+ if (argc == 2 && strcmp (argv [1 ], "-x" ) == 0 )
269+ {
270+ extract = 1 ;
271+ umask (0 );
272+ }
273+
191274 for (;;)
192275 read_file ();
193276
0 commit comments