blob: cd255f85cee36dfb609e4581a4c997e341265ad8 [file] [log] [blame]
Eric Andersencc8ed391999-10-05 16:24:54 +00001/*
Eric Andersenc4996011999-10-20 22:08:37 +00002 * Mini tar implementation for busybox based on code taken from sash.
3 *
Eric Andersencc8ed391999-10-05 16:24:54 +00004 * Copyright (c) 1999 by David I. Bell
5 * Permission is granted to use, distribute, or modify this source,
6 * provided that this copyright notice remains intact.
7 *
Eric Andersencc8ed391999-10-05 16:24:54 +00008 * Permission to distribute this code under the GPL has been granted.
Eric Andersenc4996011999-10-20 22:08:37 +00009 *
Eric Andersen3cf52d11999-10-12 22:26:06 +000010 * Modified for busybox by Erik Andersen <andersee@debian.org>
Eric Andersenc4996011999-10-20 22:08:37 +000011 * Adjusted to grok stdin/stdout options.
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 *
Eric Andersencc8ed391999-10-05 16:24:54 +000027 */
28
29
30#include "internal.h"
Eric Andersencc8ed391999-10-05 16:24:54 +000031#include <stdio.h>
32#include <dirent.h>
33#include <errno.h>
34#include <fcntl.h>
35#include <signal.h>
36#include <time.h>
37
Eric Andersene77ae3a1999-10-19 20:03:34 +000038
39static const char tar_usage[] =
Eric Andersenbe971d61999-11-03 16:52:50 +000040 "tar -[cxtvOf] [tarFileName] [FILE] ...\n"
41 "Create, extract, or list files from a tar file\n\n"
Eric Andersene77ae3a1999-10-19 20:03:34 +000042 "\tc=create, x=extract, t=list contents, v=verbose,\n"
43 "\tO=extract to stdout, f=tarfile or \"-\" for stdin\n";
44
45
46
Eric Andersencc8ed391999-10-05 16:24:54 +000047/*
48 * Tar file constants.
49 */
50#define TAR_BLOCK_SIZE 512
51#define TAR_NAME_SIZE 100
52
53
54/*
55 * The POSIX (and basic GNU) tar header format.
56 * This structure is always embedded in a TAR_BLOCK_SIZE sized block
57 * with zero padding. We only process this information minimally.
58 */
Eric Andersen3cf52d11999-10-12 22:26:06 +000059typedef struct {
60 char name[TAR_NAME_SIZE];
61 char mode[8];
62 char uid[8];
63 char gid[8];
64 char size[12];
65 char mtime[12];
66 char checkSum[8];
67 char typeFlag;
68 char linkName[TAR_NAME_SIZE];
69 char magic[6];
70 char version[2];
71 char uname[32];
72 char gname[32];
73 char devMajor[8];
74 char devMinor[8];
75 char prefix[155];
Eric Andersencc8ed391999-10-05 16:24:54 +000076} TarHeader;
77
78#define TAR_MAGIC "ustar"
79#define TAR_VERSION "00"
80
81#define TAR_TYPE_REGULAR '0'
82#define TAR_TYPE_HARD_LINK '1'
83#define TAR_TYPE_SOFT_LINK '2'
84
85
86/*
87 * Static data.
88 */
Eric Andersen3cf52d11999-10-12 22:26:06 +000089static int listFlag;
90static int extractFlag;
91static int createFlag;
92static int verboseFlag;
93static int tostdoutFlag;
Eric Andersencc8ed391999-10-05 16:24:54 +000094
Eric Andersen3cf52d11999-10-12 22:26:06 +000095static int inHeader;
96static int badHeader;
97static int errorFlag;
98static int skipFileFlag;
99static int warnedRoot;
100static int eofFlag;
101static long dataCc;
102static int outFd;
103static char outName[TAR_NAME_SIZE];
Eric Andersencc8ed391999-10-05 16:24:54 +0000104
105
106/*
107 * Static data associated with the tar file.
108 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000109static const char *tarName;
110static int tarFd;
111static dev_t tarDev;
112static ino_t tarInode;
Eric Andersencc8ed391999-10-05 16:24:54 +0000113
114
115/*
116 * Local procedures to restore files from a tar file.
117 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000118static void readTarFile (int fileCount, char **fileTable);
119static void readData (const char *cp, int count);
Eric Andersen3cf52d11999-10-12 22:26:06 +0000120static long getOctal (const char *cp, int len);
Eric Andersencc8ed391999-10-05 16:24:54 +0000121
Eric Andersen3cf52d11999-10-12 22:26:06 +0000122static void readHeader (const TarHeader * hp,
123 int fileCount, char **fileTable);
Eric Andersencc8ed391999-10-05 16:24:54 +0000124
125
126/*
127 * Local procedures to save files into a tar file.
128 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000129static void saveFile (const char *fileName, int seeLinks);
Eric Andersencc8ed391999-10-05 16:24:54 +0000130
Eric Andersen3cf52d11999-10-12 22:26:06 +0000131static void saveRegularFile (const char *fileName,
132 const struct stat *statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000133
Eric Andersen3cf52d11999-10-12 22:26:06 +0000134static void saveDirectory (const char *fileName,
135 const struct stat *statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000136
Eric Andersen3cf52d11999-10-12 22:26:06 +0000137static int wantFileName (const char *fileName,
138 int fileCount, char **fileTable);
Eric Andersencc8ed391999-10-05 16:24:54 +0000139
Eric Andersen3cf52d11999-10-12 22:26:06 +0000140static void writeHeader (const char *fileName, const struct stat *statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000141
Eric Andersen3cf52d11999-10-12 22:26:06 +0000142static void writeTarFile (int fileCount, char **fileTable);
143static void writeTarBlock (const char *buf, int len);
144static int putOctal (char *cp, int len, long value);
Eric Andersencc8ed391999-10-05 16:24:54 +0000145
146
Eric Andersen3cf52d11999-10-12 22:26:06 +0000147extern int tar_main (int argc, char **argv)
Eric Andersencc8ed391999-10-05 16:24:54 +0000148{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000149 const char *options;
Eric Andersencc8ed391999-10-05 16:24:54 +0000150
Eric Andersen3cf52d11999-10-12 22:26:06 +0000151 argc--;
152 argv++;
Eric Andersencc8ed391999-10-05 16:24:54 +0000153
Eric Andersenbe971d61999-11-03 16:52:50 +0000154 if (argc < 1)
155 usage( tar_usage);
Eric Andersencc8ed391999-10-05 16:24:54 +0000156
157
Eric Andersen3cf52d11999-10-12 22:26:06 +0000158 errorFlag = FALSE;
159 extractFlag = FALSE;
160 createFlag = FALSE;
161 listFlag = FALSE;
162 verboseFlag = FALSE;
163 tostdoutFlag = FALSE;
164 tarName = NULL;
165 tarDev = 0;
166 tarInode = 0;
167 tarFd = -1;
Eric Andersencc8ed391999-10-05 16:24:54 +0000168
Eric Andersen3cf52d11999-10-12 22:26:06 +0000169 /*
170 * Parse the options.
171 */
172 options = *argv++;
173 argc--;
Eric Andersencc8ed391999-10-05 16:24:54 +0000174
Eric Andersen3cf52d11999-10-12 22:26:06 +0000175 if (**argv == '-') {
176 for (; *options; options++) {
177 switch (*options) {
178 case 'f':
179 if (tarName != NULL) {
180 fprintf (stderr, "Only one 'f' option allowed\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000181
Eric Andersen3cf52d11999-10-12 22:26:06 +0000182 exit (FALSE);
Eric Andersencc8ed391999-10-05 16:24:54 +0000183 }
Eric Andersen3cf52d11999-10-12 22:26:06 +0000184
185 tarName = *argv++;
186 argc--;
187
188 break;
189
190 case 't':
191 listFlag = TRUE;
192 break;
193
194 case 'x':
195 extractFlag = TRUE;
196 break;
197
198 case 'c':
199 createFlag = TRUE;
200 break;
201
202 case 'v':
203 verboseFlag = TRUE;
204 break;
205
206 case 'O':
207 tostdoutFlag = TRUE;
208 break;
209
210 case '-':
211 break;
212
213 default:
214 fprintf (stderr, "Unknown tar flag '%c'\n", *options);
215
216 exit (FALSE);
217 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000218 }
Eric Andersen3cf52d11999-10-12 22:26:06 +0000219 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000220
Eric Andersen3cf52d11999-10-12 22:26:06 +0000221 /*
222 * Validate the options.
223 */
224 if (extractFlag + listFlag + createFlag != 1) {
225 fprintf (stderr,
226 "Exactly one of 'c', 'x' or 't' must be specified\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000227
Eric Andersen3cf52d11999-10-12 22:26:06 +0000228 exit (FALSE);
229 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000230
Eric Andersen3cf52d11999-10-12 22:26:06 +0000231 /*
232 * Do the correct type of action supplying the rest of the
233 * command line arguments as the list of files to process.
234 */
235 if (createFlag)
236 writeTarFile (argc, argv);
237 else
238 readTarFile (argc, argv);
239 if (errorFlag)
240 fprintf (stderr, "\n");
241 exit (errorFlag);
Eric Andersencc8ed391999-10-05 16:24:54 +0000242}
243
244
245/*
246 * Read a tar file and extract or list the specified files within it.
247 * If the list is empty than all files are extracted or listed.
248 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000249static void readTarFile (int fileCount, char **fileTable)
Eric Andersencc8ed391999-10-05 16:24:54 +0000250{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000251 const char *cp;
252 int cc;
253 int inCc;
254 int blockSize;
255 char buf[BUF_SIZE];
Eric Andersencc8ed391999-10-05 16:24:54 +0000256
Eric Andersen3cf52d11999-10-12 22:26:06 +0000257 skipFileFlag = FALSE;
258 badHeader = FALSE;
259 warnedRoot = FALSE;
260 eofFlag = FALSE;
261 inHeader = TRUE;
262 inCc = 0;
263 dataCc = 0;
264 outFd = -1;
265 blockSize = sizeof (buf);
266 cp = buf;
Eric Andersencc8ed391999-10-05 16:24:54 +0000267
Eric Andersen3cf52d11999-10-12 22:26:06 +0000268 /*
269 * Open the tar file for reading.
270 */
271 if ((tarName == NULL) || !strcmp (tarName, "-")) {
272 tarFd = STDIN;
273 } else
274 tarFd = open (tarName, O_RDONLY);
275
276 if (tarFd < 0) {
277 perror (tarName);
278 errorFlag = TRUE;
279 return;
280 }
281
282 /*
283 * Read blocks from the file until an end of file header block
284 * has been seen. (A real end of file from a read is an error.)
285 */
286 while (!eofFlag) {
287 /*
288 * Read the next block of data if necessary.
289 * This will be a large block if possible, which we will
290 * then process in the small tar blocks.
Eric Andersencc8ed391999-10-05 16:24:54 +0000291 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000292 if (inCc <= 0) {
293 cp = buf;
294 inCc = fullRead (tarFd, buf, blockSize);
Eric Andersencc8ed391999-10-05 16:24:54 +0000295
Eric Andersen3cf52d11999-10-12 22:26:06 +0000296 if (inCc < 0) {
297 perror (tarName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000298 errorFlag = TRUE;
Eric Andersen3cf52d11999-10-12 22:26:06 +0000299 goto done;
300 }
301
302 if (inCc == 0) {
303 fprintf (stderr,
304 "Unexpected end of file from \"%s\"", tarName);
305 errorFlag = TRUE;
306 goto done;
307 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000308 }
309
Eric Andersen3cf52d11999-10-12 22:26:06 +0000310 /*
311 * If we are expecting a header block then examine it.
Eric Andersencc8ed391999-10-05 16:24:54 +0000312 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000313 if (inHeader) {
314 readHeader ((const TarHeader *) cp, fileCount, fileTable);
Eric Andersencc8ed391999-10-05 16:24:54 +0000315
Eric Andersen3cf52d11999-10-12 22:26:06 +0000316 cp += TAR_BLOCK_SIZE;
317 inCc -= TAR_BLOCK_SIZE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000318
Eric Andersen3cf52d11999-10-12 22:26:06 +0000319 continue;
Eric Andersencc8ed391999-10-05 16:24:54 +0000320 }
321
Eric Andersen3cf52d11999-10-12 22:26:06 +0000322 /*
323 * We are currently handling the data for a file.
324 * Process the minimum of the amount of data we have available
325 * and the amount left to be processed for the file.
Eric Andersencc8ed391999-10-05 16:24:54 +0000326 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000327 cc = inCc;
Eric Andersencc8ed391999-10-05 16:24:54 +0000328
Eric Andersen3cf52d11999-10-12 22:26:06 +0000329 if (cc > dataCc)
330 cc = dataCc;
331
332 readData (cp, cc);
333
334 /*
335 * If the amount left isn't an exact multiple of the tar block
336 * size then round it up to the next block boundary since there
337 * is padding at the end of the file.
Eric Andersencc8ed391999-10-05 16:24:54 +0000338 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000339 if (cc % TAR_BLOCK_SIZE)
340 cc += TAR_BLOCK_SIZE - (cc % TAR_BLOCK_SIZE);
341
342 cp += cc;
343 inCc -= cc;
344 }
345
346 done:
347 /*
348 * Close the tar file if needed.
349 */
350 if ((tarFd >= 0) && (close (tarFd) < 0))
351 perror (tarName);
352
353 /*
354 * Close the output file if needed.
355 * This is only done here on a previous error and so no
356 * message is required on errors.
357 */
358 if (tostdoutFlag == FALSE) {
359 if (outFd >= 0)
360 (void) close (outFd);
361 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000362}
363
364
365/*
366 * Examine the header block that was just read.
367 * This can specify the information for another file, or it can mark
368 * the end of the tar file.
369 */
370static void
Eric Andersen3cf52d11999-10-12 22:26:06 +0000371readHeader (const TarHeader * hp, int fileCount, char **fileTable)
Eric Andersencc8ed391999-10-05 16:24:54 +0000372{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000373 int mode;
374 int uid;
375 int gid;
376 int checkSum;
377 long size;
378 time_t mtime;
379 const char *name;
380 int cc;
381 int hardLink;
382 int softLink;
Eric Andersencc8ed391999-10-05 16:24:54 +0000383
Eric Andersen3cf52d11999-10-12 22:26:06 +0000384 /*
385 * If the block is completely empty, then this is the end of the
386 * archive file. If the name is null, then just skip this header.
387 */
388 name = hp->name;
Eric Andersencc8ed391999-10-05 16:24:54 +0000389
Eric Andersen3cf52d11999-10-12 22:26:06 +0000390 if (*name == '\0') {
391 for (cc = TAR_BLOCK_SIZE; cc > 0; cc--) {
392 if (*name++)
Eric Andersencc8ed391999-10-05 16:24:54 +0000393 return;
394 }
395
Eric Andersen3cf52d11999-10-12 22:26:06 +0000396 eofFlag = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000397
Eric Andersen3cf52d11999-10-12 22:26:06 +0000398 return;
399 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000400
Eric Andersen3cf52d11999-10-12 22:26:06 +0000401 /*
402 * There is another file in the archive to examine.
403 * Extract the encoded information and check it.
404 */
405 mode = getOctal (hp->mode, sizeof (hp->mode));
406 uid = getOctal (hp->uid, sizeof (hp->uid));
407 gid = getOctal (hp->gid, sizeof (hp->gid));
408 size = getOctal (hp->size, sizeof (hp->size));
409 mtime = getOctal (hp->mtime, sizeof (hp->mtime));
410 checkSum = getOctal (hp->checkSum, sizeof (hp->checkSum));
Eric Andersencc8ed391999-10-05 16:24:54 +0000411
Eric Andersen3cf52d11999-10-12 22:26:06 +0000412 if ((mode < 0) || (uid < 0) || (gid < 0) || (size < 0)) {
413 if (!badHeader)
414 fprintf (stderr, "Bad tar header, skipping\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000415
Eric Andersen3cf52d11999-10-12 22:26:06 +0000416 badHeader = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000417
Eric Andersen3cf52d11999-10-12 22:26:06 +0000418 return;
419 }
420
421 badHeader = FALSE;
422 skipFileFlag = FALSE;
423
424 /*
425 * Check for the file modes.
426 */
427 hardLink = ((hp->typeFlag == TAR_TYPE_HARD_LINK) ||
Eric Andersencc8ed391999-10-05 16:24:54 +0000428 (hp->typeFlag == TAR_TYPE_HARD_LINK - '0'));
429
Eric Andersen3cf52d11999-10-12 22:26:06 +0000430 softLink = ((hp->typeFlag == TAR_TYPE_SOFT_LINK) ||
Eric Andersencc8ed391999-10-05 16:24:54 +0000431 (hp->typeFlag == TAR_TYPE_SOFT_LINK - '0'));
432
Eric Andersen3cf52d11999-10-12 22:26:06 +0000433 /*
434 * Check for a directory or a regular file.
435 */
436 if (name[strlen (name) - 1] == '/')
437 mode |= S_IFDIR;
438 else if ((mode & S_IFMT) == 0)
439 mode |= S_IFREG;
Eric Andersencc8ed391999-10-05 16:24:54 +0000440
Eric Andersen3cf52d11999-10-12 22:26:06 +0000441 /*
442 * Check for absolute paths in the file.
443 * If we find any, then warn the user and make them relative.
444 */
445 if (*name == '/') {
446 while (*name == '/')
447 name++;
Eric Andersencc8ed391999-10-05 16:24:54 +0000448
Eric Andersen3cf52d11999-10-12 22:26:06 +0000449 if (!warnedRoot) {
450 fprintf (stderr,
451 "Absolute path detected, removing leading slashes\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000452 }
453
Eric Andersen3cf52d11999-10-12 22:26:06 +0000454 warnedRoot = TRUE;
455 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000456
Eric Andersen3cf52d11999-10-12 22:26:06 +0000457 /*
458 * See if we want this file to be restored.
459 * If not, then set up to skip it.
460 */
461 if (!wantFileName (name, fileCount, fileTable)) {
462 if (!hardLink && !softLink && S_ISREG (mode)) {
463 inHeader = (size == 0);
464 dataCc = size;
Eric Andersencc8ed391999-10-05 16:24:54 +0000465 }
466
Eric Andersen3cf52d11999-10-12 22:26:06 +0000467 skipFileFlag = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000468
Eric Andersen3cf52d11999-10-12 22:26:06 +0000469 return;
470 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000471
Eric Andersen3cf52d11999-10-12 22:26:06 +0000472 /*
473 * This file is to be handled.
474 * If we aren't extracting then just list information about the file.
475 */
476 if (!extractFlag) {
477 if (verboseFlag) {
478 printf ("%s %3d/%-d %9ld %s %s", modeString (mode),
479 uid, gid, size, timeString (mtime), name);
480 } else
481 printf ("%s", name);
Eric Andersencc8ed391999-10-05 16:24:54 +0000482
483 if (hardLink)
Eric Andersen3cf52d11999-10-12 22:26:06 +0000484 printf (" (link to \"%s\")", hp->linkName);
485 else if (softLink)
486 printf (" (symlink to \"%s\")", hp->linkName);
487 else if (S_ISREG (mode)) {
488 inHeader = (size == 0);
489 dataCc = size;
Eric Andersencc8ed391999-10-05 16:24:54 +0000490 }
491
Eric Andersen3cf52d11999-10-12 22:26:06 +0000492 printf ("\n");
493
494 return;
495 }
496
497 /*
498 * We really want to extract the file.
499 */
500 if (verboseFlag)
501 printf ("x %s\n", name);
502
503 if (hardLink) {
504 if (link (hp->linkName, name) < 0)
505 perror (name);
506
507 return;
508 }
509
510 if (softLink) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000511#ifdef S_ISLNK
Eric Andersen3cf52d11999-10-12 22:26:06 +0000512 if (symlink (hp->linkName, name) < 0)
513 perror (name);
Eric Andersencc8ed391999-10-05 16:24:54 +0000514#else
Eric Andersen3cf52d11999-10-12 22:26:06 +0000515 fprintf (stderr, "Cannot create symbolic links\n");
Eric Andersencc8ed391999-10-05 16:24:54 +0000516#endif
Eric Andersen3cf52d11999-10-12 22:26:06 +0000517 return;
518 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000519
Eric Andersen3cf52d11999-10-12 22:26:06 +0000520 /*
521 * If the file is a directory, then just create the path.
522 */
523 if (S_ISDIR (mode)) {
524 createPath (name, mode);
Eric Andersencc8ed391999-10-05 16:24:54 +0000525
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 * There is a file to write.
531 * First create the path to it if necessary with a default permission.
532 */
533 createPath (name, 0777);
Eric Andersencc8ed391999-10-05 16:24:54 +0000534
Eric Andersen3cf52d11999-10-12 22:26:06 +0000535 inHeader = (size == 0);
536 dataCc = size;
Eric Andersencc8ed391999-10-05 16:24:54 +0000537
Eric Andersen3cf52d11999-10-12 22:26:06 +0000538 /*
539 * Start the output file.
540 */
541 if (tostdoutFlag == TRUE)
542 outFd = STDOUT;
543 else
544 outFd = open (name, O_WRONLY | O_CREAT | O_TRUNC, mode);
Eric Andersencc8ed391999-10-05 16:24:54 +0000545
Eric Andersen3cf52d11999-10-12 22:26:06 +0000546 if (outFd < 0) {
547 perror (name);
548 skipFileFlag = TRUE;
549 return;
550 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000551
Eric Andersen3cf52d11999-10-12 22:26:06 +0000552 /*
553 * If the file is empty, then that's all we need to do.
554 */
555 if (size == 0 && tostdoutFlag == FALSE) {
556 (void) close (outFd);
557 outFd = -1;
558 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000559}
560
561
562/*
563 * Handle a data block of some specified size that was read.
564 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000565static void readData (const char *cp, int count)
Eric Andersencc8ed391999-10-05 16:24:54 +0000566{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000567 /*
568 * Reduce the amount of data left in this file.
569 * If there is no more data left, then we need to read
570 * the header again.
571 */
572 dataCc -= count;
Eric Andersencc8ed391999-10-05 16:24:54 +0000573
Eric Andersen3cf52d11999-10-12 22:26:06 +0000574 if (dataCc <= 0)
575 inHeader = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000576
Eric Andersen3cf52d11999-10-12 22:26:06 +0000577 /*
578 * If we aren't extracting files or this file is being
579 * skipped then do nothing more.
580 */
581 if (!extractFlag || skipFileFlag)
582 return;
Eric Andersencc8ed391999-10-05 16:24:54 +0000583
Eric Andersen3cf52d11999-10-12 22:26:06 +0000584 /*
585 * Write the data to the output file.
586 */
587 if (fullWrite (outFd, cp, count) < 0) {
588 perror (outName);
589 if (tostdoutFlag == FALSE) {
590 (void) close (outFd);
591 outFd = -1;
Eric Andersencc8ed391999-10-05 16:24:54 +0000592 }
Eric Andersen3cf52d11999-10-12 22:26:06 +0000593 skipFileFlag = TRUE;
594 return;
595 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000596
Eric Andersen3cf52d11999-10-12 22:26:06 +0000597 /*
598 * If the write failed, close the file and disable further
599 * writes to this file.
600 */
601 if (dataCc <= 0 && tostdoutFlag == FALSE) {
602 if (close (outFd))
603 perror (outName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000604
Eric Andersen3cf52d11999-10-12 22:26:06 +0000605 outFd = -1;
606 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000607}
608
609
610/*
611 * Write a tar file containing the specified files.
612 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000613static void writeTarFile (int fileCount, char **fileTable)
Eric Andersencc8ed391999-10-05 16:24:54 +0000614{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000615 struct stat statbuf;
Eric Andersencc8ed391999-10-05 16:24:54 +0000616
Eric Andersen3cf52d11999-10-12 22:26:06 +0000617 /*
618 * Make sure there is at least one file specified.
619 */
620 if (fileCount <= 0) {
621 fprintf (stderr, "No files specified to be saved\n");
622 errorFlag = TRUE;
623 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000624
Eric Andersen3cf52d11999-10-12 22:26:06 +0000625 /*
626 * Create the tar file for writing.
627 */
628 if ((tarName == NULL) || !strcmp (tarName, "-")) {
629 tostdoutFlag = TRUE;
630 tarFd = STDOUT;
631 } else
632 tarFd = open (tarName, O_WRONLY | O_CREAT | O_TRUNC, 0666);
Eric Andersencc8ed391999-10-05 16:24:54 +0000633
Eric Andersen3cf52d11999-10-12 22:26:06 +0000634 if (tarFd < 0) {
635 perror (tarName);
636 errorFlag = TRUE;
637 return;
638 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000639
Eric Andersen3cf52d11999-10-12 22:26:06 +0000640 /*
641 * Get the device and inode of the tar file for checking later.
642 */
643 if (fstat (tarFd, &statbuf) < 0) {
644 perror (tarName);
645 errorFlag = TRUE;
646 goto done;
647 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000648
Eric Andersen3cf52d11999-10-12 22:26:06 +0000649 tarDev = statbuf.st_dev;
650 tarInode = statbuf.st_ino;
Eric Andersencc8ed391999-10-05 16:24:54 +0000651
Eric Andersen3cf52d11999-10-12 22:26:06 +0000652 /*
653 * Append each file name into the archive file.
654 * Follow symbolic links for these top level file names.
655 */
656 while (!errorFlag && (fileCount-- > 0)) {
657 saveFile (*fileTable++, FALSE);
658 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000659
Eric Andersen3cf52d11999-10-12 22:26:06 +0000660 /*
661 * Now write an empty block of zeroes to end the archive.
662 */
663 writeTarBlock ("", 1);
Eric Andersencc8ed391999-10-05 16:24:54 +0000664
665
Eric Andersen3cf52d11999-10-12 22:26:06 +0000666 done:
667 /*
668 * Close the tar file and check for errors if it was opened.
669 */
670 if ((tostdoutFlag == FALSE) && (tarFd >= 0) && (close (tarFd) < 0))
671 perror (tarName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000672}
673
674
675/*
676 * Save one file into the tar file.
677 * If the file is a directory, then this will recursively save all of
678 * the files and directories within the directory. The seeLinks
679 * flag indicates whether or not we want to see symbolic links as
680 * they really are, instead of blindly following them.
681 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000682static void saveFile (const char *fileName, int seeLinks)
Eric Andersencc8ed391999-10-05 16:24:54 +0000683{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000684 int status;
685 int mode;
686 struct stat statbuf;
Eric Andersencc8ed391999-10-05 16:24:54 +0000687
Eric Andersen3cf52d11999-10-12 22:26:06 +0000688 if (verboseFlag)
689 printf ("a %s\n", fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000690
Eric Andersen3cf52d11999-10-12 22:26:06 +0000691 /*
692 * Check that the file name will fit in the header.
693 */
694 if (strlen (fileName) >= TAR_NAME_SIZE) {
695 fprintf (stderr, "%s: File name is too long\n", fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000696
Eric Andersen3cf52d11999-10-12 22:26:06 +0000697 return;
698 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000699
Eric Andersen3cf52d11999-10-12 22:26:06 +0000700 /*
701 * Find out about the file.
702 */
Eric Andersencc8ed391999-10-05 16:24:54 +0000703#ifdef S_ISLNK
Eric Andersen3cf52d11999-10-12 22:26:06 +0000704 if (seeLinks)
705 status = lstat (fileName, &statbuf);
706 else
Eric Andersencc8ed391999-10-05 16:24:54 +0000707#endif
Eric Andersen3cf52d11999-10-12 22:26:06 +0000708 status = stat (fileName, &statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000709
Eric Andersen3cf52d11999-10-12 22:26:06 +0000710 if (status < 0) {
711 perror (fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000712
Eric Andersen3cf52d11999-10-12 22:26:06 +0000713 return;
714 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000715
Eric Andersen3cf52d11999-10-12 22:26:06 +0000716 /*
717 * Make sure we aren't trying to save our file into itself.
718 */
719 if ((statbuf.st_dev == tarDev) && (statbuf.st_ino == tarInode)) {
720 fprintf (stderr, "Skipping saving of archive file itself\n");
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 * Check the type of file.
727 */
728 mode = statbuf.st_mode;
Eric Andersencc8ed391999-10-05 16:24:54 +0000729
Eric Andersen3cf52d11999-10-12 22:26:06 +0000730 if (S_ISDIR (mode)) {
731 saveDirectory (fileName, &statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000732
Eric Andersen3cf52d11999-10-12 22:26:06 +0000733 return;
734 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000735
Eric Andersen3cf52d11999-10-12 22:26:06 +0000736 if (S_ISREG (mode)) {
737 saveRegularFile (fileName, &statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000738
Eric Andersen3cf52d11999-10-12 22:26:06 +0000739 return;
740 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000741
Eric Andersen3cf52d11999-10-12 22:26:06 +0000742 /*
743 * The file is a strange type of file, ignore it.
744 */
745 fprintf (stderr, "%s: not a directory or regular file\n", fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000746}
747
748
749/*
750 * Save a regular file to the tar file.
751 */
752static void
Eric Andersen3cf52d11999-10-12 22:26:06 +0000753saveRegularFile (const char *fileName, const struct stat *statbuf)
Eric Andersencc8ed391999-10-05 16:24:54 +0000754{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000755 int sawEof;
756 int fileFd;
757 int cc;
758 int dataCount;
759 long fullDataCount;
760 char data[TAR_BLOCK_SIZE * 16];
Eric Andersencc8ed391999-10-05 16:24:54 +0000761
Eric Andersen3cf52d11999-10-12 22:26:06 +0000762 /*
763 * Open the file for reading.
764 */
765 fileFd = open (fileName, O_RDONLY);
766
767 if (fileFd < 0) {
768 perror (fileName);
769
770 return;
771 }
772
773 /*
774 * Write out the header for the file.
775 */
776 writeHeader (fileName, statbuf);
777
778 /*
779 * Write the data blocks of the file.
780 * We must be careful to write the amount of data that the stat
781 * buffer indicated, even if the file has changed size. Otherwise
782 * the tar file will be incorrect.
783 */
784 fullDataCount = statbuf->st_size;
785 sawEof = FALSE;
786
787 while (fullDataCount > 0) {
788 /*
789 * Get the amount to write this iteration which is
790 * the minumum of the amount left to write and the
791 * buffer size.
Eric Andersencc8ed391999-10-05 16:24:54 +0000792 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000793 dataCount = sizeof (data);
Eric Andersencc8ed391999-10-05 16:24:54 +0000794
Eric Andersen3cf52d11999-10-12 22:26:06 +0000795 if (dataCount > fullDataCount)
796 dataCount = (int) fullDataCount;
797
798 /*
799 * Read the data from the file if we haven't seen the
800 * end of file yet.
801 */
802 cc = 0;
803
804 if (!sawEof) {
805 cc = fullRead (fileFd, data, dataCount);
806
807 if (cc < 0) {
808 perror (fileName);
809
810 (void) close (fileFd);
811 errorFlag = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000812
813 return;
Eric Andersen3cf52d11999-10-12 22:26:06 +0000814 }
815
816 /*
817 * If the file ended too soon, complain and set
818 * a flag so we will zero fill the rest of it.
819 */
820 if (cc < dataCount) {
821 fprintf (stderr,
822 "%s: Short read - zero filling", fileName);
823
824 sawEof = TRUE;
825 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000826 }
827
Eric Andersen3cf52d11999-10-12 22:26:06 +0000828 /*
829 * Zero fill the rest of the data if necessary.
Eric Andersencc8ed391999-10-05 16:24:54 +0000830 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000831 if (cc < dataCount)
832 memset (data + cc, 0, dataCount - cc);
Eric Andersencc8ed391999-10-05 16:24:54 +0000833
Eric Andersen3cf52d11999-10-12 22:26:06 +0000834 /*
835 * Write the buffer to the TAR file.
Eric Andersencc8ed391999-10-05 16:24:54 +0000836 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000837 writeTarBlock (data, dataCount);
Eric Andersencc8ed391999-10-05 16:24:54 +0000838
Eric Andersen3cf52d11999-10-12 22:26:06 +0000839 fullDataCount -= dataCount;
840 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000841
Eric Andersen3cf52d11999-10-12 22:26:06 +0000842 /*
843 * Close the file.
844 */
845 if ((tostdoutFlag == FALSE) && close (fileFd) < 0)
846 fprintf (stderr, "%s: close: %s\n", fileName, strerror (errno));
Eric Andersencc8ed391999-10-05 16:24:54 +0000847}
848
849
850/*
851 * Save a directory and all of its files to the tar file.
852 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000853static void saveDirectory (const char *dirName, const struct stat *statbuf)
Eric Andersencc8ed391999-10-05 16:24:54 +0000854{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000855 DIR *dir;
856 struct dirent *entry;
857 int needSlash;
Eric Andersen1b61f411999-10-13 18:56:42 +0000858 char fullName[NAME_MAX];
Eric Andersencc8ed391999-10-05 16:24:54 +0000859
Eric Andersen3cf52d11999-10-12 22:26:06 +0000860 /*
861 * Construct the directory name as used in the tar file by appending
862 * a slash character to it.
863 */
864 strcpy (fullName, dirName);
865 strcat (fullName, "/");
Eric Andersencc8ed391999-10-05 16:24:54 +0000866
Eric Andersen3cf52d11999-10-12 22:26:06 +0000867 /*
868 * Write out the header for the directory entry.
869 */
870 writeHeader (fullName, statbuf);
Eric Andersencc8ed391999-10-05 16:24:54 +0000871
Eric Andersen3cf52d11999-10-12 22:26:06 +0000872 /*
873 * Open the directory.
874 */
875 dir = opendir (dirName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000876
Eric Andersen3cf52d11999-10-12 22:26:06 +0000877 if (dir == NULL) {
878 fprintf (stderr, "Cannot read directory \"%s\": %s\n",
879 dirName, strerror (errno));
Eric Andersencc8ed391999-10-05 16:24:54 +0000880
Eric Andersen3cf52d11999-10-12 22:26:06 +0000881 return;
882 }
883
884 /*
885 * See if a slash is needed.
886 */
887 needSlash = (*dirName && (dirName[strlen (dirName) - 1] != '/'));
888
889 /*
890 * Read all of the directory entries and check them,
891 * except for the current and parent directory entries.
892 */
893 while (!errorFlag && ((entry = readdir (dir)) != NULL)) {
894 if ((strcmp (entry->d_name, ".") == 0) ||
895 (strcmp (entry->d_name, "..") == 0)) {
896 continue;
Eric Andersencc8ed391999-10-05 16:24:54 +0000897 }
898
Eric Andersen3cf52d11999-10-12 22:26:06 +0000899 /*
900 * Build the full path name to the file.
Eric Andersencc8ed391999-10-05 16:24:54 +0000901 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000902 strcpy (fullName, dirName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000903
Eric Andersen3cf52d11999-10-12 22:26:06 +0000904 if (needSlash)
905 strcat (fullName, "/");
906
907 strcat (fullName, entry->d_name);
908
909 /*
910 * Write this file to the tar file, noticing whether or not
911 * the file is a symbolic link.
Eric Andersencc8ed391999-10-05 16:24:54 +0000912 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000913 saveFile (fullName, TRUE);
914 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000915
Eric Andersen3cf52d11999-10-12 22:26:06 +0000916 /*
917 * All done, close the directory.
918 */
919 closedir (dir);
Eric Andersencc8ed391999-10-05 16:24:54 +0000920}
921
922
923/*
924 * Write a tar header for the specified file name and status.
925 * It is assumed that the file name fits.
926 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000927static void writeHeader (const char *fileName, const struct stat *statbuf)
Eric Andersencc8ed391999-10-05 16:24:54 +0000928{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000929 long checkSum;
930 const unsigned char *cp;
931 int len;
932 TarHeader header;
Eric Andersencc8ed391999-10-05 16:24:54 +0000933
Eric Andersen3cf52d11999-10-12 22:26:06 +0000934 /*
935 * Zero the header block in preparation for filling it in.
936 */
937 memset ((char *) &header, 0, sizeof (header));
Eric Andersencc8ed391999-10-05 16:24:54 +0000938
Eric Andersen3cf52d11999-10-12 22:26:06 +0000939 /*
940 * Fill in the header.
941 */
942 strcpy (header.name, fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +0000943
Eric Andersen3cf52d11999-10-12 22:26:06 +0000944 strncpy (header.magic, TAR_MAGIC, sizeof (header.magic));
945 strncpy (header.version, TAR_VERSION, sizeof (header.version));
Eric Andersencc8ed391999-10-05 16:24:54 +0000946
Eric Andersen3cf52d11999-10-12 22:26:06 +0000947 putOctal (header.mode, sizeof (header.mode), statbuf->st_mode & 0777);
948 putOctal (header.uid, sizeof (header.uid), statbuf->st_uid);
949 putOctal (header.gid, sizeof (header.gid), statbuf->st_gid);
950 putOctal (header.size, sizeof (header.size), statbuf->st_size);
951 putOctal (header.mtime, sizeof (header.mtime), statbuf->st_mtime);
Eric Andersencc8ed391999-10-05 16:24:54 +0000952
Eric Andersen3cf52d11999-10-12 22:26:06 +0000953 header.typeFlag = TAR_TYPE_REGULAR;
Eric Andersencc8ed391999-10-05 16:24:54 +0000954
Eric Andersen3cf52d11999-10-12 22:26:06 +0000955 /*
956 * Calculate and store the checksum.
957 * This is the sum of all of the bytes of the header,
958 * with the checksum field itself treated as blanks.
959 */
960 memset (header.checkSum, ' ', sizeof (header.checkSum));
Eric Andersencc8ed391999-10-05 16:24:54 +0000961
Eric Andersen3cf52d11999-10-12 22:26:06 +0000962 cp = (const unsigned char *) &header;
963 len = sizeof (header);
964 checkSum = 0;
Eric Andersencc8ed391999-10-05 16:24:54 +0000965
Eric Andersen3cf52d11999-10-12 22:26:06 +0000966 while (len-- > 0)
967 checkSum += *cp++;
Eric Andersencc8ed391999-10-05 16:24:54 +0000968
Eric Andersen3cf52d11999-10-12 22:26:06 +0000969 putOctal (header.checkSum, sizeof (header.checkSum), checkSum);
Eric Andersencc8ed391999-10-05 16:24:54 +0000970
Eric Andersen3cf52d11999-10-12 22:26:06 +0000971 /*
972 * Write the tar header.
973 */
974 writeTarBlock ((const char *) &header, sizeof (header));
Eric Andersencc8ed391999-10-05 16:24:54 +0000975}
976
977
978/*
979 * Write data to one or more blocks of the tar file.
980 * The data is always padded out to a multiple of TAR_BLOCK_SIZE.
981 * The errorFlag static variable is set on an error.
982 */
Eric Andersen3cf52d11999-10-12 22:26:06 +0000983static void writeTarBlock (const char *buf, int len)
Eric Andersencc8ed391999-10-05 16:24:54 +0000984{
Eric Andersen3cf52d11999-10-12 22:26:06 +0000985 int partialLength;
986 int completeLength;
987 char fullBlock[TAR_BLOCK_SIZE];
Eric Andersencc8ed391999-10-05 16:24:54 +0000988
Eric Andersen3cf52d11999-10-12 22:26:06 +0000989 /*
990 * If we had a write error before, then do nothing more.
991 */
992 if (errorFlag)
993 return;
Eric Andersencc8ed391999-10-05 16:24:54 +0000994
Eric Andersen3cf52d11999-10-12 22:26:06 +0000995 /*
996 * Get the amount of complete and partial blocks.
997 */
998 partialLength = len % TAR_BLOCK_SIZE;
999 completeLength = len - partialLength;
Eric Andersencc8ed391999-10-05 16:24:54 +00001000
Eric Andersen3cf52d11999-10-12 22:26:06 +00001001 /*
1002 * Write all of the complete blocks.
1003 */
1004 if ((completeLength > 0) && !fullWrite (tarFd, buf, completeLength)) {
1005 perror (tarName);
Eric Andersencc8ed391999-10-05 16:24:54 +00001006
Eric Andersen3cf52d11999-10-12 22:26:06 +00001007 errorFlag = TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001008
Eric Andersen3cf52d11999-10-12 22:26:06 +00001009 return;
1010 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001011
Eric Andersen3cf52d11999-10-12 22:26:06 +00001012 /*
1013 * If there are no partial blocks left, we are done.
1014 */
1015 if (partialLength == 0)
1016 return;
Eric Andersencc8ed391999-10-05 16:24:54 +00001017
Eric Andersen3cf52d11999-10-12 22:26:06 +00001018 /*
1019 * Copy the partial data into a complete block, and pad the rest
1020 * of it with zeroes.
1021 */
1022 memcpy (fullBlock, buf + completeLength, partialLength);
1023 memset (fullBlock + partialLength, 0, TAR_BLOCK_SIZE - partialLength);
Eric Andersencc8ed391999-10-05 16:24:54 +00001024
Eric Andersen3cf52d11999-10-12 22:26:06 +00001025 /*
1026 * Write the last complete block.
1027 */
1028 if (!fullWrite (tarFd, fullBlock, TAR_BLOCK_SIZE)) {
1029 perror (tarName);
Eric Andersencc8ed391999-10-05 16:24:54 +00001030
Eric Andersen3cf52d11999-10-12 22:26:06 +00001031 errorFlag = TRUE;
1032 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001033}
1034
1035
1036/*
Eric Andersencc8ed391999-10-05 16:24:54 +00001037 * Read an octal value in a field of the specified width, with optional
1038 * spaces on both sides of the number and with an optional null character
1039 * at the end. Returns -1 on an illegal format.
1040 */
Eric Andersen3cf52d11999-10-12 22:26:06 +00001041static long getOctal (const char *cp, int len)
Eric Andersencc8ed391999-10-05 16:24:54 +00001042{
Eric Andersen3cf52d11999-10-12 22:26:06 +00001043 long val;
Eric Andersencc8ed391999-10-05 16:24:54 +00001044
Eric Andersen3cf52d11999-10-12 22:26:06 +00001045 while ((len > 0) && (*cp == ' ')) {
1046 cp++;
1047 len--;
1048 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001049
Eric Andersen3cf52d11999-10-12 22:26:06 +00001050 if ((len == 0) || !isOctal (*cp))
1051 return -1;
Eric Andersencc8ed391999-10-05 16:24:54 +00001052
Eric Andersen3cf52d11999-10-12 22:26:06 +00001053 val = 0;
Eric Andersencc8ed391999-10-05 16:24:54 +00001054
Eric Andersen3cf52d11999-10-12 22:26:06 +00001055 while ((len > 0) && isOctal (*cp)) {
1056 val = val * 8 + *cp++ - '0';
1057 len--;
1058 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001059
Eric Andersen3cf52d11999-10-12 22:26:06 +00001060 while ((len > 0) && (*cp == ' ')) {
1061 cp++;
1062 len--;
1063 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001064
Eric Andersen3cf52d11999-10-12 22:26:06 +00001065 if ((len > 0) && *cp)
1066 return -1;
Eric Andersencc8ed391999-10-05 16:24:54 +00001067
Eric Andersen3cf52d11999-10-12 22:26:06 +00001068 return val;
Eric Andersencc8ed391999-10-05 16:24:54 +00001069}
1070
1071
1072/*
1073 * Put an octal string into the specified buffer.
1074 * The number is zero and space padded and possibly null padded.
1075 * Returns TRUE if successful.
1076 */
Eric Andersen3cf52d11999-10-12 22:26:06 +00001077static int putOctal (char *cp, int len, long value)
Eric Andersencc8ed391999-10-05 16:24:54 +00001078{
Eric Andersen3cf52d11999-10-12 22:26:06 +00001079 int tempLength;
1080 char *tempString;
1081 char tempBuffer[32];
Eric Andersencc8ed391999-10-05 16:24:54 +00001082
Eric Andersen3cf52d11999-10-12 22:26:06 +00001083 /*
1084 * Create a string of the specified length with an initial space,
1085 * leading zeroes and the octal number, and a trailing null.
1086 */
1087 tempString = tempBuffer;
Eric Andersencc8ed391999-10-05 16:24:54 +00001088
Eric Andersen3cf52d11999-10-12 22:26:06 +00001089 sprintf (tempString, " %0*lo", len - 2, value);
Eric Andersencc8ed391999-10-05 16:24:54 +00001090
Eric Andersen3cf52d11999-10-12 22:26:06 +00001091 tempLength = strlen (tempString) + 1;
Eric Andersencc8ed391999-10-05 16:24:54 +00001092
Eric Andersen3cf52d11999-10-12 22:26:06 +00001093 /*
1094 * If the string is too large, suppress the leading space.
1095 */
1096 if (tempLength > len) {
1097 tempLength--;
1098 tempString++;
1099 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001100
Eric Andersen3cf52d11999-10-12 22:26:06 +00001101 /*
1102 * If the string is still too large, suppress the trailing null.
1103 */
1104 if (tempLength > len)
1105 tempLength--;
Eric Andersencc8ed391999-10-05 16:24:54 +00001106
Eric Andersen3cf52d11999-10-12 22:26:06 +00001107 /*
1108 * If the string is still too large, fail.
1109 */
1110 if (tempLength > len)
1111 return FALSE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001112
Eric Andersen3cf52d11999-10-12 22:26:06 +00001113 /*
1114 * Copy the string to the field.
1115 */
1116 memcpy (cp, tempString, len);
Eric Andersencc8ed391999-10-05 16:24:54 +00001117
Eric Andersen3cf52d11999-10-12 22:26:06 +00001118 return TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001119}
1120
1121
1122/*
1123 * See if the specified file name belongs to one of the specified list
1124 * of path prefixes. An empty list implies that all files are wanted.
1125 * Returns TRUE if the file is selected.
1126 */
Eric Andersenf811e071999-10-09 00:25:00 +00001127static int
Eric Andersen3cf52d11999-10-12 22:26:06 +00001128wantFileName (const char *fileName, int fileCount, char **fileTable)
Eric Andersencc8ed391999-10-05 16:24:54 +00001129{
Eric Andersen3cf52d11999-10-12 22:26:06 +00001130 const char *pathName;
1131 int fileLength;
1132 int pathLength;
Eric Andersencc8ed391999-10-05 16:24:54 +00001133
Eric Andersen3cf52d11999-10-12 22:26:06 +00001134 /*
1135 * If there are no files in the list, then the file is wanted.
1136 */
1137 if (fileCount == 0)
1138 return TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001139
Eric Andersen3cf52d11999-10-12 22:26:06 +00001140 fileLength = strlen (fileName);
Eric Andersencc8ed391999-10-05 16:24:54 +00001141
Eric Andersen3cf52d11999-10-12 22:26:06 +00001142 /*
1143 * Check each of the test paths.
1144 */
1145 while (fileCount-- > 0) {
1146 pathName = *fileTable++;
Eric Andersencc8ed391999-10-05 16:24:54 +00001147
Eric Andersen3cf52d11999-10-12 22:26:06 +00001148 pathLength = strlen (pathName);
Eric Andersencc8ed391999-10-05 16:24:54 +00001149
Eric Andersen3cf52d11999-10-12 22:26:06 +00001150 if (fileLength < pathLength)
1151 continue;
Eric Andersencc8ed391999-10-05 16:24:54 +00001152
Eric Andersen3cf52d11999-10-12 22:26:06 +00001153 if (memcmp (fileName, pathName, pathLength) != 0)
1154 continue;
Eric Andersencc8ed391999-10-05 16:24:54 +00001155
Eric Andersen3cf52d11999-10-12 22:26:06 +00001156 if ((fileLength == pathLength) || (fileName[pathLength] == '/')) {
1157 return TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001158 }
Eric Andersen3cf52d11999-10-12 22:26:06 +00001159 }
Eric Andersencc8ed391999-10-05 16:24:54 +00001160
Eric Andersen3cf52d11999-10-12 22:26:06 +00001161 return FALSE;
Eric Andersencc8ed391999-10-05 16:24:54 +00001162}
1163
1164
1165
Eric Andersencc8ed391999-10-05 16:24:54 +00001166/* END CODE */