blob: c7ef3851ccbd7172397a91cfc070710455674f34 [file] [log] [blame]
Eric Andersencc8ed391999-10-05 16:24:54 +00001/*
Eric Andersenc4996011999-10-20 22:08:37 +00002 * Mini tar implementation for busybox based on code taken from sash.
3 *
Eric Andersencc8ed391999-10-05 16:24:54 +00004 * Copyright (c) 1999 by David I. Bell
5 * Permission is granted to use, distribute, or modify this source,
6 * provided that this copyright notice remains intact.
7 *
Eric Andersencc8ed391999-10-05 16:24:54 +00008 * Permission to distribute this code under the GPL has been granted.
Eric Andersenc4996011999-10-20 22:08:37 +00009 *
Eric Andersen3cf52d11999-10-12 22:26:06 +000010 * Modified for busybox by Erik Andersen <andersee@debian.org>
Eric Andersenc4996011999-10-20 22:08:37 +000011 * Adjusted to grok stdin/stdout options.
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 *
Eric Andersencc8ed391999-10-05 16:24:54 +000027 */
28
29
30#include "internal.h"
Eric Andersencc8ed391999-10-05 16:24:54 +000031#include <stdio.h>
32#include <dirent.h>
33#include <errno.h>
34#include <fcntl.h>
35#include <signal.h>
36#include <time.h>
37
Eric Andersene77ae3a1999-10-19 20:03:34 +000038
39static const char tar_usage[] =
40 "Create, extract, or list files from a TAR file\n\n"
41 "usage: tar -[cxtvOf] [tarFileName] [FILE] ...\n"
42 "\tc=create, x=extract, t=list contents, v=verbose,\n"
43 "\tO=extract to stdout, f=tarfile or \"-\" for stdin\n";
44
45
46
Eric Andersencc8ed391999-10-05 16:24:54 +000047/*
48 * Tar file constants.
49 */
50#define TAR_BLOCK_SIZE 512
51#define TAR_NAME_SIZE 100
52
53
54/*
55 * The POSIX (and basic GNU) tar header format.
56 * This structure is always embedded in a TAR_BLOCK_SIZE sized block
57 * with zero padding. We only process this information minimally.
58 */
Eric Andersen3cf52d11999-10-12 22:26:06 +000059typedef struct {
60 char name[TAR_NAME_SIZE];
61 char mode[8];
62 char uid[8];
63 char gid[8];
64 char size[12];
65 char mtime[12];
66 char checkSum[8];
67 char typeFlag;
68 char linkName[TAR_NAME_SIZE];
69 char magic[6];
70 char version[2];
71 char uname[32];
72 char gname[32];
73 char devMajor[8];
74 char devMinor[8];
75 char prefix[155];
Eric Andersencc8ed391999-10-05 16:24:54 +000076} TarHeader;
77
78#define TAR_MAGIC "ustar"
79#define TAR_VERSION "00"
80
81#define TAR_TYPE_REGULAR '0'
82#define TAR_TYPE_HARD_LINK '1'
83#define TAR_TYPE_SOFT_LINK '2'
84
85
86/*
87 * Static data.
88 */
Eric Andersen3cf52d11999-10-12 22:26:06 +000089static int listFlag;
90static int extractFlag;
91static int createFlag;
92static int verboseFlag;
93static int tostdoutFlag;
Eric Andersencc8ed391999-10-05 16:24:54 +000094
Eric Andersen3cf52d11999-10-12 22:26:06 +000095static int inHeader;
96static int badHeader;
97static int errorFlag;
98static int skipFileFlag;
99static int warnedRoot;
100static int eofFlag;
101static long dataCc;
102static int outFd;
103static char outName[TAR_NAME_SIZE];
Eric Andersencc8ed391999-10-05 16:24:54 +0000104
105
106/*
107 * Static data associated with the tar file.
108 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000109static const char *tarName;
110static int tarFd;
111static dev_t tarDev;
112static ino_t tarInode;
Eric Andersencc8ed391999-10-05 16:24:54 +0000113
114
115/*
116 * Local procedures to restore files from a tar file.
117 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000118static void readTarFile (int fileCount, char **fileTable);
119static void readData (const char *cp, int count);
Eric Andersen3cf52d11999-10-12 22:26:06 +0000120static long getOctal (const char *cp, int len);
Eric Andersencc8ed391999-10-05 16:24:54 +0000121
Eric Andersen3cf52d11999-10-12 22:26:06 +0000122static void readHeader (const TarHeader * hp,
123 int fileCount, char **fileTable);
Eric Andersencc8ed391999-10-05 16:24:54 +0000124
125
126/*
127 * Local procedures to save files into a tar file.
128 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000129static void saveFile (const char *fileName, int seeLinks);
Eric Andersencc8ed391999-10-05 16:24:54 +0000130
Eric Andersen3cf52d11999-10-12 22:26:06 +0000131static void saveRegularFile (const char *fileName,
132 const struct stat *statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000133
Eric Andersen3cf52d11999-10-12 22:26:06 +0000134static void saveDirectory (const char *fileName,
135 const struct stat *statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000136
Eric Andersen3cf52d11999-10-12 22:26:06 +0000137static int wantFileName (const char *fileName,
138 int fileCount, char **fileTable);
Eric Andersencc8ed391999-10-05 16:24:54 +0000139
Eric Andersen3cf52d11999-10-12 22:26:06 +0000140static void writeHeader (const char *fileName, const struct stat *statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000141
Eric Andersen3cf52d11999-10-12 22:26:06 +0000142static void writeTarFile (int fileCount, char **fileTable);
143static void writeTarBlock (const char *buf, int len);
144static int putOctal (char *cp, int len, long value);
Eric Andersencc8ed391999-10-05 16:24:54 +0000145
146
Eric Andersen3cf52d11999-10-12 22:26:06 +0000147extern int tar_main (int argc, char **argv)
Eric Andersencc8ed391999-10-05 16:24:54 +0000148{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000149 const char *options;
Eric Andersencc8ed391999-10-05 16:24:54 +0000150
Eric Andersen3cf52d11999-10-12 22:26:06 +0000151 argc--;
152 argv++;
Eric Andersencc8ed391999-10-05 16:24:54 +0000153
Eric Andersen3cf52d11999-10-12 22:26:06 +0000154 if (argc < 1) {
155 fprintf (stderr, "%s", tar_usage);
156 exit (FALSE);
157 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000158
159
Eric Andersen3cf52d11999-10-12 22:26:06 +0000160 errorFlag = FALSE;
161 extractFlag = FALSE;
162 createFlag = FALSE;
163 listFlag = FALSE;
164 verboseFlag = FALSE;
165 tostdoutFlag = FALSE;
166 tarName = NULL;
167 tarDev = 0;
168 tarInode = 0;
169 tarFd = -1;
Eric Andersencc8ed391999-10-05 16:24:54 +0000170
Eric Andersen3cf52d11999-10-12 22:26:06 +0000171 /*
172 * Parse the options.
173 */
174 options = *argv++;
175 argc--;
Eric Andersencc8ed391999-10-05 16:24:54 +0000176
Eric Andersen3cf52d11999-10-12 22:26:06 +0000177 if (**argv == '-') {
178 for (; *options; options++) {
179 switch (*options) {
180 case 'f':
181 if (tarName != NULL) {
182 fprintf (stderr, "Only one 'f' option allowed\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000183
Eric Andersen3cf52d11999-10-12 22:26:06 +0000184 exit (FALSE);
Eric Andersencc8ed391999-10-05 16:24:54 +0000185 }
Eric Andersen3cf52d11999-10-12 22:26:06 +0000186
187 tarName = *argv++;
188 argc--;
189
190 break;
191
192 case 't':
193 listFlag = TRUE;
194 break;
195
196 case 'x':
197 extractFlag = TRUE;
198 break;
199
200 case 'c':
201 createFlag = TRUE;
202 break;
203
204 case 'v':
205 verboseFlag = TRUE;
206 break;
207
208 case 'O':
209 tostdoutFlag = TRUE;
210 break;
211
212 case '-':
213 break;
214
215 default:
216 fprintf (stderr, "Unknown tar flag '%c'\n", *options);
217
218 exit (FALSE);
219 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000220 }
Eric Andersen3cf52d11999-10-12 22:26:06 +0000221 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000222
Eric Andersen3cf52d11999-10-12 22:26:06 +0000223 /*
224 * Validate the options.
225 */
226 if (extractFlag + listFlag + createFlag != 1) {
227 fprintf (stderr,
228 "Exactly one of 'c', 'x' or 't' must be specified\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000229
Eric Andersen3cf52d11999-10-12 22:26:06 +0000230 exit (FALSE);
231 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000232
Eric Andersen3cf52d11999-10-12 22:26:06 +0000233 /*
234 * Do the correct type of action supplying the rest of the
235 * command line arguments as the list of files to process.
236 */
237 if (createFlag)
238 writeTarFile (argc, argv);
239 else
240 readTarFile (argc, argv);
241 if (errorFlag)
242 fprintf (stderr, "\n");
243 exit (errorFlag);
Eric Andersencc8ed391999-10-05 16:24:54 +0000244}
245
246
247/*
248 * Read a tar file and extract or list the specified files within it.
249 * If the list is empty than all files are extracted or listed.
250 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000251static void readTarFile (int fileCount, char **fileTable)
Eric Andersencc8ed391999-10-05 16:24:54 +0000252{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000253 const char *cp;
254 int cc;
255 int inCc;
256 int blockSize;
257 char buf[BUF_SIZE];
Eric Andersencc8ed391999-10-05 16:24:54 +0000258
Eric Andersen3cf52d11999-10-12 22:26:06 +0000259 skipFileFlag = FALSE;
260 badHeader = FALSE;
261 warnedRoot = FALSE;
262 eofFlag = FALSE;
263 inHeader = TRUE;
264 inCc = 0;
265 dataCc = 0;
266 outFd = -1;
267 blockSize = sizeof (buf);
268 cp = buf;
Eric Andersencc8ed391999-10-05 16:24:54 +0000269
Eric Andersen3cf52d11999-10-12 22:26:06 +0000270 /*
271 * Open the tar file for reading.
272 */
273 if ((tarName == NULL) || !strcmp (tarName, "-")) {
274 tarFd = STDIN;
275 } else
276 tarFd = open (tarName, O_RDONLY);
277
278 if (tarFd < 0) {
279 perror (tarName);
280 errorFlag = TRUE;
281 return;
282 }
283
284 /*
285 * Read blocks from the file until an end of file header block
286 * has been seen. (A real end of file from a read is an error.)
287 */
288 while (!eofFlag) {
289 /*
290 * Read the next block of data if necessary.
291 * This will be a large block if possible, which we will
292 * then process in the small tar blocks.
Eric Andersencc8ed391999-10-05 16:24:54 +0000293 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000294 if (inCc <= 0) {
295 cp = buf;
296 inCc = fullRead (tarFd, buf, blockSize);
Eric Andersencc8ed391999-10-05 16:24:54 +0000297
Eric Andersen3cf52d11999-10-12 22:26:06 +0000298 if (inCc < 0) {
299 perror (tarName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000300 errorFlag = TRUE;
Eric Andersen3cf52d11999-10-12 22:26:06 +0000301 goto done;
302 }
303
304 if (inCc == 0) {
305 fprintf (stderr,
306 "Unexpected end of file from \"%s\"", tarName);
307 errorFlag = TRUE;
308 goto done;
309 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000310 }
311
Eric Andersen3cf52d11999-10-12 22:26:06 +0000312 /*
313 * If we are expecting a header block then examine it.
Eric Andersencc8ed391999-10-05 16:24:54 +0000314 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000315 if (inHeader) {
316 readHeader ((const TarHeader *) cp, fileCount, fileTable);
Eric Andersencc8ed391999-10-05 16:24:54 +0000317
Eric Andersen3cf52d11999-10-12 22:26:06 +0000318 cp += TAR_BLOCK_SIZE;
319 inCc -= TAR_BLOCK_SIZE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000320
Eric Andersen3cf52d11999-10-12 22:26:06 +0000321 continue;
Eric Andersencc8ed391999-10-05 16:24:54 +0000322 }
323
Eric Andersen3cf52d11999-10-12 22:26:06 +0000324 /*
325 * We are currently handling the data for a file.
326 * Process the minimum of the amount of data we have available
327 * and the amount left to be processed for the file.
Eric Andersencc8ed391999-10-05 16:24:54 +0000328 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000329 cc = inCc;
Eric Andersencc8ed391999-10-05 16:24:54 +0000330
Eric Andersen3cf52d11999-10-12 22:26:06 +0000331 if (cc > dataCc)
332 cc = dataCc;
333
334 readData (cp, cc);
335
336 /*
337 * If the amount left isn't an exact multiple of the tar block
338 * size then round it up to the next block boundary since there
339 * is padding at the end of the file.
Eric Andersencc8ed391999-10-05 16:24:54 +0000340 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000341 if (cc % TAR_BLOCK_SIZE)
342 cc += TAR_BLOCK_SIZE - (cc % TAR_BLOCK_SIZE);
343
344 cp += cc;
345 inCc -= cc;
346 }
347
348 done:
349 /*
350 * Close the tar file if needed.
351 */
352 if ((tarFd >= 0) && (close (tarFd) < 0))
353 perror (tarName);
354
355 /*
356 * Close the output file if needed.
357 * This is only done here on a previous error and so no
358 * message is required on errors.
359 */
360 if (tostdoutFlag == FALSE) {
361 if (outFd >= 0)
362 (void) close (outFd);
363 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000364}
365
366
367/*
368 * Examine the header block that was just read.
369 * This can specify the information for another file, or it can mark
370 * the end of the tar file.
371 */
372static void
Eric Andersen3cf52d11999-10-12 22:26:06 +0000373readHeader (const TarHeader * hp, int fileCount, char **fileTable)
Eric Andersencc8ed391999-10-05 16:24:54 +0000374{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000375 int mode;
376 int uid;
377 int gid;
378 int checkSum;
379 long size;
380 time_t mtime;
381 const char *name;
382 int cc;
383 int hardLink;
384 int softLink;
Eric Andersencc8ed391999-10-05 16:24:54 +0000385
Eric Andersen3cf52d11999-10-12 22:26:06 +0000386 /*
387 * If the block is completely empty, then this is the end of the
388 * archive file. If the name is null, then just skip this header.
389 */
390 name = hp->name;
Eric Andersencc8ed391999-10-05 16:24:54 +0000391
Eric Andersen3cf52d11999-10-12 22:26:06 +0000392 if (*name == '\0') {
393 for (cc = TAR_BLOCK_SIZE; cc > 0; cc--) {
394 if (*name++)
Eric Andersencc8ed391999-10-05 16:24:54 +0000395 return;
396 }
397
Eric Andersen3cf52d11999-10-12 22:26:06 +0000398 eofFlag = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000399
Eric Andersen3cf52d11999-10-12 22:26:06 +0000400 return;
401 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000402
Eric Andersen3cf52d11999-10-12 22:26:06 +0000403 /*
404 * There is another file in the archive to examine.
405 * Extract the encoded information and check it.
406 */
407 mode = getOctal (hp->mode, sizeof (hp->mode));
408 uid = getOctal (hp->uid, sizeof (hp->uid));
409 gid = getOctal (hp->gid, sizeof (hp->gid));
410 size = getOctal (hp->size, sizeof (hp->size));
411 mtime = getOctal (hp->mtime, sizeof (hp->mtime));
412 checkSum = getOctal (hp->checkSum, sizeof (hp->checkSum));
Eric Andersencc8ed391999-10-05 16:24:54 +0000413
Eric Andersen3cf52d11999-10-12 22:26:06 +0000414 if ((mode < 0) || (uid < 0) || (gid < 0) || (size < 0)) {
415 if (!badHeader)
416 fprintf (stderr, "Bad tar header, skipping\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000417
Eric Andersen3cf52d11999-10-12 22:26:06 +0000418 badHeader = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000419
Eric Andersen3cf52d11999-10-12 22:26:06 +0000420 return;
421 }
422
423 badHeader = FALSE;
424 skipFileFlag = FALSE;
425
426 /*
427 * Check for the file modes.
428 */
429 hardLink = ((hp->typeFlag == TAR_TYPE_HARD_LINK) ||
Eric Andersencc8ed391999-10-05 16:24:54 +0000430 (hp->typeFlag == TAR_TYPE_HARD_LINK - '0'));
431
Eric Andersen3cf52d11999-10-12 22:26:06 +0000432 softLink = ((hp->typeFlag == TAR_TYPE_SOFT_LINK) ||
Eric Andersencc8ed391999-10-05 16:24:54 +0000433 (hp->typeFlag == TAR_TYPE_SOFT_LINK - '0'));
434
Eric Andersen3cf52d11999-10-12 22:26:06 +0000435 /*
436 * Check for a directory or a regular file.
437 */
438 if (name[strlen (name) - 1] == '/')
439 mode |= S_IFDIR;
440 else if ((mode & S_IFMT) == 0)
441 mode |= S_IFREG;
Eric Andersencc8ed391999-10-05 16:24:54 +0000442
Eric Andersen3cf52d11999-10-12 22:26:06 +0000443 /*
444 * Check for absolute paths in the file.
445 * If we find any, then warn the user and make them relative.
446 */
447 if (*name == '/') {
448 while (*name == '/')
449 name++;
Eric Andersencc8ed391999-10-05 16:24:54 +0000450
Eric Andersen3cf52d11999-10-12 22:26:06 +0000451 if (!warnedRoot) {
452 fprintf (stderr,
453 "Absolute path detected, removing leading slashes\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000454 }
455
Eric Andersen3cf52d11999-10-12 22:26:06 +0000456 warnedRoot = TRUE;
457 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000458
Eric Andersen3cf52d11999-10-12 22:26:06 +0000459 /*
460 * See if we want this file to be restored.
461 * If not, then set up to skip it.
462 */
463 if (!wantFileName (name, fileCount, fileTable)) {
464 if (!hardLink && !softLink && S_ISREG (mode)) {
465 inHeader = (size == 0);
466 dataCc = size;
Eric Andersencc8ed391999-10-05 16:24:54 +0000467 }
468
Eric Andersen3cf52d11999-10-12 22:26:06 +0000469 skipFileFlag = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000470
Eric Andersen3cf52d11999-10-12 22:26:06 +0000471 return;
472 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000473
Eric Andersen3cf52d11999-10-12 22:26:06 +0000474 /*
475 * This file is to be handled.
476 * If we aren't extracting then just list information about the file.
477 */
478 if (!extractFlag) {
479 if (verboseFlag) {
480 printf ("%s %3d/%-d %9ld %s %s", modeString (mode),
481 uid, gid, size, timeString (mtime), name);
482 } else
483 printf ("%s", name);
Eric Andersencc8ed391999-10-05 16:24:54 +0000484
485 if (hardLink)
Eric Andersen3cf52d11999-10-12 22:26:06 +0000486 printf (" (link to \"%s\")", hp->linkName);
487 else if (softLink)
488 printf (" (symlink to \"%s\")", hp->linkName);
489 else if (S_ISREG (mode)) {
490 inHeader = (size == 0);
491 dataCc = size;
Eric Andersencc8ed391999-10-05 16:24:54 +0000492 }
493
Eric Andersen3cf52d11999-10-12 22:26:06 +0000494 printf ("\n");
495
496 return;
497 }
498
499 /*
500 * We really want to extract the file.
501 */
502 if (verboseFlag)
503 printf ("x %s\n", name);
504
505 if (hardLink) {
506 if (link (hp->linkName, name) < 0)
507 perror (name);
508
509 return;
510 }
511
512 if (softLink) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000513#ifdef S_ISLNK
Eric Andersen3cf52d11999-10-12 22:26:06 +0000514 if (symlink (hp->linkName, name) < 0)
515 perror (name);
Eric Andersencc8ed391999-10-05 16:24:54 +0000516#else
Eric Andersen3cf52d11999-10-12 22:26:06 +0000517 fprintf (stderr, "Cannot create symbolic links\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000518#endif
Eric Andersen3cf52d11999-10-12 22:26:06 +0000519 return;
520 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000521
Eric Andersen3cf52d11999-10-12 22:26:06 +0000522 /*
523 * If the file is a directory, then just create the path.
524 */
525 if (S_ISDIR (mode)) {
526 createPath (name, mode);
Eric Andersencc8ed391999-10-05 16:24:54 +0000527
Eric Andersen3cf52d11999-10-12 22:26:06 +0000528 return;
529 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000530
Eric Andersen3cf52d11999-10-12 22:26:06 +0000531 /*
532 * There is a file to write.
533 * First create the path to it if necessary with a default permission.
534 */
535 createPath (name, 0777);
Eric Andersencc8ed391999-10-05 16:24:54 +0000536
Eric Andersen3cf52d11999-10-12 22:26:06 +0000537 inHeader = (size == 0);
538 dataCc = size;
Eric Andersencc8ed391999-10-05 16:24:54 +0000539
Eric Andersen3cf52d11999-10-12 22:26:06 +0000540 /*
541 * Start the output file.
542 */
543 if (tostdoutFlag == TRUE)
544 outFd = STDOUT;
545 else
546 outFd = open (name, O_WRONLY | O_CREAT | O_TRUNC, mode);
Eric Andersencc8ed391999-10-05 16:24:54 +0000547
Eric Andersen3cf52d11999-10-12 22:26:06 +0000548 if (outFd < 0) {
549 perror (name);
550 skipFileFlag = TRUE;
551 return;
552 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000553
Eric Andersen3cf52d11999-10-12 22:26:06 +0000554 /*
555 * If the file is empty, then that's all we need to do.
556 */
557 if (size == 0 && tostdoutFlag == FALSE) {
558 (void) close (outFd);
559 outFd = -1;
560 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000561}
562
563
564/*
565 * Handle a data block of some specified size that was read.
566 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000567static void readData (const char *cp, int count)
Eric Andersencc8ed391999-10-05 16:24:54 +0000568{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000569 /*
570 * Reduce the amount of data left in this file.
571 * If there is no more data left, then we need to read
572 * the header again.
573 */
574 dataCc -= count;
Eric Andersencc8ed391999-10-05 16:24:54 +0000575
Eric Andersen3cf52d11999-10-12 22:26:06 +0000576 if (dataCc <= 0)
577 inHeader = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000578
Eric Andersen3cf52d11999-10-12 22:26:06 +0000579 /*
580 * If we aren't extracting files or this file is being
581 * skipped then do nothing more.
582 */
583 if (!extractFlag || skipFileFlag)
584 return;
Eric Andersencc8ed391999-10-05 16:24:54 +0000585
Eric Andersen3cf52d11999-10-12 22:26:06 +0000586 /*
587 * Write the data to the output file.
588 */
589 if (fullWrite (outFd, cp, count) < 0) {
590 perror (outName);
591 if (tostdoutFlag == FALSE) {
592 (void) close (outFd);
593 outFd = -1;
Eric Andersencc8ed391999-10-05 16:24:54 +0000594 }
Eric Andersen3cf52d11999-10-12 22:26:06 +0000595 skipFileFlag = TRUE;
596 return;
597 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000598
Eric Andersen3cf52d11999-10-12 22:26:06 +0000599 /*
600 * If the write failed, close the file and disable further
601 * writes to this file.
602 */
603 if (dataCc <= 0 && tostdoutFlag == FALSE) {
604 if (close (outFd))
605 perror (outName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000606
Eric Andersen3cf52d11999-10-12 22:26:06 +0000607 outFd = -1;
608 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000609}
610
611
612/*
613 * Write a tar file containing the specified files.
614 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000615static void writeTarFile (int fileCount, char **fileTable)
Eric Andersencc8ed391999-10-05 16:24:54 +0000616{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000617 struct stat statbuf;
Eric Andersencc8ed391999-10-05 16:24:54 +0000618
Eric Andersen3cf52d11999-10-12 22:26:06 +0000619 /*
620 * Make sure there is at least one file specified.
621 */
622 if (fileCount <= 0) {
623 fprintf (stderr, "No files specified to be saved\n");
624 errorFlag = TRUE;
625 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000626
Eric Andersen3cf52d11999-10-12 22:26:06 +0000627 /*
628 * Create the tar file for writing.
629 */
630 if ((tarName == NULL) || !strcmp (tarName, "-")) {
631 tostdoutFlag = TRUE;
632 tarFd = STDOUT;
633 } else
634 tarFd = open (tarName, O_WRONLY | O_CREAT | O_TRUNC, 0666);
Eric Andersencc8ed391999-10-05 16:24:54 +0000635
Eric Andersen3cf52d11999-10-12 22:26:06 +0000636 if (tarFd < 0) {
637 perror (tarName);
638 errorFlag = TRUE;
639 return;
640 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000641
Eric Andersen3cf52d11999-10-12 22:26:06 +0000642 /*
643 * Get the device and inode of the tar file for checking later.
644 */
645 if (fstat (tarFd, &statbuf) < 0) {
646 perror (tarName);
647 errorFlag = TRUE;
648 goto done;
649 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000650
Eric Andersen3cf52d11999-10-12 22:26:06 +0000651 tarDev = statbuf.st_dev;
652 tarInode = statbuf.st_ino;
Eric Andersencc8ed391999-10-05 16:24:54 +0000653
Eric Andersen3cf52d11999-10-12 22:26:06 +0000654 /*
655 * Append each file name into the archive file.
656 * Follow symbolic links for these top level file names.
657 */
658 while (!errorFlag && (fileCount-- > 0)) {
659 saveFile (*fileTable++, FALSE);
660 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000661
Eric Andersen3cf52d11999-10-12 22:26:06 +0000662 /*
663 * Now write an empty block of zeroes to end the archive.
664 */
665 writeTarBlock ("", 1);
Eric Andersencc8ed391999-10-05 16:24:54 +0000666
667
Eric Andersen3cf52d11999-10-12 22:26:06 +0000668 done:
669 /*
670 * Close the tar file and check for errors if it was opened.
671 */
672 if ((tostdoutFlag == FALSE) && (tarFd >= 0) && (close (tarFd) < 0))
673 perror (tarName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000674}
675
676
677/*
678 * Save one file into the tar file.
679 * If the file is a directory, then this will recursively save all of
680 * the files and directories within the directory. The seeLinks
681 * flag indicates whether or not we want to see symbolic links as
682 * they really are, instead of blindly following them.
683 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000684static void saveFile (const char *fileName, int seeLinks)
Eric Andersencc8ed391999-10-05 16:24:54 +0000685{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000686 int status;
687 int mode;
688 struct stat statbuf;
Eric Andersencc8ed391999-10-05 16:24:54 +0000689
Eric Andersen3cf52d11999-10-12 22:26:06 +0000690 if (verboseFlag)
691 printf ("a %s\n", fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000692
Eric Andersen3cf52d11999-10-12 22:26:06 +0000693 /*
694 * Check that the file name will fit in the header.
695 */
696 if (strlen (fileName) >= TAR_NAME_SIZE) {
697 fprintf (stderr, "%s: File name is too long\n", fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000698
Eric Andersen3cf52d11999-10-12 22:26:06 +0000699 return;
700 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000701
Eric Andersen3cf52d11999-10-12 22:26:06 +0000702 /*
703 * Find out about the file.
704 */
Eric Andersencc8ed391999-10-05 16:24:54 +0000705#ifdef S_ISLNK
Eric Andersen3cf52d11999-10-12 22:26:06 +0000706 if (seeLinks)
707 status = lstat (fileName, &statbuf);
708 else
Eric Andersencc8ed391999-10-05 16:24:54 +0000709#endif
Eric Andersen3cf52d11999-10-12 22:26:06 +0000710 status = stat (fileName, &statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000711
Eric Andersen3cf52d11999-10-12 22:26:06 +0000712 if (status < 0) {
713 perror (fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000714
Eric Andersen3cf52d11999-10-12 22:26:06 +0000715 return;
716 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000717
Eric Andersen3cf52d11999-10-12 22:26:06 +0000718 /*
719 * Make sure we aren't trying to save our file into itself.
720 */
721 if ((statbuf.st_dev == tarDev) && (statbuf.st_ino == tarInode)) {
722 fprintf (stderr, "Skipping saving of archive file itself\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000723
Eric Andersen3cf52d11999-10-12 22:26:06 +0000724 return;
725 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000726
Eric Andersen3cf52d11999-10-12 22:26:06 +0000727 /*
728 * Check the type of file.
729 */
730 mode = statbuf.st_mode;
Eric Andersencc8ed391999-10-05 16:24:54 +0000731
Eric Andersen3cf52d11999-10-12 22:26:06 +0000732 if (S_ISDIR (mode)) {
733 saveDirectory (fileName, &statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000734
Eric Andersen3cf52d11999-10-12 22:26:06 +0000735 return;
736 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000737
Eric Andersen3cf52d11999-10-12 22:26:06 +0000738 if (S_ISREG (mode)) {
739 saveRegularFile (fileName, &statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000740
Eric Andersen3cf52d11999-10-12 22:26:06 +0000741 return;
742 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000743
Eric Andersen3cf52d11999-10-12 22:26:06 +0000744 /*
745 * The file is a strange type of file, ignore it.
746 */
747 fprintf (stderr, "%s: not a directory or regular file\n", fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000748}
749
750
751/*
752 * Save a regular file to the tar file.
753 */
754static void
Eric Andersen3cf52d11999-10-12 22:26:06 +0000755saveRegularFile (const char *fileName, const struct stat *statbuf)
Eric Andersencc8ed391999-10-05 16:24:54 +0000756{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000757 int sawEof;
758 int fileFd;
759 int cc;
760 int dataCount;
761 long fullDataCount;
762 char data[TAR_BLOCK_SIZE * 16];
Eric Andersencc8ed391999-10-05 16:24:54 +0000763
Eric Andersen3cf52d11999-10-12 22:26:06 +0000764 /*
765 * Open the file for reading.
766 */
767 fileFd = open (fileName, O_RDONLY);
768
769 if (fileFd < 0) {
770 perror (fileName);
771
772 return;
773 }
774
775 /*
776 * Write out the header for the file.
777 */
778 writeHeader (fileName, statbuf);
779
780 /*
781 * Write the data blocks of the file.
782 * We must be careful to write the amount of data that the stat
783 * buffer indicated, even if the file has changed size. Otherwise
784 * the tar file will be incorrect.
785 */
786 fullDataCount = statbuf->st_size;
787 sawEof = FALSE;
788
789 while (fullDataCount > 0) {
790 /*
791 * Get the amount to write this iteration which is
792 * the minumum of the amount left to write and the
793 * buffer size.
Eric Andersencc8ed391999-10-05 16:24:54 +0000794 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000795 dataCount = sizeof (data);
Eric Andersencc8ed391999-10-05 16:24:54 +0000796
Eric Andersen3cf52d11999-10-12 22:26:06 +0000797 if (dataCount > fullDataCount)
798 dataCount = (int) fullDataCount;
799
800 /*
801 * Read the data from the file if we haven't seen the
802 * end of file yet.
803 */
804 cc = 0;
805
806 if (!sawEof) {
807 cc = fullRead (fileFd, data, dataCount);
808
809 if (cc < 0) {
810 perror (fileName);
811
812 (void) close (fileFd);
813 errorFlag = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000814
815 return;
Eric Andersen3cf52d11999-10-12 22:26:06 +0000816 }
817
818 /*
819 * If the file ended too soon, complain and set
820 * a flag so we will zero fill the rest of it.
821 */
822 if (cc < dataCount) {
823 fprintf (stderr,
824 "%s: Short read - zero filling", fileName);
825
826 sawEof = TRUE;
827 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000828 }
829
Eric Andersen3cf52d11999-10-12 22:26:06 +0000830 /*
831 * Zero fill the rest of the data if necessary.
Eric Andersencc8ed391999-10-05 16:24:54 +0000832 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000833 if (cc < dataCount)
834 memset (data + cc, 0, dataCount - cc);
Eric Andersencc8ed391999-10-05 16:24:54 +0000835
Eric Andersen3cf52d11999-10-12 22:26:06 +0000836 /*
837 * Write the buffer to the TAR file.
Eric Andersencc8ed391999-10-05 16:24:54 +0000838 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000839 writeTarBlock (data, dataCount);
Eric Andersencc8ed391999-10-05 16:24:54 +0000840
Eric Andersen3cf52d11999-10-12 22:26:06 +0000841 fullDataCount -= dataCount;
842 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000843
Eric Andersen3cf52d11999-10-12 22:26:06 +0000844 /*
845 * Close the file.
846 */
847 if ((tostdoutFlag == FALSE) && close (fileFd) < 0)
848 fprintf (stderr, "%s: close: %s\n", fileName, strerror (errno));
Eric Andersencc8ed391999-10-05 16:24:54 +0000849}
850
851
852/*
853 * Save a directory and all of its files to the tar file.
854 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000855static void saveDirectory (const char *dirName, const struct stat *statbuf)
Eric Andersencc8ed391999-10-05 16:24:54 +0000856{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000857 DIR *dir;
858 struct dirent *entry;
859 int needSlash;
Eric Andersen1b61f411999-10-13 18:56:42 +0000860 char fullName[NAME_MAX];
Eric Andersencc8ed391999-10-05 16:24:54 +0000861
Eric Andersen3cf52d11999-10-12 22:26:06 +0000862 /*
863 * Construct the directory name as used in the tar file by appending
864 * a slash character to it.
865 */
866 strcpy (fullName, dirName);
867 strcat (fullName, "/");
Eric Andersencc8ed391999-10-05 16:24:54 +0000868
Eric Andersen3cf52d11999-10-12 22:26:06 +0000869 /*
870 * Write out the header for the directory entry.
871 */
872 writeHeader (fullName, statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000873
Eric Andersen3cf52d11999-10-12 22:26:06 +0000874 /*
875 * Open the directory.
876 */
877 dir = opendir (dirName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000878
Eric Andersen3cf52d11999-10-12 22:26:06 +0000879 if (dir == NULL) {
880 fprintf (stderr, "Cannot read directory \"%s\": %s\n",
881 dirName, strerror (errno));
Eric Andersencc8ed391999-10-05 16:24:54 +0000882
Eric Andersen3cf52d11999-10-12 22:26:06 +0000883 return;
884 }
885
886 /*
887 * See if a slash is needed.
888 */
889 needSlash = (*dirName && (dirName[strlen (dirName) - 1] != '/'));
890
891 /*
892 * Read all of the directory entries and check them,
893 * except for the current and parent directory entries.
894 */
895 while (!errorFlag && ((entry = readdir (dir)) != NULL)) {
896 if ((strcmp (entry->d_name, ".") == 0) ||
897 (strcmp (entry->d_name, "..") == 0)) {
898 continue;
Eric Andersencc8ed391999-10-05 16:24:54 +0000899 }
900
Eric Andersen3cf52d11999-10-12 22:26:06 +0000901 /*
902 * Build the full path name to the file.
Eric Andersencc8ed391999-10-05 16:24:54 +0000903 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000904 strcpy (fullName, dirName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000905
Eric Andersen3cf52d11999-10-12 22:26:06 +0000906 if (needSlash)
907 strcat (fullName, "/");
908
909 strcat (fullName, entry->d_name);
910
911 /*
912 * Write this file to the tar file, noticing whether or not
913 * the file is a symbolic link.
Eric Andersencc8ed391999-10-05 16:24:54 +0000914 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000915 saveFile (fullName, TRUE);
916 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000917
Eric Andersen3cf52d11999-10-12 22:26:06 +0000918 /*
919 * All done, close the directory.
920 */
921 closedir (dir);
Eric Andersencc8ed391999-10-05 16:24:54 +0000922}
923
924
925/*
926 * Write a tar header for the specified file name and status.
927 * It is assumed that the file name fits.
928 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000929static void writeHeader (const char *fileName, const struct stat *statbuf)
Eric Andersencc8ed391999-10-05 16:24:54 +0000930{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000931 long checkSum;
932 const unsigned char *cp;
933 int len;
934 TarHeader header;
Eric Andersencc8ed391999-10-05 16:24:54 +0000935
Eric Andersen3cf52d11999-10-12 22:26:06 +0000936 /*
937 * Zero the header block in preparation for filling it in.
938 */
939 memset ((char *) &header, 0, sizeof (header));
Eric Andersencc8ed391999-10-05 16:24:54 +0000940
Eric Andersen3cf52d11999-10-12 22:26:06 +0000941 /*
942 * Fill in the header.
943 */
944 strcpy (header.name, fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000945
Eric Andersen3cf52d11999-10-12 22:26:06 +0000946 strncpy (header.magic, TAR_MAGIC, sizeof (header.magic));
947 strncpy (header.version, TAR_VERSION, sizeof (header.version));
Eric Andersencc8ed391999-10-05 16:24:54 +0000948
Eric Andersen3cf52d11999-10-12 22:26:06 +0000949 putOctal (header.mode, sizeof (header.mode), statbuf->st_mode & 0777);
950 putOctal (header.uid, sizeof (header.uid), statbuf->st_uid);
951 putOctal (header.gid, sizeof (header.gid), statbuf->st_gid);
952 putOctal (header.size, sizeof (header.size), statbuf->st_size);
953 putOctal (header.mtime, sizeof (header.mtime), statbuf->st_mtime);
Eric Andersencc8ed391999-10-05 16:24:54 +0000954
Eric Andersen3cf52d11999-10-12 22:26:06 +0000955 header.typeFlag = TAR_TYPE_REGULAR;
Eric Andersencc8ed391999-10-05 16:24:54 +0000956
Eric Andersen3cf52d11999-10-12 22:26:06 +0000957 /*
958 * Calculate and store the checksum.
959 * This is the sum of all of the bytes of the header,
960 * with the checksum field itself treated as blanks.
961 */
962 memset (header.checkSum, ' ', sizeof (header.checkSum));
Eric Andersencc8ed391999-10-05 16:24:54 +0000963
Eric Andersen3cf52d11999-10-12 22:26:06 +0000964 cp = (const unsigned char *) &header;
965 len = sizeof (header);
966 checkSum = 0;
Eric Andersencc8ed391999-10-05 16:24:54 +0000967
Eric Andersen3cf52d11999-10-12 22:26:06 +0000968 while (len-- > 0)
969 checkSum += *cp++;
Eric Andersencc8ed391999-10-05 16:24:54 +0000970
Eric Andersen3cf52d11999-10-12 22:26:06 +0000971 putOctal (header.checkSum, sizeof (header.checkSum), checkSum);
Eric Andersencc8ed391999-10-05 16:24:54 +0000972
Eric Andersen3cf52d11999-10-12 22:26:06 +0000973 /*
974 * Write the tar header.
975 */
976 writeTarBlock ((const char *) &header, sizeof (header));
Eric Andersencc8ed391999-10-05 16:24:54 +0000977}
978
979
980/*
981 * Write data to one or more blocks of the tar file.
982 * The data is always padded out to a multiple of TAR_BLOCK_SIZE.
983 * The errorFlag static variable is set on an error.
984 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000985static void writeTarBlock (const char *buf, int len)
Eric Andersencc8ed391999-10-05 16:24:54 +0000986{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000987 int partialLength;
988 int completeLength;
989 char fullBlock[TAR_BLOCK_SIZE];
Eric Andersencc8ed391999-10-05 16:24:54 +0000990
Eric Andersen3cf52d11999-10-12 22:26:06 +0000991 /*
992 * If we had a write error before, then do nothing more.
993 */
994 if (errorFlag)
995 return;
Eric Andersencc8ed391999-10-05 16:24:54 +0000996
Eric Andersen3cf52d11999-10-12 22:26:06 +0000997 /*
998 * Get the amount of complete and partial blocks.
999 */
1000 partialLength = len % TAR_BLOCK_SIZE;
1001 completeLength = len - partialLength;
Eric Andersencc8ed391999-10-05 16:24:54 +00001002
Eric Andersen3cf52d11999-10-12 22:26:06 +00001003 /*
1004 * Write all of the complete blocks.
1005 */
1006 if ((completeLength > 0) && !fullWrite (tarFd, buf, completeLength)) {
1007 perror (tarName);
Eric Andersencc8ed391999-10-05 16:24:54 +00001008
Eric Andersen3cf52d11999-10-12 22:26:06 +00001009 errorFlag = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001010
Eric Andersen3cf52d11999-10-12 22:26:06 +00001011 return;
1012 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001013
Eric Andersen3cf52d11999-10-12 22:26:06 +00001014 /*
1015 * If there are no partial blocks left, we are done.
1016 */
1017 if (partialLength == 0)
1018 return;
Eric Andersencc8ed391999-10-05 16:24:54 +00001019
Eric Andersen3cf52d11999-10-12 22:26:06 +00001020 /*
1021 * Copy the partial data into a complete block, and pad the rest
1022 * of it with zeroes.
1023 */
1024 memcpy (fullBlock, buf + completeLength, partialLength);
1025 memset (fullBlock + partialLength, 0, TAR_BLOCK_SIZE - partialLength);
Eric Andersencc8ed391999-10-05 16:24:54 +00001026
Eric Andersen3cf52d11999-10-12 22:26:06 +00001027 /*
1028 * Write the last complete block.
1029 */
1030 if (!fullWrite (tarFd, fullBlock, TAR_BLOCK_SIZE)) {
1031 perror (tarName);
Eric Andersencc8ed391999-10-05 16:24:54 +00001032
Eric Andersen3cf52d11999-10-12 22:26:06 +00001033 errorFlag = TRUE;
1034 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001035}
1036
1037
1038/*
Eric Andersencc8ed391999-10-05 16:24:54 +00001039 * Read an octal value in a field of the specified width, with optional
1040 * spaces on both sides of the number and with an optional null character
1041 * at the end. Returns -1 on an illegal format.
1042 */
Eric Andersen3cf52d11999-10-12 22:26:06 +00001043static long getOctal (const char *cp, int len)
Eric Andersencc8ed391999-10-05 16:24:54 +00001044{
Eric Andersen3cf52d11999-10-12 22:26:06 +00001045 long val;
Eric Andersencc8ed391999-10-05 16:24:54 +00001046
Eric Andersen3cf52d11999-10-12 22:26:06 +00001047 while ((len > 0) && (*cp == ' ')) {
1048 cp++;
1049 len--;
1050 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001051
Eric Andersen3cf52d11999-10-12 22:26:06 +00001052 if ((len == 0) || !isOctal (*cp))
1053 return -1;
Eric Andersencc8ed391999-10-05 16:24:54 +00001054
Eric Andersen3cf52d11999-10-12 22:26:06 +00001055 val = 0;
Eric Andersencc8ed391999-10-05 16:24:54 +00001056
Eric Andersen3cf52d11999-10-12 22:26:06 +00001057 while ((len > 0) && isOctal (*cp)) {
1058 val = val * 8 + *cp++ - '0';
1059 len--;
1060 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001061
Eric Andersen3cf52d11999-10-12 22:26:06 +00001062 while ((len > 0) && (*cp == ' ')) {
1063 cp++;
1064 len--;
1065 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001066
Eric Andersen3cf52d11999-10-12 22:26:06 +00001067 if ((len > 0) && *cp)
1068 return -1;
Eric Andersencc8ed391999-10-05 16:24:54 +00001069
Eric Andersen3cf52d11999-10-12 22:26:06 +00001070 return val;
Eric Andersencc8ed391999-10-05 16:24:54 +00001071}
1072
1073
1074/*
1075 * Put an octal string into the specified buffer.
1076 * The number is zero and space padded and possibly null padded.
1077 * Returns TRUE if successful.
1078 */
Eric Andersen3cf52d11999-10-12 22:26:06 +00001079static int putOctal (char *cp, int len, long value)
Eric Andersencc8ed391999-10-05 16:24:54 +00001080{
Eric Andersen3cf52d11999-10-12 22:26:06 +00001081 int tempLength;
1082 char *tempString;
1083 char tempBuffer[32];
Eric Andersencc8ed391999-10-05 16:24:54 +00001084
Eric Andersen3cf52d11999-10-12 22:26:06 +00001085 /*
1086 * Create a string of the specified length with an initial space,
1087 * leading zeroes and the octal number, and a trailing null.
1088 */
1089 tempString = tempBuffer;
Eric Andersencc8ed391999-10-05 16:24:54 +00001090
Eric Andersen3cf52d11999-10-12 22:26:06 +00001091 sprintf (tempString, " %0*lo", len - 2, value);
Eric Andersencc8ed391999-10-05 16:24:54 +00001092
Eric Andersen3cf52d11999-10-12 22:26:06 +00001093 tempLength = strlen (tempString) + 1;
Eric Andersencc8ed391999-10-05 16:24:54 +00001094
Eric Andersen3cf52d11999-10-12 22:26:06 +00001095 /*
1096 * If the string is too large, suppress the leading space.
1097 */
1098 if (tempLength > len) {
1099 tempLength--;
1100 tempString++;
1101 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001102
Eric Andersen3cf52d11999-10-12 22:26:06 +00001103 /*
1104 * If the string is still too large, suppress the trailing null.
1105 */
1106 if (tempLength > len)
1107 tempLength--;
Eric Andersencc8ed391999-10-05 16:24:54 +00001108
Eric Andersen3cf52d11999-10-12 22:26:06 +00001109 /*
1110 * If the string is still too large, fail.
1111 */
1112 if (tempLength > len)
1113 return FALSE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001114
Eric Andersen3cf52d11999-10-12 22:26:06 +00001115 /*
1116 * Copy the string to the field.
1117 */
1118 memcpy (cp, tempString, len);
Eric Andersencc8ed391999-10-05 16:24:54 +00001119
Eric Andersen3cf52d11999-10-12 22:26:06 +00001120 return TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001121}
1122
1123
1124/*
1125 * See if the specified file name belongs to one of the specified list
1126 * of path prefixes. An empty list implies that all files are wanted.
1127 * Returns TRUE if the file is selected.
1128 */
Eric Andersenf811e071999-10-09 00:25:00 +00001129static int
Eric Andersen3cf52d11999-10-12 22:26:06 +00001130wantFileName (const char *fileName, int fileCount, char **fileTable)
Eric Andersencc8ed391999-10-05 16:24:54 +00001131{
Eric Andersen3cf52d11999-10-12 22:26:06 +00001132 const char *pathName;
1133 int fileLength;
1134 int pathLength;
Eric Andersencc8ed391999-10-05 16:24:54 +00001135
Eric Andersen3cf52d11999-10-12 22:26:06 +00001136 /*
1137 * If there are no files in the list, then the file is wanted.
1138 */
1139 if (fileCount == 0)
1140 return TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001141
Eric Andersen3cf52d11999-10-12 22:26:06 +00001142 fileLength = strlen (fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +00001143
Eric Andersen3cf52d11999-10-12 22:26:06 +00001144 /*
1145 * Check each of the test paths.
1146 */
1147 while (fileCount-- > 0) {
1148 pathName = *fileTable++;
Eric Andersencc8ed391999-10-05 16:24:54 +00001149
Eric Andersen3cf52d11999-10-12 22:26:06 +00001150 pathLength = strlen (pathName);
Eric Andersencc8ed391999-10-05 16:24:54 +00001151
Eric Andersen3cf52d11999-10-12 22:26:06 +00001152 if (fileLength < pathLength)
1153 continue;
Eric Andersencc8ed391999-10-05 16:24:54 +00001154
Eric Andersen3cf52d11999-10-12 22:26:06 +00001155 if (memcmp (fileName, pathName, pathLength) != 0)
1156 continue;
Eric Andersencc8ed391999-10-05 16:24:54 +00001157
Eric Andersen3cf52d11999-10-12 22:26:06 +00001158 if ((fileLength == pathLength) || (fileName[pathLength] == '/')) {
1159 return TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001160 }
Eric Andersen3cf52d11999-10-12 22:26:06 +00001161 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001162
Eric Andersen3cf52d11999-10-12 22:26:06 +00001163 return FALSE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001164}
1165
1166
1167
Eric Andersencc8ed391999-10-05 16:24:54 +00001168/* END CODE */