blob: 9ad41bea84f9ab3b59d5da9f237c7353c4a483a0 [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 Andersen50d63601999-11-09 01:47:36 +000038/* Note that tar.c expects TRUE and FALSE to be defined
39 * exactly the opposite of how they are used everywhere else.
40 * Some time this should be integrated a bit better, but this
41 * does the job for now.
42 */
43#undef FALSE
44#undef TRUE
45#define FALSE ((int) 0)
46#define TRUE ((int) 1)
47
Eric Andersene77ae3a1999-10-19 20:03:34 +000048
49static const char tar_usage[] =
Eric Andersenbe971d61999-11-03 16:52:50 +000050 "tar -[cxtvOf] [tarFileName] [FILE] ...\n"
51 "Create, extract, or list files from a tar file\n\n"
Eric Andersene77ae3a1999-10-19 20:03:34 +000052 "\tc=create, x=extract, t=list contents, v=verbose,\n"
53 "\tO=extract to stdout, f=tarfile or \"-\" for stdin\n";
54
55
56
Eric Andersencc8ed391999-10-05 16:24:54 +000057/*
58 * Tar file constants.
59 */
60#define TAR_BLOCK_SIZE 512
61#define TAR_NAME_SIZE 100
62
63
64/*
65 * The POSIX (and basic GNU) tar header format.
66 * This structure is always embedded in a TAR_BLOCK_SIZE sized block
67 * with zero padding. We only process this information minimally.
68 */
Eric Andersen3cf52d11999-10-12 22:26:06 +000069typedef struct {
70 char name[TAR_NAME_SIZE];
71 char mode[8];
72 char uid[8];
73 char gid[8];
74 char size[12];
75 char mtime[12];
76 char checkSum[8];
77 char typeFlag;
78 char linkName[TAR_NAME_SIZE];
79 char magic[6];
80 char version[2];
81 char uname[32];
82 char gname[32];
83 char devMajor[8];
84 char devMinor[8];
85 char prefix[155];
Eric Andersencc8ed391999-10-05 16:24:54 +000086} TarHeader;
87
88#define TAR_MAGIC "ustar"
89#define TAR_VERSION "00"
90
91#define TAR_TYPE_REGULAR '0'
92#define TAR_TYPE_HARD_LINK '1'
93#define TAR_TYPE_SOFT_LINK '2'
94
95
96/*
97 * Static data.
98 */
Eric Andersen3cf52d11999-10-12 22:26:06 +000099static int listFlag;
100static int extractFlag;
101static int createFlag;
102static int verboseFlag;
103static int tostdoutFlag;
Eric Andersencc8ed391999-10-05 16:24:54 +0000104
Eric Andersen3cf52d11999-10-12 22:26:06 +0000105static int inHeader;
106static int badHeader;
107static int errorFlag;
108static int skipFileFlag;
109static int warnedRoot;
110static int eofFlag;
111static long dataCc;
112static int outFd;
113static char outName[TAR_NAME_SIZE];
Eric Andersencc8ed391999-10-05 16:24:54 +0000114
115
116/*
117 * Static data associated with the tar file.
118 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000119static const char *tarName;
120static int tarFd;
121static dev_t tarDev;
122static ino_t tarInode;
Eric Andersencc8ed391999-10-05 16:24:54 +0000123
124
125/*
126 * Local procedures to restore files from a tar file.
127 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000128static void readTarFile (int fileCount, char **fileTable);
129static void readData (const char *cp, int count);
Eric Andersen3cf52d11999-10-12 22:26:06 +0000130static long getOctal (const char *cp, int len);
Eric Andersencc8ed391999-10-05 16:24:54 +0000131
Eric Andersen3cf52d11999-10-12 22:26:06 +0000132static void readHeader (const TarHeader * hp,
133 int fileCount, char **fileTable);
Eric Andersencc8ed391999-10-05 16:24:54 +0000134
135
136/*
137 * Local procedures to save files into a tar file.
138 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000139static void saveFile (const char *fileName, int seeLinks);
Eric Andersencc8ed391999-10-05 16:24:54 +0000140
Eric Andersen3cf52d11999-10-12 22:26:06 +0000141static void saveRegularFile (const char *fileName,
142 const struct stat *statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000143
Eric Andersen3cf52d11999-10-12 22:26:06 +0000144static void saveDirectory (const char *fileName,
145 const struct stat *statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000146
Eric Andersen3cf52d11999-10-12 22:26:06 +0000147static int wantFileName (const char *fileName,
148 int fileCount, char **fileTable);
Eric Andersencc8ed391999-10-05 16:24:54 +0000149
Eric Andersen3cf52d11999-10-12 22:26:06 +0000150static void writeHeader (const char *fileName, const struct stat *statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000151
Eric Andersen3cf52d11999-10-12 22:26:06 +0000152static void writeTarFile (int fileCount, char **fileTable);
153static void writeTarBlock (const char *buf, int len);
154static int putOctal (char *cp, int len, long value);
Eric Andersencc8ed391999-10-05 16:24:54 +0000155
156
Eric Andersen3cf52d11999-10-12 22:26:06 +0000157extern int tar_main (int argc, char **argv)
Eric Andersencc8ed391999-10-05 16:24:54 +0000158{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000159 const char *options;
Eric Andersencc8ed391999-10-05 16:24:54 +0000160
Eric Andersen3cf52d11999-10-12 22:26:06 +0000161 argc--;
162 argv++;
Eric Andersencc8ed391999-10-05 16:24:54 +0000163
Eric Andersenbe971d61999-11-03 16:52:50 +0000164 if (argc < 1)
165 usage( tar_usage);
Eric Andersencc8ed391999-10-05 16:24:54 +0000166
167
Eric Andersen3cf52d11999-10-12 22:26:06 +0000168 errorFlag = FALSE;
169 extractFlag = FALSE;
170 createFlag = FALSE;
171 listFlag = FALSE;
172 verboseFlag = FALSE;
173 tostdoutFlag = FALSE;
174 tarName = NULL;
175 tarDev = 0;
176 tarInode = 0;
177 tarFd = -1;
Eric Andersencc8ed391999-10-05 16:24:54 +0000178
Eric Andersen3cf52d11999-10-12 22:26:06 +0000179 /*
180 * Parse the options.
181 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000182 if (**argv == '-') {
Eric Andersen50d63601999-11-09 01:47:36 +0000183 options = (*argv++) + 1;
184 argc--;
Eric Andersen3cf52d11999-10-12 22:26:06 +0000185 for (; *options; options++) {
186 switch (*options) {
187 case 'f':
188 if (tarName != NULL) {
189 fprintf (stderr, "Only one 'f' option allowed\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000190
Eric Andersen3cf52d11999-10-12 22:26:06 +0000191 exit (FALSE);
Eric Andersencc8ed391999-10-05 16:24:54 +0000192 }
Eric Andersen3cf52d11999-10-12 22:26:06 +0000193
194 tarName = *argv++;
195 argc--;
196
197 break;
198
199 case 't':
200 listFlag = TRUE;
201 break;
202
203 case 'x':
204 extractFlag = TRUE;
205 break;
206
207 case 'c':
208 createFlag = TRUE;
209 break;
210
211 case 'v':
212 verboseFlag = TRUE;
213 break;
214
215 case 'O':
216 tostdoutFlag = TRUE;
217 break;
218
219 case '-':
220 break;
221
222 default:
223 fprintf (stderr, "Unknown tar flag '%c'\n", *options);
224
225 exit (FALSE);
226 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000227 }
Eric Andersen3cf52d11999-10-12 22:26:06 +0000228 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000229
Eric Andersen3cf52d11999-10-12 22:26:06 +0000230 /*
231 * Validate the options.
232 */
233 if (extractFlag + listFlag + createFlag != 1) {
234 fprintf (stderr,
235 "Exactly one of 'c', 'x' or 't' must be specified\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000236
Eric Andersen3cf52d11999-10-12 22:26:06 +0000237 exit (FALSE);
238 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000239
Eric Andersen3cf52d11999-10-12 22:26:06 +0000240 /*
241 * Do the correct type of action supplying the rest of the
242 * command line arguments as the list of files to process.
243 */
244 if (createFlag)
245 writeTarFile (argc, argv);
246 else
247 readTarFile (argc, argv);
248 if (errorFlag)
249 fprintf (stderr, "\n");
250 exit (errorFlag);
Eric Andersencc8ed391999-10-05 16:24:54 +0000251}
252
253
254/*
255 * Read a tar file and extract or list the specified files within it.
256 * If the list is empty than all files are extracted or listed.
257 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000258static void readTarFile (int fileCount, char **fileTable)
Eric Andersencc8ed391999-10-05 16:24:54 +0000259{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000260 const char *cp;
261 int cc;
262 int inCc;
263 int blockSize;
264 char buf[BUF_SIZE];
Eric Andersencc8ed391999-10-05 16:24:54 +0000265
Eric Andersen3cf52d11999-10-12 22:26:06 +0000266 skipFileFlag = FALSE;
267 badHeader = FALSE;
268 warnedRoot = FALSE;
269 eofFlag = FALSE;
270 inHeader = TRUE;
271 inCc = 0;
272 dataCc = 0;
273 outFd = -1;
274 blockSize = sizeof (buf);
275 cp = buf;
Eric Andersencc8ed391999-10-05 16:24:54 +0000276
Eric Andersen3cf52d11999-10-12 22:26:06 +0000277 /*
278 * Open the tar file for reading.
279 */
280 if ((tarName == NULL) || !strcmp (tarName, "-")) {
281 tarFd = STDIN;
282 } else
283 tarFd = open (tarName, O_RDONLY);
284
285 if (tarFd < 0) {
286 perror (tarName);
287 errorFlag = TRUE;
288 return;
289 }
290
291 /*
292 * Read blocks from the file until an end of file header block
293 * has been seen. (A real end of file from a read is an error.)
294 */
295 while (!eofFlag) {
296 /*
297 * Read the next block of data if necessary.
298 * This will be a large block if possible, which we will
299 * then process in the small tar blocks.
Eric Andersencc8ed391999-10-05 16:24:54 +0000300 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000301 if (inCc <= 0) {
302 cp = buf;
303 inCc = fullRead (tarFd, buf, blockSize);
Eric Andersencc8ed391999-10-05 16:24:54 +0000304
Eric Andersen3cf52d11999-10-12 22:26:06 +0000305 if (inCc < 0) {
306 perror (tarName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000307 errorFlag = TRUE;
Eric Andersen3cf52d11999-10-12 22:26:06 +0000308 goto done;
309 }
310
311 if (inCc == 0) {
312 fprintf (stderr,
313 "Unexpected end of file from \"%s\"", tarName);
314 errorFlag = TRUE;
315 goto done;
316 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000317 }
318
Eric Andersen3cf52d11999-10-12 22:26:06 +0000319 /*
320 * If we are expecting a header block then examine it.
Eric Andersencc8ed391999-10-05 16:24:54 +0000321 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000322 if (inHeader) {
323 readHeader ((const TarHeader *) cp, fileCount, fileTable);
Eric Andersencc8ed391999-10-05 16:24:54 +0000324
Eric Andersen3cf52d11999-10-12 22:26:06 +0000325 cp += TAR_BLOCK_SIZE;
326 inCc -= TAR_BLOCK_SIZE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000327
Eric Andersen3cf52d11999-10-12 22:26:06 +0000328 continue;
Eric Andersencc8ed391999-10-05 16:24:54 +0000329 }
330
Eric Andersen3cf52d11999-10-12 22:26:06 +0000331 /*
332 * We are currently handling the data for a file.
333 * Process the minimum of the amount of data we have available
334 * and the amount left to be processed for the file.
Eric Andersencc8ed391999-10-05 16:24:54 +0000335 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000336 cc = inCc;
Eric Andersencc8ed391999-10-05 16:24:54 +0000337
Eric Andersen3cf52d11999-10-12 22:26:06 +0000338 if (cc > dataCc)
339 cc = dataCc;
340
341 readData (cp, cc);
342
343 /*
344 * If the amount left isn't an exact multiple of the tar block
345 * size then round it up to the next block boundary since there
346 * is padding at the end of the file.
Eric Andersencc8ed391999-10-05 16:24:54 +0000347 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000348 if (cc % TAR_BLOCK_SIZE)
349 cc += TAR_BLOCK_SIZE - (cc % TAR_BLOCK_SIZE);
350
351 cp += cc;
352 inCc -= cc;
353 }
354
355 done:
356 /*
357 * Close the tar file if needed.
358 */
359 if ((tarFd >= 0) && (close (tarFd) < 0))
360 perror (tarName);
361
362 /*
363 * Close the output file if needed.
364 * This is only done here on a previous error and so no
365 * message is required on errors.
366 */
367 if (tostdoutFlag == FALSE) {
368 if (outFd >= 0)
369 (void) close (outFd);
370 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000371}
372
373
374/*
375 * Examine the header block that was just read.
376 * This can specify the information for another file, or it can mark
377 * the end of the tar file.
378 */
379static void
Eric Andersen3cf52d11999-10-12 22:26:06 +0000380readHeader (const TarHeader * hp, int fileCount, char **fileTable)
Eric Andersencc8ed391999-10-05 16:24:54 +0000381{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000382 int mode;
383 int uid;
384 int gid;
385 int checkSum;
386 long size;
387 time_t mtime;
388 const char *name;
389 int cc;
390 int hardLink;
391 int softLink;
Eric Andersencc8ed391999-10-05 16:24:54 +0000392
Eric Andersen3cf52d11999-10-12 22:26:06 +0000393 /*
394 * If the block is completely empty, then this is the end of the
395 * archive file. If the name is null, then just skip this header.
396 */
397 name = hp->name;
Eric Andersencc8ed391999-10-05 16:24:54 +0000398
Eric Andersen3cf52d11999-10-12 22:26:06 +0000399 if (*name == '\0') {
400 for (cc = TAR_BLOCK_SIZE; cc > 0; cc--) {
401 if (*name++)
Eric Andersencc8ed391999-10-05 16:24:54 +0000402 return;
403 }
404
Eric Andersen3cf52d11999-10-12 22:26:06 +0000405 eofFlag = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000406
Eric Andersen3cf52d11999-10-12 22:26:06 +0000407 return;
408 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000409
Eric Andersen3cf52d11999-10-12 22:26:06 +0000410 /*
411 * There is another file in the archive to examine.
412 * Extract the encoded information and check it.
413 */
414 mode = getOctal (hp->mode, sizeof (hp->mode));
415 uid = getOctal (hp->uid, sizeof (hp->uid));
416 gid = getOctal (hp->gid, sizeof (hp->gid));
417 size = getOctal (hp->size, sizeof (hp->size));
418 mtime = getOctal (hp->mtime, sizeof (hp->mtime));
419 checkSum = getOctal (hp->checkSum, sizeof (hp->checkSum));
Eric Andersencc8ed391999-10-05 16:24:54 +0000420
Eric Andersen3cf52d11999-10-12 22:26:06 +0000421 if ((mode < 0) || (uid < 0) || (gid < 0) || (size < 0)) {
422 if (!badHeader)
423 fprintf (stderr, "Bad tar header, skipping\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000424
Eric Andersen3cf52d11999-10-12 22:26:06 +0000425 badHeader = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000426
Eric Andersen3cf52d11999-10-12 22:26:06 +0000427 return;
428 }
429
430 badHeader = FALSE;
431 skipFileFlag = FALSE;
432
433 /*
434 * Check for the file modes.
435 */
436 hardLink = ((hp->typeFlag == TAR_TYPE_HARD_LINK) ||
Eric Andersencc8ed391999-10-05 16:24:54 +0000437 (hp->typeFlag == TAR_TYPE_HARD_LINK - '0'));
438
Eric Andersen3cf52d11999-10-12 22:26:06 +0000439 softLink = ((hp->typeFlag == TAR_TYPE_SOFT_LINK) ||
Eric Andersencc8ed391999-10-05 16:24:54 +0000440 (hp->typeFlag == TAR_TYPE_SOFT_LINK - '0'));
441
Eric Andersen3cf52d11999-10-12 22:26:06 +0000442 /*
443 * Check for a directory or a regular file.
444 */
445 if (name[strlen (name) - 1] == '/')
446 mode |= S_IFDIR;
447 else if ((mode & S_IFMT) == 0)
448 mode |= S_IFREG;
Eric Andersencc8ed391999-10-05 16:24:54 +0000449
Eric Andersen3cf52d11999-10-12 22:26:06 +0000450 /*
451 * Check for absolute paths in the file.
452 * If we find any, then warn the user and make them relative.
453 */
454 if (*name == '/') {
455 while (*name == '/')
456 name++;
Eric Andersencc8ed391999-10-05 16:24:54 +0000457
Eric Andersen3cf52d11999-10-12 22:26:06 +0000458 if (!warnedRoot) {
459 fprintf (stderr,
460 "Absolute path detected, removing leading slashes\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000461 }
462
Eric Andersen3cf52d11999-10-12 22:26:06 +0000463 warnedRoot = TRUE;
464 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000465
Eric Andersen3cf52d11999-10-12 22:26:06 +0000466 /*
467 * See if we want this file to be restored.
468 * If not, then set up to skip it.
469 */
470 if (!wantFileName (name, fileCount, fileTable)) {
471 if (!hardLink && !softLink && S_ISREG (mode)) {
472 inHeader = (size == 0);
473 dataCc = size;
Eric Andersencc8ed391999-10-05 16:24:54 +0000474 }
475
Eric Andersen3cf52d11999-10-12 22:26:06 +0000476 skipFileFlag = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000477
Eric Andersen3cf52d11999-10-12 22:26:06 +0000478 return;
479 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000480
Eric Andersen3cf52d11999-10-12 22:26:06 +0000481 /*
482 * This file is to be handled.
483 * If we aren't extracting then just list information about the file.
484 */
485 if (!extractFlag) {
486 if (verboseFlag) {
487 printf ("%s %3d/%-d %9ld %s %s", modeString (mode),
488 uid, gid, size, timeString (mtime), name);
489 } else
490 printf ("%s", name);
Eric Andersencc8ed391999-10-05 16:24:54 +0000491
492 if (hardLink)
Eric Andersen3cf52d11999-10-12 22:26:06 +0000493 printf (" (link to \"%s\")", hp->linkName);
494 else if (softLink)
495 printf (" (symlink to \"%s\")", hp->linkName);
496 else if (S_ISREG (mode)) {
497 inHeader = (size == 0);
498 dataCc = size;
Eric Andersencc8ed391999-10-05 16:24:54 +0000499 }
500
Eric Andersen3cf52d11999-10-12 22:26:06 +0000501 printf ("\n");
502
503 return;
504 }
505
506 /*
507 * We really want to extract the file.
508 */
509 if (verboseFlag)
510 printf ("x %s\n", name);
511
512 if (hardLink) {
513 if (link (hp->linkName, name) < 0)
514 perror (name);
515
516 return;
517 }
518
519 if (softLink) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000520#ifdef S_ISLNK
Eric Andersen3cf52d11999-10-12 22:26:06 +0000521 if (symlink (hp->linkName, name) < 0)
522 perror (name);
Eric Andersencc8ed391999-10-05 16:24:54 +0000523#else
Eric Andersen3cf52d11999-10-12 22:26:06 +0000524 fprintf (stderr, "Cannot create symbolic links\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000525#endif
Eric Andersen3cf52d11999-10-12 22:26:06 +0000526 return;
527 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000528
Eric Andersen3cf52d11999-10-12 22:26:06 +0000529 /*
530 * If the file is a directory, then just create the path.
531 */
532 if (S_ISDIR (mode)) {
533 createPath (name, mode);
Eric Andersencc8ed391999-10-05 16:24:54 +0000534
Eric Andersen3cf52d11999-10-12 22:26:06 +0000535 return;
536 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000537
Eric Andersen3cf52d11999-10-12 22:26:06 +0000538 /*
539 * There is a file to write.
540 * First create the path to it if necessary with a default permission.
541 */
542 createPath (name, 0777);
Eric Andersencc8ed391999-10-05 16:24:54 +0000543
Eric Andersen3cf52d11999-10-12 22:26:06 +0000544 inHeader = (size == 0);
545 dataCc = size;
Eric Andersencc8ed391999-10-05 16:24:54 +0000546
Eric Andersen3cf52d11999-10-12 22:26:06 +0000547 /*
548 * Start the output file.
549 */
550 if (tostdoutFlag == TRUE)
551 outFd = STDOUT;
552 else
553 outFd = open (name, O_WRONLY | O_CREAT | O_TRUNC, mode);
Eric Andersencc8ed391999-10-05 16:24:54 +0000554
Eric Andersen3cf52d11999-10-12 22:26:06 +0000555 if (outFd < 0) {
556 perror (name);
557 skipFileFlag = TRUE;
558 return;
559 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000560
Eric Andersen3cf52d11999-10-12 22:26:06 +0000561 /*
562 * If the file is empty, then that's all we need to do.
563 */
564 if (size == 0 && tostdoutFlag == FALSE) {
565 (void) close (outFd);
566 outFd = -1;
567 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000568}
569
570
571/*
572 * Handle a data block of some specified size that was read.
573 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000574static void readData (const char *cp, int count)
Eric Andersencc8ed391999-10-05 16:24:54 +0000575{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000576 /*
577 * Reduce the amount of data left in this file.
578 * If there is no more data left, then we need to read
579 * the header again.
580 */
581 dataCc -= count;
Eric Andersencc8ed391999-10-05 16:24:54 +0000582
Eric Andersen3cf52d11999-10-12 22:26:06 +0000583 if (dataCc <= 0)
584 inHeader = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000585
Eric Andersen3cf52d11999-10-12 22:26:06 +0000586 /*
587 * If we aren't extracting files or this file is being
588 * skipped then do nothing more.
589 */
590 if (!extractFlag || skipFileFlag)
591 return;
Eric Andersencc8ed391999-10-05 16:24:54 +0000592
Eric Andersen3cf52d11999-10-12 22:26:06 +0000593 /*
594 * Write the data to the output file.
595 */
596 if (fullWrite (outFd, cp, count) < 0) {
597 perror (outName);
598 if (tostdoutFlag == FALSE) {
599 (void) close (outFd);
600 outFd = -1;
Eric Andersencc8ed391999-10-05 16:24:54 +0000601 }
Eric Andersen3cf52d11999-10-12 22:26:06 +0000602 skipFileFlag = TRUE;
603 return;
604 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000605
Eric Andersen3cf52d11999-10-12 22:26:06 +0000606 /*
607 * If the write failed, close the file and disable further
608 * writes to this file.
609 */
610 if (dataCc <= 0 && tostdoutFlag == FALSE) {
611 if (close (outFd))
612 perror (outName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000613
Eric Andersen3cf52d11999-10-12 22:26:06 +0000614 outFd = -1;
615 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000616}
617
618
619/*
620 * Write a tar file containing the specified files.
621 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000622static void writeTarFile (int fileCount, char **fileTable)
Eric Andersencc8ed391999-10-05 16:24:54 +0000623{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000624 struct stat statbuf;
Eric Andersencc8ed391999-10-05 16:24:54 +0000625
Eric Andersen3cf52d11999-10-12 22:26:06 +0000626 /*
627 * Make sure there is at least one file specified.
628 */
629 if (fileCount <= 0) {
630 fprintf (stderr, "No files specified to be saved\n");
631 errorFlag = TRUE;
632 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000633
Eric Andersen3cf52d11999-10-12 22:26:06 +0000634 /*
635 * Create the tar file for writing.
636 */
637 if ((tarName == NULL) || !strcmp (tarName, "-")) {
638 tostdoutFlag = TRUE;
639 tarFd = STDOUT;
640 } else
641 tarFd = open (tarName, O_WRONLY | O_CREAT | O_TRUNC, 0666);
Eric Andersencc8ed391999-10-05 16:24:54 +0000642
Eric Andersen3cf52d11999-10-12 22:26:06 +0000643 if (tarFd < 0) {
644 perror (tarName);
645 errorFlag = TRUE;
646 return;
647 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000648
Eric Andersen3cf52d11999-10-12 22:26:06 +0000649 /*
650 * Get the device and inode of the tar file for checking later.
651 */
652 if (fstat (tarFd, &statbuf) < 0) {
653 perror (tarName);
654 errorFlag = TRUE;
655 goto done;
656 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000657
Eric Andersen3cf52d11999-10-12 22:26:06 +0000658 tarDev = statbuf.st_dev;
659 tarInode = statbuf.st_ino;
Eric Andersencc8ed391999-10-05 16:24:54 +0000660
Eric Andersen3cf52d11999-10-12 22:26:06 +0000661 /*
662 * Append each file name into the archive file.
663 * Follow symbolic links for these top level file names.
664 */
665 while (!errorFlag && (fileCount-- > 0)) {
666 saveFile (*fileTable++, FALSE);
667 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000668
Eric Andersen3cf52d11999-10-12 22:26:06 +0000669 /*
670 * Now write an empty block of zeroes to end the archive.
671 */
672 writeTarBlock ("", 1);
Eric Andersencc8ed391999-10-05 16:24:54 +0000673
674
Eric Andersen3cf52d11999-10-12 22:26:06 +0000675 done:
676 /*
677 * Close the tar file and check for errors if it was opened.
678 */
679 if ((tostdoutFlag == FALSE) && (tarFd >= 0) && (close (tarFd) < 0))
680 perror (tarName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000681}
682
683
684/*
685 * Save one file into the tar file.
686 * If the file is a directory, then this will recursively save all of
687 * the files and directories within the directory. The seeLinks
688 * flag indicates whether or not we want to see symbolic links as
689 * they really are, instead of blindly following them.
690 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000691static void saveFile (const char *fileName, int seeLinks)
Eric Andersencc8ed391999-10-05 16:24:54 +0000692{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000693 int status;
694 int mode;
695 struct stat statbuf;
Eric Andersencc8ed391999-10-05 16:24:54 +0000696
Eric Andersen3cf52d11999-10-12 22:26:06 +0000697 if (verboseFlag)
698 printf ("a %s\n", fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000699
Eric Andersen3cf52d11999-10-12 22:26:06 +0000700 /*
701 * Check that the file name will fit in the header.
702 */
703 if (strlen (fileName) >= TAR_NAME_SIZE) {
704 fprintf (stderr, "%s: File name is too long\n", fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000705
Eric Andersen3cf52d11999-10-12 22:26:06 +0000706 return;
707 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000708
Eric Andersen3cf52d11999-10-12 22:26:06 +0000709 /*
710 * Find out about the file.
711 */
Eric Andersencc8ed391999-10-05 16:24:54 +0000712#ifdef S_ISLNK
Eric Andersen3cf52d11999-10-12 22:26:06 +0000713 if (seeLinks)
714 status = lstat (fileName, &statbuf);
715 else
Eric Andersencc8ed391999-10-05 16:24:54 +0000716#endif
Eric Andersen3cf52d11999-10-12 22:26:06 +0000717 status = stat (fileName, &statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000718
Eric Andersen3cf52d11999-10-12 22:26:06 +0000719 if (status < 0) {
720 perror (fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000721
Eric Andersen3cf52d11999-10-12 22:26:06 +0000722 return;
723 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000724
Eric Andersen3cf52d11999-10-12 22:26:06 +0000725 /*
726 * Make sure we aren't trying to save our file into itself.
727 */
728 if ((statbuf.st_dev == tarDev) && (statbuf.st_ino == tarInode)) {
729 fprintf (stderr, "Skipping saving of archive file itself\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000730
Eric Andersen3cf52d11999-10-12 22:26:06 +0000731 return;
732 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000733
Eric Andersen3cf52d11999-10-12 22:26:06 +0000734 /*
735 * Check the type of file.
736 */
737 mode = statbuf.st_mode;
Eric Andersencc8ed391999-10-05 16:24:54 +0000738
Eric Andersen3cf52d11999-10-12 22:26:06 +0000739 if (S_ISDIR (mode)) {
740 saveDirectory (fileName, &statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000741
Eric Andersen3cf52d11999-10-12 22:26:06 +0000742 return;
743 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000744
Eric Andersen3cf52d11999-10-12 22:26:06 +0000745 if (S_ISREG (mode)) {
746 saveRegularFile (fileName, &statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000747
Eric Andersen3cf52d11999-10-12 22:26:06 +0000748 return;
749 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000750
Eric Andersen3cf52d11999-10-12 22:26:06 +0000751 /*
752 * The file is a strange type of file, ignore it.
753 */
754 fprintf (stderr, "%s: not a directory or regular file\n", fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000755}
756
757
758/*
759 * Save a regular file to the tar file.
760 */
761static void
Eric Andersen3cf52d11999-10-12 22:26:06 +0000762saveRegularFile (const char *fileName, const struct stat *statbuf)
Eric Andersencc8ed391999-10-05 16:24:54 +0000763{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000764 int sawEof;
765 int fileFd;
766 int cc;
767 int dataCount;
768 long fullDataCount;
769 char data[TAR_BLOCK_SIZE * 16];
Eric Andersencc8ed391999-10-05 16:24:54 +0000770
Eric Andersen3cf52d11999-10-12 22:26:06 +0000771 /*
772 * Open the file for reading.
773 */
774 fileFd = open (fileName, O_RDONLY);
775
776 if (fileFd < 0) {
777 perror (fileName);
778
779 return;
780 }
781
782 /*
783 * Write out the header for the file.
784 */
785 writeHeader (fileName, statbuf);
786
787 /*
788 * Write the data blocks of the file.
789 * We must be careful to write the amount of data that the stat
790 * buffer indicated, even if the file has changed size. Otherwise
791 * the tar file will be incorrect.
792 */
793 fullDataCount = statbuf->st_size;
794 sawEof = FALSE;
795
796 while (fullDataCount > 0) {
797 /*
798 * Get the amount to write this iteration which is
799 * the minumum of the amount left to write and the
800 * buffer size.
Eric Andersencc8ed391999-10-05 16:24:54 +0000801 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000802 dataCount = sizeof (data);
Eric Andersencc8ed391999-10-05 16:24:54 +0000803
Eric Andersen3cf52d11999-10-12 22:26:06 +0000804 if (dataCount > fullDataCount)
805 dataCount = (int) fullDataCount;
806
807 /*
808 * Read the data from the file if we haven't seen the
809 * end of file yet.
810 */
811 cc = 0;
812
813 if (!sawEof) {
814 cc = fullRead (fileFd, data, dataCount);
815
816 if (cc < 0) {
817 perror (fileName);
818
819 (void) close (fileFd);
820 errorFlag = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000821
822 return;
Eric Andersen3cf52d11999-10-12 22:26:06 +0000823 }
824
825 /*
826 * If the file ended too soon, complain and set
827 * a flag so we will zero fill the rest of it.
828 */
829 if (cc < dataCount) {
830 fprintf (stderr,
831 "%s: Short read - zero filling", fileName);
832
833 sawEof = TRUE;
834 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000835 }
836
Eric Andersen3cf52d11999-10-12 22:26:06 +0000837 /*
838 * Zero fill the rest of the data if necessary.
Eric Andersencc8ed391999-10-05 16:24:54 +0000839 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000840 if (cc < dataCount)
841 memset (data + cc, 0, dataCount - cc);
Eric Andersencc8ed391999-10-05 16:24:54 +0000842
Eric Andersen3cf52d11999-10-12 22:26:06 +0000843 /*
844 * Write the buffer to the TAR file.
Eric Andersencc8ed391999-10-05 16:24:54 +0000845 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000846 writeTarBlock (data, dataCount);
Eric Andersencc8ed391999-10-05 16:24:54 +0000847
Eric Andersen3cf52d11999-10-12 22:26:06 +0000848 fullDataCount -= dataCount;
849 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000850
Eric Andersen3cf52d11999-10-12 22:26:06 +0000851 /*
852 * Close the file.
853 */
854 if ((tostdoutFlag == FALSE) && close (fileFd) < 0)
855 fprintf (stderr, "%s: close: %s\n", fileName, strerror (errno));
Eric Andersencc8ed391999-10-05 16:24:54 +0000856}
857
858
859/*
860 * Save a directory and all of its files to the tar file.
861 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000862static void saveDirectory (const char *dirName, const struct stat *statbuf)
Eric Andersencc8ed391999-10-05 16:24:54 +0000863{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000864 DIR *dir;
865 struct dirent *entry;
866 int needSlash;
Eric Andersen1b61f411999-10-13 18:56:42 +0000867 char fullName[NAME_MAX];
Eric Andersencc8ed391999-10-05 16:24:54 +0000868
Eric Andersen3cf52d11999-10-12 22:26:06 +0000869 /*
870 * Construct the directory name as used in the tar file by appending
871 * a slash character to it.
872 */
873 strcpy (fullName, dirName);
874 strcat (fullName, "/");
Eric Andersencc8ed391999-10-05 16:24:54 +0000875
Eric Andersen3cf52d11999-10-12 22:26:06 +0000876 /*
877 * Write out the header for the directory entry.
878 */
879 writeHeader (fullName, statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000880
Eric Andersen3cf52d11999-10-12 22:26:06 +0000881 /*
882 * Open the directory.
883 */
884 dir = opendir (dirName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000885
Eric Andersen3cf52d11999-10-12 22:26:06 +0000886 if (dir == NULL) {
887 fprintf (stderr, "Cannot read directory \"%s\": %s\n",
888 dirName, strerror (errno));
Eric Andersencc8ed391999-10-05 16:24:54 +0000889
Eric Andersen3cf52d11999-10-12 22:26:06 +0000890 return;
891 }
892
893 /*
894 * See if a slash is needed.
895 */
896 needSlash = (*dirName && (dirName[strlen (dirName) - 1] != '/'));
897
898 /*
899 * Read all of the directory entries and check them,
900 * except for the current and parent directory entries.
901 */
902 while (!errorFlag && ((entry = readdir (dir)) != NULL)) {
903 if ((strcmp (entry->d_name, ".") == 0) ||
904 (strcmp (entry->d_name, "..") == 0)) {
905 continue;
Eric Andersencc8ed391999-10-05 16:24:54 +0000906 }
907
Eric Andersen3cf52d11999-10-12 22:26:06 +0000908 /*
909 * Build the full path name to the file.
Eric Andersencc8ed391999-10-05 16:24:54 +0000910 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000911 strcpy (fullName, dirName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000912
Eric Andersen3cf52d11999-10-12 22:26:06 +0000913 if (needSlash)
914 strcat (fullName, "/");
915
916 strcat (fullName, entry->d_name);
917
918 /*
919 * Write this file to the tar file, noticing whether or not
920 * the file is a symbolic link.
Eric Andersencc8ed391999-10-05 16:24:54 +0000921 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000922 saveFile (fullName, TRUE);
923 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000924
Eric Andersen3cf52d11999-10-12 22:26:06 +0000925 /*
926 * All done, close the directory.
927 */
928 closedir (dir);
Eric Andersencc8ed391999-10-05 16:24:54 +0000929}
930
931
932/*
933 * Write a tar header for the specified file name and status.
934 * It is assumed that the file name fits.
935 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000936static void writeHeader (const char *fileName, const struct stat *statbuf)
Eric Andersencc8ed391999-10-05 16:24:54 +0000937{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000938 long checkSum;
939 const unsigned char *cp;
940 int len;
941 TarHeader header;
Eric Andersencc8ed391999-10-05 16:24:54 +0000942
Eric Andersen3cf52d11999-10-12 22:26:06 +0000943 /*
944 * Zero the header block in preparation for filling it in.
945 */
946 memset ((char *) &header, 0, sizeof (header));
Eric Andersencc8ed391999-10-05 16:24:54 +0000947
Eric Andersen3cf52d11999-10-12 22:26:06 +0000948 /*
949 * Fill in the header.
950 */
951 strcpy (header.name, fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000952
Eric Andersen3cf52d11999-10-12 22:26:06 +0000953 strncpy (header.magic, TAR_MAGIC, sizeof (header.magic));
954 strncpy (header.version, TAR_VERSION, sizeof (header.version));
Eric Andersencc8ed391999-10-05 16:24:54 +0000955
Eric Andersen3cf52d11999-10-12 22:26:06 +0000956 putOctal (header.mode, sizeof (header.mode), statbuf->st_mode & 0777);
957 putOctal (header.uid, sizeof (header.uid), statbuf->st_uid);
958 putOctal (header.gid, sizeof (header.gid), statbuf->st_gid);
959 putOctal (header.size, sizeof (header.size), statbuf->st_size);
960 putOctal (header.mtime, sizeof (header.mtime), statbuf->st_mtime);
Eric Andersencc8ed391999-10-05 16:24:54 +0000961
Eric Andersen3cf52d11999-10-12 22:26:06 +0000962 header.typeFlag = TAR_TYPE_REGULAR;
Eric Andersencc8ed391999-10-05 16:24:54 +0000963
Eric Andersen3cf52d11999-10-12 22:26:06 +0000964 /*
965 * Calculate and store the checksum.
966 * This is the sum of all of the bytes of the header,
967 * with the checksum field itself treated as blanks.
968 */
969 memset (header.checkSum, ' ', sizeof (header.checkSum));
Eric Andersencc8ed391999-10-05 16:24:54 +0000970
Eric Andersen3cf52d11999-10-12 22:26:06 +0000971 cp = (const unsigned char *) &header;
972 len = sizeof (header);
973 checkSum = 0;
Eric Andersencc8ed391999-10-05 16:24:54 +0000974
Eric Andersen3cf52d11999-10-12 22:26:06 +0000975 while (len-- > 0)
976 checkSum += *cp++;
Eric Andersencc8ed391999-10-05 16:24:54 +0000977
Eric Andersen3cf52d11999-10-12 22:26:06 +0000978 putOctal (header.checkSum, sizeof (header.checkSum), checkSum);
Eric Andersencc8ed391999-10-05 16:24:54 +0000979
Eric Andersen3cf52d11999-10-12 22:26:06 +0000980 /*
981 * Write the tar header.
982 */
983 writeTarBlock ((const char *) &header, sizeof (header));
Eric Andersencc8ed391999-10-05 16:24:54 +0000984}
985
986
987/*
988 * Write data to one or more blocks of the tar file.
989 * The data is always padded out to a multiple of TAR_BLOCK_SIZE.
990 * The errorFlag static variable is set on an error.
991 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000992static void writeTarBlock (const char *buf, int len)
Eric Andersencc8ed391999-10-05 16:24:54 +0000993{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000994 int partialLength;
995 int completeLength;
996 char fullBlock[TAR_BLOCK_SIZE];
Eric Andersencc8ed391999-10-05 16:24:54 +0000997
Eric Andersen3cf52d11999-10-12 22:26:06 +0000998 /*
999 * If we had a write error before, then do nothing more.
1000 */
1001 if (errorFlag)
1002 return;
Eric Andersencc8ed391999-10-05 16:24:54 +00001003
Eric Andersen3cf52d11999-10-12 22:26:06 +00001004 /*
1005 * Get the amount of complete and partial blocks.
1006 */
1007 partialLength = len % TAR_BLOCK_SIZE;
1008 completeLength = len - partialLength;
Eric Andersencc8ed391999-10-05 16:24:54 +00001009
Eric Andersen3cf52d11999-10-12 22:26:06 +00001010 /*
1011 * Write all of the complete blocks.
1012 */
1013 if ((completeLength > 0) && !fullWrite (tarFd, buf, completeLength)) {
1014 perror (tarName);
Eric Andersencc8ed391999-10-05 16:24:54 +00001015
Eric Andersen3cf52d11999-10-12 22:26:06 +00001016 errorFlag = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001017
Eric Andersen3cf52d11999-10-12 22:26:06 +00001018 return;
1019 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001020
Eric Andersen3cf52d11999-10-12 22:26:06 +00001021 /*
1022 * If there are no partial blocks left, we are done.
1023 */
1024 if (partialLength == 0)
1025 return;
Eric Andersencc8ed391999-10-05 16:24:54 +00001026
Eric Andersen3cf52d11999-10-12 22:26:06 +00001027 /*
1028 * Copy the partial data into a complete block, and pad the rest
1029 * of it with zeroes.
1030 */
1031 memcpy (fullBlock, buf + completeLength, partialLength);
1032 memset (fullBlock + partialLength, 0, TAR_BLOCK_SIZE - partialLength);
Eric Andersencc8ed391999-10-05 16:24:54 +00001033
Eric Andersen3cf52d11999-10-12 22:26:06 +00001034 /*
1035 * Write the last complete block.
1036 */
1037 if (!fullWrite (tarFd, fullBlock, TAR_BLOCK_SIZE)) {
1038 perror (tarName);
Eric Andersencc8ed391999-10-05 16:24:54 +00001039
Eric Andersen3cf52d11999-10-12 22:26:06 +00001040 errorFlag = TRUE;
1041 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001042}
1043
1044
1045/*
Eric Andersencc8ed391999-10-05 16:24:54 +00001046 * Read an octal value in a field of the specified width, with optional
1047 * spaces on both sides of the number and with an optional null character
1048 * at the end. Returns -1 on an illegal format.
1049 */
Eric Andersen3cf52d11999-10-12 22:26:06 +00001050static long getOctal (const char *cp, int len)
Eric Andersencc8ed391999-10-05 16:24:54 +00001051{
Eric Andersen3cf52d11999-10-12 22:26:06 +00001052 long val;
Eric Andersencc8ed391999-10-05 16:24:54 +00001053
Eric Andersen3cf52d11999-10-12 22:26:06 +00001054 while ((len > 0) && (*cp == ' ')) {
1055 cp++;
1056 len--;
1057 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001058
Eric Andersen3cf52d11999-10-12 22:26:06 +00001059 if ((len == 0) || !isOctal (*cp))
1060 return -1;
Eric Andersencc8ed391999-10-05 16:24:54 +00001061
Eric Andersen3cf52d11999-10-12 22:26:06 +00001062 val = 0;
Eric Andersencc8ed391999-10-05 16:24:54 +00001063
Eric Andersen3cf52d11999-10-12 22:26:06 +00001064 while ((len > 0) && isOctal (*cp)) {
1065 val = val * 8 + *cp++ - '0';
1066 len--;
1067 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001068
Eric Andersen3cf52d11999-10-12 22:26:06 +00001069 while ((len > 0) && (*cp == ' ')) {
1070 cp++;
1071 len--;
1072 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001073
Eric Andersen3cf52d11999-10-12 22:26:06 +00001074 if ((len > 0) && *cp)
1075 return -1;
Eric Andersencc8ed391999-10-05 16:24:54 +00001076
Eric Andersen3cf52d11999-10-12 22:26:06 +00001077 return val;
Eric Andersencc8ed391999-10-05 16:24:54 +00001078}
1079
1080
1081/*
1082 * Put an octal string into the specified buffer.
1083 * The number is zero and space padded and possibly null padded.
1084 * Returns TRUE if successful.
1085 */
Eric Andersen3cf52d11999-10-12 22:26:06 +00001086static int putOctal (char *cp, int len, long value)
Eric Andersencc8ed391999-10-05 16:24:54 +00001087{
Eric Andersen3cf52d11999-10-12 22:26:06 +00001088 int tempLength;
1089 char *tempString;
1090 char tempBuffer[32];
Eric Andersencc8ed391999-10-05 16:24:54 +00001091
Eric Andersen3cf52d11999-10-12 22:26:06 +00001092 /*
1093 * Create a string of the specified length with an initial space,
1094 * leading zeroes and the octal number, and a trailing null.
1095 */
1096 tempString = tempBuffer;
Eric Andersencc8ed391999-10-05 16:24:54 +00001097
Eric Andersen3cf52d11999-10-12 22:26:06 +00001098 sprintf (tempString, " %0*lo", len - 2, value);
Eric Andersencc8ed391999-10-05 16:24:54 +00001099
Eric Andersen3cf52d11999-10-12 22:26:06 +00001100 tempLength = strlen (tempString) + 1;
Eric Andersencc8ed391999-10-05 16:24:54 +00001101
Eric Andersen3cf52d11999-10-12 22:26:06 +00001102 /*
1103 * If the string is too large, suppress the leading space.
1104 */
1105 if (tempLength > len) {
1106 tempLength--;
1107 tempString++;
1108 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001109
Eric Andersen3cf52d11999-10-12 22:26:06 +00001110 /*
1111 * If the string is still too large, suppress the trailing null.
1112 */
1113 if (tempLength > len)
1114 tempLength--;
Eric Andersencc8ed391999-10-05 16:24:54 +00001115
Eric Andersen3cf52d11999-10-12 22:26:06 +00001116 /*
1117 * If the string is still too large, fail.
1118 */
1119 if (tempLength > len)
1120 return FALSE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001121
Eric Andersen3cf52d11999-10-12 22:26:06 +00001122 /*
1123 * Copy the string to the field.
1124 */
1125 memcpy (cp, tempString, len);
Eric Andersencc8ed391999-10-05 16:24:54 +00001126
Eric Andersen3cf52d11999-10-12 22:26:06 +00001127 return TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001128}
1129
1130
1131/*
1132 * See if the specified file name belongs to one of the specified list
1133 * of path prefixes. An empty list implies that all files are wanted.
1134 * Returns TRUE if the file is selected.
1135 */
Eric Andersenf811e071999-10-09 00:25:00 +00001136static int
Eric Andersen3cf52d11999-10-12 22:26:06 +00001137wantFileName (const char *fileName, int fileCount, char **fileTable)
Eric Andersencc8ed391999-10-05 16:24:54 +00001138{
Eric Andersen3cf52d11999-10-12 22:26:06 +00001139 const char *pathName;
1140 int fileLength;
1141 int pathLength;
Eric Andersencc8ed391999-10-05 16:24:54 +00001142
Eric Andersen3cf52d11999-10-12 22:26:06 +00001143 /*
1144 * If there are no files in the list, then the file is wanted.
1145 */
1146 if (fileCount == 0)
1147 return TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001148
Eric Andersen3cf52d11999-10-12 22:26:06 +00001149 fileLength = strlen (fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +00001150
Eric Andersen3cf52d11999-10-12 22:26:06 +00001151 /*
1152 * Check each of the test paths.
1153 */
1154 while (fileCount-- > 0) {
1155 pathName = *fileTable++;
Eric Andersencc8ed391999-10-05 16:24:54 +00001156
Eric Andersen3cf52d11999-10-12 22:26:06 +00001157 pathLength = strlen (pathName);
Eric Andersencc8ed391999-10-05 16:24:54 +00001158
Eric Andersen3cf52d11999-10-12 22:26:06 +00001159 if (fileLength < pathLength)
1160 continue;
Eric Andersencc8ed391999-10-05 16:24:54 +00001161
Eric Andersen3cf52d11999-10-12 22:26:06 +00001162 if (memcmp (fileName, pathName, pathLength) != 0)
1163 continue;
Eric Andersencc8ed391999-10-05 16:24:54 +00001164
Eric Andersen3cf52d11999-10-12 22:26:06 +00001165 if ((fileLength == pathLength) || (fileName[pathLength] == '/')) {
1166 return TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001167 }
Eric Andersen3cf52d11999-10-12 22:26:06 +00001168 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001169
Eric Andersen3cf52d11999-10-12 22:26:06 +00001170 return FALSE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001171}
1172
1173
1174
Eric Andersencc8ed391999-10-05 16:24:54 +00001175/* END CODE */