blob: 8f802de64544cf5a8a6697548856fab761c1ce73 [file] [log] [blame]
Erik Andersene49d5ec2000-02-08 19:58:47 +00001/* vi: set sw=4 ts=4: */
Eric Andersencc8ed391999-10-05 16:24:54 +00002/*
Eric Andersenc4996011999-10-20 22:08:37 +00003 * Mini tar implementation for busybox based on code taken from sash.
4 *
Eric Andersencc8ed391999-10-05 16:24:54 +00005 * Copyright (c) 1999 by David I. Bell
6 * Permission is granted to use, distribute, or modify this source,
7 * provided that this copyright notice remains intact.
8 *
Eric Andersencc8ed391999-10-05 16:24:54 +00009 * Permission to distribute this code under the GPL has been granted.
Eric Andersenc4996011999-10-20 22:08:37 +000010 *
Eric Andersen3cf52d11999-10-12 22:26:06 +000011 * Modified for busybox by Erik Andersen <andersee@debian.org>
Eric Andersenc4996011999-10-20 22:08:37 +000012 * Adjusted to grok stdin/stdout options.
13 *
Eric Andersen96bcfd31999-11-12 01:30:18 +000014 * Modified to handle device special files by Matt Porter
15 * <porter@debian.org>
16 *
Eric Andersenc4996011999-10-20 22:08:37 +000017 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 * General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 *
Eric Andersencc8ed391999-10-05 16:24:54 +000031 */
32
33
34#include "internal.h"
Eric Andersencc8ed391999-10-05 16:24:54 +000035#include <stdio.h>
36#include <dirent.h>
37#include <errno.h>
38#include <fcntl.h>
39#include <signal.h>
40#include <time.h>
Erik Andersen7dc16072000-01-04 01:10:25 +000041#include <utime.h>
Eric Andersen96bcfd31999-11-12 01:30:18 +000042#include <sys/types.h>
Eric Andersen08b10341999-11-19 02:38:58 +000043#include <sys/sysmacros.h>
Erik Andersene49d5ec2000-02-08 19:58:47 +000044#include <sys/param.h> /* for PATH_MAX */
Eric Andersencc8ed391999-10-05 16:24:54 +000045
Eric Andersene77ae3a1999-10-19 20:03:34 +000046
Erik Andersen05100cd2000-01-16 01:30:52 +000047#ifdef BB_FEATURE_TAR_CREATE
48
Eric Andersene77ae3a1999-10-19 20:03:34 +000049static const char tar_usage[] =
Erik Andersene49d5ec2000-02-08 19:58:47 +000050 "tar -[cxtvOf] [tarFileName] [FILE] ...\n\n"
51 "Create, extract, or list files from a tar file.\n\n"
52 "Options:\n"
53
54 "\tc=create, x=extract, t=list contents, v=verbose,\n"
55 "\tO=extract to stdout, f=tarfile or \"-\" for stdin\n";
Eric Andersene77ae3a1999-10-19 20:03:34 +000056
Erik Andersen05100cd2000-01-16 01:30:52 +000057#else
58
59static const char tar_usage[] =
Erik Andersene49d5ec2000-02-08 19:58:47 +000060 "tar -[xtvOf] [tarFileName] [FILE] ...\n\n"
61 "Extract, or list files stored in a tar file. This\n"
62 "version of tar does not support creation of tar files.\n\n"
63 "Options:\n"
64
65 "\tx=extract, t=list contents, v=verbose,\n"
66 "\tO=extract to stdout, f=tarfile or \"-\" for stdin\n";
Erik Andersen05100cd2000-01-16 01:30:52 +000067
68#endif
Eric Andersene77ae3a1999-10-19 20:03:34 +000069
70
Eric Andersencc8ed391999-10-05 16:24:54 +000071/*
72 * Tar file constants.
73 */
74#define TAR_BLOCK_SIZE 512
75#define TAR_NAME_SIZE 100
76
77
78/*
79 * The POSIX (and basic GNU) tar header format.
80 * This structure is always embedded in a TAR_BLOCK_SIZE sized block
81 * with zero padding. We only process this information minimally.
82 */
Eric Andersen3cf52d11999-10-12 22:26:06 +000083typedef struct {
Erik Andersene49d5ec2000-02-08 19:58:47 +000084 char name[TAR_NAME_SIZE];
85 char mode[8];
86 char uid[8];
87 char gid[8];
88 char size[12];
89 char mtime[12];
90 char checkSum[8];
91 char typeFlag;
92 char linkName[TAR_NAME_SIZE];
93 char magic[6];
94 char version[2];
95 char uname[32];
96 char gname[32];
97 char devMajor[8];
98 char devMinor[8];
99 char prefix[155];
Eric Andersencc8ed391999-10-05 16:24:54 +0000100} TarHeader;
101
102#define TAR_MAGIC "ustar"
103#define TAR_VERSION "00"
104
105#define TAR_TYPE_REGULAR '0'
106#define TAR_TYPE_HARD_LINK '1'
107#define TAR_TYPE_SOFT_LINK '2'
108
109
110/*
111 * Static data.
112 */
Eric Andersend73dc5b1999-11-10 23:13:02 +0000113static int listFlag;
114static int extractFlag;
115static int createFlag;
116static int verboseFlag;
117static int tostdoutFlag;
Eric Andersencc8ed391999-10-05 16:24:54 +0000118
Erik Andersene49d5ec2000-02-08 19:58:47 +0000119static int inHeader; // <- check me
Eric Andersend73dc5b1999-11-10 23:13:02 +0000120static int badHeader;
121static int errorFlag;
122static int skipFileFlag;
123static int warnedRoot;
124static int eofFlag;
Eric Andersen3cf52d11999-10-12 22:26:06 +0000125static long dataCc;
126static int outFd;
Erik Andersen7dc16072000-01-04 01:10:25 +0000127static const char *outName;
Eric Andersencc8ed391999-10-05 16:24:54 +0000128
Erik Andersen7dc16072000-01-04 01:10:25 +0000129static int mode;
130static int uid;
131static int gid;
132static time_t mtime;
Eric Andersencc8ed391999-10-05 16:24:54 +0000133
134/*
135 * Static data associated with the tar file.
136 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000137static const char *tarName;
138static int tarFd;
139static dev_t tarDev;
140static ino_t tarInode;
Eric Andersencc8ed391999-10-05 16:24:54 +0000141
142
143/*
144 * Local procedures to restore files from a tar file.
145 */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000146static void readTarFile(int fileCount, char **fileTable);
147static void readData(const char *cp, int count);
148static long getOctal(const char *cp, int len);
Eric Andersencc8ed391999-10-05 16:24:54 +0000149
Erik Andersene49d5ec2000-02-08 19:58:47 +0000150static void readHeader(const TarHeader * hp,
Eric Andersencc8ed391999-10-05 16:24:54 +0000151
Erik Andersene49d5ec2000-02-08 19:58:47 +0000152 int fileCount, char **fileTable);
153
154static int wantFileName(const char *fileName,
155
156 int fileCount, char **fileTable);
Eric Andersencc8ed391999-10-05 16:24:54 +0000157
Erik Andersen05100cd2000-01-16 01:30:52 +0000158#ifdef BB_FEATURE_TAR_CREATE
Eric Andersencc8ed391999-10-05 16:24:54 +0000159/*
160 * Local procedures to save files into a tar file.
161 */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000162static void saveFile(const char *fileName, int seeLinks);
Eric Andersencc8ed391999-10-05 16:24:54 +0000163
Erik Andersene49d5ec2000-02-08 19:58:47 +0000164static void saveRegularFile(const char *fileName,
Eric Andersencc8ed391999-10-05 16:24:54 +0000165
Erik Andersene49d5ec2000-02-08 19:58:47 +0000166 const struct stat *statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000167
Erik Andersene49d5ec2000-02-08 19:58:47 +0000168static void saveDirectory(const char *fileName,
Eric Andersencc8ed391999-10-05 16:24:54 +0000169
Erik Andersene49d5ec2000-02-08 19:58:47 +0000170 const struct stat *statbuf);
171
172static void writeHeader(const char *fileName, const struct stat *statbuf);
173
174static void writeTarFile(int fileCount, char **fileTable);
175static void writeTarBlock(const char *buf, int len);
176static int putOctal(char *cp, int len, long value);
Eric Andersencc8ed391999-10-05 16:24:54 +0000177
Erik Andersen05100cd2000-01-16 01:30:52 +0000178#endif
179
Eric Andersencc8ed391999-10-05 16:24:54 +0000180
Erik Andersene49d5ec2000-02-08 19:58:47 +0000181extern int tar_main(int argc, char **argv)
Eric Andersencc8ed391999-10-05 16:24:54 +0000182{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000183 const char *options;
Eric Andersencc8ed391999-10-05 16:24:54 +0000184
Erik Andersene49d5ec2000-02-08 19:58:47 +0000185 argc--;
186 argv++;
Eric Andersencc8ed391999-10-05 16:24:54 +0000187
Erik Andersene49d5ec2000-02-08 19:58:47 +0000188 if (argc < 1)
189 usage(tar_usage);
Eric Andersencc8ed391999-10-05 16:24:54 +0000190
191
Erik Andersene49d5ec2000-02-08 19:58:47 +0000192 errorFlag = FALSE;
193 extractFlag = FALSE;
194 createFlag = FALSE;
195 listFlag = FALSE;
196 verboseFlag = FALSE;
197 tostdoutFlag = FALSE;
198 tarName = NULL;
199 tarDev = 0;
200 tarInode = 0;
201 tarFd = -1;
Eric Andersencc8ed391999-10-05 16:24:54 +0000202
Erik Andersene49d5ec2000-02-08 19:58:47 +0000203 /*
204 * Parse the options.
205 */
206 if (**argv == '-')
207 options = (*argv++) + 1;
208 else
209 options = (*argv++);
210 argc--;
Eric Andersencc8ed391999-10-05 16:24:54 +0000211
Erik Andersene49d5ec2000-02-08 19:58:47 +0000212 for (; *options; options++) {
213 switch (*options) {
214 case 'f':
215 if (tarName != NULL) {
216 fprintf(stderr, "Only one 'f' option allowed\n");
Eric Andersen3cf52d11999-10-12 22:26:06 +0000217
Erik Andersene49d5ec2000-02-08 19:58:47 +0000218 exit(FALSE);
219 }
Erik Andersende552872000-01-23 01:34:05 +0000220
Erik Andersene49d5ec2000-02-08 19:58:47 +0000221 tarName = *argv++;
222 argc--;
Erik Andersende552872000-01-23 01:34:05 +0000223
Erik Andersene49d5ec2000-02-08 19:58:47 +0000224 break;
Erik Andersende552872000-01-23 01:34:05 +0000225
Erik Andersene49d5ec2000-02-08 19:58:47 +0000226 case 't':
227 if (extractFlag == TRUE || createFlag == TRUE)
228 goto flagError;
229 listFlag = TRUE;
230 break;
Erik Andersende552872000-01-23 01:34:05 +0000231
Erik Andersene49d5ec2000-02-08 19:58:47 +0000232 case 'x':
233 if (listFlag == TRUE || createFlag == TRUE)
234 goto flagError;
235 extractFlag = TRUE;
236 break;
237 case 'c':
238 if (extractFlag == TRUE || listFlag == TRUE)
239 goto flagError;
240 createFlag = TRUE;
241 break;
Erik Andersende552872000-01-23 01:34:05 +0000242
Erik Andersene49d5ec2000-02-08 19:58:47 +0000243 case 'v':
244 verboseFlag = TRUE;
245 break;
Erik Andersende552872000-01-23 01:34:05 +0000246
Erik Andersene49d5ec2000-02-08 19:58:47 +0000247 case 'O':
248 tostdoutFlag = TRUE;
249 break;
Erik Andersende552872000-01-23 01:34:05 +0000250
Erik Andersene49d5ec2000-02-08 19:58:47 +0000251 case '-':
252 usage(tar_usage);
253 break;
Erik Andersende552872000-01-23 01:34:05 +0000254
Erik Andersene49d5ec2000-02-08 19:58:47 +0000255 default:
256 fprintf(stderr, "Unknown tar flag '%c'\n"
257 "Try `tar --help' for more information\n", *options);
258 exit(FALSE);
259 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000260 }
261
Erik Andersene49d5ec2000-02-08 19:58:47 +0000262 /*
263 * Do the correct type of action supplying the rest of the
264 * command line arguments as the list of files to process.
265 */
266 if (createFlag == TRUE) {
Erik Andersende552872000-01-23 01:34:05 +0000267#ifndef BB_FEATURE_TAR_CREATE
Erik Andersene49d5ec2000-02-08 19:58:47 +0000268 fprintf(stderr,
269 "This version of tar was not compiled with tar creation support.\n");
270 exit(FALSE);
Erik Andersende552872000-01-23 01:34:05 +0000271#else
Erik Andersene49d5ec2000-02-08 19:58:47 +0000272 writeTarFile(argc, argv);
273#endif
274 } else {
275 readTarFile(argc, argv);
276 }
277 if (errorFlag == TRUE) {
278 fprintf(stderr, "\n");
279 }
280 exit(!errorFlag);
Erik Andersende552872000-01-23 01:34:05 +0000281
Erik Andersene49d5ec2000-02-08 19:58:47 +0000282 flagError:
283 fprintf(stderr, "Exactly one of 'c', 'x' or 't' must be specified\n");
284 exit(FALSE);
Eric Andersencc8ed391999-10-05 16:24:54 +0000285}
286
287
288/*
289 * Read a tar file and extract or list the specified files within it.
290 * If the list is empty than all files are extracted or listed.
291 */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000292static void readTarFile(int fileCount, char **fileTable)
Eric Andersencc8ed391999-10-05 16:24:54 +0000293{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000294 const char *cp;
295 int cc;
296 int inCc;
297 int blockSize;
298 char buf[BUF_SIZE];
Eric Andersencc8ed391999-10-05 16:24:54 +0000299
Erik Andersene49d5ec2000-02-08 19:58:47 +0000300 skipFileFlag = FALSE;
301 badHeader = FALSE;
302 warnedRoot = FALSE;
303 eofFlag = FALSE;
304 inHeader = TRUE;
305 inCc = 0;
306 dataCc = 0;
307 outFd = -1;
308 blockSize = sizeof(buf);
309 cp = buf;
Eric Andersencc8ed391999-10-05 16:24:54 +0000310
Eric Andersen3cf52d11999-10-12 22:26:06 +0000311 /*
Erik Andersene49d5ec2000-02-08 19:58:47 +0000312 * Open the tar file for reading.
Eric Andersencc8ed391999-10-05 16:24:54 +0000313 */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000314 if ((tarName == NULL) || !strcmp(tarName, "-")) {
315 tarFd = fileno(stdin);
316 } else
317 tarFd = open(tarName, O_RDONLY);
Eric Andersencc8ed391999-10-05 16:24:54 +0000318
Erik Andersene49d5ec2000-02-08 19:58:47 +0000319 if (tarFd < 0) {
320 perror(tarName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000321 errorFlag = TRUE;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000322 return;
Eric Andersencc8ed391999-10-05 16:24:54 +0000323 }
324
Eric Andersen3cf52d11999-10-12 22:26:06 +0000325 /*
Erik Andersene49d5ec2000-02-08 19:58:47 +0000326 * Read blocks from the file until an end of file header block
327 * has been seen. (A real end of file from a read is an error.)
Eric Andersencc8ed391999-10-05 16:24:54 +0000328 */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000329 while (eofFlag == FALSE) {
330 /*
331 * Read the next block of data if necessary.
332 * This will be a large block if possible, which we will
333 * then process in the small tar blocks.
334 */
335 if (inCc <= 0) {
336 cp = buf;
337 inCc = fullRead(tarFd, buf, blockSize);
Eric Andersencc8ed391999-10-05 16:24:54 +0000338
Erik Andersene49d5ec2000-02-08 19:58:47 +0000339 if (inCc < 0) {
340 perror(tarName);
341 errorFlag = TRUE;
342 goto done;
343 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000344
Erik Andersene49d5ec2000-02-08 19:58:47 +0000345 if (inCc == 0) {
346 fprintf(stderr,
347 "Unexpected end of file from \"%s\"", tarName);
348 errorFlag = TRUE;
349 goto done;
350 }
351 }
352
353 /*
354 * If we are expecting a header block then examine it.
355 */
356 if (inHeader == TRUE) {
357 readHeader((const TarHeader *) cp, fileCount, fileTable);
358
359 cp += TAR_BLOCK_SIZE;
360 inCc -= TAR_BLOCK_SIZE;
361
362 continue;
363 }
364
365 /*
366 * We are currently handling the data for a file.
367 * Process the minimum of the amount of data we have available
368 * and the amount left to be processed for the file.
369 */
370 cc = inCc;
371
372 if (cc > dataCc)
373 cc = dataCc;
374
375 readData(cp, cc);
376
377 /*
378 * If the amount left isn't an exact multiple of the tar block
379 * size then round it up to the next block boundary since there
380 * is padding at the end of the file.
381 */
382 if (cc % TAR_BLOCK_SIZE)
383 cc += TAR_BLOCK_SIZE - (cc % TAR_BLOCK_SIZE);
384
385 cp += cc;
386 inCc -= cc;
Eric Andersencc8ed391999-10-05 16:24:54 +0000387 }
388
Eric Andersen3cf52d11999-10-12 22:26:06 +0000389 done:
Erik Andersene49d5ec2000-02-08 19:58:47 +0000390 /*
391 * Close the tar file if needed.
392 */
393 if ((tarFd >= 0) && (close(tarFd) < 0))
394 perror(tarName);
Eric Andersen3cf52d11999-10-12 22:26:06 +0000395
Erik Andersene49d5ec2000-02-08 19:58:47 +0000396 /*
397 * Close the output file if needed.
398 * This is only done here on a previous error and so no
399 * message is required on errors.
400 */
401 if (tostdoutFlag == FALSE) {
402 if (outFd >= 0) {
403 close(outFd);
404 }
Erik Andersen7dc16072000-01-04 01:10:25 +0000405 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000406}
407
408
409/*
410 * Examine the header block that was just read.
411 * This can specify the information for another file, or it can mark
412 * the end of the tar file.
413 */
414static void
Erik Andersene49d5ec2000-02-08 19:58:47 +0000415readHeader(const TarHeader * hp, int fileCount, char **fileTable)
Eric Andersencc8ed391999-10-05 16:24:54 +0000416{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000417 int checkSum;
418 int cc;
419 int hardLink;
420 int softLink;
421 int devFileFlag;
422 unsigned int major;
423 unsigned int minor;
424 long size;
425 struct utimbuf utb;
Eric Andersencc8ed391999-10-05 16:24:54 +0000426
Erik Andersene49d5ec2000-02-08 19:58:47 +0000427 /*
428 * If the block is completely empty, then this is the end of the
429 * archive file. If the name is null, then just skip this header.
430 */
431 outName = hp->name;
Eric Andersencc8ed391999-10-05 16:24:54 +0000432
Erik Andersene49d5ec2000-02-08 19:58:47 +0000433 if (*outName == '\0') {
434 for (cc = TAR_BLOCK_SIZE; cc > 0; cc--) {
435 if (*outName++)
436 return;
437 }
438
439 eofFlag = TRUE;
440
Eric Andersencc8ed391999-10-05 16:24:54 +0000441 return;
442 }
443
Erik Andersene49d5ec2000-02-08 19:58:47 +0000444 /*
445 * There is another file in the archive to examine.
446 * Extract the encoded information and check it.
Erik Andersen7dc16072000-01-04 01:10:25 +0000447 */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000448 mode = getOctal(hp->mode, sizeof(hp->mode));
449 uid = getOctal(hp->uid, sizeof(hp->uid));
450 gid = getOctal(hp->gid, sizeof(hp->gid));
451 size = getOctal(hp->size, sizeof(hp->size));
452 mtime = getOctal(hp->mtime, sizeof(hp->mtime));
453 checkSum = getOctal(hp->checkSum, sizeof(hp->checkSum));
454 major = getOctal(hp->devMajor, sizeof(hp->devMajor));
455 minor = getOctal(hp->devMinor, sizeof(hp->devMinor));
456
457 if ((mode < 0) || (uid < 0) || (gid < 0) || (size < 0)) {
458 if (badHeader == FALSE)
459 fprintf(stderr, "Bad tar header, skipping\n");
460
461 badHeader = TRUE;
462
463 return;
464 }
465
466 badHeader = FALSE;
467 skipFileFlag = FALSE;
468 devFileFlag = FALSE;
469
470 /*
471 * Check for the file modes.
472 */
473 hardLink = ((hp->typeFlag == TAR_TYPE_HARD_LINK) ||
474 (hp->typeFlag == TAR_TYPE_HARD_LINK - '0'));
475
476 softLink = ((hp->typeFlag == TAR_TYPE_SOFT_LINK) ||
477 (hp->typeFlag == TAR_TYPE_SOFT_LINK - '0'));
478
479 /*
480 * Check for a directory.
481 */
482 if (outName[strlen(outName) - 1] == '/')
483 mode |= S_IFDIR;
484
485 /*
486 * Check for absolute paths in the file.
487 * If we find any, then warn the user and make them relative.
488 */
489 if (*outName == '/') {
490 while (*outName == '/')
491 outName++;
492
493 if (warnedRoot == FALSE) {
494 fprintf(stderr,
495 "Absolute path detected, removing leading slashes\n");
496 }
497
498 warnedRoot = TRUE;
499 }
500
501 /*
502 * See if we want this file to be restored.
503 * If not, then set up to skip it.
504 */
505 if (wantFileName(outName, fileCount, fileTable) == FALSE) {
506 if (!hardLink && !softLink && (S_ISREG(mode) || S_ISCHR(mode)
507 || S_ISBLK(mode) || S_ISSOCK(mode)
508 || S_ISFIFO(mode))) {
509 inHeader = (size == 0) ? TRUE : FALSE;
510 dataCc = size;
511 }
512
513 skipFileFlag = TRUE;
514
515 return;
516 }
517
518 /*
519 * This file is to be handled.
520 * If we aren't extracting then just list information about the file.
521 */
522 if (extractFlag == FALSE) {
523 if (verboseFlag == TRUE) {
524 printf("%s %3d/%-d ", modeString(mode), uid, gid);
525 if (S_ISCHR(mode) || S_ISBLK(mode))
526 printf("%4d,%4d %s ", major, minor, timeString(mtime));
527 else
528 printf("%9ld %s ", size, timeString(mtime));
529 }
530 printf("%s", outName);
531
532 if (hardLink)
533 printf(" (link to \"%s\")", hp->linkName);
534 else if (softLink)
535 printf(" (symlink to \"%s\")", hp->linkName);
536 else if (S_ISREG(mode) || S_ISCHR(mode) || S_ISBLK(mode) ||
537 S_ISSOCK(mode) || S_ISFIFO(mode)) {
538 inHeader = (size == 0) ? TRUE : FALSE;
539 dataCc = size;
540 }
541
542 printf("\n");
543
544 return;
545 }
546
547 /*
548 * We really want to extract the file.
549 */
550 if (verboseFlag == TRUE)
551 printf("x %s\n", outName);
552
553 if (hardLink) {
554 if (link(hp->linkName, outName) < 0) {
555 perror(outName);
556 return;
557 }
558 /* Set the file time */
559 utb.actime = mtime;
560 utb.modtime = mtime;
561 utime(outName, &utb);
562 /* Set the file permissions */
563 chown(outName, uid, gid);
564 chmod(outName, mode);
565 return;
566 }
567
568 if (softLink) {
569#ifdef S_ISLNK
570 if (symlink(hp->linkName, outName) < 0) {
571 perror(outName);
572 return;
573 }
574 /* Try to change ownership of the symlink.
575 * If libs doesn't support that, don't bother.
576 * Changing the pointed-to file is the Wrong Thing(tm).
577 */
Erik Andersen7dc16072000-01-04 01:10:25 +0000578#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
Erik Andersene49d5ec2000-02-08 19:58:47 +0000579 lchown(outName, uid, gid);
Erik Andersen7dc16072000-01-04 01:10:25 +0000580#endif
581
Erik Andersene49d5ec2000-02-08 19:58:47 +0000582 /* Do not change permissions or date on symlink,
583 * since it changes the pointed to file instead. duh. */
Eric Andersencc8ed391999-10-05 16:24:54 +0000584#else
Erik Andersene49d5ec2000-02-08 19:58:47 +0000585 fprintf(stderr, "Cannot create symbolic links\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000586#endif
Erik Andersene49d5ec2000-02-08 19:58:47 +0000587 return;
Erik Andersen06936df2000-01-23 02:14:20 +0000588 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000589
Erik Andersene49d5ec2000-02-08 19:58:47 +0000590 /* Set the umask for this process so it doesn't
591 * screw things up. */
592 umask(0);
Eric Andersencc8ed391999-10-05 16:24:54 +0000593
Erik Andersene49d5ec2000-02-08 19:58:47 +0000594 /*
595 * If the file is a directory, then just create the path.
596 */
597 if (S_ISDIR(mode)) {
598 if (createPath(outName, mode) == TRUE) {
Erik Andersene2729152000-02-18 21:34:17 +0000599 /* make the final component, just in case it was
600 * omitted by createPath() (which will skip the
601 * directory if it doesn't have a terminating '/')
602 */
603 mkdir(outName, mode);
604
Erik Andersene49d5ec2000-02-08 19:58:47 +0000605 /* Set the file time */
606 utb.actime = mtime;
607 utb.modtime = mtime;
608 utime(outName, &utb);
609 /* Set the file permissions */
610 chown(outName, uid, gid);
611 chmod(outName, mode);
612 return;
613 }
614 return;
Eric Andersen96bcfd31999-11-12 01:30:18 +0000615 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000616
617 /*
618 * There is a file to write.
619 * First create the path to it if necessary with default permissions.
620 */
621 createPath(outName, 0777);
622
623 inHeader = (size == 0) ? TRUE : FALSE;
624 dataCc = size;
625
626 /*
627 * Start the output file.
628 */
629 if (tostdoutFlag == TRUE)
630 outFd = fileno(stdout);
631 else {
632 if (S_ISCHR(mode) || S_ISBLK(mode) || S_ISSOCK(mode)) {
633 devFileFlag = TRUE;
634 outFd = mknod(outName, mode, makedev(major, minor));
635 } else if (S_ISFIFO(mode)) {
636 devFileFlag = TRUE;
637 outFd = mkfifo(outName, mode);
638 } else {
639 outFd = open(outName, O_WRONLY | O_CREAT | O_TRUNC, mode);
640 }
641 if (outFd < 0) {
642 perror(outName);
643 skipFileFlag = TRUE;
644 return;
645 }
646 /* Set the file time */
647 utb.actime = mtime;
648 utb.modtime = mtime;
649 utime(outName, &utb);
650 /* Set the file permissions */
651 chown(outName, uid, gid);
652 chmod(outName, mode);
Eric Andersen96bcfd31999-11-12 01:30:18 +0000653 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000654
Eric Andersencc8ed391999-10-05 16:24:54 +0000655
Erik Andersene49d5ec2000-02-08 19:58:47 +0000656 /*
657 * If the file is empty, then that's all we need to do.
658 */
659 if (size == 0 && (tostdoutFlag == FALSE) && (devFileFlag == FALSE)) {
660 close(outFd);
661 outFd = -1;
662 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000663}
664
665
666/*
667 * Handle a data block of some specified size that was read.
668 */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000669static void readData(const char *cp, int count)
Eric Andersencc8ed391999-10-05 16:24:54 +0000670{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000671 /*
672 * Reduce the amount of data left in this file.
673 * If there is no more data left, then we need to read
674 * the header again.
675 */
676 dataCc -= count;
Eric Andersencc8ed391999-10-05 16:24:54 +0000677
Erik Andersene49d5ec2000-02-08 19:58:47 +0000678 if (dataCc <= 0)
679 inHeader = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000680
Erik Andersene49d5ec2000-02-08 19:58:47 +0000681 /*
682 * If we aren't extracting files or this file is being
683 * skipped then do nothing more.
684 */
685 if (extractFlag == FALSE || skipFileFlag == TRUE)
686 return;
Eric Andersencc8ed391999-10-05 16:24:54 +0000687
Erik Andersene49d5ec2000-02-08 19:58:47 +0000688 /*
689 * Write the data to the output file.
690 */
691 if (fullWrite(outFd, cp, count) < 0) {
692 perror(outName);
693 if (tostdoutFlag == FALSE) {
694 close(outFd);
695 outFd = -1;
696 }
697 skipFileFlag = TRUE;
698 return;
Eric Andersencc8ed391999-10-05 16:24:54 +0000699 }
700
Erik Andersene49d5ec2000-02-08 19:58:47 +0000701 /*
702 * Check if we are done writing to the file now.
703 */
704 if (dataCc <= 0 && tostdoutFlag == FALSE) {
705 struct utimbuf utb;
Eric Andersencc8ed391999-10-05 16:24:54 +0000706
Erik Andersene49d5ec2000-02-08 19:58:47 +0000707 if (close(outFd))
708 perror(outName);
Erik Andersen7dc16072000-01-04 01:10:25 +0000709
Erik Andersene49d5ec2000-02-08 19:58:47 +0000710 /* Set the file time */
711 utb.actime = mtime;
712 utb.modtime = mtime;
713 utime(outName, &utb);
714 /* Set the file permissions */
715 chown(outName, uid, gid);
716 chmod(outName, mode);
717
718 outFd = -1;
719 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000720}
721
722
723/*
Erik Andersen05100cd2000-01-16 01:30:52 +0000724 * See if the specified file name belongs to one of the specified list
725 * of path prefixes. An empty list implies that all files are wanted.
726 * Returns TRUE if the file is selected.
727 */
728static int
Erik Andersene49d5ec2000-02-08 19:58:47 +0000729wantFileName(const char *fileName, int fileCount, char **fileTable)
Erik Andersen05100cd2000-01-16 01:30:52 +0000730{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000731 const char *pathName;
732 int fileLength;
733 int pathLength;
Erik Andersen05100cd2000-01-16 01:30:52 +0000734
Erik Andersene49d5ec2000-02-08 19:58:47 +0000735 /*
736 * If there are no files in the list, then the file is wanted.
737 */
738 if (fileCount == 0)
739 return TRUE;
Erik Andersen05100cd2000-01-16 01:30:52 +0000740
Erik Andersene49d5ec2000-02-08 19:58:47 +0000741 fileLength = strlen(fileName);
Erik Andersen05100cd2000-01-16 01:30:52 +0000742
Erik Andersene49d5ec2000-02-08 19:58:47 +0000743 /*
744 * Check each of the test paths.
745 */
746 while (fileCount-- > 0) {
747 pathName = *fileTable++;
Erik Andersen05100cd2000-01-16 01:30:52 +0000748
Erik Andersene49d5ec2000-02-08 19:58:47 +0000749 pathLength = strlen(pathName);
Erik Andersen05100cd2000-01-16 01:30:52 +0000750
Erik Andersene49d5ec2000-02-08 19:58:47 +0000751 if (fileLength < pathLength)
752 continue;
Erik Andersen05100cd2000-01-16 01:30:52 +0000753
Erik Andersene49d5ec2000-02-08 19:58:47 +0000754 if (memcmp(fileName, pathName, pathLength) != 0)
755 continue;
Erik Andersen05100cd2000-01-16 01:30:52 +0000756
Erik Andersene49d5ec2000-02-08 19:58:47 +0000757 if ((fileLength == pathLength) || (fileName[pathLength] == '/')) {
758 return TRUE;
759 }
Erik Andersen05100cd2000-01-16 01:30:52 +0000760 }
Erik Andersen05100cd2000-01-16 01:30:52 +0000761
Erik Andersene49d5ec2000-02-08 19:58:47 +0000762 return FALSE;
Erik Andersen05100cd2000-01-16 01:30:52 +0000763}
764
765/*
766 * Read an octal value in a field of the specified width, with optional
767 * spaces on both sides of the number and with an optional null character
768 * at the end. Returns -1 on an illegal format.
769 */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000770static long getOctal(const char *cp, int len)
Erik Andersen05100cd2000-01-16 01:30:52 +0000771{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000772 long val;
Erik Andersen05100cd2000-01-16 01:30:52 +0000773
Erik Andersene49d5ec2000-02-08 19:58:47 +0000774 while ((len > 0) && (*cp == ' ')) {
775 cp++;
776 len--;
777 }
Erik Andersen05100cd2000-01-16 01:30:52 +0000778
Erik Andersene49d5ec2000-02-08 19:58:47 +0000779 if ((len == 0) || !isOctal(*cp))
780 return -1;
Erik Andersen05100cd2000-01-16 01:30:52 +0000781
Erik Andersene49d5ec2000-02-08 19:58:47 +0000782 val = 0;
Erik Andersen05100cd2000-01-16 01:30:52 +0000783
Erik Andersene49d5ec2000-02-08 19:58:47 +0000784 while ((len > 0) && isOctal(*cp)) {
785 val = val * 8 + *cp++ - '0';
786 len--;
787 }
Erik Andersen05100cd2000-01-16 01:30:52 +0000788
Erik Andersene49d5ec2000-02-08 19:58:47 +0000789 while ((len > 0) && (*cp == ' ')) {
790 cp++;
791 len--;
792 }
Erik Andersen05100cd2000-01-16 01:30:52 +0000793
Erik Andersene49d5ec2000-02-08 19:58:47 +0000794 if ((len > 0) && *cp)
795 return -1;
Erik Andersen05100cd2000-01-16 01:30:52 +0000796
Erik Andersene49d5ec2000-02-08 19:58:47 +0000797 return val;
Erik Andersen05100cd2000-01-16 01:30:52 +0000798}
799
800
801
802
803/* From here to the end of the file is the tar writing stuff.
804 * If you do not have BB_FEATURE_TAR_CREATE defined, this will
805 * not be built.
806 * */
807#ifdef BB_FEATURE_TAR_CREATE
808
809/*
Eric Andersencc8ed391999-10-05 16:24:54 +0000810 * Write a tar file containing the specified files.
811 */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000812static void writeTarFile(int fileCount, char **fileTable)
Eric Andersencc8ed391999-10-05 16:24:54 +0000813{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000814 struct stat statbuf;
Eric Andersencc8ed391999-10-05 16:24:54 +0000815
Erik Andersene49d5ec2000-02-08 19:58:47 +0000816 /*
817 * Make sure there is at least one file specified.
818 */
819 if (fileCount <= 0) {
820 fprintf(stderr, "No files specified to be saved\n");
821 errorFlag = TRUE;
822 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000823
Erik Andersene49d5ec2000-02-08 19:58:47 +0000824 /*
825 * Create the tar file for writing.
826 */
827 if ((tarName == NULL) || !strcmp(tarName, "-")) {
828 tostdoutFlag = TRUE;
829 tarFd = fileno(stdout);
830 } else
831 tarFd = open(tarName, O_WRONLY | O_CREAT | O_TRUNC, 0666);
Eric Andersencc8ed391999-10-05 16:24:54 +0000832
Erik Andersene49d5ec2000-02-08 19:58:47 +0000833 if (tarFd < 0) {
834 perror(tarName);
835 errorFlag = TRUE;
836 return;
837 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000838
Erik Andersene49d5ec2000-02-08 19:58:47 +0000839 /*
840 * Get the device and inode of the tar file for checking later.
841 */
842 if (fstat(tarFd, &statbuf) < 0) {
843 perror(tarName);
844 errorFlag = TRUE;
845 goto done;
846 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000847
Erik Andersene49d5ec2000-02-08 19:58:47 +0000848 tarDev = statbuf.st_dev;
849 tarInode = statbuf.st_ino;
Eric Andersencc8ed391999-10-05 16:24:54 +0000850
Erik Andersene49d5ec2000-02-08 19:58:47 +0000851 /*
852 * Append each file name into the archive file.
853 * Follow symbolic links for these top level file names.
854 */
855 while (errorFlag == FALSE && (fileCount-- > 0)) {
856 saveFile(*fileTable++, FALSE);
857 }
858
859 /*
860 * Now write an empty block of zeroes to end the archive.
861 */
862 writeTarBlock("", 1);
Eric Andersencc8ed391999-10-05 16:24:54 +0000863
864
Eric Andersen3cf52d11999-10-12 22:26:06 +0000865 done:
Erik Andersene49d5ec2000-02-08 19:58:47 +0000866 /*
867 * Close the tar file and check for errors if it was opened.
868 */
869 if ((tostdoutFlag == FALSE) && (tarFd >= 0) && (close(tarFd) < 0))
870 perror(tarName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000871}
872
Eric Andersencc8ed391999-10-05 16:24:54 +0000873/*
874 * Save one file into the tar file.
875 * If the file is a directory, then this will recursively save all of
876 * the files and directories within the directory. The seeLinks
877 * flag indicates whether or not we want to see symbolic links as
878 * they really are, instead of blindly following them.
879 */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000880static void saveFile(const char *fileName, int seeLinks)
Eric Andersencc8ed391999-10-05 16:24:54 +0000881{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000882 int status;
883 struct stat statbuf;
Eric Andersencc8ed391999-10-05 16:24:54 +0000884
Erik Andersene49d5ec2000-02-08 19:58:47 +0000885 if (verboseFlag == TRUE)
886 printf("a %s\n", fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000887
Erik Andersene49d5ec2000-02-08 19:58:47 +0000888 /*
889 * Check that the file name will fit in the header.
890 */
891 if (strlen(fileName) >= TAR_NAME_SIZE) {
892 fprintf(stderr, "%s: File name is too long\n", fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000893
Erik Andersene49d5ec2000-02-08 19:58:47 +0000894 return;
895 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000896
Erik Andersene49d5ec2000-02-08 19:58:47 +0000897 /*
898 * Find out about the file.
899 */
Eric Andersencc8ed391999-10-05 16:24:54 +0000900#ifdef S_ISLNK
Erik Andersene49d5ec2000-02-08 19:58:47 +0000901 if (seeLinks == TRUE)
902 status = lstat(fileName, &statbuf);
903 else
Eric Andersencc8ed391999-10-05 16:24:54 +0000904#endif
Erik Andersene49d5ec2000-02-08 19:58:47 +0000905 status = stat(fileName, &statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000906
Erik Andersene49d5ec2000-02-08 19:58:47 +0000907 if (status < 0) {
908 perror(fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000909
Erik Andersene49d5ec2000-02-08 19:58:47 +0000910 return;
911 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000912
Erik Andersene49d5ec2000-02-08 19:58:47 +0000913 /*
914 * Make sure we aren't trying to save our file into itself.
915 */
916 if ((statbuf.st_dev == tarDev) && (statbuf.st_ino == tarInode)) {
917 fprintf(stderr, "Skipping saving of archive file itself\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000918
Erik Andersene49d5ec2000-02-08 19:58:47 +0000919 return;
920 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000921
Erik Andersene49d5ec2000-02-08 19:58:47 +0000922 /*
923 * Check the type of file.
924 */
925 mode = statbuf.st_mode;
Eric Andersencc8ed391999-10-05 16:24:54 +0000926
Erik Andersene49d5ec2000-02-08 19:58:47 +0000927 if (S_ISDIR(mode)) {
928 saveDirectory(fileName, &statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000929
Erik Andersene49d5ec2000-02-08 19:58:47 +0000930 return;
931 }
932 if (S_ISREG(mode)) {
933 saveRegularFile(fileName, &statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000934
Erik Andersene49d5ec2000-02-08 19:58:47 +0000935 return;
936 }
937
938 /* Some day add support for tarring these up... but not today. :) */
Eric Andersen96bcfd31999-11-12 01:30:18 +0000939// if (S_ISLNK(mode) || S_ISFIFO(mode) || S_ISBLK(mode) || S_ISCHR (mode) ) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000940// fprintf (stderr, "%s: This version of tar can't store this type of file\n", fileName);
Eric Andersen96bcfd31999-11-12 01:30:18 +0000941// }
Eric Andersencc8ed391999-10-05 16:24:54 +0000942
Erik Andersene49d5ec2000-02-08 19:58:47 +0000943 /*
944 * The file is a strange type of file, ignore it.
945 */
946 fprintf(stderr, "%s: not a directory or regular file\n", fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000947}
948
949
950/*
951 * Save a regular file to the tar file.
952 */
953static void
Erik Andersene49d5ec2000-02-08 19:58:47 +0000954saveRegularFile(const char *fileName, const struct stat *statbuf)
Eric Andersencc8ed391999-10-05 16:24:54 +0000955{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000956 int sawEof;
957 int fileFd;
958 int cc;
959 int dataCount;
960 long fullDataCount;
961 char data[TAR_BLOCK_SIZE * 16];
Eric Andersen3cf52d11999-10-12 22:26:06 +0000962
963 /*
Erik Andersene49d5ec2000-02-08 19:58:47 +0000964 * Open the file for reading.
Eric Andersen3cf52d11999-10-12 22:26:06 +0000965 */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000966 fileFd = open(fileName, O_RDONLY);
Eric Andersen3cf52d11999-10-12 22:26:06 +0000967
Erik Andersene49d5ec2000-02-08 19:58:47 +0000968 if (fileFd < 0) {
969 perror(fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000970
971 return;
972 }
973
Eric Andersen3cf52d11999-10-12 22:26:06 +0000974 /*
Erik Andersene49d5ec2000-02-08 19:58:47 +0000975 * Write out the header for the file.
Eric Andersencc8ed391999-10-05 16:24:54 +0000976 */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000977 writeHeader(fileName, statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000978
Eric Andersen3cf52d11999-10-12 22:26:06 +0000979 /*
Erik Andersene49d5ec2000-02-08 19:58:47 +0000980 * Write the data blocks of the file.
981 * We must be careful to write the amount of data that the stat
982 * buffer indicated, even if the file has changed size. Otherwise
983 * the tar file will be incorrect.
Eric Andersencc8ed391999-10-05 16:24:54 +0000984 */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000985 fullDataCount = statbuf->st_size;
986 sawEof = FALSE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000987
Erik Andersene49d5ec2000-02-08 19:58:47 +0000988 while (fullDataCount > 0) {
989 /*
990 * Get the amount to write this iteration which is
991 * the minumum of the amount left to write and the
992 * buffer size.
993 */
994 dataCount = sizeof(data);
Eric Andersencc8ed391999-10-05 16:24:54 +0000995
Erik Andersene49d5ec2000-02-08 19:58:47 +0000996 if (dataCount > fullDataCount)
997 dataCount = (int) fullDataCount;
998
999 /*
1000 * Read the data from the file if we haven't seen the
1001 * end of file yet.
1002 */
1003 cc = 0;
1004
1005 if (sawEof == FALSE) {
1006 cc = fullRead(fileFd, data, dataCount);
1007
1008 if (cc < 0) {
1009 perror(fileName);
1010
1011 (void) close(fileFd);
1012 errorFlag = TRUE;
1013
1014 return;
1015 }
1016
1017 /*
1018 * If the file ended too soon, complain and set
1019 * a flag so we will zero fill the rest of it.
1020 */
1021 if (cc < dataCount) {
1022 fprintf(stderr, "%s: Short read - zero filling", fileName);
1023
1024 sawEof = TRUE;
1025 }
1026 }
1027
1028 /*
1029 * Zero fill the rest of the data if necessary.
1030 */
1031 if (cc < dataCount)
1032 memset(data + cc, 0, dataCount - cc);
1033
1034 /*
1035 * Write the buffer to the TAR file.
1036 */
1037 writeTarBlock(data, dataCount);
1038
1039 fullDataCount -= dataCount;
1040 }
1041
1042 /*
1043 * Close the file.
1044 */
1045 if ((tostdoutFlag == FALSE) && close(fileFd) < 0)
1046 fprintf(stderr, "%s: close: %s\n", fileName, strerror(errno));
Eric Andersencc8ed391999-10-05 16:24:54 +00001047}
1048
1049
1050/*
1051 * Save a directory and all of its files to the tar file.
1052 */
Erik Andersene49d5ec2000-02-08 19:58:47 +00001053static void saveDirectory(const char *dirName, const struct stat *statbuf)
Eric Andersencc8ed391999-10-05 16:24:54 +00001054{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001055 DIR *dir;
1056 struct dirent *entry;
1057 int needSlash;
1058 char fullName[PATH_MAX + 1];
Eric Andersencc8ed391999-10-05 16:24:54 +00001059
Erik Andersene49d5ec2000-02-08 19:58:47 +00001060 /*
1061 * Construct the directory name as used in the tar file by appending
1062 * a slash character to it.
1063 */
1064 strcpy(fullName, dirName);
1065 strcat(fullName, "/");
Eric Andersencc8ed391999-10-05 16:24:54 +00001066
Erik Andersene49d5ec2000-02-08 19:58:47 +00001067 /*
1068 * Write out the header for the directory entry.
1069 */
1070 writeHeader(fullName, statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +00001071
Erik Andersene49d5ec2000-02-08 19:58:47 +00001072 /*
1073 * Open the directory.
1074 */
1075 dir = opendir(dirName);
Eric Andersencc8ed391999-10-05 16:24:54 +00001076
Erik Andersene49d5ec2000-02-08 19:58:47 +00001077 if (dir == NULL) {
1078 fprintf(stderr, "Cannot read directory \"%s\": %s\n",
1079 dirName, strerror(errno));
Eric Andersencc8ed391999-10-05 16:24:54 +00001080
Erik Andersene49d5ec2000-02-08 19:58:47 +00001081 return;
Eric Andersencc8ed391999-10-05 16:24:54 +00001082 }
1083
Eric Andersen3cf52d11999-10-12 22:26:06 +00001084 /*
Erik Andersene49d5ec2000-02-08 19:58:47 +00001085 * See if a slash is needed.
Eric Andersencc8ed391999-10-05 16:24:54 +00001086 */
Erik Andersene49d5ec2000-02-08 19:58:47 +00001087 needSlash = (*dirName && (dirName[strlen(dirName) - 1] != '/'));
Eric Andersen3cf52d11999-10-12 22:26:06 +00001088
1089 /*
Erik Andersene49d5ec2000-02-08 19:58:47 +00001090 * Read all of the directory entries and check them,
1091 * except for the current and parent directory entries.
Eric Andersencc8ed391999-10-05 16:24:54 +00001092 */
Erik Andersene49d5ec2000-02-08 19:58:47 +00001093 while (errorFlag == FALSE && ((entry = readdir(dir)) != NULL)) {
1094 if ((strcmp(entry->d_name, ".") == 0) ||
1095 (strcmp(entry->d_name, "..") == 0)) {
1096 continue;
1097 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001098
Erik Andersene49d5ec2000-02-08 19:58:47 +00001099 /*
1100 * Build the full path name to the file.
1101 */
1102 strcpy(fullName, dirName);
1103
1104 if (needSlash)
1105 strcat(fullName, "/");
1106
1107 strcat(fullName, entry->d_name);
1108
1109 /*
1110 * Write this file to the tar file, noticing whether or not
1111 * the file is a symbolic link.
1112 */
1113 saveFile(fullName, TRUE);
1114 }
1115
1116 /*
1117 * All done, close the directory.
1118 */
1119 closedir(dir);
Eric Andersencc8ed391999-10-05 16:24:54 +00001120}
1121
1122
1123/*
1124 * Write a tar header for the specified file name and status.
1125 * It is assumed that the file name fits.
1126 */
Erik Andersene49d5ec2000-02-08 19:58:47 +00001127static void writeHeader(const char *fileName, const struct stat *statbuf)
Eric Andersencc8ed391999-10-05 16:24:54 +00001128{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001129 long checkSum;
1130 const unsigned char *cp;
1131 int len;
1132 TarHeader header;
Eric Andersencc8ed391999-10-05 16:24:54 +00001133
Erik Andersene49d5ec2000-02-08 19:58:47 +00001134 /*
1135 * Zero the header block in preparation for filling it in.
1136 */
1137 memset((char *) &header, 0, sizeof(header));
Eric Andersencc8ed391999-10-05 16:24:54 +00001138
Erik Andersene49d5ec2000-02-08 19:58:47 +00001139 /*
1140 * Fill in the header.
1141 */
1142 strcpy(header.name, fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +00001143
Erik Andersene49d5ec2000-02-08 19:58:47 +00001144 strncpy(header.magic, TAR_MAGIC, sizeof(header.magic));
1145 strncpy(header.version, TAR_VERSION, sizeof(header.version));
Eric Andersencc8ed391999-10-05 16:24:54 +00001146
Erik Andersene49d5ec2000-02-08 19:58:47 +00001147 putOctal(header.mode, sizeof(header.mode), statbuf->st_mode & 0777);
1148 putOctal(header.uid, sizeof(header.uid), statbuf->st_uid);
1149 putOctal(header.gid, sizeof(header.gid), statbuf->st_gid);
1150 putOctal(header.size, sizeof(header.size), statbuf->st_size);
1151 putOctal(header.mtime, sizeof(header.mtime), statbuf->st_mtime);
Eric Andersencc8ed391999-10-05 16:24:54 +00001152
Erik Andersene49d5ec2000-02-08 19:58:47 +00001153 header.typeFlag = TAR_TYPE_REGULAR;
Eric Andersencc8ed391999-10-05 16:24:54 +00001154
Erik Andersene49d5ec2000-02-08 19:58:47 +00001155 /*
1156 * Calculate and store the checksum.
1157 * This is the sum of all of the bytes of the header,
1158 * with the checksum field itself treated as blanks.
1159 */
1160 memset(header.checkSum, ' ', sizeof(header.checkSum));
Eric Andersencc8ed391999-10-05 16:24:54 +00001161
Erik Andersene49d5ec2000-02-08 19:58:47 +00001162 cp = (const unsigned char *) &header;
1163 len = sizeof(header);
1164 checkSum = 0;
Eric Andersencc8ed391999-10-05 16:24:54 +00001165
Erik Andersene49d5ec2000-02-08 19:58:47 +00001166 while (len-- > 0)
1167 checkSum += *cp++;
Eric Andersencc8ed391999-10-05 16:24:54 +00001168
Erik Andersene49d5ec2000-02-08 19:58:47 +00001169 putOctal(header.checkSum, sizeof(header.checkSum), checkSum);
Eric Andersencc8ed391999-10-05 16:24:54 +00001170
Erik Andersene49d5ec2000-02-08 19:58:47 +00001171 /*
1172 * Write the tar header.
1173 */
1174 writeTarBlock((const char *) &header, sizeof(header));
Eric Andersencc8ed391999-10-05 16:24:54 +00001175}
1176
1177
1178/*
1179 * Write data to one or more blocks of the tar file.
1180 * The data is always padded out to a multiple of TAR_BLOCK_SIZE.
1181 * The errorFlag static variable is set on an error.
1182 */
Erik Andersene49d5ec2000-02-08 19:58:47 +00001183static void writeTarBlock(const char *buf, int len)
Eric Andersencc8ed391999-10-05 16:24:54 +00001184{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001185 int partialLength;
1186 int completeLength;
1187 char fullBlock[TAR_BLOCK_SIZE];
Eric Andersencc8ed391999-10-05 16:24:54 +00001188
Erik Andersene49d5ec2000-02-08 19:58:47 +00001189 /*
1190 * If we had a write error before, then do nothing more.
1191 */
1192 if (errorFlag == TRUE)
1193 return;
Eric Andersencc8ed391999-10-05 16:24:54 +00001194
Erik Andersene49d5ec2000-02-08 19:58:47 +00001195 /*
1196 * Get the amount of complete and partial blocks.
1197 */
1198 partialLength = len % TAR_BLOCK_SIZE;
1199 completeLength = len - partialLength;
Eric Andersencc8ed391999-10-05 16:24:54 +00001200
Erik Andersene49d5ec2000-02-08 19:58:47 +00001201 /*
1202 * Write all of the complete blocks.
1203 */
1204 if ((completeLength > 0) && !fullWrite(tarFd, buf, completeLength)) {
1205 perror(tarName);
Eric Andersencc8ed391999-10-05 16:24:54 +00001206
Erik Andersene49d5ec2000-02-08 19:58:47 +00001207 errorFlag = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001208
Erik Andersene49d5ec2000-02-08 19:58:47 +00001209 return;
1210 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001211
Erik Andersene49d5ec2000-02-08 19:58:47 +00001212 /*
1213 * If there are no partial blocks left, we are done.
1214 */
1215 if (partialLength == 0)
1216 return;
Eric Andersencc8ed391999-10-05 16:24:54 +00001217
Erik Andersene49d5ec2000-02-08 19:58:47 +00001218 /*
1219 * Copy the partial data into a complete block, and pad the rest
1220 * of it with zeroes.
1221 */
1222 memcpy(fullBlock, buf + completeLength, partialLength);
1223 memset(fullBlock + partialLength, 0, TAR_BLOCK_SIZE - partialLength);
Eric Andersencc8ed391999-10-05 16:24:54 +00001224
Erik Andersene49d5ec2000-02-08 19:58:47 +00001225 /*
1226 * Write the last complete block.
1227 */
1228 if (!fullWrite(tarFd, fullBlock, TAR_BLOCK_SIZE)) {
1229 perror(tarName);
Eric Andersencc8ed391999-10-05 16:24:54 +00001230
Erik Andersene49d5ec2000-02-08 19:58:47 +00001231 errorFlag = TRUE;
1232 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001233}
1234
1235
1236/*
Eric Andersencc8ed391999-10-05 16:24:54 +00001237 * Put an octal string into the specified buffer.
1238 * The number is zero and space padded and possibly null padded.
1239 * Returns TRUE if successful.
1240 */
Erik Andersene49d5ec2000-02-08 19:58:47 +00001241static int putOctal(char *cp, int len, long value)
Eric Andersencc8ed391999-10-05 16:24:54 +00001242{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001243 int tempLength;
1244 char *tempString;
1245 char tempBuffer[32];
Eric Andersencc8ed391999-10-05 16:24:54 +00001246
Erik Andersene49d5ec2000-02-08 19:58:47 +00001247 /*
1248 * Create a string of the specified length with an initial space,
1249 * leading zeroes and the octal number, and a trailing null.
1250 */
1251 tempString = tempBuffer;
Eric Andersencc8ed391999-10-05 16:24:54 +00001252
Erik Andersene49d5ec2000-02-08 19:58:47 +00001253 sprintf(tempString, " %0*lo", len - 2, value);
Eric Andersencc8ed391999-10-05 16:24:54 +00001254
Erik Andersene49d5ec2000-02-08 19:58:47 +00001255 tempLength = strlen(tempString) + 1;
Eric Andersencc8ed391999-10-05 16:24:54 +00001256
Erik Andersene49d5ec2000-02-08 19:58:47 +00001257 /*
1258 * If the string is too large, suppress the leading space.
1259 */
1260 if (tempLength > len) {
1261 tempLength--;
1262 tempString++;
1263 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001264
Erik Andersene49d5ec2000-02-08 19:58:47 +00001265 /*
1266 * If the string is still too large, suppress the trailing null.
1267 */
1268 if (tempLength > len)
1269 tempLength--;
Eric Andersencc8ed391999-10-05 16:24:54 +00001270
Erik Andersene49d5ec2000-02-08 19:58:47 +00001271 /*
1272 * If the string is still too large, fail.
1273 */
1274 if (tempLength > len)
1275 return FALSE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001276
Erik Andersene49d5ec2000-02-08 19:58:47 +00001277 /*
1278 * Copy the string to the field.
1279 */
1280 memcpy(cp, tempString, len);
Eric Andersencc8ed391999-10-05 16:24:54 +00001281
Erik Andersene49d5ec2000-02-08 19:58:47 +00001282 return TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001283}
Erik Andersen05100cd2000-01-16 01:30:52 +00001284#endif
Eric Andersencc8ed391999-10-05 16:24:54 +00001285
Eric Andersencc8ed391999-10-05 16:24:54 +00001286/* END CODE */