blob: 87b5d2176ee185b7ad746c17ab2aad5721c80c07 [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) {
599 /* Set the file time */
600 utb.actime = mtime;
601 utb.modtime = mtime;
602 utime(outName, &utb);
603 /* Set the file permissions */
604 chown(outName, uid, gid);
605 chmod(outName, mode);
606 return;
607 }
608 return;
Eric Andersen96bcfd31999-11-12 01:30:18 +0000609 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000610
611 /*
612 * There is a file to write.
613 * First create the path to it if necessary with default permissions.
614 */
615 createPath(outName, 0777);
616
617 inHeader = (size == 0) ? TRUE : FALSE;
618 dataCc = size;
619
620 /*
621 * Start the output file.
622 */
623 if (tostdoutFlag == TRUE)
624 outFd = fileno(stdout);
625 else {
626 if (S_ISCHR(mode) || S_ISBLK(mode) || S_ISSOCK(mode)) {
627 devFileFlag = TRUE;
628 outFd = mknod(outName, mode, makedev(major, minor));
629 } else if (S_ISFIFO(mode)) {
630 devFileFlag = TRUE;
631 outFd = mkfifo(outName, mode);
632 } else {
633 outFd = open(outName, O_WRONLY | O_CREAT | O_TRUNC, mode);
634 }
635 if (outFd < 0) {
636 perror(outName);
637 skipFileFlag = TRUE;
638 return;
639 }
640 /* Set the file time */
641 utb.actime = mtime;
642 utb.modtime = mtime;
643 utime(outName, &utb);
644 /* Set the file permissions */
645 chown(outName, uid, gid);
646 chmod(outName, mode);
Eric Andersen96bcfd31999-11-12 01:30:18 +0000647 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000648
Eric Andersencc8ed391999-10-05 16:24:54 +0000649
Erik Andersene49d5ec2000-02-08 19:58:47 +0000650 /*
651 * If the file is empty, then that's all we need to do.
652 */
653 if (size == 0 && (tostdoutFlag == FALSE) && (devFileFlag == FALSE)) {
654 close(outFd);
655 outFd = -1;
656 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000657}
658
659
660/*
661 * Handle a data block of some specified size that was read.
662 */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000663static void readData(const char *cp, int count)
Eric Andersencc8ed391999-10-05 16:24:54 +0000664{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000665 /*
666 * Reduce the amount of data left in this file.
667 * If there is no more data left, then we need to read
668 * the header again.
669 */
670 dataCc -= count;
Eric Andersencc8ed391999-10-05 16:24:54 +0000671
Erik Andersene49d5ec2000-02-08 19:58:47 +0000672 if (dataCc <= 0)
673 inHeader = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000674
Erik Andersene49d5ec2000-02-08 19:58:47 +0000675 /*
676 * If we aren't extracting files or this file is being
677 * skipped then do nothing more.
678 */
679 if (extractFlag == FALSE || skipFileFlag == TRUE)
680 return;
Eric Andersencc8ed391999-10-05 16:24:54 +0000681
Erik Andersene49d5ec2000-02-08 19:58:47 +0000682 /*
683 * Write the data to the output file.
684 */
685 if (fullWrite(outFd, cp, count) < 0) {
686 perror(outName);
687 if (tostdoutFlag == FALSE) {
688 close(outFd);
689 outFd = -1;
690 }
691 skipFileFlag = TRUE;
692 return;
Eric Andersencc8ed391999-10-05 16:24:54 +0000693 }
694
Erik Andersene49d5ec2000-02-08 19:58:47 +0000695 /*
696 * Check if we are done writing to the file now.
697 */
698 if (dataCc <= 0 && tostdoutFlag == FALSE) {
699 struct utimbuf utb;
Eric Andersencc8ed391999-10-05 16:24:54 +0000700
Erik Andersene49d5ec2000-02-08 19:58:47 +0000701 if (close(outFd))
702 perror(outName);
Erik Andersen7dc16072000-01-04 01:10:25 +0000703
Erik Andersene49d5ec2000-02-08 19:58:47 +0000704 /* Set the file time */
705 utb.actime = mtime;
706 utb.modtime = mtime;
707 utime(outName, &utb);
708 /* Set the file permissions */
709 chown(outName, uid, gid);
710 chmod(outName, mode);
711
712 outFd = -1;
713 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000714}
715
716
717/*
Erik Andersen05100cd2000-01-16 01:30:52 +0000718 * See if the specified file name belongs to one of the specified list
719 * of path prefixes. An empty list implies that all files are wanted.
720 * Returns TRUE if the file is selected.
721 */
722static int
Erik Andersene49d5ec2000-02-08 19:58:47 +0000723wantFileName(const char *fileName, int fileCount, char **fileTable)
Erik Andersen05100cd2000-01-16 01:30:52 +0000724{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000725 const char *pathName;
726 int fileLength;
727 int pathLength;
Erik Andersen05100cd2000-01-16 01:30:52 +0000728
Erik Andersene49d5ec2000-02-08 19:58:47 +0000729 /*
730 * If there are no files in the list, then the file is wanted.
731 */
732 if (fileCount == 0)
733 return TRUE;
Erik Andersen05100cd2000-01-16 01:30:52 +0000734
Erik Andersene49d5ec2000-02-08 19:58:47 +0000735 fileLength = strlen(fileName);
Erik Andersen05100cd2000-01-16 01:30:52 +0000736
Erik Andersene49d5ec2000-02-08 19:58:47 +0000737 /*
738 * Check each of the test paths.
739 */
740 while (fileCount-- > 0) {
741 pathName = *fileTable++;
Erik Andersen05100cd2000-01-16 01:30:52 +0000742
Erik Andersene49d5ec2000-02-08 19:58:47 +0000743 pathLength = strlen(pathName);
Erik Andersen05100cd2000-01-16 01:30:52 +0000744
Erik Andersene49d5ec2000-02-08 19:58:47 +0000745 if (fileLength < pathLength)
746 continue;
Erik Andersen05100cd2000-01-16 01:30:52 +0000747
Erik Andersene49d5ec2000-02-08 19:58:47 +0000748 if (memcmp(fileName, pathName, pathLength) != 0)
749 continue;
Erik Andersen05100cd2000-01-16 01:30:52 +0000750
Erik Andersene49d5ec2000-02-08 19:58:47 +0000751 if ((fileLength == pathLength) || (fileName[pathLength] == '/')) {
752 return TRUE;
753 }
Erik Andersen05100cd2000-01-16 01:30:52 +0000754 }
Erik Andersen05100cd2000-01-16 01:30:52 +0000755
Erik Andersene49d5ec2000-02-08 19:58:47 +0000756 return FALSE;
Erik Andersen05100cd2000-01-16 01:30:52 +0000757}
758
759/*
760 * Read an octal value in a field of the specified width, with optional
761 * spaces on both sides of the number and with an optional null character
762 * at the end. Returns -1 on an illegal format.
763 */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000764static long getOctal(const char *cp, int len)
Erik Andersen05100cd2000-01-16 01:30:52 +0000765{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000766 long val;
Erik Andersen05100cd2000-01-16 01:30:52 +0000767
Erik Andersene49d5ec2000-02-08 19:58:47 +0000768 while ((len > 0) && (*cp == ' ')) {
769 cp++;
770 len--;
771 }
Erik Andersen05100cd2000-01-16 01:30:52 +0000772
Erik Andersene49d5ec2000-02-08 19:58:47 +0000773 if ((len == 0) || !isOctal(*cp))
774 return -1;
Erik Andersen05100cd2000-01-16 01:30:52 +0000775
Erik Andersene49d5ec2000-02-08 19:58:47 +0000776 val = 0;
Erik Andersen05100cd2000-01-16 01:30:52 +0000777
Erik Andersene49d5ec2000-02-08 19:58:47 +0000778 while ((len > 0) && isOctal(*cp)) {
779 val = val * 8 + *cp++ - '0';
780 len--;
781 }
Erik Andersen05100cd2000-01-16 01:30:52 +0000782
Erik Andersene49d5ec2000-02-08 19:58:47 +0000783 while ((len > 0) && (*cp == ' ')) {
784 cp++;
785 len--;
786 }
Erik Andersen05100cd2000-01-16 01:30:52 +0000787
Erik Andersene49d5ec2000-02-08 19:58:47 +0000788 if ((len > 0) && *cp)
789 return -1;
Erik Andersen05100cd2000-01-16 01:30:52 +0000790
Erik Andersene49d5ec2000-02-08 19:58:47 +0000791 return val;
Erik Andersen05100cd2000-01-16 01:30:52 +0000792}
793
794
795
796
797/* From here to the end of the file is the tar writing stuff.
798 * If you do not have BB_FEATURE_TAR_CREATE defined, this will
799 * not be built.
800 * */
801#ifdef BB_FEATURE_TAR_CREATE
802
803/*
Eric Andersencc8ed391999-10-05 16:24:54 +0000804 * Write a tar file containing the specified files.
805 */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000806static void writeTarFile(int fileCount, char **fileTable)
Eric Andersencc8ed391999-10-05 16:24:54 +0000807{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000808 struct stat statbuf;
Eric Andersencc8ed391999-10-05 16:24:54 +0000809
Erik Andersene49d5ec2000-02-08 19:58:47 +0000810 /*
811 * Make sure there is at least one file specified.
812 */
813 if (fileCount <= 0) {
814 fprintf(stderr, "No files specified to be saved\n");
815 errorFlag = TRUE;
816 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000817
Erik Andersene49d5ec2000-02-08 19:58:47 +0000818 /*
819 * Create the tar file for writing.
820 */
821 if ((tarName == NULL) || !strcmp(tarName, "-")) {
822 tostdoutFlag = TRUE;
823 tarFd = fileno(stdout);
824 } else
825 tarFd = open(tarName, O_WRONLY | O_CREAT | O_TRUNC, 0666);
Eric Andersencc8ed391999-10-05 16:24:54 +0000826
Erik Andersene49d5ec2000-02-08 19:58:47 +0000827 if (tarFd < 0) {
828 perror(tarName);
829 errorFlag = TRUE;
830 return;
831 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000832
Erik Andersene49d5ec2000-02-08 19:58:47 +0000833 /*
834 * Get the device and inode of the tar file for checking later.
835 */
836 if (fstat(tarFd, &statbuf) < 0) {
837 perror(tarName);
838 errorFlag = TRUE;
839 goto done;
840 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000841
Erik Andersene49d5ec2000-02-08 19:58:47 +0000842 tarDev = statbuf.st_dev;
843 tarInode = statbuf.st_ino;
Eric Andersencc8ed391999-10-05 16:24:54 +0000844
Erik Andersene49d5ec2000-02-08 19:58:47 +0000845 /*
846 * Append each file name into the archive file.
847 * Follow symbolic links for these top level file names.
848 */
849 while (errorFlag == FALSE && (fileCount-- > 0)) {
850 saveFile(*fileTable++, FALSE);
851 }
852
853 /*
854 * Now write an empty block of zeroes to end the archive.
855 */
856 writeTarBlock("", 1);
Eric Andersencc8ed391999-10-05 16:24:54 +0000857
858
Eric Andersen3cf52d11999-10-12 22:26:06 +0000859 done:
Erik Andersene49d5ec2000-02-08 19:58:47 +0000860 /*
861 * Close the tar file and check for errors if it was opened.
862 */
863 if ((tostdoutFlag == FALSE) && (tarFd >= 0) && (close(tarFd) < 0))
864 perror(tarName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000865}
866
Eric Andersencc8ed391999-10-05 16:24:54 +0000867/*
868 * Save one file into the tar file.
869 * If the file is a directory, then this will recursively save all of
870 * the files and directories within the directory. The seeLinks
871 * flag indicates whether or not we want to see symbolic links as
872 * they really are, instead of blindly following them.
873 */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000874static void saveFile(const char *fileName, int seeLinks)
Eric Andersencc8ed391999-10-05 16:24:54 +0000875{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000876 int status;
877 struct stat statbuf;
Eric Andersencc8ed391999-10-05 16:24:54 +0000878
Erik Andersene49d5ec2000-02-08 19:58:47 +0000879 if (verboseFlag == TRUE)
880 printf("a %s\n", fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000881
Erik Andersene49d5ec2000-02-08 19:58:47 +0000882 /*
883 * Check that the file name will fit in the header.
884 */
885 if (strlen(fileName) >= TAR_NAME_SIZE) {
886 fprintf(stderr, "%s: File name is too long\n", fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000887
Erik Andersene49d5ec2000-02-08 19:58:47 +0000888 return;
889 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000890
Erik Andersene49d5ec2000-02-08 19:58:47 +0000891 /*
892 * Find out about the file.
893 */
Eric Andersencc8ed391999-10-05 16:24:54 +0000894#ifdef S_ISLNK
Erik Andersene49d5ec2000-02-08 19:58:47 +0000895 if (seeLinks == TRUE)
896 status = lstat(fileName, &statbuf);
897 else
Eric Andersencc8ed391999-10-05 16:24:54 +0000898#endif
Erik Andersene49d5ec2000-02-08 19:58:47 +0000899 status = stat(fileName, &statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000900
Erik Andersene49d5ec2000-02-08 19:58:47 +0000901 if (status < 0) {
902 perror(fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000903
Erik Andersene49d5ec2000-02-08 19:58:47 +0000904 return;
905 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000906
Erik Andersene49d5ec2000-02-08 19:58:47 +0000907 /*
908 * Make sure we aren't trying to save our file into itself.
909 */
910 if ((statbuf.st_dev == tarDev) && (statbuf.st_ino == tarInode)) {
911 fprintf(stderr, "Skipping saving of archive file itself\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000912
Erik Andersene49d5ec2000-02-08 19:58:47 +0000913 return;
914 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000915
Erik Andersene49d5ec2000-02-08 19:58:47 +0000916 /*
917 * Check the type of file.
918 */
919 mode = statbuf.st_mode;
Eric Andersencc8ed391999-10-05 16:24:54 +0000920
Erik Andersene49d5ec2000-02-08 19:58:47 +0000921 if (S_ISDIR(mode)) {
922 saveDirectory(fileName, &statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000923
Erik Andersene49d5ec2000-02-08 19:58:47 +0000924 return;
925 }
926 if (S_ISREG(mode)) {
927 saveRegularFile(fileName, &statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000928
Erik Andersene49d5ec2000-02-08 19:58:47 +0000929 return;
930 }
931
932 /* Some day add support for tarring these up... but not today. :) */
Eric Andersen96bcfd31999-11-12 01:30:18 +0000933// if (S_ISLNK(mode) || S_ISFIFO(mode) || S_ISBLK(mode) || S_ISCHR (mode) ) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000934// fprintf (stderr, "%s: This version of tar can't store this type of file\n", fileName);
Eric Andersen96bcfd31999-11-12 01:30:18 +0000935// }
Eric Andersencc8ed391999-10-05 16:24:54 +0000936
Erik Andersene49d5ec2000-02-08 19:58:47 +0000937 /*
938 * The file is a strange type of file, ignore it.
939 */
940 fprintf(stderr, "%s: not a directory or regular file\n", fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000941}
942
943
944/*
945 * Save a regular file to the tar file.
946 */
947static void
Erik Andersene49d5ec2000-02-08 19:58:47 +0000948saveRegularFile(const char *fileName, const struct stat *statbuf)
Eric Andersencc8ed391999-10-05 16:24:54 +0000949{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000950 int sawEof;
951 int fileFd;
952 int cc;
953 int dataCount;
954 long fullDataCount;
955 char data[TAR_BLOCK_SIZE * 16];
Eric Andersen3cf52d11999-10-12 22:26:06 +0000956
957 /*
Erik Andersene49d5ec2000-02-08 19:58:47 +0000958 * Open the file for reading.
Eric Andersen3cf52d11999-10-12 22:26:06 +0000959 */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000960 fileFd = open(fileName, O_RDONLY);
Eric Andersen3cf52d11999-10-12 22:26:06 +0000961
Erik Andersene49d5ec2000-02-08 19:58:47 +0000962 if (fileFd < 0) {
963 perror(fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000964
965 return;
966 }
967
Eric Andersen3cf52d11999-10-12 22:26:06 +0000968 /*
Erik Andersene49d5ec2000-02-08 19:58:47 +0000969 * Write out the header for the file.
Eric Andersencc8ed391999-10-05 16:24:54 +0000970 */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000971 writeHeader(fileName, statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000972
Eric Andersen3cf52d11999-10-12 22:26:06 +0000973 /*
Erik Andersene49d5ec2000-02-08 19:58:47 +0000974 * Write the data blocks of the file.
975 * We must be careful to write the amount of data that the stat
976 * buffer indicated, even if the file has changed size. Otherwise
977 * the tar file will be incorrect.
Eric Andersencc8ed391999-10-05 16:24:54 +0000978 */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000979 fullDataCount = statbuf->st_size;
980 sawEof = FALSE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000981
Erik Andersene49d5ec2000-02-08 19:58:47 +0000982 while (fullDataCount > 0) {
983 /*
984 * Get the amount to write this iteration which is
985 * the minumum of the amount left to write and the
986 * buffer size.
987 */
988 dataCount = sizeof(data);
Eric Andersencc8ed391999-10-05 16:24:54 +0000989
Erik Andersene49d5ec2000-02-08 19:58:47 +0000990 if (dataCount > fullDataCount)
991 dataCount = (int) fullDataCount;
992
993 /*
994 * Read the data from the file if we haven't seen the
995 * end of file yet.
996 */
997 cc = 0;
998
999 if (sawEof == FALSE) {
1000 cc = fullRead(fileFd, data, dataCount);
1001
1002 if (cc < 0) {
1003 perror(fileName);
1004
1005 (void) close(fileFd);
1006 errorFlag = TRUE;
1007
1008 return;
1009 }
1010
1011 /*
1012 * If the file ended too soon, complain and set
1013 * a flag so we will zero fill the rest of it.
1014 */
1015 if (cc < dataCount) {
1016 fprintf(stderr, "%s: Short read - zero filling", fileName);
1017
1018 sawEof = TRUE;
1019 }
1020 }
1021
1022 /*
1023 * Zero fill the rest of the data if necessary.
1024 */
1025 if (cc < dataCount)
1026 memset(data + cc, 0, dataCount - cc);
1027
1028 /*
1029 * Write the buffer to the TAR file.
1030 */
1031 writeTarBlock(data, dataCount);
1032
1033 fullDataCount -= dataCount;
1034 }
1035
1036 /*
1037 * Close the file.
1038 */
1039 if ((tostdoutFlag == FALSE) && close(fileFd) < 0)
1040 fprintf(stderr, "%s: close: %s\n", fileName, strerror(errno));
Eric Andersencc8ed391999-10-05 16:24:54 +00001041}
1042
1043
1044/*
1045 * Save a directory and all of its files to the tar file.
1046 */
Erik Andersene49d5ec2000-02-08 19:58:47 +00001047static void saveDirectory(const char *dirName, const struct stat *statbuf)
Eric Andersencc8ed391999-10-05 16:24:54 +00001048{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001049 DIR *dir;
1050 struct dirent *entry;
1051 int needSlash;
1052 char fullName[PATH_MAX + 1];
Eric Andersencc8ed391999-10-05 16:24:54 +00001053
Erik Andersene49d5ec2000-02-08 19:58:47 +00001054 /*
1055 * Construct the directory name as used in the tar file by appending
1056 * a slash character to it.
1057 */
1058 strcpy(fullName, dirName);
1059 strcat(fullName, "/");
Eric Andersencc8ed391999-10-05 16:24:54 +00001060
Erik Andersene49d5ec2000-02-08 19:58:47 +00001061 /*
1062 * Write out the header for the directory entry.
1063 */
1064 writeHeader(fullName, statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +00001065
Erik Andersene49d5ec2000-02-08 19:58:47 +00001066 /*
1067 * Open the directory.
1068 */
1069 dir = opendir(dirName);
Eric Andersencc8ed391999-10-05 16:24:54 +00001070
Erik Andersene49d5ec2000-02-08 19:58:47 +00001071 if (dir == NULL) {
1072 fprintf(stderr, "Cannot read directory \"%s\": %s\n",
1073 dirName, strerror(errno));
Eric Andersencc8ed391999-10-05 16:24:54 +00001074
Erik Andersene49d5ec2000-02-08 19:58:47 +00001075 return;
Eric Andersencc8ed391999-10-05 16:24:54 +00001076 }
1077
Eric Andersen3cf52d11999-10-12 22:26:06 +00001078 /*
Erik Andersene49d5ec2000-02-08 19:58:47 +00001079 * See if a slash is needed.
Eric Andersencc8ed391999-10-05 16:24:54 +00001080 */
Erik Andersene49d5ec2000-02-08 19:58:47 +00001081 needSlash = (*dirName && (dirName[strlen(dirName) - 1] != '/'));
Eric Andersen3cf52d11999-10-12 22:26:06 +00001082
1083 /*
Erik Andersene49d5ec2000-02-08 19:58:47 +00001084 * Read all of the directory entries and check them,
1085 * except for the current and parent directory entries.
Eric Andersencc8ed391999-10-05 16:24:54 +00001086 */
Erik Andersene49d5ec2000-02-08 19:58:47 +00001087 while (errorFlag == FALSE && ((entry = readdir(dir)) != NULL)) {
1088 if ((strcmp(entry->d_name, ".") == 0) ||
1089 (strcmp(entry->d_name, "..") == 0)) {
1090 continue;
1091 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001092
Erik Andersene49d5ec2000-02-08 19:58:47 +00001093 /*
1094 * Build the full path name to the file.
1095 */
1096 strcpy(fullName, dirName);
1097
1098 if (needSlash)
1099 strcat(fullName, "/");
1100
1101 strcat(fullName, entry->d_name);
1102
1103 /*
1104 * Write this file to the tar file, noticing whether or not
1105 * the file is a symbolic link.
1106 */
1107 saveFile(fullName, TRUE);
1108 }
1109
1110 /*
1111 * All done, close the directory.
1112 */
1113 closedir(dir);
Eric Andersencc8ed391999-10-05 16:24:54 +00001114}
1115
1116
1117/*
1118 * Write a tar header for the specified file name and status.
1119 * It is assumed that the file name fits.
1120 */
Erik Andersene49d5ec2000-02-08 19:58:47 +00001121static void writeHeader(const char *fileName, const struct stat *statbuf)
Eric Andersencc8ed391999-10-05 16:24:54 +00001122{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001123 long checkSum;
1124 const unsigned char *cp;
1125 int len;
1126 TarHeader header;
Eric Andersencc8ed391999-10-05 16:24:54 +00001127
Erik Andersene49d5ec2000-02-08 19:58:47 +00001128 /*
1129 * Zero the header block in preparation for filling it in.
1130 */
1131 memset((char *) &header, 0, sizeof(header));
Eric Andersencc8ed391999-10-05 16:24:54 +00001132
Erik Andersene49d5ec2000-02-08 19:58:47 +00001133 /*
1134 * Fill in the header.
1135 */
1136 strcpy(header.name, fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +00001137
Erik Andersene49d5ec2000-02-08 19:58:47 +00001138 strncpy(header.magic, TAR_MAGIC, sizeof(header.magic));
1139 strncpy(header.version, TAR_VERSION, sizeof(header.version));
Eric Andersencc8ed391999-10-05 16:24:54 +00001140
Erik Andersene49d5ec2000-02-08 19:58:47 +00001141 putOctal(header.mode, sizeof(header.mode), statbuf->st_mode & 0777);
1142 putOctal(header.uid, sizeof(header.uid), statbuf->st_uid);
1143 putOctal(header.gid, sizeof(header.gid), statbuf->st_gid);
1144 putOctal(header.size, sizeof(header.size), statbuf->st_size);
1145 putOctal(header.mtime, sizeof(header.mtime), statbuf->st_mtime);
Eric Andersencc8ed391999-10-05 16:24:54 +00001146
Erik Andersene49d5ec2000-02-08 19:58:47 +00001147 header.typeFlag = TAR_TYPE_REGULAR;
Eric Andersencc8ed391999-10-05 16:24:54 +00001148
Erik Andersene49d5ec2000-02-08 19:58:47 +00001149 /*
1150 * Calculate and store the checksum.
1151 * This is the sum of all of the bytes of the header,
1152 * with the checksum field itself treated as blanks.
1153 */
1154 memset(header.checkSum, ' ', sizeof(header.checkSum));
Eric Andersencc8ed391999-10-05 16:24:54 +00001155
Erik Andersene49d5ec2000-02-08 19:58:47 +00001156 cp = (const unsigned char *) &header;
1157 len = sizeof(header);
1158 checkSum = 0;
Eric Andersencc8ed391999-10-05 16:24:54 +00001159
Erik Andersene49d5ec2000-02-08 19:58:47 +00001160 while (len-- > 0)
1161 checkSum += *cp++;
Eric Andersencc8ed391999-10-05 16:24:54 +00001162
Erik Andersene49d5ec2000-02-08 19:58:47 +00001163 putOctal(header.checkSum, sizeof(header.checkSum), checkSum);
Eric Andersencc8ed391999-10-05 16:24:54 +00001164
Erik Andersene49d5ec2000-02-08 19:58:47 +00001165 /*
1166 * Write the tar header.
1167 */
1168 writeTarBlock((const char *) &header, sizeof(header));
Eric Andersencc8ed391999-10-05 16:24:54 +00001169}
1170
1171
1172/*
1173 * Write data to one or more blocks of the tar file.
1174 * The data is always padded out to a multiple of TAR_BLOCK_SIZE.
1175 * The errorFlag static variable is set on an error.
1176 */
Erik Andersene49d5ec2000-02-08 19:58:47 +00001177static void writeTarBlock(const char *buf, int len)
Eric Andersencc8ed391999-10-05 16:24:54 +00001178{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001179 int partialLength;
1180 int completeLength;
1181 char fullBlock[TAR_BLOCK_SIZE];
Eric Andersencc8ed391999-10-05 16:24:54 +00001182
Erik Andersene49d5ec2000-02-08 19:58:47 +00001183 /*
1184 * If we had a write error before, then do nothing more.
1185 */
1186 if (errorFlag == TRUE)
1187 return;
Eric Andersencc8ed391999-10-05 16:24:54 +00001188
Erik Andersene49d5ec2000-02-08 19:58:47 +00001189 /*
1190 * Get the amount of complete and partial blocks.
1191 */
1192 partialLength = len % TAR_BLOCK_SIZE;
1193 completeLength = len - partialLength;
Eric Andersencc8ed391999-10-05 16:24:54 +00001194
Erik Andersene49d5ec2000-02-08 19:58:47 +00001195 /*
1196 * Write all of the complete blocks.
1197 */
1198 if ((completeLength > 0) && !fullWrite(tarFd, buf, completeLength)) {
1199 perror(tarName);
Eric Andersencc8ed391999-10-05 16:24:54 +00001200
Erik Andersene49d5ec2000-02-08 19:58:47 +00001201 errorFlag = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001202
Erik Andersene49d5ec2000-02-08 19:58:47 +00001203 return;
1204 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001205
Erik Andersene49d5ec2000-02-08 19:58:47 +00001206 /*
1207 * If there are no partial blocks left, we are done.
1208 */
1209 if (partialLength == 0)
1210 return;
Eric Andersencc8ed391999-10-05 16:24:54 +00001211
Erik Andersene49d5ec2000-02-08 19:58:47 +00001212 /*
1213 * Copy the partial data into a complete block, and pad the rest
1214 * of it with zeroes.
1215 */
1216 memcpy(fullBlock, buf + completeLength, partialLength);
1217 memset(fullBlock + partialLength, 0, TAR_BLOCK_SIZE - partialLength);
Eric Andersencc8ed391999-10-05 16:24:54 +00001218
Erik Andersene49d5ec2000-02-08 19:58:47 +00001219 /*
1220 * Write the last complete block.
1221 */
1222 if (!fullWrite(tarFd, fullBlock, TAR_BLOCK_SIZE)) {
1223 perror(tarName);
Eric Andersencc8ed391999-10-05 16:24:54 +00001224
Erik Andersene49d5ec2000-02-08 19:58:47 +00001225 errorFlag = TRUE;
1226 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001227}
1228
1229
1230/*
Eric Andersencc8ed391999-10-05 16:24:54 +00001231 * Put an octal string into the specified buffer.
1232 * The number is zero and space padded and possibly null padded.
1233 * Returns TRUE if successful.
1234 */
Erik Andersene49d5ec2000-02-08 19:58:47 +00001235static int putOctal(char *cp, int len, long value)
Eric Andersencc8ed391999-10-05 16:24:54 +00001236{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001237 int tempLength;
1238 char *tempString;
1239 char tempBuffer[32];
Eric Andersencc8ed391999-10-05 16:24:54 +00001240
Erik Andersene49d5ec2000-02-08 19:58:47 +00001241 /*
1242 * Create a string of the specified length with an initial space,
1243 * leading zeroes and the octal number, and a trailing null.
1244 */
1245 tempString = tempBuffer;
Eric Andersencc8ed391999-10-05 16:24:54 +00001246
Erik Andersene49d5ec2000-02-08 19:58:47 +00001247 sprintf(tempString, " %0*lo", len - 2, value);
Eric Andersencc8ed391999-10-05 16:24:54 +00001248
Erik Andersene49d5ec2000-02-08 19:58:47 +00001249 tempLength = strlen(tempString) + 1;
Eric Andersencc8ed391999-10-05 16:24:54 +00001250
Erik Andersene49d5ec2000-02-08 19:58:47 +00001251 /*
1252 * If the string is too large, suppress the leading space.
1253 */
1254 if (tempLength > len) {
1255 tempLength--;
1256 tempString++;
1257 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001258
Erik Andersene49d5ec2000-02-08 19:58:47 +00001259 /*
1260 * If the string is still too large, suppress the trailing null.
1261 */
1262 if (tempLength > len)
1263 tempLength--;
Eric Andersencc8ed391999-10-05 16:24:54 +00001264
Erik Andersene49d5ec2000-02-08 19:58:47 +00001265 /*
1266 * If the string is still too large, fail.
1267 */
1268 if (tempLength > len)
1269 return FALSE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001270
Erik Andersene49d5ec2000-02-08 19:58:47 +00001271 /*
1272 * Copy the string to the field.
1273 */
1274 memcpy(cp, tempString, len);
Eric Andersencc8ed391999-10-05 16:24:54 +00001275
Erik Andersene49d5ec2000-02-08 19:58:47 +00001276 return TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001277}
Erik Andersen05100cd2000-01-16 01:30:52 +00001278#endif
Eric Andersencc8ed391999-10-05 16:24:54 +00001279
Eric Andersencc8ed391999-10-05 16:24:54 +00001280/* END CODE */