blob: bbd86628ad10e3129dc1ebba647b5357bd08f690 [file] [log] [blame]
Eric Andersencc8ed391999-10-05 16:24:54 +00001/*
Eric Andersenc4996011999-10-20 22:08:37 +00002 * Mini tar implementation for busybox based on code taken from sash.
3 *
Eric Andersencc8ed391999-10-05 16:24:54 +00004 * Copyright (c) 1999 by David I. Bell
5 * Permission is granted to use, distribute, or modify this source,
6 * provided that this copyright notice remains intact.
7 *
Eric Andersencc8ed391999-10-05 16:24:54 +00008 * Permission to distribute this code under the GPL has been granted.
Eric Andersenc4996011999-10-20 22:08:37 +00009 *
Eric Andersen3cf52d11999-10-12 22:26:06 +000010 * Modified for busybox by Erik Andersen <andersee@debian.org>
Eric Andersenc4996011999-10-20 22:08:37 +000011 * Adjusted to grok stdin/stdout options.
12 *
Eric Andersen96bcfd31999-11-12 01:30:18 +000013 * Modified to handle device special files by Matt Porter
14 * <porter@debian.org>
15 *
Eric Andersenc4996011999-10-20 22:08:37 +000016 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 * General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 *
Eric Andersencc8ed391999-10-05 16:24:54 +000030 */
31
32
33#include "internal.h"
Eric Andersencc8ed391999-10-05 16:24:54 +000034#include <stdio.h>
35#include <dirent.h>
36#include <errno.h>
37#include <fcntl.h>
38#include <signal.h>
39#include <time.h>
Eric Andersen96bcfd31999-11-12 01:30:18 +000040#include <sys/types.h>
Eric Andersen08b10341999-11-19 02:38:58 +000041#include <sys/sysmacros.h>
Eric Andersencc8ed391999-10-05 16:24:54 +000042
Eric Andersene77ae3a1999-10-19 20:03:34 +000043
44static const char tar_usage[] =
Eric Andersend73dc5b1999-11-10 23:13:02 +000045"tar -[cxtvOf] [tarFileName] [FILE] ...\n\n"
46"Create, extract, or list files from a tar file\n\n"
47"Options:\n"
48"\tc=create, x=extract, t=list contents, v=verbose,\n"
49"\tO=extract to stdout, f=tarfile or \"-\" for stdin\n";
Eric Andersene77ae3a1999-10-19 20:03:34 +000050
51
52
Eric Andersencc8ed391999-10-05 16:24:54 +000053/*
54 * Tar file constants.
55 */
56#define TAR_BLOCK_SIZE 512
57#define TAR_NAME_SIZE 100
58
59
60/*
61 * The POSIX (and basic GNU) tar header format.
62 * This structure is always embedded in a TAR_BLOCK_SIZE sized block
63 * with zero padding. We only process this information minimally.
64 */
Eric Andersen3cf52d11999-10-12 22:26:06 +000065typedef struct {
66 char name[TAR_NAME_SIZE];
67 char mode[8];
68 char uid[8];
69 char gid[8];
70 char size[12];
71 char mtime[12];
72 char checkSum[8];
73 char typeFlag;
74 char linkName[TAR_NAME_SIZE];
75 char magic[6];
76 char version[2];
77 char uname[32];
78 char gname[32];
79 char devMajor[8];
80 char devMinor[8];
81 char prefix[155];
Eric Andersencc8ed391999-10-05 16:24:54 +000082} TarHeader;
83
84#define TAR_MAGIC "ustar"
85#define TAR_VERSION "00"
86
87#define TAR_TYPE_REGULAR '0'
88#define TAR_TYPE_HARD_LINK '1'
89#define TAR_TYPE_SOFT_LINK '2'
90
91
92/*
93 * Static data.
94 */
Eric Andersend73dc5b1999-11-10 23:13:02 +000095static int listFlag;
96static int extractFlag;
97static int createFlag;
98static int verboseFlag;
99static int tostdoutFlag;
Eric Andersencc8ed391999-10-05 16:24:54 +0000100
Eric Andersen5556c181999-11-10 19:27:58 +0000101static int inHeader; // <- check me
Eric Andersend73dc5b1999-11-10 23:13:02 +0000102static int badHeader;
103static int errorFlag;
104static int skipFileFlag;
105static int warnedRoot;
106static int eofFlag;
Eric Andersen3cf52d11999-10-12 22:26:06 +0000107static long dataCc;
108static int outFd;
109static char outName[TAR_NAME_SIZE];
Eric Andersencc8ed391999-10-05 16:24:54 +0000110
111
112/*
113 * Static data associated with the tar file.
114 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000115static const char *tarName;
116static int tarFd;
117static dev_t tarDev;
118static ino_t tarInode;
Eric Andersencc8ed391999-10-05 16:24:54 +0000119
120
121/*
122 * Local procedures to restore files from a tar file.
123 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000124static void readTarFile (int fileCount, char **fileTable);
125static void readData (const char *cp, int count);
Eric Andersen3cf52d11999-10-12 22:26:06 +0000126static long getOctal (const char *cp, int len);
Eric Andersencc8ed391999-10-05 16:24:54 +0000127
Eric Andersen3cf52d11999-10-12 22:26:06 +0000128static void readHeader (const TarHeader * hp,
129 int fileCount, char **fileTable);
Eric Andersencc8ed391999-10-05 16:24:54 +0000130
131
132/*
133 * Local procedures to save files into a tar file.
134 */
Eric Andersend73dc5b1999-11-10 23:13:02 +0000135static void saveFile (const char *fileName, int seeLinks);
Eric Andersencc8ed391999-10-05 16:24:54 +0000136
Eric Andersen3cf52d11999-10-12 22:26:06 +0000137static void saveRegularFile (const char *fileName,
138 const struct stat *statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000139
Eric Andersen3cf52d11999-10-12 22:26:06 +0000140static void saveDirectory (const char *fileName,
141 const struct stat *statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000142
Eric Andersen3cf52d11999-10-12 22:26:06 +0000143static int wantFileName (const char *fileName,
Eric Andersend73dc5b1999-11-10 23:13:02 +0000144 int fileCount, char **fileTable);
Eric Andersencc8ed391999-10-05 16:24:54 +0000145
Eric Andersen3cf52d11999-10-12 22:26:06 +0000146static void writeHeader (const char *fileName, const struct stat *statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000147
Eric Andersen3cf52d11999-10-12 22:26:06 +0000148static void writeTarFile (int fileCount, char **fileTable);
149static void writeTarBlock (const char *buf, int len);
Eric Andersend73dc5b1999-11-10 23:13:02 +0000150static int putOctal (char *cp, int len, long value);
Eric Andersencc8ed391999-10-05 16:24:54 +0000151
152
Eric Andersen3cf52d11999-10-12 22:26:06 +0000153extern int tar_main (int argc, char **argv)
Eric Andersencc8ed391999-10-05 16:24:54 +0000154{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000155 const char *options;
Eric Andersencc8ed391999-10-05 16:24:54 +0000156
Eric Andersen3cf52d11999-10-12 22:26:06 +0000157 argc--;
158 argv++;
Eric Andersencc8ed391999-10-05 16:24:54 +0000159
Eric Andersenbe971d61999-11-03 16:52:50 +0000160 if (argc < 1)
161 usage( tar_usage);
Eric Andersencc8ed391999-10-05 16:24:54 +0000162
163
Eric Andersen3cf52d11999-10-12 22:26:06 +0000164 errorFlag = FALSE;
165 extractFlag = FALSE;
166 createFlag = FALSE;
167 listFlag = FALSE;
168 verboseFlag = FALSE;
169 tostdoutFlag = FALSE;
170 tarName = NULL;
171 tarDev = 0;
172 tarInode = 0;
173 tarFd = -1;
Eric Andersencc8ed391999-10-05 16:24:54 +0000174
Eric Andersen3cf52d11999-10-12 22:26:06 +0000175 /*
176 * Parse the options.
177 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000178 if (**argv == '-') {
Eric Andersen50d63601999-11-09 01:47:36 +0000179 options = (*argv++) + 1;
180 argc--;
Eric Andersen3cf52d11999-10-12 22:26:06 +0000181 for (; *options; options++) {
182 switch (*options) {
183 case 'f':
184 if (tarName != NULL) {
185 fprintf (stderr, "Only one 'f' option allowed\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000186
Eric Andersen3cf52d11999-10-12 22:26:06 +0000187 exit (FALSE);
Eric Andersencc8ed391999-10-05 16:24:54 +0000188 }
Eric Andersen3cf52d11999-10-12 22:26:06 +0000189
190 tarName = *argv++;
191 argc--;
192
193 break;
194
195 case 't':
196 listFlag = TRUE;
197 break;
198
199 case 'x':
200 extractFlag = TRUE;
201 break;
202
203 case 'c':
204 createFlag = TRUE;
205 break;
206
207 case 'v':
208 verboseFlag = TRUE;
209 break;
210
211 case 'O':
212 tostdoutFlag = TRUE;
213 break;
214
215 case '-':
Eric Andersend73dc5b1999-11-10 23:13:02 +0000216 usage( tar_usage);
Eric Andersen3cf52d11999-10-12 22:26:06 +0000217 break;
218
219 default:
Eric Andersend73dc5b1999-11-10 23:13:02 +0000220 fprintf (stderr, "Unknown tar flag '%c'\n"
221 "Try `tar --help' for more information\n",
222 *options);
Eric Andersen3cf52d11999-10-12 22:26:06 +0000223
224 exit (FALSE);
225 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000226 }
Eric Andersen3cf52d11999-10-12 22:26:06 +0000227 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000228
Eric Andersen3cf52d11999-10-12 22:26:06 +0000229 /*
230 * Validate the options.
231 */
Eric Andersen5556c181999-11-10 19:27:58 +0000232 if (extractFlag + listFlag + createFlag != (TRUE+FALSE+FALSE)) {
Eric Andersen3cf52d11999-10-12 22:26:06 +0000233 fprintf (stderr,
234 "Exactly one of 'c', 'x' or 't' must be specified\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000235
Eric Andersen3cf52d11999-10-12 22:26:06 +0000236 exit (FALSE);
237 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000238
Eric Andersen3cf52d11999-10-12 22:26:06 +0000239 /*
240 * Do the correct type of action supplying the rest of the
241 * command line arguments as the list of files to process.
242 */
Eric Andersen5556c181999-11-10 19:27:58 +0000243 if (createFlag==TRUE)
Eric Andersen3cf52d11999-10-12 22:26:06 +0000244 writeTarFile (argc, argv);
245 else
246 readTarFile (argc, argv);
Eric Andersen5556c181999-11-10 19:27:58 +0000247 if (errorFlag==TRUE)
Eric Andersen3cf52d11999-10-12 22:26:06 +0000248 fprintf (stderr, "\n");
Eric Andersen5556c181999-11-10 19:27:58 +0000249 exit (!errorFlag);
Eric Andersencc8ed391999-10-05 16:24:54 +0000250}
251
252
253/*
254 * Read a tar file and extract or list the specified files within it.
255 * If the list is empty than all files are extracted or listed.
256 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000257static void readTarFile (int fileCount, char **fileTable)
Eric Andersencc8ed391999-10-05 16:24:54 +0000258{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000259 const char *cp;
260 int cc;
261 int inCc;
262 int blockSize;
263 char buf[BUF_SIZE];
Eric Andersencc8ed391999-10-05 16:24:54 +0000264
Eric Andersen3cf52d11999-10-12 22:26:06 +0000265 skipFileFlag = FALSE;
266 badHeader = FALSE;
267 warnedRoot = FALSE;
268 eofFlag = FALSE;
269 inHeader = TRUE;
270 inCc = 0;
271 dataCc = 0;
272 outFd = -1;
273 blockSize = sizeof (buf);
274 cp = buf;
Eric Andersencc8ed391999-10-05 16:24:54 +0000275
Eric Andersen3cf52d11999-10-12 22:26:06 +0000276 /*
277 * Open the tar file for reading.
278 */
279 if ((tarName == NULL) || !strcmp (tarName, "-")) {
Eric Andersen08b10341999-11-19 02:38:58 +0000280 tarFd = fileno(stdin);
Eric Andersen3cf52d11999-10-12 22:26:06 +0000281 } else
282 tarFd = open (tarName, O_RDONLY);
283
284 if (tarFd < 0) {
285 perror (tarName);
286 errorFlag = TRUE;
287 return;
288 }
289
290 /*
291 * Read blocks from the file until an end of file header block
292 * has been seen. (A real end of file from a read is an error.)
293 */
Eric Andersen5556c181999-11-10 19:27:58 +0000294 while (eofFlag==FALSE) {
Eric Andersen3cf52d11999-10-12 22:26:06 +0000295 /*
296 * Read the next block of data if necessary.
297 * This will be a large block if possible, which we will
298 * then process in the small tar blocks.
Eric Andersencc8ed391999-10-05 16:24:54 +0000299 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000300 if (inCc <= 0) {
301 cp = buf;
302 inCc = fullRead (tarFd, buf, blockSize);
Eric Andersencc8ed391999-10-05 16:24:54 +0000303
Eric Andersen3cf52d11999-10-12 22:26:06 +0000304 if (inCc < 0) {
305 perror (tarName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000306 errorFlag = TRUE;
Eric Andersen3cf52d11999-10-12 22:26:06 +0000307 goto done;
308 }
309
310 if (inCc == 0) {
311 fprintf (stderr,
312 "Unexpected end of file from \"%s\"", tarName);
313 errorFlag = TRUE;
314 goto done;
315 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000316 }
317
Eric Andersen3cf52d11999-10-12 22:26:06 +0000318 /*
319 * If we are expecting a header block then examine it.
Eric Andersencc8ed391999-10-05 16:24:54 +0000320 */
Eric Andersen5556c181999-11-10 19:27:58 +0000321 if (inHeader==TRUE) {
Eric Andersen3cf52d11999-10-12 22:26:06 +0000322 readHeader ((const TarHeader *) cp, fileCount, fileTable);
Eric Andersencc8ed391999-10-05 16:24:54 +0000323
Eric Andersen3cf52d11999-10-12 22:26:06 +0000324 cp += TAR_BLOCK_SIZE;
325 inCc -= TAR_BLOCK_SIZE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000326
Eric Andersen3cf52d11999-10-12 22:26:06 +0000327 continue;
Eric Andersencc8ed391999-10-05 16:24:54 +0000328 }
329
Eric Andersen3cf52d11999-10-12 22:26:06 +0000330 /*
331 * We are currently handling the data for a file.
332 * Process the minimum of the amount of data we have available
333 * and the amount left to be processed for the file.
Eric Andersencc8ed391999-10-05 16:24:54 +0000334 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000335 cc = inCc;
Eric Andersencc8ed391999-10-05 16:24:54 +0000336
Eric Andersen3cf52d11999-10-12 22:26:06 +0000337 if (cc > dataCc)
338 cc = dataCc;
339
340 readData (cp, cc);
341
342 /*
343 * If the amount left isn't an exact multiple of the tar block
344 * size then round it up to the next block boundary since there
345 * is padding at the end of the file.
Eric Andersencc8ed391999-10-05 16:24:54 +0000346 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000347 if (cc % TAR_BLOCK_SIZE)
348 cc += TAR_BLOCK_SIZE - (cc % TAR_BLOCK_SIZE);
349
350 cp += cc;
351 inCc -= cc;
352 }
353
354 done:
355 /*
356 * Close the tar file if needed.
357 */
358 if ((tarFd >= 0) && (close (tarFd) < 0))
359 perror (tarName);
360
361 /*
362 * Close the output file if needed.
363 * This is only done here on a previous error and so no
364 * message is required on errors.
365 */
366 if (tostdoutFlag == FALSE) {
367 if (outFd >= 0)
368 (void) close (outFd);
369 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000370}
371
372
373/*
374 * Examine the header block that was just read.
375 * This can specify the information for another file, or it can mark
376 * the end of the tar file.
377 */
378static void
Eric Andersen3cf52d11999-10-12 22:26:06 +0000379readHeader (const TarHeader * hp, int fileCount, char **fileTable)
Eric Andersencc8ed391999-10-05 16:24:54 +0000380{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000381 int mode;
382 int uid;
383 int gid;
384 int checkSum;
Eric Andersen96bcfd31999-11-12 01:30:18 +0000385 int major;
386 int minor;
Eric Andersen3cf52d11999-10-12 22:26:06 +0000387 long size;
388 time_t mtime;
389 const char *name;
390 int cc;
391 int hardLink;
392 int softLink;
Eric Andersen96bcfd31999-11-12 01:30:18 +0000393 int devFileFlag;
Eric Andersencc8ed391999-10-05 16:24:54 +0000394
Eric Andersen3cf52d11999-10-12 22:26:06 +0000395 /*
396 * If the block is completely empty, then this is the end of the
397 * archive file. If the name is null, then just skip this header.
398 */
399 name = hp->name;
Eric Andersencc8ed391999-10-05 16:24:54 +0000400
Eric Andersen3cf52d11999-10-12 22:26:06 +0000401 if (*name == '\0') {
402 for (cc = TAR_BLOCK_SIZE; cc > 0; cc--) {
403 if (*name++)
Eric Andersencc8ed391999-10-05 16:24:54 +0000404 return;
405 }
406
Eric Andersen3cf52d11999-10-12 22:26:06 +0000407 eofFlag = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000408
Eric Andersen3cf52d11999-10-12 22:26:06 +0000409 return;
410 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000411
Eric Andersen3cf52d11999-10-12 22:26:06 +0000412 /*
413 * There is another file in the archive to examine.
414 * Extract the encoded information and check it.
415 */
416 mode = getOctal (hp->mode, sizeof (hp->mode));
417 uid = getOctal (hp->uid, sizeof (hp->uid));
418 gid = getOctal (hp->gid, sizeof (hp->gid));
419 size = getOctal (hp->size, sizeof (hp->size));
420 mtime = getOctal (hp->mtime, sizeof (hp->mtime));
421 checkSum = getOctal (hp->checkSum, sizeof (hp->checkSum));
Eric Andersen96bcfd31999-11-12 01:30:18 +0000422 major = getOctal (hp->devMajor, sizeof (hp->devMajor));
423 minor = getOctal (hp->devMinor, sizeof (hp->devMinor));
Eric Andersencc8ed391999-10-05 16:24:54 +0000424
Eric Andersen3cf52d11999-10-12 22:26:06 +0000425 if ((mode < 0) || (uid < 0) || (gid < 0) || (size < 0)) {
Eric Andersen5556c181999-11-10 19:27:58 +0000426 if (badHeader==FALSE)
Eric Andersen3cf52d11999-10-12 22:26:06 +0000427 fprintf (stderr, "Bad tar header, skipping\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000428
Eric Andersen3cf52d11999-10-12 22:26:06 +0000429 badHeader = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000430
Eric Andersen3cf52d11999-10-12 22:26:06 +0000431 return;
432 }
433
434 badHeader = FALSE;
435 skipFileFlag = FALSE;
Eric Andersen96bcfd31999-11-12 01:30:18 +0000436 devFileFlag = FALSE;
Eric Andersen3cf52d11999-10-12 22:26:06 +0000437
438 /*
439 * Check for the file modes.
440 */
441 hardLink = ((hp->typeFlag == TAR_TYPE_HARD_LINK) ||
Eric Andersencc8ed391999-10-05 16:24:54 +0000442 (hp->typeFlag == TAR_TYPE_HARD_LINK - '0'));
443
Eric Andersen3cf52d11999-10-12 22:26:06 +0000444 softLink = ((hp->typeFlag == TAR_TYPE_SOFT_LINK) ||
Eric Andersencc8ed391999-10-05 16:24:54 +0000445 (hp->typeFlag == TAR_TYPE_SOFT_LINK - '0'));
446
Eric Andersen3cf52d11999-10-12 22:26:06 +0000447 /*
Eric Andersen96bcfd31999-11-12 01:30:18 +0000448 * Check for a directory.
Eric Andersen3cf52d11999-10-12 22:26:06 +0000449 */
450 if (name[strlen (name) - 1] == '/')
451 mode |= S_IFDIR;
Eric Andersencc8ed391999-10-05 16:24:54 +0000452
Eric Andersen3cf52d11999-10-12 22:26:06 +0000453 /*
454 * Check for absolute paths in the file.
455 * If we find any, then warn the user and make them relative.
456 */
457 if (*name == '/') {
458 while (*name == '/')
459 name++;
Eric Andersencc8ed391999-10-05 16:24:54 +0000460
Eric Andersen5556c181999-11-10 19:27:58 +0000461 if (warnedRoot==FALSE) {
Eric Andersen3cf52d11999-10-12 22:26:06 +0000462 fprintf (stderr,
463 "Absolute path detected, removing leading slashes\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000464 }
465
Eric Andersen3cf52d11999-10-12 22:26:06 +0000466 warnedRoot = TRUE;
467 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000468
Eric Andersen3cf52d11999-10-12 22:26:06 +0000469 /*
470 * See if we want this file to be restored.
471 * If not, then set up to skip it.
472 */
Eric Andersen5556c181999-11-10 19:27:58 +0000473 if (wantFileName (name, fileCount, fileTable) == FALSE) {
Eric Andersen96bcfd31999-11-12 01:30:18 +0000474 if ( !hardLink && !softLink && (S_ISREG (mode) || S_ISCHR (mode)
475 || S_ISBLK (mode) || S_ISSOCK(mode) || S_ISFIFO(mode) ) ) {
Eric Andersen5556c181999-11-10 19:27:58 +0000476 inHeader = (size == 0)? TRUE : FALSE;
Eric Andersen3cf52d11999-10-12 22:26:06 +0000477 dataCc = size;
Eric Andersencc8ed391999-10-05 16:24:54 +0000478 }
479
Eric Andersen3cf52d11999-10-12 22:26:06 +0000480 skipFileFlag = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000481
Eric Andersen3cf52d11999-10-12 22:26:06 +0000482 return;
483 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000484
Eric Andersen3cf52d11999-10-12 22:26:06 +0000485 /*
486 * This file is to be handled.
487 * If we aren't extracting then just list information about the file.
488 */
Eric Andersen5556c181999-11-10 19:27:58 +0000489 if (extractFlag==FALSE) {
490 if (verboseFlag==TRUE) {
Eric Andersen3cf52d11999-10-12 22:26:06 +0000491 printf ("%s %3d/%-d %9ld %s %s", modeString (mode),
492 uid, gid, size, timeString (mtime), name);
493 } else
494 printf ("%s", name);
Eric Andersencc8ed391999-10-05 16:24:54 +0000495
496 if (hardLink)
Eric Andersen3cf52d11999-10-12 22:26:06 +0000497 printf (" (link to \"%s\")", hp->linkName);
498 else if (softLink)
499 printf (" (symlink to \"%s\")", hp->linkName);
Eric Andersen96bcfd31999-11-12 01:30:18 +0000500 else if (S_ISREG (mode) || S_ISCHR (mode) || S_ISBLK (mode) ||
501 S_ISSOCK(mode) || S_ISFIFO(mode) ) {
Eric Andersen5556c181999-11-10 19:27:58 +0000502 inHeader = (size == 0)? TRUE : FALSE;
Eric Andersen3cf52d11999-10-12 22:26:06 +0000503 dataCc = size;
Eric Andersencc8ed391999-10-05 16:24:54 +0000504 }
505
Eric Andersen3cf52d11999-10-12 22:26:06 +0000506 printf ("\n");
507
508 return;
509 }
510
511 /*
512 * We really want to extract the file.
513 */
Eric Andersen5556c181999-11-10 19:27:58 +0000514 if (verboseFlag==TRUE)
Eric Andersen3cf52d11999-10-12 22:26:06 +0000515 printf ("x %s\n", name);
516
517 if (hardLink) {
518 if (link (hp->linkName, name) < 0)
519 perror (name);
520
521 return;
522 }
523
524 if (softLink) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000525#ifdef S_ISLNK
Eric Andersen3cf52d11999-10-12 22:26:06 +0000526 if (symlink (hp->linkName, name) < 0)
527 perror (name);
Eric Andersencc8ed391999-10-05 16:24:54 +0000528#else
Eric Andersen3cf52d11999-10-12 22:26:06 +0000529 fprintf (stderr, "Cannot create symbolic links\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000530#endif
Eric Andersen3cf52d11999-10-12 22:26:06 +0000531 return;
532 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000533
Eric Andersen3cf52d11999-10-12 22:26:06 +0000534 /*
535 * If the file is a directory, then just create the path.
536 */
537 if (S_ISDIR (mode)) {
538 createPath (name, mode);
Eric Andersencc8ed391999-10-05 16:24:54 +0000539
Eric Andersen3cf52d11999-10-12 22:26:06 +0000540 return;
541 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000542
Eric Andersen3cf52d11999-10-12 22:26:06 +0000543 /*
544 * There is a file to write.
545 * First create the path to it if necessary with a default permission.
546 */
547 createPath (name, 0777);
Eric Andersencc8ed391999-10-05 16:24:54 +0000548
Eric Andersen5556c181999-11-10 19:27:58 +0000549 inHeader = (size == 0)? TRUE : FALSE;
Eric Andersen3cf52d11999-10-12 22:26:06 +0000550 dataCc = size;
Eric Andersencc8ed391999-10-05 16:24:54 +0000551
Eric Andersen3cf52d11999-10-12 22:26:06 +0000552 /*
553 * Start the output file.
554 */
555 if (tostdoutFlag == TRUE)
Eric Andersen08b10341999-11-19 02:38:58 +0000556 outFd = fileno(stdout);
Eric Andersen96bcfd31999-11-12 01:30:18 +0000557 else {
558 if ( S_ISCHR(mode) || S_ISBLK(mode) || S_ISSOCK(mode) ) {
559 devFileFlag = TRUE;
560 outFd = mknod (name, mode, makedev(major, minor) );
561 }
562 else if (S_ISFIFO(mode) ) {
Eric Andersenb6a44b81999-11-13 04:47:09 +0000563 devFileFlag = TRUE;
Eric Andersen96bcfd31999-11-12 01:30:18 +0000564 outFd = mkfifo(name, mode);
565 } else {
566 outFd = open (name, O_WRONLY | O_CREAT | O_TRUNC, mode);
567 }
568 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000569
Eric Andersen3cf52d11999-10-12 22:26:06 +0000570 if (outFd < 0) {
571 perror (name);
572 skipFileFlag = TRUE;
573 return;
574 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000575
Eric Andersen3cf52d11999-10-12 22:26:06 +0000576 /*
577 * If the file is empty, then that's all we need to do.
578 */
Eric Andersen96bcfd31999-11-12 01:30:18 +0000579 if (size == 0 && (tostdoutFlag == FALSE) && (devFileFlag == FALSE)) {
Eric Andersen3cf52d11999-10-12 22:26:06 +0000580 (void) close (outFd);
581 outFd = -1;
582 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000583}
584
585
586/*
587 * Handle a data block of some specified size that was read.
588 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000589static void readData (const char *cp, int count)
Eric Andersencc8ed391999-10-05 16:24:54 +0000590{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000591 /*
592 * Reduce the amount of data left in this file.
593 * If there is no more data left, then we need to read
594 * the header again.
595 */
596 dataCc -= count;
Eric Andersencc8ed391999-10-05 16:24:54 +0000597
Eric Andersen3cf52d11999-10-12 22:26:06 +0000598 if (dataCc <= 0)
599 inHeader = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000600
Eric Andersen3cf52d11999-10-12 22:26:06 +0000601 /*
602 * If we aren't extracting files or this file is being
603 * skipped then do nothing more.
604 */
Eric Andersen5556c181999-11-10 19:27:58 +0000605 if (extractFlag==FALSE || skipFileFlag==TRUE)
Eric Andersen3cf52d11999-10-12 22:26:06 +0000606 return;
Eric Andersencc8ed391999-10-05 16:24:54 +0000607
Eric Andersen3cf52d11999-10-12 22:26:06 +0000608 /*
609 * Write the data to the output file.
610 */
611 if (fullWrite (outFd, cp, count) < 0) {
612 perror (outName);
613 if (tostdoutFlag == FALSE) {
614 (void) close (outFd);
615 outFd = -1;
Eric Andersencc8ed391999-10-05 16:24:54 +0000616 }
Eric Andersen3cf52d11999-10-12 22:26:06 +0000617 skipFileFlag = TRUE;
618 return;
619 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000620
Eric Andersen3cf52d11999-10-12 22:26:06 +0000621 /*
622 * If the write failed, close the file and disable further
623 * writes to this file.
624 */
625 if (dataCc <= 0 && tostdoutFlag == FALSE) {
626 if (close (outFd))
627 perror (outName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000628
Eric Andersen3cf52d11999-10-12 22:26:06 +0000629 outFd = -1;
630 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000631}
632
633
634/*
635 * Write a tar file containing the specified files.
636 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000637static void writeTarFile (int fileCount, char **fileTable)
Eric Andersencc8ed391999-10-05 16:24:54 +0000638{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000639 struct stat statbuf;
Eric Andersencc8ed391999-10-05 16:24:54 +0000640
Eric Andersen3cf52d11999-10-12 22:26:06 +0000641 /*
642 * Make sure there is at least one file specified.
643 */
644 if (fileCount <= 0) {
645 fprintf (stderr, "No files specified to be saved\n");
646 errorFlag = TRUE;
647 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000648
Eric Andersen3cf52d11999-10-12 22:26:06 +0000649 /*
650 * Create the tar file for writing.
651 */
652 if ((tarName == NULL) || !strcmp (tarName, "-")) {
653 tostdoutFlag = TRUE;
Eric Andersen08b10341999-11-19 02:38:58 +0000654 tarFd = fileno(stdout);
Eric Andersen3cf52d11999-10-12 22:26:06 +0000655 } else
656 tarFd = open (tarName, O_WRONLY | O_CREAT | O_TRUNC, 0666);
Eric Andersencc8ed391999-10-05 16:24:54 +0000657
Eric Andersen3cf52d11999-10-12 22:26:06 +0000658 if (tarFd < 0) {
659 perror (tarName);
660 errorFlag = TRUE;
661 return;
662 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000663
Eric Andersen3cf52d11999-10-12 22:26:06 +0000664 /*
665 * Get the device and inode of the tar file for checking later.
666 */
667 if (fstat (tarFd, &statbuf) < 0) {
668 perror (tarName);
669 errorFlag = TRUE;
670 goto done;
671 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000672
Eric Andersen3cf52d11999-10-12 22:26:06 +0000673 tarDev = statbuf.st_dev;
674 tarInode = statbuf.st_ino;
Eric Andersencc8ed391999-10-05 16:24:54 +0000675
Eric Andersen3cf52d11999-10-12 22:26:06 +0000676 /*
677 * Append each file name into the archive file.
678 * Follow symbolic links for these top level file names.
679 */
Eric Andersen5556c181999-11-10 19:27:58 +0000680 while (errorFlag==FALSE && (fileCount-- > 0)) {
Eric Andersen3cf52d11999-10-12 22:26:06 +0000681 saveFile (*fileTable++, FALSE);
682 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000683
Eric Andersen3cf52d11999-10-12 22:26:06 +0000684 /*
685 * Now write an empty block of zeroes to end the archive.
686 */
687 writeTarBlock ("", 1);
Eric Andersencc8ed391999-10-05 16:24:54 +0000688
689
Eric Andersen3cf52d11999-10-12 22:26:06 +0000690 done:
691 /*
692 * Close the tar file and check for errors if it was opened.
693 */
694 if ((tostdoutFlag == FALSE) && (tarFd >= 0) && (close (tarFd) < 0))
695 perror (tarName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000696}
697
698
699/*
700 * Save one file into the tar file.
701 * If the file is a directory, then this will recursively save all of
702 * the files and directories within the directory. The seeLinks
703 * flag indicates whether or not we want to see symbolic links as
704 * they really are, instead of blindly following them.
705 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000706static void saveFile (const char *fileName, int seeLinks)
Eric Andersencc8ed391999-10-05 16:24:54 +0000707{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000708 int status;
709 int mode;
710 struct stat statbuf;
Eric Andersencc8ed391999-10-05 16:24:54 +0000711
Eric Andersen5556c181999-11-10 19:27:58 +0000712 if (verboseFlag==TRUE)
Eric Andersen3cf52d11999-10-12 22:26:06 +0000713 printf ("a %s\n", fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000714
Eric Andersen3cf52d11999-10-12 22:26:06 +0000715 /*
716 * Check that the file name will fit in the header.
717 */
718 if (strlen (fileName) >= TAR_NAME_SIZE) {
719 fprintf (stderr, "%s: File name is too long\n", fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000720
Eric Andersen3cf52d11999-10-12 22:26:06 +0000721 return;
722 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000723
Eric Andersen3cf52d11999-10-12 22:26:06 +0000724 /*
725 * Find out about the file.
726 */
Eric Andersencc8ed391999-10-05 16:24:54 +0000727#ifdef S_ISLNK
Eric Andersen5556c181999-11-10 19:27:58 +0000728 if (seeLinks==TRUE)
Eric Andersen3cf52d11999-10-12 22:26:06 +0000729 status = lstat (fileName, &statbuf);
730 else
Eric Andersencc8ed391999-10-05 16:24:54 +0000731#endif
Eric Andersen3cf52d11999-10-12 22:26:06 +0000732 status = stat (fileName, &statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000733
Eric Andersen3cf52d11999-10-12 22:26:06 +0000734 if (status < 0) {
735 perror (fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000736
Eric Andersen3cf52d11999-10-12 22:26:06 +0000737 return;
738 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000739
Eric Andersen3cf52d11999-10-12 22:26:06 +0000740 /*
741 * Make sure we aren't trying to save our file into itself.
742 */
743 if ((statbuf.st_dev == tarDev) && (statbuf.st_ino == tarInode)) {
744 fprintf (stderr, "Skipping saving of archive file itself\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000745
Eric Andersen3cf52d11999-10-12 22:26:06 +0000746 return;
747 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000748
Eric Andersen3cf52d11999-10-12 22:26:06 +0000749 /*
750 * Check the type of file.
751 */
752 mode = statbuf.st_mode;
Eric Andersencc8ed391999-10-05 16:24:54 +0000753
Eric Andersen3cf52d11999-10-12 22:26:06 +0000754 if (S_ISDIR (mode)) {
755 saveDirectory (fileName, &statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000756
Eric Andersen3cf52d11999-10-12 22:26:06 +0000757 return;
758 }
Eric Andersen3cf52d11999-10-12 22:26:06 +0000759 if (S_ISREG (mode)) {
760 saveRegularFile (fileName, &statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000761
Eric Andersen3cf52d11999-10-12 22:26:06 +0000762 return;
763 }
Eric Andersen96bcfd31999-11-12 01:30:18 +0000764
765 /* Some day add support for tarring these up... but not today. :) */
766// if (S_ISLNK(mode) || S_ISFIFO(mode) || S_ISBLK(mode) || S_ISCHR (mode) ) {
767// fprintf (stderr, "%s: This version of tar can't store this type of file\n", fileName);
768// }
Eric Andersencc8ed391999-10-05 16:24:54 +0000769
Eric Andersen3cf52d11999-10-12 22:26:06 +0000770 /*
771 * The file is a strange type of file, ignore it.
772 */
773 fprintf (stderr, "%s: not a directory or regular file\n", fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000774}
775
776
777/*
778 * Save a regular file to the tar file.
779 */
780static void
Eric Andersen3cf52d11999-10-12 22:26:06 +0000781saveRegularFile (const char *fileName, const struct stat *statbuf)
Eric Andersencc8ed391999-10-05 16:24:54 +0000782{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000783 int sawEof;
784 int fileFd;
785 int cc;
786 int dataCount;
787 long fullDataCount;
788 char data[TAR_BLOCK_SIZE * 16];
Eric Andersencc8ed391999-10-05 16:24:54 +0000789
Eric Andersen3cf52d11999-10-12 22:26:06 +0000790 /*
791 * Open the file for reading.
792 */
793 fileFd = open (fileName, O_RDONLY);
794
795 if (fileFd < 0) {
796 perror (fileName);
797
798 return;
799 }
800
801 /*
802 * Write out the header for the file.
803 */
804 writeHeader (fileName, statbuf);
805
806 /*
807 * Write the data blocks of the file.
808 * We must be careful to write the amount of data that the stat
809 * buffer indicated, even if the file has changed size. Otherwise
810 * the tar file will be incorrect.
811 */
812 fullDataCount = statbuf->st_size;
813 sawEof = FALSE;
814
815 while (fullDataCount > 0) {
816 /*
817 * Get the amount to write this iteration which is
818 * the minumum of the amount left to write and the
819 * buffer size.
Eric Andersencc8ed391999-10-05 16:24:54 +0000820 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000821 dataCount = sizeof (data);
Eric Andersencc8ed391999-10-05 16:24:54 +0000822
Eric Andersen3cf52d11999-10-12 22:26:06 +0000823 if (dataCount > fullDataCount)
824 dataCount = (int) fullDataCount;
825
826 /*
827 * Read the data from the file if we haven't seen the
828 * end of file yet.
829 */
830 cc = 0;
831
Eric Andersen5556c181999-11-10 19:27:58 +0000832 if (sawEof==FALSE) {
Eric Andersen3cf52d11999-10-12 22:26:06 +0000833 cc = fullRead (fileFd, data, dataCount);
834
835 if (cc < 0) {
836 perror (fileName);
837
838 (void) close (fileFd);
839 errorFlag = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000840
841 return;
Eric Andersen3cf52d11999-10-12 22:26:06 +0000842 }
843
844 /*
845 * If the file ended too soon, complain and set
846 * a flag so we will zero fill the rest of it.
847 */
848 if (cc < dataCount) {
849 fprintf (stderr,
850 "%s: Short read - zero filling", fileName);
851
852 sawEof = TRUE;
853 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000854 }
855
Eric Andersen3cf52d11999-10-12 22:26:06 +0000856 /*
857 * Zero fill the rest of the data if necessary.
Eric Andersencc8ed391999-10-05 16:24:54 +0000858 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000859 if (cc < dataCount)
860 memset (data + cc, 0, dataCount - cc);
Eric Andersencc8ed391999-10-05 16:24:54 +0000861
Eric Andersen3cf52d11999-10-12 22:26:06 +0000862 /*
863 * Write the buffer to the TAR file.
Eric Andersencc8ed391999-10-05 16:24:54 +0000864 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000865 writeTarBlock (data, dataCount);
Eric Andersencc8ed391999-10-05 16:24:54 +0000866
Eric Andersen3cf52d11999-10-12 22:26:06 +0000867 fullDataCount -= dataCount;
868 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000869
Eric Andersen3cf52d11999-10-12 22:26:06 +0000870 /*
871 * Close the file.
872 */
873 if ((tostdoutFlag == FALSE) && close (fileFd) < 0)
874 fprintf (stderr, "%s: close: %s\n", fileName, strerror (errno));
Eric Andersencc8ed391999-10-05 16:24:54 +0000875}
876
877
878/*
879 * Save a directory and all of its files to the tar file.
880 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000881static void saveDirectory (const char *dirName, const struct stat *statbuf)
Eric Andersencc8ed391999-10-05 16:24:54 +0000882{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000883 DIR *dir;
884 struct dirent *entry;
885 int needSlash;
Eric Andersen1b61f411999-10-13 18:56:42 +0000886 char fullName[NAME_MAX];
Eric Andersencc8ed391999-10-05 16:24:54 +0000887
Eric Andersen3cf52d11999-10-12 22:26:06 +0000888 /*
889 * Construct the directory name as used in the tar file by appending
890 * a slash character to it.
891 */
892 strcpy (fullName, dirName);
893 strcat (fullName, "/");
Eric Andersencc8ed391999-10-05 16:24:54 +0000894
Eric Andersen3cf52d11999-10-12 22:26:06 +0000895 /*
896 * Write out the header for the directory entry.
897 */
898 writeHeader (fullName, statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000899
Eric Andersen3cf52d11999-10-12 22:26:06 +0000900 /*
901 * Open the directory.
902 */
903 dir = opendir (dirName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000904
Eric Andersen3cf52d11999-10-12 22:26:06 +0000905 if (dir == NULL) {
906 fprintf (stderr, "Cannot read directory \"%s\": %s\n",
907 dirName, strerror (errno));
Eric Andersencc8ed391999-10-05 16:24:54 +0000908
Eric Andersen3cf52d11999-10-12 22:26:06 +0000909 return;
910 }
911
912 /*
913 * See if a slash is needed.
914 */
915 needSlash = (*dirName && (dirName[strlen (dirName) - 1] != '/'));
916
917 /*
918 * Read all of the directory entries and check them,
919 * except for the current and parent directory entries.
920 */
Eric Andersen5556c181999-11-10 19:27:58 +0000921 while (errorFlag==FALSE && ((entry = readdir (dir)) != NULL)) {
Eric Andersen3cf52d11999-10-12 22:26:06 +0000922 if ((strcmp (entry->d_name, ".") == 0) ||
923 (strcmp (entry->d_name, "..") == 0)) {
924 continue;
Eric Andersencc8ed391999-10-05 16:24:54 +0000925 }
926
Eric Andersen3cf52d11999-10-12 22:26:06 +0000927 /*
928 * Build the full path name to the file.
Eric Andersencc8ed391999-10-05 16:24:54 +0000929 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000930 strcpy (fullName, dirName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000931
Eric Andersen3cf52d11999-10-12 22:26:06 +0000932 if (needSlash)
933 strcat (fullName, "/");
934
935 strcat (fullName, entry->d_name);
936
937 /*
938 * Write this file to the tar file, noticing whether or not
939 * the file is a symbolic link.
Eric Andersencc8ed391999-10-05 16:24:54 +0000940 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000941 saveFile (fullName, TRUE);
942 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000943
Eric Andersen3cf52d11999-10-12 22:26:06 +0000944 /*
945 * All done, close the directory.
946 */
947 closedir (dir);
Eric Andersencc8ed391999-10-05 16:24:54 +0000948}
949
950
951/*
952 * Write a tar header for the specified file name and status.
953 * It is assumed that the file name fits.
954 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000955static void writeHeader (const char *fileName, const struct stat *statbuf)
Eric Andersencc8ed391999-10-05 16:24:54 +0000956{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000957 long checkSum;
958 const unsigned char *cp;
959 int len;
960 TarHeader header;
Eric Andersencc8ed391999-10-05 16:24:54 +0000961
Eric Andersen3cf52d11999-10-12 22:26:06 +0000962 /*
963 * Zero the header block in preparation for filling it in.
964 */
965 memset ((char *) &header, 0, sizeof (header));
Eric Andersencc8ed391999-10-05 16:24:54 +0000966
Eric Andersen3cf52d11999-10-12 22:26:06 +0000967 /*
968 * Fill in the header.
969 */
970 strcpy (header.name, fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000971
Eric Andersen3cf52d11999-10-12 22:26:06 +0000972 strncpy (header.magic, TAR_MAGIC, sizeof (header.magic));
973 strncpy (header.version, TAR_VERSION, sizeof (header.version));
Eric Andersencc8ed391999-10-05 16:24:54 +0000974
Eric Andersen3cf52d11999-10-12 22:26:06 +0000975 putOctal (header.mode, sizeof (header.mode), statbuf->st_mode & 0777);
976 putOctal (header.uid, sizeof (header.uid), statbuf->st_uid);
977 putOctal (header.gid, sizeof (header.gid), statbuf->st_gid);
978 putOctal (header.size, sizeof (header.size), statbuf->st_size);
979 putOctal (header.mtime, sizeof (header.mtime), statbuf->st_mtime);
Eric Andersencc8ed391999-10-05 16:24:54 +0000980
Eric Andersen3cf52d11999-10-12 22:26:06 +0000981 header.typeFlag = TAR_TYPE_REGULAR;
Eric Andersencc8ed391999-10-05 16:24:54 +0000982
Eric Andersen3cf52d11999-10-12 22:26:06 +0000983 /*
984 * Calculate and store the checksum.
985 * This is the sum of all of the bytes of the header,
986 * with the checksum field itself treated as blanks.
987 */
988 memset (header.checkSum, ' ', sizeof (header.checkSum));
Eric Andersencc8ed391999-10-05 16:24:54 +0000989
Eric Andersen3cf52d11999-10-12 22:26:06 +0000990 cp = (const unsigned char *) &header;
991 len = sizeof (header);
992 checkSum = 0;
Eric Andersencc8ed391999-10-05 16:24:54 +0000993
Eric Andersen3cf52d11999-10-12 22:26:06 +0000994 while (len-- > 0)
995 checkSum += *cp++;
Eric Andersencc8ed391999-10-05 16:24:54 +0000996
Eric Andersen3cf52d11999-10-12 22:26:06 +0000997 putOctal (header.checkSum, sizeof (header.checkSum), checkSum);
Eric Andersencc8ed391999-10-05 16:24:54 +0000998
Eric Andersen3cf52d11999-10-12 22:26:06 +0000999 /*
1000 * Write the tar header.
1001 */
1002 writeTarBlock ((const char *) &header, sizeof (header));
Eric Andersencc8ed391999-10-05 16:24:54 +00001003}
1004
1005
1006/*
1007 * Write data to one or more blocks of the tar file.
1008 * The data is always padded out to a multiple of TAR_BLOCK_SIZE.
1009 * The errorFlag static variable is set on an error.
1010 */
Eric Andersen3cf52d11999-10-12 22:26:06 +00001011static void writeTarBlock (const char *buf, int len)
Eric Andersencc8ed391999-10-05 16:24:54 +00001012{
Eric Andersen3cf52d11999-10-12 22:26:06 +00001013 int partialLength;
1014 int completeLength;
1015 char fullBlock[TAR_BLOCK_SIZE];
Eric Andersencc8ed391999-10-05 16:24:54 +00001016
Eric Andersen3cf52d11999-10-12 22:26:06 +00001017 /*
1018 * If we had a write error before, then do nothing more.
1019 */
Eric Andersen5556c181999-11-10 19:27:58 +00001020 if (errorFlag==TRUE)
Eric Andersen3cf52d11999-10-12 22:26:06 +00001021 return;
Eric Andersencc8ed391999-10-05 16:24:54 +00001022
Eric Andersen3cf52d11999-10-12 22:26:06 +00001023 /*
1024 * Get the amount of complete and partial blocks.
1025 */
1026 partialLength = len % TAR_BLOCK_SIZE;
1027 completeLength = len - partialLength;
Eric Andersencc8ed391999-10-05 16:24:54 +00001028
Eric Andersen3cf52d11999-10-12 22:26:06 +00001029 /*
1030 * Write all of the complete blocks.
1031 */
1032 if ((completeLength > 0) && !fullWrite (tarFd, buf, completeLength)) {
1033 perror (tarName);
Eric Andersencc8ed391999-10-05 16:24:54 +00001034
Eric Andersen3cf52d11999-10-12 22:26:06 +00001035 errorFlag = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001036
Eric Andersen3cf52d11999-10-12 22:26:06 +00001037 return;
1038 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001039
Eric Andersen3cf52d11999-10-12 22:26:06 +00001040 /*
1041 * If there are no partial blocks left, we are done.
1042 */
1043 if (partialLength == 0)
1044 return;
Eric Andersencc8ed391999-10-05 16:24:54 +00001045
Eric Andersen3cf52d11999-10-12 22:26:06 +00001046 /*
1047 * Copy the partial data into a complete block, and pad the rest
1048 * of it with zeroes.
1049 */
1050 memcpy (fullBlock, buf + completeLength, partialLength);
1051 memset (fullBlock + partialLength, 0, TAR_BLOCK_SIZE - partialLength);
Eric Andersencc8ed391999-10-05 16:24:54 +00001052
Eric Andersen3cf52d11999-10-12 22:26:06 +00001053 /*
1054 * Write the last complete block.
1055 */
1056 if (!fullWrite (tarFd, fullBlock, TAR_BLOCK_SIZE)) {
1057 perror (tarName);
Eric Andersencc8ed391999-10-05 16:24:54 +00001058
Eric Andersen3cf52d11999-10-12 22:26:06 +00001059 errorFlag = TRUE;
1060 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001061}
1062
1063
1064/*
Eric Andersencc8ed391999-10-05 16:24:54 +00001065 * Read an octal value in a field of the specified width, with optional
1066 * spaces on both sides of the number and with an optional null character
1067 * at the end. Returns -1 on an illegal format.
1068 */
Eric Andersen3cf52d11999-10-12 22:26:06 +00001069static long getOctal (const char *cp, int len)
Eric Andersencc8ed391999-10-05 16:24:54 +00001070{
Eric Andersen3cf52d11999-10-12 22:26:06 +00001071 long val;
Eric Andersencc8ed391999-10-05 16:24:54 +00001072
Eric Andersen3cf52d11999-10-12 22:26:06 +00001073 while ((len > 0) && (*cp == ' ')) {
1074 cp++;
1075 len--;
1076 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001077
Eric Andersen3cf52d11999-10-12 22:26:06 +00001078 if ((len == 0) || !isOctal (*cp))
1079 return -1;
Eric Andersencc8ed391999-10-05 16:24:54 +00001080
Eric Andersen3cf52d11999-10-12 22:26:06 +00001081 val = 0;
Eric Andersencc8ed391999-10-05 16:24:54 +00001082
Eric Andersen3cf52d11999-10-12 22:26:06 +00001083 while ((len > 0) && isOctal (*cp)) {
1084 val = val * 8 + *cp++ - '0';
1085 len--;
1086 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001087
Eric Andersen3cf52d11999-10-12 22:26:06 +00001088 while ((len > 0) && (*cp == ' ')) {
1089 cp++;
1090 len--;
1091 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001092
Eric Andersen3cf52d11999-10-12 22:26:06 +00001093 if ((len > 0) && *cp)
1094 return -1;
Eric Andersencc8ed391999-10-05 16:24:54 +00001095
Eric Andersen3cf52d11999-10-12 22:26:06 +00001096 return val;
Eric Andersencc8ed391999-10-05 16:24:54 +00001097}
1098
1099
1100/*
1101 * Put an octal string into the specified buffer.
1102 * The number is zero and space padded and possibly null padded.
1103 * Returns TRUE if successful.
1104 */
Eric Andersen3cf52d11999-10-12 22:26:06 +00001105static int putOctal (char *cp, int len, long value)
Eric Andersencc8ed391999-10-05 16:24:54 +00001106{
Eric Andersen3cf52d11999-10-12 22:26:06 +00001107 int tempLength;
1108 char *tempString;
1109 char tempBuffer[32];
Eric Andersencc8ed391999-10-05 16:24:54 +00001110
Eric Andersen3cf52d11999-10-12 22:26:06 +00001111 /*
1112 * Create a string of the specified length with an initial space,
1113 * leading zeroes and the octal number, and a trailing null.
1114 */
1115 tempString = tempBuffer;
Eric Andersencc8ed391999-10-05 16:24:54 +00001116
Eric Andersen3cf52d11999-10-12 22:26:06 +00001117 sprintf (tempString, " %0*lo", len - 2, value);
Eric Andersencc8ed391999-10-05 16:24:54 +00001118
Eric Andersen3cf52d11999-10-12 22:26:06 +00001119 tempLength = strlen (tempString) + 1;
Eric Andersencc8ed391999-10-05 16:24:54 +00001120
Eric Andersen3cf52d11999-10-12 22:26:06 +00001121 /*
1122 * If the string is too large, suppress the leading space.
1123 */
1124 if (tempLength > len) {
1125 tempLength--;
1126 tempString++;
1127 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001128
Eric Andersen3cf52d11999-10-12 22:26:06 +00001129 /*
1130 * If the string is still too large, suppress the trailing null.
1131 */
1132 if (tempLength > len)
1133 tempLength--;
Eric Andersencc8ed391999-10-05 16:24:54 +00001134
Eric Andersen3cf52d11999-10-12 22:26:06 +00001135 /*
1136 * If the string is still too large, fail.
1137 */
1138 if (tempLength > len)
1139 return FALSE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001140
Eric Andersen3cf52d11999-10-12 22:26:06 +00001141 /*
1142 * Copy the string to the field.
1143 */
1144 memcpy (cp, tempString, len);
Eric Andersencc8ed391999-10-05 16:24:54 +00001145
Eric Andersen3cf52d11999-10-12 22:26:06 +00001146 return TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001147}
1148
1149
1150/*
1151 * See if the specified file name belongs to one of the specified list
1152 * of path prefixes. An empty list implies that all files are wanted.
1153 * Returns TRUE if the file is selected.
1154 */
Eric Andersenf811e071999-10-09 00:25:00 +00001155static int
Eric Andersen3cf52d11999-10-12 22:26:06 +00001156wantFileName (const char *fileName, int fileCount, char **fileTable)
Eric Andersencc8ed391999-10-05 16:24:54 +00001157{
Eric Andersen3cf52d11999-10-12 22:26:06 +00001158 const char *pathName;
1159 int fileLength;
1160 int pathLength;
Eric Andersencc8ed391999-10-05 16:24:54 +00001161
Eric Andersen3cf52d11999-10-12 22:26:06 +00001162 /*
1163 * If there are no files in the list, then the file is wanted.
1164 */
1165 if (fileCount == 0)
1166 return TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001167
Eric Andersen3cf52d11999-10-12 22:26:06 +00001168 fileLength = strlen (fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +00001169
Eric Andersen3cf52d11999-10-12 22:26:06 +00001170 /*
1171 * Check each of the test paths.
1172 */
1173 while (fileCount-- > 0) {
1174 pathName = *fileTable++;
Eric Andersencc8ed391999-10-05 16:24:54 +00001175
Eric Andersen3cf52d11999-10-12 22:26:06 +00001176 pathLength = strlen (pathName);
Eric Andersencc8ed391999-10-05 16:24:54 +00001177
Eric Andersen3cf52d11999-10-12 22:26:06 +00001178 if (fileLength < pathLength)
1179 continue;
Eric Andersencc8ed391999-10-05 16:24:54 +00001180
Eric Andersen3cf52d11999-10-12 22:26:06 +00001181 if (memcmp (fileName, pathName, pathLength) != 0)
1182 continue;
Eric Andersencc8ed391999-10-05 16:24:54 +00001183
Eric Andersen3cf52d11999-10-12 22:26:06 +00001184 if ((fileLength == pathLength) || (fileName[pathLength] == '/')) {
1185 return TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001186 }
Eric Andersen3cf52d11999-10-12 22:26:06 +00001187 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001188
Eric Andersen3cf52d11999-10-12 22:26:06 +00001189 return FALSE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001190}
1191
1192
1193
Eric Andersencc8ed391999-10-05 16:24:54 +00001194/* END CODE */