blob: ff60f06894cd9a69fc564a833c7a762553443702 [file] [log] [blame]
Eric Andersencc8ed391999-10-05 16:24:54 +00001/*
2 * Copyright (c) 1999 by David I. Bell
3 * Permission is granted to use, distribute, or modify this source,
4 * provided that this copyright notice remains intact.
5 *
6 * The "tar" command, taken from sash.
7 * This allows creation, extraction, and listing of tar files.
8 *
9 * Permission to distribute this code under the GPL has been granted.
Eric Andersen3cf52d11999-10-12 22:26:06 +000010 * Modified for busybox by Erik Andersen <andersee@debian.org>
Eric Andersencc8ed391999-10-05 16:24:54 +000011 */
12
13
14#include "internal.h"
15
16#ifdef BB_TAR
17
Eric Andersen3cf52d11999-10-12 22:26:06 +000018const char tar_usage[] =
19 "Create, extract, or list files from a TAR file\n\n"
20 "usage: tar -[cxtvOf] [tarFileName] [FILE] ...\n"
21 "\tc=create, x=extract, t=list contents, v=verbose,\n"
22 "\tO=extract to stdout, f=tarfile or \"-\" for stdin\n";
Eric Andersencc8ed391999-10-05 16:24:54 +000023
24
25
26#include <stdio.h>
27#include <dirent.h>
28#include <errno.h>
29#include <fcntl.h>
30#include <signal.h>
31#include <time.h>
32
33/*
34 * Tar file constants.
35 */
36#define TAR_BLOCK_SIZE 512
37#define TAR_NAME_SIZE 100
38
39
40/*
41 * The POSIX (and basic GNU) tar header format.
42 * This structure is always embedded in a TAR_BLOCK_SIZE sized block
43 * with zero padding. We only process this information minimally.
44 */
Eric Andersen3cf52d11999-10-12 22:26:06 +000045typedef struct {
46 char name[TAR_NAME_SIZE];
47 char mode[8];
48 char uid[8];
49 char gid[8];
50 char size[12];
51 char mtime[12];
52 char checkSum[8];
53 char typeFlag;
54 char linkName[TAR_NAME_SIZE];
55 char magic[6];
56 char version[2];
57 char uname[32];
58 char gname[32];
59 char devMajor[8];
60 char devMinor[8];
61 char prefix[155];
Eric Andersencc8ed391999-10-05 16:24:54 +000062} TarHeader;
63
64#define TAR_MAGIC "ustar"
65#define TAR_VERSION "00"
66
67#define TAR_TYPE_REGULAR '0'
68#define TAR_TYPE_HARD_LINK '1'
69#define TAR_TYPE_SOFT_LINK '2'
70
71
72/*
73 * Static data.
74 */
Eric Andersen3cf52d11999-10-12 22:26:06 +000075static int listFlag;
76static int extractFlag;
77static int createFlag;
78static int verboseFlag;
79static int tostdoutFlag;
Eric Andersencc8ed391999-10-05 16:24:54 +000080
Eric Andersen3cf52d11999-10-12 22:26:06 +000081static int inHeader;
82static int badHeader;
83static int errorFlag;
84static int skipFileFlag;
85static int warnedRoot;
86static int eofFlag;
87static long dataCc;
88static int outFd;
89static char outName[TAR_NAME_SIZE];
Eric Andersencc8ed391999-10-05 16:24:54 +000090
91
92/*
93 * Static data associated with the tar file.
94 */
Eric Andersen3cf52d11999-10-12 22:26:06 +000095static const char *tarName;
96static int tarFd;
97static dev_t tarDev;
98static ino_t tarInode;
Eric Andersencc8ed391999-10-05 16:24:54 +000099
100
101/*
102 * Local procedures to restore files from a tar file.
103 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000104static void readTarFile (int fileCount, char **fileTable);
105static void readData (const char *cp, int count);
106static void createPath (const char *name, int mode);
107static long getOctal (const char *cp, int len);
Eric Andersencc8ed391999-10-05 16:24:54 +0000108
Eric Andersen3cf52d11999-10-12 22:26:06 +0000109static void readHeader (const TarHeader * hp,
110 int fileCount, char **fileTable);
Eric Andersencc8ed391999-10-05 16:24:54 +0000111
112
113/*
114 * Local procedures to save files into a tar file.
115 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000116static void saveFile (const char *fileName, int seeLinks);
Eric Andersencc8ed391999-10-05 16:24:54 +0000117
Eric Andersen3cf52d11999-10-12 22:26:06 +0000118static void saveRegularFile (const char *fileName,
119 const struct stat *statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000120
Eric Andersen3cf52d11999-10-12 22:26:06 +0000121static void saveDirectory (const char *fileName,
122 const struct stat *statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000123
Eric Andersen3cf52d11999-10-12 22:26:06 +0000124static int wantFileName (const char *fileName,
125 int fileCount, char **fileTable);
Eric Andersencc8ed391999-10-05 16:24:54 +0000126
Eric Andersen3cf52d11999-10-12 22:26:06 +0000127static void writeHeader (const char *fileName, const struct stat *statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000128
Eric Andersen3cf52d11999-10-12 22:26:06 +0000129static void writeTarFile (int fileCount, char **fileTable);
130static void writeTarBlock (const char *buf, int len);
131static int putOctal (char *cp, int len, long value);
Eric Andersencc8ed391999-10-05 16:24:54 +0000132
133
Eric Andersen3cf52d11999-10-12 22:26:06 +0000134extern int tar_main (int argc, char **argv)
Eric Andersencc8ed391999-10-05 16:24:54 +0000135{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000136 const char *options;
Eric Andersencc8ed391999-10-05 16:24:54 +0000137
Eric Andersen3cf52d11999-10-12 22:26:06 +0000138 argc--;
139 argv++;
Eric Andersencc8ed391999-10-05 16:24:54 +0000140
Eric Andersen3cf52d11999-10-12 22:26:06 +0000141 if (argc < 1) {
142 fprintf (stderr, "%s", tar_usage);
143 exit (FALSE);
144 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000145
146
Eric Andersen3cf52d11999-10-12 22:26:06 +0000147 errorFlag = FALSE;
148 extractFlag = FALSE;
149 createFlag = FALSE;
150 listFlag = FALSE;
151 verboseFlag = FALSE;
152 tostdoutFlag = FALSE;
153 tarName = NULL;
154 tarDev = 0;
155 tarInode = 0;
156 tarFd = -1;
Eric Andersencc8ed391999-10-05 16:24:54 +0000157
Eric Andersen3cf52d11999-10-12 22:26:06 +0000158 /*
159 * Parse the options.
160 */
161 options = *argv++;
162 argc--;
Eric Andersencc8ed391999-10-05 16:24:54 +0000163
Eric Andersen3cf52d11999-10-12 22:26:06 +0000164 if (**argv == '-') {
165 for (; *options; options++) {
166 switch (*options) {
167 case 'f':
168 if (tarName != NULL) {
169 fprintf (stderr, "Only one 'f' option allowed\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000170
Eric Andersen3cf52d11999-10-12 22:26:06 +0000171 exit (FALSE);
Eric Andersencc8ed391999-10-05 16:24:54 +0000172 }
Eric Andersen3cf52d11999-10-12 22:26:06 +0000173
174 tarName = *argv++;
175 argc--;
176
177 break;
178
179 case 't':
180 listFlag = TRUE;
181 break;
182
183 case 'x':
184 extractFlag = TRUE;
185 break;
186
187 case 'c':
188 createFlag = TRUE;
189 break;
190
191 case 'v':
192 verboseFlag = TRUE;
193 break;
194
195 case 'O':
196 tostdoutFlag = TRUE;
197 break;
198
199 case '-':
200 break;
201
202 default:
203 fprintf (stderr, "Unknown tar flag '%c'\n", *options);
204
205 exit (FALSE);
206 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000207 }
Eric Andersen3cf52d11999-10-12 22:26:06 +0000208 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000209
Eric Andersen3cf52d11999-10-12 22:26:06 +0000210 /*
211 * Validate the options.
212 */
213 if (extractFlag + listFlag + createFlag != 1) {
214 fprintf (stderr,
215 "Exactly one of 'c', 'x' or 't' must be specified\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000216
Eric Andersen3cf52d11999-10-12 22:26:06 +0000217 exit (FALSE);
218 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000219
Eric Andersen3cf52d11999-10-12 22:26:06 +0000220 /*
221 * Do the correct type of action supplying the rest of the
222 * command line arguments as the list of files to process.
223 */
224 if (createFlag)
225 writeTarFile (argc, argv);
226 else
227 readTarFile (argc, argv);
228 if (errorFlag)
229 fprintf (stderr, "\n");
230 exit (errorFlag);
Eric Andersencc8ed391999-10-05 16:24:54 +0000231}
232
233
234/*
235 * Read a tar file and extract or list the specified files within it.
236 * If the list is empty than all files are extracted or listed.
237 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000238static void readTarFile (int fileCount, char **fileTable)
Eric Andersencc8ed391999-10-05 16:24:54 +0000239{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000240 const char *cp;
241 int cc;
242 int inCc;
243 int blockSize;
244 char buf[BUF_SIZE];
Eric Andersencc8ed391999-10-05 16:24:54 +0000245
Eric Andersen3cf52d11999-10-12 22:26:06 +0000246 skipFileFlag = FALSE;
247 badHeader = FALSE;
248 warnedRoot = FALSE;
249 eofFlag = FALSE;
250 inHeader = TRUE;
251 inCc = 0;
252 dataCc = 0;
253 outFd = -1;
254 blockSize = sizeof (buf);
255 cp = buf;
Eric Andersencc8ed391999-10-05 16:24:54 +0000256
Eric Andersen3cf52d11999-10-12 22:26:06 +0000257 /*
258 * Open the tar file for reading.
259 */
260 if ((tarName == NULL) || !strcmp (tarName, "-")) {
261 tarFd = STDIN;
262 } else
263 tarFd = open (tarName, O_RDONLY);
264
265 if (tarFd < 0) {
266 perror (tarName);
267 errorFlag = TRUE;
268 return;
269 }
270
271 /*
272 * Read blocks from the file until an end of file header block
273 * has been seen. (A real end of file from a read is an error.)
274 */
275 while (!eofFlag) {
276 /*
277 * Read the next block of data if necessary.
278 * This will be a large block if possible, which we will
279 * then process in the small tar blocks.
Eric Andersencc8ed391999-10-05 16:24:54 +0000280 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000281 if (inCc <= 0) {
282 cp = buf;
283 inCc = fullRead (tarFd, buf, blockSize);
Eric Andersencc8ed391999-10-05 16:24:54 +0000284
Eric Andersen3cf52d11999-10-12 22:26:06 +0000285 if (inCc < 0) {
286 perror (tarName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000287 errorFlag = TRUE;
Eric Andersen3cf52d11999-10-12 22:26:06 +0000288 goto done;
289 }
290
291 if (inCc == 0) {
292 fprintf (stderr,
293 "Unexpected end of file from \"%s\"", tarName);
294 errorFlag = TRUE;
295 goto done;
296 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000297 }
298
Eric Andersen3cf52d11999-10-12 22:26:06 +0000299 /*
300 * If we are expecting a header block then examine it.
Eric Andersencc8ed391999-10-05 16:24:54 +0000301 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000302 if (inHeader) {
303 readHeader ((const TarHeader *) cp, fileCount, fileTable);
Eric Andersencc8ed391999-10-05 16:24:54 +0000304
Eric Andersen3cf52d11999-10-12 22:26:06 +0000305 cp += TAR_BLOCK_SIZE;
306 inCc -= TAR_BLOCK_SIZE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000307
Eric Andersen3cf52d11999-10-12 22:26:06 +0000308 continue;
Eric Andersencc8ed391999-10-05 16:24:54 +0000309 }
310
Eric Andersen3cf52d11999-10-12 22:26:06 +0000311 /*
312 * We are currently handling the data for a file.
313 * Process the minimum of the amount of data we have available
314 * and the amount left to be processed for the file.
Eric Andersencc8ed391999-10-05 16:24:54 +0000315 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000316 cc = inCc;
Eric Andersencc8ed391999-10-05 16:24:54 +0000317
Eric Andersen3cf52d11999-10-12 22:26:06 +0000318 if (cc > dataCc)
319 cc = dataCc;
320
321 readData (cp, cc);
322
323 /*
324 * If the amount left isn't an exact multiple of the tar block
325 * size then round it up to the next block boundary since there
326 * is padding at the end of the file.
Eric Andersencc8ed391999-10-05 16:24:54 +0000327 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000328 if (cc % TAR_BLOCK_SIZE)
329 cc += TAR_BLOCK_SIZE - (cc % TAR_BLOCK_SIZE);
330
331 cp += cc;
332 inCc -= cc;
333 }
334
335 done:
336 /*
337 * Close the tar file if needed.
338 */
339 if ((tarFd >= 0) && (close (tarFd) < 0))
340 perror (tarName);
341
342 /*
343 * Close the output file if needed.
344 * This is only done here on a previous error and so no
345 * message is required on errors.
346 */
347 if (tostdoutFlag == FALSE) {
348 if (outFd >= 0)
349 (void) close (outFd);
350 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000351}
352
353
354/*
355 * Examine the header block that was just read.
356 * This can specify the information for another file, or it can mark
357 * the end of the tar file.
358 */
359static void
Eric Andersen3cf52d11999-10-12 22:26:06 +0000360readHeader (const TarHeader * hp, int fileCount, char **fileTable)
Eric Andersencc8ed391999-10-05 16:24:54 +0000361{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000362 int mode;
363 int uid;
364 int gid;
365 int checkSum;
366 long size;
367 time_t mtime;
368 const char *name;
369 int cc;
370 int hardLink;
371 int softLink;
Eric Andersencc8ed391999-10-05 16:24:54 +0000372
Eric Andersen3cf52d11999-10-12 22:26:06 +0000373 /*
374 * If the block is completely empty, then this is the end of the
375 * archive file. If the name is null, then just skip this header.
376 */
377 name = hp->name;
Eric Andersencc8ed391999-10-05 16:24:54 +0000378
Eric Andersen3cf52d11999-10-12 22:26:06 +0000379 if (*name == '\0') {
380 for (cc = TAR_BLOCK_SIZE; cc > 0; cc--) {
381 if (*name++)
Eric Andersencc8ed391999-10-05 16:24:54 +0000382 return;
383 }
384
Eric Andersen3cf52d11999-10-12 22:26:06 +0000385 eofFlag = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000386
Eric Andersen3cf52d11999-10-12 22:26:06 +0000387 return;
388 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000389
Eric Andersen3cf52d11999-10-12 22:26:06 +0000390 /*
391 * There is another file in the archive to examine.
392 * Extract the encoded information and check it.
393 */
394 mode = getOctal (hp->mode, sizeof (hp->mode));
395 uid = getOctal (hp->uid, sizeof (hp->uid));
396 gid = getOctal (hp->gid, sizeof (hp->gid));
397 size = getOctal (hp->size, sizeof (hp->size));
398 mtime = getOctal (hp->mtime, sizeof (hp->mtime));
399 checkSum = getOctal (hp->checkSum, sizeof (hp->checkSum));
Eric Andersencc8ed391999-10-05 16:24:54 +0000400
Eric Andersen3cf52d11999-10-12 22:26:06 +0000401 if ((mode < 0) || (uid < 0) || (gid < 0) || (size < 0)) {
402 if (!badHeader)
403 fprintf (stderr, "Bad tar header, skipping\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000404
Eric Andersen3cf52d11999-10-12 22:26:06 +0000405 badHeader = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000406
Eric Andersen3cf52d11999-10-12 22:26:06 +0000407 return;
408 }
409
410 badHeader = FALSE;
411 skipFileFlag = FALSE;
412
413 /*
414 * Check for the file modes.
415 */
416 hardLink = ((hp->typeFlag == TAR_TYPE_HARD_LINK) ||
Eric Andersencc8ed391999-10-05 16:24:54 +0000417 (hp->typeFlag == TAR_TYPE_HARD_LINK - '0'));
418
Eric Andersen3cf52d11999-10-12 22:26:06 +0000419 softLink = ((hp->typeFlag == TAR_TYPE_SOFT_LINK) ||
Eric Andersencc8ed391999-10-05 16:24:54 +0000420 (hp->typeFlag == TAR_TYPE_SOFT_LINK - '0'));
421
Eric Andersen3cf52d11999-10-12 22:26:06 +0000422 /*
423 * Check for a directory or a regular file.
424 */
425 if (name[strlen (name) - 1] == '/')
426 mode |= S_IFDIR;
427 else if ((mode & S_IFMT) == 0)
428 mode |= S_IFREG;
Eric Andersencc8ed391999-10-05 16:24:54 +0000429
Eric Andersen3cf52d11999-10-12 22:26:06 +0000430 /*
431 * Check for absolute paths in the file.
432 * If we find any, then warn the user and make them relative.
433 */
434 if (*name == '/') {
435 while (*name == '/')
436 name++;
Eric Andersencc8ed391999-10-05 16:24:54 +0000437
Eric Andersen3cf52d11999-10-12 22:26:06 +0000438 if (!warnedRoot) {
439 fprintf (stderr,
440 "Absolute path detected, removing leading slashes\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000441 }
442
Eric Andersen3cf52d11999-10-12 22:26:06 +0000443 warnedRoot = TRUE;
444 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000445
Eric Andersen3cf52d11999-10-12 22:26:06 +0000446 /*
447 * See if we want this file to be restored.
448 * If not, then set up to skip it.
449 */
450 if (!wantFileName (name, fileCount, fileTable)) {
451 if (!hardLink && !softLink && S_ISREG (mode)) {
452 inHeader = (size == 0);
453 dataCc = size;
Eric Andersencc8ed391999-10-05 16:24:54 +0000454 }
455
Eric Andersen3cf52d11999-10-12 22:26:06 +0000456 skipFileFlag = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000457
Eric Andersen3cf52d11999-10-12 22:26:06 +0000458 return;
459 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000460
Eric Andersen3cf52d11999-10-12 22:26:06 +0000461 /*
462 * This file is to be handled.
463 * If we aren't extracting then just list information about the file.
464 */
465 if (!extractFlag) {
466 if (verboseFlag) {
467 printf ("%s %3d/%-d %9ld %s %s", modeString (mode),
468 uid, gid, size, timeString (mtime), name);
469 } else
470 printf ("%s", name);
Eric Andersencc8ed391999-10-05 16:24:54 +0000471
472 if (hardLink)
Eric Andersen3cf52d11999-10-12 22:26:06 +0000473 printf (" (link to \"%s\")", hp->linkName);
474 else if (softLink)
475 printf (" (symlink to \"%s\")", hp->linkName);
476 else if (S_ISREG (mode)) {
477 inHeader = (size == 0);
478 dataCc = size;
Eric Andersencc8ed391999-10-05 16:24:54 +0000479 }
480
Eric Andersen3cf52d11999-10-12 22:26:06 +0000481 printf ("\n");
482
483 return;
484 }
485
486 /*
487 * We really want to extract the file.
488 */
489 if (verboseFlag)
490 printf ("x %s\n", name);
491
492 if (hardLink) {
493 if (link (hp->linkName, name) < 0)
494 perror (name);
495
496 return;
497 }
498
499 if (softLink) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000500#ifdef S_ISLNK
Eric Andersen3cf52d11999-10-12 22:26:06 +0000501 if (symlink (hp->linkName, name) < 0)
502 perror (name);
Eric Andersencc8ed391999-10-05 16:24:54 +0000503#else
Eric Andersen3cf52d11999-10-12 22:26:06 +0000504 fprintf (stderr, "Cannot create symbolic links\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000505#endif
Eric Andersen3cf52d11999-10-12 22:26:06 +0000506 return;
507 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000508
Eric Andersen3cf52d11999-10-12 22:26:06 +0000509 /*
510 * If the file is a directory, then just create the path.
511 */
512 if (S_ISDIR (mode)) {
513 createPath (name, mode);
Eric Andersencc8ed391999-10-05 16:24:54 +0000514
Eric Andersen3cf52d11999-10-12 22:26:06 +0000515 return;
516 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000517
Eric Andersen3cf52d11999-10-12 22:26:06 +0000518 /*
519 * There is a file to write.
520 * First create the path to it if necessary with a default permission.
521 */
522 createPath (name, 0777);
Eric Andersencc8ed391999-10-05 16:24:54 +0000523
Eric Andersen3cf52d11999-10-12 22:26:06 +0000524 inHeader = (size == 0);
525 dataCc = size;
Eric Andersencc8ed391999-10-05 16:24:54 +0000526
Eric Andersen3cf52d11999-10-12 22:26:06 +0000527 /*
528 * Start the output file.
529 */
530 if (tostdoutFlag == TRUE)
531 outFd = STDOUT;
532 else
533 outFd = open (name, O_WRONLY | O_CREAT | O_TRUNC, mode);
Eric Andersencc8ed391999-10-05 16:24:54 +0000534
Eric Andersen3cf52d11999-10-12 22:26:06 +0000535 if (outFd < 0) {
536 perror (name);
537 skipFileFlag = TRUE;
538 return;
539 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000540
Eric Andersen3cf52d11999-10-12 22:26:06 +0000541 /*
542 * If the file is empty, then that's all we need to do.
543 */
544 if (size == 0 && tostdoutFlag == FALSE) {
545 (void) close (outFd);
546 outFd = -1;
547 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000548}
549
550
551/*
552 * Handle a data block of some specified size that was read.
553 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000554static void readData (const char *cp, int count)
Eric Andersencc8ed391999-10-05 16:24:54 +0000555{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000556 /*
557 * Reduce the amount of data left in this file.
558 * If there is no more data left, then we need to read
559 * the header again.
560 */
561 dataCc -= count;
Eric Andersencc8ed391999-10-05 16:24:54 +0000562
Eric Andersen3cf52d11999-10-12 22:26:06 +0000563 if (dataCc <= 0)
564 inHeader = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000565
Eric Andersen3cf52d11999-10-12 22:26:06 +0000566 /*
567 * If we aren't extracting files or this file is being
568 * skipped then do nothing more.
569 */
570 if (!extractFlag || skipFileFlag)
571 return;
Eric Andersencc8ed391999-10-05 16:24:54 +0000572
Eric Andersen3cf52d11999-10-12 22:26:06 +0000573 /*
574 * Write the data to the output file.
575 */
576 if (fullWrite (outFd, cp, count) < 0) {
577 perror (outName);
578 if (tostdoutFlag == FALSE) {
579 (void) close (outFd);
580 outFd = -1;
Eric Andersencc8ed391999-10-05 16:24:54 +0000581 }
Eric Andersen3cf52d11999-10-12 22:26:06 +0000582 skipFileFlag = TRUE;
583 return;
584 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000585
Eric Andersen3cf52d11999-10-12 22:26:06 +0000586 /*
587 * If the write failed, close the file and disable further
588 * writes to this file.
589 */
590 if (dataCc <= 0 && tostdoutFlag == FALSE) {
591 if (close (outFd))
592 perror (outName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000593
Eric Andersen3cf52d11999-10-12 22:26:06 +0000594 outFd = -1;
595 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000596}
597
598
599/*
600 * Write a tar file containing the specified files.
601 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000602static void writeTarFile (int fileCount, char **fileTable)
Eric Andersencc8ed391999-10-05 16:24:54 +0000603{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000604 struct stat statbuf;
Eric Andersencc8ed391999-10-05 16:24:54 +0000605
Eric Andersen3cf52d11999-10-12 22:26:06 +0000606 /*
607 * Make sure there is at least one file specified.
608 */
609 if (fileCount <= 0) {
610 fprintf (stderr, "No files specified to be saved\n");
611 errorFlag = TRUE;
612 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000613
Eric Andersen3cf52d11999-10-12 22:26:06 +0000614 /*
615 * Create the tar file for writing.
616 */
617 if ((tarName == NULL) || !strcmp (tarName, "-")) {
618 tostdoutFlag = TRUE;
619 tarFd = STDOUT;
620 } else
621 tarFd = open (tarName, O_WRONLY | O_CREAT | O_TRUNC, 0666);
Eric Andersencc8ed391999-10-05 16:24:54 +0000622
Eric Andersen3cf52d11999-10-12 22:26:06 +0000623 if (tarFd < 0) {
624 perror (tarName);
625 errorFlag = TRUE;
626 return;
627 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000628
Eric Andersen3cf52d11999-10-12 22:26:06 +0000629 /*
630 * Get the device and inode of the tar file for checking later.
631 */
632 if (fstat (tarFd, &statbuf) < 0) {
633 perror (tarName);
634 errorFlag = TRUE;
635 goto done;
636 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000637
Eric Andersen3cf52d11999-10-12 22:26:06 +0000638 tarDev = statbuf.st_dev;
639 tarInode = statbuf.st_ino;
Eric Andersencc8ed391999-10-05 16:24:54 +0000640
Eric Andersen3cf52d11999-10-12 22:26:06 +0000641 /*
642 * Append each file name into the archive file.
643 * Follow symbolic links for these top level file names.
644 */
645 while (!errorFlag && (fileCount-- > 0)) {
646 saveFile (*fileTable++, FALSE);
647 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000648
Eric Andersen3cf52d11999-10-12 22:26:06 +0000649 /*
650 * Now write an empty block of zeroes to end the archive.
651 */
652 writeTarBlock ("", 1);
Eric Andersencc8ed391999-10-05 16:24:54 +0000653
654
Eric Andersen3cf52d11999-10-12 22:26:06 +0000655 done:
656 /*
657 * Close the tar file and check for errors if it was opened.
658 */
659 if ((tostdoutFlag == FALSE) && (tarFd >= 0) && (close (tarFd) < 0))
660 perror (tarName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000661}
662
663
664/*
665 * Save one file into the tar file.
666 * If the file is a directory, then this will recursively save all of
667 * the files and directories within the directory. The seeLinks
668 * flag indicates whether or not we want to see symbolic links as
669 * they really are, instead of blindly following them.
670 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000671static void saveFile (const char *fileName, int seeLinks)
Eric Andersencc8ed391999-10-05 16:24:54 +0000672{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000673 int status;
674 int mode;
675 struct stat statbuf;
Eric Andersencc8ed391999-10-05 16:24:54 +0000676
Eric Andersen3cf52d11999-10-12 22:26:06 +0000677 if (verboseFlag)
678 printf ("a %s\n", fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000679
Eric Andersen3cf52d11999-10-12 22:26:06 +0000680 /*
681 * Check that the file name will fit in the header.
682 */
683 if (strlen (fileName) >= TAR_NAME_SIZE) {
684 fprintf (stderr, "%s: File name is too long\n", fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000685
Eric Andersen3cf52d11999-10-12 22:26:06 +0000686 return;
687 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000688
Eric Andersen3cf52d11999-10-12 22:26:06 +0000689 /*
690 * Find out about the file.
691 */
Eric Andersencc8ed391999-10-05 16:24:54 +0000692#ifdef S_ISLNK
Eric Andersen3cf52d11999-10-12 22:26:06 +0000693 if (seeLinks)
694 status = lstat (fileName, &statbuf);
695 else
Eric Andersencc8ed391999-10-05 16:24:54 +0000696#endif
Eric Andersen3cf52d11999-10-12 22:26:06 +0000697 status = stat (fileName, &statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000698
Eric Andersen3cf52d11999-10-12 22:26:06 +0000699 if (status < 0) {
700 perror (fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000701
Eric Andersen3cf52d11999-10-12 22:26:06 +0000702 return;
703 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000704
Eric Andersen3cf52d11999-10-12 22:26:06 +0000705 /*
706 * Make sure we aren't trying to save our file into itself.
707 */
708 if ((statbuf.st_dev == tarDev) && (statbuf.st_ino == tarInode)) {
709 fprintf (stderr, "Skipping saving of archive file itself\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000710
Eric Andersen3cf52d11999-10-12 22:26:06 +0000711 return;
712 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000713
Eric Andersen3cf52d11999-10-12 22:26:06 +0000714 /*
715 * Check the type of file.
716 */
717 mode = statbuf.st_mode;
Eric Andersencc8ed391999-10-05 16:24:54 +0000718
Eric Andersen3cf52d11999-10-12 22:26:06 +0000719 if (S_ISDIR (mode)) {
720 saveDirectory (fileName, &statbuf);
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 if (S_ISREG (mode)) {
726 saveRegularFile (fileName, &statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000727
Eric Andersen3cf52d11999-10-12 22:26:06 +0000728 return;
729 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000730
Eric Andersen3cf52d11999-10-12 22:26:06 +0000731 /*
732 * The file is a strange type of file, ignore it.
733 */
734 fprintf (stderr, "%s: not a directory or regular file\n", fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000735}
736
737
738/*
739 * Save a regular file to the tar file.
740 */
741static void
Eric Andersen3cf52d11999-10-12 22:26:06 +0000742saveRegularFile (const char *fileName, const struct stat *statbuf)
Eric Andersencc8ed391999-10-05 16:24:54 +0000743{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000744 int sawEof;
745 int fileFd;
746 int cc;
747 int dataCount;
748 long fullDataCount;
749 char data[TAR_BLOCK_SIZE * 16];
Eric Andersencc8ed391999-10-05 16:24:54 +0000750
Eric Andersen3cf52d11999-10-12 22:26:06 +0000751 /*
752 * Open the file for reading.
753 */
754 fileFd = open (fileName, O_RDONLY);
755
756 if (fileFd < 0) {
757 perror (fileName);
758
759 return;
760 }
761
762 /*
763 * Write out the header for the file.
764 */
765 writeHeader (fileName, statbuf);
766
767 /*
768 * Write the data blocks of the file.
769 * We must be careful to write the amount of data that the stat
770 * buffer indicated, even if the file has changed size. Otherwise
771 * the tar file will be incorrect.
772 */
773 fullDataCount = statbuf->st_size;
774 sawEof = FALSE;
775
776 while (fullDataCount > 0) {
777 /*
778 * Get the amount to write this iteration which is
779 * the minumum of the amount left to write and the
780 * buffer size.
Eric Andersencc8ed391999-10-05 16:24:54 +0000781 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000782 dataCount = sizeof (data);
Eric Andersencc8ed391999-10-05 16:24:54 +0000783
Eric Andersen3cf52d11999-10-12 22:26:06 +0000784 if (dataCount > fullDataCount)
785 dataCount = (int) fullDataCount;
786
787 /*
788 * Read the data from the file if we haven't seen the
789 * end of file yet.
790 */
791 cc = 0;
792
793 if (!sawEof) {
794 cc = fullRead (fileFd, data, dataCount);
795
796 if (cc < 0) {
797 perror (fileName);
798
799 (void) close (fileFd);
800 errorFlag = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000801
802 return;
Eric Andersen3cf52d11999-10-12 22:26:06 +0000803 }
804
805 /*
806 * If the file ended too soon, complain and set
807 * a flag so we will zero fill the rest of it.
808 */
809 if (cc < dataCount) {
810 fprintf (stderr,
811 "%s: Short read - zero filling", fileName);
812
813 sawEof = TRUE;
814 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000815 }
816
Eric Andersen3cf52d11999-10-12 22:26:06 +0000817 /*
818 * Zero fill the rest of the data if necessary.
Eric Andersencc8ed391999-10-05 16:24:54 +0000819 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000820 if (cc < dataCount)
821 memset (data + cc, 0, dataCount - cc);
Eric Andersencc8ed391999-10-05 16:24:54 +0000822
Eric Andersen3cf52d11999-10-12 22:26:06 +0000823 /*
824 * Write the buffer to the TAR file.
Eric Andersencc8ed391999-10-05 16:24:54 +0000825 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000826 writeTarBlock (data, dataCount);
Eric Andersencc8ed391999-10-05 16:24:54 +0000827
Eric Andersen3cf52d11999-10-12 22:26:06 +0000828 fullDataCount -= dataCount;
829 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000830
Eric Andersen3cf52d11999-10-12 22:26:06 +0000831 /*
832 * Close the file.
833 */
834 if ((tostdoutFlag == FALSE) && close (fileFd) < 0)
835 fprintf (stderr, "%s: close: %s\n", fileName, strerror (errno));
Eric Andersencc8ed391999-10-05 16:24:54 +0000836}
837
838
839/*
840 * Save a directory and all of its files to the tar file.
841 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000842static void saveDirectory (const char *dirName, const struct stat *statbuf)
Eric Andersencc8ed391999-10-05 16:24:54 +0000843{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000844 DIR *dir;
845 struct dirent *entry;
846 int needSlash;
Eric Andersen1b61f411999-10-13 18:56:42 +0000847 char fullName[NAME_MAX];
Eric Andersencc8ed391999-10-05 16:24:54 +0000848
Eric Andersen3cf52d11999-10-12 22:26:06 +0000849 /*
850 * Construct the directory name as used in the tar file by appending
851 * a slash character to it.
852 */
853 strcpy (fullName, dirName);
854 strcat (fullName, "/");
Eric Andersencc8ed391999-10-05 16:24:54 +0000855
Eric Andersen3cf52d11999-10-12 22:26:06 +0000856 /*
857 * Write out the header for the directory entry.
858 */
859 writeHeader (fullName, statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000860
Eric Andersen3cf52d11999-10-12 22:26:06 +0000861 /*
862 * Open the directory.
863 */
864 dir = opendir (dirName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000865
Eric Andersen3cf52d11999-10-12 22:26:06 +0000866 if (dir == NULL) {
867 fprintf (stderr, "Cannot read directory \"%s\": %s\n",
868 dirName, strerror (errno));
Eric Andersencc8ed391999-10-05 16:24:54 +0000869
Eric Andersen3cf52d11999-10-12 22:26:06 +0000870 return;
871 }
872
873 /*
874 * See if a slash is needed.
875 */
876 needSlash = (*dirName && (dirName[strlen (dirName) - 1] != '/'));
877
878 /*
879 * Read all of the directory entries and check them,
880 * except for the current and parent directory entries.
881 */
882 while (!errorFlag && ((entry = readdir (dir)) != NULL)) {
883 if ((strcmp (entry->d_name, ".") == 0) ||
884 (strcmp (entry->d_name, "..") == 0)) {
885 continue;
Eric Andersencc8ed391999-10-05 16:24:54 +0000886 }
887
Eric Andersen3cf52d11999-10-12 22:26:06 +0000888 /*
889 * Build the full path name to the file.
Eric Andersencc8ed391999-10-05 16:24:54 +0000890 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000891 strcpy (fullName, dirName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000892
Eric Andersen3cf52d11999-10-12 22:26:06 +0000893 if (needSlash)
894 strcat (fullName, "/");
895
896 strcat (fullName, entry->d_name);
897
898 /*
899 * Write this file to the tar file, noticing whether or not
900 * the file is a symbolic link.
Eric Andersencc8ed391999-10-05 16:24:54 +0000901 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000902 saveFile (fullName, TRUE);
903 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000904
Eric Andersen3cf52d11999-10-12 22:26:06 +0000905 /*
906 * All done, close the directory.
907 */
908 closedir (dir);
Eric Andersencc8ed391999-10-05 16:24:54 +0000909}
910
911
912/*
913 * Write a tar header for the specified file name and status.
914 * It is assumed that the file name fits.
915 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000916static void writeHeader (const char *fileName, const struct stat *statbuf)
Eric Andersencc8ed391999-10-05 16:24:54 +0000917{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000918 long checkSum;
919 const unsigned char *cp;
920 int len;
921 TarHeader header;
Eric Andersencc8ed391999-10-05 16:24:54 +0000922
Eric Andersen3cf52d11999-10-12 22:26:06 +0000923 /*
924 * Zero the header block in preparation for filling it in.
925 */
926 memset ((char *) &header, 0, sizeof (header));
Eric Andersencc8ed391999-10-05 16:24:54 +0000927
Eric Andersen3cf52d11999-10-12 22:26:06 +0000928 /*
929 * Fill in the header.
930 */
931 strcpy (header.name, fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000932
Eric Andersen3cf52d11999-10-12 22:26:06 +0000933 strncpy (header.magic, TAR_MAGIC, sizeof (header.magic));
934 strncpy (header.version, TAR_VERSION, sizeof (header.version));
Eric Andersencc8ed391999-10-05 16:24:54 +0000935
Eric Andersen3cf52d11999-10-12 22:26:06 +0000936 putOctal (header.mode, sizeof (header.mode), statbuf->st_mode & 0777);
937 putOctal (header.uid, sizeof (header.uid), statbuf->st_uid);
938 putOctal (header.gid, sizeof (header.gid), statbuf->st_gid);
939 putOctal (header.size, sizeof (header.size), statbuf->st_size);
940 putOctal (header.mtime, sizeof (header.mtime), statbuf->st_mtime);
Eric Andersencc8ed391999-10-05 16:24:54 +0000941
Eric Andersen3cf52d11999-10-12 22:26:06 +0000942 header.typeFlag = TAR_TYPE_REGULAR;
Eric Andersencc8ed391999-10-05 16:24:54 +0000943
Eric Andersen3cf52d11999-10-12 22:26:06 +0000944 /*
945 * Calculate and store the checksum.
946 * This is the sum of all of the bytes of the header,
947 * with the checksum field itself treated as blanks.
948 */
949 memset (header.checkSum, ' ', sizeof (header.checkSum));
Eric Andersencc8ed391999-10-05 16:24:54 +0000950
Eric Andersen3cf52d11999-10-12 22:26:06 +0000951 cp = (const unsigned char *) &header;
952 len = sizeof (header);
953 checkSum = 0;
Eric Andersencc8ed391999-10-05 16:24:54 +0000954
Eric Andersen3cf52d11999-10-12 22:26:06 +0000955 while (len-- > 0)
956 checkSum += *cp++;
Eric Andersencc8ed391999-10-05 16:24:54 +0000957
Eric Andersen3cf52d11999-10-12 22:26:06 +0000958 putOctal (header.checkSum, sizeof (header.checkSum), checkSum);
Eric Andersencc8ed391999-10-05 16:24:54 +0000959
Eric Andersen3cf52d11999-10-12 22:26:06 +0000960 /*
961 * Write the tar header.
962 */
963 writeTarBlock ((const char *) &header, sizeof (header));
Eric Andersencc8ed391999-10-05 16:24:54 +0000964}
965
966
967/*
968 * Write data to one or more blocks of the tar file.
969 * The data is always padded out to a multiple of TAR_BLOCK_SIZE.
970 * The errorFlag static variable is set on an error.
971 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000972static void writeTarBlock (const char *buf, int len)
Eric Andersencc8ed391999-10-05 16:24:54 +0000973{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000974 int partialLength;
975 int completeLength;
976 char fullBlock[TAR_BLOCK_SIZE];
Eric Andersencc8ed391999-10-05 16:24:54 +0000977
Eric Andersen3cf52d11999-10-12 22:26:06 +0000978 /*
979 * If we had a write error before, then do nothing more.
980 */
981 if (errorFlag)
982 return;
Eric Andersencc8ed391999-10-05 16:24:54 +0000983
Eric Andersen3cf52d11999-10-12 22:26:06 +0000984 /*
985 * Get the amount of complete and partial blocks.
986 */
987 partialLength = len % TAR_BLOCK_SIZE;
988 completeLength = len - partialLength;
Eric Andersencc8ed391999-10-05 16:24:54 +0000989
Eric Andersen3cf52d11999-10-12 22:26:06 +0000990 /*
991 * Write all of the complete blocks.
992 */
993 if ((completeLength > 0) && !fullWrite (tarFd, buf, completeLength)) {
994 perror (tarName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000995
Eric Andersen3cf52d11999-10-12 22:26:06 +0000996 errorFlag = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000997
Eric Andersen3cf52d11999-10-12 22:26:06 +0000998 return;
999 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001000
Eric Andersen3cf52d11999-10-12 22:26:06 +00001001 /*
1002 * If there are no partial blocks left, we are done.
1003 */
1004 if (partialLength == 0)
1005 return;
Eric Andersencc8ed391999-10-05 16:24:54 +00001006
Eric Andersen3cf52d11999-10-12 22:26:06 +00001007 /*
1008 * Copy the partial data into a complete block, and pad the rest
1009 * of it with zeroes.
1010 */
1011 memcpy (fullBlock, buf + completeLength, partialLength);
1012 memset (fullBlock + partialLength, 0, TAR_BLOCK_SIZE - partialLength);
Eric Andersencc8ed391999-10-05 16:24:54 +00001013
Eric Andersen3cf52d11999-10-12 22:26:06 +00001014 /*
1015 * Write the last complete block.
1016 */
1017 if (!fullWrite (tarFd, fullBlock, TAR_BLOCK_SIZE)) {
1018 perror (tarName);
Eric Andersencc8ed391999-10-05 16:24:54 +00001019
Eric Andersen3cf52d11999-10-12 22:26:06 +00001020 errorFlag = TRUE;
1021 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001022}
1023
1024
1025/*
1026 * Attempt to create the directories along the specified path, except for
1027 * the final component. The mode is given for the final directory only,
1028 * while all previous ones get default protections. Errors are not reported
1029 * here, as failures to restore files can be reported later.
1030 */
Eric Andersen3cf52d11999-10-12 22:26:06 +00001031static void createPath (const char *name, int mode)
Eric Andersencc8ed391999-10-05 16:24:54 +00001032{
Eric Andersen3cf52d11999-10-12 22:26:06 +00001033 char *cp;
1034 char *cpOld;
1035 char buf[TAR_NAME_SIZE];
Eric Andersencc8ed391999-10-05 16:24:54 +00001036
Eric Andersen3cf52d11999-10-12 22:26:06 +00001037 strcpy (buf, name);
Eric Andersencc8ed391999-10-05 16:24:54 +00001038
Eric Andersen3cf52d11999-10-12 22:26:06 +00001039 cp = strchr (buf, '/');
Eric Andersencc8ed391999-10-05 16:24:54 +00001040
Eric Andersen3cf52d11999-10-12 22:26:06 +00001041 while (cp) {
1042 cpOld = cp;
1043 cp = strchr (cp + 1, '/');
Eric Andersencc8ed391999-10-05 16:24:54 +00001044
Eric Andersen3cf52d11999-10-12 22:26:06 +00001045 *cpOld = '\0';
Eric Andersencc8ed391999-10-05 16:24:54 +00001046
Eric Andersen3cf52d11999-10-12 22:26:06 +00001047 if (mkdir (buf, cp ? 0777 : mode) == 0)
1048 printf ("Directory \"%s\" created\n", buf);
Eric Andersencc8ed391999-10-05 16:24:54 +00001049
Eric Andersen3cf52d11999-10-12 22:26:06 +00001050 *cpOld = '/';
1051 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001052}
1053
1054
1055/*
1056 * Read an octal value in a field of the specified width, with optional
1057 * spaces on both sides of the number and with an optional null character
1058 * at the end. Returns -1 on an illegal format.
1059 */
Eric Andersen3cf52d11999-10-12 22:26:06 +00001060static long getOctal (const char *cp, int len)
Eric Andersencc8ed391999-10-05 16:24:54 +00001061{
Eric Andersen3cf52d11999-10-12 22:26:06 +00001062 long val;
Eric Andersencc8ed391999-10-05 16:24:54 +00001063
Eric Andersen3cf52d11999-10-12 22:26:06 +00001064 while ((len > 0) && (*cp == ' ')) {
1065 cp++;
1066 len--;
1067 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001068
Eric Andersen3cf52d11999-10-12 22:26:06 +00001069 if ((len == 0) || !isOctal (*cp))
1070 return -1;
Eric Andersencc8ed391999-10-05 16:24:54 +00001071
Eric Andersen3cf52d11999-10-12 22:26:06 +00001072 val = 0;
Eric Andersencc8ed391999-10-05 16:24:54 +00001073
Eric Andersen3cf52d11999-10-12 22:26:06 +00001074 while ((len > 0) && isOctal (*cp)) {
1075 val = val * 8 + *cp++ - '0';
1076 len--;
1077 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001078
Eric Andersen3cf52d11999-10-12 22:26:06 +00001079 while ((len > 0) && (*cp == ' ')) {
1080 cp++;
1081 len--;
1082 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001083
Eric Andersen3cf52d11999-10-12 22:26:06 +00001084 if ((len > 0) && *cp)
1085 return -1;
Eric Andersencc8ed391999-10-05 16:24:54 +00001086
Eric Andersen3cf52d11999-10-12 22:26:06 +00001087 return val;
Eric Andersencc8ed391999-10-05 16:24:54 +00001088}
1089
1090
1091/*
1092 * Put an octal string into the specified buffer.
1093 * The number is zero and space padded and possibly null padded.
1094 * Returns TRUE if successful.
1095 */
Eric Andersen3cf52d11999-10-12 22:26:06 +00001096static int putOctal (char *cp, int len, long value)
Eric Andersencc8ed391999-10-05 16:24:54 +00001097{
Eric Andersen3cf52d11999-10-12 22:26:06 +00001098 int tempLength;
1099 char *tempString;
1100 char tempBuffer[32];
Eric Andersencc8ed391999-10-05 16:24:54 +00001101
Eric Andersen3cf52d11999-10-12 22:26:06 +00001102 /*
1103 * Create a string of the specified length with an initial space,
1104 * leading zeroes and the octal number, and a trailing null.
1105 */
1106 tempString = tempBuffer;
Eric Andersencc8ed391999-10-05 16:24:54 +00001107
Eric Andersen3cf52d11999-10-12 22:26:06 +00001108 sprintf (tempString, " %0*lo", len - 2, value);
Eric Andersencc8ed391999-10-05 16:24:54 +00001109
Eric Andersen3cf52d11999-10-12 22:26:06 +00001110 tempLength = strlen (tempString) + 1;
Eric Andersencc8ed391999-10-05 16:24:54 +00001111
Eric Andersen3cf52d11999-10-12 22:26:06 +00001112 /*
1113 * If the string is too large, suppress the leading space.
1114 */
1115 if (tempLength > len) {
1116 tempLength--;
1117 tempString++;
1118 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001119
Eric Andersen3cf52d11999-10-12 22:26:06 +00001120 /*
1121 * If the string is still too large, suppress the trailing null.
1122 */
1123 if (tempLength > len)
1124 tempLength--;
Eric Andersencc8ed391999-10-05 16:24:54 +00001125
Eric Andersen3cf52d11999-10-12 22:26:06 +00001126 /*
1127 * If the string is still too large, fail.
1128 */
1129 if (tempLength > len)
1130 return FALSE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001131
Eric Andersen3cf52d11999-10-12 22:26:06 +00001132 /*
1133 * Copy the string to the field.
1134 */
1135 memcpy (cp, tempString, len);
Eric Andersencc8ed391999-10-05 16:24:54 +00001136
Eric Andersen3cf52d11999-10-12 22:26:06 +00001137 return TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001138}
1139
1140
1141/*
1142 * See if the specified file name belongs to one of the specified list
1143 * of path prefixes. An empty list implies that all files are wanted.
1144 * Returns TRUE if the file is selected.
1145 */
Eric Andersenf811e071999-10-09 00:25:00 +00001146static int
Eric Andersen3cf52d11999-10-12 22:26:06 +00001147wantFileName (const char *fileName, int fileCount, char **fileTable)
Eric Andersencc8ed391999-10-05 16:24:54 +00001148{
Eric Andersen3cf52d11999-10-12 22:26:06 +00001149 const char *pathName;
1150 int fileLength;
1151 int pathLength;
Eric Andersencc8ed391999-10-05 16:24:54 +00001152
Eric Andersen3cf52d11999-10-12 22:26:06 +00001153 /*
1154 * If there are no files in the list, then the file is wanted.
1155 */
1156 if (fileCount == 0)
1157 return TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001158
Eric Andersen3cf52d11999-10-12 22:26:06 +00001159 fileLength = strlen (fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +00001160
Eric Andersen3cf52d11999-10-12 22:26:06 +00001161 /*
1162 * Check each of the test paths.
1163 */
1164 while (fileCount-- > 0) {
1165 pathName = *fileTable++;
Eric Andersencc8ed391999-10-05 16:24:54 +00001166
Eric Andersen3cf52d11999-10-12 22:26:06 +00001167 pathLength = strlen (pathName);
Eric Andersencc8ed391999-10-05 16:24:54 +00001168
Eric Andersen3cf52d11999-10-12 22:26:06 +00001169 if (fileLength < pathLength)
1170 continue;
Eric Andersencc8ed391999-10-05 16:24:54 +00001171
Eric Andersen3cf52d11999-10-12 22:26:06 +00001172 if (memcmp (fileName, pathName, pathLength) != 0)
1173 continue;
Eric Andersencc8ed391999-10-05 16:24:54 +00001174
Eric Andersen3cf52d11999-10-12 22:26:06 +00001175 if ((fileLength == pathLength) || (fileName[pathLength] == '/')) {
1176 return TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001177 }
Eric Andersen3cf52d11999-10-12 22:26:06 +00001178 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001179
Eric Andersen3cf52d11999-10-12 22:26:06 +00001180 return FALSE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001181}
1182
1183
1184
Eric Andersencc8ed391999-10-05 16:24:54 +00001185#endif
1186/* END CODE */