blob: f222c3c9d786c0d8119fa56d5a5bd3b6de402fc8 [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);
Eric Andersen3cf52d11999-10-12 22:26:06 +0000106static long getOctal (const char *cp, int len);
Eric Andersencc8ed391999-10-05 16:24:54 +0000107
Eric Andersen3cf52d11999-10-12 22:26:06 +0000108static void readHeader (const TarHeader * hp,
109 int fileCount, char **fileTable);
Eric Andersencc8ed391999-10-05 16:24:54 +0000110
111
112/*
113 * Local procedures to save files into a tar file.
114 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000115static void saveFile (const char *fileName, int seeLinks);
Eric Andersencc8ed391999-10-05 16:24:54 +0000116
Eric Andersen3cf52d11999-10-12 22:26:06 +0000117static void saveRegularFile (const char *fileName,
118 const struct stat *statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000119
Eric Andersen3cf52d11999-10-12 22:26:06 +0000120static void saveDirectory (const char *fileName,
121 const struct stat *statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000122
Eric Andersen3cf52d11999-10-12 22:26:06 +0000123static int wantFileName (const char *fileName,
124 int fileCount, char **fileTable);
Eric Andersencc8ed391999-10-05 16:24:54 +0000125
Eric Andersen3cf52d11999-10-12 22:26:06 +0000126static void writeHeader (const char *fileName, const struct stat *statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000127
Eric Andersen3cf52d11999-10-12 22:26:06 +0000128static void writeTarFile (int fileCount, char **fileTable);
129static void writeTarBlock (const char *buf, int len);
130static int putOctal (char *cp, int len, long value);
Eric Andersencc8ed391999-10-05 16:24:54 +0000131
132
Eric Andersen3cf52d11999-10-12 22:26:06 +0000133extern int tar_main (int argc, char **argv)
Eric Andersencc8ed391999-10-05 16:24:54 +0000134{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000135 const char *options;
Eric Andersencc8ed391999-10-05 16:24:54 +0000136
Eric Andersen3cf52d11999-10-12 22:26:06 +0000137 argc--;
138 argv++;
Eric Andersencc8ed391999-10-05 16:24:54 +0000139
Eric Andersen3cf52d11999-10-12 22:26:06 +0000140 if (argc < 1) {
141 fprintf (stderr, "%s", tar_usage);
142 exit (FALSE);
143 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000144
145
Eric Andersen3cf52d11999-10-12 22:26:06 +0000146 errorFlag = FALSE;
147 extractFlag = FALSE;
148 createFlag = FALSE;
149 listFlag = FALSE;
150 verboseFlag = FALSE;
151 tostdoutFlag = FALSE;
152 tarName = NULL;
153 tarDev = 0;
154 tarInode = 0;
155 tarFd = -1;
Eric Andersencc8ed391999-10-05 16:24:54 +0000156
Eric Andersen3cf52d11999-10-12 22:26:06 +0000157 /*
158 * Parse the options.
159 */
160 options = *argv++;
161 argc--;
Eric Andersencc8ed391999-10-05 16:24:54 +0000162
Eric Andersen3cf52d11999-10-12 22:26:06 +0000163 if (**argv == '-') {
164 for (; *options; options++) {
165 switch (*options) {
166 case 'f':
167 if (tarName != NULL) {
168 fprintf (stderr, "Only one 'f' option allowed\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000169
Eric Andersen3cf52d11999-10-12 22:26:06 +0000170 exit (FALSE);
Eric Andersencc8ed391999-10-05 16:24:54 +0000171 }
Eric Andersen3cf52d11999-10-12 22:26:06 +0000172
173 tarName = *argv++;
174 argc--;
175
176 break;
177
178 case 't':
179 listFlag = TRUE;
180 break;
181
182 case 'x':
183 extractFlag = TRUE;
184 break;
185
186 case 'c':
187 createFlag = TRUE;
188 break;
189
190 case 'v':
191 verboseFlag = TRUE;
192 break;
193
194 case 'O':
195 tostdoutFlag = TRUE;
196 break;
197
198 case '-':
199 break;
200
201 default:
202 fprintf (stderr, "Unknown tar flag '%c'\n", *options);
203
204 exit (FALSE);
205 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000206 }
Eric Andersen3cf52d11999-10-12 22:26:06 +0000207 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000208
Eric Andersen3cf52d11999-10-12 22:26:06 +0000209 /*
210 * Validate the options.
211 */
212 if (extractFlag + listFlag + createFlag != 1) {
213 fprintf (stderr,
214 "Exactly one of 'c', 'x' or 't' must be specified\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000215
Eric Andersen3cf52d11999-10-12 22:26:06 +0000216 exit (FALSE);
217 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000218
Eric Andersen3cf52d11999-10-12 22:26:06 +0000219 /*
220 * Do the correct type of action supplying the rest of the
221 * command line arguments as the list of files to process.
222 */
223 if (createFlag)
224 writeTarFile (argc, argv);
225 else
226 readTarFile (argc, argv);
227 if (errorFlag)
228 fprintf (stderr, "\n");
229 exit (errorFlag);
Eric Andersencc8ed391999-10-05 16:24:54 +0000230}
231
232
233/*
234 * Read a tar file and extract or list the specified files within it.
235 * If the list is empty than all files are extracted or listed.
236 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000237static void readTarFile (int fileCount, char **fileTable)
Eric Andersencc8ed391999-10-05 16:24:54 +0000238{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000239 const char *cp;
240 int cc;
241 int inCc;
242 int blockSize;
243 char buf[BUF_SIZE];
Eric Andersencc8ed391999-10-05 16:24:54 +0000244
Eric Andersen3cf52d11999-10-12 22:26:06 +0000245 skipFileFlag = FALSE;
246 badHeader = FALSE;
247 warnedRoot = FALSE;
248 eofFlag = FALSE;
249 inHeader = TRUE;
250 inCc = 0;
251 dataCc = 0;
252 outFd = -1;
253 blockSize = sizeof (buf);
254 cp = buf;
Eric Andersencc8ed391999-10-05 16:24:54 +0000255
Eric Andersen3cf52d11999-10-12 22:26:06 +0000256 /*
257 * Open the tar file for reading.
258 */
259 if ((tarName == NULL) || !strcmp (tarName, "-")) {
260 tarFd = STDIN;
261 } else
262 tarFd = open (tarName, O_RDONLY);
263
264 if (tarFd < 0) {
265 perror (tarName);
266 errorFlag = TRUE;
267 return;
268 }
269
270 /*
271 * Read blocks from the file until an end of file header block
272 * has been seen. (A real end of file from a read is an error.)
273 */
274 while (!eofFlag) {
275 /*
276 * Read the next block of data if necessary.
277 * This will be a large block if possible, which we will
278 * then process in the small tar blocks.
Eric Andersencc8ed391999-10-05 16:24:54 +0000279 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000280 if (inCc <= 0) {
281 cp = buf;
282 inCc = fullRead (tarFd, buf, blockSize);
Eric Andersencc8ed391999-10-05 16:24:54 +0000283
Eric Andersen3cf52d11999-10-12 22:26:06 +0000284 if (inCc < 0) {
285 perror (tarName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000286 errorFlag = TRUE;
Eric Andersen3cf52d11999-10-12 22:26:06 +0000287 goto done;
288 }
289
290 if (inCc == 0) {
291 fprintf (stderr,
292 "Unexpected end of file from \"%s\"", tarName);
293 errorFlag = TRUE;
294 goto done;
295 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000296 }
297
Eric Andersen3cf52d11999-10-12 22:26:06 +0000298 /*
299 * If we are expecting a header block then examine it.
Eric Andersencc8ed391999-10-05 16:24:54 +0000300 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000301 if (inHeader) {
302 readHeader ((const TarHeader *) cp, fileCount, fileTable);
Eric Andersencc8ed391999-10-05 16:24:54 +0000303
Eric Andersen3cf52d11999-10-12 22:26:06 +0000304 cp += TAR_BLOCK_SIZE;
305 inCc -= TAR_BLOCK_SIZE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000306
Eric Andersen3cf52d11999-10-12 22:26:06 +0000307 continue;
Eric Andersencc8ed391999-10-05 16:24:54 +0000308 }
309
Eric Andersen3cf52d11999-10-12 22:26:06 +0000310 /*
311 * We are currently handling the data for a file.
312 * Process the minimum of the amount of data we have available
313 * and the amount left to be processed for the file.
Eric Andersencc8ed391999-10-05 16:24:54 +0000314 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000315 cc = inCc;
Eric Andersencc8ed391999-10-05 16:24:54 +0000316
Eric Andersen3cf52d11999-10-12 22:26:06 +0000317 if (cc > dataCc)
318 cc = dataCc;
319
320 readData (cp, cc);
321
322 /*
323 * If the amount left isn't an exact multiple of the tar block
324 * size then round it up to the next block boundary since there
325 * is padding at the end of the file.
Eric Andersencc8ed391999-10-05 16:24:54 +0000326 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000327 if (cc % TAR_BLOCK_SIZE)
328 cc += TAR_BLOCK_SIZE - (cc % TAR_BLOCK_SIZE);
329
330 cp += cc;
331 inCc -= cc;
332 }
333
334 done:
335 /*
336 * Close the tar file if needed.
337 */
338 if ((tarFd >= 0) && (close (tarFd) < 0))
339 perror (tarName);
340
341 /*
342 * Close the output file if needed.
343 * This is only done here on a previous error and so no
344 * message is required on errors.
345 */
346 if (tostdoutFlag == FALSE) {
347 if (outFd >= 0)
348 (void) close (outFd);
349 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000350}
351
352
353/*
354 * Examine the header block that was just read.
355 * This can specify the information for another file, or it can mark
356 * the end of the tar file.
357 */
358static void
Eric Andersen3cf52d11999-10-12 22:26:06 +0000359readHeader (const TarHeader * hp, int fileCount, char **fileTable)
Eric Andersencc8ed391999-10-05 16:24:54 +0000360{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000361 int mode;
362 int uid;
363 int gid;
364 int checkSum;
365 long size;
366 time_t mtime;
367 const char *name;
368 int cc;
369 int hardLink;
370 int softLink;
Eric Andersencc8ed391999-10-05 16:24:54 +0000371
Eric Andersen3cf52d11999-10-12 22:26:06 +0000372 /*
373 * If the block is completely empty, then this is the end of the
374 * archive file. If the name is null, then just skip this header.
375 */
376 name = hp->name;
Eric Andersencc8ed391999-10-05 16:24:54 +0000377
Eric Andersen3cf52d11999-10-12 22:26:06 +0000378 if (*name == '\0') {
379 for (cc = TAR_BLOCK_SIZE; cc > 0; cc--) {
380 if (*name++)
Eric Andersencc8ed391999-10-05 16:24:54 +0000381 return;
382 }
383
Eric Andersen3cf52d11999-10-12 22:26:06 +0000384 eofFlag = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000385
Eric Andersen3cf52d11999-10-12 22:26:06 +0000386 return;
387 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000388
Eric Andersen3cf52d11999-10-12 22:26:06 +0000389 /*
390 * There is another file in the archive to examine.
391 * Extract the encoded information and check it.
392 */
393 mode = getOctal (hp->mode, sizeof (hp->mode));
394 uid = getOctal (hp->uid, sizeof (hp->uid));
395 gid = getOctal (hp->gid, sizeof (hp->gid));
396 size = getOctal (hp->size, sizeof (hp->size));
397 mtime = getOctal (hp->mtime, sizeof (hp->mtime));
398 checkSum = getOctal (hp->checkSum, sizeof (hp->checkSum));
Eric Andersencc8ed391999-10-05 16:24:54 +0000399
Eric Andersen3cf52d11999-10-12 22:26:06 +0000400 if ((mode < 0) || (uid < 0) || (gid < 0) || (size < 0)) {
401 if (!badHeader)
402 fprintf (stderr, "Bad tar header, skipping\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000403
Eric Andersen3cf52d11999-10-12 22:26:06 +0000404 badHeader = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000405
Eric Andersen3cf52d11999-10-12 22:26:06 +0000406 return;
407 }
408
409 badHeader = FALSE;
410 skipFileFlag = FALSE;
411
412 /*
413 * Check for the file modes.
414 */
415 hardLink = ((hp->typeFlag == TAR_TYPE_HARD_LINK) ||
Eric Andersencc8ed391999-10-05 16:24:54 +0000416 (hp->typeFlag == TAR_TYPE_HARD_LINK - '0'));
417
Eric Andersen3cf52d11999-10-12 22:26:06 +0000418 softLink = ((hp->typeFlag == TAR_TYPE_SOFT_LINK) ||
Eric Andersencc8ed391999-10-05 16:24:54 +0000419 (hp->typeFlag == TAR_TYPE_SOFT_LINK - '0'));
420
Eric Andersen3cf52d11999-10-12 22:26:06 +0000421 /*
422 * Check for a directory or a regular file.
423 */
424 if (name[strlen (name) - 1] == '/')
425 mode |= S_IFDIR;
426 else if ((mode & S_IFMT) == 0)
427 mode |= S_IFREG;
Eric Andersencc8ed391999-10-05 16:24:54 +0000428
Eric Andersen3cf52d11999-10-12 22:26:06 +0000429 /*
430 * Check for absolute paths in the file.
431 * If we find any, then warn the user and make them relative.
432 */
433 if (*name == '/') {
434 while (*name == '/')
435 name++;
Eric Andersencc8ed391999-10-05 16:24:54 +0000436
Eric Andersen3cf52d11999-10-12 22:26:06 +0000437 if (!warnedRoot) {
438 fprintf (stderr,
439 "Absolute path detected, removing leading slashes\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000440 }
441
Eric Andersen3cf52d11999-10-12 22:26:06 +0000442 warnedRoot = TRUE;
443 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000444
Eric Andersen3cf52d11999-10-12 22:26:06 +0000445 /*
446 * See if we want this file to be restored.
447 * If not, then set up to skip it.
448 */
449 if (!wantFileName (name, fileCount, fileTable)) {
450 if (!hardLink && !softLink && S_ISREG (mode)) {
451 inHeader = (size == 0);
452 dataCc = size;
Eric Andersencc8ed391999-10-05 16:24:54 +0000453 }
454
Eric Andersen3cf52d11999-10-12 22:26:06 +0000455 skipFileFlag = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000456
Eric Andersen3cf52d11999-10-12 22:26:06 +0000457 return;
458 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000459
Eric Andersen3cf52d11999-10-12 22:26:06 +0000460 /*
461 * This file is to be handled.
462 * If we aren't extracting then just list information about the file.
463 */
464 if (!extractFlag) {
465 if (verboseFlag) {
466 printf ("%s %3d/%-d %9ld %s %s", modeString (mode),
467 uid, gid, size, timeString (mtime), name);
468 } else
469 printf ("%s", name);
Eric Andersencc8ed391999-10-05 16:24:54 +0000470
471 if (hardLink)
Eric Andersen3cf52d11999-10-12 22:26:06 +0000472 printf (" (link to \"%s\")", hp->linkName);
473 else if (softLink)
474 printf (" (symlink to \"%s\")", hp->linkName);
475 else if (S_ISREG (mode)) {
476 inHeader = (size == 0);
477 dataCc = size;
Eric Andersencc8ed391999-10-05 16:24:54 +0000478 }
479
Eric Andersen3cf52d11999-10-12 22:26:06 +0000480 printf ("\n");
481
482 return;
483 }
484
485 /*
486 * We really want to extract the file.
487 */
488 if (verboseFlag)
489 printf ("x %s\n", name);
490
491 if (hardLink) {
492 if (link (hp->linkName, name) < 0)
493 perror (name);
494
495 return;
496 }
497
498 if (softLink) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000499#ifdef S_ISLNK
Eric Andersen3cf52d11999-10-12 22:26:06 +0000500 if (symlink (hp->linkName, name) < 0)
501 perror (name);
Eric Andersencc8ed391999-10-05 16:24:54 +0000502#else
Eric Andersen3cf52d11999-10-12 22:26:06 +0000503 fprintf (stderr, "Cannot create symbolic links\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000504#endif
Eric Andersen3cf52d11999-10-12 22:26:06 +0000505 return;
506 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000507
Eric Andersen3cf52d11999-10-12 22:26:06 +0000508 /*
509 * If the file is a directory, then just create the path.
510 */
511 if (S_ISDIR (mode)) {
512 createPath (name, mode);
Eric Andersencc8ed391999-10-05 16:24:54 +0000513
Eric Andersen3cf52d11999-10-12 22:26:06 +0000514 return;
515 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000516
Eric Andersen3cf52d11999-10-12 22:26:06 +0000517 /*
518 * There is a file to write.
519 * First create the path to it if necessary with a default permission.
520 */
521 createPath (name, 0777);
Eric Andersencc8ed391999-10-05 16:24:54 +0000522
Eric Andersen3cf52d11999-10-12 22:26:06 +0000523 inHeader = (size == 0);
524 dataCc = size;
Eric Andersencc8ed391999-10-05 16:24:54 +0000525
Eric Andersen3cf52d11999-10-12 22:26:06 +0000526 /*
527 * Start the output file.
528 */
529 if (tostdoutFlag == TRUE)
530 outFd = STDOUT;
531 else
532 outFd = open (name, O_WRONLY | O_CREAT | O_TRUNC, mode);
Eric Andersencc8ed391999-10-05 16:24:54 +0000533
Eric Andersen3cf52d11999-10-12 22:26:06 +0000534 if (outFd < 0) {
535 perror (name);
536 skipFileFlag = TRUE;
537 return;
538 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000539
Eric Andersen3cf52d11999-10-12 22:26:06 +0000540 /*
541 * If the file is empty, then that's all we need to do.
542 */
543 if (size == 0 && tostdoutFlag == FALSE) {
544 (void) close (outFd);
545 outFd = -1;
546 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000547}
548
549
550/*
551 * Handle a data block of some specified size that was read.
552 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000553static void readData (const char *cp, int count)
Eric Andersencc8ed391999-10-05 16:24:54 +0000554{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000555 /*
556 * Reduce the amount of data left in this file.
557 * If there is no more data left, then we need to read
558 * the header again.
559 */
560 dataCc -= count;
Eric Andersencc8ed391999-10-05 16:24:54 +0000561
Eric Andersen3cf52d11999-10-12 22:26:06 +0000562 if (dataCc <= 0)
563 inHeader = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000564
Eric Andersen3cf52d11999-10-12 22:26:06 +0000565 /*
566 * If we aren't extracting files or this file is being
567 * skipped then do nothing more.
568 */
569 if (!extractFlag || skipFileFlag)
570 return;
Eric Andersencc8ed391999-10-05 16:24:54 +0000571
Eric Andersen3cf52d11999-10-12 22:26:06 +0000572 /*
573 * Write the data to the output file.
574 */
575 if (fullWrite (outFd, cp, count) < 0) {
576 perror (outName);
577 if (tostdoutFlag == FALSE) {
578 (void) close (outFd);
579 outFd = -1;
Eric Andersencc8ed391999-10-05 16:24:54 +0000580 }
Eric Andersen3cf52d11999-10-12 22:26:06 +0000581 skipFileFlag = TRUE;
582 return;
583 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000584
Eric Andersen3cf52d11999-10-12 22:26:06 +0000585 /*
586 * If the write failed, close the file and disable further
587 * writes to this file.
588 */
589 if (dataCc <= 0 && tostdoutFlag == FALSE) {
590 if (close (outFd))
591 perror (outName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000592
Eric Andersen3cf52d11999-10-12 22:26:06 +0000593 outFd = -1;
594 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000595}
596
597
598/*
599 * Write a tar file containing the specified files.
600 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000601static void writeTarFile (int fileCount, char **fileTable)
Eric Andersencc8ed391999-10-05 16:24:54 +0000602{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000603 struct stat statbuf;
Eric Andersencc8ed391999-10-05 16:24:54 +0000604
Eric Andersen3cf52d11999-10-12 22:26:06 +0000605 /*
606 * Make sure there is at least one file specified.
607 */
608 if (fileCount <= 0) {
609 fprintf (stderr, "No files specified to be saved\n");
610 errorFlag = TRUE;
611 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000612
Eric Andersen3cf52d11999-10-12 22:26:06 +0000613 /*
614 * Create the tar file for writing.
615 */
616 if ((tarName == NULL) || !strcmp (tarName, "-")) {
617 tostdoutFlag = TRUE;
618 tarFd = STDOUT;
619 } else
620 tarFd = open (tarName, O_WRONLY | O_CREAT | O_TRUNC, 0666);
Eric Andersencc8ed391999-10-05 16:24:54 +0000621
Eric Andersen3cf52d11999-10-12 22:26:06 +0000622 if (tarFd < 0) {
623 perror (tarName);
624 errorFlag = TRUE;
625 return;
626 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000627
Eric Andersen3cf52d11999-10-12 22:26:06 +0000628 /*
629 * Get the device and inode of the tar file for checking later.
630 */
631 if (fstat (tarFd, &statbuf) < 0) {
632 perror (tarName);
633 errorFlag = TRUE;
634 goto done;
635 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000636
Eric Andersen3cf52d11999-10-12 22:26:06 +0000637 tarDev = statbuf.st_dev;
638 tarInode = statbuf.st_ino;
Eric Andersencc8ed391999-10-05 16:24:54 +0000639
Eric Andersen3cf52d11999-10-12 22:26:06 +0000640 /*
641 * Append each file name into the archive file.
642 * Follow symbolic links for these top level file names.
643 */
644 while (!errorFlag && (fileCount-- > 0)) {
645 saveFile (*fileTable++, FALSE);
646 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000647
Eric Andersen3cf52d11999-10-12 22:26:06 +0000648 /*
649 * Now write an empty block of zeroes to end the archive.
650 */
651 writeTarBlock ("", 1);
Eric Andersencc8ed391999-10-05 16:24:54 +0000652
653
Eric Andersen3cf52d11999-10-12 22:26:06 +0000654 done:
655 /*
656 * Close the tar file and check for errors if it was opened.
657 */
658 if ((tostdoutFlag == FALSE) && (tarFd >= 0) && (close (tarFd) < 0))
659 perror (tarName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000660}
661
662
663/*
664 * Save one file into the tar file.
665 * If the file is a directory, then this will recursively save all of
666 * the files and directories within the directory. The seeLinks
667 * flag indicates whether or not we want to see symbolic links as
668 * they really are, instead of blindly following them.
669 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000670static void saveFile (const char *fileName, int seeLinks)
Eric Andersencc8ed391999-10-05 16:24:54 +0000671{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000672 int status;
673 int mode;
674 struct stat statbuf;
Eric Andersencc8ed391999-10-05 16:24:54 +0000675
Eric Andersen3cf52d11999-10-12 22:26:06 +0000676 if (verboseFlag)
677 printf ("a %s\n", fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000678
Eric Andersen3cf52d11999-10-12 22:26:06 +0000679 /*
680 * Check that the file name will fit in the header.
681 */
682 if (strlen (fileName) >= TAR_NAME_SIZE) {
683 fprintf (stderr, "%s: File name is too long\n", fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000684
Eric Andersen3cf52d11999-10-12 22:26:06 +0000685 return;
686 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000687
Eric Andersen3cf52d11999-10-12 22:26:06 +0000688 /*
689 * Find out about the file.
690 */
Eric Andersencc8ed391999-10-05 16:24:54 +0000691#ifdef S_ISLNK
Eric Andersen3cf52d11999-10-12 22:26:06 +0000692 if (seeLinks)
693 status = lstat (fileName, &statbuf);
694 else
Eric Andersencc8ed391999-10-05 16:24:54 +0000695#endif
Eric Andersen3cf52d11999-10-12 22:26:06 +0000696 status = stat (fileName, &statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000697
Eric Andersen3cf52d11999-10-12 22:26:06 +0000698 if (status < 0) {
699 perror (fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000700
Eric Andersen3cf52d11999-10-12 22:26:06 +0000701 return;
702 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000703
Eric Andersen3cf52d11999-10-12 22:26:06 +0000704 /*
705 * Make sure we aren't trying to save our file into itself.
706 */
707 if ((statbuf.st_dev == tarDev) && (statbuf.st_ino == tarInode)) {
708 fprintf (stderr, "Skipping saving of archive file itself\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000709
Eric Andersen3cf52d11999-10-12 22:26:06 +0000710 return;
711 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000712
Eric Andersen3cf52d11999-10-12 22:26:06 +0000713 /*
714 * Check the type of file.
715 */
716 mode = statbuf.st_mode;
Eric Andersencc8ed391999-10-05 16:24:54 +0000717
Eric Andersen3cf52d11999-10-12 22:26:06 +0000718 if (S_ISDIR (mode)) {
719 saveDirectory (fileName, &statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000720
Eric Andersen3cf52d11999-10-12 22:26:06 +0000721 return;
722 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000723
Eric Andersen3cf52d11999-10-12 22:26:06 +0000724 if (S_ISREG (mode)) {
725 saveRegularFile (fileName, &statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000726
Eric Andersen3cf52d11999-10-12 22:26:06 +0000727 return;
728 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000729
Eric Andersen3cf52d11999-10-12 22:26:06 +0000730 /*
731 * The file is a strange type of file, ignore it.
732 */
733 fprintf (stderr, "%s: not a directory or regular file\n", fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000734}
735
736
737/*
738 * Save a regular file to the tar file.
739 */
740static void
Eric Andersen3cf52d11999-10-12 22:26:06 +0000741saveRegularFile (const char *fileName, const struct stat *statbuf)
Eric Andersencc8ed391999-10-05 16:24:54 +0000742{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000743 int sawEof;
744 int fileFd;
745 int cc;
746 int dataCount;
747 long fullDataCount;
748 char data[TAR_BLOCK_SIZE * 16];
Eric Andersencc8ed391999-10-05 16:24:54 +0000749
Eric Andersen3cf52d11999-10-12 22:26:06 +0000750 /*
751 * Open the file for reading.
752 */
753 fileFd = open (fileName, O_RDONLY);
754
755 if (fileFd < 0) {
756 perror (fileName);
757
758 return;
759 }
760
761 /*
762 * Write out the header for the file.
763 */
764 writeHeader (fileName, statbuf);
765
766 /*
767 * Write the data blocks of the file.
768 * We must be careful to write the amount of data that the stat
769 * buffer indicated, even if the file has changed size. Otherwise
770 * the tar file will be incorrect.
771 */
772 fullDataCount = statbuf->st_size;
773 sawEof = FALSE;
774
775 while (fullDataCount > 0) {
776 /*
777 * Get the amount to write this iteration which is
778 * the minumum of the amount left to write and the
779 * buffer size.
Eric Andersencc8ed391999-10-05 16:24:54 +0000780 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000781 dataCount = sizeof (data);
Eric Andersencc8ed391999-10-05 16:24:54 +0000782
Eric Andersen3cf52d11999-10-12 22:26:06 +0000783 if (dataCount > fullDataCount)
784 dataCount = (int) fullDataCount;
785
786 /*
787 * Read the data from the file if we haven't seen the
788 * end of file yet.
789 */
790 cc = 0;
791
792 if (!sawEof) {
793 cc = fullRead (fileFd, data, dataCount);
794
795 if (cc < 0) {
796 perror (fileName);
797
798 (void) close (fileFd);
799 errorFlag = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000800
801 return;
Eric Andersen3cf52d11999-10-12 22:26:06 +0000802 }
803
804 /*
805 * If the file ended too soon, complain and set
806 * a flag so we will zero fill the rest of it.
807 */
808 if (cc < dataCount) {
809 fprintf (stderr,
810 "%s: Short read - zero filling", fileName);
811
812 sawEof = TRUE;
813 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000814 }
815
Eric Andersen3cf52d11999-10-12 22:26:06 +0000816 /*
817 * Zero fill the rest of the data if necessary.
Eric Andersencc8ed391999-10-05 16:24:54 +0000818 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000819 if (cc < dataCount)
820 memset (data + cc, 0, dataCount - cc);
Eric Andersencc8ed391999-10-05 16:24:54 +0000821
Eric Andersen3cf52d11999-10-12 22:26:06 +0000822 /*
823 * Write the buffer to the TAR file.
Eric Andersencc8ed391999-10-05 16:24:54 +0000824 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000825 writeTarBlock (data, dataCount);
Eric Andersencc8ed391999-10-05 16:24:54 +0000826
Eric Andersen3cf52d11999-10-12 22:26:06 +0000827 fullDataCount -= dataCount;
828 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000829
Eric Andersen3cf52d11999-10-12 22:26:06 +0000830 /*
831 * Close the file.
832 */
833 if ((tostdoutFlag == FALSE) && close (fileFd) < 0)
834 fprintf (stderr, "%s: close: %s\n", fileName, strerror (errno));
Eric Andersencc8ed391999-10-05 16:24:54 +0000835}
836
837
838/*
839 * Save a directory and all of its files to the tar file.
840 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000841static void saveDirectory (const char *dirName, const struct stat *statbuf)
Eric Andersencc8ed391999-10-05 16:24:54 +0000842{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000843 DIR *dir;
844 struct dirent *entry;
845 int needSlash;
Eric Andersen1b61f411999-10-13 18:56:42 +0000846 char fullName[NAME_MAX];
Eric Andersencc8ed391999-10-05 16:24:54 +0000847
Eric Andersen3cf52d11999-10-12 22:26:06 +0000848 /*
849 * Construct the directory name as used in the tar file by appending
850 * a slash character to it.
851 */
852 strcpy (fullName, dirName);
853 strcat (fullName, "/");
Eric Andersencc8ed391999-10-05 16:24:54 +0000854
Eric Andersen3cf52d11999-10-12 22:26:06 +0000855 /*
856 * Write out the header for the directory entry.
857 */
858 writeHeader (fullName, statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000859
Eric Andersen3cf52d11999-10-12 22:26:06 +0000860 /*
861 * Open the directory.
862 */
863 dir = opendir (dirName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000864
Eric Andersen3cf52d11999-10-12 22:26:06 +0000865 if (dir == NULL) {
866 fprintf (stderr, "Cannot read directory \"%s\": %s\n",
867 dirName, strerror (errno));
Eric Andersencc8ed391999-10-05 16:24:54 +0000868
Eric Andersen3cf52d11999-10-12 22:26:06 +0000869 return;
870 }
871
872 /*
873 * See if a slash is needed.
874 */
875 needSlash = (*dirName && (dirName[strlen (dirName) - 1] != '/'));
876
877 /*
878 * Read all of the directory entries and check them,
879 * except for the current and parent directory entries.
880 */
881 while (!errorFlag && ((entry = readdir (dir)) != NULL)) {
882 if ((strcmp (entry->d_name, ".") == 0) ||
883 (strcmp (entry->d_name, "..") == 0)) {
884 continue;
Eric Andersencc8ed391999-10-05 16:24:54 +0000885 }
886
Eric Andersen3cf52d11999-10-12 22:26:06 +0000887 /*
888 * Build the full path name to the file.
Eric Andersencc8ed391999-10-05 16:24:54 +0000889 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000890 strcpy (fullName, dirName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000891
Eric Andersen3cf52d11999-10-12 22:26:06 +0000892 if (needSlash)
893 strcat (fullName, "/");
894
895 strcat (fullName, entry->d_name);
896
897 /*
898 * Write this file to the tar file, noticing whether or not
899 * the file is a symbolic link.
Eric Andersencc8ed391999-10-05 16:24:54 +0000900 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000901 saveFile (fullName, TRUE);
902 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000903
Eric Andersen3cf52d11999-10-12 22:26:06 +0000904 /*
905 * All done, close the directory.
906 */
907 closedir (dir);
Eric Andersencc8ed391999-10-05 16:24:54 +0000908}
909
910
911/*
912 * Write a tar header for the specified file name and status.
913 * It is assumed that the file name fits.
914 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000915static void writeHeader (const char *fileName, const struct stat *statbuf)
Eric Andersencc8ed391999-10-05 16:24:54 +0000916{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000917 long checkSum;
918 const unsigned char *cp;
919 int len;
920 TarHeader header;
Eric Andersencc8ed391999-10-05 16:24:54 +0000921
Eric Andersen3cf52d11999-10-12 22:26:06 +0000922 /*
923 * Zero the header block in preparation for filling it in.
924 */
925 memset ((char *) &header, 0, sizeof (header));
Eric Andersencc8ed391999-10-05 16:24:54 +0000926
Eric Andersen3cf52d11999-10-12 22:26:06 +0000927 /*
928 * Fill in the header.
929 */
930 strcpy (header.name, fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000931
Eric Andersen3cf52d11999-10-12 22:26:06 +0000932 strncpy (header.magic, TAR_MAGIC, sizeof (header.magic));
933 strncpy (header.version, TAR_VERSION, sizeof (header.version));
Eric Andersencc8ed391999-10-05 16:24:54 +0000934
Eric Andersen3cf52d11999-10-12 22:26:06 +0000935 putOctal (header.mode, sizeof (header.mode), statbuf->st_mode & 0777);
936 putOctal (header.uid, sizeof (header.uid), statbuf->st_uid);
937 putOctal (header.gid, sizeof (header.gid), statbuf->st_gid);
938 putOctal (header.size, sizeof (header.size), statbuf->st_size);
939 putOctal (header.mtime, sizeof (header.mtime), statbuf->st_mtime);
Eric Andersencc8ed391999-10-05 16:24:54 +0000940
Eric Andersen3cf52d11999-10-12 22:26:06 +0000941 header.typeFlag = TAR_TYPE_REGULAR;
Eric Andersencc8ed391999-10-05 16:24:54 +0000942
Eric Andersen3cf52d11999-10-12 22:26:06 +0000943 /*
944 * Calculate and store the checksum.
945 * This is the sum of all of the bytes of the header,
946 * with the checksum field itself treated as blanks.
947 */
948 memset (header.checkSum, ' ', sizeof (header.checkSum));
Eric Andersencc8ed391999-10-05 16:24:54 +0000949
Eric Andersen3cf52d11999-10-12 22:26:06 +0000950 cp = (const unsigned char *) &header;
951 len = sizeof (header);
952 checkSum = 0;
Eric Andersencc8ed391999-10-05 16:24:54 +0000953
Eric Andersen3cf52d11999-10-12 22:26:06 +0000954 while (len-- > 0)
955 checkSum += *cp++;
Eric Andersencc8ed391999-10-05 16:24:54 +0000956
Eric Andersen3cf52d11999-10-12 22:26:06 +0000957 putOctal (header.checkSum, sizeof (header.checkSum), checkSum);
Eric Andersencc8ed391999-10-05 16:24:54 +0000958
Eric Andersen3cf52d11999-10-12 22:26:06 +0000959 /*
960 * Write the tar header.
961 */
962 writeTarBlock ((const char *) &header, sizeof (header));
Eric Andersencc8ed391999-10-05 16:24:54 +0000963}
964
965
966/*
967 * Write data to one or more blocks of the tar file.
968 * The data is always padded out to a multiple of TAR_BLOCK_SIZE.
969 * The errorFlag static variable is set on an error.
970 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000971static void writeTarBlock (const char *buf, int len)
Eric Andersencc8ed391999-10-05 16:24:54 +0000972{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000973 int partialLength;
974 int completeLength;
975 char fullBlock[TAR_BLOCK_SIZE];
Eric Andersencc8ed391999-10-05 16:24:54 +0000976
Eric Andersen3cf52d11999-10-12 22:26:06 +0000977 /*
978 * If we had a write error before, then do nothing more.
979 */
980 if (errorFlag)
981 return;
Eric Andersencc8ed391999-10-05 16:24:54 +0000982
Eric Andersen3cf52d11999-10-12 22:26:06 +0000983 /*
984 * Get the amount of complete and partial blocks.
985 */
986 partialLength = len % TAR_BLOCK_SIZE;
987 completeLength = len - partialLength;
Eric Andersencc8ed391999-10-05 16:24:54 +0000988
Eric Andersen3cf52d11999-10-12 22:26:06 +0000989 /*
990 * Write all of the complete blocks.
991 */
992 if ((completeLength > 0) && !fullWrite (tarFd, buf, completeLength)) {
993 perror (tarName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000994
Eric Andersen3cf52d11999-10-12 22:26:06 +0000995 errorFlag = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000996
Eric Andersen3cf52d11999-10-12 22:26:06 +0000997 return;
998 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000999
Eric Andersen3cf52d11999-10-12 22:26:06 +00001000 /*
1001 * If there are no partial blocks left, we are done.
1002 */
1003 if (partialLength == 0)
1004 return;
Eric Andersencc8ed391999-10-05 16:24:54 +00001005
Eric Andersen3cf52d11999-10-12 22:26:06 +00001006 /*
1007 * Copy the partial data into a complete block, and pad the rest
1008 * of it with zeroes.
1009 */
1010 memcpy (fullBlock, buf + completeLength, partialLength);
1011 memset (fullBlock + partialLength, 0, TAR_BLOCK_SIZE - partialLength);
Eric Andersencc8ed391999-10-05 16:24:54 +00001012
Eric Andersen3cf52d11999-10-12 22:26:06 +00001013 /*
1014 * Write the last complete block.
1015 */
1016 if (!fullWrite (tarFd, fullBlock, TAR_BLOCK_SIZE)) {
1017 perror (tarName);
Eric Andersencc8ed391999-10-05 16:24:54 +00001018
Eric Andersen3cf52d11999-10-12 22:26:06 +00001019 errorFlag = TRUE;
1020 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001021}
1022
1023
1024/*
Eric Andersencc8ed391999-10-05 16:24:54 +00001025 * Read an octal value in a field of the specified width, with optional
1026 * spaces on both sides of the number and with an optional null character
1027 * at the end. Returns -1 on an illegal format.
1028 */
Eric Andersen3cf52d11999-10-12 22:26:06 +00001029static long getOctal (const char *cp, int len)
Eric Andersencc8ed391999-10-05 16:24:54 +00001030{
Eric Andersen3cf52d11999-10-12 22:26:06 +00001031 long val;
Eric Andersencc8ed391999-10-05 16:24:54 +00001032
Eric Andersen3cf52d11999-10-12 22:26:06 +00001033 while ((len > 0) && (*cp == ' ')) {
1034 cp++;
1035 len--;
1036 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001037
Eric Andersen3cf52d11999-10-12 22:26:06 +00001038 if ((len == 0) || !isOctal (*cp))
1039 return -1;
Eric Andersencc8ed391999-10-05 16:24:54 +00001040
Eric Andersen3cf52d11999-10-12 22:26:06 +00001041 val = 0;
Eric Andersencc8ed391999-10-05 16:24:54 +00001042
Eric Andersen3cf52d11999-10-12 22:26:06 +00001043 while ((len > 0) && isOctal (*cp)) {
1044 val = val * 8 + *cp++ - '0';
1045 len--;
1046 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001047
Eric Andersen3cf52d11999-10-12 22:26:06 +00001048 while ((len > 0) && (*cp == ' ')) {
1049 cp++;
1050 len--;
1051 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001052
Eric Andersen3cf52d11999-10-12 22:26:06 +00001053 if ((len > 0) && *cp)
1054 return -1;
Eric Andersencc8ed391999-10-05 16:24:54 +00001055
Eric Andersen3cf52d11999-10-12 22:26:06 +00001056 return val;
Eric Andersencc8ed391999-10-05 16:24:54 +00001057}
1058
1059
1060/*
1061 * Put an octal string into the specified buffer.
1062 * The number is zero and space padded and possibly null padded.
1063 * Returns TRUE if successful.
1064 */
Eric Andersen3cf52d11999-10-12 22:26:06 +00001065static int putOctal (char *cp, int len, long value)
Eric Andersencc8ed391999-10-05 16:24:54 +00001066{
Eric Andersen3cf52d11999-10-12 22:26:06 +00001067 int tempLength;
1068 char *tempString;
1069 char tempBuffer[32];
Eric Andersencc8ed391999-10-05 16:24:54 +00001070
Eric Andersen3cf52d11999-10-12 22:26:06 +00001071 /*
1072 * Create a string of the specified length with an initial space,
1073 * leading zeroes and the octal number, and a trailing null.
1074 */
1075 tempString = tempBuffer;
Eric Andersencc8ed391999-10-05 16:24:54 +00001076
Eric Andersen3cf52d11999-10-12 22:26:06 +00001077 sprintf (tempString, " %0*lo", len - 2, value);
Eric Andersencc8ed391999-10-05 16:24:54 +00001078
Eric Andersen3cf52d11999-10-12 22:26:06 +00001079 tempLength = strlen (tempString) + 1;
Eric Andersencc8ed391999-10-05 16:24:54 +00001080
Eric Andersen3cf52d11999-10-12 22:26:06 +00001081 /*
1082 * If the string is too large, suppress the leading space.
1083 */
1084 if (tempLength > len) {
1085 tempLength--;
1086 tempString++;
1087 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001088
Eric Andersen3cf52d11999-10-12 22:26:06 +00001089 /*
1090 * If the string is still too large, suppress the trailing null.
1091 */
1092 if (tempLength > len)
1093 tempLength--;
Eric Andersencc8ed391999-10-05 16:24:54 +00001094
Eric Andersen3cf52d11999-10-12 22:26:06 +00001095 /*
1096 * If the string is still too large, fail.
1097 */
1098 if (tempLength > len)
1099 return FALSE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001100
Eric Andersen3cf52d11999-10-12 22:26:06 +00001101 /*
1102 * Copy the string to the field.
1103 */
1104 memcpy (cp, tempString, len);
Eric Andersencc8ed391999-10-05 16:24:54 +00001105
Eric Andersen3cf52d11999-10-12 22:26:06 +00001106 return TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001107}
1108
1109
1110/*
1111 * See if the specified file name belongs to one of the specified list
1112 * of path prefixes. An empty list implies that all files are wanted.
1113 * Returns TRUE if the file is selected.
1114 */
Eric Andersenf811e071999-10-09 00:25:00 +00001115static int
Eric Andersen3cf52d11999-10-12 22:26:06 +00001116wantFileName (const char *fileName, int fileCount, char **fileTable)
Eric Andersencc8ed391999-10-05 16:24:54 +00001117{
Eric Andersen3cf52d11999-10-12 22:26:06 +00001118 const char *pathName;
1119 int fileLength;
1120 int pathLength;
Eric Andersencc8ed391999-10-05 16:24:54 +00001121
Eric Andersen3cf52d11999-10-12 22:26:06 +00001122 /*
1123 * If there are no files in the list, then the file is wanted.
1124 */
1125 if (fileCount == 0)
1126 return TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001127
Eric Andersen3cf52d11999-10-12 22:26:06 +00001128 fileLength = strlen (fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +00001129
Eric Andersen3cf52d11999-10-12 22:26:06 +00001130 /*
1131 * Check each of the test paths.
1132 */
1133 while (fileCount-- > 0) {
1134 pathName = *fileTable++;
Eric Andersencc8ed391999-10-05 16:24:54 +00001135
Eric Andersen3cf52d11999-10-12 22:26:06 +00001136 pathLength = strlen (pathName);
Eric Andersencc8ed391999-10-05 16:24:54 +00001137
Eric Andersen3cf52d11999-10-12 22:26:06 +00001138 if (fileLength < pathLength)
1139 continue;
Eric Andersencc8ed391999-10-05 16:24:54 +00001140
Eric Andersen3cf52d11999-10-12 22:26:06 +00001141 if (memcmp (fileName, pathName, pathLength) != 0)
1142 continue;
Eric Andersencc8ed391999-10-05 16:24:54 +00001143
Eric Andersen3cf52d11999-10-12 22:26:06 +00001144 if ((fileLength == pathLength) || (fileName[pathLength] == '/')) {
1145 return TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001146 }
Eric Andersen3cf52d11999-10-12 22:26:06 +00001147 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001148
Eric Andersen3cf52d11999-10-12 22:26:06 +00001149 return FALSE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001150}
1151
1152
1153
Eric Andersencc8ed391999-10-05 16:24:54 +00001154#endif
1155/* END CODE */